Xinqi Bao's Git

minor update for patch xresources
[st.git] / x.c
diff --git a/x.c b/x.c
index 89786b8..b5acc4c 100644 (file)
--- a/x.c
+++ b/x.c
@@ -14,6 +14,7 @@
 #include <X11/keysym.h>
 #include <X11/Xft/Xft.h>
 #include <X11/XKBlib.h>
+#include <X11/Xresource.h>
 
 char *argv0;
 #include "arg.h"
@@ -45,6 +46,19 @@ typedef struct {
        signed char appcursor; /* application cursor */
 } Key;
 
+/* Xresources preferences */
+enum resource_type {
+       STRING = 0,
+       INTEGER = 1,
+       FLOAT = 2
+};
+
+typedef struct {
+       char *name;
+       enum resource_type type;
+       void *dst;
+} ResourcePref;
+
 /* X modifiers */
 #define XK_ANY_MOD    UINT_MAX
 #define XK_NO_MOD     0
@@ -81,6 +95,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 */
@@ -105,6 +120,7 @@ typedef struct {
        XSetWindowAttributes attrs;
        int scr;
        int isfixed; /* is fixed geometry? */
+       int depth; /* bit depth */
        int l, t; /* left and top offset */
        int gm; /* geometry mask */
 } XWindow;
@@ -243,6 +259,7 @@ static char *usedfont = NULL;
 static double usedfontsize = 0;
 static double defaultfontsize = 0;
 
+static char *opt_alpha = NULL;
 static char *opt_class = NULL;
 static char **opt_cmd  = NULL;
 static char *opt_embed = NULL;
@@ -252,7 +269,7 @@ static char *opt_line  = NULL;
 static char *opt_name  = NULL;
 static char *opt_title = NULL;
 
-static int oldbutton = 3; /* button event on startup: 3 = release */
+static uint buttons; /* bit field of pressed buttons */
 
 void
 clipcopy(const Arg *dummy)
@@ -331,7 +348,7 @@ ttysend(const Arg *arg)
 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 +356,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;
 }
@@ -364,61 +381,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 >= 7)
-                               button += 128 - 7;
-                       else 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,
-                               e->xbutton.type == ButtonRelease ? 'm' : 'M');
+                               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;
        }
@@ -461,9 +485,13 @@ mouseaction(XEvent *e, uint release)
 void
 bpress(XEvent *e)
 {
+       int btn = e->xbutton.button;
        struct timespec now;
        int snap;
 
+       if (1 <= btn && btn <= 11)
+               buttons |= 1 << (btn-1);
+
        if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
                mousereport(e);
                return;
@@ -472,7 +500,7 @@ bpress(XEvent *e)
        if (mouseaction(e, 0))
                return;
 
-       if (e->xbutton.button == Button1) {
+       if (btn == Button1) {
                /*
                 * If the user clicks below predefined timeouts specific
                 * snapping behaviour is exposed.
@@ -686,6 +714,11 @@ xsetsel(char *str)
 void
 brelease(XEvent *e)
 {
+       int btn = e->xbutton.button;
+
+       if (1 <= btn && btn <= 11)
+               buttons &= ~(1 << (btn-1));
+
        if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
                mousereport(e);
                return;
@@ -693,7 +726,7 @@ brelease(XEvent *e)
 
        if (mouseaction(e, 1))
                return;
-       if (e->xbutton.button == Button1)
+       if (btn == Button1)
                mousesel(e, 1);
 }
 
@@ -723,6 +756,9 @@ cresize(int width, int height)
        col = MAX(1, col);
        row = MAX(1, row);
 
+       win.hborderpx = (win.w - col * win.cw) / 2;
+       win.vborderpx = (win.h - row * win.ch) / 2;
+
        tresize(col, row);
        xresize(col, row);
        ttyresize(win.tw, win.th);
@@ -736,7 +772,7 @@ 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));
+                       xw.depth);
        XftDrawChange(xw.draw, xw.buf);
        xclear(0, 0, win.w, win.h);
 
@@ -796,9 +832,29 @@ xloadcols(void)
                        else
                                die("could not allocate color %d\n", i);
                }
+
+       /* set alpha value of bg color */
+       if (opt_alpha)
+               alpha = strtof(opt_alpha, NULL);
+       dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * alpha);
+       dc.col[defaultbg].pixel &= 0x00FFFFFF;
+       dc.col[defaultbg].pixel |= (unsigned char)(0xff * alpha) << 24;
        loaded = 1;
 }
 
+int
+xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b)
+{
+       if (!BETWEEN(x, 0, dc.collen))
+               return 1;
+
+       *r = dc.col[x].color.red >> 8;
+       *g = dc.col[x].color.green >> 8;
+       *b = dc.col[x].color.blue >> 8;
+
+       return 0;
+}
+
 int
 xsetcolorname(int x, const char *name)
 {
@@ -830,8 +886,8 @@ xclear(int x1, int y1, int x2, int y2)
 void
 xhints(void)
 {
-       XClassHint class = {opt_name ? opt_name : termname,
-                           opt_class ? opt_class : termname};
+       XClassHint class = {opt_name ? opt_name : "st",
+                           opt_class ? opt_class : "St"};
        XWMHints wm = {.flags = InputHint, .input = 1};
        XSizeHints *sizeh;
 
@@ -840,8 +896,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;
@@ -1105,11 +1161,21 @@ xinit(int cols, int rows)
        Window parent;
        pid_t thispid = getpid();
        XColor xmousefg, xmousebg;
+       XWindowAttributes attr;
+       XVisualInfo vis;
 
-       if (!(xw.dpy = XOpenDisplay(NULL)))
-               die("can't open display\n");
        xw.scr = XDefaultScreen(xw.dpy);
-       xw.vis = XDefaultVisual(xw.dpy, xw.scr);
+
+       if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0)))) {
+               parent = XRootWindow(xw.dpy, xw.scr);
+               xw.depth = 32;
+       } else {
+               XGetWindowAttributes(xw.dpy, parent, &attr);
+               xw.depth = attr.depth;
+       }
+
+       XMatchVisualInfo(xw.dpy, xw.scr, xw.depth, TrueColor, &vis);
+       xw.vis = vis.visual;
 
        /* font */
        if (!FcInit())
@@ -1119,12 +1185,12 @@ xinit(int cols, int rows)
        xloadfonts(usedfont, 0);
 
        /* colors */
-       xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
+       xw.cmap = XCreateColormap(xw.dpy, parent, xw.vis, None);
        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)
@@ -1139,19 +1205,15 @@ xinit(int cols, int rows)
                | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
        xw.attrs.colormap = xw.cmap;
 
-       if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0))))
-               parent = XRootWindow(xw.dpy, xw.scr);
        xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t,
-                       win.w, win.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
+                       win.w, win.h, 0, xw.depth, InputOutput,
                        xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity
                        | CWEventMask | CWColormap, &xw.attrs);
 
        memset(&gcvalues, 0, sizeof(gcvalues));
        gcvalues.graphics_exposures = False;
-       dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures,
-                       &gcvalues);
-       xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
-                       DefaultDepth(xw.dpy, xw.scr));
+       xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, xw.depth);
+       dc.gc = XCreateGC(xw.dpy, xw.buf, GCGraphicsExposures, &gcvalues);
        XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
        XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
 
@@ -1213,7 +1275,7 @@ xinit(int cols, int rows)
 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;
@@ -1346,7 +1408,7 @@ 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;
@@ -1436,17 +1498,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.vborderpx,
                        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. */
@@ -1464,12 +1526,12 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
 
        /* Render underline and strikethrough. */
        if (base.mode & ATTR_UNDERLINE) {
-               XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1,
+               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 / 3,
+               XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent * chscale / 3,
                                width, 1);
        }
 
@@ -1540,35 +1602,35 @@ 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);
        }
 }
@@ -1982,6 +2044,59 @@ run(void)
        }
 }
 
+int
+resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst)
+{
+       char **sdst = dst;
+       int *idst = dst;
+       float *fdst = dst;
+
+       char fullname[256];
+       char fullclass[256];
+       char *type;
+       XrmValue ret;
+
+       snprintf(fullname, sizeof(fullname), "%s.%s",
+                       opt_name ? opt_name : "st", name);
+       snprintf(fullclass, sizeof(fullclass), "%s.%s",
+                       opt_class ? opt_class : "St", name);
+       fullname[sizeof(fullname) - 1] = fullclass[sizeof(fullclass) - 1] = '\0';
+
+       XrmGetResource(db, fullname, fullclass, &type, &ret);
+       if (ret.addr == NULL || strncmp("String", type, 64))
+               return 1;
+
+       switch (rtype) {
+       case STRING:
+               *sdst = ret.addr;
+               break;
+       case INTEGER:
+               *idst = strtoul(ret.addr, NULL, 10);
+               break;
+       case FLOAT:
+               *fdst = strtof(ret.addr, NULL);
+               break;
+       }
+       return 0;
+}
+
+void
+config_init(void)
+{
+       char *resm;
+       XrmDatabase db;
+       ResourcePref *p;
+
+       XrmInitialize();
+       resm = XResourceManagerString(xw.dpy);
+       if (!resm)
+               return;
+
+       db = XrmGetStringDatabase(resm);
+       for (p = resources; p < resources + LEN(resources); p++)
+               resource_load(db, p->name, p->type, p->dst);
+}
+
 void
 usage(void)
 {
@@ -2006,6 +2121,9 @@ main(int argc, char *argv[])
        case 'a':
                allowaltscreen = 0;
                break;
+       case 'A':
+               opt_alpha = EARGF(usage());
+               break;
        case 'c':
                opt_class = EARGF(usage());
                break;
@@ -2055,6 +2173,11 @@ run:
 
        setlocale(LC_CTYPE, "");
        XSetLocaleModifiers("");
+
+       if(!(xw.dpy = XOpenDisplay(NULL)))
+               die("Can't open display\n");
+
+       config_init();
        cols = MAX(cols, 1);
        rows = MAX(rows, 1);
        tnew(cols, rows);