X-Git-Url: https://git.armaanb.net/?a=blobdiff_plain;f=dwm.c;h=4cdc1f777f078c8d3a6f413cef27d8186f95ecc5;hb=453d99635e490519626e9c7690812013c8d5acaf;hp=09feae368cec6e4838c4a65cc4837cf61694d0ad;hpb=f40f86fa873bc4acccdf3d929aa0f786993ae31d;p=dwm.git diff --git a/dwm.c b/dwm.c index 09feae3..4cdc1f7 100644 --- a/dwm.c +++ b/dwm.c @@ -40,6 +40,7 @@ #include #endif /* XINERAMA */ #include +#include #include "drw.h" #include "util.h" @@ -111,6 +112,7 @@ typedef struct { void (*arrange)(Monitor *); } Layout; +typedef struct Pertag Pertag; struct Monitor { char ltsymbol[16]; float mfact; @@ -130,6 +132,7 @@ struct Monitor { Monitor *next; Window barwin; const Layout *lt[2]; + Pertag *pertag; }; typedef struct { @@ -147,6 +150,7 @@ static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interac static void arrange(Monitor *m); static void arrangemon(Monitor *m); static void attach(Client *c); +static void attachbottom(Client *c); static void attachstack(Client *c); static void buttonpress(XEvent *e); static void checkotherwm(void); @@ -165,10 +169,12 @@ static void drawbar(Monitor *m); static void drawbars(void); static void enternotify(XEvent *e); static void expose(XEvent *e); +static Client *findbefore(Client *c); static void focus(Client *c); static void focusin(XEvent *e); static void focusmon(const Arg *arg); static void focusstack(const Arg *arg); +static Atom getatomprop(Client *c, Atom prop); static int getrootptr(int *x, int *y); static long getstate(Window w); static int gettextprop(Window w, Atom atom, char *text, unsigned int size); @@ -184,8 +190,10 @@ static void monocle(Monitor *m); static void motionnotify(XEvent *e); static void movemouse(const Arg *arg); static Client *nexttiled(Client *c); -static void pop(Client *); +static Client *prevtiled(Client *c); static void propertynotify(XEvent *e); +static void pushdown(const Arg *arg); +static void pushup(const Arg *arg); static void quit(const Arg *arg); static Monitor *recttomon(int x, int y, int w, int h); static void resize(Client *c, int x, int y, int w, int h, int interact); @@ -235,6 +243,7 @@ static int xerrorstart(Display *dpy, XErrorEvent *ee); static void zoom(const Arg *arg); /* variables */ +static Client *prevzoom = NULL; static const char broken[] = "broken"; static char stext[256]; static int screen; @@ -271,6 +280,15 @@ static Window root, wmcheckwin; /* configuration, allows nested code to access above variables */ #include "config.h" +struct Pertag { + unsigned int curtag, prevtag; /* current and previous tag */ + int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ + float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ + unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */ + const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */ + int showbars[LENGTH(tags) + 1]; /* display bar for the current tag */ +}; + /* compile-time check if all tags fit into an unsigned int bit array. */ struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; @@ -406,6 +424,15 @@ attach(Client *c) c->mon->clients = c; } +void +attachbottom(Client *c) +{ + Client **tc; + c->next = NULL; + for (tc = &c->mon->clients; *tc; tc = &(*tc)->next); + *tc = c; +} + void attachstack(Client *c) { @@ -439,7 +466,7 @@ buttonpress(XEvent *e) arg.ui = 1 << i; } else if (ev->x < x + blw) click = ClkLtSymbol; - else if (ev->x > selmon->ww - TEXTW(stext)) + else if (ev->x > selmon->ww - (int)TEXTW(stext)) click = ClkStatusText; else click = ClkWinTitle; @@ -521,7 +548,7 @@ clientmessage(XEvent *e) if (cme->data.l[1] == netatom[NetWMFullscreen] || cme->data.l[2] == netatom[NetWMFullscreen]) setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */ - || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen))); + || cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */)); } else if (cme->message_type == netatom[NetActiveWindow]) { if (c != selmon->sel && !c->isurgent) seturgent(c, 1); @@ -551,7 +578,6 @@ void configurenotify(XEvent *e) { Monitor *m; - Client *c; XConfigureEvent *ev = &e->xconfigure; int dirty; @@ -564,9 +590,6 @@ configurenotify(XEvent *e) drw_resize(drw, sw, bh); updatebars(); for (m = mons; m; m = m->next) { - for (c = m->clients; c; c = c->next) - if (c->isfullscreen) - resizeclient(c, m->mx, m->my, m->mw, m->mh); XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); } focus(NULL); @@ -631,6 +654,7 @@ Monitor * createmon(void) { Monitor *m; + unsigned int i; m = ecalloc(1, sizeof(Monitor)); m->tagset[0] = m->tagset[1] = 1; @@ -641,6 +665,20 @@ createmon(void) m->lt[0] = &layouts[0]; m->lt[1] = &layouts[1 % LENGTH(layouts)]; strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); + m->pertag = ecalloc(1, sizeof(Pertag)); + m->pertag->curtag = m->pertag->prevtag = 1; + + for (i = 0; i <= LENGTH(tags); i++) { + m->pertag->nmasters[i] = m->nmaster; + m->pertag->mfacts[i] = m->mfact; + + m->pertag->ltidxs[i][0] = m->lt[0]; + m->pertag->ltidxs[i][1] = m->lt[1]; + m->pertag->sellts[i] = m->sellt; + + m->pertag->showbars[i] = m->showbar; + } + return m; } @@ -695,7 +733,7 @@ dirtomon(int dir) void drawbar(Monitor *m) { - int x, w, sw = 0; + int x, w, tw = 0; int boxs = drw->fonts->h / 9; int boxw = drw->fonts->h / 6 + 2; unsigned int i, occ = 0, urg = 0; @@ -704,8 +742,8 @@ drawbar(Monitor *m) /* draw status first so it can be overdrawn by tags later */ if (m == selmon) { /* status is only drawn on selected monitor */ drw_setscheme(drw, scheme[SchemeNorm]); - sw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ - drw_text(drw, m->ww - sw, 0, sw, bh, 0, stext, 0); + tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ + drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); } for (c = m->clients; c; c = c->next) { @@ -728,7 +766,7 @@ drawbar(Monitor *m) drw_setscheme(drw, scheme[SchemeNorm]); x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); - if ((w = m->ww - sw - x) > bh) { + if ((w = m->ww - tw - x) > bh) { if (m->sel) { drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); @@ -780,6 +818,16 @@ expose(XEvent *e) drawbar(m); } +Client * +findbefore(Client *c) +{ + Client *tmp; + if (c == selmon->clients) + return NULL; + for (tmp = selmon->clients; tmp && tmp->next != c; tmp = tmp->next); + return tmp; +} + void focus(Client *c) { @@ -966,7 +1014,7 @@ grabkeys(void) void incnmaster(const Arg *arg) { - selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); arrange(selmon); } @@ -1062,7 +1110,7 @@ manage(Window w, XWindowAttributes *wa) c->isfloating = c->oldstate = trans != None || c->isfixed; if (c->isfloating) XRaiseWindow(dpy, c->win); - attach(c); + attachbottom(c); attachstack(c); XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, (unsigned char *) &(c->win), 1); @@ -1143,8 +1191,6 @@ movemouse(const Arg *arg) if (!(c = selmon->sel)) return; - if (c->isfullscreen) /* no support moving fullscreen windows by mouse */ - return; restack(selmon); ocx = c->x; ocy = c->y; @@ -1199,13 +1245,14 @@ nexttiled(Client *c) return c; } -void -pop(Client *c) -{ - detach(c); - attach(c); - focus(c); - arrange(c->mon); +Client * +prevtiled(Client *c) { + Client *p, *r; + + for(p = selmon->clients, r = NULL; p && p != c; p = p->next) + if(!p->isfloating && ISVISIBLE(p)) + r = p; + return r; } void @@ -1245,6 +1292,49 @@ propertynotify(XEvent *e) } } +void +pushdown(const Arg *arg) { + Client *sel = selmon->sel, *c; + + if(!sel || sel->isfloating) + return; + if((c = nexttiled(sel->next))) { + detach(sel); + sel->next = c->next; + c->next = sel; + } else { + detach(sel); + attach(sel); + } + focus(sel); + arrange(selmon); +} + +void +pushup(const Arg *arg) { + Client *sel = selmon->sel, *c; + + if(!sel || sel->isfloating) + return; + if((c = prevtiled(sel))) { + detach(sel); + sel->next = c; + if(selmon->clients == c) + selmon->clients = sel; + else { + for(c = selmon->clients; c->next != sel->next; c = c->next); + c->next = sel; + } + } else { + for(c = sel; c->next; c = c->next); + detach(sel); + sel->next = NULL; + c->next = sel; + } + focus(sel); + arrange(selmon); +} + void quit(const Arg *arg) { @@ -1298,8 +1388,6 @@ resizemouse(const Arg *arg) if (!(c = selmon->sel)) return; - if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */ - return; restack(selmon); ocx = c->x; ocy = c->y; @@ -1417,7 +1505,7 @@ sendmon(Client *c, Monitor *m) detachstack(c); c->mon = m; c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ - attach(c); + attachbottom(c); attachstack(c); focus(NULL); arrange(NULL); @@ -1476,24 +1564,10 @@ setfullscreen(Client *c, int fullscreen) XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1); c->isfullscreen = 1; - c->oldstate = c->isfloating; - c->oldbw = c->bw; - c->bw = 0; - c->isfloating = 1; - resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); - XRaiseWindow(dpy, c->win); } else if (!fullscreen && c->isfullscreen){ XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, PropModeReplace, (unsigned char*)0, 0); c->isfullscreen = 0; - c->isfloating = c->oldstate; - c->bw = c->oldbw; - c->x = c->oldx; - c->y = c->oldy; - c->w = c->oldw; - c->h = c->oldh; - resizeclient(c, c->x, c->y, c->w, c->h); - arrange(c->mon); } } @@ -1501,9 +1575,9 @@ void setlayout(const Arg *arg) { if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) - selmon->sellt ^= 1; + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; if (arg && arg->v) - selmon->lt[selmon->sellt] = (Layout *)arg->v; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); if (selmon->sel) arrange(selmon); @@ -1520,9 +1594,9 @@ setmfact(const Arg *arg) if (!arg || !selmon->lt[selmon->sellt]->arrange) return; f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; - if (f < 0.1 || f > 0.9) + if (f < 0.05 || f > 0.95) return; - selmon->mfact = f; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; arrange(selmon); } @@ -1618,7 +1692,7 @@ showhide(Client *c) if (ISVISIBLE(c)) { /* show clients top down */ XMoveWindow(dpy, c->win, c->x, c->y); - if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen) + if (!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) resize(c, c->x, c->y, c->w, c->h, 0); showhide(c->snext); } else { @@ -1688,18 +1762,20 @@ tile(Monitor *m) if (i < m->nmaster) { h = (m->wh - my) / (MIN(n, m->nmaster) - i); resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); - my += HEIGHT(c); + if (my + HEIGHT(c) < m->wh) + my += HEIGHT(c); } else { h = (m->wh - ty) / (n - i); resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0); - ty += HEIGHT(c); + if (ty + HEIGHT(c) < m->wh) + ty += HEIGHT(c); } } void togglebar(const Arg *arg) { - selmon->showbar = !selmon->showbar; + selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; updatebarpos(selmon); XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); arrange(selmon); @@ -1710,8 +1786,6 @@ togglefloating(const Arg *arg) { if (!selmon->sel) return; - if (selmon->sel->isfullscreen) /* no support for fullscreen windows */ - return; selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed; if (selmon->sel->isfloating) resize(selmon->sel, selmon->sel->x, selmon->sel->y, @@ -1738,9 +1812,33 @@ void toggleview(const Arg *arg) { unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); + int i; if (newtagset) { selmon->tagset[selmon->seltags] = newtagset; + + if (newtagset == ~0) { + selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->pertag->curtag = 0; + } + + /* test if the user did not select the same tag */ + if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) { + selmon->pertag->prevtag = selmon->pertag->curtag; + for (i = 0; !(newtagset & 1 << i); i++) ; + selmon->pertag->curtag = i + 1; + } + + /* apply settings for this view */ + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; + + if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) + togglebar(NULL); + focus(NULL); arrange(selmon); } @@ -1779,6 +1877,7 @@ unmanage(Client *c, int destroyed) XUngrabServer(dpy); } free(c); + focus(NULL); updateclientlist(); arrange(m); @@ -1897,7 +1996,7 @@ updategeom(void) m->clients = c->next; detachstack(c); c->mon = mons; - attach(c); + attachbottom(c); attachstack(c); } if (m == selmon) @@ -2035,11 +2134,37 @@ updatewmhints(Client *c) void view(const Arg *arg) { + int i; + unsigned int tmptag; + if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) return; selmon->seltags ^= 1; /* toggle sel tagset */ - if (arg->ui & TAGMASK) + if (arg->ui & TAGMASK) { selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; + selmon->pertag->prevtag = selmon->pertag->curtag; + + if (arg->ui == ~0) + selmon->pertag->curtag = 0; + else { + for (i = 0; !(arg->ui & 1 << i); i++) ; + selmon->pertag->curtag = i + 1; + } + } else { + tmptag = selmon->pertag->prevtag; + selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->pertag->curtag = tmptag; + } + + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; + + if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) + togglebar(NULL); + focus(NULL); arrange(selmon); } @@ -2114,14 +2239,38 @@ void zoom(const Arg *arg) { Client *c = selmon->sel; + Client *at = NULL, *cold, *cprevious = NULL; if (!selmon->lt[selmon->sellt]->arrange || (selmon->sel && selmon->sel->isfloating)) return; - if (c == nexttiled(selmon->clients)) - if (!c || !(c = nexttiled(c->next))) - return; - pop(c); + if (c == nexttiled(selmon->clients)) { + at = findbefore(prevzoom); + if (at) + cprevious = nexttiled(at->next); + if (!cprevious || cprevious != prevzoom) { + prevzoom = NULL; + if (!c || !(c = nexttiled(c->next))) + return; + } else + c = cprevious; + } + cold = nexttiled(selmon->clients); + if (c != cold && !at) + at = findbefore(c); + detach(c); + attach(c); + /* swap windows instead of pushing the previous one down */ + if (c != cold && at) { + prevzoom = cold; + if (cold && at != cold) { + detach(cold); + cold->next = at->next; + at->next = cold; + } + } + focus(c); + arrange(c->mon); } int @@ -2138,7 +2287,7 @@ main(int argc, char *argv[]) checkotherwm(); setup(); #ifdef __OpenBSD__ - if (pledge("stdio proc exec", NULL) == -1) + if (pledge("stdio rpath proc exec", NULL) == -1) die("pledge"); #endif /* __OpenBSD__ */ scan();