feat: kitty images patch applied
This commit is contained in:
411
x.c
411
x.c
@@ -4,6 +4,8 @@
|
||||
#include <limits.h>
|
||||
#include <locale.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/select.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
@@ -19,6 +21,7 @@ char *argv0;
|
||||
#include "arg.h"
|
||||
#include "st.h"
|
||||
#include "win.h"
|
||||
#include "graphics.h"
|
||||
|
||||
/* types used in config.h */
|
||||
typedef struct {
|
||||
@@ -59,6 +62,12 @@ static void zoom(const Arg *);
|
||||
static void zoomabs(const Arg *);
|
||||
static void zoomreset(const Arg *);
|
||||
static void ttysend(const Arg *);
|
||||
static void previewimage(const Arg *);
|
||||
static void showimageinfo(const Arg *);
|
||||
static void togglegrdebug(const Arg *);
|
||||
static void dumpgrstate(const Arg *);
|
||||
static void unloadimages(const Arg *);
|
||||
static void toggleimages(const Arg *);
|
||||
|
||||
/* config.h for applying patches and the configuration. */
|
||||
#include "config.h"
|
||||
@@ -81,6 +90,7 @@ typedef XftGlyphFontSpec GlyphFontSpec;
|
||||
typedef struct {
|
||||
int tw, th; /* tty width and height */
|
||||
int w, h; /* window width and height */
|
||||
int hborderpx, vborderpx;
|
||||
int ch; /* char height */
|
||||
int cw; /* char width */
|
||||
int mode; /* window state/mode flags */
|
||||
@@ -144,6 +154,8 @@ static inline ushort sixd_to_16bit(int);
|
||||
static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int);
|
||||
static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int);
|
||||
static void xdrawglyph(Glyph, int, int);
|
||||
static void xdrawimages(Glyph, Line, int x1, int y1, int x2);
|
||||
static void xdrawoneimagecell(Glyph, int x, int y);
|
||||
static void xclear(int, int, int, int);
|
||||
static int xgeommasktogravity(int);
|
||||
static int ximopen(Display *);
|
||||
@@ -220,6 +232,7 @@ static DC dc;
|
||||
static XWindow xw;
|
||||
static XSelection xsel;
|
||||
static TermWindow win;
|
||||
static unsigned int mouse_col = 0, mouse_row = 0;
|
||||
|
||||
/* Font Ring Cache */
|
||||
enum {
|
||||
@@ -328,10 +341,72 @@ ttysend(const Arg *arg)
|
||||
ttywrite(arg->s, strlen(arg->s), 1);
|
||||
}
|
||||
|
||||
void
|
||||
previewimage(const Arg *arg)
|
||||
{
|
||||
Glyph g = getglyphat(mouse_col, mouse_row);
|
||||
if (g.mode & ATTR_IMAGE) {
|
||||
uint32_t image_id = tgetimgid(&g);
|
||||
fprintf(stderr, "Clicked on placeholder %u/%u, x=%d, y=%d\n",
|
||||
image_id, tgetimgplacementid(&g), tgetimgcol(&g),
|
||||
tgetimgrow(&g));
|
||||
gr_preview_image(image_id, arg->s);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
showimageinfo(const Arg *arg)
|
||||
{
|
||||
Glyph g = getglyphat(mouse_col, mouse_row);
|
||||
if (g.mode & ATTR_IMAGE) {
|
||||
uint32_t image_id = tgetimgid(&g);
|
||||
fprintf(stderr, "Clicked on placeholder %u/%u, x=%d, y=%d\n",
|
||||
image_id, tgetimgplacementid(&g), tgetimgcol(&g),
|
||||
tgetimgrow(&g));
|
||||
char stcommand[256] = {0};
|
||||
size_t len = snprintf(stcommand, sizeof(stcommand), "%s -e less", argv0);
|
||||
if (len > sizeof(stcommand) - 1) {
|
||||
fprintf(stderr, "Executable name too long: %s\n",
|
||||
argv0);
|
||||
return;
|
||||
}
|
||||
gr_show_image_info(image_id, tgetimgplacementid(&g),
|
||||
tgetimgcol(&g), tgetimgrow(&g),
|
||||
tgetisclassicplaceholder(&g),
|
||||
tgetimgdiacriticcount(&g), argv0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
togglegrdebug(const Arg *arg)
|
||||
{
|
||||
graphics_debug_mode = (graphics_debug_mode + 1) % 3;
|
||||
redraw();
|
||||
}
|
||||
|
||||
void
|
||||
dumpgrstate(const Arg *arg)
|
||||
{
|
||||
gr_dump_state();
|
||||
}
|
||||
|
||||
void
|
||||
unloadimages(const Arg *arg)
|
||||
{
|
||||
gr_unload_images_to_reduce_ram();
|
||||
}
|
||||
|
||||
void
|
||||
toggleimages(const Arg *arg)
|
||||
{
|
||||
graphics_display_images = !graphics_display_images;
|
||||
redraw();
|
||||
}
|
||||
|
||||
int
|
||||
evcol(XEvent *e)
|
||||
{
|
||||
int x = e->xbutton.x - borderpx;
|
||||
int x = e->xbutton.x - win.hborderpx;
|
||||
LIMIT(x, 0, win.tw - 1);
|
||||
return x / win.cw;
|
||||
}
|
||||
@@ -339,7 +414,7 @@ evcol(XEvent *e)
|
||||
int
|
||||
evrow(XEvent *e)
|
||||
{
|
||||
int y = e->xbutton.y - borderpx;
|
||||
int y = e->xbutton.y - win.vborderpx;
|
||||
LIMIT(y, 0, win.th - 1);
|
||||
return y / win.ch;
|
||||
}
|
||||
@@ -452,6 +527,9 @@ mouseaction(XEvent *e, uint release)
|
||||
/* ignore Button<N>mask for Button<N> - it's set on release */
|
||||
uint state = e->xbutton.state & ~buttonmask(e->xbutton.button);
|
||||
|
||||
mouse_col = evcol(e);
|
||||
mouse_row = evrow(e);
|
||||
|
||||
for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
|
||||
if (ms->release == release &&
|
||||
ms->button == e->xbutton.button &&
|
||||
@@ -739,6 +817,9 @@ cresize(int width, int height)
|
||||
col = MAX(1, col);
|
||||
row = MAX(1, row);
|
||||
|
||||
win.hborderpx = (win.w - col * win.cw) * anysize_halign / 100;
|
||||
win.vborderpx = (win.h - row * win.ch) * anysize_valign / 100;
|
||||
|
||||
tresize(col, row);
|
||||
xresize(col, row);
|
||||
ttyresize(win.tw, win.th);
|
||||
@@ -869,8 +950,8 @@ xhints(void)
|
||||
sizeh->flags = PSize | PResizeInc | PBaseSize | PMinSize;
|
||||
sizeh->height = win.h;
|
||||
sizeh->width = win.w;
|
||||
sizeh->height_inc = win.ch;
|
||||
sizeh->width_inc = win.cw;
|
||||
sizeh->height_inc = 1;
|
||||
sizeh->width_inc = 1;
|
||||
sizeh->base_height = 2 * borderpx;
|
||||
sizeh->base_width = 2 * borderpx;
|
||||
sizeh->min_height = win.ch + 2 * borderpx;
|
||||
@@ -1014,7 +1095,8 @@ xloadfonts(const char *fontstr, double fontsize)
|
||||
FcPatternAddDouble(pattern, FC_PIXEL_SIZE, 12);
|
||||
usedfontsize = 12;
|
||||
}
|
||||
defaultfontsize = usedfontsize;
|
||||
if (defaultfontsize <= 0)
|
||||
defaultfontsize = usedfontsize;
|
||||
}
|
||||
|
||||
if (xloadfont(&dc.font, pattern))
|
||||
@@ -1024,7 +1106,7 @@ xloadfonts(const char *fontstr, double fontsize)
|
||||
FcPatternGetDouble(dc.font.match->pattern,
|
||||
FC_PIXEL_SIZE, 0, &fontval);
|
||||
usedfontsize = fontval;
|
||||
if (fontsize == 0)
|
||||
if (defaultfontsize <= 0 && fontsize == 0)
|
||||
defaultfontsize = fontval;
|
||||
}
|
||||
|
||||
@@ -1152,8 +1234,8 @@ xinit(int cols, int rows)
|
||||
xloadcols();
|
||||
|
||||
/* adjust fixed window geometry */
|
||||
win.w = 2 * borderpx + cols * win.cw;
|
||||
win.h = 2 * borderpx + rows * win.ch;
|
||||
win.w = 2 * win.hborderpx + 2 * borderpx + cols * win.cw;
|
||||
win.h = 2 * win.vborderpx + 2 * borderpx + rows * win.ch;
|
||||
if (xw.gm & XNegative)
|
||||
xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2;
|
||||
if (xw.gm & YNegative)
|
||||
@@ -1240,12 +1322,15 @@ xinit(int cols, int rows)
|
||||
xsel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0);
|
||||
if (xsel.xtarget == None)
|
||||
xsel.xtarget = XA_STRING;
|
||||
|
||||
// Initialize the graphics (image display) module.
|
||||
gr_init(xw.dpy, xw.vis, xw.cmap);
|
||||
}
|
||||
|
||||
int
|
||||
xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y)
|
||||
{
|
||||
float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, yp;
|
||||
float winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch, xp, yp;
|
||||
ushort mode, prevmode = USHRT_MAX;
|
||||
Font *font = &dc.font;
|
||||
int frcflags = FRC_NORMAL;
|
||||
@@ -1267,6 +1352,11 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
|
||||
if (mode == ATTR_WDUMMY)
|
||||
continue;
|
||||
|
||||
/* Draw spaces for image placeholders (images will be drawn
|
||||
* separately). */
|
||||
if (mode & ATTR_IMAGE)
|
||||
rune = ' ';
|
||||
|
||||
/* Determine font for glyph if different from previous glyph. */
|
||||
if (prevmode != mode) {
|
||||
prevmode = mode;
|
||||
@@ -1374,11 +1464,61 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
|
||||
return numspecs;
|
||||
}
|
||||
|
||||
/* Draws a horizontal dashed line of length `w` starting at `(x, y)`. `wavelen`
|
||||
* is the length of the dash plus the length of the gap. `fraction` is the
|
||||
* fraction of the dash length compared to `wavelen`. */
|
||||
static void
|
||||
xdrawunderdashed(Draw draw, Color *color, int x, int y, int w,
|
||||
int wavelen, float fraction, int thick)
|
||||
{
|
||||
int dashw = MAX(1, fraction * wavelen);
|
||||
for (int i = x - x % wavelen; i < x + w; i += wavelen) {
|
||||
int startx = MAX(i, x);
|
||||
int endx = MIN(i + dashw, x + w);
|
||||
if (startx < endx)
|
||||
XftDrawRect(xw.draw, color, startx, y, endx - startx,
|
||||
thick);
|
||||
}
|
||||
}
|
||||
|
||||
/* Draws an undercurl. `h` is the total height, including line thickness. */
|
||||
static void
|
||||
xdrawundercurl(Draw draw, Color *color, int x, int y, int w, int h, int thick)
|
||||
{
|
||||
XGCValues gcvals = {.foreground = color->pixel,
|
||||
.line_width = thick,
|
||||
.line_style = LineSolid,
|
||||
.cap_style = CapRound};
|
||||
GC gc = XCreateGC(xw.dpy, XftDrawDrawable(xw.draw),
|
||||
GCForeground | GCLineWidth | GCLineStyle | GCCapStyle,
|
||||
&gcvals);
|
||||
|
||||
XRectangle clip = {.x = x, .y = y, .width = w, .height = h};
|
||||
XSetClipRectangles(xw.dpy, gc, 0, 0, &clip, 1, Unsorted);
|
||||
|
||||
int yoffset = thick / 2;
|
||||
int segh = MAX(1, h - thick);
|
||||
/* Make sure every segment is at a 45 degree angle, otherwise it doesn't
|
||||
* look good without antialiasing. */
|
||||
int segw = segh;
|
||||
int wavelen = MAX(1, segw * 2);
|
||||
|
||||
for (int i = x - (x % wavelen); i < x + w; i += wavelen) {
|
||||
XPoint points[3] = {{.x = i, .y = y + yoffset},
|
||||
{.x = i + segw, .y = y + yoffset + segh},
|
||||
{.x = i + wavelen, .y = y + yoffset}};
|
||||
XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), gc, points, 3,
|
||||
CoordModeOrigin);
|
||||
}
|
||||
|
||||
XFreeGC(xw.dpy, gc);
|
||||
}
|
||||
|
||||
void
|
||||
xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y)
|
||||
{
|
||||
int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1);
|
||||
int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch,
|
||||
int winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch,
|
||||
width = charlen * win.cw;
|
||||
Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
|
||||
XRenderColor colfg, colbg;
|
||||
@@ -1468,17 +1608,17 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
|
||||
|
||||
/* Intelligent cleaning up of the borders. */
|
||||
if (x == 0) {
|
||||
xclear(0, (y == 0)? 0 : winy, borderpx,
|
||||
xclear(0, (y == 0)? 0 : winy, win.hborderpx,
|
||||
winy + win.ch +
|
||||
((winy + win.ch >= borderpx + win.th)? win.h : 0));
|
||||
((winy + win.ch >= win.vborderpx + win.th)? win.h : 0));
|
||||
}
|
||||
if (winx + width >= borderpx + win.tw) {
|
||||
if (winx + width >= win.hborderpx + win.tw) {
|
||||
xclear(winx + width, (y == 0)? 0 : winy, win.w,
|
||||
((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch)));
|
||||
((winy + win.ch >= win.vborderpx + win.th)? win.h : (winy + win.ch)));
|
||||
}
|
||||
if (y == 0)
|
||||
xclear(winx, 0, winx + width, borderpx);
|
||||
if (winy + win.ch >= borderpx + win.th)
|
||||
xclear(winx, 0, winx + width, win.vborderpx);
|
||||
if (winy + win.ch >= win.vborderpx + win.th)
|
||||
xclear(winx, winy + win.ch, winx + width, win.h);
|
||||
|
||||
/* Clean up the region we want to draw to. */
|
||||
@@ -1491,18 +1631,68 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
|
||||
r.width = width;
|
||||
XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1);
|
||||
|
||||
/* Decoration color. */
|
||||
Color decor;
|
||||
uint32_t decorcolor = tgetdecorcolor(&base);
|
||||
if (decorcolor == DECOR_DEFAULT_COLOR) {
|
||||
decor = *fg;
|
||||
} else if (IS_TRUECOL(decorcolor)) {
|
||||
colfg.alpha = 0xffff;
|
||||
colfg.red = TRUERED(decorcolor);
|
||||
colfg.green = TRUEGREEN(decorcolor);
|
||||
colfg.blue = TRUEBLUE(decorcolor);
|
||||
XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &decor);
|
||||
} else {
|
||||
decor = dc.col[decorcolor];
|
||||
}
|
||||
decor.color.alpha = 0xffff;
|
||||
decor.pixel |= 0xff << 24;
|
||||
|
||||
/* Float thickness, used as a base to compute other values. */
|
||||
float fthick = dc.font.height / 18.0;
|
||||
/* Integer thickness in pixels. Must not be 0. */
|
||||
int thick = MAX(1, roundf(fthick));
|
||||
/* The default gap between the baseline and a single underline. */
|
||||
int gap = roundf(fthick * 2);
|
||||
/* The total thickness of a double underline. */
|
||||
int doubleh = thick * 2 + ceilf(fthick * 0.5);
|
||||
/* The total thickness of an undercurl. */
|
||||
int curlh = thick * 2 + roundf(fthick * 0.75);
|
||||
|
||||
/* Render the underline before the glyphs. */
|
||||
if (base.mode & ATTR_UNDERLINE) {
|
||||
uint32_t style = tgetdecorstyle(&base);
|
||||
int liney = winy + dc.font.ascent + gap;
|
||||
/* Adjust liney to guarantee that a single underline fits. */
|
||||
liney -= MAX(0, liney + thick - (winy + win.ch));
|
||||
if (style == UNDERLINE_DOUBLE) {
|
||||
liney -= MAX(0, liney + doubleh - (winy + win.ch));
|
||||
XftDrawRect(xw.draw, &decor, winx, liney, width, thick);
|
||||
XftDrawRect(xw.draw, &decor, winx,
|
||||
liney + doubleh - thick, width, thick);
|
||||
} else if (style == UNDERLINE_DOTTED) {
|
||||
xdrawunderdashed(xw.draw, &decor, winx, liney, width,
|
||||
thick * 2, 0.5, thick);
|
||||
} else if (style == UNDERLINE_DASHED) {
|
||||
int wavelen = MAX(2, win.cw * 0.9);
|
||||
xdrawunderdashed(xw.draw, &decor, winx, liney, width,
|
||||
wavelen, 0.65, thick);
|
||||
} else if (style == UNDERLINE_CURLY) {
|
||||
liney -= MAX(0, liney + curlh - (winy + win.ch));
|
||||
xdrawundercurl(xw.draw, &decor, winx, liney, width,
|
||||
curlh, thick);
|
||||
} else {
|
||||
XftDrawRect(xw.draw, &decor, winx, liney, width, thick);
|
||||
}
|
||||
}
|
||||
|
||||
/* Render the glyphs. */
|
||||
XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
|
||||
|
||||
/* Render underline and strikethrough. */
|
||||
if (base.mode & ATTR_UNDERLINE) {
|
||||
XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent * chscale + 1,
|
||||
width, 1);
|
||||
}
|
||||
|
||||
/* Render strikethrough. Alway use the fg color. */
|
||||
if (base.mode & ATTR_STRUCK) {
|
||||
XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent * chscale / 3,
|
||||
width, 1);
|
||||
XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3,
|
||||
width, thick);
|
||||
}
|
||||
|
||||
/* Reset clip to none. */
|
||||
@@ -1517,6 +1707,11 @@ xdrawglyph(Glyph g, int x, int y)
|
||||
|
||||
numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y);
|
||||
xdrawglyphfontspecs(&spec, g, numspecs, x, y);
|
||||
if (g.mode & ATTR_IMAGE) {
|
||||
gr_start_drawing(xw.buf, win.cw, win.ch);
|
||||
xdrawoneimagecell(g, x, y);
|
||||
gr_finish_drawing(xw.buf);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1532,6 +1727,10 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
|
||||
if (IS_SET(MODE_HIDE))
|
||||
return;
|
||||
|
||||
// If it's an image, just draw a ballot box for simplicity.
|
||||
if (g.mode & ATTR_IMAGE)
|
||||
g.u = 0x2610;
|
||||
|
||||
/*
|
||||
* Select the right color for the right mode.
|
||||
*/
|
||||
@@ -1572,39 +1771,167 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
|
||||
case 3: /* Blinking Underline */
|
||||
case 4: /* Steady Underline */
|
||||
XftDrawRect(xw.draw, &drawcol,
|
||||
borderpx + cx * win.cw,
|
||||
borderpx + (cy + 1) * win.ch - \
|
||||
win.hborderpx + cx * win.cw,
|
||||
win.vborderpx + (cy + 1) * win.ch - \
|
||||
cursorthickness,
|
||||
win.cw, cursorthickness);
|
||||
break;
|
||||
case 5: /* Blinking bar */
|
||||
case 6: /* Steady bar */
|
||||
XftDrawRect(xw.draw, &drawcol,
|
||||
borderpx + cx * win.cw,
|
||||
borderpx + cy * win.ch,
|
||||
win.hborderpx + cx * win.cw,
|
||||
win.vborderpx + cy * win.ch,
|
||||
cursorthickness, win.ch);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
XftDrawRect(xw.draw, &drawcol,
|
||||
borderpx + cx * win.cw,
|
||||
borderpx + cy * win.ch,
|
||||
win.hborderpx + cx * win.cw,
|
||||
win.vborderpx + cy * win.ch,
|
||||
win.cw - 1, 1);
|
||||
XftDrawRect(xw.draw, &drawcol,
|
||||
borderpx + cx * win.cw,
|
||||
borderpx + cy * win.ch,
|
||||
win.hborderpx + cx * win.cw,
|
||||
win.vborderpx + cy * win.ch,
|
||||
1, win.ch - 1);
|
||||
XftDrawRect(xw.draw, &drawcol,
|
||||
borderpx + (cx + 1) * win.cw - 1,
|
||||
borderpx + cy * win.ch,
|
||||
win.hborderpx + (cx + 1) * win.cw - 1,
|
||||
win.vborderpx + cy * win.ch,
|
||||
1, win.ch - 1);
|
||||
XftDrawRect(xw.draw, &drawcol,
|
||||
borderpx + cx * win.cw,
|
||||
borderpx + (cy + 1) * win.ch - 1,
|
||||
win.hborderpx + cx * win.cw,
|
||||
win.vborderpx + (cy + 1) * win.ch - 1,
|
||||
win.cw, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw (or queue for drawing) image cells between columns x1 and x2 assuming
|
||||
* that they have the same attributes (and thus the same lower 24 bits of the
|
||||
* image ID and the same placement ID). */
|
||||
void
|
||||
xdrawimages(Glyph base, Line line, int x1, int y1, int x2) {
|
||||
int y_pix = win.vborderpx + y1 * win.ch;
|
||||
uint32_t image_id_24bits = base.fg & 0xFFFFFF;
|
||||
uint32_t placement_id = tgetimgplacementid(&base);
|
||||
// Columns and rows are 1-based, 0 means unspecified.
|
||||
int last_col = 0;
|
||||
int last_row = 0;
|
||||
int last_start_col = 0;
|
||||
int last_start_x = x1;
|
||||
// The most significant byte is also 1-base, subtract 1 before use.
|
||||
uint32_t last_id_4thbyteplus1 = 0;
|
||||
// We may need to inherit row/column/4th byte from the previous cell.
|
||||
Glyph *prev = &line[x1 - 1];
|
||||
if (x1 > 0 && (prev->mode & ATTR_IMAGE) &&
|
||||
(prev->fg & 0xFFFFFF) == image_id_24bits &&
|
||||
prev->decor == base.decor) {
|
||||
last_row = tgetimgrow(prev);
|
||||
last_col = tgetimgcol(prev);
|
||||
last_id_4thbyteplus1 = tgetimgid4thbyteplus1(prev);
|
||||
last_start_col = last_col + 1;
|
||||
}
|
||||
for (int x = x1; x < x2; ++x) {
|
||||
Glyph *g = &line[x];
|
||||
uint32_t cur_row = tgetimgrow(g);
|
||||
uint32_t cur_col = tgetimgcol(g);
|
||||
uint32_t cur_id_4thbyteplus1 = tgetimgid4thbyteplus1(g);
|
||||
uint32_t num_diacritics = tgetimgdiacriticcount(g);
|
||||
// If the row is not specified, assume it's the same as the row
|
||||
// of the previous cell. Note that `cur_row` may contain a
|
||||
// value imputed earlier, which will be preserved if `last_row`
|
||||
// is zero (i.e. we don't know the row of the previous cell).
|
||||
if (last_row && (num_diacritics == 0 || !cur_row))
|
||||
cur_row = last_row;
|
||||
// If the column is not specified and the row is the same as the
|
||||
// row of the previous cell, then assume that the column is the
|
||||
// next one.
|
||||
if (last_col && (num_diacritics <= 1 || !cur_col) &&
|
||||
cur_row == last_row)
|
||||
cur_col = last_col + 1;
|
||||
// If the additional id byte is not specified and the
|
||||
// coordinates are consecutive, assume the byte is also the
|
||||
// same.
|
||||
if (last_id_4thbyteplus1 &&
|
||||
(num_diacritics <= 2 || !cur_id_4thbyteplus1) &&
|
||||
cur_row == last_row && cur_col == last_col + 1)
|
||||
cur_id_4thbyteplus1 = last_id_4thbyteplus1;
|
||||
// If we couldn't infer row and column, start from the top left
|
||||
// corner.
|
||||
if (cur_row == 0)
|
||||
cur_row = 1;
|
||||
if (cur_col == 0)
|
||||
cur_col = 1;
|
||||
// If this cell breaks a contiguous stripe of image cells, draw
|
||||
// that line and start a new one.
|
||||
if (cur_col != last_col + 1 || cur_row != last_row ||
|
||||
cur_id_4thbyteplus1 != last_id_4thbyteplus1) {
|
||||
uint32_t image_id = image_id_24bits;
|
||||
if (last_id_4thbyteplus1)
|
||||
image_id |= (last_id_4thbyteplus1 - 1) << 24;
|
||||
if (last_row != 0) {
|
||||
int x_pix =
|
||||
win.hborderpx + last_start_x * win.cw;
|
||||
gr_append_imagerect(
|
||||
xw.buf, image_id, placement_id,
|
||||
last_start_col - 1, last_col,
|
||||
last_row - 1, last_row, last_start_x,
|
||||
y1, x_pix, y_pix, win.cw, win.ch,
|
||||
base.mode & ATTR_REVERSE);
|
||||
}
|
||||
last_start_col = cur_col;
|
||||
last_start_x = x;
|
||||
}
|
||||
last_row = cur_row;
|
||||
last_col = cur_col;
|
||||
last_id_4thbyteplus1 = cur_id_4thbyteplus1;
|
||||
// Populate the missing glyph data to enable inheritance between
|
||||
// runs and support the naive implementation of tgetimgid.
|
||||
if (!tgetimgrow(g))
|
||||
tsetimgrow(g, cur_row);
|
||||
// We cannot save this information if there are > 511 cols.
|
||||
if (!tgetimgcol(g) && (cur_col & ~0x1ff) == 0)
|
||||
tsetimgcol(g, cur_col);
|
||||
if (!tgetimgid4thbyteplus1(g))
|
||||
tsetimg4thbyteplus1(g, cur_id_4thbyteplus1);
|
||||
}
|
||||
uint32_t image_id = image_id_24bits;
|
||||
if (last_id_4thbyteplus1)
|
||||
image_id |= (last_id_4thbyteplus1 - 1) << 24;
|
||||
// Draw the last contiguous stripe.
|
||||
if (last_row != 0) {
|
||||
int x_pix = win.hborderpx + last_start_x * win.cw;
|
||||
gr_append_imagerect(xw.buf, image_id, placement_id,
|
||||
last_start_col - 1, last_col, last_row - 1,
|
||||
last_row, last_start_x, y1, x_pix, y_pix,
|
||||
win.cw, win.ch, base.mode & ATTR_REVERSE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw just one image cell without inheriting attributes from the left. */
|
||||
void xdrawoneimagecell(Glyph g, int x, int y) {
|
||||
if (!(g.mode & ATTR_IMAGE))
|
||||
return;
|
||||
int x_pix = win.hborderpx + x * win.cw;
|
||||
int y_pix = win.vborderpx + y * win.ch;
|
||||
uint32_t row = tgetimgrow(&g) - 1;
|
||||
uint32_t col = tgetimgcol(&g) - 1;
|
||||
uint32_t placement_id = tgetimgplacementid(&g);
|
||||
uint32_t image_id = tgetimgid(&g);
|
||||
gr_append_imagerect(xw.buf, image_id, placement_id, col, col + 1, row,
|
||||
row + 1, x, y, x_pix, y_pix, win.cw, win.ch,
|
||||
g.mode & ATTR_REVERSE);
|
||||
}
|
||||
|
||||
/* Prepare for image drawing. */
|
||||
void xstartimagedraw(int *dirty, int rows) {
|
||||
gr_start_drawing(xw.buf, win.cw, win.ch);
|
||||
gr_mark_dirty_animations(dirty, rows);
|
||||
}
|
||||
|
||||
/* Draw all queued image cells. */
|
||||
void xfinishimagedraw() {
|
||||
gr_finish_drawing(xw.buf);
|
||||
}
|
||||
|
||||
void
|
||||
xsetenv(void)
|
||||
{
|
||||
@@ -1671,6 +1998,8 @@ xdrawline(Line line, int x1, int y1, int x2)
|
||||
new.mode ^= ATTR_REVERSE;
|
||||
if (i > 0 && ATTRCMP(base, new)) {
|
||||
xdrawglyphfontspecs(specs, base, i, ox, y1);
|
||||
if (base.mode & ATTR_IMAGE)
|
||||
xdrawimages(base, line, ox, y1, x);
|
||||
specs += i;
|
||||
numspecs -= i;
|
||||
i = 0;
|
||||
@@ -1683,6 +2012,8 @@ xdrawline(Line line, int x1, int y1, int x2)
|
||||
}
|
||||
if (i > 0)
|
||||
xdrawglyphfontspecs(specs, base, i, ox, y1);
|
||||
if (i > 0 && base.mode & ATTR_IMAGE)
|
||||
xdrawimages(base, line, ox, y1, x);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1907,6 +2238,7 @@ cmessage(XEvent *e)
|
||||
}
|
||||
} else if (e->xclient.data.l[0] == xw.wmdeletewin) {
|
||||
ttyhangup();
|
||||
gr_deinit();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
@@ -1957,6 +2289,13 @@ run(void)
|
||||
if (XPending(xw.dpy))
|
||||
timeout = 0; /* existing events might not set xfd */
|
||||
|
||||
/* Decrease the timeout if there are active animations. */
|
||||
if (graphics_next_redraw_delay != INT_MAX &&
|
||||
IS_SET(MODE_VISIBLE))
|
||||
timeout = timeout < 0 ? graphics_next_redraw_delay
|
||||
: MIN(timeout,
|
||||
graphics_next_redraw_delay);
|
||||
|
||||
seltv.tv_sec = timeout / 1E3;
|
||||
seltv.tv_nsec = 1E6 * (timeout - 1E3 * seltv.tv_sec);
|
||||
tv = timeout >= 0 ? &seltv : NULL;
|
||||
|
||||
Reference in New Issue
Block a user