[hackers] [dwm][patch] xkb indicator patch for 6.4

From: Evgenii Morozov <jmv_AT_emorozov.net>
Date: Wed, 30 Nov 2022 23:38:05 +0300

Hello,

Updated this patch: https://dwm.suckless.org/patches/xkb/ for
compatibility with 6.4. Haven't tested it thoroughly yet, but seems to work.

---
  config.def.h |  13 ++++--
  dwm.c        | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++
  2 files changed, 126 insertions(+), 3 deletions(-)
diff --git a/config.def.h b/config.def.h
index 061ad66..4170feb 100644
--- a/config.def.h
+++ b/config.def.h
_AT_@ -26,9 +26,9 @@ static const Rule rules[] = {
       *    WM_CLASS(STRING) = instance, class
       *    WM_NAME(STRING) = title
       */
-    /* class      instance    title       tags mask isfloating   monitor */
-    { "Gimp",     NULL,       NULL,       0, 1,           -1 },
-    { "Firefox",  NULL,       NULL,       1 << 8, 0,           -1 },
+    /* class      instance    title       tags mask isfloating   
monitor xkb_layout */
+    { "Gimp",     NULL,       NULL,       0, 1,           -1,    0 },
+    { "Firefox",  NULL,       NULL,       1 << 8, 0,           -1,    -1 },
  };
  /* layout(s) */
_AT_@ -37,6 +37,13 @@ static const int nmaster     = 1;    /* number of 
clients in master area */
  static const int resizehints = 1;    /* 1 means respect size hints in 
tiled resizals */
  static const int lockfullscreen = 1; /* 1 will force focus on the 
fullscreen window */
+/* xkb frontend */
+static const Bool showxkb         = True; /* False means no xkb layout 
text */
+static const char *xkb_layouts [] = {
+    "en",
+    "ru",
+};
+
  static const Layout layouts[] = {
      /* symbol     arrange function */
      { "[]=",      tile },    /* first entry is default */
diff --git a/dwm.c b/dwm.c
index e5efb6a..5e3e3ca 100644
--- a/dwm.c
+++ b/dwm.c
_AT_@ -36,6 +36,7 @@
  #include <X11/Xlib.h>
  #include <X11/Xproto.h>
  #include <X11/Xutil.h>
+#include <X11/XKBlib.h>
  #ifdef XINERAMA
  #include <X11/extensions/Xinerama.h>
  #endif /* XINERAMA */
_AT_@ -84,6 +85,7 @@ typedef struct {
  typedef struct Monitor Monitor;
  typedef struct Client Client;
+typedef struct XkbInfo XkbInfo;
  struct Client {
      char name[256];
      float mina, maxa;
_AT_@ -97,6 +99,13 @@ struct Client {
      Client *snext;
      Monitor *mon;
      Window win;
+    XkbInfo *xkb;
+};
+struct XkbInfo {
+    XkbInfo *next;
+    XkbInfo *prev;
+    int group;
+    Window w;
  };
  typedef struct {
_AT_@ -139,6 +148,7 @@ typedef struct {
      unsigned int tags;
      int isfloating;
      int monitor;
+    int xkb_layout;
  } Rule;
  /* function declarations */
_AT_@ -157,6 +167,7 @@ static void configure(Client *c);
  static void configurenotify(XEvent *e);
  static void configurerequest(XEvent *e);
  static Monitor *createmon(void);
+static XkbInfo *createxkb(Window w);
  static void destroynotify(XEvent *e);
  static void detach(Client *c);
  static void detachstack(Client *c);
_AT_@ -165,6 +176,7 @@ static void drawbar(Monitor *m);
  static void drawbars(void);
  static void enternotify(XEvent *e);
  static void expose(XEvent *e);
+static XkbInfo *findxkb(Window w);
  static void focus(Client *c);
  static void focusin(XEvent *e);
  static void focusmon(const Arg *arg);
_AT_@ -233,6 +245,7 @@ static Monitor *wintomon(Window w);
  static int xerror(Display *dpy, XErrorEvent *ee);
  static int xerrordummy(Display *dpy, XErrorEvent *ee);
  static int xerrorstart(Display *dpy, XErrorEvent *ee);
+static void xkbeventnotify(XEvent *e);
  static void zoom(const Arg *arg);
  /* variables */
_AT_@ -244,6 +257,7 @@ static int bh;               /* bar height */
  static int lrpad;            /* sum of left and right padding for text */
  static int (*xerrorxlib)(Display *, XErrorEvent *);
  static unsigned int numlockmask = 0;
+static int xkbEventType = 0;
  static void (*handler[LASTEvent]) (XEvent *) = {
      [ButtonPress] = buttonpress,
      [ClientMessage] = clientmessage,
_AT_@ -268,6 +282,8 @@ static Display *dpy;
  static Drw *drw;
  static Monitor *mons, *selmon;
  static Window root, wmcheckwin;
+static XkbInfo xkbGlobal;
+static XkbInfo *xkbSaved = NULL;
  /* configuration, allows nested code to access above variables */
  #include "config.h"
_AT_@ -303,6 +319,9 @@ applyrules(Client *c)
              for (m = mons; m && m->num != r->monitor; m = m->next);
              if (m)
                  c->mon = m;
+            if(r->xkb_layout > -1 ) {
+                c->xkb->group = r->xkb_layout;
+            }
          }
      }
      if (ch.res_class)
_AT_@ -647,6 +666,25 @@ createmon(void)
      strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
      return m;
  }
+static XkbInfo *
+createxkb(Window w){
+    XkbInfo *xkb;
+
+    xkb = malloc(sizeof *xkb);
+    if (xkb == NULL) {
+        die("fatal: could not malloc() %u bytes\n", sizeof *xkb);
+    }
+    xkb->group = xkbGlobal.group;
+    xkb->w = w;
+    xkb->next = xkbSaved;
+    if (xkbSaved != NULL) {
+        xkbSaved->prev = xkb;
+    }
+    xkb->prev = NULL;
+    xkbSaved = xkb;
+
+    return xkb;
+}
  void
  destroynotify(XEvent *e)
_AT_@ -700,6 +738,7 @@ void
  drawbar(Monitor *m)
  {
      int x, w, tw = 0;
+    int ww = 0;
      int boxs = drw->fonts->h / 9;
      int boxw = drw->fonts->h / 6 + 2;
      unsigned int i, occ = 0, urg = 0;
_AT_@ -712,7 +751,15 @@ drawbar(Monitor *m)
      if (m == selmon) { /* status is only drawn on selected monitor */
          drw_setscheme(drw, scheme[SchemeNorm]);
          tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
+        if (showxkb) {
+            ww = TEXTW(xkb_layouts[xkbGlobal.group]);
+        }
          drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
+        if (showxkb) {
+            drw_setscheme(drw, scheme[SchemeNorm]);
+            drw_text(drw, m->ww - tw - ww, 0, ww, bh, 0, 
xkb_layouts[xkbGlobal.group], 0);
+            tw += ww;
+        }
      }
      for (c = m->clients; c; c = c->next) {
_AT_@ -777,6 +824,18 @@ enternotify(XEvent *e)
      focus(c);
  }
+XkbInfo *
+findxkb(Window w)
+{
+    XkbInfo *xkb;
+    for (xkb = xkbSaved; xkb != NULL; xkb=xkb->next) {
+        if (xkb->w == w) {
+            return xkb;
+        }
+    }
+    return NULL;
+}
+
  void
  expose(XEvent *e)
  {
_AT_@ -1025,6 +1084,7 @@ manage(Window w, XWindowAttributes *wa)
      Client *c, *t = NULL;
      Window trans = None;
      XWindowChanges wc;
+    XkbInfo *xkb;
      c = ecalloc(1, sizeof(Client));
      c->win = w;
_AT_@ -1036,6 +1096,14 @@ manage(Window w, XWindowAttributes *wa)
      c->oldbw = wa->border_width;
      updatetitle(c);
+
+    /* Setting current xkb state must be before applyrules */
+    xkb = findxkb(c->win);
+    if (xkb == NULL) {
+        xkb = createxkb(c->win);
+    }
+    c->xkb = xkb;
+
      if (XGetTransientForHint(dpy, w, &trans) && (t = 
wintoclient(trans))) {
          c->mon = t->mon;
          c->tags = t->tags;
_AT_@ -1377,8 +1445,14 @@ run(void)
      /* main event loop */
      XSync(dpy, False);
      while (running && !XNextEvent(dpy, &ev))
+    {
+        if(ev.type == xkbEventType) {
+            xkbeventnotify(&ev);
+            continue;
+        }
          if (handler[ev.type])
              handler[ev.type](&ev); /* call handler */
+    }
  }
  void
_AT_@ -1466,6 +1540,7 @@ setfocus(Client *c)
          XChangeProperty(dpy, root, netatom[NetActiveWindow],
              XA_WINDOW, 32, PropModeReplace,
              (unsigned char *) &(c->win), 1);
+        XkbLockGroup(dpy, XkbUseCoreKbd, c->xkb->group);
      }
      sendevent(c, wmatom[WMTakeFocus]);
  }
_AT_@ -1533,6 +1608,7 @@ setup(void)
      int i;
      XSetWindowAttributes wa;
      Atom utf8string;
+    XkbStateRec xkbstate;
      /* clean up any zombies immediately */
      sigchld(0);
_AT_@ -1593,6 +1669,16 @@ setup(void)
          |LeaveWindowMask|StructureNotifyMask|PropertyChangeMask;
      XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
      XSelectInput(dpy, root, wa.event_mask);
+
+    /* get xkb extension info, events and current state */
+    if (!XkbQueryExtension(dpy, NULL, &xkbEventType, NULL, NULL, NULL)) {
+        fputs("warning: can not query xkb extension\n", stderr);
+    }
+    XkbSelectEventDetails(dpy, XkbUseCoreKbd, XkbStateNotify,
+                          XkbAllStateComponentsMask, XkbGroupStateMask);
+    XkbGetState(dpy, XkbUseCoreKbd, &xkbstate);
+    xkbGlobal.group = xkbstate.locked_group;
+
      grabkeys();
      focus(NULL);
  }
_AT_@ -1762,6 +1848,7 @@ unmanage(Client *c, int destroyed)
  {
      Monitor *m = c->mon;
      XWindowChanges wc;
+    XkbInfo *xkb;
      detach(c);
      detachstack(c);
_AT_@ -1777,6 +1864,18 @@ unmanage(Client *c, int destroyed)
          XSetErrorHandler(xerror);
          XUngrabServer(dpy);
      }
+    else {
+        xkb = findxkb(c->win);
+        if (xkb != NULL) {
+            if (xkb->prev) {
+                xkb->prev->next = xkb->next;
+            }
+            if (xkb->next) {
+                xkb->next->prev = xkb->prev;
+            }
+            free(xkb);
+        }
+    }
      free(c);
      focus(NULL);
      updateclientlist();
_AT_@ -2110,6 +2209,23 @@ xerrorstart(Display *dpy, XErrorEvent *ee)
      return -1;
  }
+void xkbeventnotify(XEvent *e)
+{
+    XkbEvent *ev;
+
+    ev = (XkbEvent *) e;
+    switch (ev->any.xkb_type) {
+    case XkbStateNotify:
+        xkbGlobal.group = ev->state.locked_group;
+        if (selmon != NULL && selmon->sel != NULL) {
+            selmon->sel->xkb->group = xkbGlobal.group;
+        }
+        if (showxkb) {
+            drawbars();
+        }
+        break;
+    }
+}
  void
  zoom(const Arg *arg)
  {
-- 
2.38.1
Received on Wed Nov 30 2022 - 21:38:05 CET

This archive was generated by hypermail 2.3.0 : Wed Nov 30 2022 - 22:12:32 CET