]> git.armaanb.net Git - st.git/blobdiff - x.c
mouseshortcuts: fix custom modifier on release
[st.git] / x.c
diff --git a/x.c b/x.c
index c967caf2cf0ce3a548bc36414bb6410ae75fb3a4..4cf6b21ce97109703d09504849973daec2bebe38 100644 (file)
--- a/x.c
+++ b/x.c
@@ -33,6 +33,7 @@ typedef struct {
        uint button;
        void (*func)(const Arg *);
        const Arg arg;
+       uint  release;
 } MouseShortcut;
 
 typedef struct {
@@ -93,8 +94,12 @@ typedef struct {
        Drawable buf;
        GlyphFontSpec *specbuf; /* font spec buffer used for rendering */
        Atom xembed, wmdeletewin, netwmname, netwmpid;
-       XIM xim;
-       XIC xic;
+       struct {
+               XIM xim;
+               XIC xic;
+               XPoint spot;
+               XVaNestedList spotlist;
+       } ime;
        Draw draw;
        Visual *vis;
        XSetWindowAttributes attrs;
@@ -141,9 +146,10 @@ static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int);
 static void xdrawglyph(Glyph, int, int);
 static void xclear(int, int, int, int);
 static int xgeommasktogravity(int);
-static void ximopen(Display *);
+static int ximopen(Display *);
 static void ximinstantiate(Display *, XPointer, XPointer);
 static void ximdestroy(XIM, XPointer, XPointer);
+static int xicdestroy(XIC, XPointer, XPointer);
 static void xinit(int, int);
 static void cresize(int, int);
 static void xresize(int, int);
@@ -165,6 +171,8 @@ static void kpress(XEvent *);
 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 *);
@@ -416,11 +424,42 @@ 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)
 {
        struct timespec now;
-       MouseShortcut *ms;
        int snap;
 
        if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
@@ -428,13 +467,8 @@ bpress(XEvent *e)
                return;
        }
 
-       for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
-               if (e->xbutton.button == ms->button &&
-                   match(ms->mod, e->xbutton.state & ~forcemousemod)) {
-                       ms->func(&(ms->arg));
-                       return;
-               }
-       }
+       if (mouseaction(e, 0))
+               return;
 
        if (e->xbutton.button == Button1) {
                /*
@@ -655,9 +689,9 @@ brelease(XEvent *e)
                return;
        }
 
-       if (e->xbutton.button == Button2)
-               selpaste(NULL);
-       else if (e->xbutton.button == Button1)
+       if (mouseaction(e, 1))
+               return;
+       if (e->xbutton.button == Button1)
                mousesel(e, 1);
 }
 
@@ -1007,41 +1041,58 @@ xunloadfonts(void)
        xunloadfont(&dc.ibfont);
 }
 
-void
+int
 ximopen(Display *dpy)
 {
-       XIMCallback destroy = { .client_data = NULL, .callback = ximdestroy };
+       XIMCallback imdestroy = { .client_data = NULL, .callback = ximdestroy };
+       XICCallback icdestroy = { .client_data = NULL, .callback = xicdestroy };
 
-       if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
-               XSetLocaleModifiers("@im=local");
-               if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
-                       XSetLocaleModifiers("@im=");
-                       if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL)
-                               die("XOpenIM failed. Could not open input device.\n");
-               }
+       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 (XSetIMValues(xw.xim, XNDestroyCallback, &destroy, NULL) != NULL)
-               die("XSetIMValues failed. Could not set input method value.\n");
-       xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
-                               XNClientWindow, xw.win, XNFocusWindow, xw.win, NULL);
-       if (xw.xic == NULL)
-               die("XCreateIC failed. Could not obtain input method.\n");
+       if (xw.ime.xic == NULL)
+               fprintf(stderr, "XCreateIC: Could not create input context.\n");
+
+       return 1;
 }
 
 void
 ximinstantiate(Display *dpy, XPointer client, XPointer call)
 {
-       ximopen(dpy);
-       XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
-                                       ximinstantiate, NULL);
+       if (ximopen(dpy))
+               XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
+                                                ximinstantiate, NULL);
 }
 
 void
 ximdestroy(XIM xim, XPointer client, XPointer call)
 {
-       xw.xim = NULL;
+       xw.ime.xim = NULL;
        XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
-                                       ximinstantiate, NULL);
+                                      ximinstantiate, NULL);
+       XFree(xw.ime.spotlist);
+}
+
+int
+xicdestroy(XIC xim, XPointer client, XPointer call)
+{
+       xw.ime.xic = NULL;
+       return 1;
 }
 
 void
@@ -1109,7 +1160,10 @@ xinit(int cols, int rows)
        xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
 
        /* input methods */
-       ximopen(xw.dpy);
+       if (!ximopen(xw.dpy)) {
+               XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
+                                              ximinstantiate, NULL);
+       }
 
        /* white cursor, black outline */
        cursor = XCreateFontCursor(xw.dpy, mouseshape);
@@ -1140,8 +1194,8 @@ xinit(int cols, int rows)
 
        win.mode = MODE_NUMLOCK;
        resettitle();
-       XMapWindow(xw.dpy, xw.win);
        xhints();
+       XMapWindow(xw.dpy, xw.win);
        XSync(xw.dpy, False);
 
        clock_gettime(CLOCK_MONOTONIC, &xsel.tclick1);
@@ -1587,11 +1641,13 @@ xfinishdraw(void)
 void
 xximspot(int x, int y)
 {
-       XPoint spot = { borderpx + x * win.cw, borderpx + (y + 1) * win.ch };
-       XVaNestedList attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL);
+       if (xw.ime.xic == NULL)
+               return;
 
-       XSetICValues(xw.xic, XNPreeditAttributes, attr, NULL);
-       XFree(attr);
+       xw.ime.spot.x = borderpx + x * win.cw;
+       xw.ime.spot.y = borderpx + (y + 1) * win.ch;
+
+       XSetICValues(xw.ime.xic, XNPreeditAttributes, xw.ime.spotlist, NULL);
 }
 
 void
@@ -1668,13 +1724,15 @@ focus(XEvent *ev)
                return;
 
        if (ev->type == FocusIn) {
-               XSetICFocus(xw.xic);
+               if (xw.ime.xic)
+                       XSetICFocus(xw.ime.xic);
                win.mode |= MODE_FOCUSED;
                xseturgency(0);
                if (IS_SET(MODE_FOCUS))
                        ttywrite("\033[I", 3, 0);
        } else {
-               XUnsetICFocus(xw.xic);
+               if (xw.ime.xic)
+                       XUnsetICFocus(xw.ime.xic);
                win.mode &= ~MODE_FOCUSED;
                if (IS_SET(MODE_FOCUS))
                        ttywrite("\033[O", 3, 0);
@@ -1729,7 +1787,7 @@ kpress(XEvent *ev)
 {
        XKeyEvent *e = &ev->xkey;
        KeySym ksym;
-       char buf[32], *customkey;
+       char buf[64], *customkey;
        int len;
        Rune c;
        Status status;
@@ -1738,7 +1796,10 @@ kpress(XEvent *ev)
        if (IS_SET(MODE_KBDLOCK))
                return;
 
-       len = XmbLookupString(xw.xic, e, buf, sizeof buf, &ksym, &status);
+       if (xw.ime.xic)
+               len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status);
+       else
+               len = XLookupString(e, buf, sizeof buf, &ksym, NULL);
        /* 1. shortcuts */
        for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
                if (ksym == bp->keysym && match(bp->mod, e->state)) {