summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--config.def.h11
-rw-r--r--dwm.c87
-rw-r--r--patch/include.c3
-rw-r--r--patch/include.h3
-rw-r--r--patch/ipc.c9
-rw-r--r--patch/xkb.c67
-rw-r--r--patch/xkb.h7
-rw-r--r--patches.def.h7
8 files changed, 193 insertions, 1 deletions
diff --git a/config.def.h b/config.def.h
index 1ac028c..da77ebf 100644
--- a/config.def.h
+++ b/config.def.h
@@ -483,6 +483,9 @@ static const BarRule barrules[] = {
#elif BAR_STATUS_PATCH
{ 'A', 0, BAR_ALIGN_RIGHT, width_status, draw_status, click_status, "status" },
#endif // BAR_STATUS2D_PATCH | BAR_STATUSCMD_PATCH
+ #if XKB_PATCH
+ { 0, 0, BAR_ALIGN_RIGHT, width_xkb, draw_xkb, click_xkb, "xkb" },
+ #endif // XKB_PATCH
#if BAR_FLEXWINTITLE_PATCH
{ -1, 0, BAR_ALIGN_NONE, width_flexwintitle, draw_flexwintitle, click_flexwintitle, "flexwintitle" },
#elif BAR_TABGROUPS_PATCH
@@ -660,6 +663,14 @@ static const Layout layouts[] = {
};
#endif // FLEXTILE_DELUXE_LAYOUT
+#if XKB_PATCH
+/* xkb frontend */
+static const char *xkb_layouts[] = {
+ "en",
+ "ru",
+};
+#endif // XKB_PATCH
+
/* key definitions */
#define MODKEY Mod1Mask
#if COMBO_PATCH && SWAPTAGS_PATCH && TAGOTHERMONITOR_PATCH
diff --git a/dwm.c b/dwm.c
index 31061f6..4084ed6 100644
--- a/dwm.c
+++ b/dwm.c
@@ -55,6 +55,10 @@
#include <pango/pango.h>
#endif // BAR_PANGO_PATCH
+#if XKB_PATCH
+#include <X11/XKBlib.h>
+#endif // XKB_PATCH
+
#if SPAWNCMD_PATCH
#include <assert.h>
#include <libgen.h>
@@ -217,6 +221,9 @@ enum {
ClkWinTitle,
ClkClientWin,
ClkRootWin,
+ #if XKB_PATCH
+ ClkXKB,
+ #endif // XKB_PATCH
ClkLast
}; /* clicks */
@@ -303,6 +310,16 @@ typedef struct {
const Arg arg;
} Button;
+#if XKB_PATCH
+typedef struct XkbInfo XkbInfo;
+struct XkbInfo {
+ XkbInfo *next;
+ XkbInfo *prev;
+ int group;
+ Window w;
+};
+#endif // XKB_PATCH
+
typedef struct Client Client;
struct Client {
char name[256];
@@ -367,6 +384,9 @@ struct Client {
#if IPC_PATCH
ClientState prevstate;
#endif // IPC_PATCH
+ #if XKB_PATCH
+ XkbInfo *xkb;
+ #endif // XKB_PATCH
};
typedef struct {
@@ -496,9 +516,16 @@ typedef struct {
const char *floatpos;
#endif // FLOATPOS_PATCH
int monitor;
+ #if XKB_PATCH
+ int xkb_layout;
+ #endif // XKB_PATCH
} Rule;
+#if XKB_PATCH
+#define RULE(...) { .monitor = -1, .xkb_layout = -1, ##__VA_ARGS__ },
+#else
#define RULE(...) { .monitor = -1, ##__VA_ARGS__ },
+#endif // XKB_PATCH
/* Cross patch compatibility rule macro helper macros */
#define FLOATING , .isfloating = 1
@@ -688,6 +715,9 @@ static char rawestext[1024];
#endif // BAR_STATUS2D_PATCH | BAR_STATUSCMD_PATCH
#endif // BAR_EXTRASTATUS_PATCH
+#if XKB_PATCH
+static int xkbEventType = 0;
+#endif // XKB_PATCH
static int screen;
static int sw, sh; /* X display screen geometry width, height */
static int bh; /* bar geometry */
@@ -877,6 +907,10 @@ applyrules(Client *c)
}
}
#endif // SWITCHTAG_PATCH
+ #if XKB_PATCH
+ if (r->xkb_layout > -1)
+ c->xkb->group = r->xkb_layout;
+ #endif // XKB_PATCH
#if ONLY_ONE_RULE_MATCH_PATCH
break;
#endif // ONLY_ONE_RULE_MATCH_PATCH
@@ -2246,6 +2280,13 @@ manage(Window w, XWindowAttributes *wa)
c->cfact = 1.0;
#endif // CFACTS_PATCH
updatetitle(c);
+
+ #if XKB_PATCH
+ /* Setting current xkb state must be before applyrules */
+ if (!(c->xkb = findxkb(c->win)))
+ c->xkb = createxkb(c->win);
+ #endif // XKB_PATCH
+
if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) {
c->mon = t->mon;
c->tags = t->tags;
@@ -3018,9 +3059,20 @@ run(void)
XEvent ev;
/* main event loop */
XSync(dpy, False);
- while (running && !XNextEvent(dpy, &ev))
+ while (running && !XNextEvent(dpy, &ev)) {
+
+ #if XKB_PATCH
+ /* Unfortunately the xkbEventType is not constant hence it can't be part of the
+ * normal event handler below */
+ if (ev.type == xkbEventType) {
+ xkbeventnotify(&ev);
+ continue;
+ }
+ #endif // XKB_PATCH
+
if (handler[ev.type])
handler[ev.type](&ev); /* call handler */
+ }
}
#endif // IPC_PATCH
@@ -3198,6 +3250,9 @@ setfocus(Client *c)
XChangeProperty(dpy, root, netatom[NetActiveWindow],
XA_WINDOW, 32, PropModeReplace,
(unsigned char *) &(c->win), 1);
+ #if XKB_PATCH
+ XkbLockGroup(dpy, XkbUseCoreKbd, c->xkb->group);
+ #endif // XKB_PATCH
}
#if BAR_SYSTRAY_PATCH
sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0);
@@ -3381,6 +3436,9 @@ setup(void)
{
int i;
XSetWindowAttributes wa;
+ #if XKB_PATCH
+ XkbStateRec xkbstate;
+ #endif // XKB_PATCH
Atom utf8string;
/* clean up any zombies immediately */
@@ -3553,6 +3611,17 @@ setup(void)
|LeaveWindowMask|StructureNotifyMask|PropertyChangeMask;
XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
XSelectInput(dpy, root, wa.event_mask);
+
+ #if XKB_PATCH
+ /* 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;
+ #endif // XKB_PATCH
+
grabkeys();
focus(NULL);
#if IPC_PATCH
@@ -4034,6 +4103,9 @@ unmanage(Client *c, int destroyed)
unsigned int switchtag = c->switchtag;
#endif // SWITCHTAG_PATCH
XWindowChanges wc;
+ #if XKB_PATCH
+ XkbInfo *xkb;
+ #endif // XKB_PATCH
#if SWALLOW_PATCH
if (c->swallowing) {
@@ -4064,6 +4136,19 @@ unmanage(Client *c, int destroyed)
XSetErrorHandler(xerror);
XUngrabServer(dpy);
}
+ #if XKB_PATCH
+ 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);
+ }
+ }
+ #endif // XKB_PATCH
+
free(c);
#if SWALLOW_PATCH
if (s)
diff --git a/patch/include.c b/patch/include.c
index 9e93ded..e4f121d 100644
--- a/patch/include.c
+++ b/patch/include.c
@@ -298,6 +298,9 @@
#if ZOOMSWAP_PATCH
#include "zoomswap.c"
#endif
+#if XKB_PATCH
+#include "xkb.c"
+#endif
#if XRDB_PATCH && !BAR_VTCOLORS_PATCH
#include "xrdb.c"
#endif
diff --git a/patch/include.h b/patch/include.h
index 5cf6e70..9df14fc 100644
--- a/patch/include.h
+++ b/patch/include.h
@@ -294,6 +294,9 @@
#if ZOOMSWAP_PATCH
#include "zoomswap.h"
#endif
+#if XKB_PATCH
+#include "xkb.h"
+#endif
#if XRDB_PATCH && !BAR_VTCOLORS_PATCH
#include "xrdb.h"
#endif
diff --git a/patch/ipc.c b/patch/ipc.c
index e863afc..ef0e577 100644
--- a/patch/ipc.c
+++ b/patch/ipc.c
@@ -9,6 +9,15 @@ handlexevent(struct epoll_event *ev)
XEvent ev;
while (running && XPending(dpy)) {
XNextEvent(dpy, &ev);
+ #if XKB_PATCH
+ /* Unfortunately the xkbEventType is not constant hence it can't be part of the
+ * normal event handler below */
+ if (ev.type == xkbEventType) {
+ xkbeventnotify(&ev);
+ continue;
+ }
+ #endif // XKB_PATCH
+
if (handler[ev.type]) {
handler[ev.type](&ev); /* call handler */
ipc_send_events(mons, &lastselmon, selmon);
diff --git a/patch/xkb.c b/patch/xkb.c
new file mode 100644
index 0000000..0ce2cec
--- /dev/null
+++ b/patch/xkb.c
@@ -0,0 +1,67 @@
+static XkbInfo xkbGlobal;
+static XkbInfo *xkbSaved = NULL;
+
+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;
+}
+
+XkbInfo *
+findxkb(Window w)
+{
+ XkbInfo *xkb;
+ for (xkb = xkbSaved; xkb != NULL; xkb = xkb->next)
+ if (xkb->w == w)
+ return xkb;
+ return NULL;
+}
+
+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;
+ drawbars();
+ break;
+ }
+}
+
+/* xkb bar module */
+int
+width_xkb(Bar *bar, BarArg *a)
+{
+ return TEXTW(xkb_layouts[xkbGlobal.group]);
+}
+
+int
+draw_xkb(Bar *bar, BarArg *a)
+{
+ drw_text(drw, a->x, a->y, a->w, a->h, lrpad / 2, xkb_layouts[xkbGlobal.group], 0, False);
+ return 1;
+}
+
+int
+click_xkb(Bar *bar, Arg *arg, BarArg *a)
+{
+ return ClkXKB;
+}
diff --git a/patch/xkb.h b/patch/xkb.h
new file mode 100644
index 0000000..abe7c2c
--- /dev/null
+++ b/patch/xkb.h
@@ -0,0 +1,7 @@
+static XkbInfo *createxkb(Window w);
+static XkbInfo *findxkb(Window w);
+static void xkbeventnotify(XEvent *e);
+
+static int width_xkb(Bar *bar, BarArg *a);
+static int draw_xkb(Bar *bar, BarArg *a);
+static int click_xkb(Bar *bar, Arg *arg, BarArg *a); \ No newline at end of file
diff --git a/patches.def.h b/patches.def.h
index 472d535..441d179 100644
--- a/patches.def.h
+++ b/patches.def.h
@@ -1105,6 +1105,13 @@
*/
#define WINVIEW_PATCH 0
+/* Remember keyboard layout per client.
+ * It is recommended that you configure xkb before using this patch as described in
+ * https://www.x.org/archive/X11R7.5/doc/input/XKB-Config.html
+ * https://dwm.suckless.org/patches/xkb/
+ */
+#define XKB_PATCH 0
+
/* Allows dwm to read colors from xrdb (.Xresources) during runtime. Compatible with
* the float border color, awesomebar, urgentborder and titlecolor patches.
* https://dwm.suckless.org/patches/xrdb/