From cbf1deb725ef07b19846c8cbfc66b09e14520799 Mon Sep 17 00:00:00 2001 From: jon Date: Sun, 13 May 2018 16:36:40 -0500 Subject: [PATCH] Merged pertag --- dwm | Bin 46392 -> 46392 bytes dwm.c | 96 +- dwm.c.orig | 2174 +++++++++++++++++++++++++++++++++++ dwm.o | Bin 54232 -> 54944 bytes patches/dwm-pertag-6.1.diff | 199 ++++ 5 files changed, 2462 insertions(+), 7 deletions(-) create mode 100644 dwm.c.orig create mode 100644 patches/dwm-pertag-6.1.diff diff --git a/dwm b/dwm index 05f252c42af00f38e4deee7755192319e7cbbd26..b77b9aa1fe4cbfcf847981aa54f2dae37973f44f 100755 GIT binary patch delta 12910 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 bTmRO7`QHR 31 ? -1 : 1]; }; @@ -532,6 +544,7 @@ clientmessage(XEvent *e) { XClientMessageEvent *cme = &e->xclient; Client *c = wintoclient(cme->window); + int i; if (!c) return; @@ -543,6 +556,8 @@ clientmessage(XEvent *e) if (!ISVISIBLE(c)) { c->mon->seltags ^= 1; c->mon->tagset[c->mon->seltags] = c->tags; + for(i=0; !(c->tags & 1 << i); i++); + view(&(Arg){.ui = 1 << i}); } pop(c); } @@ -646,6 +661,7 @@ Monitor * createmon(void) { Monitor *m; + int i; m = ecalloc(1, sizeof(Monitor)); m->tagset[0] = m->tagset[1] = 1; @@ -656,6 +672,27 @@ createmon(void) m->lt[0] = &layouts[0]; m->lt[1] = &layouts[1 % LENGTH(layouts)]; strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); + if (!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag)))) + die("fatal: could not malloc() %u bytes\n", sizeof(Pertag)); + m->pertag->curtag = m->pertag->prevtag = 1; + for(i=0; i <= LENGTH(tags); i++) { + /* init nmaster */ + m->pertag->nmasters[i] = m->nmaster; + + /* init mfacts */ + m->pertag->mfacts[i] = m->mfact; + + /* init layouts */ + m->pertag->ltidxs[i][0] = m->lt[0]; + m->pertag->ltidxs[i][1] = m->lt[1]; + m->pertag->sellts[i] = m->sellt; + + /* init showbar */ + m->pertag->showbars[i] = m->showbar; + + /* swap focus and zoomswap*/ + m->pertag->prevzooms[i] = NULL; + } return m; } @@ -990,7 +1027,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); } @@ -1550,10 +1587,13 @@ setfullscreen(Client *c, int fullscreen) void setlayout(const Arg *arg) { - if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) - selmon->sellt ^= 1; + if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) { + selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; + } if (arg && arg->v) - selmon->lt[selmon->sellt] = (Layout *)arg->v; + selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); if (selmon->sel) arrange(selmon); @@ -1572,7 +1612,7 @@ setmfact(const Arg *arg) f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; if (f < 0.1 || f > 0.9) return; - selmon->mfact = f; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; arrange(selmon); } @@ -1725,7 +1765,7 @@ tile(Monitor *m) 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); @@ -1764,9 +1804,29 @@ void toggleview(const Arg *arg) { unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); + int i; if (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; + } selmon->tagset[selmon->seltags] = newtagset; + + /* 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); } @@ -2064,11 +2124,33 @@ 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->pertag->prevtag = selmon->pertag->curtag; selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; + 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); } diff --git a/dwm.c.orig b/dwm.c.orig new file mode 100644 index 0000000..4deb268 --- /dev/null +++ b/dwm.c.orig @@ -0,0 +1,2174 @@ +/* See LICENSE file for copyright and license details. + * + * dynamic window manager is designed like any other X client as well. It is + * driven through handling X events. In contrast to other X clients, a window + * manager selects for SubstructureRedirectMask on the root window, to receive + * events about window (dis-)appearance. Only one X connection at a time is + * allowed to select for this event mask. + * + * The event handlers of dwm are organized in an array which is accessed + * whenever a new event has been fetched. This allows event dispatching + * in O(1) time. + * + * Each child of the root window is called a client, except windows which have + * set the override_redirect flag. Clients are organized in a linked client + * list on each monitor, the focus history is remembered through a stack list + * on each monitor. Each client contains a bit array to indicate the tags of a + * client. + * + * Keys and tagging rules are organized as arrays and defined in config.h. + * + * To understand everything else, start reading main(). + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef XINERAMA +#include +#endif /* XINERAMA */ +#include + +#include "drw.h" +#include "util.h" + +/* macros */ +#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) +#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) +#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ + * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) +#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) +#define LENGTH(X) (sizeof X / sizeof X[0]) +#define MOUSEMASK (BUTTONMASK|PointerMotionMask) +#define WIDTH(X) ((X)->w + 2 * (X)->bw + gappx) +#define HEIGHT(X) ((X)->h + 2 * (X)->bw + gappx) +#define TAGMASK ((1 << LENGTH(tags)) - 1) +#define TEXTW(X) (drw_text(drw, 0, 0, 0, 0, (X), 0) + drw->fonts[0]->h) + +/* enums */ +enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ +enum { SchemeNorm, SchemeSel, SchemeLast }; /* color schemes */ +enum { NetSupported, NetWMName, NetWMState, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ +enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ +enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, + ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ + +typedef union { + int i; + unsigned int ui; + float f; + const void *v; +} Arg; + +typedef struct { + unsigned int click; + unsigned int mask; + unsigned int button; + void (*func)(const Arg *arg); + const Arg arg; +} Button; + +typedef struct Monitor Monitor; +typedef struct Client Client; +struct Client { + char name[256]; + float mina, maxa; + int x, y, w, h; + int oldx, oldy, oldw, oldh; + int basew, baseh, incw, inch, maxw, maxh, minw, minh; + int bw, oldbw; + unsigned int tags; + int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; + Client *next; + Client *snext; + Monitor *mon; + Window win; +}; + +typedef struct { + unsigned int mod; + KeySym keysym; + void (*func)(const Arg *); + const Arg arg; +} Key; + +typedef struct { + const char *symbol; + void (*arrange)(Monitor *); +} Layout; + +struct Monitor { + char ltsymbol[16]; + float mfact; + int nmaster; + int num; + int by; /* bar geometry */ + int mx, my, mw, mh; /* screen size */ + int wx, wy, ww, wh; /* window area */ + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; + int showbar; + int topbar; + Client *clients; + Client *sel; + Client *stack; + Monitor *next; + Window barwin; + const Layout *lt[2]; +}; + +typedef struct { + const char *class; + const char *instance; + const char *title; + unsigned int tags; + int isfloating; + int monitor; +} Rule; + +/* function declarations */ +static void applyrules(Client *c); +static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); +static void arrange(Monitor *m); +static void arrangemon(Monitor *m); +static void attach(Client *c); +static void attachstack(Client *c); +static void buttonpress(XEvent *e); +static void checkotherwm(void); +static void cleanup(void); +static void cleanupmon(Monitor *mon); +static void clearurgent(Client *c); +static void clientmessage(XEvent *e); +static void configure(Client *c); +static void configurenotify(XEvent *e); +static void configurerequest(XEvent *e); +static Monitor *createmon(void); +static void destroynotify(XEvent *e); +static void detach(Client *c); +static void detachstack(Client *c); +static Monitor *dirtomon(int dir); +static void drawbar(Monitor *m); +static void drawbars(void); +static void enternotify(XEvent *e); +static void expose(XEvent *e); +static void focus(Client *c); +static void focusin(XEvent *e); +static void focusmon(const Arg *arg); +static void focusstack(const Arg *arg); +static int getrootptr(int *x, int *y); +static long getstate(Window w); +static int gettextprop(Window w, Atom atom, char *text, unsigned int size); +static void grabbuttons(Client *c, int focused); +static void grabkeys(void); +static void incnmaster(const Arg *arg); +static void keypress(XEvent *e); +static void killclient(const Arg *arg); +static void manage(Window w, XWindowAttributes *wa); +static void mappingnotify(XEvent *e); +static void maprequest(XEvent *e); +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 void propertynotify(XEvent *e); +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); +static void resizeclient(Client *c, int x, int y, int w, int h); +static void resizemouse(const Arg *arg); +static void restack(Monitor *m); +static void run(void); +static void scan(void); +static int sendevent(Client *c, Atom proto); +static void sendmon(Client *c, Monitor *m); +static void setclientstate(Client *c, long state); +static void setfocus(Client *c); +static void setfullscreen(Client *c, int fullscreen); +static void setlayout(const Arg *arg); +static void setmfact(const Arg *arg); +static void setup(void); +static void showhide(Client *c); +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 tile(Monitor *); +static void togglebar(const Arg *arg); +static void togglefloating(const Arg *arg); +static void toggletag(const Arg *arg); +static void toggleview(const Arg *arg); +static void unfocus(Client *c, int setfocus); +static void unmanage(Client *c, int destroyed); +static void unmapnotify(XEvent *e); +static int updategeom(void); +static void updatebarpos(Monitor *m); +static void updatebars(void); +static void updateclientlist(void); +static void updatenumlockmask(void); +static void updatesizehints(Client *c); +static void updatestatus(void); +static void updatewindowtype(Client *c); +static void updatetitle(Client *c); +static void updatewmhints(Client *c); +static void view(const Arg *arg); +static Client *wintoclient(Window w); +static Monitor *wintomon(Window w); +static int xerror(Display *dpy, XErrorEvent *ee); +static int xerrordummy(Display *dpy, XErrorEvent *ee); +static int xerrorstart(Display *dpy, XErrorEvent *ee); +static void zoom(const Arg *arg); + +/* variables */ +static const char broken[] = "broken"; +static char stext[256]; +static int screen; +static int sw, sh; /* X display screen geometry width, height */ +static int bh, blw = 0; /* bar geometry */ +static int (*xerrorxlib)(Display *, XErrorEvent *); +static unsigned int numlockmask = 0; +static void (*handler[LASTEvent]) (XEvent *) = { + [ButtonPress] = buttonpress, + [ClientMessage] = clientmessage, + [ConfigureRequest] = configurerequest, + [ConfigureNotify] = configurenotify, + [DestroyNotify] = destroynotify, + [EnterNotify] = enternotify, + [Expose] = expose, + [FocusIn] = focusin, + [KeyPress] = keypress, + [MappingNotify] = mappingnotify, + [MapRequest] = maprequest, + [MotionNotify] = motionnotify, + [PropertyNotify] = propertynotify, + [UnmapNotify] = unmapnotify +}; +static Atom wmatom[WMLast], netatom[NetLast]; +static int running = 1; +static Cur *cursor[CurLast]; +static ClrScheme scheme[SchemeLast]; +static Display *dpy; +static Drw *drw; +static Monitor *mons, *selmon; +static Window root; + +/* configuration, allows nested code to access above variables */ +#include "config.h" + +/* compile-time check if all tags fit into an unsigned int bit array. */ +struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +/* function implementations */ +void +applyrules(Client *c) +{ + const char *class, *instance; + unsigned int i; + const Rule *r; + Monitor *m; + XClassHint ch = { NULL, NULL }; + + /* rule matching */ + c->isfloating = 0; + c->tags = 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]; + if ((!r->title || 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; + for (m = mons; m && m->num != r->monitor; m = m->next); + if (m) + c->mon = m; + } + } + if (ch.res_class) + XFree(ch.res_class); + if (ch.res_name) + XFree(ch.res_name); + c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags]; +} + +int +applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact) +{ + int baseismin; + Monitor *m = c->mon; + + /* set minimum possible */ + *w = MAX(1, *w); + *h = MAX(1, *h); + if (interact) { + if (*x > sw) + *x = sw - WIDTH(c); + if (*y > sh) + *y = sh - HEIGHT(c); + if (*x + *w + 2 * c->bw < 0) + *x = 0; + if (*y + *h + 2 * c->bw < 0) + *y = 0; + } else { + if (*x >= m->wx + m->ww) + *x = m->wx + m->ww - WIDTH(c); + if (*y >= m->wy + m->wh) + *y = m->wy + m->wh - HEIGHT(c); + if (*x + *w + 2 * c->bw <= m->wx) + *x = m->wx; + if (*y + *h + 2 * c->bw <= m->wy) + *y = m->wy; + } + if (*h < bh) + *h = bh; + if (*w < bh) + *w = bh; + if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) { + /* see last two sentences in ICCCM 4.1.2.3 */ + baseismin = c->basew == c->minw && c->baseh == c->minh; + 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) + *w = *h * c->maxa + 0.5; + else if (c->mina < (float)*h / *w) + *h = *w * c->mina + 0.5; + } + if (baseismin) { /* increment calculation requires this */ + *w -= c->basew; + *h -= c->baseh; + } + /* adjust for increment value */ + if (c->incw) + *w -= *w % c->incw; + if (c->inch) + *h -= *h % c->inch; + /* restore base dimensions */ + *w = MAX(*w + c->basew, c->minw); + *h = MAX(*h + c->baseh, c->minh); + if (c->maxw) + *w = MIN(*w, c->maxw); + if (c->maxh) + *h = MIN(*h, c->maxh); + } + return *x != c->x || *y != c->y || *w != c->w || *h != c->h; +} + +void +arrange(Monitor *m) +{ + if (m) + showhide(m->stack); + else for (m = mons; m; m = m->next) + showhide(m->stack); + if (m) { + arrangemon(m); + restack(m); + } else for (m = mons; m; m = m->next) + arrangemon(m); +} + +void +arrangemon(Monitor *m) +{ + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); + if (m->lt[m->sellt]->arrange) + m->lt[m->sellt]->arrange(m); +} + +void +attach(Client *c) +{ + c->next = c->mon->clients; + c->mon->clients = c; +} + +void +attachstack(Client *c) +{ + c->snext = c->mon->stack; + c->mon->stack = c; +} + +void +buttonpress(XEvent *e) +{ + unsigned int i, x, click; + Arg arg = {0}; + Client *c; + Monitor *m; + XButtonPressedEvent *ev = &e->xbutton; + + click = ClkRootWin; + /* focus monitor if necessary */ + if ((m = wintomon(ev->window)) && m != selmon) { + unfocus(selmon->sel, 1); + selmon = m; + focus(NULL); + } + if (ev->window == selmon->barwin) { + i = x = 0; + unsigned int occ = 0; + for(c = m->clients; c; c = c->next) + occ |= c->tags; + do { + /* do not reserve space for vacant tags */ + if(!(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) + continue; + x += TEXTW(tags[i]); + } while (ev->x >= x && ++i < LENGTH(tags)); + if (i < LENGTH(tags)) { + click = ClkTagBar; + arg.ui = 1 << i; + } else if (ev->x < x + blw) + click = ClkLtSymbol; + else if (ev->x > selmon->ww - TEXTW(stext)) + click = ClkStatusText; + else + click = ClkWinTitle; + } else if ((c = wintoclient(ev->window))) { + focus(c); + click = ClkClientWin; + } + 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 && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); +} + +void +checkotherwm(void) +{ + xerrorxlib = XSetErrorHandler(xerrorstart); + /* this causes an error if some other window manager is running */ + XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask); + XSync(dpy, False); + XSetErrorHandler(xerror); + XSync(dpy, False); +} + +void +cleanup(void) +{ + Arg a = {.ui = ~0}; + Layout foo = { "", NULL }; + Monitor *m; + size_t i; + + view(&a); + selmon->lt[selmon->sellt] = &foo; + for (m = mons; m; m = m->next) + while (m->stack) + unmanage(m->stack, 0); + XUngrabKey(dpy, AnyKey, AnyModifier, root); + while (mons) + cleanupmon(mons); + for (i = 0; i < CurLast; i++) + drw_cur_free(drw, cursor[i]); + for (i = 0; i < SchemeLast; i++) { + drw_clr_free(scheme[i].border); + drw_clr_free(scheme[i].bg); + drw_clr_free(scheme[i].fg); + } + drw_free(drw); + XSync(dpy, False); + XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); +} + +void +cleanupmon(Monitor *mon) +{ + Monitor *m; + + if (mon == mons) + mons = mons->next; + else { + for (m = mons; m && m->next != mon; m = m->next); + m->next = mon->next; + } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); + free(mon); +} + +void +clearurgent(Client *c) +{ + XWMHints *wmh; + + c->isurgent = 0; + if (!(wmh = XGetWMHints(dpy, c->win))) + return; + wmh->flags &= ~XUrgencyHint; + XSetWMHints(dpy, c->win, wmh); + XFree(wmh); +} + +void +clientmessage(XEvent *e) +{ + XClientMessageEvent *cme = &e->xclient; + Client *c = wintoclient(cme->window); + + if (!c) + return; + if (cme->message_type == netatom[NetWMState]) { + 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))); + } else if (cme->message_type == netatom[NetActiveWindow]) { + if (!ISVISIBLE(c)) { + c->mon->seltags ^= 1; + c->mon->tagset[c->mon->seltags] = c->tags; + } + pop(c); + } +} + +void +configure(Client *c) +{ + XConfigureEvent ce; + + ce.type = ConfigureNotify; + ce.display = dpy; + ce.event = c->win; + ce.window = c->win; + ce.x = c->x; + ce.y = c->y; + ce.width = c->w; + ce.height = c->h; + ce.border_width = c->bw; + ce.above = None; + ce.override_redirect = False; + XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce); +} + +void +configurenotify(XEvent *e) +{ + Monitor *m; + XConfigureEvent *ev = &e->xconfigure; + int dirty; + + /* TODO: updategeom handling sucks, needs to be simplified */ + if (ev->window == root) { + dirty = (sw != ev->width || sh != ev->height); + sw = ev->width; + sh = ev->height; + if (updategeom() || dirty) { + drw_resize(drw, sw, bh); + updatebars(); + for (m = mons; m; m = m->next) + XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); + focus(NULL); + arrange(NULL); + } + } +} + +void +configurerequest(XEvent *e) +{ + Client *c; + Monitor *m; + XConfigureRequestEvent *ev = &e->xconfigurerequest; + XWindowChanges wc; + + if ((c = wintoclient(ev->window))) { + if (ev->value_mask & CWBorderWidth) + c->bw = ev->border_width; + else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) { + m = c->mon; + if (ev->value_mask & CWX) { + c->oldx = c->x; + c->x = m->mx + ev->x; + } + if (ev->value_mask & CWY) { + c->oldy = c->y; + c->y = m->my + ev->y; + } + if (ev->value_mask & CWWidth) { + c->oldw = c->w; + c->w = ev->width; + } + if (ev->value_mask & CWHeight) { + c->oldh = c->h; + c->h = ev->height; + } + if ((c->x + c->w) > m->mx + m->mw && c->isfloating) + c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2); /* center in x direction */ + if ((c->y + c->h) > m->my + m->mh && c->isfloating) + c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */ + if ((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight))) + configure(c); + if (ISVISIBLE(c)) + XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); + } else + configure(c); + } else { + wc.x = ev->x; + wc.y = ev->y; + wc.width = ev->width; + wc.height = ev->height; + wc.border_width = ev->border_width; + wc.sibling = ev->above; + wc.stack_mode = ev->detail; + XConfigureWindow(dpy, ev->window, ev->value_mask, &wc); + } + XSync(dpy, False); +} + +Monitor * +createmon(void) +{ + Monitor *m; + + m = ecalloc(1, sizeof(Monitor)); + m->tagset[0] = m->tagset[1] = 1; + m->mfact = mfact; + m->nmaster = nmaster; + m->showbar = showbar; + m->topbar = topbar; + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); + return m; +} + +void +destroynotify(XEvent *e) +{ + Client *c; + XDestroyWindowEvent *ev = &e->xdestroywindow; + + if ((c = wintoclient(ev->window))) + unmanage(c, 1); +} + +void +detach(Client *c) +{ + Client **tc; + + for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next); + *tc = c->next; +} + +void +detachstack(Client *c) +{ + Client **tc, *t; + + for (tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext); + *tc = c->snext; + + if (c == c->mon->sel) { + for (t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext); + c->mon->sel = t; + } +} + +Monitor * +dirtomon(int dir) +{ + Monitor *m = NULL; + + if (dir > 0) { + if (!(m = selmon->next)) + m = mons; + } else if (selmon == mons) + for (m = mons; m->next; m = m->next); + else + for (m = mons; m->next != selmon; m = m->next); + return m; +} + +void +drawbar(Monitor *m) +{ + int x, xx, w, dx; + unsigned int i, occ = 0, urg = 0; + Client *c; + + dx = (drw->fonts[0]->ascent + drw->fonts[0]->descent + 2) / 4; + + for (c = m->clients; c; c = c->next) { + occ |= c->tags; + if (c->isurgent) + urg |= c->tags; + } + x = 0; + for (i = 0; i < LENGTH(tags); i++) { + /* do not draw vacant tags */ + if(!(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) + continue; + w = TEXTW(tags[i]); + drw_setscheme(drw, m->tagset[m->seltags] & 1 << i ? &scheme[SchemeSel] : &scheme[SchemeNorm]); + drw_text(drw, x, 0, w, bh, tags[i], urg & 1 << i); + drw_rect(drw, x + 1, 1, dx, dx, m == selmon && selmon->sel && selmon->sel->tags & 1 << i, + 0, urg & 1 << i); + x += w; + } + w = blw = TEXTW(m->ltsymbol); + drw_setscheme(drw, &scheme[SchemeNorm]); + drw_text(drw, x, 0, w, bh, m->ltsymbol, 0); + x += w; + xx = x; + if (m == selmon) { /* status is only drawn on selected monitor */ + w = TEXTW(stext); + x = m->ww - w; + if (x < xx) { + x = xx; + w = m->ww - xx; + } + drw_text(drw, x, 0, w, bh, stext, 0); + } else + x = m->ww; + if ((w = x - xx) > bh) { + x = xx; + if (m->sel) { + drw_setscheme(drw, m == selmon ? &scheme[SchemeSel] : &scheme[SchemeNorm]); + drw_text(drw, x, 0, w, bh, m->sel->name, 0); + drw_rect(drw, x + 1, 1, dx, dx, m->sel->isfixed, m->sel->isfloating, 0); + } else { + drw_setscheme(drw, &scheme[SchemeNorm]); + drw_rect(drw, x, 0, w, bh, 1, 0, 1); + } + } + drw_map(drw, m->barwin, 0, 0, m->ww, bh); +} + +void +drawbars(void) +{ + Monitor *m; + + for (m = mons; m; m = m->next) + drawbar(m); +} + +void +enternotify(XEvent *e) +{ + Client *c; + Monitor *m; + XCrossingEvent *ev = &e->xcrossing; + + if ((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root) + return; + c = wintoclient(ev->window); + m = c ? c->mon : wintomon(ev->window); + if (m != selmon) { + unfocus(selmon->sel, 1); + selmon = m; + } else if (!c || c == selmon->sel) + return; + focus(c); +} + +void +expose(XEvent *e) +{ + Monitor *m; + XExposeEvent *ev = &e->xexpose; + + if (ev->count == 0 && (m = wintomon(ev->window))) + drawbar(m); +} + +void +focus(Client *c) +{ + if (!c || !ISVISIBLE(c)) + for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext); + /* was if (selmon->sel) */ + if (selmon->sel && selmon->sel != c) + unfocus(selmon->sel, 0); + if (c) { + if (c->mon != selmon) + selmon = c->mon; + if (c->isurgent) + clearurgent(c); + detachstack(c); + attachstack(c); + grabbuttons(c, 1); + XSetWindowBorder(dpy, c->win, scheme[SchemeSel].border->pix); + setfocus(c); + } else { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); + } + selmon->sel = c; + drawbars(); +} + +/* there are some broken focus acquiring clients */ +void +focusin(XEvent *e) +{ + XFocusChangeEvent *ev = &e->xfocus; + + if (selmon->sel && ev->window != selmon->sel->win) + setfocus(selmon->sel); +} + +void +focusmon(const Arg *arg) +{ + Monitor *m; + + if (!mons->next) + return; + if ((m = dirtomon(arg->i)) == selmon) + return; + unfocus(selmon->sel, 0); /* s/1/0/ fixes input focus issues + in gedit and anjuta */ + selmon = m; + focus(NULL); +} + +void +focusstack(const Arg *arg) +{ + Client *c = NULL, *i; + + if (!selmon->sel) + return; + if (arg->i > 0) { + for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); + if (!c) + for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next); + } else { + for (i = selmon->clients; i != selmon->sel; i = i->next) + if (ISVISIBLE(i)) + c = i; + if (!c) + for (; i; i = i->next) + if (ISVISIBLE(i)) + c = i; + } + if (c) { + focus(c); + restack(selmon); + } +} + +Atom +getatomprop(Client *c, Atom prop) +{ + int di; + unsigned long dl; + unsigned char *p = NULL; + Atom da, atom = None; + + if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, + &da, &di, &dl, &dl, &p) == Success && p) { + atom = *(Atom *)p; + XFree(p); + } + return atom; +} + +int +getrootptr(int *x, int *y) +{ + int di; + unsigned int dui; + Window dummy; + + return XQueryPointer(dpy, root, &dummy, &dummy, x, y, &di, &di, &dui); +} + +long +getstate(Window w) +{ + int format; + long result = -1; + unsigned char *p = NULL; + unsigned long n, extra; + Atom real; + + if (XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState], + &real, &format, &n, &extra, (unsigned char **)&p) != Success) + return -1; + if (n != 0) + result = *p; + XFree(p); + return result; +} + +int +gettextprop(Window w, Atom atom, char *text, unsigned int size) +{ + char **list = NULL; + int n; + XTextProperty name; + + if (!text || size == 0) + return 0; + text[0] = '\0'; + XGetTextProperty(dpy, w, &name, atom); + if (!name.nitems) + return 0; + if (name.encoding == XA_STRING) + strncpy(text, (char *)name.value, size - 1); + else { + if (XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) { + strncpy(text, *list, size - 1); + XFreeStringList(list); + } + } + text[size - 1] = '\0'; + XFree(name.value); + return 1; +} + +void +grabbuttons(Client *c, int focused) +{ + 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) +{ + updatenumlockmask(); + { + 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++) + 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); + } +} + +void +incnmaster(const Arg *arg) +{ + selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); +} + +#ifdef XINERAMA +static int +isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info) +{ + while (n--) + if (unique[n].x_org == info->x_org && unique[n].y_org == info->y_org + && unique[n].width == info->width && unique[n].height == info->height) + return 0; + return 1; +} +#endif /* XINERAMA */ + +void +keypress(XEvent *e) +{ + unsigned int i; + KeySym keysym; + XKeyEvent *ev; + + ev = &e->xkey; + keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); + for (i = 0; i < LENGTH(keys); i++) + if (keysym == keys[i].keysym + && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) + && keys[i].func) + keys[i].func(&(keys[i].arg)); +} + +void +killclient(const Arg *arg) +{ + if (!selmon->sel) + return; + if (!sendevent(selmon->sel, wmatom[WMDelete])) { + XGrabServer(dpy); + XSetErrorHandler(xerrordummy); + XSetCloseDownMode(dpy, DestroyAll); + XKillClient(dpy, selmon->sel->win); + XSync(dpy, False); + XSetErrorHandler(xerror); + XUngrabServer(dpy); + } +} + +void +manage(Window w, XWindowAttributes *wa) +{ + Client *c, *t = NULL; + Window trans = None; + XWindowChanges wc; + + c = ecalloc(1, sizeof(Client)); + c->win = w; + updatetitle(c); + if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { + c->mon = t->mon; + c->tags = t->tags; + } else { + c->mon = selmon; + applyrules(c); + } + /* geometry */ + c->x = c->oldx = wa->x; + c->y = c->oldy = wa->y; + c->w = c->oldw = wa->width; + c->h = c->oldh = wa->height; + c->oldbw = wa->border_width; + + if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw) + c->x = c->mon->mx + c->mon->mw - WIDTH(c); + if (c->y + HEIGHT(c) > c->mon->my + c->mon->mh) + c->y = c->mon->my + c->mon->mh - HEIGHT(c); + c->x = MAX(c->x, c->mon->mx); + /* only fix client y-offset, if the client center might cover the bar */ + c->y = MAX(c->y, ((c->mon->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx) + && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my); + c->bw = borderpx; + + wc.border_width = c->bw; + XConfigureWindow(dpy, w, CWBorderWidth, &wc); + XSetWindowBorder(dpy, w, scheme[SchemeNorm].border->pix); + configure(c); /* propagates border_width, if size doesn't change */ + updatewindowtype(c); + updatesizehints(c); + updatewmhints(c); + XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); + grabbuttons(c, 0); + if (!c->isfloating) + c->isfloating = c->oldstate = trans != None || c->isfixed; + if (c->isfloating) + XRaiseWindow(dpy, c->win); + attach(c); + attachstack(c); + XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, + (unsigned char *) &(c->win), 1); + XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */ + setclientstate(c, NormalState); + if (c->mon == selmon) + unfocus(selmon->sel, 0); + c->mon->sel = c; + arrange(c->mon); + XMapWindow(dpy, c->win); + focus(NULL); +} + +void +mappingnotify(XEvent *e) +{ + XMappingEvent *ev = &e->xmapping; + + XRefreshKeyboardMapping(ev); + if (ev->request == MappingKeyboard) + grabkeys(); +} + +void +maprequest(XEvent *e) +{ + static XWindowAttributes wa; + XMapRequestEvent *ev = &e->xmaprequest; + + if (!XGetWindowAttributes(dpy, ev->window, &wa)) + return; + if (wa.override_redirect) + return; + if (!wintoclient(ev->window)) + manage(ev->window, &wa); +} + +void +monocle(Monitor *m) +{ + unsigned int n = 0; + Client *c; + + for (c = m->clients; c; c = c->next) + if (ISVISIBLE(c)) + n++; + if (n > 0) /* override layout symbol */ + snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n); + for (c = nexttiled(m->clients); c; c = nexttiled(c->next)) + resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0); +} + +void +motionnotify(XEvent *e) +{ + static Monitor *mon = NULL; + Monitor *m; + XMotionEvent *ev = &e->xmotion; + + if (ev->window != root) + return; + if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { + unfocus(selmon->sel, 1); + selmon = m; + focus(NULL); + } + mon = m; +} + +void +movemouse(const Arg *arg) +{ + int x, y, ocx, ocy, nx, ny; + Client *c; + Monitor *m; + XEvent ev; + Time lasttime = 0; + + if (!(c = selmon->sel)) + return; + if (c->isfullscreen) /* no support moving fullscreen windows by mouse */ + return; + restack(selmon); + ocx = c->x; + ocy = c->y; + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, + None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) + return; + if (!getrootptr(&x, &y)) + return; + do { + XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); + switch(ev.type) { + case ConfigureRequest: + case Expose: + case MapRequest: + handler[ev.type](&ev); + break; + case MotionNotify: + if ((ev.xmotion.time - lasttime) <= (1000 / 60)) + continue; + lasttime = ev.xmotion.time; + + nx = ocx + (ev.xmotion.x - x); + ny = ocy + (ev.xmotion.y - y); + if (nx >= selmon->wx && nx <= selmon->wx + selmon->ww + && ny >= selmon->wy && ny <= selmon->wy + selmon->wh) { + if (abs(selmon->wx - nx) < snap) + nx = selmon->wx; + else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap) + nx = selmon->wx + selmon->ww - WIDTH(c); + if (abs(selmon->wy - ny) < snap) + ny = selmon->wy; + else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap) + ny = selmon->wy + selmon->wh - HEIGHT(c); + if (!c->isfloating && selmon->lt[selmon->sellt]->arrange + && (abs(nx - c->x) > snap || abs(ny - c->y) > snap)) + togglefloating(NULL); + } + if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) + resize(c, nx, ny, c->w, c->h, 1); + break; + } + } while (ev.type != ButtonRelease); + XUngrabPointer(dpy, CurrentTime); + if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { + sendmon(c, m); + selmon = m; + focus(NULL); + } +} + +Client * +nexttiled(Client *c) +{ + for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next); + return c; +} + +void +pop(Client *c) +{ + detach(c); + attach(c); + focus(c); + arrange(c->mon); +} + +void +propertynotify(XEvent *e) +{ + Client *c; + Window trans; + XPropertyEvent *ev = &e->xproperty; + + if ((ev->window == root) && (ev->atom == XA_WM_NAME)) + updatestatus(); + else if (ev->state == PropertyDelete) + return; /* ignore */ + else if ((c = wintoclient(ev->window))) { + switch(ev->atom) { + default: break; + case XA_WM_TRANSIENT_FOR: + if (!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) && + (c->isfloating = (wintoclient(trans)) != NULL)) + arrange(c->mon); + break; + case XA_WM_NORMAL_HINTS: + updatesizehints(c); + break; + case XA_WM_HINTS: + updatewmhints(c); + drawbars(); + break; + } + if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { + updatetitle(c); + if (c == c->mon->sel) + drawbar(c->mon); + } + if (ev->atom == netatom[NetWMWindowType]) + updatewindowtype(c); + } +} + +void +quit(const Arg *arg) +{ + running = 0; +} + +Monitor * +recttomon(int x, int y, int w, int h) +{ + Monitor *m, *r = selmon; + int a, area = 0; + + for (m = mons; m; m = m->next) + if ((a = INTERSECT(x, y, w, h, m)) > area) { + area = a; + r = m; + } + return r; +} + +void +resize(Client *c, int x, int y, int w, int h, int interact) +{ + if (applysizehints(c, &x, &y, &w, &h, interact)) + resizeclient(c, x, y, w, h); +} + +void +resizeclient(Client *c, int x, int y, int w, int h) +{ + XWindowChanges wc; + unsigned int n; + unsigned int gapoffset; + unsigned int gapincr; + Client *nbc; + + wc.border_width = c->bw; + + /* Get number of clients for the selected monitor */ + for (n = 0, nbc = nexttiled(selmon->clients); nbc; nbc = nexttiled(nbc->next), n++); + + /* Do nothing if layout is floating */ + if (c->isfloating || selmon->lt[selmon->sellt]->arrange == NULL) { + gapincr = gapoffset = 0; + } else { + /* Remove border and gap if layout is monocle or only one client */ + if (selmon->lt[selmon->sellt]->arrange == monocle || n == 1) { + gapoffset = 0; + gapincr = -2 * borderpx; + wc.border_width = 0; + } else { + gapoffset = gappx; + gapincr = 2 * gappx; + } + } + + c->oldx = c->x; c->x = wc.x = x + gapoffset; + c->oldy = c->y; c->y = wc.y = y + gapoffset; + c->oldw = c->w; c->w = wc.width = w - gapincr; + c->oldh = c->h; c->h = wc.height = h - gapincr; + + XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc); + configure(c); + XSync(dpy, False); +} + +void +resizemouse(const Arg *arg) +{ + int ocx, ocy, nw, nh; + Client *c; + Monitor *m; + XEvent ev; + Time lasttime = 0; + + if (!(c = selmon->sel)) + return; + if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */ + return; + restack(selmon); + ocx = c->x; + ocy = c->y; + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, + None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess) + return; + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); + do { + XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); + switch(ev.type) { + case ConfigureRequest: + case Expose: + case MapRequest: + handler[ev.type](&ev); + break; + case MotionNotify: + if ((ev.xmotion.time - lasttime) <= (1000 / 60)) + continue; + lasttime = ev.xmotion.time; + + nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1); + nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1); + if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww + && c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh) + { + if (!c->isfloating && selmon->lt[selmon->sellt]->arrange + && (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) + togglefloating(NULL); + } + if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) + resize(c, c->x, c->y, nw, nh, 1); + break; + } + } while (ev.type != ButtonRelease); + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); + XUngrabPointer(dpy, CurrentTime); + while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); + if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { + sendmon(c, m); + selmon = m; + focus(NULL); + } +} + +void +restack(Monitor *m) +{ + Client *c; + XEvent ev; + XWindowChanges wc; + + drawbar(m); + if (!m->sel) + return; + if (m->sel->isfloating || !m->lt[m->sellt]->arrange) + XRaiseWindow(dpy, m->sel->win); + if (m->lt[m->sellt]->arrange) { + wc.stack_mode = Below; + wc.sibling = m->barwin; + for (c = m->stack; c; c = c->snext) + if (!c->isfloating && ISVISIBLE(c)) { + XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc); + wc.sibling = c->win; + } + } + XSync(dpy, False); + while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); +} + +void +run(void) +{ + XEvent ev; + /* main event loop */ + XSync(dpy, False); + while (running && !XNextEvent(dpy, &ev)) + if (handler[ev.type]) + handler[ev.type](&ev); /* call handler */ +} + +void +scan(void) +{ + unsigned int i, num; + Window d1, d2, *wins = NULL; + XWindowAttributes wa; + + if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) { + for (i = 0; i < num; i++) { + if (!XGetWindowAttributes(dpy, wins[i], &wa) + || wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1)) + continue; + if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) + manage(wins[i], &wa); + } + for (i = 0; i < num; i++) { /* now the transients */ + if (!XGetWindowAttributes(dpy, wins[i], &wa)) + continue; + if (XGetTransientForHint(dpy, wins[i], &d1) + && (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)) + manage(wins[i], &wa); + } + if (wins) + XFree(wins); + } +} + +void +sendmon(Client *c, Monitor *m) +{ + if (c->mon == m) + return; + unfocus(c, 1); + detach(c); + detachstack(c); + c->mon = m; + c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ + attach(c); + attachstack(c); + focus(NULL); + arrange(NULL); +} + +void +setclientstate(Client *c, long state) +{ + long data[] = { state, None }; + + XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, + PropModeReplace, (unsigned char *)data, 2); +} + +int +sendevent(Client *c, Atom proto) +{ + int n; + Atom *protocols; + int exists = 0; + XEvent ev; + + if (XGetWMProtocols(dpy, c->win, &protocols, &n)) { + while (!exists && n--) + exists = protocols[n] == proto; + XFree(protocols); + } + if (exists) { + ev.type = ClientMessage; + ev.xclient.window = c->win; + ev.xclient.message_type = wmatom[WMProtocols]; + ev.xclient.format = 32; + ev.xclient.data.l[0] = proto; + ev.xclient.data.l[1] = CurrentTime; + XSendEvent(dpy, c->win, False, NoEventMask, &ev); + } + return exists; +} + +void +setfocus(Client *c) +{ + if (!c->neverfocus) { + XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); + XChangeProperty(dpy, root, netatom[NetActiveWindow], + XA_WINDOW, 32, PropModeReplace, + (unsigned char *) &(c->win), 1); + } + sendevent(c, wmatom[WMTakeFocus]); +} + +void +setfullscreen(Client *c, int fullscreen) +{ + if (fullscreen && !c->isfullscreen) { + 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); + } +} + +void +setlayout(const Arg *arg) +{ + if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) + selmon->sellt ^= 1; + if (arg && arg->v) + selmon->lt[selmon->sellt] = (Layout *)arg->v; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); + if (selmon->sel) + arrange(selmon); + else + drawbar(selmon); +} + +/* arg > 1.0 will set mfact absolutly */ +void +setmfact(const Arg *arg) +{ + float f; + + 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) + return; + selmon->mfact = f; + arrange(selmon); +} + +void +setup(void) +{ + XSetWindowAttributes wa; + + /* clean up any zombies immediately */ + sigchld(0); + + /* init screen */ + screen = DefaultScreen(dpy); + sw = DisplayWidth(dpy, screen); + sh = DisplayHeight(dpy, screen); + root = RootWindow(dpy, screen); + drw = drw_create(dpy, screen, root, sw, sh); + drw_load_fonts(drw, fonts, LENGTH(fonts)); + if (!drw->fontcount) + die("no fonts could be loaded.\n"); + bh = drw->fonts[0]->h + 2; + updategeom(); + /* init atoms */ + wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); + wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); + wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); + wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); + netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); + netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); + netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); + netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); + netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); + netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); + netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); + netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False); + /* init cursors */ + cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); + cursor[CurResize] = drw_cur_create(drw, XC_sizing); + cursor[CurMove] = drw_cur_create(drw, XC_fleur); + /* init appearance */ + scheme[SchemeNorm].border = drw_clr_create(drw, normbordercolor); + scheme[SchemeNorm].bg = drw_clr_create(drw, normbgcolor); + scheme[SchemeNorm].fg = drw_clr_create(drw, normfgcolor); + scheme[SchemeSel].border = drw_clr_create(drw, selbordercolor); + scheme[SchemeSel].bg = drw_clr_create(drw, selbgcolor); + scheme[SchemeSel].fg = drw_clr_create(drw, selfgcolor); + /* init bars */ + updatebars(); + updatestatus(); + /* EWMH support per view */ + XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, + PropModeReplace, (unsigned char *) netatom, NetLast); + XDeleteProperty(dpy, root, netatom[NetClientList]); + /* select for events */ + wa.cursor = cursor[CurNormal]->cursor; + wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask|PointerMotionMask + |EnterWindowMask|LeaveWindowMask|StructureNotifyMask|PropertyChangeMask; + XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); + XSelectInput(dpy, root, wa.event_mask); + grabkeys(); + focus(NULL); +} + +void +showhide(Client *c) +{ + if (!c) + return; + 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) + resize(c, c->x, c->y, c->w, c->h, 0); + showhide(c->snext); + } else { + /* hide clients bottom up */ + showhide(c->snext); + XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y); + } +} + +void +sigchld(int unused) +{ + if (signal(SIGCHLD, sigchld) == SIG_ERR) + die("can't install SIGCHLD handler:"); + while (0 < waitpid(-1, NULL, WNOHANG)); +} + +void +spawn(const Arg *arg) +{ + if (arg->v == dmenucmd) + dmenumon[0] = '0' + selmon->num; + if (fork() == 0) { + if (dpy) + close(ConnectionNumber(dpy)); + setsid(); + execvp(((char **)arg->v)[0], (char **)arg->v); + fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]); + perror(" failed"); + exit(EXIT_SUCCESS); + } +} + +void +tag(const Arg *arg) +{ + if (selmon->sel && arg->ui & TAGMASK) { + selmon->sel->tags = arg->ui & TAGMASK; + focus(NULL); + arrange(selmon); + } +} + +void +tagmon(const Arg *arg) +{ + if (!selmon->sel || !mons->next) + return; + sendmon(selmon->sel, dirtomon(arg->i)); +} + +void +tile(Monitor *m) +{ + unsigned int i, n, h, mw, my, ty; + Client *c; + + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + if (n == 0) + return; + + if (n > m->nmaster) + mw = m->nmaster ? m->ww * m->mfact : 0; + 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); + resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); + 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); + } +} + +void +togglebar(const Arg *arg) +{ + selmon->showbar = !selmon->showbar; + updatebarpos(selmon); + XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); + arrange(selmon); +} + +void +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, + selmon->sel->w, selmon->sel->h, 0); + arrange(selmon); +} + +void +toggletag(const Arg *arg) +{ + unsigned int newtags; + + if (!selmon->sel) + return; + newtags = selmon->sel->tags ^ (arg->ui & TAGMASK); + if (newtags) { + selmon->sel->tags = newtags; + focus(NULL); + arrange(selmon); + } +} + +void +toggleview(const Arg *arg) +{ + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); + + if (newtagset) { + selmon->tagset[selmon->seltags] = newtagset; + focus(NULL); + arrange(selmon); + } +} + +void +unfocus(Client *c, int setfocus) +{ + if (!c) + return; + grabbuttons(c, 0); + XSetWindowBorder(dpy, c->win, scheme[SchemeNorm].border->pix); + if (setfocus) { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); + } +} + +void +unmanage(Client *c, int destroyed) +{ + Monitor *m = c->mon; + XWindowChanges wc; + + /* The server grab construct avoids race conditions. */ + detach(c); + detachstack(c); + if (!destroyed) { + wc.border_width = c->oldbw; + XGrabServer(dpy); + XSetErrorHandler(xerrordummy); + XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */ + XUngrabButton(dpy, AnyButton, AnyModifier, c->win); + setclientstate(c, WithdrawnState); + XSync(dpy, False); + XSetErrorHandler(xerror); + XUngrabServer(dpy); + } + free(c); + focus(NULL); + updateclientlist(); + arrange(m); +} + +void +unmapnotify(XEvent *e) +{ + Client *c; + XUnmapEvent *ev = &e->xunmap; + + if ((c = wintoclient(ev->window))) { + if (ev->send_event) + setclientstate(c, WithdrawnState); + else + unmanage(c, 0); + } +} + +void +updatebars(void) +{ + Monitor *m; + XSetWindowAttributes wa = { + .override_redirect = True, + .background_pixmap = ParentRelative, + .event_mask = ButtonPressMask|ExposureMask + }; + for (m = mons; m; m = m->next) { + if (m->barwin) + continue; + m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen), + CopyFromParent, DefaultVisual(dpy, screen), + CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); + XMapRaised(dpy, m->barwin); + } +} + +void +updatebarpos(Monitor *m) +{ + m->wy = m->my; + m->wh = m->mh; + if (m->showbar) { + m->wh -= bh; + m->by = m->topbar ? m->wy : m->wy + m->wh; + m->wy = m->topbar ? m->wy + bh : m->wy; + } else + m->by = -bh; +} + +void +updateclientlist() +{ + Client *c; + Monitor *m; + + XDeleteProperty(dpy, root, netatom[NetClientList]); + for (m = mons; m; m = m->next) + for (c = m->clients; c; c = c->next) + XChangeProperty(dpy, root, netatom[NetClientList], + XA_WINDOW, 32, PropModeAppend, + (unsigned char *) &(c->win), 1); +} + +int +updategeom(void) +{ + int dirty = 0; + +#ifdef XINERAMA + if (XineramaIsActive(dpy)) { + int i, j, n, nn; + Client *c; + Monitor *m; + XineramaScreenInfo *info = XineramaQueryScreens(dpy, &nn); + XineramaScreenInfo *unique = NULL; + + for (n = 0, m = mons; m; m = m->next, n++); + /* only consider unique geometries as separate screens */ + unique = ecalloc(nn, sizeof(XineramaScreenInfo)); + for (i = 0, j = 0; i < nn; i++) + if (isuniquegeom(unique, j, &info[i])) + memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo)); + XFree(info); + nn = j; + if (n <= nn) { + for (i = 0; i < (nn - n); i++) { /* new monitors available */ + for (m = mons; m && m->next; m = m->next); + if (m) + m->next = createmon(); + else + mons = createmon(); + } + for (i = 0, m = mons; i < nn && m; m = m->next, i++) + if (i >= n + || (unique[i].x_org != m->mx || unique[i].y_org != m->my + || unique[i].width != m->mw || unique[i].height != m->mh)) + { + dirty = 1; + m->num = i; + m->mx = m->wx = unique[i].x_org; + m->my = m->wy = unique[i].y_org; + m->mw = m->ww = unique[i].width; + m->mh = m->wh = unique[i].height; + updatebarpos(m); + } + } else { + /* less monitors available nn < n */ + for (i = nn; i < n; i++) { + for (m = mons; m && m->next; m = m->next); + while (m->clients) { + dirty = 1; + c = m->clients; + m->clients = c->next; + detachstack(c); + c->mon = mons; + attach(c); + attachstack(c); + } + if (m == selmon) + selmon = mons; + cleanupmon(m); + } + } + free(unique); + } else +#endif /* XINERAMA */ + /* default monitor setup */ + { + if (!mons) + mons = createmon(); + if (mons->mw != sw || mons->mh != sh) { + dirty = 1; + mons->mw = mons->ww = sw; + mons->mh = mons->wh = sh; + updatebarpos(mons); + } + } + if (dirty) { + selmon = mons; + selmon = wintomon(root); + } + return dirty; +} + +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; + + if (!XGetWMNormalHints(dpy, c->win, &size, &msize)) + /* size is uninitialized, ensure that size.flags aren't used */ + size.flags = PSize; + if (size.flags & PBaseSize) { + c->basew = size.base_width; + c->baseh = size.base_height; + } else if (size.flags & PMinSize) { + c->basew = size.min_width; + c->baseh = size.min_height; + } else + c->basew = c->baseh = 0; + if (size.flags & PResizeInc) { + c->incw = size.width_inc; + c->inch = size.height_inc; + } else + c->incw = c->inch = 0; + if (size.flags & PMaxSize) { + c->maxw = size.max_width; + c->maxh = size.max_height; + } else + c->maxw = c->maxh = 0; + if (size.flags & PMinSize) { + c->minw = size.min_width; + c->minh = size.min_height; + } else if (size.flags & PBaseSize) { + c->minw = size.base_width; + c->minh = size.base_height; + } else + c->minw = c->minh = 0; + if (size.flags & PAspect) { + c->mina = (float)size.min_aspect.y / size.min_aspect.x; + c->maxa = (float)size.max_aspect.x / size.max_aspect.y; + } else + c->maxa = c->mina = 0.0; + c->isfixed = (c->maxw && c->minw && c->maxh && c->minh + && c->maxw == c->minw && c->maxh == c->minh); +} + +void +updatetitle(Client *c) +{ + if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name)) + gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name); + if (c->name[0] == '\0') /* hack to mark broken clients */ + strcpy(c->name, broken); +} + +void +updatestatus(void) +{ + if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) + strcpy(stext, "dwm-"VERSION); + drawbar(selmon); +} + +void +updatewindowtype(Client *c) +{ + Atom state = getatomprop(c, netatom[NetWMState]); + Atom wtype = getatomprop(c, netatom[NetWMWindowType]); + + if (state == netatom[NetWMFullscreen]) + setfullscreen(c, 1); + if (wtype == netatom[NetWMWindowTypeDialog]) + c->isfloating = 1; +} + +void +updatewmhints(Client *c) +{ + XWMHints *wmh; + + if ((wmh = XGetWMHints(dpy, c->win))) { + if (c == selmon->sel && wmh->flags & XUrgencyHint) { + wmh->flags &= ~XUrgencyHint; + XSetWMHints(dpy, c->win, wmh); + } else + c->isurgent = (wmh->flags & XUrgencyHint) ? 1 : 0; + if (wmh->flags & InputHint) + c->neverfocus = !wmh->input; + else + c->neverfocus = 0; + XFree(wmh); + } +} + +void +view(const Arg *arg) +{ + if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + return; + selmon->seltags ^= 1; /* toggle sel tagset */ + if (arg->ui & TAGMASK) + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; + focus(NULL); + arrange(selmon); +} + +Client * +wintoclient(Window w) +{ + Client *c; + Monitor *m; + + for (m = mons; m; m = m->next) + for (c = m->clients; c; c = c->next) + if (c->win == w) + return c; + return NULL; +} + +Monitor * +wintomon(Window w) +{ + int x, y; + Client *c; + Monitor *m; + + if (w == root && getrootptr(&x, &y)) + return recttomon(x, y, 1, 1); + for (m = mons; m; m = m->next) + if (w == m->barwin) + return m; + if ((c = wintoclient(w))) + return c->mon; + return selmon; +} + +/* There's no way to check accesses to destroyed windows, thus those cases are + * ignored (especially on UnmapNotify's). Other types of errors call Xlibs + * default error handler, which may call exit. */ +int +xerror(Display *dpy, XErrorEvent *ee) +{ + if (ee->error_code == BadWindow + || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch) + || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable) + || (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable) + || (ee->request_code == X_PolySegment && ee->error_code == BadDrawable) + || (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch) + || (ee->request_code == X_GrabButton && ee->error_code == BadAccess) + || (ee->request_code == X_GrabKey && ee->error_code == BadAccess) + || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable)) + return 0; + fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n", + ee->request_code, ee->error_code); + return xerrorxlib(dpy, ee); /* may call exit */ +} + +int +xerrordummy(Display *dpy, XErrorEvent *ee) +{ + return 0; +} + +/* Startup Error handler to check if another window manager + * is already running. */ +int +xerrorstart(Display *dpy, XErrorEvent *ee) +{ + die("dwm: another window manager is already running\n"); + return -1; +} + +void +zoom(const Arg *arg) +{ + Client *c = selmon->sel; + + 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); +} + +int +main(int argc, char *argv[]) +{ + if (argc == 2 && !strcmp("-v", argv[1])) + die("dwm-"VERSION "\n"); + else if (argc != 1) + die("usage: dwm [-v]\n"); + if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) + fputs("warning: no locale support\n", stderr); + if (!(dpy = XOpenDisplay(NULL))) + die("dwm: cannot open display\n"); + checkotherwm(); + setup(); + scan(); + run(); + cleanup(); + XCloseDisplay(dpy); + return EXIT_SUCCESS; +} diff --git a/dwm.o b/dwm.o index d0b847bc9c084fa19c7168f41f4a2d0c64e74e25..e467f5d7667fd746b55233bc037162829f33cc7f 100644 GIT binary patch delta 18260 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

Gtu8k7+Q_1Ewj?+9y6U8*j3QKV< z_%X>2dD+XPHSLTdAII_QHV(_S2kZACYrE<4?_;yb(RuudT1w%#h$NR=m?_E2{Ux&& z{FS~n_9;TKbjr7J_~M;lXR#!+UW(zEgp=-V+m!YRTzJQH{9WQ6mb88+t}8g!7N)$) zC2ov_lg(qcnATUqw@LCD5>E2@Tz;8?3p=}Pyk;DTHOT=(~)v3t}p_{IjO6T8hFDUy;pK zaEy24yO9PSmb@E@TV@L1#nmpqr&lSm0uQ2Ukb)84^+nf$rzp7iK5*{;#wTdG3PV(O zfr5+LDOYguU0;=gZ-cGxMd{n%0;Br-bnblLbct5U<;z>jn^cAU0tFWzkCiL9_~@&u z7CeZ0KbC6y_S3UVi~ipXEk(s6Z3A-^Ty%$A1s8!9D7feiqN1Mw}lkQX&NSC&WrnsAUSGY}UJ3KU#8C|7Xdpi04o{h)e(Oo04r(F#L2 zNKtU%V6K7-2e}Gfoq&Q1`{niccd}{~RVfO>K~ViaX223qaN!_D!K)Lf#xZ~D?ZQEB zHN(cMGf;5hpj^R)gDM3V_Je$t1YEq+MJo*9AVtB2gSiSW9ONo^bpi@5>_gn{h#qzL zTp|7@L(S2YYK7yz4Qiq$+%(|z-H}EM1J2-~jRC*np{)U33L^E6Fuov4?*i_ED93oN z&u?JWpIn`W3k6MJQlWovsBO5Ka~AYMQ~w+sg;CA^!FlogNX9;g$%QdERj)2=0*4Cy z8%>dTUqCVHUWU&LV~jdF`0Yv1i(vSkp}1{f-JU3Y0~|+M1ozl^hoT+$f!(>Hp>TVz zKZNa#Fk0&{Z0{7~y-;{>ZzO))xAo;F`c?RGZ;U<|!awYa=fgjY(Z@m-JKu%pQ{e_X zZ?rE)e-7gJk<4>=z8JRd>k4lk@Q2I$BJ{t4{*isv_oE2hNRiI3HsaNLaD-ny#H%t0 z-)~E%?T^sEfGmEsAFuAh4Sv=9zyRFZFy_Eeq?;N2{=iiID;WGS(d~@ZJxJ#>7(LEt zheI(fl4v!9g}&>hLKRBCZlN&$(0qM2e1B-FUJ8SYr{Xsi+l#5GxK2+aX#P^bM5>Df&AD5r4;DaFbnCTeGxjPkZ5@aFw3C`WGaEC)7a%oop zl~eYiI*U}ef!tA?ds*R*f#Bn&YaHjQ%cvL%8OtkAZl@rgTa z_oO21@SO@SEl**H4H>5tTzo@cuHfRM`|AomiLb@gwVn8={~?nfRTB~4r=o@N8X-QN zito}b1s5O6rzrSmMGH@i(_JDj;?hs-4?4u-6u8(2^qGQ-eLzf^+aR58{BGHvF0cqY zqT40fxcxXr=b{(qDheTdf+$e%;T#uhN@CN`q?bQf@{|ch>?=C-2#&W}v9ajdBMe+@ z2HJ+$vlgBT2V!GUdu0L<8;jBuTr}7s1!rBCmO48XhS+H&)_lUT*lE;LnUKUzqtOa} zi{IjAE4bKuv>b8rU!9rQe6&+hsP5|uem{h?ahIopr|^fs2;K)o0^$kIs=@8{7Y`tl zY8Wgi@gO7CcEXU@ptM|(7talO3eGnuX`d$5oM07(*q{`|mrTO3c#w%!@Xh@3 zHd(qaqxLJxsp7kK$qvQ<#F!3bp0p6kKd-TBP7&Q`1h4yM$x0 z_9|5r#2W6hf{R^EVtFR)@Lf$>7+;RC@tB{Z;Nt0ar-F-j7ZLuHVU2yU*=3T1k09q_tJ89cLAbc36exH(fAQ+yh|JeG zn1uhe<5T<>8hQPo-}&Btrxw|4-$;1*d~f4=KiG4Api%xF+{MGXn+!CgFrjes5(1{w=az57UI>z Ma{For1Sf?4KbKDj-2eap delta 17430 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�=x)Mm`+iT!AwG5Wa41zn`2Qjy`3)U= zFDRB9Fb0<@ysI6MCrch$@ftrO^Bt~nURY!)e2Wr)s?Dp<4PHR5QXHsaoWWX!Z&U(p zQ#jdg!i~};jdPrz6@J1{`k{WJ?MNe!0!7+CjYeR;V|8>&Ew#r<+_;^h6;56ty&g=2 z@869xaXo?mC#|RdhP+RP+B$t?;H&u}5q}Ri4n5AQ=4#h`pge+7*L=@5ueMiLX{Gj^ zbPI8Imnj*9*!Bj^CX{(?xcHuB)`q{{ix1;>l5#a0e3Pr!`*GgX2W(Dvl9V_EzhQR5 z##NkO$+@a=e&r{G0$}1e{4Q1pjmuYu+8Q2B!7p{?Y8=ZOwkghmyZ)Qvy!>L^3C)V% zFuGa;525B!ipMYBb*O=RG%jD@^BTGTTVX8MI5+=RjdOdQ&^W(%cU9y3M&V7t;mOS{ zuz%NXjz{_N=J=`?4s-9hyMEk_%Qeo~Z`C-z(RD)O{D#)m|INKd2%R&SsNJcE@|`-P zLk--caV}7<#(DfK*Ekn+tKi=1jCuT=&>T2}s~YDFLTXX*tK)D69W>7IJu1ii4bFhy zcj1=c43?`7XwMmJ)i`HxLgO6&s>Ufkpz*2-+-v7w z)%Tpi3C)2sxTapqDtcNjg7%5J3~Q<)%Y#j*^qyji7xm8 zHkUMWz9TjA_DI~UQohA-5xoyX==O%NsU!$GY>#bRCT&N^J$2-1n6ll1ob5sNCn@wR zcx`)v(Rh6`5ZbQN_SbXd{>Cs2%?^82ClG#FT{%|aQy;pxf$tgk}7qa~UBF_tXE% z7TKF1CuwR)+WOuP-44z$x4`CuW6gt5|Ik?TTbOd_p)Q}Jk{2nR0p2U^h3JYv%?}II?QjNm(CWhpQHNz;?v*nb zXEnIJttf@id~0RdgXVeYUX~Desg;eR!7RrPD{G01upMQy@k^NYN8+K~ksz3Oq@~!e zk^7J2{-)f=9<}x9xF3!7OOCe0qHI1IZ*GNek5XH7FON5WfGOq8oOP)*nB<96HJRaO z66KaNSZX7MjXlTGfW8k-qLyEHOwqJWz&wVpf=S=?nil^`MlHSSPf1;XQREoNLTwwV zJwzs$_(W|BD^S~BYSl#=`Qm%VsC7y01#-m1z6o&cnB`s5(59JkDxe)X@EhRz`ioyB zpQG9HtLOBMASI5&Uly#_xcq(sp8F`&%dfNRt2loB{etEjAlK;n>W<&9zp2^FFG-9@ z*%Dkf`I`6xhFeqci~SyrCzYgrJi_#@k?~1OTbVr3_?Cw`uadZ4%(LaWbX$wVpXqQp z*}iIA5umF)E4s>2y3AHo@u%esuu0?FB)_cjd32A2X`MD>@TWh!@8Wos8e+{zPiC2!H!COyk^Rb2KhSE3I;hGzEVQbXnv4F;E9>uHlb?JR0{jwkt3} zPCz>ov|F9-Y%TPrPEmrnH&Qp_ r=^l>!a@c#iN8r^_c3k`-=HFcdJ=5)9Hz5^&b)cuInBIoLeIou3nnJB0 diff --git a/patches/dwm-pertag-6.1.diff b/patches/dwm-pertag-6.1.diff new file mode 100644 index 0000000..34fbc01 --- /dev/null +++ b/patches/dwm-pertag-6.1.diff @@ -0,0 +1,199 @@ +diff --git a/dwm.c b/dwm.c +index 0362114..9ba4ec5 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -111,6 +111,7 @@ typedef struct { + void (*arrange)(Monitor *); + } Layout; + ++typedef struct Pertag Pertag; + struct Monitor { + char ltsymbol[16]; + float mfact; +@@ -130,6 +131,7 @@ struct Monitor { + Monitor *next; + Window barwin; + const Layout *lt[2]; ++ Pertag *pertag; + }; + + typedef struct { +@@ -270,6 +272,16 @@ static Window root; + /* 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 */ ++ Bool showbars[LENGTH(tags) + 1]; /* display bar for the current tag */ ++ Client *prevzooms[LENGTH(tags) + 1]; /* store zoom information */ ++}; ++ + /* compile-time check if all tags fit into an unsigned int bit array. */ + struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +@@ -526,6 +538,7 @@ clientmessage(XEvent *e) + { + XClientMessageEvent *cme = &e->xclient; + Client *c = wintoclient(cme->window); ++ int i; + + if (!c) + return; +@@ -537,6 +550,8 @@ clientmessage(XEvent *e) + if (!ISVISIBLE(c)) { + c->mon->seltags ^= 1; + c->mon->tagset[c->mon->seltags] = c->tags; ++ for(i=0; !(c->tags & 1 << i); i++); ++ view(&(Arg){.ui = 1 << i}); + } + pop(c); + } +@@ -640,6 +655,7 @@ Monitor * + createmon(void) + { + Monitor *m; ++ int i; + + m = ecalloc(1, sizeof(Monitor)); + m->tagset[0] = m->tagset[1] = 1; +@@ -650,6 +666,27 @@ createmon(void) + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); ++ if (!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag)))) ++ die("fatal: could not malloc() %u bytes\n", sizeof(Pertag)); ++ m->pertag->curtag = m->pertag->prevtag = 1; ++ for(i=0; i <= LENGTH(tags); i++) { ++ /* init nmaster */ ++ m->pertag->nmasters[i] = m->nmaster; ++ ++ /* init mfacts */ ++ m->pertag->mfacts[i] = m->mfact; ++ ++ /* init layouts */ ++ m->pertag->ltidxs[i][0] = m->lt[0]; ++ m->pertag->ltidxs[i][1] = m->lt[1]; ++ m->pertag->sellts[i] = m->sellt; ++ ++ /* init showbar */ ++ m->pertag->showbars[i] = m->showbar; ++ ++ /* swap focus and zoomswap*/ ++ m->pertag->prevzooms[i] = NULL; ++ } + return m; + } + +@@ -981,7 +1018,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); + } + +@@ -1517,10 +1554,13 @@ setfullscreen(Client *c, int fullscreen) + void + setlayout(const Arg *arg) + { +- if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) +- selmon->sellt ^= 1; ++ if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) { ++ selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ } + if (arg && arg->v) +- selmon->lt[selmon->sellt] = (Layout *)arg->v; ++ selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); + if (selmon->sel) + arrange(selmon); +@@ -1539,7 +1579,7 @@ setmfact(const Arg *arg) + f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; + if (f < 0.1 || f > 0.9) + return; +- selmon->mfact = f; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; + arrange(selmon); + } + +@@ -1692,7 +1732,7 @@ tile(Monitor *m) + 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); +@@ -1731,9 +1771,29 @@ void + toggleview(const Arg *arg) + { + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); ++ int i; + + if (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; ++ } + selmon->tagset[selmon->seltags] = newtagset; ++ ++ /* 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); + } +@@ -2031,11 +2091,33 @@ 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->pertag->prevtag = selmon->pertag->curtag; + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; ++ 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); + }