diff options
author | zachir <zachir@librem.one> | 2021-02-06 00:06:23 -0600 |
---|---|---|
committer | zachir <zachir@librem.one> | 2021-02-06 00:06:23 -0600 |
commit | 23e3b11d1cdd7926173040050429ce624bace728 (patch) | |
tree | 0f6642803a52340caac14f5ee6560727e5762390 | |
parent | 1ca0264677027f2ddcceacd58397e049304dc40e (diff) |
Update to follow upstream
-rw-r--r-- | config.h | 7 | ||||
-rw-r--r-- | drw.c | 1 | ||||
-rw-r--r-- | dwm.1 | 2 | ||||
-rw-r--r-- | dwm.c | 68 | ||||
-rw-r--r-- | dwm.c.orig | 2152 | ||||
-rw-r--r-- | dwm.c.rej | 124 | ||||
-rw-r--r-- | patch.diff | 5087 |
7 files changed, 4793 insertions, 2648 deletions
@@ -131,16 +131,13 @@ static Key keys[] = { { MODKEY, XK_k, focusstack, {.i = -1 } }, { MODKEY|ShiftMask, XK_j, pushdown, {.i = +1 } }, { MODKEY|ShiftMask, XK_k, pushup, {.i = -1 } }, - { MODKEY|ControlMask, XK_j, setcfact, {.f = +0.25} }, - { MODKEY|ControlMask, XK_k, setcfact, {.f = -0.25} }, + { MODKEY|ControlMask, XK_k, setcfact, {.f = +0.25} }, + { MODKEY|ControlMask, XK_j, setcfact, {.f = -0.25} }, { MODKEY|ControlMask, XK_o, setcfact, {.f = 0.00} }, { MODKEY|ShiftMask, XK_h, incnmaster, {.i = +1 } }, { MODKEY|ShiftMask, XK_l, incnmaster, {.i = -1 } }, { MODKEY, XK_h, setmfact, {.f = -0.05} }, { MODKEY, XK_l, setmfact, {.f = +0.05} }, - { MODKEY|ControlMask, XK_h, setcfact, {.f = +0.25} }, - { MODKEY|ControlMask, XK_l, setcfact, {.f = -0.25} }, - { MODKEY|ShiftMask, XK_o, setcfact, {.f = 0.00} }, { MODKEY|ShiftMask, XK_Return, zoom, {0} }, { MODKEY, XK_Tab, view, {0} }, { MODKEY|ShiftMask, XK_q, killclient, {0} }, @@ -95,6 +95,7 @@ drw_free(Drw *drw) { XFreePixmap(drw->dpy, drw->drawable); XFreeGC(drw->dpy, drw->gc); + drw_fontset_free(drw->fonts); free(drw); } @@ -37,7 +37,7 @@ dwm draws a small border around windows to indicate the focus state. .SH OPTIONS .TP .B \-v -prints version information to standard output, then exits. +prints version information to stderr, then exits. .SH USAGE .SS Status bar .TP @@ -594,24 +594,24 @@ buttonpress(XEvent *e) arg.ui = 1 << i; } else if (ev->x < x + blw) click = ClkLtSymbol; - else if (ev->x > (x = selmon->ww - TEXTW(stext) + lrpad - getsystraywidth())) { + else if (ev->x > (x = selmon->ww - (int)TEXTW(stext) + lrpad - getsystraywidth())) { click = ClkStatusText; char *text = rawstext; int i = -1; char ch; dwmblockssig = 0; - while (text[++i]) { - if ((unsigned char)text[i] < ' ') { - ch = text[i]; - text[i] = '\0'; - x += TEXTW(text) - lrpad; - text[i] = ch; - text += i+1; - i = -1; - if (x >= ev->x) break; - dwmblockssig = ch; - } - } + while (text[++i]) { + if ((unsigned char)text[i] < ' ') { + ch = text[i]; + text[i] = '\0'; + x += TEXTW(text) - lrpad; + text[i] = ch; + text += i+1; + i = -1; + if (x >= ev->x) break; + dwmblockssig = ch; + } + } } else click = ClkWinTitle; } else if ((c = wintoclient(ev->window))) { @@ -941,24 +941,25 @@ dirtomon(int dir) void drawbar(Monitor *m) { - int indn; - int x, w, sw = 0, stw = 0; + int indn; + int x, w, tw = 0, stw = 0; int boxs = drw->fonts->h / 9; int boxw = drw->fonts->h / 6 + 2; unsigned int i, occ = 0, urg = 0; Client *c; if(showsystray && m == systraytomon(m)) - stw = getsystraywidth(); + stw = getsystraywidth(); /* 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 + 2; /* 2px right padding */ - drw_text(drw, m->ww - sw - stw, 0, sw, bh, lrpad / 2 - 2, stext, 0); - } + tw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */ + drw_text(drw, m->ww - tw - stw, 0, tw, bh, lrpad / 2 - 2, stext, 0); + } resizebarwin(m); + for (c = m->clients; c; c = c->next) { occ |= c->tags; if (c->isurgent) @@ -966,17 +967,16 @@ drawbar(Monitor *m) } x = 0; for (i = 0; i < LENGTH(tags); i++) { - indn = 0; + indn = 0; w = TEXTW(tags[i]); drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); - - for (c = m->clients; c; c = c->next) { - if (c->tags & (1 << i)) { - drw_rect(drw, x, 1 + (indn * 2), selmon->sel == c ? 6 : 1, 1, 1, urg & 1 << i); - indn++; - } - } + for (c = m->clients; c; c = c->next) { + if (c->tags & (1 << i)) { + drw_rect(drw, x, 1 + (indn * 2), selmon->sel == c ? 6 : 1, 1, 1, urg & 1 << i); + indn++; + } + } x += w; } @@ -984,7 +984,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 - stw - x) > bh) { + if ((w = m->ww - tw - stw - 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); @@ -2248,13 +2248,17 @@ tile(Monitor *m) if (i < m->nmaster) { h = (m->wh - my) * (c->cfact / mfacts); resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); - my += HEIGHT(c); - mfacts -= c->cfact; + if (my + HEIGHT(c) < m->wh) { + my += HEIGHT(c); + mfacts -= c->cfact; + } } else { h = (m->wh - ty) * (c->cfact / sfacts); resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0); - ty += HEIGHT(c); - sfacts -= c->cfact; + if (ty + HEIGHT(c) < m->wh) { + ty += HEIGHT(c); + sfacts -= c->cfact; + } } } diff --git a/dwm.c.orig b/dwm.c.orig new file mode 100644 index 0000000..664c527 --- /dev/null +++ b/dwm.c.orig @@ -0,0 +1,2152 @@ +/* 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 <errno.h> +#include <locale.h> +#include <signal.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <X11/cursorfont.h> +#include <X11/keysym.h> +#include <X11/Xatom.h> +#include <X11/Xlib.h> +#include <X11/Xproto.h> +#include <X11/Xutil.h> +#ifdef XINERAMA +#include <X11/extensions/Xinerama.h> +#endif /* XINERAMA */ +#include <X11/Xft/Xft.h> + +#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) +#define HEIGHT(X) ((X)->h + 2 * (X)->bw) +#define TAGMASK ((1 << LENGTH(tags)) - 1) +#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) + +/* enums */ +enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ +enum { SchemeNorm, SchemeSel }; /* color schemes */ +enum { NetSupported, NetWMName, NetWMState, NetWMCheck, + 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 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 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); +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 seturgent(Client *c, int urg); +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 void updatebarpos(Monitor *m); +static void updatebars(void); +static void updateclientlist(void); +static int updategeom(void); +static void updatenumlockmask(void); +static void updatesizehints(Client *c); +static void updatestatus(void); +static void updatetitle(Client *c); +static void updatewindowtype(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 lrpad; /* sum of left and right padding for text */ +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 Clr **scheme; +static Display *dpy; +static Drw *drw; +static Monitor *mons, *selmon; +static Window root, wmcheckwin; + +/* 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; + do + 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 - (int)TEXTW(stext)) + click = ClkStatusText; + else + click = ClkWinTitle; + } else if ((c = wintoclient(ev->window))) { + focus(c); + restack(selmon); + XAllowEvents(dpy, ReplayPointer, CurrentTime); + 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 < LENGTH(colors); i++) + free(scheme[i]); + XDestroyWindow(dpy, wmcheckwin); + 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 +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 (c != selmon->sel && !c->isurgent) + seturgent(c, 1); + } +} + +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; + Client *c; + 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) { + 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); + 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, w, tw = 0; + int boxs = drw->fonts->h / 9; + int boxw = drw->fonts->h / 6 + 2; + unsigned int i, occ = 0, urg = 0; + Client *c; + + /* 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]); + 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) { + occ |= c->tags; + if (c->isurgent) + urg |= c->tags; + } + x = 0; + for (i = 0; i < LENGTH(tags); i++) { + w = TEXTW(tags[i]); + drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); + if (occ & 1 << i) + drw_rect(drw, x + boxs, boxs, boxw, boxw, + m == selmon && selmon->sel && selmon->sel->tags & 1 << i, + urg & 1 << i); + x += w; + } + w = blw = TEXTW(m->ltsymbol); + drw_setscheme(drw, scheme[SchemeNorm]); + x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); + + 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); + if (m->sel->isfloating) + drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0); + } else { + drw_setscheme(drw, scheme[SchemeNorm]); + drw_rect(drw, x, 0, w, bh, 1, 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); + if (selmon->sel && selmon->sel != c) + unfocus(selmon->sel, 0); + if (c) { + if (c->mon != selmon) + selmon = c->mon; + if (c->isurgent) + seturgent(c, 0); + detachstack(c); + attachstack(c); + grabbuttons(c, 1); + XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel); + setfocus(c); + } else { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); + } + selmon->sel = c; + drawbars(); +} + +/* there are some broken focus acquiring clients needing extra handling */ +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); + 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'; + if (!XGetTextProperty(dpy, w, &name, atom) || !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) + XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, + BUTTONMASK, GrabModeSync, GrabModeSync, None, None); + 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); + } +} + +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; + /* 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; + + updatetitle(c); + if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { + c->mon = t->mon; + c->tags = t->tags; + } else { + c->mon = selmon; + applyrules(c); + } + + 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][ColBorder].pixel); + 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 (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; + + c->oldx = c->x; c->x = wc.x = x; + c->oldy = c->y; c->y = wc.y = y; + c->oldw = c->w; c->w = wc.width = w; + c->oldh = c->h; c->h = wc.height = h; + wc.border_width = c->bw; + 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 absolutely */ +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.05 || f > 0.95) + return; + selmon->mfact = f; + arrange(selmon); +} + +void +setup(void) +{ + int i; + XSetWindowAttributes wa; + Atom utf8string; + + /* 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); + if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) + die("no fonts could be loaded."); + lrpad = drw->fonts->h; + bh = drw->fonts->h + 2; + updategeom(); + /* init atoms */ + utf8string = XInternAtom(dpy, "UTF8_STRING", False); + 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[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", 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 = ecalloc(LENGTH(colors), sizeof(Clr *)); + for (i = 0; i < LENGTH(colors); i++) + scheme[i] = drw_scm_create(drw, colors[i], 3); + /* init bars */ + updatebars(); + updatestatus(); + /* supporting window for NetWMCheck */ + wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0); + XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW, 32, + PropModeReplace, (unsigned char *) &wmcheckwin, 1); + XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8, + PropModeReplace, (unsigned char *) "dwm", 3); + XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32, + PropModeReplace, (unsigned char *) &wmcheckwin, 1); + /* EWMH support per view */ + XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, + PropModeReplace, (unsigned char *) netatom, NetLast); + XDeleteProperty(dpy, root, netatom[NetClientList]); + /* select 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 +seturgent(Client *c, int urg) +{ + XWMHints *wmh; + + c->isurgent = urg; + if (!(wmh = XGetWMHints(dpy, c->win))) + return; + wmh->flags = urg ? (wmh->flags | XUrgencyHint) : (wmh->flags & ~XUrgencyHint); + XSetWMHints(dpy, c->win, wmh); + XFree(wmh); +} + +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); + 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); + if (ty + HEIGHT(c) < m->wh) + 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][ColBorder].pixel); + if (setfocus) { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); + } +} + +void +unmanage(Client *c, int destroyed) +{ + Monitor *m = c->mon; + XWindowChanges wc; + + detach(c); + detachstack(c); + if (!destroyed) { + wc.border_width = c->oldbw; + XGrabServer(dpy); /* avoid race conditions */ + 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 + }; + XClassHint ch = {"dwm", "dwm"}; + 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); + XSetClassHint(dpy, m->barwin, &ch); + } +} + +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) { /* new monitors available */ + for (i = 0; i < (nn - n); i++) { + 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 ((c = m->clients)) { + dirty = 1; + 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->maxh && c->maxw == c->minw && c->maxh == c->minh); +} + +void +updatestatus(void) +{ + if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) + strcpy(stext, "dwm-"VERSION); + drawbar(selmon); +} + +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 +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"); + 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); + else if (argc != 1) + die("usage: dwm [-v]"); + if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) + fputs("warning: no locale support\n", stderr); + if (!(dpy = XOpenDisplay(NULL))) + die("dwm: cannot open display"); + checkotherwm(); + setup(); +#ifdef __OpenBSD__ + if (pledge("stdio rpath proc exec", NULL) == -1) + die("pledge"); +#endif /* __OpenBSD__ */ + scan(); + run(); + cleanup(); + XCloseDisplay(dpy); + return EXIT_SUCCESS; +} diff --git a/dwm.c.rej b/dwm.c.rej new file mode 100644 index 0000000..079df04 --- /dev/null +++ b/dwm.c.rej @@ -0,0 +1,124 @@ +--- dwm.c ++++ dwm.c +@@ -205,12 +245,16 @@ 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 int getdwmblockspid(); ++static Atom getatomprop(Client *c, Atom prop); + static int getrootptr(int *x, int *y); + static long getstate(Window w); ++static unsigned int getsystraywidth(); + static int gettextprop(Window w, Atom atom, char *text, unsigned int size); + static void grabbuttons(Client *c, int focused); + static void grabkeys(void); +@@ -590,9 +745,25 @@ 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 > (x = selmon->ww - TEXTW(stext) + lrpad - getsystraywidth())) { + click = ClkStatusText; +- else ++ char *text = rawstext; ++ int i = -1; ++ char ch; ++ dwmblockssig = 0; ++ while (text[++i]) { ++ if ((unsigned char)text[i] < ' ') { ++ ch = text[i]; ++ text[i] = '\0'; ++ x += TEXTW(text) - lrpad; ++ text[i] = ch; ++ text += i+1; ++ i = -1; ++ if (x >= ev->x) break; ++ dwmblockssig = ch; ++ } ++ } ++ } else + click = ClkWinTitle; + } else if ((c = wintoclient(ev->window))) { + focus(c); +@@ -921,19 +1167,24 @@ dirtomon(int dir) + void + drawbar(Monitor *m) + { +- int x, w, sw = 0; ++ int indn; ++ int x, w, sw = 0, stw = 0; + int boxs = drw->fonts->h / 9; + int boxw = drw->fonts->h / 6 + 2; + unsigned int i, occ = 0, urg = 0; + Client *c; + ++ if(showsystray && m == systraytomon(m)) ++ stw = getsystraywidth(); ++ + /* 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); ++ sw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */ ++ drw_text(drw, m->ww - sw - stw, 0, sw, bh, lrpad / 2 - 2, stext, 0); + } + ++ resizebarwin(m); + for (c = m->clients; c; c = c->next) { + occ |= c->tags; + if (c->isurgent) +@@ -941,20 +1192,25 @@ drawbar(Monitor *m) + } + x = 0; + for (i = 0; i < LENGTH(tags); i++) { ++ indn = 0; + w = TEXTW(tags[i]); + drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); +- if (occ & 1 << i) +- drw_rect(drw, x + boxs, boxs, boxw, boxw, +- m == selmon && selmon->sel && selmon->sel->tags & 1 << i, +- urg & 1 << i); ++ ++ for (c = m->clients; c; c = c->next) { ++ if (c->tags & (1 << i)) { ++ drw_rect(drw, x, 1 + (indn * 2), selmon->sel == c ? 6 : 1, 1, 1, urg & 1 << i); ++ indn++; ++ } ++ } ++ + x += w; + } + w = blw = TEXTW(m->ltsymbol); + 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 - sw - stw - 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); +@@ -2216,13 +2776,15 @@ tile(Monitor *m) + 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); ++ h = (m->wh - my) * (c->cfact / mfacts); + resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); + my += HEIGHT(c); ++ mfacts -= c->cfact; + } else { +- h = (m->wh - ty) / (n - i); ++ h = (m->wh - ty) * (c->cfact / sfacts); + resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0); + ty += HEIGHT(c); ++ sfacts -= c->cfact; + } + } + @@ -1,17 +1,20 @@ diff --git a/Makefile b/Makefile -index 77bcbc0..1e95356 100644 +index 77bcbc0..c6bc24b 100644 --- a/Makefile +++ b/Makefile -@@ -38,7 +38,7 @@ dist: clean +@@ -37,8 +37,9 @@ dist: clean + rm -rf dwm-${VERSION} install: all - mkdir -p ${DESTDIR}${PREFIX}/bin +- mkdir -p ${DESTDIR}${PREFIX}/bin - cp -f dwm ${DESTDIR}${PREFIX}/bin ++ mkdir -p ${DESTDIR}${PREFIX}/bin ${DESTDIR}${XSESSIONPREFIX} + cp -f dwm dwmc volsv ${DESTDIR}${PREFIX}/bin ++ cp -f dwm.desktop ${DESTDIR}${XSESSIONPREFIX} chmod 755 ${DESTDIR}${PREFIX}/bin/dwm mkdir -p ${DESTDIR}${MANPREFIX}/man1 sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1 -@@ -46,6 +46,8 @@ install: all +@@ -46,6 +47,8 @@ install: all uninstall: rm -f ${DESTDIR}${PREFIX}/bin/dwm\ @@ -173,10 +176,10 @@ index 1c0b587..8bfef3e 100644 +}; diff --git a/config.h b/config.h new file mode 100644 -index 0000000..b355e1f +index 0000000..607e67f --- /dev/null +++ b/config.h -@@ -0,0 +1,264 @@ +@@ -0,0 +1,260 @@ +/* See LICENSE file for copyright and license details. */ + +#include <X11/XF86keysym.h> @@ -192,8 +195,8 @@ index 0000000..b355e1f +static const int showsystray = 1; /* 0 means no systray */ +static const int showbar = 1; /* 0 means no bar */ +static const int topbar = 1; /* 0 means bottom bar */ -+static const char *fonts[] = { "mononoki:size=9", "JoyPixels:size=9" }; -+static const char dmenufont[] = "mononoki:size=9"; ++static const char *fonts[] = { "mononoki Nerd Font:size=9", "JoyPixels:size=9" }; ++static const char dmenufont[] = "mononoki Nerd Font:size=9"; +static const char col_gray1[] = "#222222"; +static const char col_gray2[] = "#444444"; +static const char col_gray3[] = "#bbbbbb"; @@ -268,59 +271,55 @@ index 0000000..b355e1f +static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ +static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; +static const char *passmenu[] = { "passmenu", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; -+static const char *termcmd[] = { "tabbed", "-c", "alacritty", "--embed", NULL }; -+//static const char *termcmd[] = { "dmenuabduco", NULL }; -+//static const char *mpdtoggle[] = { "playerctl", "--player=mpd,mpv,%any", "play-pause", NULL }; -+//static const char *mpdnext[] = { "playerctl", "--player=mpd,mpv,%any", "next", NULL }; -+//static const char *mpdprev[] = { "playerctl", "--player=mpd,mpv,%any", "previous", NULL }; -+//static const char *plytoggle[] = { "playerctl", "--player=%any,mpd", "play-pause", NULL }; -+//static const char *plyfwd[] = { "playerctl", "--player=%any,mpd", "position 5+", NULL }; -+//static const char *plybck[] = { "playerctl", "--player=%any,mpd", "position 5-", NULL }; -+//static const char *blightup[] = { "light", "-A", "1", NULL }; -+//static const char *blightdown[] = { "light", "-U", "1", NULL }; -+//static const char *audioup[] = { "volsv", "-i", NULL }; -+//static const char *audiodown[] = { "volsv", "-d", NULL }; -+//static const char *audiomute[] = { "volsv", "-t", NULL }; -+//static const char *micmute[] = { "pamixer", "--source", "1", "-t", NULL }; -+//static const char *lockscr[] = { "xscreensaver-command", "-lock", NULL }; -+//static const char *xidletog[] = { "xidletog", NULL }; -+//static const char *xkillcmd[] = { "xkill", NULL }; ++static const char *termcmd[] = { "tabbed", "-c", "st", "-w", NULL }; ++static const char *mpdtoggle[] = { "playerctl", "--player=mpd,mpv,%any", "play-pause", NULL }; ++static const char *mpdnext[] = { "playerctl", "--player=mpd,mpv,%any", "next", NULL }; ++static const char *mpdprev[] = { "playerctl", "--player=mpd,mpv,%any", "previous", NULL }; ++static const char *plytoggle[] = { "playerctl", "--player=%any,mpd", "play-pause", NULL }; ++static const char *plyfwd[] = { "playerctl", "--player=%any,mpd", "position 5+", NULL }; ++static const char *plybck[] = { "playerctl", "--player=%any,mpd", "position 5-", NULL }; ++static const char *blightup[] = { "light", "-A", "1", NULL }; ++static const char *blightdown[] = { "light", "-U", "1", NULL }; ++static const char *audioup[] = { "volsv", "-i", NULL }; ++static const char *audiodown[] = { "volsv", "-d", NULL }; ++static const char *audiomute[] = { "volsv", "-t", NULL }; ++static const char *micmute[] = { "pamixer", "--source", "1", "-t", NULL }; ++static const char *lockscr[] = { "xscreensaver-command", "-lock", NULL }; ++static const char *xidletog[] = { "xidletog", NULL }; ++static const char *xkillcmd[] = { "xkill", NULL }; + +static Key keys[] = { + /* modifier key function argument */ -+// { MODKEY, XK_d, spawn, {.v = dmenucmd } }, ++ { MODKEY, XK_d, spawn, {.v = dmenucmd } }, + { MODKEY, XK_p, spawn, {.v = passmenu } }, -+// { MODKEY, XK_c, spawn, {.v = xidletog } }, -+// { MODKEY, XK_x, spawn, {.v = xkillcmd } }, ++ { MODKEY, XK_c, spawn, {.v = xidletog } }, ++ { MODKEY, XK_x, spawn, {.v = xkillcmd } }, + { MODKEY, XK_Return, spawn, {.v = termcmd } }, -+// { 0, XF86XK_AudioPlay, spawn, {.v = mpdtoggle } }, -+// { 0, XF86XK_AudioNext, spawn, {.v = mpdnext } }, -+// { 0, XF86XK_AudioPrev, spawn, {.v = mpdprev } }, -+// { ShiftMask, XF86XK_AudioPlay, spawn, {.v = plytoggle } }, -+// { ShiftMask, XF86XK_AudioNext, spawn, {.v = plyfwd } }, -+// { ShiftMask, XF86XK_AudioPrev, spawn, {.v = plybck } }, -+// { 0, XF86XK_MonBrightnessUp, spawn, {.v = blightup } }, -+// { 0, XF86XK_MonBrightnessDown, spawn, {.v = blightdown } }, -+// { 0, XF86XK_AudioLowerVolume, spawn, {.v = audiodown } }, -+// { 0, XF86XK_AudioRaiseVolume, spawn, {.v = audioup } }, -+// { 0, XF86XK_AudioMute, spawn, {.v = audiomute } }, -+// { 0, XF86XK_AudioMicMute, spawn, {.v = micmute } }, -+// { Mod4Mask, XK_l, spawn, {.v = lockscr } }, ++ { 0, XF86XK_AudioPlay, spawn, {.v = mpdtoggle } }, ++ { 0, XF86XK_AudioNext, spawn, {.v = mpdnext } }, ++ { 0, XF86XK_AudioPrev, spawn, {.v = mpdprev } }, ++ { ShiftMask, XF86XK_AudioPlay, spawn, {.v = plytoggle } }, ++ { ShiftMask, XF86XK_AudioNext, spawn, {.v = plyfwd } }, ++ { ShiftMask, XF86XK_AudioPrev, spawn, {.v = plybck } }, ++ { 0, XF86XK_MonBrightnessUp, spawn, {.v = blightup } }, ++ { 0, XF86XK_MonBrightnessDown, spawn, {.v = blightdown } }, ++ { 0, XF86XK_AudioLowerVolume, spawn, {.v = audiodown } }, ++ { 0, XF86XK_AudioRaiseVolume, spawn, {.v = audioup } }, ++ { 0, XF86XK_AudioMute, spawn, {.v = audiomute } }, ++ { 0, XF86XK_AudioMicMute, spawn, {.v = micmute } }, ++ { Mod4Mask, XK_l, spawn, {.v = lockscr } }, + { MODKEY, XK_b, togglebar, {0} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY|ShiftMask, XK_j, pushdown, {.i = +1 } }, + { MODKEY|ShiftMask, XK_k, pushup, {.i = -1 } }, -+ { MODKEY|ControlMask, XK_j, setcfact, {.f = +0.25} }, -+ { MODKEY|ControlMask, XK_k, setcfact, {.f = -0.25} }, ++ { MODKEY|ControlMask, XK_k, setcfact, {.f = +0.25} }, ++ { MODKEY|ControlMask, XK_j, setcfact, {.f = -0.25} }, + { MODKEY|ControlMask, XK_o, setcfact, {.f = 0.00} }, -+ { MODKEY, XK_comma, incnmaster, {.i = +1 } }, -+ { MODKEY, XK_period, incnmaster, {.i = -1 } }, ++ { MODKEY|ShiftMask, XK_h, incnmaster, {.i = +1 } }, ++ { MODKEY|ShiftMask, XK_l, incnmaster, {.i = -1 } }, + { MODKEY, XK_h, setmfact, {.f = -0.05} }, + { MODKEY, XK_l, setmfact, {.f = +0.05} }, -+ { MODKEY|ShiftMask, XK_h, setcfact, {.f = +0.25} }, -+ { MODKEY|ShiftMask, XK_l, setcfact, {.f = -0.25} }, -+ { MODKEY|ShiftMask, XK_o, setcfact, {.f = 0.00} }, + { MODKEY|ShiftMask, XK_Return, zoom, {0} }, + { MODKEY, XK_Tab, view, {0} }, + { MODKEY|ShiftMask, XK_q, killclient, {0} }, @@ -442,10 +441,18 @@ index 0000000..b355e1f +}; + diff --git a/config.mk b/config.mk -index 7084c33..5e93cfd 100644 +index 7084c33..dbbc526 100644 --- a/config.mk +++ b/config.mk -@@ -22,10 +22,10 @@ FREETYPEINC = /usr/include/freetype2 +@@ -6,6 +6,7 @@ VERSION = 6.2 + # paths + PREFIX = /usr/local + MANPREFIX = ${PREFIX}/share/man ++XSESSIONPREFIX = /usr/share/xsessions + + X11INC = /usr/X11R6/include + X11LIB = /usr/X11R6/lib +@@ -22,10 +23,10 @@ FREETYPEINC = /usr/include/freetype2 # includes and libs INCS = -I${X11INC} -I${FREETYPEINC} @@ -459,7 +466,7 @@ index 7084c33..5e93cfd 100644 CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS} LDFLAGS = ${LIBS} diff --git a/dwm.1 b/dwm.1 -index 13b3729..68b6722 100644 +index ddc8321..0ec6c60 100644 --- a/dwm.1 +++ b/dwm.1 @@ -12,10 +12,11 @@ environment for the application in use and the task performed. @@ -700,7 +707,7 @@ index 13b3729..68b6722 100644 .BR dmenu (1), .BR st (1) diff --git a/dwm.c b/dwm.c -index 41c6767..22fbade 100644 +index 664c527..cecbe53 100644 --- a/dwm.c +++ b/dwm.c @@ -40,6 +40,8 @@ @@ -817,7 +824,7 @@ index 41c6767..22fbade 100644 static Monitor *createmon(void); static void destroynotify(XEvent *e); static void detach(Client *c); -@@ -165,12 +205,16 @@ static void drawbar(Monitor *m); +@@ -165,13 +205,16 @@ static void drawbar(Monitor *m); static void drawbars(void); static void enternotify(XEvent *e); static void expose(XEvent *e); @@ -827,14 +834,14 @@ index 41c6767..22fbade 100644 static void focusmon(const Arg *arg); static void focusstack(const Arg *arg); +static int getdwmblockspid(); -+static Atom getatomprop(Client *c, Atom prop); + static Atom getatomprop(Client *c, Atom prop); static int getrootptr(int *x, int *y); static long getstate(Window w); +static unsigned int getsystraywidth(); static int gettextprop(Window w, Atom atom, char *text, unsigned int size); static void grabbuttons(Client *c, int focused); static void grabkeys(void); -@@ -184,33 +228,46 @@ static void monocle(Monitor *m); +@@ -185,33 +228,46 @@ static void monocle(Monitor *m); static void motionnotify(XEvent *e); static void movemouse(const Arg *arg); static Client *nexttiled(Client *c); @@ -883,7 +890,7 @@ index 41c6767..22fbade 100644 static void toggletag(const Arg *arg); static void toggleview(const Arg *arg); static void unfocus(Client *c, int setfocus); -@@ -223,20 +280,36 @@ static int updategeom(void); +@@ -224,20 +280,36 @@ static int updategeom(void); static void updatenumlockmask(void); static void updatesizehints(Client *c); static void updatestatus(void); @@ -920,7 +927,7 @@ index 41c6767..22fbade 100644 static int screen; static int sw, sh; /* X display screen geometry width, height */ static int bh, blw = 0; /* bar geometry */ -@@ -257,9 +330,11 @@ static void (*handler[LASTEvent]) (XEvent *) = { +@@ -258,9 +330,11 @@ static void (*handler[LASTEvent]) (XEvent *) = { [MapRequest] = maprequest, [MotionNotify] = motionnotify, [PropertyNotify] = propertynotify, @@ -933,7 +940,7 @@ index 41c6767..22fbade 100644 static int running = 1; static Cur *cursor[CurLast]; static Clr **scheme; -@@ -268,6 +343,8 @@ static Drw *drw; +@@ -269,6 +343,8 @@ static Drw *drw; static Monitor *mons, *selmon; static Window root, wmcheckwin; @@ -942,7 +949,7 @@ index 41c6767..22fbade 100644 /* configuration, allows nested code to access above variables */ #include "config.h" -@@ -285,6 +362,7 @@ applyrules(Client *c) +@@ -286,6 +362,7 @@ applyrules(Client *c) XClassHint ch = { NULL, NULL }; /* rule matching */ @@ -950,7 +957,7 @@ index 41c6767..22fbade 100644 c->isfloating = 0; c->tags = 0; XGetClassHint(dpy, c->win, &ch); -@@ -297,6 +375,8 @@ applyrules(Client *c) +@@ -298,6 +375,8 @@ applyrules(Client *c) && (!r->class || strstr(class, r->class)) && (!r->instance || strstr(instance, r->instance))) { @@ -959,7 +966,7 @@ index 41c6767..22fbade 100644 c->isfloating = r->isfloating; c->tags |= r->tags; for (m = mons; m && m->num != r->monitor; m = m->next); -@@ -405,6 +485,26 @@ attach(Client *c) +@@ -406,6 +485,26 @@ attach(Client *c) c->next = c->mon->clients; c->mon->clients = c; } @@ -986,7 +993,7 @@ index 41c6767..22fbade 100644 void attachstack(Client *c) -@@ -413,6 +513,61 @@ attachstack(Client *c) +@@ -414,6 +513,61 @@ attachstack(Client *c) c->mon->stack = c; } @@ -1048,35 +1055,35 @@ index 41c6767..22fbade 100644 void buttonpress(XEvent *e) { -@@ -439,9 +594,25 @@ buttonpress(XEvent *e) +@@ -440,9 +594,25 @@ 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 > (x = selmon->ww - TEXTW(stext) + lrpad - getsystraywidth())) { +- else if (ev->x > selmon->ww - (int)TEXTW(stext)) ++ else if (ev->x > (x = selmon->ww - (int)TEXTW(stext) + lrpad - getsystraywidth())) { click = ClkStatusText; - else + char *text = rawstext; + int i = -1; + char ch; + dwmblockssig = 0; -+ while (text[++i]) { -+ if ((unsigned char)text[i] < ' ') { -+ ch = text[i]; -+ text[i] = '\0'; -+ x += TEXTW(text) - lrpad; -+ text[i] = ch; -+ text += i+1; -+ i = -1; -+ if (x >= ev->x) break; -+ dwmblockssig = ch; -+ } -+ } ++ while (text[++i]) { ++ if ((unsigned char)text[i] < ' ') { ++ ch = text[i]; ++ text[i] = '\0'; ++ x += TEXTW(text) - lrpad; ++ text[i] = ch; ++ text += i+1; ++ i = -1; ++ if (x >= ev->x) break; ++ dwmblockssig = ch; ++ } ++ } + } else click = ClkWinTitle; } else if ((c = wintoclient(ev->window))) { focus(c); -@@ -482,6 +653,11 @@ cleanup(void) +@@ -483,6 +653,11 @@ cleanup(void) XUngrabKey(dpy, AnyKey, AnyModifier, root); while (mons) cleanupmon(mons); @@ -1088,7 +1095,7 @@ index 41c6767..22fbade 100644 for (i = 0; i < CurLast; i++) drw_cur_free(drw, cursor[i]); for (i = 0; i < LENGTH(colors); i++) -@@ -512,9 +688,57 @@ cleanupmon(Monitor *mon) +@@ -513,9 +688,57 @@ cleanupmon(Monitor *mon) void clientmessage(XEvent *e) { @@ -1146,7 +1153,7 @@ index 41c6767..22fbade 100644 if (!c) return; if (cme->message_type == netatom[NetWMState]) { -@@ -567,7 +791,7 @@ configurenotify(XEvent *e) +@@ -568,7 +791,7 @@ configurenotify(XEvent *e) for (c = m->clients; c; c = c->next) if (c->isfullscreen) resizeclient(c, m->mx, m->my, m->mw, m->mh); @@ -1155,7 +1162,7 @@ index 41c6767..22fbade 100644 } focus(NULL); arrange(NULL); -@@ -627,6 +851,19 @@ configurerequest(XEvent *e) +@@ -628,6 +851,19 @@ configurerequest(XEvent *e) XSync(dpy, False); } @@ -1175,7 +1182,7 @@ index 41c6767..22fbade 100644 Monitor * createmon(void) { -@@ -652,6 +889,15 @@ destroynotify(XEvent *e) +@@ -653,6 +889,15 @@ destroynotify(XEvent *e) if ((c = wintoclient(ev->window))) unmanage(c, 1); @@ -1191,39 +1198,40 @@ index 41c6767..22fbade 100644 } void -@@ -695,19 +941,24 @@ dirtomon(int dir) +@@ -696,18 +941,24 @@ dirtomon(int dir) void drawbar(Monitor *m) { -- int x, w, sw = 0; -+ int indn; -+ int x, w, sw = 0, stw = 0; +- int x, w, tw = 0; ++ int indn; ++ int x, w, tw = 0, stw = 0; int boxs = drw->fonts->h / 9; int boxw = drw->fonts->h / 6 + 2; unsigned int i, occ = 0, urg = 0; Client *c; + if(showsystray && m == systraytomon(m)) -+ stw = getsystraywidth(); ++ stw = getsystraywidth(); + /* 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); -+ sw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */ -+ drw_text(drw, m->ww - sw - stw, 0, sw, bh, lrpad / 2 - 2, stext, 0); - } - +- tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ +- drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); +- } ++ tw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */ ++ drw_text(drw, m->ww - tw - stw, 0, tw, bh, lrpad / 2 - 2, stext, 0); ++ } ++ + resizebarwin(m); + for (c = m->clients; c; c = c->next) { occ |= c->tags; - if (c->isurgent) -@@ -715,20 +966,25 @@ drawbar(Monitor *m) +@@ -716,20 +967,24 @@ drawbar(Monitor *m) } x = 0; for (i = 0; i < LENGTH(tags); i++) { -+ indn = 0; ++ indn = 0; w = TEXTW(tags[i]); drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); @@ -1231,13 +1239,12 @@ index 41c6767..22fbade 100644 - drw_rect(drw, x + boxs, boxs, boxw, boxw, - m == selmon && selmon->sel && selmon->sel->tags & 1 << i, - urg & 1 << i); -+ -+ for (c = m->clients; c; c = c->next) { -+ if (c->tags & (1 << i)) { -+ drw_rect(drw, x, 1 + (indn * 2), selmon->sel == c ? 6 : 1, 1, 1, urg & 1 << i); -+ indn++; -+ } -+ } ++ for (c = m->clients; c; c = c->next) { ++ if (c->tags & (1 << i)) { ++ drw_rect(drw, x, 1 + (indn * 2), selmon->sel == c ? 6 : 1, 1, 1, urg & 1 << i); ++ indn++; ++ } ++ } + x += w; } @@ -1245,12 +1252,12 @@ index 41c6767..22fbade 100644 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 - sw - stw - x) > bh) { +- if ((w = m->ww - tw - x) > bh) { ++ if ((w = m->ww - tw - stw - 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); -@@ -739,7 +995,7 @@ drawbar(Monitor *m) +@@ -740,7 +995,7 @@ drawbar(Monitor *m) drw_rect(drw, x, 0, w, bh, 1, 1); } } @@ -1259,7 +1266,7 @@ index 41c6767..22fbade 100644 } void -@@ -776,8 +1032,21 @@ expose(XEvent *e) +@@ -777,8 +1032,21 @@ expose(XEvent *e) Monitor *m; XExposeEvent *ev = &e->xexpose; @@ -1282,7 +1289,7 @@ index 41c6767..22fbade 100644 } void -@@ -862,15 +1131,34 @@ getatomprop(Client *c, Atom prop) +@@ -863,15 +1131,34 @@ getatomprop(Client *c, Atom prop) unsigned long dl; unsigned char *p = NULL; Atom da, atom = None; @@ -1318,7 +1325,7 @@ index 41c6767..22fbade 100644 int getrootptr(int *x, int *y) { -@@ -899,6 +1187,16 @@ getstate(Window w) +@@ -900,6 +1187,16 @@ getstate(Window w) return result; } @@ -1335,7 +1342,7 @@ index 41c6767..22fbade 100644 int gettextprop(Window w, Atom atom, char *text, unsigned int size) { -@@ -998,12 +1296,55 @@ keypress(XEvent *e) +@@ -999,12 +1296,55 @@ keypress(XEvent *e) keys[i].func(&(keys[i].arg)); } @@ -1392,7 +1399,7 @@ index 41c6767..22fbade 100644 XGrabServer(dpy); XSetErrorHandler(xerrordummy); XSetCloseDownMode(dpy, DestroyAll); -@@ -1017,18 +1358,20 @@ killclient(const Arg *arg) +@@ -1018,18 +1358,20 @@ killclient(const Arg *arg) void manage(Window w, XWindowAttributes *wa) { @@ -1414,7 +1421,7 @@ index 41c6767..22fbade 100644 updatetitle(c); if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { -@@ -1037,6 +1380,7 @@ manage(Window w, XWindowAttributes *wa) +@@ -1038,6 +1380,7 @@ manage(Window w, XWindowAttributes *wa) } else { c->mon = selmon; applyrules(c); @@ -1422,7 +1429,7 @@ index 41c6767..22fbade 100644 } if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw) -@@ -1062,7 +1406,10 @@ manage(Window w, XWindowAttributes *wa) +@@ -1063,7 +1406,10 @@ manage(Window w, XWindowAttributes *wa) c->isfloating = c->oldstate = trans != None || c->isfixed; if (c->isfloating) XRaiseWindow(dpy, c->win); @@ -1434,7 +1441,7 @@ index 41c6767..22fbade 100644 attachstack(c); XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, (unsigned char *) &(c->win), 1); -@@ -1073,6 +1420,8 @@ manage(Window w, XWindowAttributes *wa) +@@ -1074,6 +1420,8 @@ manage(Window w, XWindowAttributes *wa) c->mon->sel = c; arrange(c->mon); XMapWindow(dpy, c->win); @@ -1443,7 +1450,7 @@ index 41c6767..22fbade 100644 focus(NULL); } -@@ -1091,6 +1440,12 @@ maprequest(XEvent *e) +@@ -1092,6 +1440,12 @@ maprequest(XEvent *e) { static XWindowAttributes wa; XMapRequestEvent *ev = &e->xmaprequest; @@ -1456,7 +1463,7 @@ index 41c6767..22fbade 100644 if (!XGetWindowAttributes(dpy, ev->window, &wa)) return; -@@ -1199,6 +1554,7 @@ nexttiled(Client *c) +@@ -1200,6 +1554,7 @@ nexttiled(Client *c) return c; } @@ -1464,7 +1471,7 @@ index 41c6767..22fbade 100644 void pop(Client *c) { -@@ -1207,6 +1563,17 @@ pop(Client *c) +@@ -1208,6 +1563,17 @@ pop(Client *c) focus(c); arrange(c->mon); } @@ -1482,7 +1489,7 @@ index 41c6767..22fbade 100644 void propertynotify(XEvent *e) -@@ -1215,8 +1582,20 @@ propertynotify(XEvent *e) +@@ -1216,8 +1582,20 @@ propertynotify(XEvent *e) Window trans; XPropertyEvent *ev = &e->xproperty; @@ -1505,7 +1512,7 @@ index 41c6767..22fbade 100644 else if (ev->state == PropertyDelete) return; /* ignore */ else if ((c = wintoclient(ev->window))) { -@@ -1245,9 +1624,41 @@ propertynotify(XEvent *e) +@@ -1246,9 +1624,41 @@ propertynotify(XEvent *e) } } @@ -1547,7 +1554,7 @@ index 41c6767..22fbade 100644 running = 0; } -@@ -1265,6 +1676,20 @@ recttomon(int x, int y, int w, int h) +@@ -1266,6 +1676,20 @@ recttomon(int x, int y, int w, int h) return r; } @@ -1568,7 +1575,7 @@ index 41c6767..22fbade 100644 void resize(Client *c, int x, int y, int w, int h, int interact) { -@@ -1272,16 +1697,48 @@ resize(Client *c, int x, int y, int w, int h, int interact) +@@ -1273,16 +1697,48 @@ resize(Client *c, int x, int y, int w, int h, int interact) resizeclient(c, x, y, w, h); } @@ -1621,7 +1628,7 @@ index 41c6767..22fbade 100644 XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc); configure(c); XSync(dpy, False); -@@ -1344,6 +1801,19 @@ resizemouse(const Arg *arg) +@@ -1345,6 +1801,19 @@ resizemouse(const Arg *arg) } } @@ -1641,7 +1648,7 @@ index 41c6767..22fbade 100644 void restack(Monitor *m) { -@@ -1380,10 +1850,18 @@ run(void) +@@ -1381,10 +1850,18 @@ run(void) handler[ev.type](&ev); /* call handler */ } @@ -1660,7 +1667,7 @@ index 41c6767..22fbade 100644 Window d1, d2, *wins = NULL; XWindowAttributes wa; -@@ -1394,6 +1872,8 @@ scan(void) +@@ -1395,6 +1872,8 @@ scan(void) continue; if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) manage(wins[i], &wa); @@ -1669,7 +1676,7 @@ index 41c6767..22fbade 100644 } for (i = 0; i < num; i++) { /* now the transients */ if (!XGetWindowAttributes(dpy, wins[i], &wa)) -@@ -1405,6 +1885,7 @@ scan(void) +@@ -1406,6 +1885,7 @@ scan(void) if (wins) XFree(wins); } @@ -1677,7 +1684,7 @@ index 41c6767..22fbade 100644 } void -@@ -1417,7 +1898,10 @@ sendmon(Client *c, Monitor *m) +@@ -1418,7 +1898,10 @@ sendmon(Client *c, Monitor *m) detachstack(c); c->mon = m; c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ @@ -1689,7 +1696,7 @@ index 41c6767..22fbade 100644 attachstack(c); focus(NULL); arrange(NULL); -@@ -1433,26 +1917,36 @@ setclientstate(Client *c, long state) +@@ -1434,26 +1917,36 @@ setclientstate(Client *c, long state) } int @@ -1737,7 +1744,7 @@ index 41c6767..22fbade 100644 } return exists; } -@@ -1466,7 +1960,7 @@ setfocus(Client *c) +@@ -1467,7 +1960,7 @@ setfocus(Client *c) XA_WINDOW, 32, PropModeReplace, (unsigned char *) &(c->win), 1); } @@ -1746,7 +1753,7 @@ index 41c6767..22fbade 100644 } void -@@ -1511,6 +2005,23 @@ setlayout(const Arg *arg) +@@ -1512,6 +2005,23 @@ setlayout(const Arg *arg) drawbar(selmon); } @@ -1770,7 +1777,7 @@ index 41c6767..22fbade 100644 /* arg > 1.0 will set mfact absolutely */ void setmfact(const Arg *arg) -@@ -1520,7 +2031,7 @@ setmfact(const Arg *arg) +@@ -1521,7 +2031,7 @@ 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; @@ -1779,7 +1786,7 @@ index 41c6767..22fbade 100644 return; selmon->mfact = f; arrange(selmon); -@@ -1536,6 +2047,9 @@ setup(void) +@@ -1537,6 +2047,9 @@ setup(void) /* clean up any zombies immediately */ sigchld(0); @@ -1789,7 +1796,7 @@ index 41c6767..22fbade 100644 /* init screen */ screen = DefaultScreen(dpy); sw = DisplayWidth(dpy, screen); -@@ -1555,6 +2069,10 @@ setup(void) +@@ -1556,6 +2069,10 @@ setup(void) wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); @@ -1800,7 +1807,7 @@ index 41c6767..22fbade 100644 netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False); -@@ -1562,6 +2080,9 @@ setup(void) +@@ -1563,6 +2080,9 @@ setup(void) 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); @@ -1810,7 +1817,7 @@ index 41c6767..22fbade 100644 /* init cursors */ cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); cursor[CurResize] = drw_cur_create(drw, XC_sizing); -@@ -1570,6 +2091,8 @@ setup(void) +@@ -1571,6 +2091,8 @@ setup(void) scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); for (i = 0; i < LENGTH(colors); i++) scheme[i] = drw_scm_create(drw, colors[i], 3); @@ -1819,7 +1826,7 @@ index 41c6767..22fbade 100644 /* init bars */ updatebars(); updatestatus(); -@@ -1636,6 +2159,37 @@ sigchld(int unused) +@@ -1637,6 +2159,37 @@ sigchld(int unused) while (0 < waitpid(-1, NULL, WNOHANG)); } @@ -1857,7 +1864,7 @@ index 41c6767..22fbade 100644 void spawn(const Arg *arg) { -@@ -1674,9 +2228,15 @@ void +@@ -1675,9 +2228,15 @@ void tile(Monitor *m) { unsigned int i, n, h, mw, my, ty; @@ -1874,25 +1881,31 @@ index 41c6767..22fbade 100644 if (n == 0) return; -@@ -1686,13 +2246,15 @@ tile(Monitor *m) +@@ -1687,15 +2246,19 @@ tile(Monitor *m) 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); + h = (m->wh - my) * (c->cfact / mfacts); resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); - my += HEIGHT(c); -+ mfacts -= c->cfact; +- if (my + HEIGHT(c) < m->wh) ++ if (my + HEIGHT(c) < m->wh) { + my += HEIGHT(c); ++ mfacts -= c->cfact; ++ } } else { - h = (m->wh - ty) / (n - i); + h = (m->wh - ty) * (c->cfact / sfacts); resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0); - ty += HEIGHT(c); -+ sfacts -= c->cfact; +- if (ty + HEIGHT(c) < m->wh) ++ if (ty + HEIGHT(c) < m->wh) { + ty += HEIGHT(c); ++ sfacts -= c->cfact; ++ } } } -@@ -1701,7 +2263,18 @@ togglebar(const Arg *arg) +@@ -1704,7 +2267,18 @@ togglebar(const Arg *arg) { selmon->showbar = !selmon->showbar; updatebarpos(selmon); @@ -1912,7 +1925,7 @@ index 41c6767..22fbade 100644 arrange(selmon); } -@@ -1719,6 +2292,13 @@ togglefloating(const Arg *arg) +@@ -1722,6 +2296,13 @@ togglefloating(const Arg *arg) arrange(selmon); } @@ -1926,7 +1939,7 @@ index 41c6767..22fbade 100644 void toggletag(const Arg *arg) { -@@ -1765,6 +2345,20 @@ unmanage(Client *c, int destroyed) +@@ -1768,6 +2349,20 @@ unmanage(Client *c, int destroyed) Monitor *m = c->mon; XWindowChanges wc; @@ -1947,7 +1960,7 @@ index 41c6767..22fbade 100644 detach(c); detachstack(c); if (!destroyed) { -@@ -1779,9 +2373,12 @@ unmanage(Client *c, int destroyed) +@@ -1782,9 +2377,12 @@ unmanage(Client *c, int destroyed) XUngrabServer(dpy); } free(c); @@ -1963,7 +1976,7 @@ index 41c6767..22fbade 100644 } void -@@ -1796,11 +2393,18 @@ unmapnotify(XEvent *e) +@@ -1799,11 +2397,18 @@ unmapnotify(XEvent *e) else unmanage(c, 0); } @@ -1982,7 +1995,7 @@ index 41c6767..22fbade 100644 Monitor *m; XSetWindowAttributes wa = { .override_redirect = True, -@@ -1811,10 +2415,15 @@ updatebars(void) +@@ -1814,10 +2419,15 @@ updatebars(void) for (m = mons; m; m = m->next) { if (m->barwin) continue; @@ -1999,7 +2012,7 @@ index 41c6767..22fbade 100644 XMapRaised(dpy, m->barwin); XSetClassHint(dpy, m->barwin, &ch); } -@@ -1897,7 +2506,10 @@ updategeom(void) +@@ -1900,7 +2510,10 @@ updategeom(void) m->clients = c->next; detachstack(c); c->mon = mons; @@ -2011,7 +2024,7 @@ index 41c6767..22fbade 100644 attachstack(c); } if (m == selmon) -@@ -1987,9 +2599,126 @@ updatesizehints(Client *c) +@@ -1990,9 +2603,126 @@ updatesizehints(Client *c) void updatestatus(void) { @@ -2139,7 +2152,7 @@ index 41c6767..22fbade 100644 } void -@@ -2044,6 +2773,110 @@ view(const Arg *arg) +@@ -2047,6 +2777,110 @@ view(const Arg *arg) arrange(selmon); } @@ -2250,7 +2263,7 @@ index 41c6767..22fbade 100644 Client * wintoclient(Window w) { -@@ -2057,6 +2890,16 @@ wintoclient(Window w) +@@ -2060,6 +2894,16 @@ wintoclient(Window w) return NULL; } @@ -2267,7 +2280,7 @@ index 41c6767..22fbade 100644 Monitor * wintomon(Window w) { -@@ -2110,18 +2953,58 @@ xerrorstart(Display *dpy, XErrorEvent *ee) +@@ -2113,18 +2957,58 @@ xerrorstart(Display *dpy, XErrorEvent *ee) return -1; } @@ -2330,7 +2343,7 @@ index 41c6767..22fbade 100644 } int -@@ -2135,6 +3018,8 @@ main(int argc, char *argv[]) +@@ -2138,6 +3022,8 @@ main(int argc, char *argv[]) fputs("warning: no locale support\n", stderr); if (!(dpy = XOpenDisplay(NULL))) die("dwm: cannot open display"); @@ -2339,7 +2352,7 @@ index 41c6767..22fbade 100644 checkotherwm(); setup(); #ifdef __OpenBSD__ -@@ -2142,7 +3027,9 @@ main(int argc, char *argv[]) +@@ -2145,7 +3031,9 @@ main(int argc, char *argv[]) die("pledge"); #endif /* __OpenBSD__ */ scan(); @@ -2350,1077 +2363,2201 @@ index 41c6767..22fbade 100644 cleanup(); XCloseDisplay(dpy); return EXIT_SUCCESS; -diff --git a/dwmc b/dwmc -new file mode 100755 -index 0000000..5ff8dbc +diff --git a/dwm.c.orig b/dwm.c.orig +new file mode 100644 +index 0000000..664c527 --- /dev/null -+++ b/dwmc -@@ -0,0 +1,40 @@ -+#!/usr/bin/env sh ++++ b/dwm.c.orig +@@ -0,0 +1,2152 @@ ++/* 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 <errno.h> ++#include <locale.h> ++#include <signal.h> ++#include <stdarg.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <unistd.h> ++#include <sys/types.h> ++#include <sys/wait.h> ++#include <X11/cursorfont.h> ++#include <X11/keysym.h> ++#include <X11/Xatom.h> ++#include <X11/Xlib.h> ++#include <X11/Xproto.h> ++#include <X11/Xutil.h> ++#ifdef XINERAMA ++#include <X11/extensions/Xinerama.h> ++#endif /* XINERAMA */ ++#include <X11/Xft/Xft.h> ++ ++#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) ++#define HEIGHT(X) ((X)->h + 2 * (X)->bw) ++#define TAGMASK ((1 << LENGTH(tags)) - 1) ++#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) ++ ++/* enums */ ++enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ ++enum { SchemeNorm, SchemeSel }; /* color schemes */ ++enum { NetSupported, NetWMName, NetWMState, NetWMCheck, ++ 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; + -+signal() { -+ xsetroot -name "fsignal:$*" ++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 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 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); ++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 seturgent(Client *c, int urg); ++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 void updatebarpos(Monitor *m); ++static void updatebars(void); ++static void updateclientlist(void); ++static int updategeom(void); ++static void updatenumlockmask(void); ++static void updatesizehints(Client *c); ++static void updatestatus(void); ++static void updatetitle(Client *c); ++static void updatewindowtype(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 lrpad; /* sum of left and right padding for text */ ++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 Clr **scheme; ++static Display *dpy; ++static Drw *drw; ++static Monitor *mons, *selmon; ++static Window root, wmcheckwin; ++ ++/* 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]; +} + -+case $# in -+1) -+ case $1 in -+ setlayout | view | viewall | togglebar | togglefloating | zoom | killclient | quit) -+ signal $1 -+ ;; -+ *) -+ echo "Unknown command or missing one argument." -+ exit 1 -+ ;; -+ esac -+ ;; -+2) -+ case $1 in -+ view) -+ signal $1 ui $2 -+ ;; -+ viewex | toggleviewex | tagex | toggletagex | setlayoutex | focusstack | incnmaster | focusmon | tagmon) -+ signal $1 i $2 -+ ;; -+ setmfact) -+ signal $1 f $2 -+ ;; -+ *) -+ echo "Unknown command or one too many arguments." -+ exit 1 -+ ;; -+ esac -+ ;; -+*) -+ echo "Too many arguments." -+ exit 1 -+ ;; -+esac -diff --git a/patches/dwm-actualfullscreen-20191112-cb3f58a.diff b/patches/dwm-actualfullscreen-20191112-cb3f58a.diff -new file mode 100644 -index 0000000..21eea19 ---- /dev/null -+++ b/patches/dwm-actualfullscreen-20191112-cb3f58a.diff -@@ -0,0 +1,53 @@ -+From 3a16816a6f5d38014c2a06ce395873c545c8789a Mon Sep 17 00:00:00 2001 -+From: Soenke Lambert <s.lambert@mittwald.de> -+Date: Tue, 12 Nov 2019 10:44:02 +0100 -+Subject: [PATCH] Fullscreen current window with [Alt]+[Shift]+[f] -+ -+This actually fullscreens a window, instead of just hiding the statusbar -+and applying the monocle layout. -+--- -+ config.def.h | 1 + -+ dwm.c | 8 ++++++++ -+ 2 files changed, 9 insertions(+) -+ -+diff --git a/config.def.h b/config.def.h -+index 1c0b587..8cd3204 100644 -+--- a/config.def.h -++++ b/config.def.h -+@@ -78,6 +78,7 @@ static Key keys[] = { -+ { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, -+ { MODKEY, XK_space, setlayout, {0} }, -+ { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, -++ { MODKEY|ShiftMask, XK_f, togglefullscr, {0} }, -+ { MODKEY, XK_0, view, {.ui = ~0 } }, -+ { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, -+ { MODKEY, XK_comma, focusmon, {.i = -1 } }, -+diff --git a/dwm.c b/dwm.c -+index 4465af1..c1b899a 100644 -+--- a/dwm.c -++++ b/dwm.c -+@@ -211,6 +211,7 @@ static void tagmon(const Arg *arg); -+ static void tile(Monitor *); -+ static void togglebar(const Arg *arg); -+ static void togglefloating(const Arg *arg); -++static void togglefullscr(const Arg *arg); -+ static void toggletag(const Arg *arg); -+ static void toggleview(const Arg *arg); -+ static void unfocus(Client *c, int setfocus); -+@@ -1719,6 +1720,13 @@ togglefloating(const Arg *arg) -+ arrange(selmon); -+ } -+ -++void -++togglefullscr(const Arg *arg) -++{ -++ if(selmon->sel) -++ setfullscreen(selmon->sel, !selmon->sel->isfullscreen); -++} -++ -+ void -+ toggletag(const Arg *arg) -+ { -+-- -+2.17.1 ++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; ++} + -diff --git a/patches/dwm-attachbelow-toggleable-6.2.diff b/patches/dwm-attachbelow-toggleable-6.2.diff -new file mode 100644 -index 0000000..e5ff9fd ---- /dev/null -+++ b/patches/dwm-attachbelow-toggleable-6.2.diff -@@ -0,0 +1,199 @@ -+From ee036687ed9e1bb973b9e34694a57cf5dd67652d Mon Sep 17 00:00:00 2001 -+From: Jonathan Hodgson <git@jonathanh.co.uk> -+Date: Mon, 6 May 2019 18:34:40 +0100 -+Subject: [PATCH 1/4] Adds attach below option -+ -+--- -+ config.def.h | 1 + -+ dwm.c | 31 ++++++++++++++++++++++++++++--- -+ 2 files changed, 29 insertions(+), 3 deletions(-) -+ -+diff --git a/config.def.h b/config.def.h -+index 1c0b587..51ad933 100644 -+--- a/config.def.h -++++ b/config.def.h -+@@ -35,6 +35,7 @@ static const Rule rules[] = { -+ static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ -+ static const int nmaster = 1; /* number of clients in master area */ -+ static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ -++static const int attachbelow = 1; /* 1 means attach at the end */ -+ -+ static const Layout layouts[] = { -+ /* symbol arrange function */ -+diff --git a/dwm.c b/dwm.c -+index 4465af1..bd715a2 100644 -+--- a/dwm.c -++++ b/dwm.c -+@@ -147,6 +147,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 attachBelow(Client *c); -+ static void attachstack(Client *c); -+ static void buttonpress(XEvent *e); -+ static void checkotherwm(void); -+@@ -405,6 +406,21 @@ attach(Client *c) -+ c->next = c->mon->clients; -+ c->mon->clients = c; -+ } -++void -++attachBelow(Client *c) -++{ -++ //If there is nothing on the monitor or the selected client is floating, attach as normal -++ if(c->mon->sel == NULL || c->mon->sel->isfloating) { -++ attach(c); -++ return; -++ } -++ -++ //Set the new client's next property to the same as the currently selected clients next -++ c->next = c->mon->sel->next; -++ //Set the currently selected clients next property to the new client -++ c->mon->sel->next = c; -++ -++} -+ -+ void -+ attachstack(Client *c) -+@@ -1062,7 +1078,10 @@ manage(Window w, XWindowAttributes *wa) -+ c->isfloating = c->oldstate = trans != None || c->isfixed; -+ if (c->isfloating) -+ XRaiseWindow(dpy, c->win); -+- attach(c); -++ if( attachbelow ) -++ attachBelow(c); -++ else -++ attach(c); -+ attachstack(c); -+ XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, -+ (unsigned char *) &(c->win), 1); -+@@ -1417,7 +1436,10 @@ sendmon(Client *c, Monitor *m) -+ detachstack(c); -+ c->mon = m; -+ c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ -+- attach(c); -++ if( attachbelow ) -++ attachBelow(c); -++ else -++ attach(c); -+ attachstack(c); -+ focus(NULL); -+ arrange(NULL); -+@@ -1897,7 +1919,10 @@ updategeom(void) -+ m->clients = c->next; -+ detachstack(c); -+ c->mon = mons; -+- attach(c); -++ if( attachbelow ) -++ attachBelow(c); -++ else -++ attach(c); -+ attachstack(c); -+ } -+ if (m == selmon) -+-- -+2.21.0 -+ -+ -+From e212c1d8cbdcc56c33c717131dfa7c1689e27e9f Mon Sep 17 00:00:00 2001 -+From: Jonathan Hodgson <git@jonathanh.co.uk> -+Date: Mon, 6 May 2019 19:27:57 +0100 -+Subject: [PATCH 2/4] fixes comment -+ -+--- -+ config.def.h | 2 +- -+ 1 file changed, 1 insertion(+), 1 deletion(-) -+ -+diff --git a/config.def.h b/config.def.h -+index 51ad933..cb8053a 100644 -+--- a/config.def.h -++++ b/config.def.h -+@@ -35,7 +35,7 @@ static const Rule rules[] = { -+ static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ -+ static const int nmaster = 1; /* number of clients in master area */ -+ static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ -+-static const int attachbelow = 1; /* 1 means attach at the end */ -++static const int attachbelow = 1; /* 1 means attach after the currently active window */ -+ -+ static const Layout layouts[] = { -+ /* symbol arrange function */ -+-- -+2.21.0 -+ -+ -+From 7568ea3f8756e7e82b30c4943556ae646a445d1c Mon Sep 17 00:00:00 2001 -+From: Jonathan Hodgson <git@jonathanh.co.uk> -+Date: Mon, 6 May 2019 20:00:30 +0100 -+Subject: [PATCH 3/4] Makes changes to man page to reflect attach below patch -+ -+--- -+ dwm.1 | 3 +++ -+ 1 file changed, 3 insertions(+) -+ -+diff --git a/dwm.1 b/dwm.1 -+index 13b3729..fb6e76c 100644 -+--- a/dwm.1 -++++ b/dwm.1 -+@@ -29,6 +29,9 @@ color. The tags of the focused window are indicated with a filled square in the -+ top left corner. The tags which are applied to one or more windows are -+ indicated with an empty square in the top left corner. -+ .P -++The attach below patch makes newly spawned windows attach after the currently -++selected window -++.P -+ dwm draws a small border around windows to indicate the focus state. -+ .SH OPTIONS -+ .TP -+-- -+2.21.0 -+ -+ -+From 362b95a5b9f91673f27f3e3343b5738df3c9d6e9 Mon Sep 17 00:00:00 2001 -+From: Jonathan Hodgson <git@jonathanh.co.uk> -+Date: Sun, 2 Jun 2019 15:11:57 +0100 -+Subject: [PATCH 4/4] Allows attach below to be toggled -+ -+--- -+ config.def.h | 2 +- -+ dwm.c | 6 ++++++ -+ 2 files changed, 7 insertions(+), 1 deletion(-) -+ -+diff --git a/config.def.h b/config.def.h -+index cb8053a..b4d35aa 100644 -+--- a/config.def.h -++++ b/config.def.h -+@@ -35,7 +35,7 @@ static const Rule rules[] = { -+ static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ -+ static const int nmaster = 1; /* number of clients in master area */ -+ static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ -+-static const int attachbelow = 1; /* 1 means attach after the currently active window */ -++static int attachbelow = 1; /* 1 means attach after the currently active window */ -+ -+ static const Layout layouts[] = { -+ /* symbol arrange function */ -+diff --git a/dwm.c b/dwm.c -+index bd715a2..5d88653 100644 -+--- a/dwm.c -++++ b/dwm.c -+@@ -148,6 +148,7 @@ static void arrange(Monitor *m); -+ static void arrangemon(Monitor *m); -+ static void attach(Client *c); -+ static void attachBelow(Client *c); -++static void toggleAttachBelow(); -+ static void attachstack(Client *c); -+ static void buttonpress(XEvent *e); -+ static void checkotherwm(void); -+@@ -422,6 +423,11 @@ attachBelow(Client *c) -+ -+ } -+ -++void toggleAttachBelow() -++{ -++ attachbelow = !attachbelow; -++} -++ -+ void -+ attachstack(Client *c) -+ { -+-- -+2.21.0 ++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); ++} + -diff --git a/patches/dwm-autostart-20161205-bb3bd6f.diff b/patches/dwm-autostart-20161205-bb3bd6f.diff -new file mode 100644 -index 0000000..6f11eaf ---- /dev/null -+++ b/patches/dwm-autostart-20161205-bb3bd6f.diff -@@ -0,0 +1,39 @@ -+commit 5918623c5bd7fda155bf9dc3d33890c4ae1722d0 -+Author: Simon Bremer <simon.bremer@tum.de> -+Date: Thu Dec 22 17:31:07 2016 +0100 -+ -+ Applied and fixed autostart patch for previous version; -+ -+diff --git a/dwm.c b/dwm.c -+index d27cb67..066ed71 100644 -+--- a/dwm.c -++++ b/dwm.c -+@@ -194,6 +194,7 @@ 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 runAutostart(void); -+ static void scan(void); -+ static int sendevent(Client *c, Atom proto); -+ static void sendmon(Client *c, Monitor *m); -+@@ -1386,6 +1387,12 @@ run(void) -+ } -+ -+ void -++runAutostart(void) { -++ system("cd ~/.dwm; ./autostart_blocking.sh"); -++ system("cd ~/.dwm; ./autostart.sh &"); -++} -++ -++void -+ scan(void) -+ { -+ unsigned int i, num; -+@@ -2145,6 +2152,7 @@ main(int argc, char *argv[]) -+ checkotherwm(); -+ setup(); -+ scan(); -++ runAutostart(); -+ run(); -+ cleanup(); -+ XCloseDisplay(dpy); -diff --git a/patches/dwm-cfacts-20200913-61bb8b2.diff b/patches/dwm-cfacts-20200913-61bb8b2.diff -new file mode 100644 -index 0000000..bb70e13 ---- /dev/null -+++ b/patches/dwm-cfacts-20200913-61bb8b2.diff -@@ -0,0 +1,117 @@ -+From c32a879432573d71dec7fcb4bf68927d2f4cdf10 Mon Sep 17 00:00:00 2001 -+From: iofq <cjriddz@protonmail.com> -+Date: Sat, 12 Sep 2020 22:28:09 -0500 -+Subject: [PATCH] Fixed 'cfacts' patch failure due to upstream commit -+ 'f09418bbb...' -+ -+--- -+ config.def.h | 3 +++ -+ dwm.c | 34 +++++++++++++++++++++++++++++++--- -+ 2 files changed, 34 insertions(+), 3 deletions(-) -+ -+diff --git a/config.def.h b/config.def.h -+index 1c0b587..83910c1 100644 -+--- a/config.def.h -++++ b/config.def.h -+@@ -70,6 +70,9 @@ static Key keys[] = { -+ { MODKEY, XK_d, incnmaster, {.i = -1 } }, -+ { MODKEY, XK_h, setmfact, {.f = -0.05} }, -+ { MODKEY, XK_l, setmfact, {.f = +0.05} }, -++ { MODKEY|ShiftMask, XK_h, setcfact, {.f = +0.25} }, -++ { MODKEY|ShiftMask, XK_l, setcfact, {.f = -0.25} }, -++ { MODKEY|ShiftMask, XK_o, setcfact, {.f = 0.00} }, -+ { MODKEY, XK_Return, zoom, {0} }, -+ { MODKEY, XK_Tab, view, {0} }, -+ { MODKEY|ShiftMask, XK_c, killclient, {0} }, -+diff --git a/dwm.c b/dwm.c -+index 664c527..5233229 100644 -+--- a/dwm.c -++++ b/dwm.c -+@@ -87,6 +87,7 @@ typedef struct Client Client; -+ struct Client { -+ char name[256]; -+ float mina, maxa; -++ float cfact; -+ int x, y, w, h; -+ int oldx, oldy, oldw, oldh; -+ int basew, baseh, incw, inch, maxw, maxh, minw, minh; -+@@ -201,6 +202,7 @@ 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 setcfact(const Arg *arg); -+ static void setmfact(const Arg *arg); -+ static void setup(void); -+ static void seturgent(Client *c, int urg); -+@@ -1030,6 +1032,7 @@ manage(Window w, XWindowAttributes *wa) -+ c->w = c->oldw = wa->width; -+ c->h = c->oldh = wa->height; -+ c->oldbw = wa->border_width; -++ c->cfact = 1.0; -+ -+ updatetitle(c); -+ if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { -+@@ -1512,6 +1515,23 @@ setlayout(const Arg *arg) -+ drawbar(selmon); -+ } -+ -++void setcfact(const Arg *arg) { -++ float f; -++ Client *c; -++ -++ c = selmon->sel; -++ -++ if(!arg || !c || !selmon->lt[selmon->sellt]->arrange) -++ return; -++ f = arg->f + c->cfact; -++ if(arg->f == 0.0) -++ f = 1.0; -++ else if(f < 0.25 || f > 4.0) -++ return; -++ c->cfact = f; -++ arrange(selmon); -++} -++ -+ /* arg > 1.0 will set mfact absolutely */ -+ void -+ setmfact(const Arg *arg) -+@@ -1675,9 +1695,15 @@ void -+ tile(Monitor *m) -+ { -+ unsigned int i, n, h, mw, my, ty; -++ float mfacts = 0, sfacts = 0; -+ Client *c; -+ -+- for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); -++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) { -++ if (n < m->nmaster) -++ mfacts += c->cfact; -++ else -++ sfacts += c->cfact; -++ } -+ if (n == 0) -+ return; -+ -+@@ -1687,15 +1713,17 @@ tile(Monitor *m) -+ 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); -++ h = (m->wh - my) * (c->cfact / mfacts); -+ resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); -+ if (my + HEIGHT(c) < m->wh) -+ my += HEIGHT(c); -++ mfacts -= c->cfact; -+ } else { -+- h = (m->wh - ty) / (n - i); -++ h = (m->wh - ty) * (c->cfact / sfacts); -+ resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0); -+ if (ty + HEIGHT(c) < m->wh) -+ ty += HEIGHT(c); -++ sfacts -= c->cfact; -+ } -+ } -+ -+-- -+2.28.0 ++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); ++} + -diff --git a/patches/dwm-clientindicators-6.2.diff b/patches/dwm-clientindicators-6.2.diff -new file mode 100644 -index 0000000..f2e9afb ---- /dev/null -+++ b/patches/dwm-clientindicators-6.2.diff -@@ -0,0 +1,48 @@ -+From 8c72f9ea7c9cd8d254b52a4f7059113c41483597 Mon Sep 17 00:00:00 2001 -+From: Miles Alan <m@milesalan.com> -+Date: Mon, 17 Aug 2020 20:33:45 -0500 -+Subject: [PATCH] Draws a dot indicator overlayed on each tag icon for each -+ client. The selected client is drawn as a larger horizontal line. -+ -+--- -+ dwm.c | 14 ++++++++++---- -+ 1 file changed, 10 insertions(+), 4 deletions(-) -+ -+diff --git a/dwm.c b/dwm.c -+index 4465af1..e0ca438 100644 -+--- a/dwm.c -++++ b/dwm.c -+@@ -695,6 +695,7 @@ dirtomon(int dir) -+ void -+ drawbar(Monitor *m) -+ { -++ int indn; -+ int x, w, sw = 0; -+ int boxs = drw->fonts->h / 9; -+ int boxw = drw->fonts->h / 6 + 2; -+@@ -715,13 +716,18 @@ drawbar(Monitor *m) -+ } -+ x = 0; -+ for (i = 0; i < LENGTH(tags); i++) { -++ indn = 0; -+ w = TEXTW(tags[i]); -+ drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); -+ drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); -+- if (occ & 1 << i) -+- drw_rect(drw, x + boxs, boxs, boxw, boxw, -+- m == selmon && selmon->sel && selmon->sel->tags & 1 << i, -+- urg & 1 << i); -++ -++ for (c = m->clients; c; c = c->next) { -++ if (c->tags & (1 << i)) { -++ drw_rect(drw, x, 1 + (indn * 2), selmon->sel == c ? 6 : 1, 1, 1, urg & 1 << i); -++ indn++; -++ } -++ } -++ -+ x += w; -+ } -+ w = blw = TEXTW(m->ltsymbol); -+-- -+2.25.4 ++void ++attach(Client *c) ++{ ++ c->next = c->mon->clients; ++ c->mon->clients = c; ++} + -diff --git a/patches/dwm-dwmc-6.2.diff b/patches/dwm-dwmc-6.2.diff -new file mode 100644 -index 0000000..bf606d5 ---- /dev/null -+++ b/patches/dwm-dwmc-6.2.diff -@@ -0,0 +1,240 @@ -+From d94cb6f1a553d19127f44dbdc96e8bb5041956c2 Mon Sep 17 00:00:00 2001 -+From: Nihal Jere <noocsharp@gmail.com> -+Date: Sat, 21 Mar 2020 15:16:49 -0500 -+Subject: [PATCH] dwm-client -+ -+--- -+ Makefile | 2 +- -+ config.def.h | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++ -+ dwm.c | 55 +++++++++++++++++++++++++++++++++++++++-- -+ dwmc | 40 ++++++++++++++++++++++++++++++ -+ 4 files changed, 164 insertions(+), 3 deletions(-) -+ create mode 100755 dwmc -+ -+diff --git a/Makefile b/Makefile -+index 77bcbc0..f837f5c 100644 -+--- a/Makefile -++++ b/Makefile -+@@ -38,7 +38,7 @@ dist: clean -+ -+ install: all -+ mkdir -p ${DESTDIR}${PREFIX}/bin -+- cp -f dwm ${DESTDIR}${PREFIX}/bin -++ cp -f dwm dwmc ${DESTDIR}${PREFIX}/bin -+ chmod 755 ${DESTDIR}${PREFIX}/bin/dwm -+ mkdir -p ${DESTDIR}${MANPREFIX}/man1 -+ sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1 -+diff --git a/config.def.h b/config.def.h -+index 1c0b587..efbae79 100644 -+--- a/config.def.h -++++ b/config.def.h -+@@ -113,3 +113,73 @@ static Button buttons[] = { -+ { ClkTagBar, MODKEY, Button3, toggletag, {0} }, -+ }; -+ -++void -++setlayoutex(const Arg *arg) -++{ -++ setlayout(&((Arg) { .v = &layouts[arg->i] })); -++} -++ -++void -++viewex(const Arg *arg) -++{ -++ view(&((Arg) { .ui = 1 << arg->ui })); -++} -++ -++void -++viewall(const Arg *arg) -++{ -++ view(&((Arg){.ui = ~0})); -++} -++ -++void -++toggleviewex(const Arg *arg) -++{ -++ toggleview(&((Arg) { .ui = 1 << arg->ui })); -++} -++ -++void -++tagex(const Arg *arg) -++{ -++ tag(&((Arg) { .ui = 1 << arg->ui })); -++} -++ -++void -++toggletagex(const Arg *arg) -++{ -++ toggletag(&((Arg) { .ui = 1 << arg->ui })); -++} -++ -++void -++tagall(const Arg *arg) -++{ -++ tag(&((Arg){.ui = ~0})); -++} -++ -++/* signal definitions */ -++/* signum must be greater than 0 */ -++/* trigger signals using `xsetroot -name "fsignal:<signame> [<type> <value>]"` */ -++static Signal signals[] = { -++ /* signum function */ -++ { "focusstack", focusstack }, -++ { "setmfact", setmfact }, -++ { "togglebar", togglebar }, -++ { "incnmaster", incnmaster }, -++ { "togglefloating", togglefloating }, -++ { "focusmon", focusmon }, -++ { "tagmon", tagmon }, -++ { "zoom", zoom }, -++ { "view", view }, -++ { "viewall", viewall }, -++ { "viewex", viewex }, -++ { "toggleview", view }, -++ { "toggleviewex", toggleviewex }, -++ { "tag", tag }, -++ { "tagall", tagall }, -++ { "tagex", tagex }, -++ { "toggletag", tag }, -++ { "toggletagex", toggletagex }, -++ { "killclient", killclient }, -++ { "quit", quit }, -++ { "setlayout", setlayout }, -++ { "setlayoutex", setlayoutex }, -++}; -+diff --git a/dwm.c b/dwm.c -+index 4465af1..aa53706 100644 -+--- a/dwm.c -++++ b/dwm.c -+@@ -106,6 +106,11 @@ typedef struct { -+ const Arg arg; -+ } Key; -+ -++typedef struct { -++ const char * sig; -++ void (*func)(const Arg *); -++} Signal; -++ -+ typedef struct { -+ const char *symbol; -+ void (*arrange)(Monitor *); -+@@ -148,6 +153,7 @@ static void arrange(Monitor *m); -+ static void arrangemon(Monitor *m); -+ static void attach(Client *c); -+ static void attachstack(Client *c); -++static int fake_signal(void); -+ static void buttonpress(XEvent *e); -+ static void checkotherwm(void); -+ static void cleanup(void); -+@@ -998,6 +1004,49 @@ keypress(XEvent *e) -+ keys[i].func(&(keys[i].arg)); -+ } -+ -++int -++fake_signal(void) -++{ -++ char fsignal[256]; -++ char indicator[9] = "fsignal:"; -++ char str_sig[50]; -++ char param[16]; -++ int i, len_str_sig, n, paramn; -++ size_t len_fsignal, len_indicator = strlen(indicator); -++ Arg arg; -++ -++ // Get root name property -++ if (gettextprop(root, XA_WM_NAME, fsignal, sizeof(fsignal))) { -++ len_fsignal = strlen(fsignal); -++ -++ // Check if this is indeed a fake signal -++ if (len_indicator > len_fsignal ? 0 : strncmp(indicator, fsignal, len_indicator) == 0) { -++ paramn = sscanf(fsignal+len_indicator, "%s%n%s%n", str_sig, &len_str_sig, param, &n); -++ -++ if (paramn == 1) arg = (Arg) {0}; -++ else if (paramn > 2) return 1; -++ else if (strncmp(param, "i", n - len_str_sig) == 0) -++ sscanf(fsignal + len_indicator + n, "%i", &(arg.i)); -++ else if (strncmp(param, "ui", n - len_str_sig) == 0) -++ sscanf(fsignal + len_indicator + n, "%u", &(arg.ui)); -++ else if (strncmp(param, "f", n - len_str_sig) == 0) -++ sscanf(fsignal + len_indicator + n, "%f", &(arg.f)); -++ else return 1; -++ -++ // Check if a signal was found, and if so handle it -++ for (i = 0; i < LENGTH(signals); i++) -++ if (strncmp(str_sig, signals[i].sig, len_str_sig) == 0 && signals[i].func) -++ signals[i].func(&(arg)); -++ -++ // A fake signal was sent -++ return 1; -++ } -++ } -++ -++ // No fake signal was sent, so proceed with update -++ return 0; -++} -++ -+ void -+ killclient(const Arg *arg) -+ { -+@@ -1215,8 +1264,10 @@ propertynotify(XEvent *e) -+ Window trans; -+ XPropertyEvent *ev = &e->xproperty; -+ -+- if ((ev->window == root) && (ev->atom == XA_WM_NAME)) -+- updatestatus(); -++ if ((ev->window == root) && (ev->atom == XA_WM_NAME)) { -++ if (!fake_signal()) -++ updatestatus(); -++ } -+ else if (ev->state == PropertyDelete) -+ return; /* ignore */ -+ else if ((c = wintoclient(ev->window))) { -+diff --git a/dwmc b/dwmc -+new file mode 100755 -+index 0000000..5ff8dbc -+--- /dev/null -++++ b/dwmc -+@@ -0,0 +1,40 @@ -++#!/usr/bin/env sh -++ -++signal() { -++ xsetroot -name "fsignal:$*" -++} -++ -++case $# in -++1) -++ case $1 in -++ setlayout | view | viewall | togglebar | togglefloating | zoom | killclient | quit) -++ signal $1 -++ ;; -++ *) -++ echo "Unknown command or missing one argument." -++ exit 1 -++ ;; -++ esac -++ ;; -++2) -++ case $1 in -++ view) -++ signal $1 ui $2 -++ ;; -++ viewex | toggleviewex | tagex | toggletagex | setlayoutex | focusstack | incnmaster | focusmon | tagmon) -++ signal $1 i $2 -++ ;; -++ setmfact) -++ signal $1 f $2 -++ ;; -++ *) -++ echo "Unknown command or one too many arguments." -++ exit 1 -++ ;; -++ esac -++ ;; -++*) -++ echo "Too many arguments." -++ exit 1 -++ ;; -++esac -+-- -+2.25.1 -+ -diff --git a/patches/dwm-push_no_master-6.2.diff b/patches/dwm-push_no_master-6.2.diff -new file mode 100644 -index 0000000..873e438 ---- /dev/null -+++ b/patches/dwm-push_no_master-6.2.diff -@@ -0,0 +1,70 @@ -+diff --git a/dwm.c b/dwm.c -+index 4465af1..49e63f0 100644 -+--- a/dwm.c -++++ b/dwm.c -+@@ -185,7 +185,10 @@ 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); -+@@ -1208,6 +1211,16 @@ pop(Client *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 -+ propertynotify(XEvent *e) -+ { -+@@ -1245,6 +1258,37 @@ propertynotify(XEvent *e) -+ } -+ } -+ -++void -++pushdown(const Arg *arg) { -++ Client *sel = selmon->sel, *c; -++ -++ if(!sel || sel->isfloating || sel == nexttiled(selmon->clients)) -++ return; -++ if((c = nexttiled(sel->next))) { -++ detach(sel); -++ sel->next = c->next; -++ c->next = sel; -++ } -++ focus(sel); -++ arrange(selmon); -++} -++ -++void -++pushup(const Arg *arg) { -++ Client *sel = selmon->sel, *c; -++ -++ if(!sel || sel->isfloating) -++ return; -++ if((c = prevtiled(sel)) && c != nexttiled(selmon->clients)) { -++ detach(sel); -++ sel->next = c; -++ for(c = selmon->clients; c->next != sel->next; c = c->next); -++ c->next = sel; -++ } -++ focus(sel); -++ arrange(selmon); -++} -++ -+ void -+ quit(const Arg *arg) -+ { -diff --git a/patches/dwm-restartsig-20180523-6.2.diff b/patches/dwm-restartsig-20180523-6.2.diff -new file mode 100644 -index 0000000..f1f8680 ---- /dev/null -+++ b/patches/dwm-restartsig-20180523-6.2.diff -@@ -0,0 +1,139 @@ -+From 2991f37f0aaf44b9f9b11e7893ff0af8eb88f649 Mon Sep 17 00:00:00 2001 -+From: Christopher Drelich <cd@cdrakka.com> -+Date: Wed, 23 May 2018 22:50:38 -0400 -+Subject: [PATCH] Modifies quit to handle restarts and adds SIGHUP and SIGTERM -+ handlers. -+ -+Modified quit() to restart if it receives arg .i = 1 -+MOD+CTRL+SHIFT+Q was added to confid.def.h to do just that. -+ -+Signal handlers were handled for SIGHUP and SIGTERM. -+If dwm receives these signals it calls quit() with -+arg .i = to 1 or 0, respectively. -+ -+To restart dwm: -+MOD+CTRL+SHIFT+Q -+or -+kill -HUP dwmpid -+ -+To quit dwm cleanly: -+MOD+SHIFT+Q -+or -+kill -TERM dwmpid -+--- -+ config.def.h | 1 + -+ dwm.1 | 10 ++++++++++ -+ dwm.c | 22 ++++++++++++++++++++++ -+ 3 files changed, 33 insertions(+) -+ -+diff --git a/config.def.h b/config.def.h -+index a9ac303..e559429 100644 -+--- a/config.def.h -++++ b/config.def.h -+@@ -94,6 +94,7 @@ static Key keys[] = { -+ TAGKEYS( XK_8, 7) -+ TAGKEYS( XK_9, 8) -+ { MODKEY|ShiftMask, XK_q, quit, {0} }, -++ { MODKEY|ControlMask|ShiftMask, XK_q, quit, {1} }, -+ }; -+ -+ /* button definitions */ -+diff --git a/dwm.1 b/dwm.1 -+index 13b3729..36a331c 100644 -+--- a/dwm.1 -++++ b/dwm.1 -+@@ -142,6 +142,9 @@ Add/remove all windows with nth tag to/from the view. -+ .TP -+ .B Mod1\-Shift\-q -+ Quit dwm. -++.TP -++.B Mod1\-Control\-Shift\-q -++Restart dwm. -+ .SS Mouse commands -+ .TP -+ .B Mod1\-Button1 -+@@ -155,6 +158,13 @@ Resize focused window while dragging. Tiled windows will be toggled to the float -+ .SH CUSTOMIZATION -+ dwm is customized by creating a custom config.h and (re)compiling the source -+ code. This keeps it fast, secure and simple. -++.SH SIGNALS -++.TP -++.B SIGHUP - 1 -++Restart the dwm process. -++.TP -++.B SIGTERM - 15 -++Cleanly terminate the dwm process. -+ .SH SEE ALSO -+ .BR dmenu (1), -+ .BR st (1) -+diff --git a/dwm.c b/dwm.c -+index bb95e26..286eecd 100644 -+--- a/dwm.c -++++ b/dwm.c -+@@ -205,6 +205,8 @@ static void setup(void); -+ static void seturgent(Client *c, int urg); -+ static void showhide(Client *c); -+ static void sigchld(int unused); -++static void sighup(int unused); -++static void sigterm(int unused); -+ static void spawn(const Arg *arg); -+ static void tag(const Arg *arg); -+ static void tagmon(const Arg *arg); -+@@ -260,6 +262,7 @@ static void (*handler[LASTEvent]) (XEvent *) = { -+ [UnmapNotify] = unmapnotify -+ }; -+ static Atom wmatom[WMLast], netatom[NetLast]; -++static int restart = 0; -+ static int running = 1; -+ static Cur *cursor[CurLast]; -+ static Clr **scheme; -+@@ -1248,6 +1251,7 @@ propertynotify(XEvent *e) -+ void -+ quit(const Arg *arg) -+ { -++ if(arg->i) restart = 1; -+ running = 0; -+ } -+ -+@@ -1536,6 +1540,9 @@ setup(void) -+ /* clean up any zombies immediately */ -+ sigchld(0); -+ -++ signal(SIGHUP, sighup); -++ signal(SIGTERM, sigterm); -++ -+ /* init screen */ -+ screen = DefaultScreen(dpy); -+ sw = DisplayWidth(dpy, screen); -+@@ -1637,6 +1644,20 @@ sigchld(int unused) -+ } -+ -+ void -++sighup(int unused) -++{ -++ Arg a = {.i = 1}; -++ quit(&a); -++} -++ -++void -++sigterm(int unused) -++{ -++ Arg a = {.i = 0}; -++ quit(&a); -++} -++ -++void -+ spawn(const Arg *arg) -+ { -+ if (arg->v == dmenucmd) -+@@ -2139,6 +2160,7 @@ main(int argc, char *argv[]) -+ setup(); -+ scan(); -+ run(); -++ if(restart) execvp(argv[0], argv); -+ cleanup(); -+ XCloseDisplay(dpy); -+ return EXIT_SUCCESS; -+-- -+2.7.4 -+ -diff --git a/patches/dwm-statuscmd-signal-6.2.diff b/patches/dwm-statuscmd-signal-6.2.diff ++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; ++ do ++ 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 - (int)TEXTW(stext)) ++ click = ClkStatusText; ++ else ++ click = ClkWinTitle; ++ } else if ((c = wintoclient(ev->window))) { ++ focus(c); ++ restack(selmon); ++ XAllowEvents(dpy, ReplayPointer, CurrentTime); ++ 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 < LENGTH(colors); i++) ++ free(scheme[i]); ++ XDestroyWindow(dpy, wmcheckwin); ++ 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 ++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 (c != selmon->sel && !c->isurgent) ++ seturgent(c, 1); ++ } ++} ++ ++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; ++ Client *c; ++ 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) { ++ 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); ++ 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, w, tw = 0; ++ int boxs = drw->fonts->h / 9; ++ int boxw = drw->fonts->h / 6 + 2; ++ unsigned int i, occ = 0, urg = 0; ++ Client *c; ++ ++ /* 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]); ++ 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) { ++ occ |= c->tags; ++ if (c->isurgent) ++ urg |= c->tags; ++ } ++ x = 0; ++ for (i = 0; i < LENGTH(tags); i++) { ++ w = TEXTW(tags[i]); ++ drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); ++ drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); ++ if (occ & 1 << i) ++ drw_rect(drw, x + boxs, boxs, boxw, boxw, ++ m == selmon && selmon->sel && selmon->sel->tags & 1 << i, ++ urg & 1 << i); ++ x += w; ++ } ++ w = blw = TEXTW(m->ltsymbol); ++ drw_setscheme(drw, scheme[SchemeNorm]); ++ x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); ++ ++ 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); ++ if (m->sel->isfloating) ++ drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0); ++ } else { ++ drw_setscheme(drw, scheme[SchemeNorm]); ++ drw_rect(drw, x, 0, w, bh, 1, 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); ++ if (selmon->sel && selmon->sel != c) ++ unfocus(selmon->sel, 0); ++ if (c) { ++ if (c->mon != selmon) ++ selmon = c->mon; ++ if (c->isurgent) ++ seturgent(c, 0); ++ detachstack(c); ++ attachstack(c); ++ grabbuttons(c, 1); ++ XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel); ++ setfocus(c); ++ } else { ++ XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); ++ XDeleteProperty(dpy, root, netatom[NetActiveWindow]); ++ } ++ selmon->sel = c; ++ drawbars(); ++} ++ ++/* there are some broken focus acquiring clients needing extra handling */ ++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); ++ 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'; ++ if (!XGetTextProperty(dpy, w, &name, atom) || !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) ++ XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, ++ BUTTONMASK, GrabModeSync, GrabModeSync, None, None); ++ 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); ++ } ++} ++ ++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; ++ /* 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; ++ ++ updatetitle(c); ++ if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { ++ c->mon = t->mon; ++ c->tags = t->tags; ++ } else { ++ c->mon = selmon; ++ applyrules(c); ++ } ++ ++ 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][ColBorder].pixel); ++ 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 (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; ++ ++ c->oldx = c->x; c->x = wc.x = x; ++ c->oldy = c->y; c->y = wc.y = y; ++ c->oldw = c->w; c->w = wc.width = w; ++ c->oldh = c->h; c->h = wc.height = h; ++ wc.border_width = c->bw; ++ 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 absolutely */ ++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.05 || f > 0.95) ++ return; ++ selmon->mfact = f; ++ arrange(selmon); ++} ++ ++void ++setup(void) ++{ ++ int i; ++ XSetWindowAttributes wa; ++ Atom utf8string; ++ ++ /* 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); ++ if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) ++ die("no fonts could be loaded."); ++ lrpad = drw->fonts->h; ++ bh = drw->fonts->h + 2; ++ updategeom(); ++ /* init atoms */ ++ utf8string = XInternAtom(dpy, "UTF8_STRING", False); ++ 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[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", 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 = ecalloc(LENGTH(colors), sizeof(Clr *)); ++ for (i = 0; i < LENGTH(colors); i++) ++ scheme[i] = drw_scm_create(drw, colors[i], 3); ++ /* init bars */ ++ updatebars(); ++ updatestatus(); ++ /* supporting window for NetWMCheck */ ++ wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0); ++ XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW, 32, ++ PropModeReplace, (unsigned char *) &wmcheckwin, 1); ++ XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8, ++ PropModeReplace, (unsigned char *) "dwm", 3); ++ XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32, ++ PropModeReplace, (unsigned char *) &wmcheckwin, 1); ++ /* EWMH support per view */ ++ XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, ++ PropModeReplace, (unsigned char *) netatom, NetLast); ++ XDeleteProperty(dpy, root, netatom[NetClientList]); ++ /* select 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 ++seturgent(Client *c, int urg) ++{ ++ XWMHints *wmh; ++ ++ c->isurgent = urg; ++ if (!(wmh = XGetWMHints(dpy, c->win))) ++ return; ++ wmh->flags = urg ? (wmh->flags | XUrgencyHint) : (wmh->flags & ~XUrgencyHint); ++ XSetWMHints(dpy, c->win, wmh); ++ XFree(wmh); ++} ++ ++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); ++ 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); ++ if (ty + HEIGHT(c) < m->wh) ++ 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][ColBorder].pixel); ++ if (setfocus) { ++ XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); ++ XDeleteProperty(dpy, root, netatom[NetActiveWindow]); ++ } ++} ++ ++void ++unmanage(Client *c, int destroyed) ++{ ++ Monitor *m = c->mon; ++ XWindowChanges wc; ++ ++ detach(c); ++ detachstack(c); ++ if (!destroyed) { ++ wc.border_width = c->oldbw; ++ XGrabServer(dpy); /* avoid race conditions */ ++ 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 ++ }; ++ XClassHint ch = {"dwm", "dwm"}; ++ 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); ++ XSetClassHint(dpy, m->barwin, &ch); ++ } ++} ++ ++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) { /* new monitors available */ ++ for (i = 0; i < (nn - n); i++) { ++ 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 ((c = m->clients)) { ++ dirty = 1; ++ 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->maxh && c->maxw == c->minw && c->maxh == c->minh); ++} ++ ++void ++updatestatus(void) ++{ ++ if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) ++ strcpy(stext, "dwm-"VERSION); ++ drawbar(selmon); ++} ++ ++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 ++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"); ++ 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); ++ else if (argc != 1) ++ die("usage: dwm [-v]"); ++ if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) ++ fputs("warning: no locale support\n", stderr); ++ if (!(dpy = XOpenDisplay(NULL))) ++ die("dwm: cannot open display"); ++ checkotherwm(); ++ setup(); ++#ifdef __OpenBSD__ ++ if (pledge("stdio rpath proc exec", NULL) == -1) ++ die("pledge"); ++#endif /* __OpenBSD__ */ ++ scan(); ++ run(); ++ cleanup(); ++ XCloseDisplay(dpy); ++ return EXIT_SUCCESS; ++} +diff --git a/dwm.c.rej b/dwm.c.rej new file mode 100644 -index 0000000..97fda1b +index 0000000..079df04 --- /dev/null -+++ b/patches/dwm-statuscmd-signal-6.2.diff -@@ -0,0 +1,157 @@ -+diff --git a/config.def.h b/config.def.h -+index 1c0b587..b67825e 100644 -+--- a/config.def.h -++++ b/config.def.h -+@@ -103,7 +103,9 @@ static Button buttons[] = { -+ { ClkLtSymbol, 0, Button1, setlayout, {0} }, -+ { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, -+ { ClkWinTitle, 0, Button2, zoom, {0} }, -+- { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, -++ { ClkStatusText, 0, Button1, sigdwmblocks, {.i = 1} }, -++ { ClkStatusText, 0, Button2, sigdwmblocks, {.i = 2} }, -++ { ClkStatusText, 0, Button3, sigdwmblocks, {.i = 3} }, -+ { ClkClientWin, MODKEY, Button1, movemouse, {0} }, -+ { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, -+ { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, -+diff --git a/dwm.c b/dwm.c -+index 4465af1..c600131 100644 -+--- a/dwm.c -++++ b/dwm.c -+@@ -156,6 +156,7 @@ static void clientmessage(XEvent *e); -+ static void configure(Client *c); -+ static void configurenotify(XEvent *e); -+ static void configurerequest(XEvent *e); -++static void copyvalidchars(char *text, char *rawtext); -+ static Monitor *createmon(void); -+ static void destroynotify(XEvent *e); -+ static void detach(Client *c); -+@@ -169,6 +170,7 @@ static void focus(Client *c); ++++ b/dwm.c.rej +@@ -0,0 +1,124 @@ ++--- dwm.c +++++ dwm.c ++@@ -205,12 +245,16 @@ 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 int getdwmblockspid(); +++static Atom getatomprop(Client *c, Atom prop); + static int getrootptr(int *x, int *y); + static long getstate(Window w); +++static unsigned int getsystraywidth(); + static int gettextprop(Window w, Atom atom, char *text, unsigned int size); -+@@ -205,6 +207,7 @@ static void setup(void); -+ static void seturgent(Client *c, int urg); -+ static void showhide(Client *c); -+ static void sigchld(int unused); -++static void sigdwmblocks(const Arg *arg); -+ static void spawn(const Arg *arg); -+ static void tag(const Arg *arg); -+ static void tagmon(const Arg *arg); -+@@ -237,6 +240,9 @@ static void zoom(const Arg *arg); -+ /* variables */ -+ static const char broken[] = "broken"; -+ static char stext[256]; -++static char rawstext[256]; -++static int dwmblockssig; -++pid_t dwmblockspid = 0; -+ static int screen; -+ static int sw, sh; /* X display screen geometry width, height */ -+ static int bh, blw = 0; /* bar geometry */ -+@@ -439,9 +445,26 @@ buttonpress(XEvent *e) ++ static void grabbuttons(Client *c, int focused); ++ static void grabkeys(void); ++@@ -590,9 +745,25 @@ 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 > (x = selmon->ww - TEXTW(stext) + lrpad)) { +++ else if (ev->x > (x = selmon->ww - TEXTW(stext) + lrpad - getsystraywidth())) { + click = ClkStatusText; +- else -++ -++ char *text = rawstext; -++ int i = -1; -++ char ch; -++ dwmblockssig = 0; +++ char *text = rawstext; +++ int i = -1; +++ char ch; +++ dwmblockssig = 0; ++ while (text[++i]) { ++ if ((unsigned char)text[i] < ' ') { ++ ch = text[i]; @@ -3433,779 +4570,24 @@ index 0000000..97fda1b ++ dwmblockssig = ch; ++ } ++ } -++ } else +++ } else + click = ClkWinTitle; + } else if ((c = wintoclient(ev->window))) { + focus(c); -+@@ -627,6 +650,19 @@ configurerequest(XEvent *e) -+ XSync(dpy, False); -+ } -+ -++void -++copyvalidchars(char *text, char *rawtext) -++{ -++ int i = -1, j = 0; -++ -++ while(rawtext[++i]) { -++ if ((unsigned char)rawtext[i] >= ' ') { -++ text[j++] = rawtext[i]; -++ } -++ } -++ text[j] = '\0'; -++} -++ -+ Monitor * -+ createmon(void) -+ { -+@@ -871,6 +907,18 @@ getatomprop(Client *c, Atom prop) -+ return atom; -+ } -+ -++int -++getdwmblockspid() -++{ -++ char buf[16]; -++ FILE *fp = popen("pidof -s dwmblocks", "r"); -++ fgets(buf, sizeof(buf), fp); -++ pid_t pid = strtoul(buf, NULL, 10); -++ pclose(fp); -++ dwmblockspid = pid; -++ return pid != 0 ? 0 : -1; -++} -++ -+ int -+ getrootptr(int *x, int *y) -+ { -+@@ -1636,6 +1684,23 @@ sigchld(int unused) -+ while (0 < waitpid(-1, NULL, WNOHANG)); -+ } -+ -++void -++sigdwmblocks(const Arg *arg) -++{ -++ union sigval sv; -++ sv.sival_int = (dwmblockssig << 8) | arg->i; -++ if (!dwmblockspid) -++ if (getdwmblockspid() == -1) -++ return; -++ -++ if (sigqueue(dwmblockspid, SIGUSR1, sv) == -1) { -++ if (errno == ESRCH) { -++ if (!getdwmblockspid()) -++ sigqueue(dwmblockspid, SIGUSR1, sv); -++ } -++ } -++} -++ -+ void -+ spawn(const Arg *arg) -+ { -+@@ -1987,8 +2052,10 @@ updatesizehints(Client *c) -+ void -+ updatestatus(void) -+ { -+- if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) -++ if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext))) -+ strcpy(stext, "dwm-"VERSION); -++ else -++ copyvalidchars(stext, rawstext); -+ drawbar(selmon); -+ } -+ -diff --git a/patches/dwm-swallow-20200522-7accbcf.diff b/patches/dwm-swallow-20200522-7accbcf.diff -new file mode 100644 -index 0000000..1cb144f ---- /dev/null -+++ b/patches/dwm-swallow-20200522-7accbcf.diff -@@ -0,0 +1,420 @@ -+From 7accbcf7db35995d4c26c5cd69338aafa6feb89a Mon Sep 17 00:00:00 2001 -+From: wtl <wtl144000@gmail.com> -+Date: Fri, 22 May 2020 22:38:38 +0300 -+Subject: [PATCH] swallow X windows from the terminal -+ -+--- -+ config.def.h | 9 ++- -+ config.mk | 2 +- -+ dwm.c | 218 +++++++++++++++++++++++++++++++++++++++++++++++++-- -+ 3 files changed, 220 insertions(+), 9 deletions(-) -+ -+diff --git a/config.def.h b/config.def.h -+index 1c0b587..4c0b25c 100644 -+--- a/config.def.h -++++ b/config.def.h -+@@ -3,6 +3,7 @@ -+ /* appearance */ -+ static const unsigned int borderpx = 1; /* border pixel of windows */ -+ static const unsigned int snap = 32; /* snap pixel */ -++static const int swallowfloating = 0; /* 1 means swallow floating windows by default */ -+ static const int showbar = 1; /* 0 means no bar */ -+ static const int topbar = 1; /* 0 means bottom bar */ -+ static const char *fonts[] = { "monospace:size=10" }; -+@@ -26,9 +27,11 @@ static const Rule rules[] = { -+ * WM_CLASS(STRING) = instance, class -+ * WM_NAME(STRING) = title -+ */ -+- /* class instance title tags mask isfloating monitor */ -+- { "Gimp", NULL, NULL, 0, 1, -1 }, -+- { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, -++ /* class instance title tags mask isfloating isterminal noswallow monitor */ -++ { "Gimp", NULL, NULL, 0, 1, 0, 0, -1 }, -++ { "Firefox", NULL, NULL, 1 << 8, 0, 0, -1, -1 }, -++ { "st", NULL, NULL, 0, 0, 1, -1, -1 }, -++ { NULL, NULL, "Event Tester", 0, 1, 0, 1, -1 }, /* xev */ -+ }; -+ -+ /* layout(s) */ -+diff --git a/config.mk b/config.mk -+index 7084c33..b77641d 100644 -+--- a/config.mk -++++ b/config.mk -+@@ -22,7 +22,7 @@ FREETYPEINC = /usr/include/freetype2 -+ -+ # includes and libs -+ INCS = -I${X11INC} -I${FREETYPEINC} -+-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -++LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lX11-xcb -lxcb -lxcb-res -+ -+ # flags -+ CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} -+diff --git a/dwm.c b/dwm.c -+index 9fd0286..1befee4 100644 -+--- a/dwm.c -++++ b/dwm.c -+@@ -40,6 +40,8 @@ -+ #include <X11/extensions/Xinerama.h> -+ #endif /* XINERAMA */ -+ #include <X11/Xft/Xft.h> -++#include <X11/Xlib-xcb.h> -++#include <xcb/res.h> -+ -+ #include "drw.h" -+ #include "util.h" -+@@ -92,9 +94,11 @@ struct Client { -+ int basew, baseh, incw, inch, maxw, maxh, minw, minh; -+ int bw, oldbw; -+ unsigned int tags; -+- int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; -++ int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow; -++ pid_t pid; -+ Client *next; -+ Client *snext; -++ Client *swallowing; -+ Monitor *mon; -+ Window win; -+ }; -+@@ -138,6 +142,8 @@ typedef struct { -+ const char *title; -+ unsigned int tags; -+ int isfloating; -++ int isterminal; -++ int noswallow; -+ int monitor; -+ } Rule; -+ -+@@ -235,9 +241,16 @@ static int xerrordummy(Display *dpy, XErrorEvent *ee); -+ static int xerrorstart(Display *dpy, XErrorEvent *ee); -+ static void zoom(const Arg *arg); -+ -++static pid_t getparentprocess(pid_t p); -++static int isdescprocess(pid_t p, pid_t c); -++static Client *swallowingclient(Window w); -++static Client *termforwin(const Client *c); -++static pid_t winpid(Window w); -++ -+ /* variables */ -+ static const char broken[] = "broken"; -+ static char stext[256]; -++static int scanner; -+ static int screen; -+ static int sw, sh; /* X display screen geometry width, height */ -+ static int bh, blw = 0; /* bar geometry */ -+@@ -269,6 +282,8 @@ static Drw *drw; -+ static Monitor *mons, *selmon; -+ static Window root, wmcheckwin; -+ -++static xcb_connection_t *xcon; -++ -+ /* configuration, allows nested code to access above variables */ -+ #include "config.h" -+ -+@@ -286,6 +301,7 @@ applyrules(Client *c) -+ XClassHint ch = { NULL, NULL }; -+ -+ /* rule matching */ -++ c->noswallow = -1; -+ c->isfloating = 0; -+ c->tags = 0; -+ XGetClassHint(dpy, c->win, &ch); -+@@ -298,6 +314,8 @@ applyrules(Client *c) -+ && (!r->class || strstr(class, r->class)) -+ && (!r->instance || strstr(instance, r->instance))) -+ { -++ c->isterminal = r->isterminal; -++ c->noswallow = r->noswallow; -+ c->isfloating = r->isfloating; -+ c->tags |= r->tags; -+ for (m = mons; m && m->num != r->monitor; m = m->next); -+@@ -414,6 +432,61 @@ attachstack(Client *c) -+ c->mon->stack = c; -+ } -+ -++void -++swallow(Client *p, Client *c) -++{ -++ Client *s; -++ -++ if (c->noswallow > 0 || c->isterminal) -++ return; -++ if (c->noswallow < 0 && !swallowfloating && c->isfloating) -++ return; -++ -++ detach(c); -++ detachstack(c); -++ -++ setclientstate(c, WithdrawnState); -++ XUnmapWindow(dpy, p->win); -++ -++ p->swallowing = c; -++ c->mon = p->mon; -++ -++ Window w = p->win; -++ p->win = c->win; -++ c->win = w; -++ -++ XChangeProperty(dpy, c->win, netatom[NetClientList], XA_WINDOW, 32, PropModeReplace, -++ (unsigned char *) &(p->win), 1); -++ -++ updatetitle(p); -++ s = scanner ? c : p; -++ XMoveResizeWindow(dpy, p->win, s->x, s->y, s->w, s->h); -++ arrange(p->mon); -++ configure(p); -++ updateclientlist(); -++} -++ -++void -++unswallow(Client *c) -++{ -++ c->win = c->swallowing->win; -++ -++ free(c->swallowing); -++ c->swallowing = NULL; -++ -++ XDeleteProperty(dpy, c->win, netatom[NetClientList]); -++ -++ /* unfullscreen the client */ -++ setfullscreen(c, 0); -++ updatetitle(c); -++ arrange(c->mon); -++ XMapWindow(dpy, c->win); -++ XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); -++ setclientstate(c, NormalState); -++ focus(NULL); -++ arrange(c->mon); -++} -++ -+ void -+ buttonpress(XEvent *e) -+ { -+@@ -653,6 +726,9 @@ destroynotify(XEvent *e) -+ -+ if ((c = wintoclient(ev->window))) -+ unmanage(c, 1); -++ -++ else if ((c = swallowingclient(ev->window))) -++ unmanage(c->swallowing, 1); -+ } -+ -+ void -+@@ -1018,12 +1094,13 @@ killclient(const Arg *arg) -+ void -+ manage(Window w, XWindowAttributes *wa) -+ { -+- Client *c, *t = NULL; -++ Client *c, *t = NULL, *term = NULL; -+ Window trans = None; -+ XWindowChanges wc; -+ -+ c = ecalloc(1, sizeof(Client)); -+ c->win = w; -++ c->pid = winpid(w); -+ /* geometry */ -+ c->x = c->oldx = wa->x; -+ c->y = c->oldy = wa->y; -+@@ -1038,6 +1115,7 @@ manage(Window w, XWindowAttributes *wa) -+ } else { -+ c->mon = selmon; -+ applyrules(c); -++ term = termforwin(c); -+ } -+ -+ if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw) -+@@ -1074,6 +1152,8 @@ manage(Window w, XWindowAttributes *wa) -+ c->mon->sel = c; -+ arrange(c->mon); -+ XMapWindow(dpy, c->win); -++ if (term) -++ swallow(term, c); -+ focus(NULL); -+ } -+ -+@@ -1384,7 +1464,9 @@ run(void) -+ void -+ scan(void) -+ { -++ scanner = 1; -+ unsigned int i, num; -++ char swin[256]; -+ Window d1, d2, *wins = NULL; -+ XWindowAttributes wa; -+ -+@@ -1395,6 +1477,8 @@ scan(void) -+ continue; -+ if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) -+ manage(wins[i], &wa); -++ else if (gettextprop(wins[i], netatom[NetClientList], swin, sizeof swin)) -++ manage(wins[i], &wa); -+ } -+ for (i = 0; i < num; i++) { /* now the transients */ -+ if (!XGetWindowAttributes(dpy, wins[i], &wa)) -+@@ -1406,6 +1490,7 @@ scan(void) -+ if (wins) -+ XFree(wins); -+ } -++ scanner = 0; -+ } -+ -+ void -+@@ -1768,6 +1853,20 @@ unmanage(Client *c, int destroyed) -+ Monitor *m = c->mon; -+ XWindowChanges wc; -+ -++ if (c->swallowing) { -++ unswallow(c); -++ return; -++ } -++ -++ Client *s = swallowingclient(c->win); -++ if (s) { -++ free(s->swallowing); -++ s->swallowing = NULL; -++ arrange(m); -++ focus(NULL); -++ return; -++ } -++ -+ detach(c); -+ detachstack(c); -+ if (!destroyed) { -+@@ -1782,9 +1881,12 @@ unmanage(Client *c, int destroyed) -+ XUngrabServer(dpy); -+ } -+ free(c); -+- focus(NULL); -+- updateclientlist(); -+- arrange(m); -++ -++ if (!s) { -++ arrange(m); -++ focus(NULL); -++ updateclientlist(); -++ } -+ } -+ -+ void -+@@ -2047,6 +2149,110 @@ view(const Arg *arg) -+ arrange(selmon); -+ } -+ -++pid_t -++winpid(Window w) -++{ -++ pid_t result = 0; -++ -++ xcb_res_client_id_spec_t spec = {0}; -++ spec.client = w; -++ spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID; -++ -++ xcb_generic_error_t *e = NULL; -++ xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec); -++ xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e); -++ -++ if (!r) -++ return (pid_t)0; -++ -++ xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r); -++ for (; i.rem; xcb_res_client_id_value_next(&i)) { -++ spec = i.data->spec; -++ if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) { -++ uint32_t *t = xcb_res_client_id_value_value(i.data); -++ result = *t; -++ break; -++ } -++ } -++ -++ free(r); -++ -++ if (result == (pid_t)-1) -++ result = 0; -++ return result; -++} -++ -++pid_t -++getparentprocess(pid_t p) -++{ -++ unsigned int v = 0; -++ -++#if defined(__linux__) -++ FILE *f; -++ char buf[256]; -++ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p); -++ -++ if (!(f = fopen(buf, "r"))) -++ return (pid_t)0; -++ -++ if (fscanf(f, "%*u %*s %*c %u", (unsigned *)&v) != 1) -++ v = (pid_t)0; -++ fclose(f); -++#elif defined(__FreeBSD__) -++ struct kinfo_proc *proc = kinfo_getproc(p); -++ if (!proc) -++ return (pid_t)0; -++ -++ v = proc->ki_ppid; -++ free(proc); -++#endif -++ return (pid_t)v; -++} -++ -++int -++isdescprocess(pid_t p, pid_t c) -++{ -++ while (p != c && c != 0) -++ c = getparentprocess(c); -++ -++ return (int)c; -++} -++ -++Client * -++termforwin(const Client *w) -++{ -++ Client *c; -++ Monitor *m; -++ -++ if (!w->pid || w->isterminal) -++ return NULL; -++ -++ for (m = mons; m; m = m->next) { -++ for (c = m->clients; c; c = c->next) { -++ if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid)) -++ return c; -++ } -++ } -++ -++ return NULL; -++} -++ -++Client * -++swallowingclient(Window w) -++{ -++ Client *c; -++ Monitor *m; -++ -++ for (m = mons; m; m = m->next) { -++ for (c = m->clients; c; c = c->next) { -++ if (c->swallowing && c->swallowing->win == w) -++ return c; -++ } -++ } -++ -++ return NULL; -++} -++ -+ Client * -+ wintoclient(Window w) -+ { -+@@ -2138,6 +2344,8 @@ main(int argc, char *argv[]) -+ fputs("warning: no locale support\n", stderr); -+ if (!(dpy = XOpenDisplay(NULL))) -+ die("dwm: cannot open display"); -++ if (!(xcon = XGetXCBConnection(dpy))) -++ die("dwm: cannot get xcb connection\n"); -+ checkotherwm(); -+ setup(); -+ #ifdef __OpenBSD__ -+-- -+2.26.2 -+ -diff --git a/patches/dwm-systray-6.2.diff b/patches/dwm-systray-6.2.diff -new file mode 100644 -index 0000000..27187ac ---- /dev/null -+++ b/patches/dwm-systray-6.2.diff -@@ -0,0 +1,746 @@ -+From 4001ccae7b1a41bdcb247b0cf095a51af7b68c28 Mon Sep 17 00:00:00 2001 -+From: Igor Gevka <igor.gevka@gmail.com> -+Date: Sun, 16 Feb 2020 15:03:10 -0800 -+Subject: [PATCH] [PATCH] Implements a system tray for dwm. -+ -+Original author: Jan Christoph Ebersbach <jceb@e-jc.de>, inspired by http://code.google.com/p/dwm-plus -+URL: http://dwm.suckless.org/patches/systray -+dwm 6.2 port by Igor Gevka <igor.gevka@gmail.com> -+--- -+ config.def.h | 4 + -+ dwm.c | 404 +++++++++++++++++++++++++++++++++++++++++++++++---- -+ 2 files changed, 382 insertions(+), 26 deletions(-) -+ -+diff --git a/config.def.h b/config.def.h -+index 1c0b587..2d824d1 100644 -+--- a/config.def.h -++++ b/config.def.h -+@@ -3,6 +3,10 @@ -+ /* appearance */ -+ static const unsigned int borderpx = 1; /* border pixel of windows */ -+ static const unsigned int snap = 32; /* snap pixel */ -++static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ -++static const unsigned int systrayspacing = 2; /* systray spacing */ -++static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/ -++static const int showsystray = 1; /* 0 means no systray */ -+ static const int showbar = 1; /* 0 means no bar */ -+ static const int topbar = 1; /* 0 means bottom bar */ -+ static const char *fonts[] = { "monospace:size=10" }; -+diff --git a/dwm.c b/dwm.c -+index 4465af1..3e361fa 100644 -+--- a/dwm.c -++++ b/dwm.c -+@@ -57,12 +57,30 @@ -+ #define TAGMASK ((1 << LENGTH(tags)) - 1) -+ #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) -+ -++#define SYSTEM_TRAY_REQUEST_DOCK 0 -++ -++/* XEMBED messages */ -++#define XEMBED_EMBEDDED_NOTIFY 0 -++#define XEMBED_WINDOW_ACTIVATE 1 -++#define XEMBED_FOCUS_IN 4 -++#define XEMBED_MODALITY_ON 10 -++ -++#define XEMBED_MAPPED (1 << 0) -++#define XEMBED_WINDOW_ACTIVATE 1 -++#define XEMBED_WINDOW_DEACTIVATE 2 -++ -++#define VERSION_MAJOR 0 -++#define VERSION_MINOR 0 -++#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR -++ -+ /* enums */ -+ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ -+ enum { SchemeNorm, SchemeSel }; /* color schemes */ -+ enum { NetSupported, NetWMName, NetWMState, NetWMCheck, -++ NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz, -+ NetWMFullscreen, NetActiveWindow, NetWMWindowType, -+ NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ -++enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */ -+ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ -+ enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, -+ ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ -+@@ -141,6 +159,12 @@ typedef struct { -+ int monitor; -+ } Rule; -+ -++typedef struct Systray Systray; -++struct Systray { -++ Window win; -++ Client *icons; -++}; -++ -+ /* function declarations */ -+ static void applyrules(Client *c); -+ static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); -+@@ -169,8 +193,10 @@ 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 unsigned int getsystraywidth(); -+ static int gettextprop(Window w, Atom atom, char *text, unsigned int size); -+ static void grabbuttons(Client *c, int focused); -+ static void grabkeys(void); -+@@ -188,13 +214,16 @@ 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 removesystrayicon(Client *i); -+ static void resize(Client *c, int x, int y, int w, int h, int interact); -++static void resizebarwin(Monitor *m); -+ static void resizeclient(Client *c, int x, int y, int w, int h); -+ static void resizemouse(const Arg *arg); -++static void resizerequest(XEvent *e); -+ static void restack(Monitor *m); -+ static void run(void); -+ static void scan(void); -+-static int sendevent(Client *c, Atom proto); -++static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4); -+ static void sendmon(Client *c, Monitor *m); -+ static void setclientstate(Client *c, long state); -+ static void setfocus(Client *c); -+@@ -206,6 +235,7 @@ static void seturgent(Client *c, int urg); -+ static void showhide(Client *c); -+ static void sigchld(int unused); -+ static void spawn(const Arg *arg); -++static Monitor *systraytomon(Monitor *m); -+ static void tag(const Arg *arg); -+ static void tagmon(const Arg *arg); -+ static void tile(Monitor *); -+@@ -223,18 +253,23 @@ static int updategeom(void); -+ static void updatenumlockmask(void); -+ static void updatesizehints(Client *c); -+ static void updatestatus(void); -++static void updatesystray(void); -++static void updatesystrayicongeom(Client *i, int w, int h); -++static void updatesystrayiconstate(Client *i, XPropertyEvent *ev); -+ static void updatetitle(Client *c); -+ static void updatewindowtype(Client *c); -+ static void updatewmhints(Client *c); -+ static void view(const Arg *arg); -+ static Client *wintoclient(Window w); -+ static Monitor *wintomon(Window w); -++static Client *wintosystrayicon(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 Systray *systray = NULL; -+ static const char broken[] = "broken"; -+ static char stext[256]; -+ static int screen; -+@@ -257,9 +292,10 @@ static void (*handler[LASTEvent]) (XEvent *) = { -+ [MapRequest] = maprequest, -+ [MotionNotify] = motionnotify, -+ [PropertyNotify] = propertynotify, -++ [ResizeRequest] = resizerequest, -+ [UnmapNotify] = unmapnotify -+ }; -+-static Atom wmatom[WMLast], netatom[NetLast]; -++static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast]; -+ static int running = 1; -+ static Cur *cursor[CurLast]; -+ static Clr **scheme; -+@@ -439,7 +475,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 - TEXTW(stext) - getsystraywidth()) -+ click = ClkStatusText; -+ else -+ click = ClkWinTitle; -+@@ -482,6 +518,11 @@ cleanup(void) -+ XUngrabKey(dpy, AnyKey, AnyModifier, root); -+ while (mons) -+ cleanupmon(mons); -++ if (showsystray) { -++ XUnmapWindow(dpy, systray->win); -++ XDestroyWindow(dpy, systray->win); -++ free(systray); -++ } -+ for (i = 0; i < CurLast; i++) -+ drw_cur_free(drw, cursor[i]); -+ for (i = 0; i < LENGTH(colors); i++) -+@@ -512,9 +553,57 @@ cleanupmon(Monitor *mon) -+ void -+ clientmessage(XEvent *e) -+ { -++ XWindowAttributes wa; -++ XSetWindowAttributes swa; -+ XClientMessageEvent *cme = &e->xclient; -+ Client *c = wintoclient(cme->window); -+ -++ if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) { -++ /* add systray icons */ -++ if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { -++ if (!(c = (Client *)calloc(1, sizeof(Client)))) -++ die("fatal: could not malloc() %u bytes\n", sizeof(Client)); -++ if (!(c->win = cme->data.l[2])) { -++ free(c); -++ return; -++ } -++ c->mon = selmon; -++ c->next = systray->icons; -++ systray->icons = c; -++ if (!XGetWindowAttributes(dpy, c->win, &wa)) { -++ /* use sane defaults */ -++ wa.width = bh; -++ wa.height = bh; -++ wa.border_width = 0; -++ } -++ c->x = c->oldx = c->y = c->oldy = 0; -++ c->w = c->oldw = wa.width; -++ c->h = c->oldh = wa.height; -++ c->oldbw = wa.border_width; -++ c->bw = 0; -++ c->isfloating = True; -++ /* reuse tags field as mapped status */ -++ c->tags = 1; -++ updatesizehints(c); -++ updatesystrayicongeom(c, wa.width, wa.height); -++ XAddToSaveSet(dpy, c->win); -++ XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); -++ XReparentWindow(dpy, c->win, systray->win, 0, 0); -++ /* use parents background color */ -++ swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; -++ XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa); -++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION); -++ /* FIXME not sure if I have to send these events, too */ -++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION); -++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION); -++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION); -++ XSync(dpy, False); -++ resizebarwin(selmon); -++ updatesystray(); -++ setclientstate(c, NormalState); -++ } -++ return; -++ } -+ if (!c) -+ return; -+ if (cme->message_type == netatom[NetWMState]) { -+@@ -567,7 +656,7 @@ configurenotify(XEvent *e) -+ 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); -++ resizebarwin(m); -+ } -+ focus(NULL); -+ arrange(NULL); -+@@ -652,6 +741,11 @@ destroynotify(XEvent *e) -+ -+ if ((c = wintoclient(ev->window))) -+ unmanage(c, 1); -++ else if ((c = wintosystrayicon(ev->window))) { -++ removesystrayicon(c); -++ resizebarwin(selmon); -++ updatesystray(); -++ } -+ } -+ -+ void -+@@ -695,19 +789,23 @@ dirtomon(int dir) ++@@ -921,19 +1167,24 @@ dirtomon(int dir) + void + drawbar(Monitor *m) + { +- int x, w, sw = 0; +++ int indn; ++ int x, w, sw = 0, stw = 0; + int boxs = drw->fonts->h / 9; + int boxw = drw->fonts->h / 6 + 2; + unsigned int i, occ = 0, urg = 0; + Client *c; + -++ if(showsystray && m == systraytomon(m)) -++ stw = getsystraywidth(); +++ if(showsystray && m == systraytomon(m)) +++ stw = getsystraywidth(); ++ + /* draw status first so it can be overdrawn by tags later */ + if (m == selmon) { /* status is only drawn on selected monitor */ @@ -4216,11 +4598,33 @@ index 0000000..27187ac ++ drw_text(drw, m->ww - sw - stw, 0, sw, bh, lrpad / 2 - 2, stext, 0); + } + -++ resizebarwin(m); +++ resizebarwin(m); + for (c = m->clients; c; c = c->next) { + occ |= c->tags; + if (c->isurgent) -+@@ -728,7 +826,7 @@ drawbar(Monitor *m) ++@@ -941,20 +1192,25 @@ drawbar(Monitor *m) ++ } ++ x = 0; ++ for (i = 0; i < LENGTH(tags); i++) { +++ indn = 0; ++ w = TEXTW(tags[i]); ++ drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); ++ drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); ++- if (occ & 1 << i) ++- drw_rect(drw, x + boxs, boxs, boxw, boxw, ++- m == selmon && selmon->sel && selmon->sel->tags & 1 << i, ++- urg & 1 << i); +++ +++ for (c = m->clients; c; c = c->next) { +++ if (c->tags & (1 << i)) { +++ drw_rect(drw, x, 1 + (indn * 2), selmon->sel == c ? 6 : 1, 1, 1, urg & 1 << i); +++ indn++; +++ } +++ } +++ ++ x += w; ++ } ++ w = blw = TEXTW(m->ltsymbol); + drw_setscheme(drw, scheme[SchemeNorm]); + x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); + @@ -4229,662 +4633,101 @@ index 0000000..27187ac + if (m->sel) { + drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); -+@@ -739,7 +837,7 @@ drawbar(Monitor *m) -+ drw_rect(drw, x, 0, w, bh, 1, 1); ++@@ -2216,13 +2776,15 @@ tile(Monitor *m) ++ 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); +++ h = (m->wh - my) * (c->cfact / mfacts); ++ resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); ++ my += HEIGHT(c); +++ mfacts -= c->cfact; ++ } else { ++- h = (m->wh - ty) / (n - i); +++ h = (m->wh - ty) * (c->cfact / sfacts); ++ resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0); ++ ty += HEIGHT(c); +++ sfacts -= c->cfact; + } -+ } -+- drw_map(drw, m->barwin, 0, 0, m->ww, bh); -++ drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh); + } + -+ void -+@@ -776,8 +874,11 @@ expose(XEvent *e) -+ Monitor *m; -+ XExposeEvent *ev = &e->xexpose; -+ -+- if (ev->count == 0 && (m = wintomon(ev->window))) -++ if (ev->count == 0 && (m = wintomon(ev->window))) { -+ drawbar(m); -++ if (m == selmon) -++ updatesystray(); -++ } -+ } -+ -+ void -+@@ -862,10 +963,17 @@ getatomprop(Client *c, Atom prop) -+ unsigned long dl; -+ unsigned char *p = NULL; -+ Atom da, atom = None; -++ /* FIXME getatomprop should return the number of items and a pointer to -++ * the stored data instead of this workaround */ -++ Atom req = XA_ATOM; -++ if (prop == xatom[XembedInfo]) -++ req = xatom[XembedInfo]; -+ -+- if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, -++ if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req, -+ &da, &di, &dl, &dl, &p) == Success && p) { -+ atom = *(Atom *)p; -++ if (da == xatom[XembedInfo] && dl == 2) -++ atom = ((Atom *)p)[1]; -+ XFree(p); -+ } -+ return atom; -+@@ -899,6 +1007,16 @@ getstate(Window w) -+ return result; -+ } -+ -++unsigned int -++getsystraywidth() -++{ -++ unsigned int w = 0; -++ Client *i; -++ if(showsystray) -++ for(i = systray->icons; i; w += i->w + systrayspacing, i = i->next) ; -++ return w ? w + systrayspacing : 1; -++} -++ -+ int -+ gettextprop(Window w, Atom atom, char *text, unsigned int size) -+ { -+@@ -1003,7 +1121,7 @@ killclient(const Arg *arg) -+ { -+ if (!selmon->sel) -+ return; -+- if (!sendevent(selmon->sel, wmatom[WMDelete])) { -++ if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) { -+ XGrabServer(dpy); -+ XSetErrorHandler(xerrordummy); -+ XSetCloseDownMode(dpy, DestroyAll); -+@@ -1091,6 +1209,12 @@ maprequest(XEvent *e) -+ { -+ static XWindowAttributes wa; -+ XMapRequestEvent *ev = &e->xmaprequest; -++ Client *i; -++ if ((i = wintosystrayicon(ev->window))) { -++ sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION); -++ resizebarwin(selmon); -++ updatesystray(); -++ } -+ -+ if (!XGetWindowAttributes(dpy, ev->window, &wa)) -+ return; -+@@ -1215,6 +1339,16 @@ propertynotify(XEvent *e) -+ Window trans; -+ XPropertyEvent *ev = &e->xproperty; -+ -++ if ((c = wintosystrayicon(ev->window))) { -++ if (ev->atom == XA_WM_NORMAL_HINTS) { -++ updatesizehints(c); -++ updatesystrayicongeom(c, c->w, c->h); -++ } -++ else -++ updatesystrayiconstate(c, ev); -++ resizebarwin(selmon); -++ updatesystray(); -++ } -+ if ((ev->window == root) && (ev->atom == XA_WM_NAME)) -+ updatestatus(); -+ else if (ev->state == PropertyDelete) -+@@ -1265,6 +1399,20 @@ recttomon(int x, int y, int w, int h) -+ return r; -+ } -+ -++void -++removesystrayicon(Client *i) -++{ -++ Client **ii; -++ -++ if (!showsystray || !i) -++ return; -++ for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next); -++ if (ii) -++ *ii = i->next; -++ free(i); -++} -++ -++ -+ void -+ resize(Client *c, int x, int y, int w, int h, int interact) -+ { -+@@ -1272,6 +1420,14 @@ resize(Client *c, int x, int y, int w, int h, int interact) -+ resizeclient(c, x, y, w, h); -+ } -+ -++void -++resizebarwin(Monitor *m) { -++ unsigned int w = m->ww; -++ if (showsystray && m == systraytomon(m)) -++ w -= getsystraywidth(); -++ XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh); -++} -++ -+ void -+ resizeclient(Client *c, int x, int y, int w, int h) -+ { -+@@ -1344,6 +1500,19 @@ resizemouse(const Arg *arg) -+ } -+ } -+ -++void -++resizerequest(XEvent *e) -++{ -++ XResizeRequestEvent *ev = &e->xresizerequest; -++ Client *i; -++ -++ if ((i = wintosystrayicon(ev->window))) { -++ updatesystrayicongeom(i, ev->width, ev->height); -++ resizebarwin(selmon); -++ updatesystray(); -++ } -++} -++ -+ void -+ restack(Monitor *m) -+ { -+@@ -1433,26 +1602,36 @@ setclientstate(Client *c, long state) -+ } -+ -+ int -+-sendevent(Client *c, Atom proto) -++sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) -+ { -+ int n; -+- Atom *protocols; -++ Atom *protocols, mt; -+ int exists = 0; -+ XEvent ev; -+ -+- if (XGetWMProtocols(dpy, c->win, &protocols, &n)) { -+- while (!exists && n--) -+- exists = protocols[n] == proto; -+- XFree(protocols); -++ if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { -++ mt = wmatom[WMProtocols]; -++ if (XGetWMProtocols(dpy, w, &protocols, &n)) { -++ while (!exists && n--) -++ exists = protocols[n] == proto; -++ XFree(protocols); -++ } -++ } -++ else { -++ exists = True; -++ mt = proto; -+ } -+ if (exists) { -+ ev.type = ClientMessage; -+- ev.xclient.window = c->win; -+- ev.xclient.message_type = wmatom[WMProtocols]; -++ ev.xclient.window = w; -++ ev.xclient.message_type = mt; -+ ev.xclient.format = 32; -+- ev.xclient.data.l[0] = proto; -+- ev.xclient.data.l[1] = CurrentTime; -+- XSendEvent(dpy, c->win, False, NoEventMask, &ev); -++ ev.xclient.data.l[0] = d0; -++ ev.xclient.data.l[1] = d1; -++ ev.xclient.data.l[2] = d2; -++ ev.xclient.data.l[3] = d3; -++ ev.xclient.data.l[4] = d4; -++ XSendEvent(dpy, w, False, mask, &ev); -+ } -+ return exists; -+ } -+@@ -1466,7 +1645,7 @@ setfocus(Client *c) -+ XA_WINDOW, 32, PropModeReplace, -+ (unsigned char *) &(c->win), 1); -+ } -+- sendevent(c, wmatom[WMTakeFocus]); -++ sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); -+ } -+ -+ void -+@@ -1555,6 +1734,10 @@ setup(void) -+ wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); -+ netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); -+ netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); -++ netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False); -++ netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False); -++ netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False); -++ netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False); -+ netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); -+ netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); -+ netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False); -+@@ -1562,6 +1745,9 @@ setup(void) -+ 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); -++ xatom[Manager] = XInternAtom(dpy, "MANAGER", False); -++ xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False); -++ xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False); -+ /* init cursors */ -+ cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); -+ cursor[CurResize] = drw_cur_create(drw, XC_sizing); -+@@ -1570,6 +1756,8 @@ setup(void) -+ scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); -+ for (i = 0; i < LENGTH(colors); i++) -+ scheme[i] = drw_scm_create(drw, colors[i], 3); -++ /* init system tray */ -++ updatesystray(); -+ /* init bars */ -+ updatebars(); -+ updatestatus(); -+@@ -1701,7 +1889,18 @@ togglebar(const Arg *arg) -+ { -+ selmon->showbar = !selmon->showbar; -+ updatebarpos(selmon); -+- XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); -++ resizebarwin(selmon); -++ if (showsystray) { -++ XWindowChanges wc; -++ if (!selmon->showbar) -++ wc.y = -bh; -++ else if (selmon->showbar) { -++ wc.y = 0; -++ if (!selmon->topbar) -++ wc.y = selmon->mh - bh; -++ } -++ XConfigureWindow(dpy, systray->win, CWY, &wc); -++ } -+ arrange(selmon); -+ } -+ -+@@ -1796,11 +1995,18 @@ unmapnotify(XEvent *e) -+ else -+ unmanage(c, 0); -+ } -++ else if ((c = wintosystrayicon(ev->window))) { -++ /* KLUDGE! sometimes icons occasionally unmap their windows, but do -++ * _not_ destroy them. We map those windows back */ -++ XMapRaised(dpy, c->win); -++ updatesystray(); -++ } -+ } -+ -+ void -+ updatebars(void) -+ { -++ unsigned int w; -+ Monitor *m; -+ XSetWindowAttributes wa = { -+ .override_redirect = True, -+@@ -1811,10 +2017,15 @@ updatebars(void) -+ 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), -++ w = m->ww; -++ if (showsystray && m == systraytomon(m)) -++ w -= getsystraywidth(); -++ m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen), -+ CopyFromParent, DefaultVisual(dpy, screen), -+ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); -+ XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); -++ if (showsystray && m == systraytomon(m)) -++ XMapRaised(dpy, systray->win); -+ XMapRaised(dpy, m->barwin); -+ XSetClassHint(dpy, m->barwin, &ch); -+ } -+@@ -1990,6 +2201,121 @@ updatestatus(void) -+ if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) -+ strcpy(stext, "dwm-"VERSION); -+ drawbar(selmon); -++ updatesystray(); -++} -++ -++void -++updatesystrayicongeom(Client *i, int w, int h) -++{ -++ if (i) { -++ i->h = bh; -++ if (w == h) -++ i->w = bh; -++ else if (h == bh) -++ i->w = w; -++ else -++ i->w = (int) ((float)bh * ((float)w / (float)h)); -++ applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False); -++ /* force icons into the systray dimensions if they don't want to */ -++ if (i->h > bh) { -++ if (i->w == i->h) -++ i->w = bh; -++ else -++ i->w = (int) ((float)bh * ((float)i->w / (float)i->h)); -++ i->h = bh; -++ } -++ } -++} -++ -++void -++updatesystrayiconstate(Client *i, XPropertyEvent *ev) -++{ -++ long flags; -++ int code = 0; -++ -++ if (!showsystray || !i || ev->atom != xatom[XembedInfo] || -++ !(flags = getatomprop(i, xatom[XembedInfo]))) -++ return; -++ -++ if (flags & XEMBED_MAPPED && !i->tags) { -++ i->tags = 1; -++ code = XEMBED_WINDOW_ACTIVATE; -++ XMapRaised(dpy, i->win); -++ setclientstate(i, NormalState); -++ } -++ else if (!(flags & XEMBED_MAPPED) && i->tags) { -++ i->tags = 0; -++ code = XEMBED_WINDOW_DEACTIVATE; -++ XUnmapWindow(dpy, i->win); -++ setclientstate(i, WithdrawnState); -++ } -++ else -++ return; -++ sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0, -++ systray->win, XEMBED_EMBEDDED_VERSION); -++} -++ -++void -++updatesystray(void) -++{ -++ XSetWindowAttributes wa; -++ XWindowChanges wc; -++ Client *i; -++ Monitor *m = systraytomon(NULL); -++ unsigned int x = m->mx + m->mw; -++ unsigned int w = 1; -++ -++ if (!showsystray) -++ return; -++ if (!systray) { -++ /* init systray */ -++ if (!(systray = (Systray *)calloc(1, sizeof(Systray)))) -++ die("fatal: could not malloc() %u bytes\n", sizeof(Systray)); -++ systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel][ColBg].pixel); -++ wa.event_mask = ButtonPressMask | ExposureMask; -++ wa.override_redirect = True; -++ wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; -++ XSelectInput(dpy, systray->win, SubstructureNotifyMask); -++ XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32, -++ PropModeReplace, (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1); -++ XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel, &wa); -++ XMapRaised(dpy, systray->win); -++ XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime); -++ if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) { -++ sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0); -++ XSync(dpy, False); -++ } -++ else { -++ fprintf(stderr, "dwm: unable to obtain system tray.\n"); -++ free(systray); -++ systray = NULL; -++ return; -++ } -++ } -++ for (w = 0, i = systray->icons; i; i = i->next) { -++ /* make sure the background color stays the same */ -++ wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; -++ XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa); -++ XMapRaised(dpy, i->win); -++ w += systrayspacing; -++ i->x = w; -++ XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h); -++ w += i->w; -++ if (i->mon != m) -++ i->mon = m; -++ } -++ w = w ? w + systrayspacing : 1; -++ x -= w; -++ XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh); -++ wc.x = x; wc.y = m->by; wc.width = w; wc.height = bh; -++ wc.stack_mode = Above; wc.sibling = m->barwin; -++ XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc); -++ XMapWindow(dpy, systray->win); -++ XMapSubwindows(dpy, systray->win); -++ /* redraw background */ -++ XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel); -++ XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh); -++ XSync(dpy, False); -+ } -+ -+ void -+@@ -2057,6 +2383,16 @@ wintoclient(Window w) -+ return NULL; -+ } -+ -++Client * -++wintosystrayicon(Window w) { -++ Client *i = NULL; -++ -++ if (!showsystray || !w) -++ return i; -++ for (i = systray->icons; i && i->win != w; i = i->next) ; -++ return i; -++} -++ -+ Monitor * -+ wintomon(Window w) -+ { -+@@ -2110,6 +2446,22 @@ xerrorstart(Display *dpy, XErrorEvent *ee) -+ return -1; -+ } -+ -++Monitor * -++systraytomon(Monitor *m) { -++ Monitor *t; -++ int i, n; -++ if(!systraypinning) { -++ if(!m) -++ return selmon; -++ return m == selmon ? m : NULL; -++ } -++ for(n = 1, t = mons; t && t->next; n++, t = t->next) ; -++ for(i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) ; -++ if(systraypinningfailfirst && n < systraypinning) -++ return mons; -++ return t; -++} -++ -+ void -+ zoom(const Arg *arg) -+ { -+-- -+2.17.1 -+ -diff --git a/patches/dwm-uselessgap-6.2.diff b/patches/dwm-uselessgap-6.2.diff +diff --git a/dwm.desktop b/dwm.desktop new file mode 100644 -index 0000000..d9cacbe +index 0000000..5a6021f --- /dev/null -+++ b/patches/dwm-uselessgap-6.2.diff -@@ -0,0 +1,81 @@ -+From 58a5ece9406ca6c90dc362617c065e4aac19417f Mon Sep 17 00:00:00 2001 -+From: Cyril Cressent <cyril@cressent.org> -+Date: Wed, 3 Jul 2019 21:33:45 -0700 -+Subject: [PATCH] Port the uselessgap patch to 6.2 -+ -+--- -+ config.def.h | 1 + -+ dwm.c | 36 ++++++++++++++++++++++++++++++------ -+ 2 files changed, 31 insertions(+), 6 deletions(-) -+ -+diff --git a/config.def.h b/config.def.h -+index 1c0b587..b11471d 100644 -+--- a/config.def.h -++++ b/config.def.h -+@@ -2,6 +2,7 @@ -+ -+ /* appearance */ -+ static const unsigned int borderpx = 1; /* border pixel of windows */ -++static const unsigned int gappx = 6; /* gaps between windows */ -+ static const unsigned int snap = 32; /* snap pixel */ -+ static const int showbar = 1; /* 0 means no bar */ -+ static const int topbar = 1; /* 0 means bottom bar */ -+diff --git a/dwm.c b/dwm.c -+index 4465af1..4545e05 100644 -+--- a/dwm.c -++++ b/dwm.c -+@@ -52,8 +52,8 @@ -+ #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) -+-#define HEIGHT(X) ((X)->h + 2 * (X)->bw) -++#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_fontset_getwidth(drw, (X)) + lrpad) -+ -+@@ -1276,12 +1276,36 @@ 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; -+ -+- c->oldx = c->x; c->x = wc.x = x; -+- c->oldy = c->y; c->y = wc.y = y; -+- c->oldw = c->w; c->w = wc.width = w; -+- c->oldh = c->h; c->h = wc.height = h; -+ 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); -+-- -+2.22.0 -+ -diff --git a/patches/dwm-zoomswap-6.2.diff b/patches/dwm-zoomswap-6.2.diff -new file mode 100644 -index 0000000..3c658e6 ++++ b/dwm.desktop +@@ -0,0 +1,10 @@ ++[Desktop Entry] ++Version=6.3 ++Type=Application ++Name=dwm ++Comment=Suckless' dynamic window manager ++Exec=dwm ++Icon=dwm ++Terminal=false ++StartupNotify=false ++Categories=Application; +diff --git a/dwmc b/dwmc +new file mode 100755 +index 0000000..5ff8dbc --- /dev/null -+++ b/patches/dwm-zoomswap-6.2.diff -@@ -0,0 +1,95 @@ -+From 3867ef5a68e15a4faff377ddbc8371853de4a800 Mon Sep 17 00:00:00 2001 -+From: aleks <aleks.stier@icloud.com> -+Date: Sat, 19 Oct 2019 00:56:21 +0200 -+Subject: [PATCH] Put master to exact position of zoomed client -+ -+The default behaviour when zooming a client is to put the previous -+master on top of the client-stack. This patch puts the master to the -+exact position of the zoomed client in the stack. -+--- -+ dwm.c | 44 ++++++++++++++++++++++++++++++++++++++++---- -+ 1 file changed, 40 insertions(+), 4 deletions(-) -+ -+diff --git a/dwm.c b/dwm.c -+index 4465af1..1719b36 100644 -+--- a/dwm.c -++++ b/dwm.c -+@@ -165,6 +165,7 @@ 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); -+@@ -235,6 +236,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; -+@@ -780,6 +782,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) -+ { -+@@ -2114,14 +2126,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 -+-- -+2.23.0 ++++ b/dwmc +@@ -0,0 +1,40 @@ ++#!/usr/bin/env sh ++ ++signal() { ++ xsetroot -name "fsignal:$*" ++} + ++case $# in ++1) ++ case $1 in ++ setlayout | view | viewall | togglebar | togglefloating | zoom | killclient | quit) ++ signal $1 ++ ;; ++ *) ++ echo "Unknown command or missing one argument." ++ exit 1 ++ ;; ++ esac ++ ;; ++2) ++ case $1 in ++ view) ++ signal $1 ui $2 ++ ;; ++ viewex | toggleviewex | tagex | toggletagex | setlayoutex | focusstack | incnmaster | focusmon | tagmon) ++ signal $1 i $2 ++ ;; ++ setmfact) ++ signal $1 f $2 ++ ;; ++ *) ++ echo "Unknown command or one too many arguments." ++ exit 1 ++ ;; ++ esac ++ ;; ++*) ++ echo "Too many arguments." ++ exit 1 ++ ;; ++esac diff --git a/volsv b/volsv new file mode 100755 -index 0000000..9e62a7c +index 0000000..f79662b --- /dev/null +++ b/volsv -@@ -0,0 +1,20 @@ +@@ -0,0 +1,52 @@ +#!/bin/sh ++# calculate average of two integers (for ALSA) ++average () { ++ echo "$(( $(( $1 + $2 )) / 2 ))$" ++} ++# print error message ++printerror () { ++ echo "$1 is not a recognized command or flag" ++} +# if pulseaudio +pulsesv () { + case "$1" in @@ -4892,6 +4735,9 @@ index 0000000..9e62a7c + "down" | "-d") pamixer -d 5 ;; + "toggle" | "-t") pamixer -t ;; + "mic" | "-m") pamixer --source 1 -t ;; ++ "getv" | "-v") printf "%s%%\n" "$(pamixer --get-volume)" ;; ++ "getm" | "-g") pamixer --get-mute | sed 's/[Ff]alse/\[on\]/;s/[Tt]rue/\[off\]/' ;; ++ *) printerror "$1" ;; + esac +} +# if alsa @@ -4900,7 +4746,28 @@ index 0000000..9e62a7c + "up" | "-i") amixer sset Master 5%+ ;; + "down" | "-d") amixer sset Master 5%- ;; + "toggle" | "-t") amixer sset Master toggle ;; ++ "mic" | "-m") amixer sset Capture toggle ;; ++ "getv" | "-v") amixer sget Master | grep '\[[0-9]*\%\]' | cut -d' ' -f6 | sed 's/\[//;s/\]//g' ;; ++ "getm" | "-g") amixer sget Master | grep '\[o[fn]' | cut -d' ' -f8 | head -1 ;; ++ *) printerror "$1" ;; + esac +} -+# check which it is -+[ ! -z $(pgrep pulseaudio) ] && pulsesv $1 || alsasv $1 ; pkill -RTMIN+10 dwmblocks ++#Search input for ++echo "$@" | grep -q ' *-h *' && echo \ ++"Volsv is Free software. You can use it for any purpose, but I make no guerantee about its usability or fitness "\ ++"for any particular purpose. You are also free to redistribute, modify, and distribute your modifications to "\ ++"volsv. Volsv is distributed under the BSD 3-Clause license to ensure full license compatibility with GNU, "\ ++"Linux, and BSD operating systems. A copy of this license is included in the repository.\n\n"\ ++"Volsv is a script designed to control the volume of a *NIX machine. The commands/flags are as follows: ++increase volume: 'up' or '-i' ++decrease volume: 'down' or '-d' ++toggle volume mute: 'toggle' or '-t' ++toggle mic mute: 'mic' or '-m' ++get volume level: 'getv' or '-v' ++get mute state: 'getm' or '-g'" && exit ++ ++for i in $@; do ++ pgrep -x pulseaudio >/dev/null && pulsesv $1 || alsasv $1 ++ pgrep -x dwmblocks >/dev/null && pkill -RTMIN+10 dwmblocks ++ pgrep -x dwmbar >/dev/null && dwmbar-signal volume ++done |