X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=dwm.c;h=0af37d682280f91efcfc457e8bdcb20cddaf6457;hb=d66ad1457e6b1e3fc18c01767fdb499acaef3c8e;hp=487fafb8a7896039c34ee8eee99ed646b9baa578;hpb=13577b15e5ef15fb151d4a1444f6d07a689f967c;p=dwm.git diff --git a/dwm.c b/dwm.c index 487fafb..0af37d6 100644 --- a/dwm.c +++ b/dwm.c @@ -17,9 +17,7 @@ * set the override_redirect flag. Clients are organized in a global * doubly-linked client list, the focus history is remembered through a global * stack list. Each client contains an array of Bools of the same size as the - * global tags array to indicate the tags of a client. For each client dwm - * creates a small title window, which is resized whenever the (_NET_)WM_NAME - * properties are updated or the client is moved/resized. + * global tags array to indicate the tags of a client. * * Keys and tagging rules are organized as arrays and defined in config.h. * @@ -46,8 +44,11 @@ /* macros */ #define BUTTONMASK (ButtonPressMask | ButtonReleaseMask) #define CLEANMASK(mask) (mask & ~(numlockmask | LockMask)) +#define LENGTH(x) (sizeof x / sizeof x[0]) +#define MAXTAGLEN 16 #define MOUSEMASK (BUTTONMASK | PointerMotionMask) + /* enums */ enum { BarTop, BarBot, BarOff }; /* bar position */ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ @@ -136,6 +137,7 @@ void eprint(const char *errstr, ...); void expose(XEvent *e); void floating(void); /* default floating layout */ void focus(Client *c); +void focusin(XEvent *e); void focusnext(const char *arg); void focusprev(const char *arg); Client *getclient(Window w); @@ -143,9 +145,9 @@ unsigned long getcolor(const char *colstr); long getstate(Window w); Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); void grabbuttons(Client *c, Bool focused); +void grabkeys(void); unsigned int idxoftag(const char *tag); void initfont(const char *fontstr); -Bool isarrange(void (*func)()); Bool isoccupied(unsigned int t); Bool isprotodel(Client *c); Bool isvisible(Client *c); @@ -159,6 +161,7 @@ void movemouse(Client *c); Client *nexttiled(Client *c); void propertynotify(XEvent *e); void quit(const char *arg); +void reapply(const char *arg); void resize(Client *c, int x, int y, int w, int h, Bool sizehints); void resizemouse(Client *c); void restack(void); @@ -198,9 +201,6 @@ int screen, sx, sy, sw, sh, wax, way, waw, wah; int (*xerrorxlib)(Display *, XErrorEvent *); unsigned int bh, bpos; unsigned int blw = 0; -unsigned int ltidx = 0; /* default */ -unsigned int nlayouts = 0; -unsigned int nrules = 0; unsigned int numlockmask = 0; void (*handler[LASTEvent]) (XEvent *) = { [ButtonPress] = buttonpress, @@ -208,15 +208,18 @@ void (*handler[LASTEvent]) (XEvent *) = { [ConfigureNotify] = configurenotify, [DestroyNotify] = destroynotify, [EnterNotify] = enternotify, - [LeaveNotify] = leavenotify, [Expose] = expose, + [FocusIn] = focusin, [KeyPress] = keypress, + [LeaveNotify] = leavenotify, [MappingNotify] = mappingnotify, [MapRequest] = maprequest, [PropertyNotify] = propertynotify, [UnmapNotify] = unmapnotify }; Atom wmatom[WMLast], netatom[NetLast]; +Bool domwfact = True; +Bool dozoom = True; Bool otherwm, readin; Bool running = True; Bool selscreen = True; @@ -226,15 +229,14 @@ Client *stack = NULL; Cursor cursor[CurLast]; Display *dpy; DC dc = {0}; +Layout *layout = NULL; Window barwin, root; Regs *regs = NULL; /* configuration, allows nested code to access above variables */ #include "config.h" -#define NTAGS (sizeof tags / sizeof tags[0]) -Bool seltags[NTAGS] = {[0] = True}; -Bool prevtags[NTAGS] = {[0] = True}; +Bool prevtags[LENGTH(tags)]; /* function implementations */ void @@ -250,10 +252,10 @@ applyrules(Client *c) { snprintf(buf, sizeof buf, "%s:%s:%s", ch.res_class ? ch.res_class : "", ch.res_name ? ch.res_name : "", c->name); - for(i = 0; i < nrules; i++) + for(i = 0; i < LENGTH(rules); i++) if(regs[i].propregex && !regexec(regs[i].propregex, buf, 1, &tmp, 0)) { c->isfloating = rules[i].isfloating; - for(j = 0; regs[i].tagregex && j < NTAGS; j++) { + for(j = 0; regs[i].tagregex && j < LENGTH(tags); j++) { if(!regexec(regs[i].tagregex, tags[j], 1, &tmp, 0)) { matched = True; c->tags[j] = True; @@ -277,7 +279,7 @@ arrange(void) { unban(c); else ban(c); - layouts[ltidx].arrange(); + layout->arrange(); focus(NULL); restack(); } @@ -310,9 +312,9 @@ buttonpress(XEvent *e) { Client *c; XButtonPressedEvent *ev = &e->xbutton; - if(barwin == ev->window) { + if(ev->window == barwin) { x = 0; - for(i = 0; i < NTAGS; i++) { + for(i = 0; i < LENGTH(tags); i++) { x += textw(tags[i]); if(ev->x < x) { if(ev->button == Button1) { @@ -338,20 +340,20 @@ buttonpress(XEvent *e) { if(CLEANMASK(ev->state) != MODKEY) return; if(ev->button == Button1) { - if(isarrange(floating) || c->isfloating) + if((layout->arrange == floating) || c->isfloating) restack(); else togglefloating(NULL); movemouse(c); } else if(ev->button == Button2) { - if((ISTILE) && !c->isfixed && c->isfloating) + if((floating != layout->arrange) && c->isfloating) togglefloating(NULL); else zoom(NULL); } else if(ev->button == Button3 && !c->isfixed) { - if(isarrange(floating) || c->isfloating) + if((floating == layout->arrange) || c->isfloating) restack(); else togglefloating(NULL); @@ -405,9 +407,8 @@ compileregs(void) { if(regs) return; - nrules = sizeof rules / sizeof rules[0]; - regs = emallocz(nrules * sizeof(Regs)); - for(i = 0; i < nrules; i++) { + regs = emallocz(LENGTH(rules) * sizeof(Regs)); + for(i = 0; i < LENGTH(rules); i++) { if(rules[i].prop) { reg = emallocz(sizeof(regex_t)); if(regcomp(reg, rules[i].prop, REG_EXTENDED)) @@ -468,7 +469,7 @@ configurerequest(XEvent *e) { c->ismax = False; if(ev->value_mask & CWBorderWidth) c->border = ev->border_width; - if(c->isfixed || c->isfloating || isarrange(floating)) { + if(c->isfixed || c->isfloating || (floating == layout->arrange)) { if(ev->value_mask & CWX) c->x = ev->x; if(ev->value_mask & CWY) @@ -536,7 +537,7 @@ drawbar(void) { int i, x; dc.x = dc.y = 0; - for(i = 0; i < NTAGS; i++) { + for(i = 0; i < LENGTH(tags); i++) { dc.w = textw(tags[i]); if(seltags[i]) { drawtext(tags[i], dc.sel); @@ -549,7 +550,7 @@ drawbar(void) { dc.x += dc.w; } dc.w = blw; - drawtext(layouts[ltidx].symbol, dc.norm); + drawtext(layout->symbol, dc.norm); x = dc.x + dc.w; dc.w = textw(stext); dc.x = sw - dc.w; @@ -671,7 +672,7 @@ expose(XEvent *e) { XExposeEvent *ev = &e->xexpose; if(ev->count == 0) { - if(barwin == ev->window) + if(ev->window == barwin) drawbar(); } } @@ -680,6 +681,7 @@ void floating(void) { /* default floating layout */ Client *c; + domwfact = dozoom = False; for(c = clients; c; c = c->next) if(isvisible(c)) resize(c, c->x, c->y, c->w, c->h, True); @@ -711,6 +713,14 @@ focus(Client *c) { } void +focusin(XEvent *e) { /* there are some broken focus acquiring clients */ + XFocusChangeEvent *ev = &e->xfocus; + + if(sel && ev->window != sel->win) + XSetInputFocus(dpy, sel->win, RevertToPointerRoot, CurrentTime); +} + +void focusnext(const char *arg) { Client *c; @@ -794,8 +804,7 @@ gettextprop(Window w, Atom atom, char *text, unsigned int size) { strncpy(text, (char *)name.value, size - 1); else { if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success - && n > 0 && *list) - { + && n > 0 && *list) { strncpy(text, *list, size - 1); XFreeStringList(list); } @@ -842,12 +851,31 @@ grabbuttons(Client *c, Bool focused) { GrabModeAsync, GrabModeSync, None, None); } +void +grabkeys(void) { + unsigned int i; + KeyCode code; + + XUngrabKey(dpy, AnyKey, AnyModifier, root); + for(i = 0; i < LENGTH(keys); i++) { + code = XKeysymToKeycode(dpy, keys[i].keysym); + XGrabKey(dpy, code, keys[i].mod, root, True, + GrabModeAsync, GrabModeAsync); + XGrabKey(dpy, code, keys[i].mod | LockMask, root, True, + GrabModeAsync, GrabModeAsync); + XGrabKey(dpy, code, keys[i].mod | numlockmask, root, True, + GrabModeAsync, GrabModeAsync); + XGrabKey(dpy, code, keys[i].mod | numlockmask | LockMask, root, True, + GrabModeAsync, GrabModeAsync); + } +} + unsigned int idxoftag(const char *tag) { unsigned int i; - for(i = 0; (i < NTAGS) && (tags[i] != tag); i++); - return (i < NTAGS) ? i : 0; + for(i = 0; (i < LENGTH(tags)) && (tags[i] != tag); i++); + return (i < LENGTH(tags)) ? i : 0; } void @@ -893,12 +921,6 @@ initfont(const char *fontstr) { } Bool -isarrange(void (*func)()) -{ - return func == layouts[ltidx].arrange; -} - -Bool isoccupied(unsigned int t) { Client *c; @@ -927,7 +949,7 @@ Bool isvisible(Client *c) { unsigned int i; - for(i = 0; i < NTAGS; i++) + for(i = 0; i < LENGTH(tags); i++) if(c->tags[i] && seltags[i]) return True; return False; @@ -935,31 +957,13 @@ isvisible(Client *c) { void keypress(XEvent *e) { - KEYS - unsigned int len = sizeof keys / sizeof keys[0]; unsigned int i; - KeyCode code; KeySym keysym; XKeyEvent *ev; - if(!e) { /* grabkeys */ - XUngrabKey(dpy, AnyKey, AnyModifier, root); - for(i = 0; i < len; i++) { - code = XKeysymToKeycode(dpy, keys[i].keysym); - XGrabKey(dpy, code, keys[i].mod, root, True, - GrabModeAsync, GrabModeAsync); - XGrabKey(dpy, code, keys[i].mod | LockMask, root, True, - GrabModeAsync, GrabModeAsync); - XGrabKey(dpy, code, keys[i].mod | numlockmask, root, True, - GrabModeAsync, GrabModeAsync); - XGrabKey(dpy, code, keys[i].mod | numlockmask | LockMask, root, True, - GrabModeAsync, GrabModeAsync); - } - return; - } ev = &e->xkey; keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); - for(i = 0; i < len; i++) + for(i = 0; i < LENGTH(keys); i++) if(keysym == keys[i].keysym && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)) { @@ -1033,8 +1037,7 @@ manage(Window w, XWindowAttributes *wa) { XSetWindowBorder(dpy, w, dc.norm[ColBorder]); configure(c); /* propagates border_width, if size doesn't change */ updatesizehints(c); - XSelectInput(dpy, w, - StructureNotifyMask | PropertyChangeMask | EnterWindowMask); + XSelectInput(dpy, w, EnterWindowMask | FocusChangeMask | PropertyChangeMask | StructureNotifyMask); grabbuttons(c, False); updatetitle(c); if((rettrans = XGetTransientForHint(dpy, w, &trans) == Success)) @@ -1059,7 +1062,7 @@ mappingnotify(XEvent *e) { XRefreshKeyboardMapping(ev); if(ev->request == MappingKeyboard) - keypress(NULL); + grabkeys(); } void @@ -1137,7 +1140,7 @@ propertynotify(XEvent *e) { default: break; case XA_WM_TRANSIENT_FOR: XGetTransientForHint(dpy, c->win, &trans); - if(!c->isfloating && (c->isfloating = (NULL != getclient(trans)))) + if(!c->isfloating && (c->isfloating = (getclient(trans) != NULL))) arrange(); break; case XA_WM_NORMAL_HINTS: @@ -1158,6 +1161,18 @@ quit(const char *arg) { } void +reapply(const char *arg) { + static Bool zerotags[LENGTH(tags)] = { 0 }; + Client *c; + + for(c = clients; c; c = c->next) { + memcpy(c->tags, zerotags, sizeof zerotags); + applyrules(c); + } + arrange(); +} + +void resize(Client *c, int x, int y, int w, int h, Bool sizehints) { XWindowChanges wc; @@ -1270,9 +1285,9 @@ restack(void) { drawbar(); if(!sel) return; - if(sel->isfloating || isarrange(floating)) + if(sel->isfloating || (layout->arrange == floating)) XRaiseWindow(dpy, sel->win); - if(!isarrange(floating)) { + if(layout->arrange != floating) { wc.stack_mode = Below; wc.sibling = barwin; if(!sel->isfloating) { @@ -1293,14 +1308,19 @@ restack(void) { void run(void) { char *p; - int r, xfd; + char buf[sizeof stext]; fd_set rd; + int r, xfd; + unsigned int len, offset; XEvent ev; /* main event loop, also reads status text from stdin */ XSync(dpy, False); xfd = ConnectionNumber(dpy); readin = True; + offset = 0; + len = sizeof stext - 1; + buf[len] = stext[len] = '\0'; /* 0-terminator is never touched */ while(running) { FD_ZERO(&rd); if(readin) @@ -1312,10 +1332,9 @@ run(void) { eprint("select failed\n"); } if(FD_ISSET(STDIN_FILENO, &rd)) { - switch(r = read(STDIN_FILENO, stext, sizeof stext - 1)) { + switch((r = read(STDIN_FILENO, buf + offset, len - offset))) { case -1: - strncpy(stext, strerror(errno), sizeof stext - 1); - stext[sizeof stext - 1] = '\0'; + strncpy(stext, strerror(errno), len); readin = False; break; case 0: @@ -1323,10 +1342,18 @@ run(void) { readin = False; break; default: - for(stext[r] = '\0', p = stext + strlen(stext) - 1; p >= stext && *p == '\n'; *p-- = '\0'); - for(; p >= stext && *p != '\n'; --p); - if(p > stext) - strncpy(stext, p + 1, sizeof stext); + for(p = buf + offset; r > 0; p++, r--, offset++) + if(*p == '\n' || *p == '\0') { + *p = '\0'; + strncpy(stext, buf, len); + p += r - 1; /* p is buf + offset + r - 1 */ + for(r = 0; *(p - r) && *(p - r) != '\n'; r++); + offset = r; + if(r) + memmove(buf, p - r + 1, r); + break; + } + break; } drawbar(); } @@ -1378,16 +1405,16 @@ setlayout(const char *arg) { unsigned int i; if(!arg) { - if(++ltidx == nlayouts) - ltidx = 0;; + if(++layout == &layouts[LENGTH(layouts)]) + layout = &layouts[0]; } else { - for(i = 0; i < nlayouts; i++) + for(i = 0; i < LENGTH(layouts); i++) if(!strcmp(arg, layouts[i].symbol)) break; - if(i == nlayouts) + if(i == LENGTH(layouts)) return; - ltidx = i; + layout = &layouts[i]; } if(sel) arrange(); @@ -1399,12 +1426,12 @@ void setmwfact(const char *arg) { double delta; - if(!(ISTILE)) + if(!domwfact) return; /* arg handling, manipulate mwfact */ if(arg == NULL) mwfact = MWFACT; - else if(1 == sscanf(arg, "%lf", &delta)) { + else if(sscanf(arg, "%lf", &delta) == 1) { if(arg[0] == '+' || arg[0] == '-') mwfact += delta; else @@ -1463,9 +1490,10 @@ setup(void) { XSelectInput(dpy, root, wa.event_mask); /* grab keys */ - keypress(NULL); + grabkeys(); /* init tags */ + memcpy(prevtags, seltags, sizeof seltags); compileregs(); /* init appearance */ @@ -1480,8 +1508,8 @@ setup(void) { /* init layouts */ mwfact = MWFACT; - nlayouts = sizeof layouts / sizeof layouts[0]; - for(blw = i = 0; i < nlayouts; i++) { + layout = &layouts[0]; + for(blw = i = 0; i < LENGTH(layouts); i++) { j = textw(layouts[i].symbol); if(j > blw) blw = j; @@ -1507,6 +1535,7 @@ setup(void) { /* multihead support */ selscreen = XQueryPointer(dpy, root, &w, &w, &d, &d, &d, &d, &mask); + } void @@ -1539,7 +1568,7 @@ tag(const char *arg) { if(!sel) return; - for(i = 0; i < NTAGS; i++) + for(i = 0; i < LENGTH(tags); i++) sel->tags[i] = (NULL == arg); sel->tags[idxoftag(arg)] = True; arrange(); @@ -1566,6 +1595,7 @@ tile(void) { unsigned int i, n, nx, ny, nw, nh, mw, th; Client *c, *mc; + domwfact = dozoom = True; for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next)) n++; @@ -1595,8 +1625,8 @@ tile(void) { else nh = th - 2 * c->border; } - resize(c, nx, ny, nw, nh, True); - if((c->h < bh) || (c->h > nh) || (c->w < bh) || (c->w > nw)) + resize(c, nx, ny, nw, nh, RESIZEHINTS); + if((RESIZEHINTS) && ((c->h < bh) || (c->h > nh) || (c->w < bh) || (c->w > nw))) /* client doesn't accept size constraints */ resize(c, nx, ny, nw, nh, False); if(n > 1 && th != wah) @@ -1631,7 +1661,7 @@ togglemax(const char *arg) { if(!sel || sel->isfixed) return; if((sel->ismax = !sel->ismax)) { - if(isarrange(floating) || sel->isfloating) + if((layout->arrange == floating) || sel->isfloating) sel->wasfloating = True; else { togglefloating(NULL); @@ -1660,8 +1690,8 @@ toggletag(const char *arg) { return; i = idxoftag(arg); sel->tags[i] = !sel->tags[i]; - for(j = 0; j < NTAGS && !sel->tags[j]; j++); - if(j == NTAGS) + for(j = 0; j < LENGTH(tags) && !sel->tags[j]; j++); + if(j == LENGTH(tags)) sel->tags[i] = True; /* at least one tag must be enabled */ arrange(); } @@ -1672,8 +1702,8 @@ toggleview(const char *arg) { i = idxoftag(arg); seltags[i] = !seltags[i]; - for(j = 0; j < NTAGS && !seltags[j]; j++); - if(j == NTAGS) + for(j = 0; j < LENGTH(tags) && !seltags[j]; j++); + if(j == LENGTH(tags)) seltags[i] = True; /* at least one tag must be viewed */ arrange(); } @@ -1839,19 +1869,19 @@ view(const char *arg) { unsigned int i; memcpy(prevtags, seltags, sizeof seltags); - for(i = 0; i < NTAGS; i++) - seltags[i] = arg == NULL; + for(i = 0; i < LENGTH(tags); i++) + seltags[i] = (NULL == arg); seltags[idxoftag(arg)] = True; arrange(); } void viewprevtag(const char *arg) { - static Bool tmptags[sizeof tags / sizeof tags[0]]; + static Bool tmp[LENGTH(tags)]; - memcpy(tmptags, seltags, sizeof seltags); + memcpy(tmp, seltags, sizeof seltags); memcpy(seltags, prevtags, sizeof seltags); - memcpy(prevtags, tmptags, sizeof seltags); + memcpy(prevtags, tmp, sizeof seltags); arrange(); } @@ -1859,7 +1889,7 @@ void zoom(const char *arg) { Client *c; - if(!sel || !(ISTILE) || sel->isfloating) + if(!sel || !dozoom || sel->isfloating) return; if((c = sel) == nexttiled(clients)) if(!(c = nexttiled(c->next))) @@ -1873,7 +1903,8 @@ zoom(const char *arg) { int main(int argc, char *argv[]) { if(argc == 2 && !strcmp("-v", argv[1])) - eprint("dwm-"VERSION", © 2006-2007 A. R. Garbe, S. van Dijk, J. Salmi, P. Hruby, S. Nagy\n"); + eprint("dwm-"VERSION", © 2006-2007 Anselm R. Garbe, Sander van Dijk, " + "Jukka Salmi, Premysl Hruby, Szabolcs Nagy\n"); else if(argc != 1) eprint("usage: dwm [-v]\n");