dwm-6.1-xkb.diff (8882B)
1 diff --git a/config.def.h b/config.def.h 2 index 875885b..780ff6f 100644 3 --- a/config.def.h 4 +++ b/config.def.h 5 @@ -21,9 +21,9 @@ static const Rule rules[] = { 6 * WM_CLASS(STRING) = instance, class 7 * WM_NAME(STRING) = title 8 */ 9 - /* class instance title tags mask isfloating monitor */ 10 - { "Gimp", NULL, NULL, 0, True, -1 }, 11 - { "Firefox", NULL, NULL, 1 << 8, False, -1 }, 12 + /* class instance title tags mask isfloating monitor xkb_layout */ 13 + { "Gimp", NULL, NULL, 0, True, -1, 0 }, 14 + { "Firefox", NULL, NULL, 1 << 8, False, -1, -1 }, 15 }; 16 17 /* layout(s) */ 18 @@ -31,6 +31,13 @@ static const float mfact = 0.55; /* factor of master area size [0.05..0.95] 19 static const int nmaster = 1; /* number of clients in master area */ 20 static const Bool resizehints = True; /* True means respect size hints in tiled resizals */ 21 22 +/* xkb frontend */ 23 +static const Bool showxkb = True; /* False means no xkb layout text */ 24 +static const char *xkb_layouts [] = { 25 + "en", 26 + "ru", 27 +}; 28 + 29 static const Layout layouts[] = { 30 /* symbol arrange function */ 31 { "[]=", tile }, /* first entry is default */ 32 diff --git a/dwm.c b/dwm.c 33 index 1bbb4b3..ec39eef 100644 34 --- a/dwm.c 35 +++ b/dwm.c 36 @@ -36,6 +36,7 @@ 37 #include <X11/Xlib.h> 38 #include <X11/Xproto.h> 39 #include <X11/Xutil.h> 40 +#include <X11/XKBlib.h> 41 #ifdef XINERAMA 42 #include <X11/extensions/Xinerama.h> 43 #endif /* XINERAMA */ 44 @@ -83,6 +84,7 @@ typedef struct { 45 46 typedef struct Monitor Monitor; 47 typedef struct Client Client; 48 +typedef struct XkbInfo XkbInfo; 49 struct Client { 50 char name[256]; 51 float mina, maxa; 52 @@ -96,6 +98,13 @@ struct Client { 53 Client *snext; 54 Monitor *mon; 55 Window win; 56 + XkbInfo *xkb; 57 +}; 58 +struct XkbInfo { 59 + XkbInfo *next; 60 + XkbInfo *prev; 61 + int group; 62 + Window w; 63 }; 64 65 typedef struct { 66 @@ -138,6 +147,7 @@ typedef struct { 67 unsigned int tags; 68 Bool isfloating; 69 int monitor; 70 + int xkb_layout; 71 } Rule; 72 73 /* function declarations */ 74 @@ -157,6 +167,7 @@ static void configure(Client *c); 75 static void configurenotify(XEvent *e); 76 static void configurerequest(XEvent *e); 77 static Monitor *createmon(void); 78 +static XkbInfo *createxkb(Window w); 79 static void destroynotify(XEvent *e); 80 static void detach(Client *c); 81 static void detachstack(Client *c); 82 @@ -165,6 +176,7 @@ static void drawbar(Monitor *m); 83 static void drawbars(void); 84 static void enternotify(XEvent *e); 85 static void expose(XEvent *e); 86 +static XkbInfo *findxkb(Window w); 87 static void focus(Client *c); 88 static void focusin(XEvent *e); 89 static void focusmon(const Arg *arg); 90 @@ -231,6 +243,7 @@ static Monitor *wintomon(Window w); 91 static int xerror(Display *dpy, XErrorEvent *ee); 92 static int xerrordummy(Display *dpy, XErrorEvent *ee); 93 static int xerrorstart(Display *dpy, XErrorEvent *ee); 94 +static void xkbeventnotify(XEvent *e); 95 static void zoom(const Arg *arg); 96 97 /* variables */ 98 @@ -241,6 +254,7 @@ static int sw, sh; /* X display screen geometry width, height */ 99 static int bh, blw = 0; /* bar geometry */ 100 static int (*xerrorxlib)(Display *, XErrorEvent *); 101 static unsigned int numlockmask = 0; 102 +static int xkbEventType = 0; 103 static void (*handler[LASTEvent]) (XEvent *) = { 104 [ButtonPress] = buttonpress, 105 [ClientMessage] = clientmessage, 106 @@ -266,6 +280,8 @@ static Drw *drw; 107 static Fnt *fnt; 108 static Monitor *mons, *selmon; 109 static Window root; 110 +static XkbInfo xkbGlobal; 111 +static XkbInfo *xkbSaved = NULL; 112 113 /* configuration, allows nested code to access above variables */ 114 #include "config.h" 115 @@ -299,6 +315,9 @@ applyrules(Client *c) { 116 for(m = mons; m && m->num != r->monitor; m = m->next); 117 if(m) 118 c->mon = m; 119 + if(r->xkb_layout > -1 ) { 120 + c->xkb->group = r->xkb_layout; 121 + } 122 } 123 } 124 if(ch.res_class) 125 @@ -644,6 +663,25 @@ createmon(void) { 126 strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); 127 return m; 128 } 129 +static XkbInfo * 130 +createxkb(Window w){ 131 + XkbInfo *xkb; 132 + 133 + xkb = malloc(sizeof *xkb); 134 + if (xkb == NULL) { 135 + die("fatal: could not malloc() %u bytes\n", sizeof *xkb); 136 + } 137 + xkb->group = xkbGlobal.group; 138 + xkb->w = w; 139 + xkb->next = xkbSaved; 140 + if (xkbSaved != NULL) { 141 + xkbSaved->prev = xkb; 142 + } 143 + xkb->prev = NULL; 144 + xkbSaved = xkb; 145 + 146 + return xkb; 147 +} 148 149 void 150 destroynotify(XEvent *e) { 151 @@ -693,6 +731,7 @@ dirtomon(int dir) { 152 void 153 drawbar(Monitor *m) { 154 int x, xx, w; 155 + int ww = 0; 156 unsigned int i, occ = 0, urg = 0; 157 Client *c; 158 159 @@ -718,14 +757,23 @@ drawbar(Monitor *m) { 160 if(m == selmon) { /* status is only drawn on selected monitor */ 161 w = TEXTW(stext); 162 x = m->ww - w; 163 + if (showxkb) { 164 + ww = TEXTW(xkb_layouts[xkbGlobal.group]); 165 + x -= ww; 166 + } 167 if(x < xx) { 168 x = xx; 169 w = m->ww - xx; 170 } 171 drw_text(drw, x, 0, w, bh, stext, 0); 172 + if (showxkb) { 173 + drw_setscheme(drw, &scheme[SchemeNorm]); 174 + drw_text(drw, x+w, 0, ww, bh, xkb_layouts[xkbGlobal.group], 0); 175 + } 176 } 177 else 178 x = m->ww; 179 + 180 if((w = x - xx) > bh) { 181 x = xx; 182 if(m->sel) { 183 @@ -777,6 +825,18 @@ expose(XEvent *e) { 184 drawbar(m); 185 } 186 187 +XkbInfo * 188 +findxkb(Window w) 189 +{ 190 + XkbInfo *xkb; 191 + for (xkb = xkbSaved; xkb != NULL; xkb=xkb->next) { 192 + if (xkb->w == w) { 193 + return xkb; 194 + } 195 + } 196 + return NULL; 197 +} 198 + 199 void 200 focus(Client *c) { 201 if(!c || !ISVISIBLE(c)) 202 @@ -1008,11 +1068,20 @@ manage(Window w, XWindowAttributes *wa) { 203 Client *c, *t = NULL; 204 Window trans = None; 205 XWindowChanges wc; 206 + XkbInfo *xkb; 207 208 if(!(c = calloc(1, sizeof(Client)))) 209 die("fatal: could not malloc() %u bytes\n", sizeof(Client)); 210 c->win = w; 211 updatetitle(c); 212 + 213 + /* Setting current xkb state must be before applyrules */ 214 + xkb = findxkb(c->win); 215 + if (xkb == NULL) { 216 + xkb = createxkb(c->win); 217 + } 218 + c->xkb = xkb; 219 + 220 if(XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { 221 c->mon = t->mon; 222 c->tags = t->tags; 223 @@ -1344,8 +1413,14 @@ run(void) { 224 /* main event loop */ 225 XSync(dpy, False); 226 while(running && !XNextEvent(dpy, &ev)) 227 + { 228 + if(ev.type == xkbEventType) { 229 + xkbeventnotify(&ev); 230 + continue; 231 + } 232 if(handler[ev.type]) 233 handler[ev.type](&ev); /* call handler */ 234 + } 235 } 236 237 void 238 @@ -1428,6 +1503,7 @@ setfocus(Client *c) { 239 XChangeProperty(dpy, root, netatom[NetActiveWindow], 240 XA_WINDOW, 32, PropModeReplace, 241 (unsigned char *) &(c->win), 1); 242 + XkbLockGroup(dpy, XkbUseCoreKbd, c->xkb->group); 243 } 244 sendevent(c, wmatom[WMTakeFocus]); 245 } 246 @@ -1490,6 +1566,7 @@ setmfact(const Arg *arg) { 247 void 248 setup(void) { 249 XSetWindowAttributes wa; 250 + XkbStateRec xkbstate; 251 252 /* clean up any zombies immediately */ 253 sigchld(0); 254 @@ -1541,6 +1618,16 @@ setup(void) { 255 |EnterWindowMask|LeaveWindowMask|StructureNotifyMask|PropertyChangeMask; 256 XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); 257 XSelectInput(dpy, root, wa.event_mask); 258 + 259 + /* get xkb extension info, events and current state */ 260 + if (!XkbQueryExtension(dpy, NULL, &xkbEventType, NULL, NULL, NULL)) { 261 + fputs("warning: can not query xkb extension\n", stderr); 262 + } 263 + XkbSelectEventDetails(dpy, XkbUseCoreKbd, XkbStateNotify, 264 + XkbAllStateComponentsMask, XkbGroupStateMask); 265 + XkbGetState(dpy, XkbUseCoreKbd, &xkbstate); 266 + xkbGlobal.group = xkbstate.locked_group; 267 + 268 grabkeys(); 269 focus(NULL); 270 } 271 @@ -1687,6 +1774,7 @@ void 272 unmanage(Client *c, Bool destroyed) { 273 Monitor *m = c->mon; 274 XWindowChanges wc; 275 + XkbInfo *xkb; 276 277 /* The server grab construct avoids race conditions. */ 278 detach(c); 279 @@ -1702,6 +1790,18 @@ unmanage(Client *c, Bool destroyed) { 280 XSetErrorHandler(xerror); 281 XUngrabServer(dpy); 282 } 283 + else { 284 + xkb = findxkb(c->win); 285 + if (xkb != NULL) { 286 + if (xkb->prev) { 287 + xkb->prev->next = xkb->next; 288 + } 289 + if (xkb->next) { 290 + xkb->next->prev = xkb->prev; 291 + } 292 + free(xkb); 293 + } 294 + } 295 free(c); 296 focus(NULL); 297 updateclientlist(); 298 @@ -2030,6 +2130,23 @@ xerrorstart(Display *dpy, XErrorEvent *ee) { 299 return -1; 300 } 301 302 +void xkbeventnotify(XEvent *e) 303 +{ 304 + XkbEvent *ev; 305 + 306 + ev = (XkbEvent *) e; 307 + switch (ev->any.xkb_type) { 308 + case XkbStateNotify: 309 + xkbGlobal.group = ev->state.locked_group; 310 + if (selmon != NULL && selmon->sel != NULL) { 311 + selmon->sel->xkb->group = xkbGlobal.group; 312 + } 313 + if (showxkb) { 314 + drawbars(); 315 + } 316 + break; 317 + } 318 +} 319 void 320 zoom(const Arg *arg) { 321 Client *c = selmon->sel;