From fcc0c65b3e68e7175bd604f27f582774d43d2730 Mon Sep 17 00:00:00 2001 From: lucy Date: Tue, 9 Jun 2026 12:21:42 +0200 Subject: [PATCH] add patches autostart, attachaside, xressources and custom config --- config.def.h | 54 +- config.h | 137 +++ drw.c | 2 +- drw.c.orig | 435 ++++++++++ drw.h | 2 +- drw.o | Bin 0 -> 10392 bytes dwm | Bin 0 -> 74216 bytes dwm.1 | 23 + dwm.c | 188 ++++- dwm.c.orig | 2257 ++++++++++++++++++++++++++++++++++++++++++++++++++ dwm.o | Bin 0 -> 62920 bytes util.o | Bin 0 -> 2288 bytes 12 files changed, 3075 insertions(+), 23 deletions(-) create mode 100644 config.h create mode 100644 drw.c.orig create mode 100644 drw.o create mode 100755 dwm create mode 100644 dwm.c.orig create mode 100644 dwm.o create mode 100644 util.o diff --git a/config.def.h b/config.def.h index 1c0b587..e69f288 100644 --- a/config.def.h +++ b/config.def.h @@ -1,21 +1,22 @@ /* 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 unsigned int borderpx = 1; /* border pixel of windows */ +static unsigned int snap = 32; /* snap pixel */ +static int showbar = 1; /* 0 means no bar */ +static 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 }, +static char normbgcolor[] = "#222222"; +static char normbordercolor[] = "#444444"; +static char normfgcolor[] = "#bbbbbb"; +static char selfgcolor[] = "#eeeeee"; +static char selbordercolor[] = "#005577"; +static char selbgcolor[] = "#005577"; +static char *colors[][3] = { + /* fg bg border */ + [SchemeNorm] = { normfgcolor, normbgcolor, normbordercolor }, + [SchemeSel] = { selfgcolor, selbgcolor, selbordercolor }, }; /* tagging */ @@ -32,9 +33,9 @@ static const Rule rules[] = { }; /* 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 float mfact = 0.55; /* factor of master area size [0.05..0.95] */ +static int nmaster = 1; /* number of clients in master area */ +static int resizehints = 1; /* 1 means respect size hints in tiled resizals */ static const Layout layouts[] = { /* symbol arrange function */ @@ -56,9 +57,28 @@ static const Layout layouts[] = { /* 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 *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbordercolor, "-sf", selfgcolor, NULL }; static const char *termcmd[] = { "st", NULL }; +/* + * Xresources preferences to load at startup + */ +ResourcePref resources[] = { + { "normbgcolor", STRING, &normbgcolor }, + { "normbordercolor", STRING, &normbordercolor }, + { "normfgcolor", STRING, &normfgcolor }, + { "selbgcolor", STRING, &selbgcolor }, + { "selbordercolor", STRING, &selbordercolor }, + { "selfgcolor", STRING, &selfgcolor }, + { "borderpx", INTEGER, &borderpx }, + { "snap", INTEGER, &snap }, + { "showbar", INTEGER, &showbar }, + { "topbar", INTEGER, &topbar }, + { "nmaster", INTEGER, &nmaster }, + { "resizehints", INTEGER, &resizehints }, + { "mfact", FLOAT, &mfact }, +}; + static Key keys[] = { /* modifier key function argument */ { MODKEY, XK_p, spawn, {.v = dmenucmd } }, diff --git a/config.h b/config.h new file mode 100644 index 0000000..98e68da --- /dev/null +++ b/config.h @@ -0,0 +1,137 @@ +/* See LICENSE file for copyright and license details. */ + +/* appearance */ +static unsigned int borderpx = 1; /* border pixel of windows */ +static unsigned int snap = 32; /* snap pixel */ +static int showbar = 1; /* 0 means no bar */ +static int topbar = 1; /* 0 means bottom bar */ +static const char *fonts[] = { "Maple Mono NL:size=10" }; +static const char dmenufont[] = "Maple Mono NL:size=10"; +static char normbgcolor[] = "#222222"; +static char normbordercolor[] = "#444444"; +static char normfgcolor[] = "#bbbbbb"; +static char selfgcolor[] = "#eeeeee"; +static char selbordercolor[] = "#005577"; +static char selbgcolor[] = "#005577"; +static char *colors[][3] = { + /* fg bg border */ + [SchemeNorm] = { normfgcolor, normbgcolor, normbordercolor }, + [SchemeSel] = { selfgcolor, selbgcolor, selbordercolor }, +}; + +/* 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 float mfact = 0.55; /* factor of master area size [0.05..0.95] */ +static int nmaster = 1; /* number of clients in master area */ +static int resizehints = 0; /* 1 means respect size hints in tiled resizals */ + +static const Layout layouts[] = { + /* symbol arrange function */ + { "tile", tile }, /* first entry is default */ + { "float", NULL }, /* no layout function means floating behavior */ + { "mono", monocle }, +}; + +/* key definitions */ +#define MODKEY Mod4Mask +#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", normbgcolor, "-nf", normfgcolor, "-sb", selbordercolor, "-sf", selfgcolor, NULL }; +static const char *termcmd[] = { "st", NULL }; +static const char *quit_dwm[] = { "pkill", "xinit", NULL }; + +/* + * Xresources preferences to load at startup + */ +ResourcePref resources[] = { + { "color0", STRING, &normbgcolor }, + { "color0", STRING, &normbordercolor }, + { "color12", STRING, &normfgcolor }, + { "color12", STRING, &selbgcolor }, + { "color12", STRING, &selbordercolor }, + { "color0", STRING, &selfgcolor }, + { "borderpx", INTEGER, &borderpx }, + { "snap", INTEGER, &snap }, + { "showbar", INTEGER, &showbar }, + { "topbar", INTEGER, &topbar }, + { "nmaster", INTEGER, &nmaster }, + { "resizehints", INTEGER, &resizehints }, + { "mfact", FLOAT, &mfact }, +}; + +static Key keys[] = { + /* modifier key function argument */ + { MODKEY, XK_p, 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|ShiftMask, XK_Return, zoom, {0} }, + { MODKEY, XK_Tab, view, {0} }, + { MODKEY, XK_q, 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_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) + TAGKEYS( XK_4, 3) + TAGKEYS( XK_5, 4) + TAGKEYS( XK_6, 5) + TAGKEYS( XK_7, 6) + TAGKEYS( XK_8, 7) + TAGKEYS( XK_9, 8) + { MODKEY|ShiftMask, XK_r, quit, {0} }, + { MODKEY|ShiftMask, XK_q, spawn, {.v = quit_dwm} }, +}; + +/* 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.c b/drw.c index 8fd1ca4..e4968a0 100644 --- a/drw.c +++ b/drw.c @@ -207,7 +207,7 @@ drw_clr_create(Drw *drw, Clr *dest, const char *clrname) /* Wrapper to create color schemes. The caller has to call free(3) on the * returned color scheme when done using it. */ Clr * -drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount) +drw_scm_create(Drw *drw, char *clrnames[], size_t clrcount) { size_t i; Clr *ret; diff --git a/drw.c.orig b/drw.c.orig new file mode 100644 index 0000000..8fd1ca4 --- /dev/null +++ b/drw.c.orig @@ -0,0 +1,435 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include +#include + +#include "drw.h" +#include "util.h" + +#define UTF_INVALID 0xFFFD +#define UTF_SIZ 4 + +static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; +static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; +static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; +static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; + +static long +utf8decodebyte(const char c, size_t *i) +{ + for (*i = 0; *i < (UTF_SIZ + 1); ++(*i)) + if (((unsigned char)c & utfmask[*i]) == utfbyte[*i]) + return (unsigned char)c & ~utfmask[*i]; + return 0; +} + +static size_t +utf8validate(long *u, size_t i) +{ + if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF)) + *u = UTF_INVALID; + for (i = 1; *u > utfmax[i]; ++i) + ; + return i; +} + +static size_t +utf8decode(const char *c, long *u, size_t clen) +{ + size_t i, j, len, type; + long udecoded; + + *u = UTF_INVALID; + if (!clen) + return 0; + udecoded = utf8decodebyte(c[0], &len); + if (!BETWEEN(len, 1, UTF_SIZ)) + return 1; + for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { + udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type); + if (type) + return j; + } + if (j < len) + return 0; + *u = udecoded; + utf8validate(u, len); + + return len; +} + +Drw * +drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h) +{ + Drw *drw = ecalloc(1, sizeof(Drw)); + + drw->dpy = dpy; + drw->screen = screen; + drw->root = root; + drw->w = w; + drw->h = h; + drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen)); + drw->gc = XCreateGC(dpy, root, 0, NULL); + XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter); + + return drw; +} + +void +drw_resize(Drw *drw, unsigned int w, unsigned int h) +{ + if (!drw) + return; + + drw->w = w; + drw->h = h; + if (drw->drawable) + XFreePixmap(drw->dpy, drw->drawable); + drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen)); +} + +void +drw_free(Drw *drw) +{ + XFreePixmap(drw->dpy, drw->drawable); + XFreeGC(drw->dpy, drw->gc); + free(drw); +} + +/* This function is an implementation detail. Library users should use + * drw_fontset_create instead. + */ +static Fnt * +xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern) +{ + Fnt *font; + XftFont *xfont = NULL; + FcPattern *pattern = NULL; + + if (fontname) { + /* Using the pattern found at font->xfont->pattern does not yield the + * same substitution results as using the pattern returned by + * FcNameParse; using the latter results in the desired fallback + * behaviour whereas the former just results in missing-character + * rectangles being drawn, at least with some fonts. */ + if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) { + fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname); + return NULL; + } + if (!(pattern = FcNameParse((FcChar8 *) fontname))) { + fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", fontname); + XftFontClose(drw->dpy, xfont); + return NULL; + } + } else if (fontpattern) { + if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) { + fprintf(stderr, "error, cannot load font from pattern.\n"); + return NULL; + } + } else { + die("no font specified."); + } + + /* Do not allow using color fonts. This is a workaround for a BadLength + * error from Xft with color glyphs. Modelled on the Xterm workaround. See + * https://bugzilla.redhat.com/show_bug.cgi?id=1498269 + * https://lists.suckless.org/dev/1701/30932.html + * https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=916349 + * and lots more all over the internet. + */ + FcBool iscol; + if(FcPatternGetBool(xfont->pattern, FC_COLOR, 0, &iscol) == FcResultMatch && iscol) { + XftFontClose(drw->dpy, xfont); + return NULL; + } + + font = ecalloc(1, sizeof(Fnt)); + font->xfont = xfont; + font->pattern = pattern; + font->h = xfont->ascent + xfont->descent; + font->dpy = drw->dpy; + + return font; +} + +static void +xfont_free(Fnt *font) +{ + if (!font) + return; + if (font->pattern) + FcPatternDestroy(font->pattern); + XftFontClose(font->dpy, font->xfont); + free(font); +} + +Fnt* +drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount) +{ + Fnt *cur, *ret = NULL; + size_t i; + + if (!drw || !fonts) + return NULL; + + for (i = 1; i <= fontcount; i++) { + if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) { + cur->next = ret; + ret = cur; + } + } + return (drw->fonts = ret); +} + +void +drw_fontset_free(Fnt *font) +{ + if (font) { + drw_fontset_free(font->next); + xfont_free(font); + } +} + +void +drw_clr_create(Drw *drw, Clr *dest, const char *clrname) +{ + if (!drw || !dest || !clrname) + return; + + if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen), + DefaultColormap(drw->dpy, drw->screen), + clrname, dest)) + die("error, cannot allocate color '%s'", clrname); +} + +/* Wrapper to create color schemes. The caller has to call free(3) on the + * returned color scheme when done using it. */ +Clr * +drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount) +{ + size_t i; + Clr *ret; + + /* need at least two colors for a scheme */ + if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor)))) + return NULL; + + for (i = 0; i < clrcount; i++) + drw_clr_create(drw, &ret[i], clrnames[i]); + return ret; +} + +void +drw_setfontset(Drw *drw, Fnt *set) +{ + if (drw) + drw->fonts = set; +} + +void +drw_setscheme(Drw *drw, Clr *scm) +{ + if (drw) + drw->scheme = scm; +} + +void +drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert) +{ + if (!drw || !drw->scheme) + return; + XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel); + if (filled) + XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); + else + XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1); +} + +int +drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert) +{ + char buf[1024]; + int ty; + unsigned int ew; + XftDraw *d = NULL; + Fnt *usedfont, *curfont, *nextfont; + size_t i, len; + int utf8strlen, utf8charlen, render = x || y || w || h; + long utf8codepoint = 0; + const char *utf8str; + FcCharSet *fccharset; + FcPattern *fcpattern; + FcPattern *match; + XftResult result; + int charexists = 0; + + if (!drw || (render && !drw->scheme) || !text || !drw->fonts) + return 0; + + if (!render) { + w = ~w; + } else { + XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel); + XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); + d = XftDrawCreate(drw->dpy, drw->drawable, + DefaultVisual(drw->dpy, drw->screen), + DefaultColormap(drw->dpy, drw->screen)); + x += lpad; + w -= lpad; + } + + usedfont = drw->fonts; + while (1) { + utf8strlen = 0; + utf8str = text; + nextfont = NULL; + while (*text) { + utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ); + for (curfont = drw->fonts; curfont; curfont = curfont->next) { + charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint); + if (charexists) { + if (curfont == usedfont) { + utf8strlen += utf8charlen; + text += utf8charlen; + } else { + nextfont = curfont; + } + break; + } + } + + if (!charexists || nextfont) + break; + else + charexists = 0; + } + + if (utf8strlen) { + drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL); + /* shorten text if necessary */ + for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew > w; len--) + drw_font_getexts(usedfont, utf8str, len, &ew, NULL); + + if (len) { + memcpy(buf, utf8str, len); + buf[len] = '\0'; + if (len < utf8strlen) + for (i = len; i && i > len - 3; buf[--i] = '.') + ; /* NOP */ + + if (render) { + ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent; + XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg], + usedfont->xfont, x, ty, (XftChar8 *)buf, len); + } + x += ew; + w -= ew; + } + } + + if (!*text) { + break; + } else if (nextfont) { + charexists = 0; + usedfont = nextfont; + } else { + /* Regardless of whether or not a fallback font is found, the + * character must be drawn. */ + charexists = 1; + + fccharset = FcCharSetCreate(); + FcCharSetAddChar(fccharset, utf8codepoint); + + if (!drw->fonts->pattern) { + /* Refer to the comment in xfont_create for more information. */ + die("the first font in the cache must be loaded from a font string."); + } + + fcpattern = FcPatternDuplicate(drw->fonts->pattern); + FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); + FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue); + FcPatternAddBool(fcpattern, FC_COLOR, FcFalse); + + FcConfigSubstitute(NULL, fcpattern, FcMatchPattern); + FcDefaultSubstitute(fcpattern); + match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result); + + FcCharSetDestroy(fccharset); + FcPatternDestroy(fcpattern); + + if (match) { + usedfont = xfont_create(drw, NULL, match); + if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) { + for (curfont = drw->fonts; curfont->next; curfont = curfont->next) + ; /* NOP */ + curfont->next = usedfont; + } else { + xfont_free(usedfont); + usedfont = drw->fonts; + } + } + } + } + if (d) + XftDrawDestroy(d); + + return x + (render ? w : 0); +} + +void +drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) +{ + if (!drw) + return; + + XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y); + XSync(drw->dpy, False); +} + +unsigned int +drw_fontset_getwidth(Drw *drw, const char *text) +{ + if (!drw || !drw->fonts || !text) + return 0; + return drw_text(drw, 0, 0, 0, 0, 0, text, 0); +} + +void +drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h) +{ + XGlyphInfo ext; + + if (!font || !text) + return; + + XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext); + if (w) + *w = ext.xOff; + if (h) + *h = font->h; +} + +Cur * +drw_cur_create(Drw *drw, int shape) +{ + Cur *cur; + + if (!drw || !(cur = ecalloc(1, sizeof(Cur)))) + return NULL; + + cur->cursor = XCreateFontCursor(drw->dpy, shape); + + return cur; +} + +void +drw_cur_free(Drw *drw, Cur *cursor) +{ + if (!cursor) + return; + + XFreeCursor(drw->dpy, cursor->cursor); + free(cursor); +} diff --git a/drw.h b/drw.h index 4bcd5ad..42b04ce 100644 --- a/drw.h +++ b/drw.h @@ -39,7 +39,7 @@ void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned in /* Colorscheme abstraction */ void drw_clr_create(Drw *drw, Clr *dest, const char *clrname); -Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount); +Clr *drw_scm_create(Drw *drw, char *clrnames[], size_t clrcount); /* Cursor abstraction */ Cur *drw_cur_create(Drw *drw, int shape); diff --git a/drw.o b/drw.o new file mode 100644 index 0000000000000000000000000000000000000000..51a85f2fb2606a81148a66b7016045878c40b51d GIT binary patch literal 10392 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 literal 0 HcmV?d00001 diff --git a/dwm b/dwm new file mode 100755 index 0000000000000000000000000000000000000000..fb0c6645e6180fe72c802fc777016813e47d7475 GIT binary patch literal 74216 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 Q1Vq0&gn|jfwp+mY0MqD0Bme*a literal 0 HcmV?d00001 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..d13337d 100644 --- a/dwm.c +++ b/dwm.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,7 @@ #include #include #include +#include #ifdef XINERAMA #include #endif /* XINERAMA */ @@ -49,7 +51,8 @@ #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 ISVISIBLEONTAG(C, T) ((C->tags & T)) +#define ISVISIBLE(C) ISVISIBLEONTAG(C, 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) @@ -141,12 +144,26 @@ typedef struct { int monitor; } Rule; +/* Xresources preferences */ +enum resource_type { + STRING = 0, + INTEGER = 1, + FLOAT = 2 +}; + +typedef struct { + char *name; + enum resource_type type; + void *dst; +} ResourcePref; + /* 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 attachaside(Client *c); static void attachstack(Client *c); static void buttonpress(XEvent *e); static void checkotherwm(void); @@ -183,6 +200,7 @@ static void maprequest(XEvent *e); static void monocle(Monitor *m); static void motionnotify(XEvent *e); static void movemouse(const Arg *arg); +static Client *nexttagged(Client *c); static Client *nexttiled(Client *c); static void pop(Client *); static void propertynotify(XEvent *e); @@ -193,6 +211,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); @@ -233,9 +252,15 @@ 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); +static void load_xresources(void); +static void resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst); /* 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 */ @@ -406,6 +431,17 @@ attach(Client *c) c->mon->clients = c; } +void +attachaside(Client *c) { + Client *at = nexttagged(c); + if(!at) { + attach(c); + return; + } + c->next = at->next; + at->next = c; +} + void attachstack(Client *c) { @@ -1062,7 +1098,7 @@ manage(Window w, XWindowAttributes *wa) c->isfloating = c->oldstate = trans != None || c->isfixed; if (c->isfloating) XRaiseWindow(dpy, c->win); - attach(c); + attachaside(c); attachstack(c); XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, (unsigned char *) &(c->win), 1); @@ -1192,6 +1228,16 @@ movemouse(const Arg *arg) } } +Client * +nexttagged(Client *c) { + Client *walked = c->mon->clients; + for(; + walked && (walked->isfloating || !ISVISIBLEONTAG(walked, c->tags)); + walked = walked->next + ); + return walked; +} + Client * nexttiled(Client *c) { @@ -1380,6 +1426,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) { @@ -1417,7 +1540,7 @@ sendmon(Client *c, Monitor *m) detachstack(c); c->mon = m; c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ - attach(c); + attachaside(c); attachstack(c); focus(NULL); arrange(NULL); @@ -1897,7 +2020,7 @@ updategeom(void) m->clients = c->next; detachstack(c); c->mon = mons; - attach(c); + attachaside(c); attachstack(c); } if (m == selmon) @@ -2124,6 +2247,60 @@ zoom(const Arg *arg) pop(c); } +void +resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst) +{ + char *sdst = NULL; + int *idst = NULL; + float *fdst = NULL; + + sdst = dst; + idst = dst; + fdst = dst; + + char fullname[256]; + char *type; + XrmValue ret; + + snprintf(fullname, sizeof(fullname), "%s.%s", "dwm", name); + fullname[sizeof(fullname) - 1] = '\0'; + + XrmGetResource(db, fullname, "*", &type, &ret); + if (!(ret.addr == NULL || strncmp("String", type, 64))) + { + switch (rtype) { + case STRING: + strcpy(sdst, ret.addr); + break; + case INTEGER: + *idst = strtoul(ret.addr, NULL, 10); + break; + case FLOAT: + *fdst = strtof(ret.addr, NULL); + break; + } + } +} + +void +load_xresources(void) +{ + Display *display; + char *resm; + XrmDatabase db; + ResourcePref *p; + + display = XOpenDisplay(NULL); + resm = XResourceManagerString(display); + if (!resm) + return; + + db = XrmGetStringDatabase(resm); + for (p = resources; p < resources + LENGTH(resources); p++) + resource_load(db, p->name, p->type, p->dst); + XCloseDisplay(display); +} + int main(int argc, char *argv[]) { @@ -2136,12 +2313,15 @@ main(int argc, char *argv[]) if (!(dpy = XOpenDisplay(NULL))) die("dwm: cannot open display"); checkotherwm(); + XrmInitialize(); + load_xresources(); setup(); #ifdef __OpenBSD__ if (pledge("stdio rpath proc exec", NULL) == -1) 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..fc0c4ad --- /dev/null +++ b/dwm.c.orig @@ -0,0 +1,2257 @@ +/* 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 +#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 ISVISIBLEONTAG(C, T) ((C->tags & T)) +#define ISVISIBLE(C) ISVISIBLEONTAG(C, 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 attachaside(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 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 *nexttagged(Client *c); +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 runautostart(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 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 */ +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 +attachaside(Client *c) { + Client *at = nexttagged(c); + if(!at) { + attach(c); + return; + } + c->next = at->next; + at->next = 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 - 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, sw = 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]); + sw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ + drw_text(drw, m->ww - sw, 0, sw, 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 - sw - 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); + attachaside(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 * +nexttagged(Client *c) { + Client *walked = c->mon->clients; + for(; + walked && (walked->isfloating || !ISVISIBLEONTAG(walked, c->tags)); + walked = walked->next + ); + return walked; +} + +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 +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) +{ + 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 */ + attachaside(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.1 || f > 0.9) + 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); + my += HEIGHT(c); + } else { + h = (m->wh - ty) / (n - i); + resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0); + ty += HEIGHT(c); + } +} + +void +togglebar(const Arg *arg) +{ + selmon->showbar = !selmon->showbar; + updatebarpos(selmon); + XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); + arrange(selmon); +} + +void +togglefloating(const Arg *arg) +{ + if (!selmon->sel) + return; + if (selmon->sel->isfullscreen) /* no support for fullscreen windows */ + return; + selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed; + if (selmon->sel->isfloating) + resize(selmon->sel, selmon->sel->x, selmon->sel->y, + selmon->sel->w, selmon->sel->h, 0); + arrange(selmon); +} + +void +toggletag(const Arg *arg) +{ + unsigned int newtags; + + if (!selmon->sel) + return; + newtags = selmon->sel->tags ^ (arg->ui & TAGMASK); + if (newtags) { + selmon->sel->tags = newtags; + focus(NULL); + arrange(selmon); + } +} + +void +toggleview(const Arg *arg) +{ + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); + + if (newtagset) { + selmon->tagset[selmon->seltags] = newtagset; + focus(NULL); + arrange(selmon); + } +} + +void +unfocus(Client *c, int setfocus) +{ + if (!c) + return; + grabbuttons(c, 0); + XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][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; + attachaside(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(); + runautostart(); + run(); + cleanup(); + XCloseDisplay(dpy); + return EXIT_SUCCESS; +} diff --git a/dwm.o b/dwm.o new file mode 100644 index 0000000000000000000000000000000000000000..5ab4d987a26633d1aada4aba38f5f25d594ad71c GIT binary patch literal 62920 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