From 4437d5b3c3eea76f6e2b0fd4a2ba21c02a098aeb Mon Sep 17 00:00:00 2001 From: TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> Date: Sat, 8 Mar 2025 15:21:28 +0900 Subject: updates --- st/x.c | 600 +++++++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 376 insertions(+), 224 deletions(-) (limited to 'st/x.c') diff --git a/st/x.c b/st/x.c index 8082ded..d6067d7 100644 --- a/st/x.c +++ b/st/x.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -20,7 +21,6 @@ char *argv0; #include "arg.h" #include "st.h" #include "win.h" -#include "hb.h" /* types used in config.h */ typedef struct { @@ -36,6 +36,7 @@ typedef struct { void (*func)(const Arg *); const Arg arg; uint release; + int altscrn; /* 0: don't care, -1: not alt screen, 1: alt screen */ } MouseShortcut; typedef struct { @@ -47,6 +48,11 @@ typedef struct { signed char appcursor; /* application cursor */ } Key; +typedef enum { + PixelGeometry, + CellGeometry +} Geometry; + /* Xresources preferences */ enum resource_type { STRING = 0, @@ -70,17 +76,19 @@ static void clipcopy(const Arg *); static void clippaste(const Arg *); static void numlock(const Arg *); static void selpaste(const Arg *); -static void changealpha(const Arg *); static void zoom(const Arg *); static void zoomabs(const Arg *); static void zoomreset(const Arg *); static void ttysend(const Arg *); +static void chgalpha(const Arg *); static void cyclefonts(const Arg *); - /* config.h for applying patches and the configuration. */ #include "config.h" +/* size of title stack */ +#define TITLESTACKSIZE 8 + /* XEMBED messages */ #define XEMBED_FOCUS_IN 4 #define XEMBED_FOCUS_OUT 5 @@ -102,7 +110,6 @@ typedef struct { int hborderpx, vborderpx; int ch; /* char height */ int cw; /* char width */ - int cyo; /* char y offset */ int mode; /* window state/mode flags */ int cursor; /* cursor style */ } TermWindow; @@ -114,6 +121,7 @@ typedef struct { Drawable buf; GlyphFontSpec *specbuf; /* font spec buffer used for rendering */ Atom xembed, wmdeletewin, netwmname, netwmiconname, netwmpid; + Atom netwmstate, netwmfullscreen; struct { XIM xim; XIC xic; @@ -163,7 +171,7 @@ typedef struct { 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 xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int, int); static void xdrawglyph(Glyph, int, int); static void xclear(int, int, int, int); static int xgeommasktogravity(int); @@ -186,7 +194,6 @@ static void xsetenv(void); static void xseturgency(int); static int evcol(XEvent *); static int evrow(XEvent *); -static float clamp(float, float, float); static void expose(XEvent *); static void visibility(XEvent *); @@ -215,6 +222,7 @@ static void usage(void); static void (*handler[LASTEvent])(XEvent *) = { [KeyPress] = kpress, + [KeyRelease] = kpress, [ClientMessage] = cmessage, [ConfigureNotify] = resize, [VisibilityNotify] = visibility, @@ -244,6 +252,8 @@ static DC dc; static XWindow xw; static XSelection xsel; static TermWindow win; +static int tstki; /* title stack index */ +static char *titlestack[TITLESTACKSIZE]; /* title stack */ /* Font Ring Cache */ enum { @@ -267,6 +277,11 @@ static char *usedfont = NULL; static double usedfontsize = 0; static double defaultfontsize = 0; +/* declared in config.h */ +extern int disablebold; +extern int disableitalic; +extern int disableroman; + static char *opt_alpha = NULL; static char *opt_class = NULL; static char **opt_cmd = NULL; @@ -277,11 +292,15 @@ static char *opt_line = NULL; static char *opt_name = NULL; static char *opt_title = NULL; -static int focused = 0; - -static int oldbutton = 3; /* button event on startup: 3 = release */ static uint buttons; /* bit field of pressed buttons */ static int cursorblinks = 0; +static int focused = 0; + +static Cursor cursor; +static XColor xmousefg, xmousebg; +XWindowAttributes attr; +XVisualInfo vis; + void clipcopy(const Arg *dummy) @@ -321,20 +340,6 @@ numlock(const Arg *dummy) win.mode ^= MODE_NUMLOCK; } -void -changealpha(const Arg *arg) -{ - if((alpha > 0 && arg->f < 0) || (alpha < 1 && arg->f > 0)) - alpha += arg->f; - else if (arg->f == 0.0f) - alpha = alpha_def; - alpha = clamp(alpha, 0.0, 1.0); - alphaUnfocus = clamp(alpha-alphaOffset, 0.0, 1.0); - - xloadcols(); - redraw(); -} - void zoom(const Arg *arg) { @@ -359,7 +364,6 @@ void zoomreset(const Arg *arg) { Arg larg; - zoomabs(&larg); } @@ -396,15 +400,6 @@ evrow(XEvent *e) return y / win.ch; } -float -clamp(float value, float lower, float upper) { - if(value < lower) - return lower; - if(value > upper) - return upper; - return value; -} - void mousesel(XEvent *e, int done) { @@ -425,59 +420,68 @@ mousesel(XEvent *e, int done) void mousereport(XEvent *e) { - int len, x = evcol(e), y = evrow(e), - button = e->xbutton.button, state = e->xbutton.state; + int len, btn, code; + int x = evcol(e), y = evrow(e); + int state = e->xbutton.state; char buf[40]; static int ox, oy; - /* from urxvt */ - if (e->xbutton.type == MotionNotify) { + if (e->type == MotionNotify) { if (x == ox && y == oy) return; if (!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY)) return; - /* MOUSE_MOTION: no reporting if no button is pressed */ - if (IS_SET(MODE_MOUSEMOTION) && oldbutton == 3) + /* MODE_MOUSEMOTION: no reporting if no button is pressed */ + if (IS_SET(MODE_MOUSEMOTION) && buttons == 0) return; - - button = oldbutton + 32; - ox = x; - oy = y; + /* Set btn to lowest-numbered pressed button, or 12 if no + * buttons are pressed. */ + for (btn = 1; btn <= 11 && !(buttons & (1<<(btn-1))); btn++) + ; + code = 32; } else { - if (!IS_SET(MODE_MOUSESGR) && e->xbutton.type == ButtonRelease) { - button = 3; - } else { - button -= Button1; - if (button >= 3) - button += 64 - 3; - } - if (e->xbutton.type == ButtonPress) { - oldbutton = button; - ox = x; - oy = y; - } else if (e->xbutton.type == ButtonRelease) { - oldbutton = 3; + btn = e->xbutton.button; + /* Only buttons 1 through 11 can be encoded */ + if (btn < 1 || btn > 11) + return; + if (e->type == ButtonRelease) { /* MODE_MOUSEX10: no button release reporting */ if (IS_SET(MODE_MOUSEX10)) return; - if (button == 64 || button == 65) + /* Don't send release events for the scroll wheel */ + if (btn == 4 || btn == 5) return; } + code = 0; } + ox = x; + oy = y; + + /* Encode btn into code. If no button is pressed for a motion event in + * MODE_MOUSEMANY, then encode it as a release. */ + if ((!IS_SET(MODE_MOUSESGR) && e->type == ButtonRelease) || btn == 12) + code += 3; + else if (btn >= 8) + code += 128 + btn - 8; + else if (btn >= 4) + code += 64 + btn - 4; + else + code += btn - 1; + if (!IS_SET(MODE_MOUSEX10)) { - button += ((state & ShiftMask ) ? 4 : 0) - + ((state & Mod4Mask ) ? 8 : 0) - + ((state & ControlMask) ? 16 : 0); + code += ((state & ShiftMask ) ? 4 : 0) + + ((state & Mod1Mask ) ? 8 : 0) /* meta key: alt */ + + ((state & ControlMask) ? 16 : 0); } if (IS_SET(MODE_MOUSESGR)) { len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c", - button, x+1, y+1, + code, x+1, y+1, e->type == ButtonRelease ? 'm' : 'M'); } else if (x < 223 && y < 223) { len = snprintf(buf, sizeof(buf), "\033[M%c%c%c", - 32+button, 32+x+1, 32+y+1); + 32+code, 32+x+1, 32+y+1); } else { return; } @@ -504,9 +508,14 @@ mouseaction(XEvent *e, uint release) /* ignore Buttonmask for Button - it's set on release */ uint state = e->xbutton.state & ~buttonmask(e->xbutton.button); + if (release == 0 && e->xbutton.button == Button1) { + return followurl(evcol(e), evrow(e)); + } + for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { if (ms->release == release && ms->button == e->xbutton.button && + (!ms->altscrn || (ms->altscrn == (tisaltscr() ? 1 : -1))) && (match(ms->mod, state) || /* exact or forced */ match(ms->mod, state & ~forcemousemod))) { ms->func(&(ms->arg)); @@ -738,6 +747,7 @@ setsel(char *str, Time t) XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t); if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win) selclear(); + clipcopy(NULL); } void @@ -815,6 +825,24 @@ xresize(int col, int row) xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec)); } +void +fullscreen(const Arg *arg) +{ + XEvent ev; + + memset(&ev, 0, sizeof(ev)); + + ev.xclient.type = ClientMessage; + ev.xclient.message_type = xw.netwmstate; + ev.xclient.display = xw.dpy; + ev.xclient.window = xw.win; + ev.xclient.format = 32; + ev.xclient.data.l[0] = 2; /* _NET_WM_STATE_TOGGLE */ + ev.xclient.data.l[1] = xw.netwmfullscreen; + + XSendEvent(xw.dpy, DefaultRootWindow(xw.dpy), False, SubstructureNotifyMask|SubstructureRedirectMask, &ev); +} + ushort sixd_to_16bit(int x) { @@ -848,7 +876,8 @@ xloadcolor(int i, const char *name, Color *ncolor) void xloadalpha(void) { - float const usedAlpha = focused ? alpha : alphaUnfocus; + xloadcolor(focused ?bg :bgUnfocused, NULL, &dc.col[defaultbg]); + float const usedAlpha = focused ? alpha : alphaUnfocused; if (opt_alpha) alpha = strtof(opt_alpha, NULL); dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * usedAlpha); dc.col[defaultbg].pixel &= 0x00FFFFFF; @@ -858,16 +887,15 @@ xloadalpha(void) void xloadcols(void) { - int i; static int loaded; Color *cp; if (!loaded) { dc.collen = 1 + (defaultbg = MAX(LEN(colorname), 256)); - dc.col = xmalloc(dc.collen * sizeof(Color)); + dc.col = xmalloc((dc.collen) * sizeof(Color)); } - for (i = 0; i+1 < dc.collen; i++) + for (int i = 0; i+1 < dc.collen; ++i) if (!xloadcolor(i, NULL, &dc.col[i])) { if (colorname[i]) die("could not allocate color '%s'\n", colorname[i]); @@ -875,9 +903,6 @@ xloadcols(void) die("could not allocate color %d\n", i); } - if (dc.collen) // cannot die, as the color is already loaded. - xloadcolor(background, NULL, &dc.col[defaultbg]); - xloadalpha(); loaded = 1; } @@ -885,7 +910,7 @@ xloadcols(void) int xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b) { - if (!BETWEEN(x, 0, dc.collen)) + if (!BETWEEN(x, 0, dc.collen - 1)) return 1; *r = dc.col[x].color.red >> 8; @@ -900,7 +925,7 @@ xsetcolorname(int x, const char *name) { Color ncolor; - if (!BETWEEN(x, 0, dc.collen)) + if (!BETWEEN(x, 0, dc.collen - 1)) return 1; if (!xloadcolor(x, name, &ncolor)) @@ -923,6 +948,12 @@ xclear(int x1, int y1, int x2, int y2) x1, y1, x2-x1, y2-y1); } +void +xclearwin(void) +{ + xclear(0, 0, win.w, win.h); +} + void xhints(void) { @@ -1098,20 +1129,22 @@ xloadfonts(const char *fontstr, double fontsize) /* Setting character width and height. */ win.cw = ceilf(dc.font.width * cwscale); win.ch = ceilf(dc.font.height * chscale); - win.cyo = ceilf(dc.font.height * (chscale - 1) / 2); FcPatternDel(pattern, FC_SLANT); - FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); + if (!disableitalic) + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); if (xloadfont(&dc.ifont, pattern)) die("can't open font %s\n", fontstr); FcPatternDel(pattern, FC_WEIGHT); - FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); + if (!disablebold) + FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); if (xloadfont(&dc.ibfont, pattern)) die("can't open font %s\n", fontstr); FcPatternDel(pattern, FC_SLANT); - FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); + if (!disableroman) + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); if (xloadfont(&dc.bfont, pattern)) die("can't open font %s\n", fontstr); @@ -1149,7 +1182,6 @@ xloadsparefonts(void) double sizeshift, fontval; int fc; char **fp; - int width, height; if (frclen != 0) die("can't embed spare fonts. cache isn't empty"); @@ -1166,6 +1198,7 @@ xloadsparefonts(void) } for (fp = font2; fp - font2 < fc; ++fp) { + if (**fp == '-') pattern = XftXlfdParse(*fp, False, False); else @@ -1225,9 +1258,6 @@ xunloadfont(Font *f) void xunloadfonts(void) { - /* Clear Harfbuzz font cache. */ - hbunloadfonts(); - /* Free the loaded fonts in the font cache. */ while (frclen > 0) XftFontClose(xw.dpy, frc[--frclen].font); @@ -1293,16 +1323,11 @@ xicdestroy(XIC xim, XPointer client, XPointer call) } void -xinit(int cols, int rows) +xinit(int w, int h) { XGCValues gcvalues; - Cursor cursor; Window parent; pid_t thispid = getpid(); - XColor xmousefg, xmousebg; - XWindowAttributes attr; - XVisualInfo vis; - int width, height; xw.scr = XDefaultScreen(xw.dpy); @@ -1321,23 +1346,30 @@ xinit(int cols, int rows) if (!FcInit()) die("could not init fontconfig.\n"); - usedfont = (opt_font == NULL)? fonts[currentfont] : opt_font; - - xloadfonts(usedfont, 0); + usedfont = (opt_font == NULL)? fonts[currentfont] : opt_font; + xloadfonts(usedfont, 0); /* spare fonts */ xloadsparefonts(); - /* Backup default alpha value */ - alpha_def = alpha; + /* Backup default alpha value */ + alpha_def = alpha; /* colors */ xw.cmap = XCreateColormap(xw.dpy, parent, xw.vis, None); xloadcols(); /* adjust fixed window geometry */ - win.w = 2 * win.hborderpx + 2 * borderpx + cols * win.cw; - win.h = 2 * win.vborderpx + 2 * borderpx + rows * win.ch; + switch (geometry) { + case CellGeometry: + win.w = 2 * win.hborderpx + 2 * borderpx + w * win.cw; + win.h = 2 * win.vborderpx + 2 * borderpx + h * win.ch; + break; + case PixelGeometry: + win.w = w; + win.h = h; + break; + } if (xw.gm & XNegative) xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2; if (xw.gm & YNegative) @@ -1404,6 +1436,9 @@ xinit(int cols, int rows) XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32, PropModeReplace, (uchar *)&thispid, 1); + xw.netwmstate = XInternAtom(xw.dpy, "_NET_WM_STATE", False); + xw.netwmfullscreen = XInternAtom(xw.dpy, "_NET_WM_STATE_FULLSCREEN", False); + win.mode = MODE_NUMLOCK; resettitle(); xhints(); @@ -1437,13 +1472,13 @@ 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 + win.cyo; 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; /* Skip dummy wide-character spacing. */ - if (mode & ATTR_WDUMMY) + if (mode == ATTR_WDUMMY) continue; /* Determine font for glyph if different from previous glyph. */ @@ -1462,7 +1497,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x font = &dc.bfont; frcflags = FRC_BOLD; } - yp = winy + font->ascent + win.cyo; + yp = winy + font->ascent; } if (mode & ATTR_BOXDRAW) { @@ -1475,9 +1510,8 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x if (glyphidx) { specs[numspecs].font = font->match; specs[numspecs].glyph = glyphidx; - specs[numspecs].x = (short)xp + cxoffset; + specs[numspecs].x = (short)xp + cxoffset; specs[numspecs].y = (short)yp + cyoffset; - xp += runewidth; numspecs++; continue; @@ -1556,14 +1590,29 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x numspecs++; } - /* Harfbuzz transformation for ligatures. */ - hbtransform(specs, glyphs, len, x, y); - return numspecs; } void -xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y) +chgalpha(const Arg *arg) +{ + if (arg->f == -1.0f && alpha >= 0.1f) + alpha -= 0.1f; + else if (arg->f == 1.0f && alpha < 1.0f) + alpha += 0.1f; + else if (arg->f == 0.0f) + alpha = alpha_def; + else + return; + + dc.col[defaultbg].color.alpha = (unsigned short)(0xFFFF * alpha); + /* Required to remove artifacting from borderpx */ + cresize(0, 0); + redraw(); +} + +void +xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y, int dmode) { int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1); int winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch, @@ -1643,9 +1692,14 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i } if (base.mode & ATTR_REVERSE) { - temp = fg; - fg = bg; - bg = temp; + if (bg == fg) { + bg = &dc.col[defaultfg]; + fg = &dc.col[defaultbg]; + } else { + temp = fg; + fg = bg; + bg = temp; + } } if (base.mode & ATTR_BLINK && win.mode & MODE_BLINK) @@ -1654,51 +1708,45 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i if (base.mode & ATTR_INVISIBLE) fg = bg; - /* Intelligent cleaning up of the borders. */ - if (x == 0) { - xclear(0, (y == 0)? 0 : winy, win.hborderpx, - winy + win.ch + - ((winy + win.ch >= win.vborderpx + win.th)? win.h : 0)); - } - if (winx + width >= win.hborderpx + win.tw) { - xclear(winx + width, (y == 0)? 0 : winy, win.w, - ((winy + win.ch >= win.vborderpx + win.th)? win.h : (winy + win.ch))); - } - if (y == 0) - 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. */ - XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); - - /* Set the clip region because Xft is sometimes dirty. */ - r.x = 0; - r.y = 0; - r.height = win.ch; - r.width = width; - XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1); - - if (base.mode & ATTR_BOXDRAW) { - drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len); - } else { - /* Render the glyphs. */ - XftDrawGlyphFontSpec(xw.draw, fg, specs, len); - } - - /* Render underline and strikethrough. */ - if (base.mode & ATTR_UNDERLINE) { - XftDrawRect(xw.draw, fg, winx, winy + win.cyo + dc.font.ascent * chscale + 1, - width, 1); - } - - if (base.mode & ATTR_STRUCK) { - XftDrawRect(xw.draw, fg, winx, winy + win.cyo + 2 * dc.font.ascent * chscale / 3, - width, 1); - } - - /* Reset clip to none. */ - XftDrawSetClip(xw.draw, 0); + if (dmode & DRAW_BG) { + /* Intelligent cleaning up of the borders. */ + if (x == 0) { + xclear(0, (y == 0)? 0 : winy, win.hborderpx, + winy + win.ch + + ((winy + win.ch >= win.vborderpx + win.th)? win.h : 0)); + } + if (winx + width >= win.hborderpx + win.tw) { + xclear(winx + width, (y == 0)? 0 : winy, win.w, + ((winy + win.ch >= win.vborderpx + win.th)? win.h : (winy + win.ch))); + } + if (y == 0) + 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. */ + XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); + } + + if (dmode & DRAW_FG) { + if (base.mode & ATTR_BOXDRAW) { + drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len); + } else { + /* Render the glyphs. */ + XftDrawGlyphFontSpec(xw.draw, fg, specs, len); + } + + /* Render underline and strikethrough. */ + if (base.mode & ATTR_UNDERLINE || base.mode & ATTR_URL) { + XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent * chscale + 1, + width, 1); + } + + if (base.mode & ATTR_STRUCK) { + XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent * chscale / 3, + width, 1); + } + } } void @@ -1708,21 +1756,19 @@ xdrawglyph(Glyph g, int x, int y) XftGlyphFontSpec spec; numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y); - xdrawglyphfontspecs(&spec, g, numspecs, x, y); + xdrawglyphfontspecs(&spec, g, numspecs, x, y, DRAW_BG | DRAW_FG); } void -xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line line, int len) +xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) { Color drawcol; + XRenderColor colbg; /* remove the old cursor */ if (selected(ox, oy)) og.mode ^= ATTR_REVERSE; - - /* Redraw the line where cursor was previously. - * It will restore the ligatures broken by the cursor. */ - xdrawline(line, 0, oy, len); + xdrawglyph(og, ox, oy); if (IS_SET(MODE_HIDE)) return; @@ -1746,22 +1792,31 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line line, int le if (selected(cx, cy)) { g.fg = defaultfg; g.bg = defaultrcs; + } else if (!(og.mode & ATTR_REVERSE)) { + unsigned long col = g.bg; + g.bg = g.fg; + g.fg = col; + } + + if (IS_TRUECOL(g.bg)) { + colbg.alpha = 0xffff; + colbg.red = TRUERED(g.bg); + colbg.green = TRUEGREEN(g.bg); + colbg.blue = TRUEBLUE(g.bg); + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, &drawcol); } else { - g.fg = defaultbg; - g.bg = defaultcs; + drawcol = dc.col[g.bg]; } - drawcol = dc.col[g.bg]; } /* draw the new one */ if (IS_SET(MODE_FOCUSED)) { switch (win.cursor) { - default: + default: case 0: /* blinking block */ case 1: /* blinking block (default) */ if (IS_SET(MODE_BLINK)) break; - /* FALLTHROUGH */ case 2: /* steady block */ xdrawglyph(g, cx, cy); @@ -1831,6 +1886,9 @@ xseticontitle(char *p) XTextProperty prop; DEFAULT(p, opt_title); + if (p[0] == '\0') + p = opt_title; + if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, &prop) != Success) return; @@ -1840,10 +1898,33 @@ xseticontitle(char *p) } void -xsettitle(char *p) +xfreetitlestack(void) { - XTextProperty prop; - DEFAULT(p, opt_title); + for (int i = 0; i < LEN(titlestack); i++) { + free(titlestack[i]); + titlestack[i] = NULL; + } +} + +void +xsettitle(char *p, int pop) +{ + XTextProperty prop; + + free(titlestack[tstki]); + if (pop) { + titlestack[tstki] = NULL; + tstki = (tstki - 1 + TITLESTACKSIZE) % TITLESTACKSIZE; + p = titlestack[tstki] ? titlestack[tstki] : opt_title; + } else if (p) { + titlestack[tstki] = xstrdup(p); + } else { + titlestack[tstki] = NULL; + p = opt_title; + } + + if (p[0] == '\0') + p = opt_title; if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, &prop) != Success) @@ -1853,41 +1934,60 @@ xsettitle(char *p) XFree(prop.value); } +void +xpushtitle(void) +{ + int tstkin = (tstki + 1) % TITLESTACKSIZE; + + free(titlestack[tstkin]); + titlestack[tstkin] = titlestack[tstki] ? xstrdup(titlestack[tstki]) : NULL; + tstki = tstkin; +} + int xstartdraw(void) { + if (IS_SET(MODE_VISIBLE)) + XCopyArea(xw.dpy, xw.win, xw.buf, dc.gc, 0, 0, win.w, win.h, 0, 0); return IS_SET(MODE_VISIBLE); } void xdrawline(Line line, int x1, int y1, int x2) { - int i, x, ox, numspecs; + int i, x, ox, numspecs, numspecs_cached; Glyph base, new; - XftGlyphFontSpec *specs = xw.specbuf; - - numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1); - i = ox = 0; - for (x = x1; x < x2 && i < numspecs; x++) { - new = line[x]; - if (new.mode == ATTR_WDUMMY) - continue; - if (selected(x, y1)) - new.mode ^= ATTR_REVERSE; - if (i > 0 && ATTRCMP(base, new)) { - xdrawglyphfontspecs(specs, base, i, ox, y1); - specs += i; - numspecs -= i; - i = 0; - } - if (i == 0) { - ox = x; - base = new; + XftGlyphFontSpec *specs; + + numspecs_cached = xmakeglyphfontspecs(xw.specbuf, &line[x1], x2 - x1, x1, y1); + + /* Draw line in 2 passes: background and foreground. This way wide glyphs + won't get truncated (#223) */ + for (int dmode = DRAW_BG; dmode <= DRAW_FG; dmode <<= 1) { + specs = xw.specbuf; + numspecs = numspecs_cached; + i = ox = 0; + for (x = x1; x < x2 && i < numspecs; x++) { + new = line[x]; + if (new.mode == ATTR_WDUMMY) + continue; + if (selected(x, y1)) + new.mode ^= ATTR_REVERSE; + if (i > 0 && ATTRCMP(base, new)) { + xdrawglyphfontspecs(specs, base, i, ox, y1, dmode); + specs += i; + numspecs -= i; + i = 0; + } + if (i == 0) { + ox = x; + base = new; + } + i++; } - i++; + if (i > 0) + xdrawglyphfontspecs(specs, base, i, ox, y1, dmode); } - if (i > 0) - xdrawglyphfontspecs(specs, base, i, ox, y1); } void @@ -1944,6 +2044,12 @@ xsetmode(int set, unsigned int flags) { int mode = win.mode; MODBIT(win.mode, set, flags); + if (flags & MODE_MOUSE) { + if (win.mode & MODE_MOUSE) + XUndefineCursor(xw.dpy, xw.win); + else + XDefineCursor(xw.dpy, xw.win, cursor); + } if ((win.mode & MODE_REVERSE) != (mode & MODE_REVERSE)) redraw(); } @@ -1996,7 +2102,7 @@ focus(XEvent *ev) ttywrite("\033[I", 3, 0); if (!focused) { focused = 1; - xloadcols(); + xloadalpha(); tfulldirt(); } } else { @@ -2007,7 +2113,7 @@ focus(XEvent *ev) ttywrite("\033[O", 3, 0); if (focused) { focused = 0; - xloadcols(); + xloadalpha(); tfulldirt(); } } @@ -2060,11 +2166,9 @@ void kpress(XEvent *ev) { XKeyEvent *e = &ev->xkey; - KeySym ksym; - char *buf = NULL, *customkey; - int len = 0; - int buf_size = 64; - int critical = - 1; + KeySym ksym = NoSymbol; + char buf[64], *customkey; + int len; Rune c; Status status; Shortcut *bp; @@ -2072,44 +2176,51 @@ kpress(XEvent *ev) if (IS_SET(MODE_KBDLOCK)) return; -reallocbuf: - if (critical > 0) - goto cleanup; - if (buf) - free(buf); - - buf = xmalloc((buf_size) * sizeof(char)); - critical += 1; - if (xw.ime.xic) { - len = XmbLookupString(xw.ime.xic, e, buf, buf_size, &ksym, &status); - if (status == XBufferOverflow) { - buf_size = len; - goto reallocbuf; - } + len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status); + if (status == XBufferOverflow) + return; } else { - // Not sure how to fix this and if it is fixable - // but at least it does write something into the buffer - // so it is not as critical - len = XLookupString(e, buf, buf_size, &ksym, NULL); + len = XLookupString(e, buf, sizeof buf, &ksym, NULL); + } + + /* KeyRelease not relevant to shortcuts */ + if (ev->type == KeyRelease) + return; + + if ( IS_SET(MODE_KBDSELECT) ) { + if ( match(XK_NO_MOD, e->state) || + (XK_Shift_L | XK_Shift_R) & e->state ) + win.mode ^= trt_kbdselect(ksym, buf, len); + return; } + /* 1. shortcuts */ for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { if (ksym == bp->keysym && match(bp->mod, e->state)) { + if (bp -> func != autocomplete) + autocomplete ((const Arg []) { ACMPL_DEACTIVATE }); bp->func(&(bp->arg)); - goto cleanup; + return; } } + if (!( + len == 0 && + e -> state & ~ignoremod // ACMPL_ISSUE: I'm not sure that this is the right way + | ALTCTRL == ALTCTRL + )) + autocomplete ((const Arg []) { ACMPL_DEACTIVATE }); + /* 2. custom keys from config.h */ if ((customkey = kmap(ksym, e->state))) { ttywrite(customkey, strlen(customkey), 1); - goto cleanup; + return; } /* 3. composed string from input method */ if (len == 0) - goto cleanup; + return; if (len == 1 && e->state & Mod1Mask) { if (IS_SET(MODE_8BIT)) { if (*buf < 0177) { @@ -2122,11 +2233,7 @@ reallocbuf: len = 2; } } - if (len <= buf_size) - ttywrite(buf, len, 1); -cleanup: - if (buf) - free(buf); + ttywrite(buf, len, 1); } void @@ -2237,7 +2344,6 @@ run(void) win.mode ^= MODE_BLINK; } lastblink = now; - drawing = 1; } timeout = (maxlatency - TIMEDIFF(now, trigger)) \ @@ -2322,16 +2428,24 @@ config_init(void) void usage(void) { - die("usage: %s [-aiv] [-c class] [-f font] [-g geometry]" + die("usage: %s [-aiv] [-b borderpx] [-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]" + " %s [-aiv] [-b borderpx] [-c class] [-f font] [-g geometry]" " [-n name] [-o file]\n" " [-T title] [-t title] [-w windowid] -l line" " [stty_args ...]\n", argv0, argv0); } +void toggle_winmode(int flag) { + win.mode ^= flag; +} + +void keyboard_select(const Arg *dummy) { + win.mode ^= trt_kbdselect(-1, NULL, 0); +} + int main(int argc, char *argv[]) { @@ -2343,6 +2457,9 @@ main(int argc, char *argv[]) case 'a': allowaltscreen = 0; break; + case 'b': + borderpx = atoi(EARGF(usage())); + break; case 'A': opt_alpha = EARGF(usage()); break; @@ -2359,6 +2476,12 @@ main(int argc, char *argv[]) case 'g': xw.gm = XParseGeometry(EARGF(usage()), &xw.l, &xw.t, &cols, &rows); + geometry = CellGeometry; + break; + case 'G': + xw.gm = XParseGeometry(EARGF(usage()), + &xw.l, &xw.t, &width, &height); + geometry = PixelGeometry; break; case 'i': xw.isfixed = 1; @@ -2400,12 +2523,20 @@ run: die("Can't open display\n"); config_init(); + switch (geometry) { + case CellGeometry: + xinit(cols, rows); + break; + case PixelGeometry: + xinit(width, height); + cols = (win.w - 2 * borderpx) / win.cw; + rows = (win.h - 2 * borderpx) / win.ch; + break; + } cols = MAX(cols, 1); rows = MAX(rows, 1); defaultbg = MAX(LEN(colorname), 256); - alphaUnfocus = alpha-alphaOffset; tnew(cols, rows); - xinit(cols, rows); xsetenv(); selinit(); run(); @@ -2413,3 +2544,24 @@ run: return 0; } +void +opencopied(const Arg *arg) +{ + char * const clip = xsel.clipboard; + pid_t chpid; + + if(!clip) { + fprintf(stderr, "Warning: nothing copied to clipboard\n"); + return; + } + + if ((chpid = fork()) == 0) { + if (fork() == 0) + execlp(arg->v, arg->v, clip, NULL); + exit(1); + } + if (chpid > 0) + waitpid(chpid, NULL, WNOHANG); // Non-blocking wait + return; +} + -- cgit v1.2.3