JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
slave deck almost done
[dwm.git] / dwm.c
diff --git a/dwm.c b/dwm.c
index f873a42..d5eec04 100644 (file)
--- a/dwm.c
+++ b/dwm.c
@@ -91,7 +91,7 @@ struct Client {
        int basew, baseh, incw, inch, maxw, maxh, minw, minh;
        int bw, oldbw;
        unsigned int tags;
        int basew, baseh, incw, inch, maxw, maxh, minw, minh;
        int bw, oldbw;
        unsigned int tags;
-       Bool isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
+       Bool isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, screen_hog;
        Client *next;
        Client *snext;
        Monitor *mon;
        Client *next;
        Client *snext;
        Monitor *mon;
@@ -137,6 +137,7 @@ typedef struct {
        const char *title;
        unsigned int tags;
        Bool isfloating;
        const char *title;
        unsigned int tags;
        Bool isfloating;
+       Bool screen_hog;
        int monitor;
 } Rule;
 
        int monitor;
 } Rule;
 
@@ -145,6 +146,7 @@ static void applyrules(Client *c);
 static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact);
 static void arrange(Monitor *m);
 static void arrangemon(Monitor *m);
 static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact);
 static void arrange(Monitor *m);
 static void arrangemon(Monitor *m);
+static void attach_as_master(Client *c);
 static void attach(Client *c);
 static void attachstack(Client *c);
 static void buttonpress(XEvent *e);
 static void attach(Client *c);
 static void attachstack(Client *c);
 static void buttonpress(XEvent *e);
@@ -184,6 +186,7 @@ static void monocle(Monitor *m);
 static void motionnotify(XEvent *e);
 static void movemouse(const Arg *arg);
 static Client *nexttiled(Client *c);
 static void motionnotify(XEvent *e);
 static void movemouse(const Arg *arg);
 static Client *nexttiled(Client *c);
+static Client *nextvisible(Client *c);
 static void pop(Client *);
 static void propertynotify(XEvent *e);
 static void quit(const Arg *arg);
 static void pop(Client *);
 static void propertynotify(XEvent *e);
 static void quit(const Arg *arg);
@@ -207,6 +210,7 @@ static void sigchld(int unused);
 static void spawn(const Arg *arg);
 static void tag(const Arg *arg);
 static void tagmon(const Arg *arg);
 static void spawn(const Arg *arg);
 static void tag(const Arg *arg);
 static void tagmon(const Arg *arg);
+static void jason_layout(Monitor *);
 static void tile(Monitor *);
 static void togglebar(const Arg *arg);
 static void togglefloating(const Arg *arg);
 static void tile(Monitor *);
 static void togglebar(const Arg *arg);
 static void togglefloating(const Arg *arg);
@@ -269,8 +273,10 @@ static Window root;
 
 // unfocused windows get transparent (feature)
 static const unsigned long unfocused_opacity[] = { 0xbfffffff };
 
 // unfocused windows get transparent (feature)
 static const unsigned long unfocused_opacity[] = { 0xbfffffff };
+static const unsigned long invisible_opacity[] = { 0x00000000 };
 static void window_set_opaque(Client *c);
 static void window_set_translucent(Client *c);
 static void window_set_opaque(Client *c);
 static void window_set_translucent(Client *c);
+static void window_set_invisible(Client *c);
 void
 window_set_opaque(Client *c) {
        XDeleteProperty(dpy, c->win, netatom[NetWMWindowOpacity]);
 void
 window_set_opaque(Client *c) {
        XDeleteProperty(dpy, c->win, netatom[NetWMWindowOpacity]);
@@ -279,6 +285,10 @@ void
 window_set_translucent(Client *c) {
        XChangeProperty(dpy, c->win, netatom[NetWMWindowOpacity], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)unfocused_opacity, 1);
 }
 window_set_translucent(Client *c) {
        XChangeProperty(dpy, c->win, netatom[NetWMWindowOpacity], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)unfocused_opacity, 1);
 }
+void
+window_set_invisible(Client *c) {
+       XChangeProperty(dpy, c->win, netatom[NetWMWindowOpacity], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)invisible_opacity, 1);
+}
 
 
 /* configuration, allows nested code to access above variables */
 
 
 /* configuration, allows nested code to access above variables */
@@ -297,19 +307,20 @@ applyrules(Client *c) {
        XClassHint ch = { NULL, NULL };
 
        /* rule matching */
        XClassHint ch = { NULL, NULL };
 
        /* rule matching */
-       c->isfloating = c->tags = 0;
+       c->isfloating = c->tags = c->screen_hog = 0;
        XGetClassHint(dpy, c->win, &ch);
        class    = ch.res_class ? ch.res_class : broken;
        instance = ch.res_name  ? ch.res_name  : broken;
 
        for(i = 0; i < LENGTH(rules); i++) {
                r = &rules[i];
        XGetClassHint(dpy, c->win, &ch);
        class    = ch.res_class ? ch.res_class : broken;
        instance = ch.res_name  ? ch.res_name  : broken;
 
        for(i = 0; i < LENGTH(rules); i++) {
                r = &rules[i];
-               if((!r->title || strstr(c->name, r->title))
+               if((!r->title || c->name == strstr(c->name, r->title))
                && (!r->class || strstr(class, r->class))
                && (!r->instance || strstr(instance, r->instance)))
                {
                        c->isfloating = r->isfloating;
                        c->tags |= r->tags;
                && (!r->class || strstr(class, r->class))
                && (!r->instance || strstr(instance, r->instance)))
                {
                        c->isfloating = r->isfloating;
                        c->tags |= r->tags;
+                       c->screen_hog = r->screen_hog;
                        for(m = mons; m && m->num != r->monitor; m = m->next);
                        if(m)
                                c->mon = m;
                        for(m = mons; m && m->num != r->monitor; m = m->next);
                        if(m)
                                c->mon = m;
@@ -409,25 +420,24 @@ arrangemon(Monitor *m) {
 }
 
 void
 }
 
 void
+attach_as_master(Client *c) {
+       c->next = c->mon->clients;
+       c->mon->clients = c;
+}
+void
 attach(Client *c) {
        if (c->mon->sel) {
                c->next = c->mon->sel->next;
                c->mon->sel->next = c;
        } else {
 attach(Client *c) {
        if (c->mon->sel) {
                c->next = c->mon->sel->next;
                c->mon->sel->next = c;
        } else {
-               c->next = c->mon->clients;
-               c->mon->clients = c;
+               attach_as_master(c);
        }
 }
 
 void
 attachstack(Client *c) {
        }
 }
 
 void
 attachstack(Client *c) {
-       if (c->mon->sel) {
-               c->snext = c->mon->sel->snext;
-               c->mon->sel->snext = c;
-       } else {
-               c->snext = c->mon->stack;
-               c->mon->stack = c;
-       }
+       c->snext = c->mon->stack;
+       c->mon->stack = c;
 }
 
 void
 }
 
 void
@@ -551,6 +561,7 @@ clientmessage(XEvent *e) {
                                      || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
        }
        else if(cme->message_type == netatom[NetActiveWindow]) {
                                      || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
        }
        else if(cme->message_type == netatom[NetActiveWindow]) {
+               return;
                if(!ISVISIBLE(c)) {
                        c->mon->seltags ^= 1;
                        c->mon->tagset[c->mon->seltags] = c->tags;
                if(!ISVISIBLE(c)) {
                        c->mon->seltags ^= 1;
                        c->mon->tagset[c->mon->seltags] = c->tags;
@@ -686,19 +697,24 @@ detach(Client *c) {
        *tc = c->next;
 }
 
        *tc = c->next;
 }
 
+// NOTE: the stack is for z-order and most-recently-focused
+// only mon->clients determines position in visible layout
 void
 detachstack(Client *c) {
        Client *prev = NULL, *next_sel = NULL, *i;
        for(i = c->mon->stack; i && i != c; i = i->snext) {
                prev = i;
 void
 detachstack(Client *c) {
        Client *prev = NULL, *next_sel = NULL, *i;
        for(i = c->mon->stack; i && i != c; i = i->snext) {
                prev = i;
-               if(ISVISIBLE(i))
-                       next_sel = i;
        }
        if(c == c->mon->sel) {
        }
        if(c == c->mon->sel) {
-               if (!next_sel) { // if no visible window prev, find first visible
-                       for(i = c->mon->stack; i && !ISVISIBLE(i); i = i->snext)
+               // find last visible window before c
+               // WARNING if you detach() before detachstack() this will select last visible window
+               for(i = nextvisible(c->mon->clients); i && i != c; i = nextvisible(i->next))
+                       next_sel = i;
+               // failing that, find first visible window (besides c)
+               if (!next_sel)
+                       for(i = nextvisible(c->mon->clients); i && i == c; i = nextvisible(i->next));
+                       if (i != c)
                                next_sel = i;
                                next_sel = i;
-               }
                c->mon->sel = next_sel;
        }
        if (prev) {
                c->mon->sel = next_sel;
        }
        if (prev) {
@@ -1227,10 +1243,16 @@ nexttiled(Client *c) {
        return c;
 }
 
        return c;
 }
 
+Client *
+nextvisible(Client *c) {
+       for(; c && !ISVISIBLE(c); c = c->next);
+       return c;
+}
+
 void
 pop(Client *c) {
        detach(c);
 void
 pop(Client *c) {
        detach(c);
-       attach(c);
+       attach_as_master(c);
        focus(c);
        arrange(c->mon);
 }
        focus(c);
        arrange(c->mon);
 }
@@ -1430,8 +1452,8 @@ sendmon(Client *c, Monitor *m) {
        if(c->mon == m)
                return;
        unfocus(c, True);
        if(c->mon == m)
                return;
        unfocus(c, True);
-       detach(c);
        detachstack(c);
        detachstack(c);
+       detach(c);
        c->mon = m;
        c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
        attach(c);
        c->mon = m;
        c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
        attach(c);
@@ -1622,6 +1644,17 @@ sigchld(int unused) {
 
 void
 spawn(const Arg *arg) {
 
 void
 spawn(const Arg *arg) {
+       int tag = 0, i;
+       if(arg->v == termcmd) {
+               for(i = 0; i < 32; ++i) {
+                       if(selmon->tagset[selmon->seltags] & (1 << i)) {
+                               tag = i;
+                               break;
+                       }
+               }
+               _SWM_WS[8] = swm_tags[tag][0];
+               _SWM_WS[9] = swm_tags[tag][1];
+       }
        if(arg->v == dmenucmd)
                dmenumon[0] = '0' + selmon->num;
        if(fork() == 0) {
        if(arg->v == dmenucmd)
                dmenumon[0] = '0' + selmon->num;
        if(fork() == 0) {
@@ -1662,8 +1695,13 @@ tile(Monitor *m) {
 
        if(n > m->nmaster)
                mw = m->nmaster ? m->ww * m->mfact : 0;
 
        if(n > m->nmaster)
                mw = m->nmaster ? m->ww * m->mfact : 0;
-       else
-               mw = m->ww;
+       else {
+               c = nexttiled(m->clients);
+               if (c && !c->screen_hog)
+                       mw = m->ww * m->mfact;
+               else
+                       mw = m->ww;
+       }
        for(i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
                if(i < m->nmaster) {
                        h = (m->wh - my) / (MIN(n, m->nmaster) - i);
        for(i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
                if(i < m->nmaster) {
                        h = (m->wh - my) / (MIN(n, m->nmaster) - i);
@@ -1678,6 +1716,47 @@ tile(Monitor *m) {
 }
 
 void
 }
 
 void
+jason_layout(Monitor *m) {
+       unsigned int i, n, mw;
+       Client *c, *vis_slave;
+
+       for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+       if(n == 0) {
+               return;
+       }
+
+       c = nexttiled(m->clients);
+       if (c == m->sel) {
+               // if master is selected, show first slave
+               vis_slave = nexttiled(c->next);
+       } else {
+               vis_slave = m->sel;
+       }
+       if(n > 1 || (n == 1 && !c->screen_hog)) {
+               mw = m->ww * m->mfact;
+       } else {
+               // one of these:
+               // * zero tiled windows
+               // * one tiled window that's not a screen hog
+               // * miltiple tiled windows
+               mw = m->ww;
+       }
+       for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
+               if (i == 0) {
+                       resize(c, m->wx, m->wy, mw, m->wh, False);
+               } else {
+                       if (c == vis_slave) {
+                               resize(c, m->wx + mw, m->wy, m->ww - mw, m->wh, False);
+                       } else {
+                               // this function does not get called when focus changes
+                               // resize(c, m->wx + m->ww, m->wy, m->ww - mw, m->wh, False);
+                               resize(c, m->wx + mw, m->wy, m->ww - mw, m->wh, False);
+                       }
+               }
+       }
+}
+
+void
 togglebar(const Arg *arg) {
        selmon->showbar = !selmon->showbar;
        updatebarpos(selmon);
 togglebar(const Arg *arg) {
        selmon->showbar = !selmon->showbar;
        updatebarpos(selmon);
@@ -1725,10 +1804,32 @@ toggleview(const Arg *arg) {
 
 void
 unfocus(Client *c, Bool setfocus) {
 
 void
 unfocus(Client *c, Bool setfocus) {
+       Client *w;
        if(!c)
                return;
        if(!c)
                return;
-       if(!root || c->win!=root)
-               window_set_translucent(c);
+       if(!root || c->win!=root) {
+               w = nexttiled(c->mon->clients);
+               if (!w) {
+                       // no tiled windows
+                       window_set_translucent(c);
+               } else if (w == c) {
+                       // master
+                       window_set_translucent(c);
+               } else {
+                       w = nexttiled(w->next);
+                       if (!w) {
+                               // c must not be tiled
+                               window_set_translucent(c);
+                       } else {
+                               if (w == c) { // first slave
+                                       window_set_translucent(c);
+                               } else {
+                                       window_set_invisible(c);
+                                       window_set_translucent(w);
+                               }
+                       }
+               }
+       }
        grabbuttons(c, False);
        XSetWindowBorder(dpy, c->win, scheme[SchemeNorm].border->rgb);
        if(setfocus) {
        grabbuttons(c, False);
        XSetWindowBorder(dpy, c->win, scheme[SchemeNorm].border->rgb);
        if(setfocus) {
@@ -1743,8 +1844,8 @@ unmanage(Client *c, Bool destroyed) {
        XWindowChanges wc;
 
        /* The server grab construct avoids race conditions. */
        XWindowChanges wc;
 
        /* The server grab construct avoids race conditions. */
-       detach(c);
        detachstack(c);
        detachstack(c);
+       detach(c);
        if(!destroyed) {
                wc.border_width = c->oldbw;
                XGrabServer(dpy);
        if(!destroyed) {
                wc.border_width = c->oldbw;
                XGrabServer(dpy);