diff --git a/patch/reflow.c b/patch/reflow.c index f69aa8e..fc69148 100644 --- a/patch/reflow.c +++ b/patch/reflow.c @@ -71,7 +71,7 @@ treflow_moveimages(int oldy, int newy) void treflow(int col, int row) { - int i, j, x, x2; + int i, j; int oce, nce, bot, scr; int ox = 0, oy = -term.histf, nx = 0, ny = -1, len; int cy = -1; /* proxy for new y coordinate of cursor */ @@ -205,13 +205,12 @@ treflow(int col, int row) } /* expand images into new text cells */ - for (im = term.images; im; im = next) { - next = im->next; - if (im->x < col) { - line = TLINE(im->y); - x2 = MIN(im->x + im->cols, col); - for (x = im->x; x < x2; x++) - line[x].mode |= ATTR_SIXEL; + for (im = term.images; im; im = im->next) { + j = MIN(im->x + im->cols, col); + line = TLINE(im->y); + for (i = im->x; i < j; i++) { + if (!(line[i].mode & ATTR_SET)) + line[i].mode |= ATTR_SIXEL; } } diff --git a/st.c b/st.c index 6461daf..58311ec 100644 --- a/st.c +++ b/st.c @@ -184,6 +184,7 @@ static void tsetattr(const int *, int); static void tsetchar(Rune, const Glyph *, int, int); static void tsetdirt(int, int); static void tsetscroll(int, int); +static inline void tsetsixelattr(Line line, int x1, int x2); static void tswapscreen(void); static void tsetmode(int, int, const int *, int); static int twrite(const char *, int, int); @@ -836,6 +837,13 @@ tsetdirtattr(int attr) } } +void +tsetsixelattr(Line line, int x1, int x2) +{ + for (; x1 <= x2; x1++) + line[x1].mode |= ATTR_SIXEL; +} + void tfulldirt(void) { @@ -1771,7 +1779,7 @@ strhandle(void) { defaultcs, "cursor" } }; ImageList *im, *newimages, *next, *tail; - int i, x, y, x1, y1, x2, y2, numimages; + int i, x1, y1, x2, y2, numimages; int cx, cy; Line line; int scr = IS_SET(MODE_ALTSCREEN) ? 0 : term.scr; @@ -1897,34 +1905,38 @@ strhandle(void) } else { term.images = newimages; } - x2 = MIN(x2, term.col); - for (i = 0, im = newimages; im; im = next, i++) { - next = im->next; - scr = IS_SET(MODE_ALTSCREEN) ? 0 : term.scr; - if (IS_SET(MODE_SIXEL_SDM)) { + x2 = MIN(x2, term.col) - 1; + if (IS_SET(MODE_SIXEL_SDM)) { + /* Sixel display mode: put the sixel in the upper left corner of + * the screen, disable scrolling (the sixel will be truncated if + * it is too long) and do not change the cursor position. */ + for (i = 0, im = newimages; im; im = next, i++) { + next = im->next; if (i >= term.row) { delete_image(im); continue; } im->y = i + scr; - line = term.line[i]; - } else { + tsetsixelattr(term.line[i], x1, x2); + term.dirty[MIN(im->y, term.row-1)] = 1; + } + } else { + for (i = 0, im = newimages; im; im = next, i++) { + next = im->next; + scr = IS_SET(MODE_ALTSCREEN) ? 0 : term.scr; im->y = term.c.y + scr; - line = term.line[term.c.y]; - } - for (x = im->x; x < x2; x++) { - line[x].mode |= ATTR_SIXEL; - } - term.dirty[MIN(im->y, term.row-1)] = 1; - if (!IS_SET(MODE_SIXEL_SDM) && i < numimages-1) { - im->next = NULL; - tnewline(0); - im->next = next; + tsetsixelattr(term.line[term.c.y], x1, x2); + term.dirty[MIN(im->y, term.row-1)] = 1; + if (i < numimages-1) { + im->next = NULL; + tnewline(0); + im->next = next; + } } + /* if mode 8452 is set, sixel scrolling leaves cursor to right of graphic */ + if (IS_SET(MODE_SIXEL_CUR_RT)) + term.c.x = MIN(term.c.x + newimages->cols, term.col-1); } - /* if mode 8452 is set, sixel scrolling leaves cursor to right of graphic */ - if (!IS_SET(MODE_SIXEL_SDM) && IS_SET(MODE_SIXEL_CUR_RT)) - term.c.x = MIN(term.c.x + newimages->cols, term.col-1); } /* https://gitlab.com/gnachman/iterm2/-/wikis/synchronized-updates-spec */ if (strstr(strescseq.buf, "=1s") == strescseq.buf) diff --git a/x.c b/x.c index 6a41bd5..e2d12ee 100644 --- a/x.c +++ b/x.c @@ -254,20 +254,23 @@ zoom(const Arg *arg) void zoomabs(const Arg *arg) { + int i; ImageList *im; xunloadfonts(); xloadfonts(usedfont, arg->f); xloadsparefonts(); - /* deleting old pixmaps forces the new scaled pixmaps to be created */ - for (im = term.images; im; im = im->next) { - if (im->pixmap) - XFreePixmap(xw.dpy, (Drawable)im->pixmap); - if (im->clipmask) - XFreePixmap(xw.dpy, (Drawable)im->clipmask); - im->pixmap = NULL; - im->clipmask = NULL; + /* delete old pixmaps so that xfinishdraw() can create new scaled ones */ + for (im = term.images, i = 0; i < 2; i++, im = term.images_alt) { + for (; im; im = im->next) { + if (im->pixmap) + XFreePixmap(xw.dpy, (Drawable)im->pixmap); + if (im->clipmask) + XFreePixmap(xw.dpy, (Drawable)im->clipmask); + im->pixmap = NULL; + im->clipmask = NULL; + } } cresize(0, 0); @@ -2221,9 +2224,10 @@ xfinishdraw(void) ImageList *im, *next; Imlib_Image origin, scaled; XGCValues gcvalues; - GC gc; + GC gc = NULL; int width, height; - int x, x2, del, destx, desty; + int del, desty, mode, x1, x2, xend; + int bw = win.hborderpx, bh = win.vborderpx; Line line; for (im = term.images; im; im = next) { @@ -2233,6 +2237,10 @@ xfinishdraw(void) if (im->x >= term.col || im->y >= term.row || im->y < 0) continue; + /* do not draw the image on the search bar */ + if (im->y == term.row-1 && IS_SET(MODE_KBDSELECT) && kbds_issearchmode()) + continue; + /* scale the image */ width = MAX(im->width * win.cw / im->cw, 1); height = MAX(im->height * win.ch / im->ch, 1); @@ -2294,34 +2302,46 @@ xfinishdraw(void) } } - /* clip the image so it does not go over to borders */ - x2 = MIN(im->x + im->cols, term.col); - width = MIN(width, (x2 - im->x) * win.cw); - - /* delete the image if the text cells behind it have been changed */ - line = TLINE(im->y); - for (del = 0, x = im->x; x < x2; x++) { - if ((del = !(line[x].mode & ATTR_SIXEL))) - break; - } - if (del) { - delete_image(im); - continue; + /* create GC */ + if (!gc) { + memset(&gcvalues, 0, sizeof(gcvalues)); + gcvalues.graphics_exposures = False; + gc = XCreateGC(xw.dpy, xw.win, GCGraphicsExposures, &gcvalues); } - /* draw the image */ - memset(&gcvalues, 0, sizeof(gcvalues)); - gcvalues.graphics_exposures = False; - gc = XCreateGC(xw.dpy, xw.win, GCGraphicsExposures, &gcvalues); - destx = win.hborderpx + im->x * win.cw; - desty = win.vborderpx + im->y * win.ch; + /* set the clip mask */ + desty = bh + im->y * win.ch; if (im->clipmask) { XSetClipMask(xw.dpy, gc, (Drawable)im->clipmask); - XSetClipOrigin(xw.dpy, gc, destx, desty); + XSetClipOrigin(xw.dpy, gc, bw + im->x * win.cw, desty); } - XCopyArea(xw.dpy, (Drawable)im->pixmap, xw.buf, gc, 0, 0, width, height, destx, desty); - XFreeGC(xw.dpy, gc); + + /* draw only the parts of the image that are not erased */ + line = TLINE(im->y) + im->x; + xend = MIN(im->x + im->cols, term.col); + for (del = 1, x1 = im->x; x1 < xend; x1 = x2) { + mode = line->mode & ATTR_SIXEL; + for (x2 = x1 + 1; x2 < xend; x2++) { + if (((++line)->mode & ATTR_SIXEL) != mode) + break; + } + if (mode) { + XCopyArea(xw.dpy, (Drawable)im->pixmap, xw.buf, gc, + (x1 - im->x) * win.cw, 0, + MIN((x2 - x1) * win.cw, width - (x1 - im->x) * win.cw), height, + bw + x1 * win.cw, desty); + del = 0; + } + } + if (im->clipmask) + XSetClipMask(xw.dpy, gc, None); + + /* if all the parts are erased, we can delete the entire image */ + if (del && im->x + im->cols <= term.col) + delete_image(im); } + if (gc) + XFreeGC(xw.dpy, gc); XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w, win.h, 0, 0); XSetForeground(xw.dpy, dc.gc, dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg].pixel);