From 7d7a897db49916b1b8dcd98abe92454e9154e997 Mon Sep 17 00:00:00 2001 From: chewingbever Date: Sun, 25 Oct 2020 16:58:21 +0100 Subject: [PATCH] Added autostart patch --- .gitignore | 1 + config.def.h | 22 +- config.h | 115 + drw.o | Bin 0 -> 10624 bytes dwm | Bin 0 -> 66992 bytes dwm.1 | 23 + dwm.c | 84 + dwm.c.orig | 2152 +++++++++++++++++++ dwm.o | Bin 0 -> 59256 bytes patches/dwm-autostart-20200610-cb3f58a.diff | 179 ++ util.o | Bin 0 -> 2264 bytes 11 files changed, 2565 insertions(+), 11 deletions(-) create mode 100644 .gitignore create mode 100644 config.h create mode 100644 drw.o create mode 100755 dwm create mode 100644 dwm.c.orig create mode 100644 dwm.o create mode 100644 patches/dwm-autostart-20200610-cb3f58a.diff create mode 100644 util.o diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a9fbecd --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.vim/ diff --git a/config.def.h b/config.def.h index 1c0b587..ba42cb7 100644 --- a/config.def.h +++ b/config.def.h @@ -61,18 +61,18 @@ static const char *termcmd[] = { "st", NULL }; static Key keys[] = { /* modifier key function argument */ - { MODKEY, XK_p, spawn, {.v = dmenucmd } }, - { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_d, spawn, {.v = dmenucmd } }, + { MODKEY, XK_Return, spawn, {.v = termcmd } }, { MODKEY, XK_b, togglebar, {0} }, { MODKEY, XK_j, focusstack, {.i = +1 } }, { MODKEY, XK_k, focusstack, {.i = -1 } }, - { MODKEY, XK_i, incnmaster, {.i = +1 } }, - { MODKEY, XK_d, incnmaster, {.i = -1 } }, + /* { MODKEY, XK_i, incnmaster, {.i = +1 } }, */ + /* { MODKEY, XK_d, incnmaster, {.i = -1 } }, */ { MODKEY, XK_h, setmfact, {.f = -0.05} }, { MODKEY, XK_l, setmfact, {.f = +0.05} }, - { MODKEY, XK_Return, zoom, {0} }, + /* { MODKEY, XK_Return, zoom, {0} }, */ { MODKEY, XK_Tab, view, {0} }, - { MODKEY|ShiftMask, XK_c, killclient, {0} }, + { MODKEY , XK_x, killclient, {0} }, { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, @@ -84,11 +84,11 @@ static Key keys[] = { { MODKEY, XK_period, focusmon, {.i = +1 } }, { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, - TAGKEYS( XK_1, 0) - TAGKEYS( XK_2, 1) - TAGKEYS( XK_3, 2) - TAGKEYS( XK_4, 3) - TAGKEYS( XK_5, 4) + TAGKEYS( XK_y, 0) + TAGKEYS( XK_u, 1) + TAGKEYS( XK_i, 2) + TAGKEYS( XK_o, 3) + TAGKEYS( XK_p, 4) TAGKEYS( XK_6, 5) TAGKEYS( XK_7, 6) TAGKEYS( XK_8, 7) diff --git a/config.h b/config.h new file mode 100644 index 0000000..ba42cb7 --- /dev/null +++ b/config.h @@ -0,0 +1,115 @@ +/* See LICENSE file for copyright and license details. */ + +/* appearance */ +static const unsigned int borderpx = 1; /* border pixel of 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 */ +static const char *fonts[] = { "monospace:size=10" }; +static const char dmenufont[] = "monospace:size=10"; +static const char col_gray1[] = "#222222"; +static const char col_gray2[] = "#444444"; +static const char col_gray3[] = "#bbbbbb"; +static const char col_gray4[] = "#eeeeee"; +static const char col_cyan[] = "#005577"; +static const char *colors[][3] = { + /* fg bg border */ + [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, + [SchemeSel] = { col_gray4, col_cyan, col_cyan }, +}; + +/* tagging */ +static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + +static const Rule rules[] = { + /* xprop(1): + * 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 }, +}; + +/* layout(s) */ +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 Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, +}; + +/* key definitions */ +#define MODKEY Mod1Mask +#define TAGKEYS(KEY,TAG) \ + { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ + { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ + { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ + { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} }, + +/* helper for spawning shell commands in the pre dwm-5.0 fashion */ +#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } + +/* commands */ +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 *termcmd[] = { "st", NULL }; + +static Key keys[] = { + /* modifier key function argument */ + { MODKEY, XK_d, spawn, {.v = dmenucmd } }, + { MODKEY, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_b, togglebar, {0} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + /* { MODKEY, XK_i, incnmaster, {.i = +1 } }, */ + /* { MODKEY, XK_d, incnmaster, {.i = -1 } }, */ + { MODKEY, XK_h, setmfact, {.f = -0.05} }, + { MODKEY, XK_l, setmfact, {.f = +0.05} }, + /* { MODKEY, XK_Return, zoom, {0} }, */ + { MODKEY, XK_Tab, view, {0} }, + { MODKEY , XK_x, killclient, {0} }, + { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, + { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, + { MODKEY, XK_space, setlayout, {0} }, + { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, + { MODKEY, XK_0, view, {.ui = ~0 } }, + { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, + { MODKEY, XK_comma, focusmon, {.i = -1 } }, + { MODKEY, XK_period, focusmon, {.i = +1 } }, + { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, + TAGKEYS( XK_y, 0) + TAGKEYS( XK_u, 1) + TAGKEYS( XK_i, 2) + TAGKEYS( XK_o, 3) + TAGKEYS( XK_p, 4) + TAGKEYS( XK_6, 5) + TAGKEYS( XK_7, 6) + TAGKEYS( XK_8, 7) + TAGKEYS( XK_9, 8) + { MODKEY|ShiftMask, XK_q, quit, {0} }, +}; + +/* button definitions */ +/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ +static Button buttons[] = { + /* click event mask button function argument */ + { ClkLtSymbol, 0, Button1, setlayout, {0} }, + { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, + { ClkWinTitle, 0, Button2, zoom, {0} }, + { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, + { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, + { ClkTagBar, 0, Button1, view, {0} }, + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, +}; + diff --git a/drw.o b/drw.o new file mode 100644 index 0000000000000000000000000000000000000000..941460bd62bca873538fd2390d633e6978db77e9 GIT binary patch literal 10624 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 PX_G<`dDd=y*?<27)P!v+ literal 0 HcmV?d00001 diff --git a/dwm b/dwm new file mode 100755 index 0000000000000000000000000000000000000000..8ec14ecc79c78b2703cad0342f1ea94902a477fd GIT binary patch literal 66992 zcmeFadwf$>)<1mGHW;8JQCqDF5+rD=Tw0~t02vaR(h~>}Xn_JkTiTQsN*mh*3My37 z3dcjWDvmgpN5)|sM}1}(bsR*6Lb(*Y71WW7N>$Vo!ljCX6)$A>f5OB$E1zd%D9?p%aLvTugUrTH!n^NSIBgCikzzD$Q)E| z;~O%*@$HLKi()S|RqaVS(!X6wer)QJ#c*m$y!7#Y5h$nU*Eccp7il?l6h3OImYa@p zr04(NkJ1g?45hw!c4<{AP*b(vM^#rXynXbj>hclQRW-qe5e+%FkGOsG$okrmx3YGV z8A;XrsWZ9B`Rl%%_{QlGTLzC!xn}FTGx{Iw7)xSF2a-oT^dWx5T^_v0UZwtoKTJ-K-woIG?_(LmcbqB=C?%$V=9s8H$Ri*k}M2rq@tjKlvlN?(dU z4~kz3&xs@FojCl@qp_Egb9WqkaUA_O#;La=j-2{9`kah|pG9w6O3x#4_y@smmWwPe z6SL#!^KP7W4UJQ8Q=EElkAv@tBj@*V@YXnbj*FwGHx9okjy_xB;B(^OH^k}Rm*U{v zF!!bU>#vw}m%^Lk@WVWu1^;3{PseHR;W+lZGmhOx#gX%J99)PaXF;5HMdRo*B#!*y zXs9K&v7qg7w+>>?6dH^I07IJL1Us zC{DX3#?i+WNB+P#cDOc?&9S`~*sHIAOwUPkMRYq*jwG+gt!jNxfq!^avB zk4A+*7I(uwmqSjY!mqCDxMFwVl;Uz5bw#HXjy0F^E6&EjBT3b_G zA1JL06c@{^mt-uOSm*N<1nR147I`3sE1FresIGKjfv;|vuZ}Bn)s-%v;VTQ2)+~b5 zqI_SV(AN;~*46rbb%7OJ(KNrW##L4CuPy~q;0xr{)z#MVr8VW%R64iLR~qn5tgQ*; z2J7l;fw*g+X^k^byHpldS6WkF<*NxyM5(Hp-s&d=1A*Eau4r~?o!?uF43f5Vp|d;=CWWtRINl4 zeY2}-%4?T91F*-!V890)E&e6wtgfzI&Z>|(AiAoe%2zj~)bEEOIc8K9WIDNg^?|zD z6|yL<2#o4uZv_{OS`hU6YwH5_p4zffvbx;7{9IZ4-mdXg`vSfTrKn}SwsQF@s%m_y z)v1mtWM8N&_iryFbw6rgM$+_SZgpvWz1$-tSM877+M0^0MZr47P+ZZB(yIDif@G*m_sxGd}T{C`sCL7S2!_#xuWSoU)_pAW~YJ` zHDxrasxc+l=s{Q3F7wUs)mN?TH3LLrIQtgW)dp+I)!r+pTI#RvWnmqHt_#$b)mEcZ z(60IwOABj}ma$=~JTL?~Y{W2IlR!39FLXT9ueU=dqxrejG^f<6)m|VA(;y;^RSdSP zD_vUZu6LFNs+M6SC;*dLP=*pU_1wfV45!jyb)X=)us%=~z{~*VEe+6IMpGu#)>dBt zoaN;g1FoRIx~dG006fsW4)&2pH0Y_NOMTwbx_Xw!2G>P(DD2AYxlkT;P}YS?FK{So zDIBPaE2>~lE3Y8{qtwp~ROApuo=x_9T0~I{`6NHD0WJ~UQ-KbJ52Hy!L~d<$Z5{al zroJjnRYBn<฻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 NvreKbk|B~b{{@r-iCF*u literal 0 HcmV?d00001 diff --git a/dwm.1 b/dwm.1 index ddc8321..86e73f9 100644 --- a/dwm.1 +++ b/dwm.1 @@ -30,6 +30,14 @@ 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 dwm draws a small border around windows to indicate the focus state. +.P +On start, dwm can start additional programs that may be specified in two special +shell scripts (see the FILES section below), autostart_blocking.sh and +autostart.sh. The former is executed first and dwm will wait for its +termination before starting. The latter is executed in the background before +dwm enters its handler loop. +.P +Either of these files may be omitted. .SH OPTIONS .TP .B \-v @@ -152,6 +160,21 @@ Toggles focused window between floating and tiled state. .TP .B Mod1\-Button3 Resize focused window while dragging. Tiled windows will be toggled to the floating state. +.SH FILES +The files containing programs to be started along with dwm are searched for in +the following directories: +.IP "1. $XDG_DATA_HOME/dwm" +.IP "2. $HOME/.local/share/dwm" +.IP "3. $HOME/.dwm" +.P +The first existing directory is scanned for any of the autostart files below. +.TP 15 +autostart.sh +This file is started as a shell background process before dwm enters its handler +loop. +.TP 15 +autostart_blocking.sh +This file is started before any autostart.sh; dwm waits for its termination. .SH CUSTOMIZATION dwm is customized by creating a custom config.h and (re)compiling the source code. This keeps it fast, secure and simple. diff --git a/dwm.c b/dwm.c index 664c527..94aa6f3 100644 --- a/dwm.c +++ b/dwm.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -194,6 +195,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); @@ -236,7 +238,11 @@ static int xerrorstart(Display *dpy, XErrorEvent *ee); static void zoom(const Arg *arg); /* variables */ +static const char autostartblocksh[] = "autostart_blocking.sh"; +static const char autostartsh[] = "autostart.sh"; static const char broken[] = "broken"; +static const char dwmdir[] = "dwm"; +static const char localshare[] = ".local/share"; static char stext[256]; static int screen; static int sw, sh; /* X display screen geometry width, height */ @@ -1381,6 +1387,83 @@ run(void) handler[ev.type](&ev); /* call handler */ } +void +runautostart(void) +{ + char *pathpfx; + char *path; + char *xdgdatahome; + char *home; + struct stat sb; + + if ((home = getenv("HOME")) == NULL) + /* this is almost impossible */ + return; + + /* if $XDG_DATA_HOME is set and not empty, use $XDG_DATA_HOME/dwm, + * otherwise use ~/.local/share/dwm as autostart script directory + */ + xdgdatahome = getenv("XDG_DATA_HOME"); + if (xdgdatahome != NULL && *xdgdatahome != '\0') { + /* space for path segments, separators and nul */ + pathpfx = ecalloc(1, strlen(xdgdatahome) + strlen(dwmdir) + 2); + + if (sprintf(pathpfx, "%s/%s", xdgdatahome, dwmdir) <= 0) { + free(pathpfx); + return; + } + } else { + /* space for path segments, separators and nul */ + pathpfx = ecalloc(1, strlen(home) + strlen(localshare) + + strlen(dwmdir) + 3); + + if (sprintf(pathpfx, "%s/%s/%s", home, localshare, dwmdir) < 0) { + free(pathpfx); + return; + } + } + + /* check if the autostart script directory exists */ + if (! (stat(pathpfx, &sb) == 0 && S_ISDIR(sb.st_mode))) { + /* the XDG conformant path does not exist or is no directory + * so we try ~/.dwm instead + */ + char *pathpfx_new = realloc(pathpfx, strlen(home) + strlen(dwmdir) + 3); + if(pathpfx_new == NULL) { + free(pathpfx); + return; + } + pathpfx = pathpfx_new; + + if (sprintf(pathpfx, "%s/.%s", home, dwmdir) <= 0) { + free(pathpfx); + return; + } + } + + /* try the blocking script first */ + path = ecalloc(1, strlen(pathpfx) + strlen(autostartblocksh) + 2); + if (sprintf(path, "%s/%s", pathpfx, autostartblocksh) <= 0) { + free(path); + free(pathpfx); + } + + if (access(path, X_OK) == 0) + system(path); + + /* now the non-blocking script */ + if (sprintf(path, "%s/%s", pathpfx, autostartsh) <= 0) { + free(path); + free(pathpfx); + } + + if (access(path, X_OK) == 0) + system(strcat(path, " &")); + + free(pathpfx); + free(path); +} + void scan(void) { @@ -2145,6 +2228,7 @@ main(int argc, char *argv[]) die("pledge"); #endif /* __OpenBSD__ */ scan(); + runautostart(); run(); cleanup(); XCloseDisplay(dpy); 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef XINERAMA +#include +#endif /* XINERAMA */ +#include + +#include "drw.h" +#include "util.h" + +/* macros */ +#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) +#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) +#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ + * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) +#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) +#define LENGTH(X) (sizeof X / sizeof X[0]) +#define MOUSEMASK (BUTTONMASK|PointerMotionMask) +#define WIDTH(X) ((X)->w + 2 * (X)->bw) +#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.o b/dwm.o new file mode 100644 index 0000000000000000000000000000000000000000..0aefdd0e0467e2698fb58bfd4e667caba52e4120 GIT binary patch literal 59256 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 literal 0 HcmV?d00001 diff --git a/patches/dwm-autostart-20200610-cb3f58a.diff b/patches/dwm-autostart-20200610-cb3f58a.diff new file mode 100644 index 0000000..7e17424 --- /dev/null +++ b/patches/dwm-autostart-20200610-cb3f58a.diff @@ -0,0 +1,179 @@ +From 37e970479dc5d40e57fc0cbfeaa5e39941483237 Mon Sep 17 00:00:00 2001 +From: Gan Ainm +Date: Wed, 10 Jun 2020 10:59:02 +0000 +Subject: [PATCH] dwm-xdgautostart-6.2.diff + +=================================================================== +--- + dwm.1 | 23 +++++++++++++++++ + dwm.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 105 insertions(+) + +diff --git a/dwm.1 b/dwm.1 +index 13b3729..9533aa6 100644 +--- a/dwm.1 ++++ b/dwm.1 +@@ -30,6 +30,14 @@ 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 + dwm draws a small border around windows to indicate the focus state. ++.P ++On start, dwm can start additional programs that may be specified in two special ++shell scripts (see the FILES section below), autostart_blocking.sh and ++autostart.sh. The former is executed first and dwm will wait for its ++termination before starting. The latter is executed in the background before ++dwm enters its handler loop. ++.P ++Either of these files may be omitted. + .SH OPTIONS + .TP + .B \-v +@@ -152,6 +160,21 @@ Toggles focused window between floating and tiled state. + .TP + .B Mod1\-Button3 + Resize focused window while dragging. Tiled windows will be toggled to the floating state. ++.SH FILES ++The files containing programs to be started along with dwm are searched for in ++the following directories: ++.IP "1. $XDG_DATA_HOME/dwm" ++.IP "2. $HOME/.local/share/dwm" ++.IP "3. $HOME/.dwm" ++.P ++The first existing directory is scanned for any of the autostart files below. ++.TP 15 ++autostart.sh ++This file is started as a shell background process before dwm enters its handler ++loop. ++.TP 15 ++autostart_blocking.sh ++This file is started before any autostart.sh; dwm waits for its termination. + .SH CUSTOMIZATION + dwm is customized by creating a custom config.h and (re)compiling the source + code. This keeps it fast, secure and simple. +diff --git a/dwm.c b/dwm.c +index 4465af1..2156b49 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -193,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); +@@ -235,7 +237,11 @@ static int xerrorstart(Display *dpy, XErrorEvent *ee); + static void zoom(const Arg *arg); + + /* variables */ ++static const char autostartblocksh[] = "autostart_blocking.sh"; ++static const char autostartsh[] = "autostart.sh"; + static const char broken[] = "broken"; ++static const char dwmdir[] = "dwm"; ++static const char localshare[] = ".local/share"; + static char stext[256]; + static int screen; + static int sw, sh; /* X display screen geometry width, height */ +@@ -1380,6 +1386,83 @@ run(void) + handler[ev.type](&ev); /* call handler */ + } + ++void ++runautostart(void) ++{ ++ char *pathpfx; ++ char *path; ++ char *xdgdatahome; ++ char *home; ++ struct stat sb; ++ ++ if ((home = getenv("HOME")) == NULL) ++ /* this is almost impossible */ ++ return; ++ ++ /* if $XDG_DATA_HOME is set and not empty, use $XDG_DATA_HOME/dwm, ++ * otherwise use ~/.local/share/dwm as autostart script directory ++ */ ++ xdgdatahome = getenv("XDG_DATA_HOME"); ++ if (xdgdatahome != NULL && *xdgdatahome != '\0') { ++ /* space for path segments, separators and nul */ ++ pathpfx = ecalloc(1, strlen(xdgdatahome) + strlen(dwmdir) + 2); ++ ++ if (sprintf(pathpfx, "%s/%s", xdgdatahome, dwmdir) <= 0) { ++ free(pathpfx); ++ return; ++ } ++ } else { ++ /* space for path segments, separators and nul */ ++ pathpfx = ecalloc(1, strlen(home) + strlen(localshare) ++ + strlen(dwmdir) + 3); ++ ++ if (sprintf(pathpfx, "%s/%s/%s", home, localshare, dwmdir) < 0) { ++ free(pathpfx); ++ return; ++ } ++ } ++ ++ /* check if the autostart script directory exists */ ++ if (! (stat(pathpfx, &sb) == 0 && S_ISDIR(sb.st_mode))) { ++ /* the XDG conformant path does not exist or is no directory ++ * so we try ~/.dwm instead ++ */ ++ char *pathpfx_new = realloc(pathpfx, strlen(home) + strlen(dwmdir) + 3); ++ if(pathpfx_new == NULL) { ++ free(pathpfx); ++ return; ++ } ++ pathpfx = pathpfx_new; ++ ++ if (sprintf(pathpfx, "%s/.%s", home, dwmdir) <= 0) { ++ free(pathpfx); ++ return; ++ } ++ } ++ ++ /* try the blocking script first */ ++ path = ecalloc(1, strlen(pathpfx) + strlen(autostartblocksh) + 2); ++ if (sprintf(path, "%s/%s", pathpfx, autostartblocksh) <= 0) { ++ free(path); ++ free(pathpfx); ++ } ++ ++ if (access(path, X_OK) == 0) ++ system(path); ++ ++ /* now the non-blocking script */ ++ if (sprintf(path, "%s/%s", pathpfx, autostartsh) <= 0) { ++ free(path); ++ free(pathpfx); ++ } ++ ++ if (access(path, X_OK) == 0) ++ system(strcat(path, " &")); ++ ++ free(pathpfx); ++ free(path); ++} ++ + void + scan(void) + { +@@ -2142,6 +2223,7 @@ main(int argc, char *argv[]) + die("pledge"); + #endif /* __OpenBSD__ */ + scan(); ++ runautostart(); + run(); + cleanup(); + XCloseDisplay(dpy); +-- +2.27.0 + diff --git a/util.o b/util.o new file mode 100644 index 0000000000000000000000000000000000000000..4607dbd27ccff1daf63334f1a4c614aad4f343e1 GIT binary patch literal 2264 zcmbVNJxo(k6h5UW6-!%z0fR$_r=bbHv?NASl@uuO)ED_RB7?QGuc5Jjd3`l#OvH#o z(==glaByI7F>x@_(S$|^S4SsdG{FG}6AdQyocHd9o9FAoA-CVT-}%nH=iNUZPpFe^ zE*Eff!3Z4oI1BLN*r6XY-57L%7v`1fzVhV94pK_hkcO4&f)rD#s-&pZxHO}px47Og zqW(}^y6X?AQpq2BF0G;5A9^WmnD|QCH1Un}*2MQx!^98L7sRwuYd<@Hj)DUYL>fx% z3U;vfO{uR-do0kW)EA_HQjbgF&v7Z>K^n0)%)-I%=)l?~P-+**GX|CFHWlnK14<3O zwMXt|w9>N`#JI^unkMXaZgp~Mi`K?uXRX9%jfz*Pn-!VF(x+51mn){C08``R(cr+; zjhmrhBrFffR15Ud51Q-Y9Jp2ku6}QaX9EZAL+*?j0r*2W>I*z=yXMzEW)!7a|n@&-;;|>G3@z2TJIFggOK{ynGzzrQj@6dI_|211ot8tDWCNr-Kv0JF$ zTr1>GVGA&g2(+$FyxfAn*n%Hv!N*(h*IV#2$W#5iZgW48n{A2@ zl#R5e>yVgIr^iOs#PsCk{KP_HVRTHLNWlF}NzWFH465{;R)9>YVx*vi2}K>W)vN)U zbv&Vh^O3b-JBjUY)3Vn@qS21iT66v#k!W`PM~gP~KJ>Z%tHApOep}#aU$}l(;6?o} zfu}v@`h9`#5%>-|_-Irooh`2SGM>JRZZqeD=#!D28n?^L;XL0jkjoG9MsgX^&@Eiy zp04GRvZ1XSAg7Z?66ED_8Dzak9g;`n2*{~oKCcx}QYadljIYD_vXM;PLmg#nD~XJr z%xk=iBV!OV>67g@D25zaH(L*@XKA@l*pH3YDuzw8-|UI-uzXrea{0}s`$l#S8}arR zWzIG)Y02#LAaXS3QS&2g%ppY4`24(H9^>