JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
applied Peter Hartlichs aspect revert fix
[dwm.git] / dwm.c
diff --git a/dwm.c b/dwm.c
index 2bf0ba0..4ed5760 100644 (file)
--- a/dwm.c
+++ b/dwm.c
@@ -24,6 +24,7 @@
  * To understand everything else, start reading main().
  */
 #include <errno.h>
+#include <locale.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -52,6 +53,7 @@
 #define MIN(a, b)               ((a) < (b) ? (a) : (b))
 #define MAXTAGLEN               16
 #define MOUSEMASK               (BUTTONMASK|PointerMotionMask)
+#define NOBORDER(x)             ((x) - 2 * c->bw)
 #define TAGMASK                 ((int)((1LL << LENGTH(tags)) - 1))
 #define TEXTW(x)                (textnw(x, strlen(x)) + dc.font.height)
 
@@ -59,7 +61,7 @@
 enum { CurNormal, CurResize, CurMove, CurLast };        /* cursor */
 enum { ColBorder, ColFG, ColBG, ColLast };              /* color */
 enum { NetSupported, NetWMName, NetLast };              /* EWMH atoms */
-enum { WMProtocols, WMDelete, WMName, WMState, WMLast };/* default atoms */
+enum { WMProtocols, WMDelete, WMState, WMLast };        /* default atoms */
 enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
        ClkClientWin, ClkRootWin, ClkLast };             /* clicks */
 
@@ -190,6 +192,7 @@ static void unmanage(Client *c);
 static void unmapnotify(XEvent *e);
 static void updatebar(void);
 static void updategeom(void);
+static void updatenumlockmask(void);
 static void updatesizehints(Client *c);
 static void updatetitle(Client *c);
 static void updatewmhints(Client *c);
@@ -225,13 +228,12 @@ static void (*handler[LASTEvent]) (XEvent *) = {
 static Atom wmatom[WMLast], netatom[NetLast];
 static Bool otherwm;
 static Bool running = True;
-static unsigned int tagset[] = {1, 1}; /* after start, first tag is selected */
 static Client *clients = NULL;
 static Client *sel = NULL;
 static Client *stack = NULL;
 static Cursor cursor[CurLast];
 static Display *dpy;
-static DC dc = {0};
+static DC dc;
 static Layout *lt[] = { NULL, NULL };
 static Window root, barwin;
 /* configuration, allows nested code to access above variables */
@@ -248,20 +250,21 @@ applyrules(Client *c) {
        XClassHint ch = { 0 };
 
        /* rule matching */
-       XGetClassHint(dpy, c->win, &ch);
-       for(i = 0; i < LENGTH(rules); i++) {
-               r = &rules[i];
-               if((!r->title || strstr(c->name, r->title))
-               && (!r->class || (ch.res_class && strstr(ch.res_class, r->class)))
-               && (!r->instance || (ch.res_name && strstr(ch.res_name, r->instance)))) {
-                       c->isfloating = r->isfloating;
-                       c->tags |= r->tags & TAGMASK;
+       if(XGetClassHint(dpy, c->win, &ch)) {
+               for(i = 0; i < LENGTH(rules); i++) {
+                       r = &rules[i];
+                       if((!r->title || strstr(c->name, r->title))
+                       && (!r->class || (ch.res_class && strstr(ch.res_class, r->class)))
+                       && (!r->instance || (ch.res_name && strstr(ch.res_name, r->instance)))) {
+                               c->isfloating = r->isfloating;
+                               c->tags |= r->tags & TAGMASK;
+                       }
                }
+               if(ch.res_class)
+                       XFree(ch.res_class);
+               if(ch.res_name)
+                       XFree(ch.res_name);
        }
-       if(ch.res_class)
-               XFree(ch.res_class);
-       if(ch.res_name)
-               XFree(ch.res_name);
        if(!c->tags)
                c->tags = tagset[seltags];
 }
@@ -328,7 +331,7 @@ buttonpress(XEvent *e) {
        for(i = 0; i < LENGTH(buttons); i++)
                if(click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
                   && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
-                       buttons[i].func(click == ClkTagBar ? &arg : &buttons[i].arg);
+                       buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
 }
 
 void
@@ -734,43 +737,36 @@ gettextprop(Window w, Atom atom, char *text, unsigned int size) {
 
 void
 grabbuttons(Client *c, Bool focused) {
-       unsigned int i, j;
-       unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
-
-       XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
-       if(focused) {
-               for(i = 0; i < LENGTH(buttons); i++)
-                       if(buttons[i].click == ClkClientWin)
-                               for(j = 0; j < LENGTH(modifiers); j++)
-                                       XGrabButton(dpy, buttons[i].button, buttons[i].mask | modifiers[j], c->win, False, BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
-       } else
-               XGrabButton(dpy, AnyButton, AnyModifier, c->win, False,
-                           BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
+       updatenumlockmask();
+       {
+               unsigned int i, j;
+               unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
+               XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
+               if(focused) {
+                       for(i = 0; i < LENGTH(buttons); i++)
+                               if(buttons[i].click == ClkClientWin)
+                                       for(j = 0; j < LENGTH(modifiers); j++)
+                                               XGrabButton(dpy, buttons[i].button, buttons[i].mask | modifiers[j], c->win, False, BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
+               } else
+                       XGrabButton(dpy, AnyButton, AnyModifier, c->win, False,
+                                   BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
+       }
 }
 
 void
 grabkeys(void) {
-       unsigned int i, j;
-       XModifierKeymap *modmap;
-
-       /* update modifier map */
-       modmap = XGetModifierMapping(dpy);
-       for(i = 0; i < 8; i++)
-               for(j = 0; j < modmap->max_keypermod; j++)
-                       if(modmap->modifiermap[i * modmap->max_keypermod + j] == XKeysymToKeycode(dpy, XK_Num_Lock))
-                               numlockmask = (1 << i);
-       XFreeModifiermap(modmap);
-
+       updatenumlockmask();
        { /* grab keys */
+               unsigned int i, j;
                unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
                KeyCode code;
 
                XUngrabKey(dpy, AnyKey, AnyModifier, root);
                for(i = 0; i < LENGTH(keys); i++) {
-                       code = XKeysymToKeycode(dpy, keys[i].keysym);
-                       for(j = 0; j < LENGTH(modifiers); j++)
-                               XGrabKey(dpy, code, keys[i].mod | modifiers[j], root, True,
-                                        GrabModeAsync, GrabModeAsync);
+                       if((code = XKeysymToKeycode(dpy, keys[i].keysym)))
+                               for(j = 0; j < LENGTH(modifiers); j++)
+                                       XGrabKey(dpy, code, keys[i].mod | modifiers[j], root,
+                                                True, GrabModeAsync, GrabModeAsync);
                }
        }
 }
@@ -781,8 +777,6 @@ initfont(const char *fontstr) {
        int i, n;
 
        missing = NULL;
-       if(dc.font.set)
-               XFreeFontSet(dpy, dc.font.set);
        dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
        if(missing) {
                while(n--)
@@ -803,9 +797,6 @@ initfont(const char *fontstr) {
                }
        }
        else {
-               if(dc.font.xfont)
-                       XFreeFont(dpy, dc.font.xfont);
-               dc.font.xfont = NULL;
                if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr))
                && !(dc.font.xfont = XLoadQueryFont(dpy, "fixed")))
                        die("error, cannot load font: '%s'\n", fontstr);
@@ -887,9 +878,9 @@ manage(Window w, XWindowAttributes *wa) {
        }
        else {
                if(c->x + c->w + 2 * c->bw > sx + sw)
-                       c->x = sx + sw - c->w - 2 * c->bw;
+                       c->x = sx + sw - NOBORDER(c->w);
                if(c->y + c->h + 2 * c->bw > sy + sh)
-                       c->y = sy + sh - c->h - 2 * c->bw;
+                       c->y = sy + sh - NOBORDER(c->h);
                c->x = MAX(c->x, sx);
                /* only fix client y-offset, if the client center might cover the bar */
                c->y = MAX(c->y, ((by == 0) && (c->x + (c->w / 2) >= wx) && (c->x + (c->w / 2) < wx + ww)) ? bh : sy);
@@ -949,7 +940,7 @@ monocle(void) {
        Client *c;
 
        for(c = nexttiled(clients); c; c = nexttiled(c->next))
-               resize(c, wx, wy, ww - 2 * c->bw, wh - 2 * c->bw, resizehints);
+               resize(c, wx, wy, NOBORDER(ww), NOBORDER(wh), resizehints);
 }
 
 void
@@ -986,11 +977,11 @@ movemouse(const Arg *arg) {
                                if(abs(wx - nx) < snap)
                                        nx = wx;
                                else if(abs((wx + ww) - (nx + c->w + 2 * c->bw)) < snap)
-                                       nx = wx + ww - c->w - 2 * c->bw;
+                                       nx = wx + ww - NOBORDER(c->w);
                                if(abs(wy - ny) < snap)
                                        ny = wy;
                                else if(abs((wy + wh) - (ny + c->h + 2 * c->bw)) < snap)
-                                       ny = wy + wh - c->h - 2 * c->bw;
+                                       ny = wy + wh - NOBORDER(c->h);
                                if(!c->isfloating && lt[sellt]->arrange && (abs(nx - c->x) > snap || abs(ny - c->y) > snap))
                                        togglefloating(NULL);
                        }
@@ -1051,22 +1042,31 @@ resize(Client *c, int x, int y, int w, int h, Bool sizehints) {
        XWindowChanges wc;
 
        if(sizehints) {
+               /* see last two sentences in ICCCM 4.1.2.3 */
+               Bool baseismin = c->basew == c->minw && c->baseh == c->minh;
+
                /* set minimum possible */
                w = MAX(1, w);
                h = MAX(1, h);
 
-               /* temporarily remove base dimensions */
-               w -= c->basew;
-               h -= c->baseh;
+               if(!baseismin) { /* temporarily remove base dimensions */
+                       w -= c->basew;
+                       h -= c->baseh;
+               }
 
                /* adjust for aspect limits */
                if(c->mina > 0 && c->maxa > 0) {
-                       if(c->maxa < (float) w/h)
+                       if(c->maxa < (float)w / h)
                                w = h * c->maxa;
-                       else if(c->mina > (float) h/w)
+                       else if(c->mina < (float)h / w)
                                h = w * c->mina;
                }
 
+               if(baseismin) { /* increment calculation requires this */
+                       w -= c->basew;
+                       h -= c->baseh;
+               }
+
                /* adjust for increment value */
                if(c->incw)
                        w -= w % c->incw;
@@ -1089,9 +1089,9 @@ resize(Client *c, int x, int y, int w, int h, Bool sizehints) {
        if(w <= 0 || h <= 0)
                return;
        if(x > sx + sw)
-               x = sw - w - 2 * c->bw;
+               x = sw - NOBORDER(w);
        if(y > sy + sh)
-               y = sh - h - 2 * c->bw;
+               y = sh - NOBORDER(h);
        if(x + w + 2 * c->bw < sx)
                x = sx;
        if(y + h + 2 * c->bw < sy)
@@ -1139,8 +1139,8 @@ resizemouse(const Arg *arg) {
                        break;
                case MotionNotify:
                        XSync(dpy, False);
-                       nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
-                       nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);
+                       nw = MAX(ev.xmotion.x - NOBORDER(ocx) + 1, 1);
+                       nh = MAX(ev.xmotion.y - NOBORDER(ocy) + 1, 1);
 
                        if(snap && nw >= wx && nw <= wx + ww
                                && nh >= wy && nh <= wy + wh) {
@@ -1324,7 +1324,6 @@ setup(void) {
        /* init atoms */
        wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
        wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
-       wmatom[WMName] = XInternAtom(dpy, "WM_NAME", False);
        wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
        netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
        netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
@@ -1428,7 +1427,7 @@ tile(void) {
        /* master */
        c = nexttiled(clients);
        mw = mfact * ww;
-       resize(c, wx, wy, (n == 1 ? ww : mw) - 2 * c->bw, wh - 2 * c->bw, resizehints);
+       resize(c, wx, wy, NOBORDER(n == 1 ? ww : mw), NOBORDER(wh), resizehints);
 
        if(--n == 0)
                return;
@@ -1442,8 +1441,8 @@ tile(void) {
                h = wh;
 
        for(i = 0, c = nexttiled(c->next); c; c = nexttiled(c->next), i++) {
-               resize(c, x, y, w - 2 * c->bw, /* remainder */ ((i + 1 == n)
-                      ? (wy + wh) - y : h) - 2 * c->bw, resizehints);
+               resize(c, x, y, NOBORDER(w), /* remainder */ ((i + 1 == n)
+                      ? NOBORDER(wy + wh) - y : h), resizehints);
                if(h != wh)
                        y = c->y + c->h + 2 * c->bw;
        }
@@ -1568,6 +1567,20 @@ updategeom(void) {
 }
 
 void
+updatenumlockmask(void) {
+       unsigned int i, j;
+       XModifierKeymap *modmap;
+
+       numlockmask = 0;
+       modmap = XGetModifierMapping(dpy);
+       for(i = 0; i < 8; i++)
+               for(j = 0; j < modmap->max_keypermod; j++)
+                       if(modmap->modifiermap[i * modmap->max_keypermod + j] == XKeysymToKeycode(dpy, XK_Num_Lock))
+                               numlockmask = (1 << i);
+       XFreeModifiermap(modmap);
+}
+
+void
 updatesizehints(Client *c) {
        long msize;
        XSizeHints size;
@@ -1618,7 +1631,7 @@ updatesizehints(Client *c) {
 void
 updatetitle(Client *c) {
        if(!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
-               gettextprop(c->win, wmatom[WMName], c->name, sizeof c->name);
+               gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name);
 }
 
 void
@@ -1703,7 +1716,7 @@ main(int argc, char *argv[]) {
        else if(argc != 1)
                die("usage: dwm [-v]\n");
 
-       if(!XSupportsLocale())
+       if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())
                fprintf(stderr, "warning: no locale support\n");
 
        if(!(dpy = XOpenDisplay(0)))