From 677f854c05e04e38b77d4659578f64c4a67c347b Mon Sep 17 00:00:00 2001 From: veltza <106755522+veltza@users.noreply.github.com> Date: Mon, 12 Jun 2023 17:02:19 +0300 Subject: [PATCH] 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 --- st.c | 10 ++++++++-- x.c | 22 +++++++--------------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/st.c b/st.c index ec01dc7..a351efe 100644 --- a/st.c +++ b/st.c @@ -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 diff --git a/x.c b/x.c index c2f5a59..9b45076 100644 --- a/x.c +++ b/x.c @@ -2949,28 +2949,19 @@ 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; - } + continue; } if (!im->pixmap) { @@ -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);