diff options
| author | twells46 <173561638+twells46@users.noreply.github.com> | 2025-11-29 08:18:48 -0600 |
|---|---|---|
| committer | twells46 <173561638+twells46@users.noreply.github.com> | 2025-11-29 08:18:48 -0600 |
| commit | 9d70dfc76159cffc6d85530ce7d9897118d9677c (patch) | |
| tree | e2171e954cdeed661b8e8af3500992d9b656f96e /x.c | |
| parent | b1c93ae35772f4fb3a923605fefa02bf1fee585e (diff) | |
Add sixel patch
Diffstat (limited to 'x.c')
| -rw-r--r-- | x.c | 569 |
1 files changed, 326 insertions, 243 deletions
@@ -20,30 +20,8 @@ char *argv0; #include "st.h" #include "win.h" -/* types used in config.h */ -typedef struct { - uint mod; - KeySym keysym; - void (*func)(const Arg *); - const Arg arg; -} Shortcut; - -typedef struct { - uint mod; - uint button; - void (*func)(const Arg *); - const Arg arg; - uint release; -} MouseShortcut; - -typedef struct { - KeySym k; - uint mask; - char *s; - /* three-valued logic variables: 0 indifferent, 1 on, -1 off */ - signed char appkey; /* application keypad */ - signed char appcursor; /* application cursor */ -} Key; +#include <Imlib2.h> +#include "sixel.h" /* X modifiers */ #define XK_ANY_MOD UINT_MAX @@ -55,10 +33,11 @@ static void clipcopy(const Arg *); static void clippaste(const Arg *); static void numlock(const Arg *); static void selpaste(const Arg *); +static void ttysend(const Arg *); static void zoom(const Arg *); static void zoomabs(const Arg *); static void zoomreset(const Arg *); -static void ttysend(const Arg *); + /* config.h for applying patches and the configuration. */ #include "config.h" @@ -73,77 +52,10 @@ static void ttysend(const Arg *); #define TRUEGREEN(x) (((x) & 0xff00)) #define TRUEBLUE(x) (((x) & 0xff) << 8) -typedef XftDraw *Draw; -typedef XftColor Color; -typedef XftGlyphFontSpec GlyphFontSpec; - -/* Purely graphic info */ -typedef struct { - int tw, th; /* tty width and height */ - int w, h; /* window width and height */ - int ch; /* char height */ - int cw; /* char width */ - int mode; /* window state/mode flags */ - int cursor; /* cursor style */ -} TermWindow; - -typedef struct { - Display *dpy; - Colormap cmap; - Window win; - Drawable buf; - GlyphFontSpec *specbuf; /* font spec buffer used for rendering */ - Atom xembed, wmdeletewin, netwmname, netwmiconname, netwmpid; - struct { - XIM xim; - XIC xic; - XPoint spot; - XVaNestedList spotlist; - } ime; - Draw draw; - Visual *vis; - XSetWindowAttributes attrs; - int scr; - int isfixed; /* is fixed geometry? */ - int l, t; /* left and top offset */ - int gm; /* geometry mask */ -} XWindow; - -typedef struct { - Atom xtarget; - char *primary, *clipboard; - struct timespec tclick1; - struct timespec tclick2; -} XSelection; - -/* Font structure */ -#define Font Font_ -typedef struct { - int height; - int width; - int ascent; - int descent; - int badslant; - int badweight; - short lbearing; - short rbearing; - XftFont *match; - FcFontSet *set; - FcPattern *pattern; -} Font; - -/* Drawing Context */ -typedef struct { - Color *col; - size_t collen; - Font font, bfont, ifont, ibfont; - GC gc; -} DC; - 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); +void xdrawglyph(Glyph, int, int); static void xclear(int, int, int, int); static int xgeommasktogravity(int); static int ximopen(Display *); @@ -172,7 +84,6 @@ static void cmessage(XEvent *); static void resize(XEvent *); static void focus(XEvent *); static uint buttonmask(uint); -static int mouseaction(XEvent *, uint); static void brelease(XEvent *); static void bpress(XEvent *); static void bmotion(XEvent *); @@ -181,6 +92,7 @@ static void selnotify(XEvent *); static void selclear_(XEvent *); static void selrequest(XEvent *); static void setsel(char *, Time); +static int mouseaction(XEvent *, uint); static void mousesel(XEvent *, int); static void mousereport(XEvent *); static char *kmap(KeySym, uint); @@ -216,10 +128,11 @@ static void (*handler[LASTEvent])(XEvent *) = { }; /* Globals */ -static DC dc; -static XWindow xw; -static XSelection xsel; -static TermWindow win; +Term term; +DC dc; +XWindow xw; +XSelection xsel; +TermWindow win; /* Font Ring Cache */ enum { @@ -254,6 +167,7 @@ static char *opt_title = NULL; static uint buttons; /* bit field of pressed buttons */ + void clipcopy(const Arg *dummy) { @@ -280,16 +194,23 @@ clippaste(const Arg *dummy) } void +numlock(const Arg *dummy) +{ + win.mode ^= MODE_NUMLOCK; +} + +void selpaste(const Arg *dummy) { + XConvertSelection(xw.dpy, XA_PRIMARY, xsel.xtarget, XA_PRIMARY, xw.win, CurrentTime); } void -numlock(const Arg *dummy) +ttysend(const Arg *arg) { - win.mode ^= MODE_NUMLOCK; + ttywrite(arg->s, strlen(arg->s), 1); } void @@ -298,14 +219,31 @@ zoom(const Arg *arg) Arg larg; larg.f = usedfontsize + arg->f; - zoomabs(&larg); + if (larg.f >= 1.0) + zoomabs(&larg); } void zoomabs(const Arg *arg) { + int i; + ImageList *im; + xunloadfonts(); xloadfonts(usedfont, arg->f); + + /* 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); redraw(); xhints(); @@ -322,12 +260,6 @@ zoomreset(const Arg *arg) } } -void -ttysend(const Arg *arg) -{ - ttywrite(arg->s, strlen(arg->s), 1); -} - int evcol(XEvent *e) { @@ -344,6 +276,40 @@ evrow(XEvent *e) return y / win.ch; } +uint +buttonmask(uint button) +{ + return button == Button1 ? Button1Mask + : button == Button2 ? Button2Mask + : button == Button3 ? Button3Mask + : button == Button4 ? Button4Mask + : button == Button5 ? Button5Mask + : 0; +} + +int +mouseaction(XEvent *e, uint release) +{ + MouseShortcut *ms; + int screen = tisaltscr() ? S_ALT : S_PRI; + + /* ignore Button<N>mask for Button<N> - it's set on release */ + uint state = e->xbutton.state & ~buttonmask(e->xbutton.button); + + for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { + if (ms->release == release && + ms->button == e->xbutton.button && + (!ms->screen || (ms->screen == screen)) && + (match(ms->mod, state) || /* exact or forced */ + match(ms->mod, state & ~forcemousemod))) { + ms->func(&(ms->arg)); + return 1; + } + } + + return 0; +} + void mousesel(XEvent *e, int done) { @@ -378,6 +344,7 @@ mousereport(XEvent *e) /* MODE_MOUSEMOTION: no reporting if no button is pressed */ if (IS_SET(MODE_MOUSEMOTION) && buttons == 0) return; + /* Set btn to lowest-numbered pressed button, or 12 if no * buttons are pressed. */ for (btn = 1; btn <= 11 && !(buttons & (1<<(btn-1))); btn++) @@ -433,38 +400,6 @@ mousereport(XEvent *e) ttywrite(buf, len, 0); } -uint -buttonmask(uint button) -{ - return button == Button1 ? Button1Mask - : button == Button2 ? Button2Mask - : button == Button3 ? Button3Mask - : button == Button4 ? Button4Mask - : button == Button5 ? Button5Mask - : 0; -} - -int -mouseaction(XEvent *e, uint release) -{ - MouseShortcut *ms; - - /* ignore Button<N>mask for Button<N> - it's set on release */ - uint state = e->xbutton.state & ~buttonmask(e->xbutton.button); - - for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { - if (ms->release == release && - ms->button == e->xbutton.button && - (match(ms->mod, state) || /* exact or forced */ - match(ms->mod, state & ~forcemousemod))) { - ms->func(&(ms->arg)); - return 1; - } - } - - return 0; -} - void bpress(XEvent *e) { @@ -500,6 +435,7 @@ bpress(XEvent *e) xsel.tclick1 = now; selstart(evcol(e), evrow(e), snap); + } } @@ -515,6 +451,7 @@ propnotify(XEvent *e) xpev->atom == clipboard)) { selnotify(e); } + } void @@ -545,7 +482,8 @@ selnotify(XEvent *e) return; } - if (e->type == PropertyNotify && nitems == 0 && rem == 0) { + if (e->type == PropertyNotify && nitems == 0 && rem == 0) + { /* * If there is some PropertyNotify with no data, then * this is the signal of the selection owner that all @@ -686,6 +624,7 @@ setsel(char *str, Time t) XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t); if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win) selclear(); + } void @@ -709,13 +648,17 @@ brelease(XEvent *e) if (mouseaction(e, 1)) return; - if (btn == Button1) + + if (btn == Button1) { mousesel(e, 1); + } + } void bmotion(XEvent *e) { + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { mousereport(e); return; @@ -736,7 +679,7 @@ cresize(int width, int height) col = (win.w - 2 * borderpx) / win.cw; row = (win.h - 2 * borderpx) / win.ch; - col = MAX(1, col); + col = MAX(2, col); row = MAX(1, row); tresize(col, row); @@ -752,7 +695,8 @@ xresize(int col, int row) XFreePixmap(xw.dpy, xw.buf); xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, - DefaultDepth(xw.dpy, xw.scr)); + DefaultDepth(xw.dpy, xw.scr) + ); XftDrawChange(xw.draw, xw.buf); xclear(0, 0, win.w, win.h); @@ -857,6 +801,12 @@ xclear(int x1, int y1, int x2, int y2) } void +xclearwin(void) +{ + xclear(0, 0, win.w, win.h); +} + +void xhints(void) { XClassHint class = {opt_name ? opt_name : termname, @@ -908,6 +858,60 @@ xgeommasktogravity(int mask) } int +ximopen(Display *dpy) +{ + XIMCallback imdestroy = { .client_data = NULL, .callback = ximdestroy }; + XICCallback icdestroy = { .client_data = NULL, .callback = xicdestroy }; + + xw.ime.xim = XOpenIM(xw.dpy, NULL, NULL, NULL); + if (xw.ime.xim == NULL) + return 0; + + if (XSetIMValues(xw.ime.xim, XNDestroyCallback, &imdestroy, NULL)) + fprintf(stderr, "XSetIMValues: " + "Could not set XNDestroyCallback.\n"); + + xw.ime.spotlist = XVaCreateNestedList(0, XNSpotLocation, &xw.ime.spot, + NULL); + + if (xw.ime.xic == NULL) { + xw.ime.xic = XCreateIC(xw.ime.xim, XNInputStyle, + XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, xw.win, + XNDestroyCallback, &icdestroy, + NULL); + } + if (xw.ime.xic == NULL) + fprintf(stderr, "XCreateIC: Could not create input context.\n"); + + return 1; +} + +void +ximinstantiate(Display *dpy, XPointer client, XPointer call) +{ + if (ximopen(dpy)) + XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, + ximinstantiate, NULL); +} + +void +ximdestroy(XIM xim, XPointer client, XPointer call) +{ + xw.ime.xim = NULL; + XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, + ximinstantiate, NULL); + XFree(xw.ime.spotlist); +} + +int +xicdestroy(XIC xim, XPointer client, XPointer call) +{ + xw.ime.xic = NULL; + return 1; +} + +int xloadfont(Font *f, FcPattern *pattern) { FcPattern *configured; @@ -1062,6 +1066,7 @@ xunloadfont(Font *f) void xunloadfonts(void) { + /* Free the loaded fonts in the font cache. */ while (frclen > 0) XftFontClose(xw.dpy, frc[--frclen].font); @@ -1072,60 +1077,6 @@ xunloadfonts(void) xunloadfont(&dc.ibfont); } -int -ximopen(Display *dpy) -{ - XIMCallback imdestroy = { .client_data = NULL, .callback = ximdestroy }; - XICCallback icdestroy = { .client_data = NULL, .callback = xicdestroy }; - - xw.ime.xim = XOpenIM(xw.dpy, NULL, NULL, NULL); - if (xw.ime.xim == NULL) - return 0; - - if (XSetIMValues(xw.ime.xim, XNDestroyCallback, &imdestroy, NULL)) - fprintf(stderr, "XSetIMValues: " - "Could not set XNDestroyCallback.\n"); - - xw.ime.spotlist = XVaCreateNestedList(0, XNSpotLocation, &xw.ime.spot, - NULL); - - if (xw.ime.xic == NULL) { - xw.ime.xic = XCreateIC(xw.ime.xim, XNInputStyle, - XIMPreeditNothing | XIMStatusNothing, - XNClientWindow, xw.win, - XNDestroyCallback, &icdestroy, - NULL); - } - if (xw.ime.xic == NULL) - fprintf(stderr, "XCreateIC: Could not create input context.\n"); - - return 1; -} - -void -ximinstantiate(Display *dpy, XPointer client, XPointer call) -{ - if (ximopen(dpy)) - XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, - ximinstantiate, NULL); -} - -void -ximdestroy(XIM xim, XPointer client, XPointer call) -{ - xw.ime.xim = NULL; - XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, - ximinstantiate, NULL); - XFree(xw.ime.spotlist); -} - -int -xicdestroy(XIC xim, XPointer client, XPointer call) -{ - xw.ime.xic = NULL; - return 1; -} - void xinit(int cols, int rows) { @@ -1138,6 +1089,7 @@ xinit(int cols, int rows) if (!(xw.dpy = XOpenDisplay(NULL))) die("can't open display\n"); xw.scr = XDefaultScreen(xw.dpy); + xw.vis = XDefaultVisual(xw.dpy, xw.scr); /* font */ @@ -1165,7 +1117,8 @@ xinit(int cols, int rows) xw.attrs.bit_gravity = NorthWestGravity; xw.attrs.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask | ExposureMask | VisibilityChangeMask | StructureNotifyMask - | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask; + | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask + ; xw.attrs.colormap = xw.cmap; root = XRootWindow(xw.dpy, xw.scr); @@ -1180,6 +1133,7 @@ xinit(int cols, int rows) memset(&gcvalues, 0, sizeof(gcvalues)); gcvalues.graphics_exposures = False; + dc.gc = XCreateGC(xw.dpy, xw.win, GCGraphicsExposures, &gcvalues); xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, @@ -1196,7 +1150,7 @@ xinit(int cols, int rows) /* input methods */ if (!ximopen(xw.dpy)) { XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, - ximinstantiate, NULL); + ximinstantiate, NULL); } /* white cursor, black outline */ @@ -1240,6 +1194,7 @@ xinit(int cols, int rows) xsel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0); if (xsel.xtarget == None) xsel.xtarget = XA_STRING; + } int @@ -1249,7 +1204,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x ushort mode, prevmode = USHRT_MAX; Font *font = &dc.font; int frcflags = FRC_NORMAL; - float runewidth = win.cw; + float runewidth = win.cw * ((glyphs[0].mode & ATTR_WIDE) ? 2.0f : 1.0f); Rune rune; FT_UInt glyphidx; FcResult fcres; @@ -1258,7 +1213,8 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x FcCharSet *fccharset; int i, f, numspecs = 0; - for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { + for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) + { /* Fetch rune and mode for current glyph. */ rune = glyphs[i].u; mode = glyphs[i].mode; @@ -1314,8 +1270,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x /* Nothing was found. Use fontconfig to find matching font. */ if (f >= frclen) { if (!font->set) - font->set = FcFontSort(0, font->pattern, - 1, 0, &fcres); + font->set = FcFontSort(0, font->pattern, 1, 0, &fcres); fcsets[0] = font->set; /* @@ -1329,16 +1284,13 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x fccharset = FcCharSetCreate(); FcCharSetAddChar(fccharset, rune); - FcPatternAddCharSet(fcpattern, FC_CHARSET, - fccharset); + FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); FcPatternAddBool(fcpattern, FC_SCALABLE, 1); - FcConfigSubstitute(0, fcpattern, - FcMatchPattern); + FcConfigSubstitute(0, fcpattern, FcMatchPattern); FcDefaultSubstitute(fcpattern); - fontpattern = FcFontSetMatch(0, fcsets, 1, - fcpattern, &fcres); + fontpattern = FcFontSetMatch(0, fcsets, 1, fcpattern, &fcres); /* Allocate memory for the new cache entry. */ if (frclen >= frccap) { @@ -1346,8 +1298,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x frc = xrealloc(frc, frccap * sizeof(Fontcache)); } - frc[frclen].font = XftFontOpenPattern(xw.dpy, - fontpattern); + frc[frclen].font = XftFontOpenPattern(xw.dpy, fontpattern); if (!frc[frclen].font) die("XftFontOpenPattern failed seeking fallback font: %s\n", strerror(errno)); @@ -1375,11 +1326,11 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x } void -xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y) -{ +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, - width = charlen * win.cw; + int width = charlen * win.cw; + int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch; Color *fg, *bg, *temp, revfg, revbg, truefg, truebg; XRenderColor colfg, colbg; XRectangle r; @@ -1482,6 +1433,7 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i xclear(winx, winy + win.ch, winx + width, win.h); /* Clean up the region we want to draw to. */ + XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); /* Set the clip region because Xft is sometimes dirty. */ @@ -1513,10 +1465,11 @@ void xdrawglyph(Glyph g, int x, int y) { int numspecs; - XftGlyphFontSpec spec; + XftGlyphFontSpec *specs = xw.specbuf; - numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y); - xdrawglyphfontspecs(&spec, g, numspecs, x, y); + numspecs = xmakeglyphfontspecs(specs, &g, 1, x, y); + xdrawglyphfontspecs(specs, g, numspecs, x, y + ); } void @@ -1527,6 +1480,7 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) /* remove the old cursor */ if (selected(ox, oy)) og.mode ^= ATTR_REVERSE; + xdrawglyph(og, ox, oy); if (IS_SET(MODE_HIDE)) @@ -1535,7 +1489,8 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) /* * Select the right color for the right mode. */ - g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE; + g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE + ; if (IS_SET(MODE_REVERSE)) { g.mode |= ATTR_REVERSE; @@ -1555,6 +1510,7 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) g.fg = defaultbg; g.bg = defaultcs; } + drawcol = dc.col[g.bg]; } @@ -1564,13 +1520,13 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) case 7: /* st extension */ g.u = 0x2603; /* snowman (U+2603) */ /* FALLTHROUGH */ - case 0: /* Blinking Block */ - case 1: /* Blinking Block (Default) */ - case 2: /* Steady Block */ + case 0: /* Blinking block */ + case 1: /* Blinking block (default) */ + case 2: /* Steady block */ xdrawglyph(g, cx, cy); break; - case 3: /* Blinking Underline */ - case 4: /* Steady Underline */ + case 3: /* Blinking underline */ + case 4: /* Steady underline */ XftDrawRect(xw.draw, &drawcol, borderpx + cx * win.cw, borderpx + (cy + 1) * win.ch - \ @@ -1624,7 +1580,7 @@ xseticontitle(char *p) p = opt_title; if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, - &prop) != Success) + &prop) != Success) return; XSetWMIconName(xw.dpy, xw.win, &prop); XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmiconname); @@ -1641,7 +1597,7 @@ xsettitle(char *p) p = opt_title; if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, - &prop) != Success) + &prop) != Success) return; XSetWMName(xw.dpy, xw.win, &prop); XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname); @@ -1659,6 +1615,7 @@ xdrawline(Line line, int x1, int y1, int x2) { int i, x, ox, numspecs; Glyph base, new; + XftGlyphFontSpec *specs = xw.specbuf; numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1); @@ -1683,16 +1640,132 @@ xdrawline(Line line, int x1, int y1, int x2) } if (i > 0) xdrawglyphfontspecs(specs, base, i, ox, y1); + } void xfinishdraw(void) { - 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); + ImageList *im, *next; + Imlib_Image origin, scaled; + XGCValues gcvalues; + GC gc = NULL; + int width, height; + int del, desty, mode, x1, x2, xend; + int bw = borderpx, bh = borderpx; + Line line; + + for (im = term.images; im; im = next) { + next = im->next; + + /* do not draw or process the image, if it is not visible */ + if (im->x >= term.col || im->y >= term.row || im->y < 0) + continue; + + /* scale the image */ + width = MAX(im->width * win.cw / im->cw, 1); + height = MAX(im->height * win.ch / im->ch, 1); + if (!im->pixmap) { + im->pixmap = (void *)XCreatePixmap(xw.dpy, xw.win, width, height, + DefaultDepth(xw.dpy, xw.scr) + ); + if (!im->pixmap) + continue; + if (win.cw == im->cw && win.ch == im->ch) { + XImage ximage = { + .format = ZPixmap, + .data = (char *)im->pixels, + .width = im->width, + .height = im->height, + .xoffset = 0, + .byte_order = sixelbyteorder, + .bitmap_bit_order = MSBFirst, + .bits_per_pixel = 32, + .bytes_per_line = im->width * 4, + .bitmap_unit = 32, + .bitmap_pad = 32, + .depth = 24 + }; + XPutImage(xw.dpy, (Drawable)im->pixmap, dc.gc, &ximage, 0, 0, 0, 0, width, height); + if (im->transparent) + im->clipmask = (void *)sixel_create_clipmask((char *)im->pixels, width, height); + } else { + origin = imlib_create_image_using_data(im->width, im->height, (DATA32 *)im->pixels); + if (!origin) + continue; + imlib_context_set_image(origin); + imlib_image_set_has_alpha(1); + imlib_context_set_anti_alias(im->transparent ? 0 : 1); /* anti-aliasing messes up the clip mask */ + scaled = imlib_create_cropped_scaled_image(0, 0, im->width, im->height, width, height); + imlib_free_image_and_decache(); + if (!scaled) + continue; + imlib_context_set_image(scaled); + imlib_image_set_has_alpha(1); + XImage ximage = { + .format = ZPixmap, + .data = (char *)imlib_image_get_data_for_reading_only(), + .width = width, + .height = height, + .xoffset = 0, + .byte_order = sixelbyteorder, + .bitmap_bit_order = MSBFirst, + .bits_per_pixel = 32, + .bytes_per_line = width * 4, + .bitmap_unit = 32, + .bitmap_pad = 32, + .depth = 24 + }; + XPutImage(xw.dpy, (Drawable)im->pixmap, dc.gc, &ximage, 0, 0, 0, 0, width, height); + if (im->transparent) + im->clipmask = (void *)sixel_create_clipmask((char *)imlib_image_get_data_for_reading_only(), width, height); + imlib_free_image_and_decache(); + } + } + + /* create GC */ + if (!gc) { + memset(&gcvalues, 0, sizeof(gcvalues)); + gcvalues.graphics_exposures = False; + gc = XCreateGC(xw.dpy, xw.win, GCGraphicsExposures, &gcvalues); + } + + /* set the clip mask */ + desty = bh + im->y * win.ch; + if (im->clipmask) { + XSetClipMask(xw.dpy, gc, (Drawable)im->clipmask); + XSetClipOrigin(xw.dpy, gc, bw + im->x * win.cw, desty); + } + + /* draw only the parts of the image that are not erased */ + line = term.line[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); } void @@ -1844,7 +1917,7 @@ kpress(XEvent *ev) XKeyEvent *e = &ev->xkey; KeySym ksym = NoSymbol; char buf[64], *customkey; - int len; + int len, screen; Rune c; Status status; Shortcut *bp; @@ -1859,9 +1932,13 @@ kpress(XEvent *ev) } else { len = XLookupString(e, buf, sizeof buf, &ksym, NULL); } + + screen = tisaltscr() ? S_ALT : S_PRI; + /* 1. shortcuts */ for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { - if (ksym == bp->keysym && match(bp->mod, e->state)) { + if (ksym == bp->keysym && match(bp->mod, e->state) && + (!bp->screen || bp->screen == screen)) { bp->func(&(bp->arg)); return; } @@ -1914,6 +1991,7 @@ cmessage(XEvent *e) void resize(XEvent *e) { + if (e->xconfigure.width == win.w && e->xconfigure.height == win.h) return; @@ -1992,7 +2070,8 @@ run(void) * maximum latency intervals during `cat huge.txt`, and perfect * sync with periodic updates from animations/key-repeats/etc. */ - if (FD_ISSET(ttyfd, &rfd) || xev) { + if (FD_ISSET(ttyfd, &rfd) || xev) + { if (!drawing) { trigger = now; drawing = 1; @@ -2005,7 +2084,8 @@ run(void) /* idle detected or maxlatency exhausted -> draw */ timeout = -1; - if (blinktimeout && tattrset(ATTR_BLINK)) { + if (blinktimeout && tattrset(ATTR_BLINK)) + { timeout = blinktimeout - TIMEDIFF(now, lastblink); if (timeout <= 0) { if (-timeout > blinktimeout) /* start visible */ @@ -2026,14 +2106,16 @@ run(void) void usage(void) { - die("usage: %s [-aiv] [-c class] [-f font] [-g geometry]" - " [-n name] [-o file]\n" - " [-T title] [-t title] [-w windowid]" - " [[-e] command [args ...]]\n" - " %s [-aiv] [-c class] [-f font] [-g geometry]" - " [-n name] [-o file]\n" - " [-T title] [-t title] [-w windowid] -l line" - " [stty_args ...]\n", argv0, argv0); + die("usage: %s [-aiv] [-c class]" + " [-f font] [-g geometry]" + " [-n name] [-o file]\n" + " [-T title] [-t title] [-w windowid]" + " [[-e] command [args ...]]\n" + " %s [-aiv] [-c class]" + " [-f font] [-g geometry]" + " [-n name] [-o file]\n" + " [-T title] [-t title] [-w windowid] -l line" + " [stty_args ...]\n", argv0, argv0); } int @@ -2096,6 +2178,7 @@ run: setlocale(LC_CTYPE, ""); XSetLocaleModifiers(""); + cols = MAX(cols, 1); rows = MAX(rows, 1); tnew(cols, rows); |