| dwm-6.1-xkb.diff - sites - public wiki contents of suckless.org | |
| git clone git://git.suckless.org/sites | |
| Log | |
| Files | |
| Refs | |
| --- | |
| 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 … | |
| 10 - { "Gimp", NULL, NULL, 0, True, … | |
| 11 - { "Firefox", NULL, NULL, 1 << 8, False, … | |
| 12 + /* class instance title tags mask isfloating … | |
| 13 + { "Gimp", NULL, NULL, 0, True, … | |
| 14 + { "Firefox", NULL, NULL, 1 << 8, False, … | |
| 15 }; | |
| 16 | |
| 17 /* layout(s) */ | |
| 18 @@ -31,6 +31,13 @@ static const float mfact = 0.55; /* factor of ma… | |
| 19 static const int nmaster = 1; /* number of clients in master ar… | |
| 20 static const Bool resizehints = True; /* True means respect size hints … | |
| 21 | |
| 22 +/* xkb frontend */ | |
| 23 +static const Bool showxkb = True; /* False means no xkb layout … | |
| 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 geo… | |
| 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-… | |
| 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],… | |
| 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(Clie… | |
| 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(tra… | |
| 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|StructureNotif… | |
| 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; |