Fix sixel issues and add a clearing sequence (#99)

This patch fixes the following sixel issues:

- The current sixel implementation cleared all cells from the left side
  of the image when the image was drawn. The fix only clears the cells
  where the image will be drawn.
- The deletion routine didn't work correctly. In certain situations,
  it left the image or images undrawn. For example, if the first image
  was marked for deletion, it didn't draw the second one.
- The drawing routine caused a high cpu usage, because XCopyArea()
  triggered the X server to send the NoExpose event, which caused sixels
  to be redrawn and the X server to send another NoExpose event and so
  on. This loop caused constant redraw of sixels and high cpu usage.
  The fix prevents the X server from sending GraphicsExpose and NoExpose
  events.

The patch also adds a control sequence for removing sixels:

Because the sixels are implemented as overlay images, they cannot be
removed by clearing the underlaying cells. Therefore, we need a control
sequence to remove them. I opted to choose ESC[6J as the control
sequence because it is not used and the number refers to sixels. So when
the lf file manager supports sixels [1], you can use the following
minimal scripts to preview images in lf:

previewer:
  #!/bin/sh
  case "$(readlink -f "$1")" in
      *.bmp|*.gif|*.jpg|*.jpeg|*.png|*.webp|*.six|*.svg|*.xpm)
          chafa -s "$(($2-3))x$3" -f sixels "$1"
          exit 1 ;;
      *)
          bat "$1" ;;
  esac

cleaner:
  #!/bin/sh
  printf "\033[6J" >/dev/tty

[1] https://github.com/gokcehan/lf/pull/1211
This commit is contained in:
veltza 2023-06-12 17:02:19 +03:00 committed by GitHub
parent 1343b29ee5
commit 677f854c05
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 15 additions and 17 deletions

10
st.c
View File

@ -2297,6 +2297,12 @@ csihandle(void)
}
#endif // SIXEL_PATCH
break;
#if SIXEL_PATCH
case 6: /* sixels */
for (im = term.images; im; im = im->next)
im->should_delete = 1;
break;
#endif // SIXEL_PATCH
default:
goto unknown;
}
@ -2658,10 +2664,10 @@ strhandle(void)
}
for (i = 0; i < (sixel_st.image.height + win.ch-1)/win.ch; ++i) {
int x;
tclearregion(term.c.x, term.c.y, term.c.x+(sixel_st.image.width+win.cw-1)/win.cw, term.c.y);
tclearregion(term.c.x, term.c.y, term.c.x+(sixel_st.image.width+win.cw-1)/win.cw-1, term.c.y);
for (x = term.c.x; x < MIN(term.col, term.c.x+(sixel_st.image.width+win.cw-1)/win.cw); x++)
term.line[term.c.y][x].mode |= ATTR_SIXEL;
tnewline(1);
tnewline(0);
}
}
#endif // SIXEL_PATCH

20
x.c
View File

@ -2949,29 +2949,20 @@ void
xfinishdraw(void)
{
#if SIXEL_PATCH
ImageList *im;
ImageList *im, *next;
XGCValues gcvalues;
GC gc;
#endif // SIXEL_PATCH
#if SIXEL_PATCH
for (im = term.images; im; im = im->next) {
if (term.images == NULL) {
/* last image was deleted, bail out */
break;
}
for (im = term.images; im; im = next) {
/* get the next image here, because delete_image() will delete the current image */
next = im->next;
if (im->should_delete) {
delete_image(im);
/* prevent the next iteration from accessing an invalid image pointer */
im = term.images;
if (im == NULL) {
break;
} else {
continue;
}
}
if (!im->pixmap) {
im->pixmap = (void *)XCreatePixmap(xw.dpy, xw.win, im->width, im->height,
@ -3005,7 +2996,8 @@ xfinishdraw(void)
}
memset(&gcvalues, 0, sizeof(gcvalues));
gc = XCreateGC(xw.dpy, xw.win, 0, &gcvalues);
gcvalues.graphics_exposures = False;
gc = XCreateGC(xw.dpy, xw.win, GCGraphicsExposures, &gcvalues);
#if ANYSIZE_PATCH
XCopyArea(xw.dpy, (Drawable)im->pixmap, xw.buf, gc, 0, 0, im->width, im->height, win.hborderpx + im->x * win.cw, win.vborderpx + im->y * win.ch);