From a642d6858229b86358313e38171bbada1f65ef6c Mon Sep 17 00:00:00 2001 From: ProsperousPotato Date: Sat, 15 Mar 2025 13:54:09 +0000 Subject: rewrite from original source --- README | 6 +- config.h | 194 +++++++++------------ drw.c | 118 +++++++------ dwm.1 | 162 +++++++----------- dwm.c | 585 +++++++++++++++++---------------------------------------------- util.c | 13 +- util.h | 1 + 7 files changed, 361 insertions(+), 718 deletions(-) diff --git a/README b/README index 882a35d..95d4fd0 100644 --- a/README +++ b/README @@ -1,12 +1,11 @@ -This is my fork of dwm - dynamic window manager +dwm - dynamic window manager ============================ dwm is an extremely fast, small, and dynamic window manager for X. Requirements ------------ -In order to build dwm you need the Xlib header files, libXft and libXinerama -And obviously, you'll need xorg-server, xorg-xinit, and xorg-xauthority +In order to build dwm you need the Xlib header files. Installation @@ -42,7 +41,6 @@ like this in your .xinitrc: done & exec dwm -Or you can use a status bar program such as slstatus or dwmblocks Configuration ------------- diff --git a/config.h b/config.h index 14b1e00..663111f 100644 --- a/config.h +++ b/config.h @@ -1,36 +1,33 @@ /* See LICENSE file for copyright and license details. */ -/* Constants */ -#define TERMINAL "st" -#define BROWSER "librewolf" - /* appearance */ -static const unsigned int borderpx = 2; /* border pixel of windows */ +static const unsigned int borderpx = 3; /* border pixel of windows */ static const unsigned int snap = 16; /* snap pixel */ -static const int swallowfloating = 1; /* 1 means swallow floating windows by default */ +static const int swallowfloating = 1; static const int showbar = 1; /* 0 means no bar */ static const int topbar = 1; /* 0 means bottom bar */ -static const char *fonts[] = { "Terminus:pixelsize=12:antialias=true:autohint=true, fontawesome:size=12" }; -static const char dmenufont[] = "Terminus:pixelsize=12:antialias=true:autohint=true, fontawesome:size=12"; -static const char col_gray1[] = "#000000"; -static const char col_gray2[] = "#bbbbbb"; -static const char col_gray3[] = "#4CAF50"; // Not selected -static const char col_gray4[] = "#000000"; -static const char col_cyan[] = "#FF8C00"; // Selected +static const char *fonts[] = { "Inconsolata:size=12" }; +static const char dmenufont[] = "Inconsolata:size=12"; +static const char col_gray1[] = "#222222"; +static const char col_gray2[] = "#000000"; +static const char col_gray3[] = "#bbbbbb"; +static const char col_gray4[] = "#eeeeee"; +// static const char col_cyan[] = "#FF8C00"; /* orange */ +// static const char col_cyan[] = "#2f9b85"; /* manjaro green */ +static const char col_cyan[] = "#54487A"; /* gentoo purple */ static const char *colors[][3] = { /* fg bg border */ - [SchemeNorm] = { col_gray3, col_gray1, col_gray1 }, + [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, [SchemeSel] = { col_gray4, col_cyan, col_cyan }, - [SchemeHid] = { col_gray2, col_gray1, col_gray1 }, [SchemeStatus] = { col_gray3, col_gray1, "#000000" }, // Statusbar right {text,background,not used but cannot be empty} [SchemeTagsSel] = { col_cyan, col_gray1, "#000000" }, // Tagbar left selected {text,background,not used but cannot be empty} [SchemeTagsNorm] = { col_gray3, col_gray1, "#000000" }, // Tagbar left unselected {text,background,not used but cannot be empty} - [SchemeInfoSel] = { col_cyan, col_gray1, "#000000" }, // infobar middle selected {text,background,not used but cannot be empty} - [SchemeInfoNorm] = { col_gray3, col_gray1, "#000000" }, // infobar middle unselected {text,background,not used but cannot be empty} + [SchemeInfoSel] = { col_gray1, col_cyan, "#000000" }, // infobar middle selected {text,background,not used but cannot be empty} + [SchemeInfoNorm] = { col_cyan, col_gray1, "#000000" }, // infobar middle unselected {text,background,not used but cannot be empty} }; /* tagging */ -static const char *tags[] = { "1", "2", "3", "4", "5" }; // These are what is visually displayed in the bar, you can change them to whatever. +static const char *tags[] = { "1", "2", "3", "4", "5" }; static const Rule rules[] = { /* xprop(1): @@ -38,6 +35,8 @@ static const Rule rules[] = { * WM_NAME(STRING) = title */ /* class instance title tags mask isfloating isterminal noswallow monitor */ + { "Thunar", "thunar", NULL, 0, 1, 0, 0, -1 }, + { "Firefox", NULL, NULL, 1 << 8, 0, 0, 0, -1 }, { "steam", "steamwebhelper", NULL, 0, 1, 0, 0, -1 }, { "Steam", "Steam", NULL, 0, 1, 0, 0, -1 }, { "steam", "steamwebhelper", "Steam", 0, 0, 0, 0, -1 }, @@ -49,11 +48,10 @@ static const Rule rules[] = { { "St", "st", NULL, 0, 0, 1, 1, -1 }, { "stfloat", "st", NULL, 0, 1, 1, 1, -1 }, { "Mpv", NULL, NULL, 0, 1, 0, 0, -1 }, - { "Nsxiv", NULL, NULL, 0, 1, 0, 0, -1 }, - { "XTerm", "xterm", NULL, 0, 0, 1, 1, -1 }, { "scrcpy", NULL, NULL, 0, 1, 0, 0, -1 }, - { "LibreWolf", "Alert", NULL, 0, 1, 0, 0, -1 }, - { "LibreWolf", "Places", "Library", 0, 1, 0, 0, -1 }, + { "Pamac-manager", "pamac-manager",NULL, 0, 1, 0, 0, -1 }, + { "Floorp", "Alert", NULL, 0, 1, 0, 0, -1 }, + { "Floorp", "Places", "Library", 0, 1, 0, 0, -1 }, { NULL, NULL, "Event Tester", 0, 0, 0, 1, -1 }, }; @@ -65,120 +63,80 @@ static const int lockfullscreen = 0; /* 1 will force focus on the fullscreen win static const Layout layouts[] = { /* symbol arrange function */ - { "", tile }, /* first entry is default */ - { "", NULL }, /* no layout function means floating behavior */ - { "", monocle }, + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", 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} }, + { 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_gray4, "-sf", col_cyan, NULL }; -static const char *termcmd[] = { TERMINAL, NULL }; -static const char *floatterm[] = { TERMINAL, "-c", "stfloat", NULL }; -static const char *sutermcmd[] = { TERMINAL, "-e", "su", NULL }; - +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 const char *floattermcmd[] = { "st", "-c", "stfloat", NULL }; -#include static const Key keys[] = { - /* modifier key function argument */ - { MODKEY, XK_d, spawn, {.v = dmenucmd } }, - { MODKEY, XK_space, spawn, {.v = termcmd } }, - { MODKEY, XK_b, togglebar, {0} }, - { MODKEY, XK_j, focusstackvis, {.i = +1 } }, - { MODKEY, XK_k, focusstackvis, {.i = -1 } }, - { MODKEY, XK_i, incnmaster, {.i = +1 } }, - { MODKEY, XK_u, incnmaster, {.i = -1 } }, - { MODKEY|ControlMask, XK_h, setmfact, {.f = -0.05} }, - { MODKEY|ControlMask, XK_l, setmfact, {.f = +0.05} }, - { Mod1Mask, XK_Tab, zoom, {0} }, - { MODKEY, XK_Tab, view, {0} }, - { MODKEY, XK_q, killclient, {0} }, - { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, - { MODKEY|ShiftMask, XK_f, setlayout, {.v = &layouts[1]} }, - { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, - // { MODKEY|ShiftMask, XK_Return, setlayout, {0} }, - { Mod1Mask, XK_f, togglefloating, {0} }, - { MODKEY, XK_grave, view, {.ui = ~0 } }, - { MODKEY|ShiftMask, XK_grave, 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) - { MODKEY|ShiftMask, XK_End, quit, {0} }, + /* modifier key function argument */ + { MODKEY, XK_d, spawn, {.v = dmenucmd } }, + { MODKEY, XK_space, spawn, {.v = termcmd } }, + { Mod1Mask, XK_space, spawn, {.v = floattermcmd } }, + { 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_u, incnmaster, {.i = -1 } }, + { MODKEY|ControlMask, XK_h, setmfact, {.f = -0.05} }, + { MODKEY|ControlMask, XK_l, setmfact, {.f = +0.05} }, + { MODKEY, XK_h, viewprev, {0} }, + { MODKEY, XK_l, viewnext, {0} }, + { MODKEY|ShiftMask, XK_h, tagtoprev, {0} }, + { MODKEY|ShiftMask, XK_l, tagtonext, {0} }, + { MODKEY, XK_Return, zoom, {0} }, + { Mod1Mask, XK_Tab, 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_Return, setlayout, {0} }, + { MODKEY|ShiftMask, XK_f, 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 } }, - /* Non-default commands i.e. commands added in by me and patches */ - { MODKEY|ShiftMask, XK_space, spawn, {.v = sutermcmd } }, - { Mod1Mask, XK_space, spawn, {.v = floatterm } }, - { Mod1Mask|ShiftMask, XK_space, spawn, SHCMD(TERMINAL" -c stfloat -e su")}, - { MODKEY|ShiftMask, XK_j, movestack, {.i = +1 } }, - { MODKEY|ShiftMask, XK_k, movestack, {.i = -1 } }, - { MODKEY, XK_f, togglefullscr, {0} }, - { MODKEY, XK_BackSpace, hide, {0} }, - { MODKEY, XK_a, showall, {0} }, - { Mod1Mask|ShiftMask, XK_j, moveresize, {.v = "0x 25y 0w 0h" } }, - { Mod1Mask|ShiftMask, XK_k, moveresize, {.v = "0x -25y 0w 0h" } }, - { Mod1Mask|ShiftMask, XK_l, moveresize, {.v = "25x 0y 0w 0h" } }, - { Mod1Mask|ShiftMask, XK_h, moveresize, {.v = "-25x 0y 0w 0h" } }, - { Mod1Mask|ControlMask, XK_j, moveresize, {.v = "0x 0y 0w 25h" } }, - { Mod1Mask|ControlMask, XK_k, moveresize, {.v = "0x 0y 0w -25h" } }, - { Mod1Mask|ControlMask, XK_l, moveresize, {.v = "0x 0y 25w 0h" } }, - { Mod1Mask|ControlMask, XK_h, moveresize, {.v = "0x 0y -25w 0h" } }, - { MODKEY|ShiftMask, XK_m, spawn, SHCMD(TERMINAL" -e neomutt")}, - { MODKEY|ShiftMask, XK_n, spawn, SHCMD(TERMINAL" -e nvim")}, - { Mod1Mask, XK_Escape, spawn, SHCMD(TERMINAL" -c stfloat -e htop")}, - { MODKEY, XK_n, spawn, SHCMD(TERMINAL" -e newsboat")}, - { MODKEY, XK_e, spawn, SHCMD(TERMINAL" -e lfub")}, - { MODKEY, XK_Print, spawn, SHCMD("maimpick") }, - { MODKEY, XK_Up, spawn, SHCMD("dwmvol up") }, - { MODKEY, XK_Down, spawn, SHCMD("dwmvol down") }, - { MODKEY, XK_Right, spawn, SHCMD("dwmlight up") }, - { MODKEY, XK_Left, spawn, SHCMD("dwmlight down") }, - { 0, XF86XK_AudioRaiseVolume, spawn, SHCMD("dwmvol up") }, - { 0, XF86XK_AudioLowerVolume, spawn, SHCMD("dwmvol down") }, - { 0, XF86XK_AudioMute, spawn, SHCMD("dwmvol toggle") }, - { 0, XF86XK_MonBrightnessUp, spawn, SHCMD("dwmlight up") }, - { 0, XF86XK_MonBrightnessDown, spawn, SHCMD("dwmlight down") }, - { MODKEY, XK_F2, spawn, SHCMD("dwmstats") }, - { MODKEY, XK_F1, spawn, SHCMD("dwmext") }, - { MODKEY, XK_F8, spawn, SHCMD("dwmnet") }, - { MODKEY, XK_s, spawn, SHCMD("steam") }, - { MODKEY|ShiftMask, XK_s, spawn, SHCMD("pkill -9 steam") }, - { Mod1Mask|ControlMask, XK_Delete, spawn, SHCMD("slock") }, - { MODKEY, XK_w, spawn, SHCMD("browse "BROWSER) }, - { MODKEY, XK_c, spawn, SHCMD("cliphist add") }, - { MODKEY, XK_v, spawn, SHCMD("cliphist sel") }, - { MODKEY, XK_x, spawn, SHCMD("xkill") }, - { MODKEY, XK_h, viewprev, {0} }, - { MODKEY, XK_l, viewnext, {0} }, - { MODKEY|ShiftMask, XK_h, tagtoprev, {0} }, - { MODKEY|ShiftMask, XK_l, tagtonext, {0} }, - { MODKEY|ShiftMask, XK_r, quit, {1} }, + { MODKEY, XK_e, spawn, SHCMD("thunar") }, + { MODKEY, XK_w, spawn, SHCMD("floorp") }, + { Mod1Mask, XK_Escape, spawn, SHCMD("st -c stfloat -e htop") }, + { ControlMask, XK_F1, spawn, SHCMD("amixer sset Master 5%-") }, + { ControlMask, XK_F2, spawn, SHCMD("amixer sset Master 5%+") }, + + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) + TAGKEYS( XK_4, 3) + TAGKEYS( XK_5, 4) + { MODKEY|ShiftMask, XK_Delete, quit, {0} }, + { MODKEY|ShiftMask, XK_r, quit, {1} }, }; /* button definitions */ /* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ static const Button buttons[] = { /* click event mask button function argument */ - { 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} }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, + { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, }; - diff --git a/drw.c b/drw.c index 927db1f..9aa5f24 100644 --- a/drw.c +++ b/drw.c @@ -9,54 +9,40 @@ #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) +static int +utf8decode(const char *s_in, long *u, int *err) { - size_t i, j, len, type; - long udecoded; - + static const unsigned char lens[] = { + /* 0XXXX */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 10XXX */ 0, 0, 0, 0, 0, 0, 0, 0, /* invalid */ + /* 110XX */ 2, 2, 2, 2, + /* 1110X */ 3, 3, + /* 11110 */ 4, + /* 11111 */ 0, /* invalid */ + }; + static const unsigned char leading_mask[] = { 0x7F, 0x1F, 0x0F, 0x07 }; + static const unsigned int overlong[] = { 0x0, 0x80, 0x0800, 0x10000 }; + + const unsigned char *s = (const unsigned char *)s_in; + int len = lens[*s >> 3]; *u = UTF_INVALID; - if (!clen) - return 0; - udecoded = utf8decodebyte(c[0], &len); - if (!BETWEEN(len, 1, UTF_SIZ)) + *err = 1; + if (len == 0) return 1; - for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { - udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type); - if (type) - return j; + + long cp = s[0] & leading_mask[len - 1]; + for (int i = 1; i < len; ++i) { + if (s[i] == '\0' || (s[i] & 0xC0) != 0x80) + return i; + cp = (cp << 6) | (s[i] & 0x3F); } - if (j < len) - return 0; - *u = udecoded; - utf8validate(u, len); + /* out of range, surrogate, overlong encoding */ + if (cp > 0x10FFFF || (cp >> 11) == 0x1B || cp < overlong[len - 1]) + return len; + *err = 0; + *u = cp; return len; } @@ -191,7 +177,7 @@ drw_clr_create(Drw *drw, Clr *dest, const char *clrname) clrname, dest)) die("error, cannot allocate color '%s'", clrname); - dest->pixel |= 0xff << 24; + dest->pixel |= 0xff << 24; } /* Wrapper to create color schemes. The caller has to call free(3) on the @@ -240,11 +226,11 @@ drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert) { - int i, ty, ellipsis_x = 0; - unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len; + int ty, ellipsis_x = 0; + unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len, hash, h0, h1; XftDraw *d = NULL; Fnt *usedfont, *curfont, *nextfont; - int utf8strlen, utf8charlen, render = x || y || w || h; + int utf8strlen, utf8charlen, utf8err, render = x || y || w || h; long utf8codepoint = 0; const char *utf8str; FcCharSet *fccharset; @@ -253,9 +239,8 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp XftResult result; int charexists = 0, overflow = 0; /* keep track of a couple codepoints for which we have no match. */ - enum { nomatches_len = 64 }; - static struct { long codepoint[nomatches_len]; unsigned int idx; } nomatches; - static unsigned int ellipsis_width = 0; + static unsigned int nomatches[128], ellipsis_width, invalid_width; + static const char invalid[] = "�"; if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts) return 0; @@ -265,6 +250,8 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp } else { XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel); XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); + if (w < lpad) + return x + w; d = XftDrawCreate(drw->dpy, drw->drawable, DefaultVisual(drw->dpy, drw->screen), DefaultColormap(drw->dpy, drw->screen)); @@ -275,12 +262,14 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp usedfont = drw->fonts; if (!ellipsis_width && render) ellipsis_width = drw_fontset_getwidth(drw, "..."); + if (!invalid_width && render) + invalid_width = drw_fontset_getwidth(drw, invalid); while (1) { - ew = ellipsis_len = utf8strlen = 0; + ew = ellipsis_len = utf8err = utf8charlen = utf8strlen = 0; utf8str = text; nextfont = NULL; while (*text) { - utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ); + utf8charlen = utf8decode(text, &utf8codepoint, &utf8err); for (curfont = drw->fonts; curfont; curfont = curfont->next) { charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint); if (charexists) { @@ -302,9 +291,9 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp else utf8strlen = ellipsis_len; } else if (curfont == usedfont) { - utf8strlen += utf8charlen; text += utf8charlen; - ew += tmpw; + utf8strlen += utf8err ? 0 : utf8charlen; + ew += utf8err ? 0 : tmpw; } else { nextfont = curfont; } @@ -312,7 +301,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp } } - if (overflow || !charexists || nextfont) + if (overflow || !charexists || nextfont || utf8err) break; else charexists = 0; @@ -327,6 +316,12 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp x += ew; w -= ew; } + if (utf8err && (!render || invalid_width < w)) { + if (render) + drw_text(drw, x, y, w, h, 0, invalid, invert); + x += invalid_width; + w -= invalid_width; + } if (render && overflow) drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", invert); @@ -340,11 +335,14 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp * character must be drawn. */ charexists = 1; - for (i = 0; i < nomatches_len; ++i) { - /* avoid calling XftFontMatch if we know we won't find a match */ - if (utf8codepoint == nomatches.codepoint[i]) - goto no_match; - } + hash = (unsigned int)utf8codepoint; + hash = ((hash >> 16) ^ hash) * 0x21F0AAAD; + hash = ((hash >> 15) ^ hash) * 0xD35A2D97; + h0 = ((hash >> 15) ^ hash) % LENGTH(nomatches); + h1 = (hash >> 17) % LENGTH(nomatches); + /* avoid expensive XftFontMatch call when we know we won't find a match */ + if (nomatches[h0] == utf8codepoint || nomatches[h1] == utf8codepoint) + goto no_match; fccharset = FcCharSetCreate(); FcCharSetAddChar(fccharset, utf8codepoint); @@ -373,7 +371,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp curfont->next = usedfont; } else { xfont_free(usedfont); - nomatches.codepoint[++nomatches.idx % nomatches_len] = utf8codepoint; + nomatches[nomatches[h0] ? h1 : h0] = utf8codepoint; no_match: usedfont = drw->fonts; } diff --git a/dwm.1 b/dwm.1 index a728190..7b6cadb 100644 --- a/dwm.1 +++ b/dwm.1 @@ -42,170 +42,132 @@ is read and displayed in the status text area. It can be set with the .BR xsetroot (1) command. .TP -.B Common words explained for normies -Super/Mod4 - Windows key. -Master - The big window on the left. -Stack - The 'stack' of windows on the right. -Return - Enter key. -Tags - Tags are the numbers in the top left of the status bar, they're like workspaces -Button1 - Left Click -Button2 - Middle Click/Mouse Wheel Click -Button3 - Right Click -.SS Keyboard commands +.B Button1 +click on a tag label to display all windows with that tag, click on the layout +label toggles between tiled and floating layout. .TP -.B Super\-Space -Start the terminal defined by the TERMINAL definition in config.h, by default it is set to urxvt +.B Button3 +click on a tag label adds/removes all windows with that tag to/from the view. .TP -.B Super\-Shift\-Space -Start the terminal as root. +.B Mod1\-Button1 +click on a tag label applies that tag to the focused window. .TP -.B Super\-d -Spawn -.BR dmenu(1) -for launching other programs. +.B Mod1\-Button3 +click on a tag label adds/removes that tag to/from the focused window. +.SS Keyboard commands +.TP +.B Mod1\-Shift\-Return +Start +.BR st(1). .TP -.B Super\-g +.B Mod1\-p Spawn .BR dmenu(1) -for launching applications from ~/.local/games/ directory. +for launching other programs. .TP -.B Super\-, -Focus previous monitor, if any. +.B Mod1\-, +Focus previous screen, if any. .TP -.B Super\-. -Focus next monitor, if any. +.B Mod1\-. +Focus next screen, if any. .TP -.B Super\-Shift\-, -Send focused window to previous monitor, if any. +.B Mod1\-Shift\-, +Send focused window to previous screen, if any. .TP -.B Super\-Shift\-. -Send focused window to next monitor, if any. +.B Mod1\-Shift\-. +Send focused window to next screen, if any. .TP -.B Super\-b +.B Mod1\-b Toggles bar on and off. .TP -.B Super\-t +.B Mod1\-t Sets tiled layout. .TP -.B Super\-f +.B Mod1\-f Sets floating layout. .TP -.B Super\-m +.B Mod1\-m Sets monocle layout. .TP -.B Super\-Shift\-Return +.B Mod1\-space Toggles between current and previous layout. .TP -.B Super\-j +.B Mod1\-j Focus next window. .TP -.B Super\-k +.B Mod1\-k Focus previous window. .TP -.B Super\-Shift\-j -Rotate currently focused window down the stack, master window will be sent to the top of the stack. -.TP -.B Super\-Shift\-k -Rotate currently focused window up the stack, master window will be sent to the bottom of the stack. -.TP -.B Super\-i +.B Mod1\-i Increase number of windows in master area. .TP -.B Super\-u +.B Mod1\-d Decrease number of windows in master area. .TP -.B Super\-l +.B Mod1\-l Increase master area size. .TP -.B Super\-h +.B Mod1\-h Decrease master area size. .TP -.B Alt\-Tab +.B Mod1\-Return Zooms/cycles focused window to/from master area (tiled layouts only). .TP -.B Super\-q +.B Mod1\-Shift\-c Close focused window. .TP -.B Super\-Return +.B Mod1\-Shift\-space Toggle focused window between tiled and floating state. .TP -.B Super\-Tab -Toggles to the previously selected tag. +.B Mod1\-Tab +Toggles to the previously selected tags. .TP -.B Super\-Shift\-[1..n] +.B Mod1\-Shift\-[1..n] Apply nth tag to focused window. .TP -.B Super\-Shift\-0 +.B Mod1\-Shift\-0 Apply all tags to focused window. .TP -.B Super\-Control\-Shift\-[1..n] +.B Mod1\-Control\-Shift\-[1..n] Add/remove nth tag to/from focused window. .TP -.B Super\-[1..n] +.B Mod1\-[1..n] View all windows with nth tag. .TP -.B Super\-0 +.B Mod1\-0 View all windows with any tag. .TP -.B Super\-Minus -Decrease size of gaps around windows. -.TP -.B Super\-Equals -Increase size of gaps around windows. -.TP -.B Super\-Shift\-Equals -Remove gaps around windows. -.TP -.B Super\-Control\-[1..n] +.B Mod1\-Control\-[1..n] Add/remove all windows with nth tag to/from the view. .TP -.B Super\-Shift\-r -Restart dwm. +.B Mod1\-Shift\-q +Quit dwm. .TP -.B Super\-Shift\-End -Exit dwm. -.TP -.B Super\-w -Opens web browser defined by BROWSER in config.h. -.TP -.B Super\-e -Opens lf (file manager) in a urxvt instance. -.TP -.B Super\-s -Opens Steam. -.TP -.B Super\-Shift\-h -Opens a terminal instance running htop. -.TP -.B Super\-Shift\-n -Opens a terminal instance running neovim. -.TP -.B Super\-Shift\-m -Opens a terminal instance running neomutt. -.TP -.B Control\-Alt\-Delete -Locks the screen using slock, requires slock to be installed to work. -.TP -.B Super\-PrintScreen -Takes a screenshot using scrot. -.TP -.B Super\-v -Allows you to pick a string of text to paste from a bookmarks file using a dmenu prompt, default path is ~/.local/share/bookmarks/bookmarksfile, requires xclip. -.SS Mouse commands +.B Mod1\-Control\-Shift\-q +Restart dwm. +.SS Mouse commands .TP -.B Super\-LMB +.B Mod1\-Button1 Move focused window while dragging. Tiled windows will be toggled to the floating state. .TP -.B Super\-MMB +.B Mod1\-Button2 Toggles focused window between floating and tiled state. .TP -.B Super\-RMB +.B Mod1\-Button3 Resize focused window while dragging. Tiled windows will be toggled to the floating state. .SH CUSTOMIZATION dwm is customized by creating a custom config.h and (re)compiling the source code. This keeps it fast, secure and simple. +.SH SIGNALS +.TP +.B SIGHUP - 1 +Restart the dwm process. +.TP +.B SIGTERM - 15 +Cleanly terminate the dwm process. .SH SEE ALSO .BR dmenu (1), +.BR st (1) .SH ISSUES Java applications which use the XToolkit/XAWT backend may draw grey windows only. The XToolkit/XAWT backend breaks ICCCM-compliance in recent JDK 1.5 and early diff --git a/dwm.c b/dwm.c index bcb716f..bd3a526 100644 --- a/dwm.c +++ b/dwm.c @@ -22,7 +22,6 @@ */ #include #include -#include #include #include #include @@ -37,11 +36,12 @@ #include #include #include +#ifdef XINERAMA #include +#endif /* XINERAMA */ #include #include #include -#include #ifdef __OpenBSD__ #include #include @@ -56,8 +56,6 @@ #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 HIDDEN(C) ((getstate(C->win) == IconicState)) -#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) @@ -66,7 +64,7 @@ /* enums */ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ -enum { SchemeNorm, SchemeSel, SchemeHid, SchemeStatus, SchemeTagsSel, SchemeTagsNorm, SchemeInfoSel, SchemeInfoNorm }; /* color schemes */ +enum { SchemeNorm, SchemeSel, SchemeStatus, SchemeTagsSel, SchemeTagsNorm, SchemeInfoSel, SchemeInfoNorm }; /* color schemes */ enum { NetSupported, NetWMName, NetWMState, NetWMCheck, NetWMFullscreen, NetActiveWindow, NetWMWindowType, NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ @@ -100,10 +98,10 @@ struct Client { int bw, oldbw; unsigned int tags; int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow; - pid_t pid; + pid_t pid; Client *next; Client *snext; - Client *swallowing; + Client *swallowing; Monitor *mon; Window win; }; @@ -126,8 +124,6 @@ struct Monitor { int nmaster; int num; int by; /* bar geometry */ - int btw; /* width of tasks portion of bar */ - int bt; /* number of tasks */ int mx, my, mw, mh; /* screen size */ int wx, wy, ww, wh; /* window area */ unsigned int seltags; @@ -135,7 +131,6 @@ struct Monitor { unsigned int tagset[2]; int showbar; int topbar; - int hidsel; Client *clients; Client *sel; Client *stack; @@ -150,8 +145,8 @@ typedef struct { const char *title; unsigned int tags; int isfloating; - int isterminal; - int noswallow; + int isterminal; + int noswallow; int monitor; } Rule; @@ -182,17 +177,13 @@ static void expose(XEvent *e); static void focus(Client *c); static void focusin(XEvent *e); static void focusmon(const Arg *arg); -static void focusstackvis(const Arg *arg); -static void movestack(const Arg *arg); -static void focusstack(int inc, int vis); +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 hide(const Arg *arg); -static void hidewin(Client *c); static void incnmaster(const Arg *arg); static void keypress(XEvent *e); static void killclient(const Arg *arg); @@ -201,7 +192,6 @@ static void mappingnotify(XEvent *e); static void maprequest(XEvent *e); static void monocle(Monitor *m); static void motionnotify(XEvent *e); -static void moveresize(const Arg *arg); static void movemouse(const Arg *arg); static unsigned int nexttag(void); static unsigned int prevtag(void); @@ -229,8 +219,6 @@ 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 showall(const Arg *arg); -static void showwin(Client *c); static void showhide(Client *c); static void sighup(int unused); static void sigterm(int unused); @@ -240,7 +228,6 @@ static void tagmon(const Arg *arg); static void tile(Monitor *m); static void togglebar(const Arg *arg); static void togglefloating(const Arg *arg); -static void togglefullscr(const Arg *arg); static void toggletag(const Arg *arg); static void toggleview(const Arg *arg); static void unfocus(Client *c, int setfocus); @@ -273,7 +260,6 @@ static pid_t winpid(Window w); /* variables */ static const char broken[] = "broken"; static char stext[256]; -static bool showtags; static int screen; static int sw, sh; /* X display screen geometry width, height */ static int bh; /* bar height */ @@ -299,6 +285,7 @@ static void (*handler[LASTEvent]) (XEvent *) = { static Atom wmatom[WMLast], netatom[NetLast]; static int restart = 0; static int running = 1; +static int showtags = 0; static Cur *cursor[CurLast]; static Clr **scheme; static Display *dpy; @@ -337,8 +324,8 @@ applyrules(Client *c) && (!r->class || strstr(class, r->class)) && (!r->instance || strstr(instance, r->instance))) { - c->isterminal = r->isterminal; - c->noswallow = r->noswallow; + c->isterminal = r->isterminal; + c->noswallow = r->noswallow; c->isfloating = r->isfloating; c->tags |= r->tags; for (m = mons; m && m->num != r->monitor; m = m->next); @@ -530,25 +517,10 @@ buttonpress(XEvent *e) arg.ui = 1 << i; } else if (ev->x < x + TEXTW(selmon->ltsymbol)) click = ClkLtSymbol; - /* 2px right padding */ - else if (ev->x > selmon->ww - TEXTW(stext) + lrpad - 2) + else if (ev->x > selmon->ww - (int)TEXTW(stext)) click = ClkStatusText; - else { - x += TEXTW(selmon->ltsymbol); - c = m->clients; - - if (c) { - do { - if (!ISVISIBLE(c)) - continue; - else - x +=(1.0 / (double)m->bt) * m->btw; - } while (ev->x > x && (c = c->next)); - - click = ClkWinTitle; - arg.v = c; - } - } + else + click = ClkWinTitle; } else if ((c = wintoclient(ev->window))) { focus(c); restack(selmon); @@ -558,7 +530,7 @@ buttonpress(XEvent *e) 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 || click == ClkWinTitle) && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); + buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); } void @@ -759,8 +731,9 @@ destroynotify(XEvent *e) if ((c = wintoclient(ev->window))) unmanage(c, 1); - else if ((c = swallowingclient(ev->window))) - unmanage(c->swallowing, 1); + + else if ((c = swallowingclient(ev->window))) + unmanage(c->swallowing, 1); } void @@ -804,86 +777,78 @@ dirtomon(int dir) void drawbar(Monitor *m) { - int x, w, tw = 0, n = 0, scm; - unsigned int i, occ = 0, urg = 0; + int x, w, tw = 0, mw, ew = 0; + int boxs = drw->fonts->h / 9; + int boxw = drw->fonts->h / 6 + 2; + unsigned int i, occ = 0, urg = 0, n = 0; Client *c; if (!m->showbar) return; - drw_setscheme(drw, scheme[SchemeStatus]); - tw = TEXTW(stext) - lrpad + 2; - drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); - drw_map(drw, m->barwin, 0, 0, m->ww, bh); + /* 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[SchemeStatus]); + 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) { if (ISVISIBLE(c)) n++; - occ |= c->tags; + occ |= c->tags == TAGMASK ? 0 : c->tags; if (c->isurgent) urg |= c->tags; } - int tag_width = 0; - for (i = 0; i < LENGTH(tags); i++) { - if (m->tagset[m->seltags] & 1 << i || occ & 1 <ww - tag_width) / 2; - - x = center_x; - for (i = 0; i < LENGTH(tags); i++) { - w = TEXTW(tags[i]); - if (!(m->tagset[m->seltags] & 1 << i || occ & 1 <tagset[m->seltags] & 1 << i)) + continue; + w = TEXTW(tags[i]); drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeTagsSel : SchemeTagsNorm]); drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); - drw_map(drw, m->barwin, 0, 0, m->ww, bh); - } else { - drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeTagsSel : SchemeTagsNorm]); - drw_text(drw, x, 0, w, bh, lrpad / 2, "", urg & 1 << i); + x += w; } - x += w; } - x = 0; if ((w = m->ww - tw - x) > bh) { if (n > 0) { - int remainder = w % n; - int tabw = (1.0 / (double)n) * w + 1; + tw = TEXTW(m->sel->name) + lrpad; + mw = (tw >= w || n == 1) ? 0 : (w - tw) / (n - 1); + + i = 0; for (c = m->clients; c; c = c->next) { - if (!ISVISIBLE(c)) + if (!ISVISIBLE(c) || c == m->sel) continue; - if (m->sel == c) - scm = SchemeInfoSel; - else if (HIDDEN(c)) - scm = SchemeHid; + tw = TEXTW(c->name); + if(tw < mw) + ew += (mw - tw); else - scm = SchemeInfoNorm; - drw_setscheme(drw, scheme[scm]); - - if (remainder >= 0) { - if (remainder == 0) { - tabw--; - } - remainder--; - } - if (!showtags) { - drw_text(drw, x, 0, tabw, bh, (TEXTW(c->name) < tabw ? (tabw - c->incw - TEXTW(c->name) + lrpad) / 2 : lrpad / 2), c->name, 0); - drw_map(drw, m->barwin, 0, 0, m->ww, bh); - } else { - drw_text(drw, x, 0, tabw, bh, (TEXTW(c->name) < tabw ? (tabw - c->incw - TEXTW(c->name) + lrpad) / 2 : lrpad / 2), "", 0); - } - x += tabw; + i++; + } + if (i > 0) + mw += ew / i; + + for (c = m->clients; c; c = c->next) { + if (!ISVISIBLE(c)) + continue; + tw = MIN(m->sel == c ? w : mw, TEXTW(c->name)); + + drw_setscheme(drw, scheme[m == selmon && m->sel == c ? SchemeInfoSel : SchemeInfoNorm]); + if (tw > lrpad / 2) + drw_text(drw, x, 0, tw, bh, lrpad / 2, c->name, 0); + if (c->isfloating) + drw_rect(drw, x + boxs, boxs, boxw, boxw, c->isfixed, 0); + x += tw; + w -= tw; } - } else { - drw_setscheme(drw, scheme[SchemeTagsNorm]); - drw_rect(drw, x, 0, w, bh, 1, 1); } + drw_setscheme(drw, scheme[SchemeNorm]); + drw_rect(drw, x, 0, w, bh, 1, 1); } - m->bt = n; - m->btw = w; + drw_map(drw, m->barwin, 0, 0, m->ww, bh); } void @@ -928,17 +893,9 @@ void focus(Client *c) { if (!c || !ISVISIBLE(c)) - for (c = selmon->stack; c && (!ISVISIBLE(c) || HIDDEN(c)); c = c->snext); - if (selmon->sel && selmon->sel != c) { + for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext); + if (selmon->sel && selmon->sel != c) unfocus(selmon->sel, 0); - - if (selmon->hidsel) { - hidewin(selmon->sel); - if (c) - arrange(c->mon); - selmon->hidsel = 0; - } - } if (c) { if (c->mon != selmon) selmon = c->mon; @@ -954,7 +911,7 @@ focus(Client *c) XDeleteProperty(dpy, root, netatom[NetActiveWindow]); } selmon->sel = c; - drawbars(); + drawbars(); } /* there are some broken focus acquiring clients needing extra handling */ @@ -979,106 +936,33 @@ focusmon(const Arg *arg) unfocus(selmon->sel, 0); selmon = m; focus(NULL); - if (selmon->sel) - XWarpPointer(dpy, None, selmon->sel->win, 0, 0, 0, 0, selmon->sel->w/2, selmon->sel->h/2); } void -focusstackvis(const Arg *arg) -{ - focusstack(arg->i, 0); -} - -void -movestack(const Arg *arg) -{ - Client *c = NULL, *p = NULL, *pc = NULL, *i; - - if(arg->i > 0) { - /* find the client after selmon->sel */ - for(c = selmon->sel->next; c && (!ISVISIBLE(c) || c->isfloating); c = c->next); - if(!c) - for(c = selmon->clients; c && (!ISVISIBLE(c) || c->isfloating); c = c->next); - - } - else { - /* find the client before selmon->sel */ - for(i = selmon->clients; i != selmon->sel; i = i->next) - if(ISVISIBLE(i) && !i->isfloating) - c = i; - if(!c) - for(; i; i = i->next) - if(ISVISIBLE(i) && !i->isfloating) - c = i; - } - /* find the client before selmon->sel and c */ - for(i = selmon->clients; i && (!p || !pc); i = i->next) { - if(i->next == selmon->sel) - p = i; - if(i->next == c) - pc = i; - } - - /* swap c and selmon->sel selmon->clients in the selmon->clients list */ - if(c && c != selmon->sel) { - Client *temp = selmon->sel->next==c?selmon->sel:selmon->sel->next; - selmon->sel->next = c->next==selmon->sel?c:c->next; - c->next = temp; - - if(p && p != c) - p->next = c; - if(pc && pc != selmon->sel) - pc->next = selmon->sel; - - if(selmon->sel == selmon->clients) - selmon->clients = c; - else if(c == selmon->clients) - selmon->clients = selmon->sel; - - arrange(selmon); - } - showtags = false; -} - -void -focusstack(int inc, int hid) +focusstack(const Arg *arg) { Client *c = NULL, *i; - showtags = false; + showtags = 0; - if ((!selmon->sel && !hid) || (selmon->sel && selmon->sel->isfullscreen && lockfullscreen)) + if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen)) return; - if (!selmon->clients) - return; - if (inc > 0) { - if (selmon->sel) - for (c = selmon->sel->next; - c && (!ISVISIBLE(c) || (!hid && HIDDEN(c))); - c = c->next); + if (arg->i > 0) { + for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); if (!c) - for (c = selmon->clients; - c && (!ISVISIBLE(c) || (!hid && HIDDEN(c))); - c = c->next); + for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next); } else { - if (selmon->sel) { - for (i = selmon->clients; i != selmon->sel; i = i->next) - if (ISVISIBLE(i) && !(!hid && HIDDEN(i))) - c = i; - } else - c = selmon->clients; + 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) && !(!hid && HIDDEN(i))) + if (ISVISIBLE(i)) c = i; } if (c) { focus(c); restack(selmon); - if (HIDDEN(c)) { - showwin(c); - c->mon->hidsel = 1; - } XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w/2, c->h/2); } } @@ -1199,36 +1083,6 @@ grabkeys(void) } } -void -hide(const Arg *arg) -{ - hidewin(selmon->sel); - focus(NULL); - arrange(selmon); -} - -void -hidewin(Client *c) { - if (!c || HIDDEN(c)) - return; - - Window w = c->win; - static XWindowAttributes ra, ca; - - // more or less taken directly from blackbox's hide() function - XGrabServer(dpy); - XGetWindowAttributes(dpy, root, &ra); - XGetWindowAttributes(dpy, w, &ca); - // prevent UnmapNotify events - XSelectInput(dpy, root, ra.your_event_mask & ~SubstructureNotifyMask); - XSelectInput(dpy, w, ca.your_event_mask & ~StructureNotifyMask); - XUnmapWindow(dpy, w); - setclientstate(c, IconicState); - XSelectInput(dpy, root, ra.your_event_mask); - XSelectInput(dpy, w, ca.your_event_mask); - XUngrabServer(dpy); -} - void incnmaster(const Arg *arg) { @@ -1289,7 +1143,7 @@ manage(Window w, XWindowAttributes *wa) c = ecalloc(1, sizeof(Client)); c->win = w; - c->pid = winpid(w); + c->pid = winpid(w); /* geometry */ c->x = c->oldx = wa->x; c->y = c->oldy = wa->y; @@ -1304,7 +1158,7 @@ manage(Window w, XWindowAttributes *wa) } else { c->mon = selmon; applyrules(c); - term = termforwin(c); + term = termforwin(c); } if (c->x + WIDTH(c) > c->mon->wx + c->mon->ww) @@ -1335,17 +1189,14 @@ manage(Window w, XWindowAttributes *wa) 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 */ - if (!HIDDEN(c)) - setclientstate(c, NormalState); + setclientstate(c, NormalState); if (c->mon == selmon) unfocus(selmon->sel, 0); c->mon->sel = c; arrange(c->mon); - if (!HIDDEN(c)) - XMapWindow(dpy, c->win); - if (term) { - swallow(term, c); - } + XMapWindow(dpy, c->win); + if (term) + swallow(term, c); focus(NULL); } @@ -1432,7 +1283,6 @@ movemouse(const Arg *arg) handler[ev.type](&ev); break; case MotionNotify: - nx = ocx + (ev.xmotion.x - x); ny = ocy + (ev.xmotion.y - y); if (abs(selmon->wx - nx) < snap) @@ -1459,74 +1309,10 @@ movemouse(const Arg *arg) } } -void -moveresize(const Arg *arg) { - Client *c; - c = selmon->sel; - int x, y, w, h, nx, ny, nw, nh, ox, oy, ow, oh; - char xAbs, yAbs, wAbs, hAbs; - int msx, msy, dx, dy, nmx, nmy; - unsigned int dui; - Window dummy; - - if (!c || !arg) - return; - if (selmon->lt[selmon->sellt]->arrange && !c->isfloating) - return; - if (sscanf((char *)arg->v, "%d%c %d%c %d%c %d%c", &x, &xAbs, &y, &yAbs, &w, &wAbs, &h, &hAbs) != 8) - return; - - nw = c->w + w; - if (wAbs == 'W') - nw = w < selmon->mw - 2 * c->bw ? w : selmon->mw - 2 * c->bw; - - nh = c->h + h; - if (hAbs == 'H') - nh = h < selmon->mh - 2 * c->bw ? h : selmon->mh - 2 * c->bw; - - nx = c->x + x; - if (xAbs == 'X') { - if (x < selmon->mx) - nx = selmon->mx; - else if (x > selmon->mx + selmon->mw) - nx = selmon->mx + selmon->mw - nw - 2 * c->bw; - else - nx = x; - } - - ny = c->y + y; - if (yAbs == 'Y') { - if (y < selmon->my) - ny = selmon->my; - else if (y > selmon->my + selmon->mh) - ny = selmon->my + selmon->mh - nh - 2 * c->bw; - else - ny = y; - } - - ox = c->x; - oy = c->y; - ow = c->w; - oh = c->h; - - XRaiseWindow(dpy, c->win); - Bool xqp = XQueryPointer(dpy, root, &dummy, &dummy, &msx, &msy, &dx, &dy, &dui); - resize(c, nx, ny, nw, nh, True); - - /* move cursor along with the window to avoid problems */ - if (xqp && ox <= msx && (ox + ow) >= msx && oy <= msy && (oy + oh) >= msy) - { - nmx = c->x - ox + c->w - ow; - nmy = c->y - oy + c->h - oh; - /* make sure the cursor stays inside the window */ - if ((msx + nmx) > c->x && (msy + nmy) > c->y) - XWarpPointer(dpy, None, None, 0, 0, 0, 0, nmx, nmy); - } -} - unsigned int nexttag(void) { + showtags = 1; unsigned int seltag = selmon->tagset[selmon->seltags]; return seltag == (1 << (LENGTH(tags) - 1)) ? 1 : seltag << 1; } @@ -1534,6 +1320,7 @@ nexttag(void) unsigned int prevtag(void) { + showtags = 1; unsigned int seltag = selmon->tagset[selmon->seltags]; return seltag == 1 ? (1 << (LENGTH(tags) - 1)) : seltag >> 1; } @@ -1545,8 +1332,7 @@ tagtonext(const Arg *arg) if (selmon->sel == NULL) return; - - showtags = true; + tmp = nexttag(); tag(&(const Arg){.ui = tmp}); view(&(const Arg){.ui = tmp}); @@ -1560,7 +1346,6 @@ tagtoprev(const Arg *arg) if (selmon->sel == NULL) return; - showtags = true; tmp = prevtag(); tag(&(const Arg){.ui = tmp}); view(&(const Arg){.ui = tmp}); @@ -1569,21 +1354,19 @@ tagtoprev(const Arg *arg) void viewnext(const Arg *arg) { - showtags = true; view(&(const Arg){.ui = nexttag()}); } void viewprev(const Arg *arg) { - showtags = true; view(&(const Arg){.ui = prevtag()}); } Client * nexttiled(Client *c) { - for (; c && (c->isfloating || !ISVISIBLE(c) || HIDDEN(c)); c = c->next); + for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next); return c; } @@ -1636,16 +1419,7 @@ propertynotify(XEvent *e) void quit(const Arg *arg) { - Monitor *m; - Client *c; - for (m = mons; m; m = m->next) { - if (m) { - for (c = m->stack; c; c = c->next) - if (c && HIDDEN(c)) showwin(c); - } - } - - if(arg->i) restart = 1; + if(arg->i) restart = 1; running = 0; } @@ -1674,12 +1448,26 @@ void resizeclient(Client *c, int x, int y, int w, int h) { XWindowChanges wc; + unsigned int n; + Client *nbc; c->oldx = c->x; c->x = wc.x = x; c->oldy = c->y; c->y = wc.y = y; c->oldw = c->w; c->w = wc.width = w; c->oldh = c->h; c->h = wc.height = h; - wc.border_width = c->bw; + wc.border_width = c->bw; + + for (n = 0, nbc = nexttiled(c->mon->clients); nbc; nbc = nexttiled(nbc->next), n++); + + if (c->isfloating || c->mon->lt[c->mon->sellt]->arrange == NULL) { + } else { + if (c->mon->lt[c->mon->sellt]->arrange == monocle || n == 1) { + wc.border_width = 0; + c->w = wc.width += c->bw * 2; + c->h = wc.height += c->bw * 2; + } + } + XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc); configure(c); XSync(dpy, False); @@ -1688,35 +1476,23 @@ resizeclient(Client *c, int x, int y, int w, int h) void resizemouse(const Arg *arg) { - int ocx, ocy, nw, nh; - int ocx2, ocy2, nx, ny; + int x, y, ocw, och, nw, nh; Client *c; Monitor *m; XEvent ev; - int horizcorner, vertcorner; - int di; - unsigned int dui; - Window dummy; if (!(c = selmon->sel)) return; if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */ return; restack(selmon); - ocx = c->x; - ocy = c->y; - ocx2 = c->x + c->w; - ocy2 = c->y + c->h; + ocw = c->w; + och = c->h; if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess) return; - if (!XQueryPointer (dpy, c->win, &dummy, &dummy, &di, &di, &nx, &ny, &dui)) + if(!getrootptr(&x, &y)) return; - horizcorner = nx < c->w / 2; - vertcorner = ny < c->h / 2; - XWarpPointer (dpy, None, c->win, 0, 0, 0, 0, - horizcorner ? (-c->bw) : (c->w + c->bw -1), - vertcorner ? (-c->bw) : (c->h + c->bw -1)); do { XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); switch(ev.type) { @@ -1726,18 +1502,11 @@ resizemouse(const Arg *arg) handler[ev.type](&ev); break; case MotionNotify: - - nx = horizcorner && ocx2 - ev.xmotion.x >= c->minw ? ev.xmotion.x : c->x; - ny = vertcorner && ocy2 - ev.xmotion.y >= c->minh ? ev.xmotion.y : c->y; - nw = MAX(horizcorner ? (ocx2 - nx) : (ev.xmotion.x - ocx - 2 * c->bw + 1), 1); - nh = MAX(vertcorner ? (ocy2 - ny) : (ev.xmotion.y - ocy - 2 * c->bw + 1), 1); - - if (horizcorner && ev.xmotion.x > ocx2) - nx = ocx2 - (nw = c->minw); - if (vertcorner && ev.xmotion.y > ocy2) - ny = ocy2 - (nh = c->minh); - - if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww +// nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1); +// nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1); + nw = MAX(ocw + (ev.xmotion.x - x), 1); + nh = MAX(och + (ev.xmotion.y - y), 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 @@ -1745,13 +1514,10 @@ resizemouse(const Arg *arg) togglefloating(NULL); } if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) - resize(c, nx, ny, nw, nh, 1); + resize(c, c->x, c->y, nw, nh, 1); break; } } while (ev.type != ButtonRelease); - XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, - horizcorner ? (-c->bw) : (c->w + c->bw - 1), - vertcorner ? (-c->bw) : (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) { @@ -1829,20 +1595,15 @@ sendmon(Client *c, Monitor *m) { if (c->mon == m) return; - int hadfocus = (c == selmon->sel); unfocus(c, 1); detach(c); detachstack(c); - arrange(c->mon); c->mon = m; - attach(c); + c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ + attach(c); attachstack(c); - arrange(m); - if (hadfocus) { - focus(c); - restack(m); - } else - focus(NULL); + focus(NULL); + arrange(NULL); } void @@ -1904,7 +1665,6 @@ setfullscreen(Client *c, int fullscreen) c->isfloating = 1; resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); XRaiseWindow(dpy, c->win); - XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w/2, c->h/2); } else if (!fullscreen && c->isfullscreen){ XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, PropModeReplace, (unsigned char*)0, 0); @@ -1966,8 +1726,8 @@ setup(void) /* clean up any zombies (inherited from .xinitrc etc) immediately */ while (waitpid(-1, NULL, WNOHANG) > 0); - signal(SIGHUP, sighup); - signal(SIGTERM, sigterm); + signal(SIGHUP, sighup); + signal(SIGTERM, sigterm); /* init screen */ screen = DefaultScreen(dpy); @@ -2042,34 +1802,6 @@ seturgent(Client *c, int urg) XFree(wmh); } -void -showall(const Arg *arg) -{ - Client *c = NULL; - selmon->hidsel = 0; - for (c = selmon->clients; c; c = c->next) { - if (ISVISIBLE(c)) - showwin(c); - } - if (!selmon->sel) { - for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next); - if (c) - focus(c); - } - restack(selmon); -} - -void -showwin(Client *c) -{ - if (!c || !HIDDEN(c)) - return; - - XMapWindow(dpy, c->win); - setclientstate(c, NormalState); - arrange(c->mon); -} - void showhide(Client *c) { @@ -2077,8 +1809,8 @@ showhide(Client *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) + 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 { @@ -2091,15 +1823,15 @@ showhide(Client *c) void sighup(int unused) { - Arg a = {.i = 1}; - quit(&a); + Arg a = {.i = 1}; + quit(&a); } void sigterm(int unused) { - Arg a = {.i = 0}; - quit(&a); + Arg a = {.i = 0}; + quit(&a); } void @@ -2107,7 +1839,8 @@ spawn(const Arg *arg) { struct sigaction sa; - showtags = false; + showtags = 0; + if (arg->v == dmenucmd) dmenumon[0] = '0' + selmon->num; if (fork() == 0) { @@ -2150,7 +1883,6 @@ tile(Monitor *m) Client *c; for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); - if (n == 0) return; @@ -2159,7 +1891,7 @@ tile(Monitor *m) else mw = m->ww; for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) - if (i < m->nmaster) { + 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) @@ -2195,13 +1927,6 @@ togglefloating(const Arg *arg) arrange(selmon); } -void -togglefullscr(const Arg *arg) -{ - if(selmon->sel) - setfullscreen(selmon->sel, !selmon->sel->isfullscreen); -} - void toggletag(const Arg *arg) { @@ -2209,7 +1934,7 @@ toggletag(const Arg *arg) if (!selmon->sel) return; - showtags = true; + showtags = 1; newtags = selmon->sel->tags ^ (arg->ui & TAGMASK); if (newtags) { selmon->sel->tags = newtags; @@ -2223,7 +1948,7 @@ toggleview(const Arg *arg) { unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); - showtags = true; + showtags = 1; if (newtagset) { selmon->tagset[selmon->seltags] = newtagset; focus(NULL); @@ -2250,19 +1975,19 @@ unmanage(Client *c, int destroyed) Monitor *m = c->mon; XWindowChanges wc; - if (c->swallowing) { - unswallow(c); - return; - } + if (c->swallowing) { + unswallow(c); + return; + } - Client *s = swallowingclient(c->win); - if(s) { - free(s->swallowing); - s->swallowing = NULL; - arrange(m); - focus(NULL); - return; - } + Client *s = swallowingclient(c->win); + if (s) { + free(s->swallowing); + s->swallowing = NULL; + arrange(m); + focus(NULL); + return; + } detach(c); detachstack(c); @@ -2279,11 +2004,12 @@ unmanage(Client *c, int destroyed) XUngrabServer(dpy); } free(c); - if (!s) { - arrange(m); - focus(NULL); - updateclientlist(); - } + + if (!s) { + arrange(m); + focus(NULL); + updateclientlist(); + } } void @@ -2336,7 +2062,7 @@ updatebarpos(Monitor *m) } void -updateclientlist() +updateclientlist(void) { Client *c; Monitor *m; @@ -2490,8 +2216,8 @@ updatesizehints(Client *c) void updatestatus(void) { - if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) - strcpy(stext, ""); + // if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) + // strcpy(stext, "dwm-"VERSION); drawbar(selmon); } @@ -2540,7 +2266,7 @@ view(const Arg *arg) { if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) return; - showtags = true; + showtags = 1; selmon->seltags ^= 1; /* toggle sel tagset */ if (arg->ui & TAGMASK) selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; @@ -2767,9 +2493,8 @@ main(int argc, char *argv[]) fputs("warning: no locale support\n", stderr); if (!(dpy = XOpenDisplay(NULL))) die("dwm: cannot open display"); - if (!(xcon = XGetXCBConnection(dpy))) { - die("dwm: cannot get xcb connection\n"); - } + if (!(xcon = XGetXCBConnection(dpy))) + die("dwm: cannot get xcb connection\n"); checkotherwm(); setup(); #ifdef __OpenBSD__ @@ -2778,7 +2503,7 @@ main(int argc, char *argv[]) #endif /* __OpenBSD__ */ scan(); run(); - if(restart) execvp(argv[0], argv); + if(restart) execvp(argv[0], argv); cleanup(); XCloseDisplay(dpy); return EXIT_SUCCESS; diff --git a/util.c b/util.c index 96b82c9..8e26a51 100644 --- a/util.c +++ b/util.c @@ -1,4 +1,5 @@ /* See LICENSE file for copyright and license details. */ +#include #include #include #include @@ -10,17 +11,17 @@ void die(const char *fmt, ...) { va_list ap; + int saved_errno; + + saved_errno = errno; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); - if (fmt[0] && fmt[strlen(fmt)-1] == ':') { - fputc(' ', stderr); - perror(NULL); - } else { - fputc('\n', stderr); - } + if (fmt[0] && fmt[strlen(fmt)-1] == ':') + fprintf(stderr, " %s", strerror(saved_errno)); + fputc('\n', stderr); exit(1); } diff --git a/util.h b/util.h index f633b51..c0a50d4 100644 --- a/util.h +++ b/util.h @@ -3,6 +3,7 @@ #define MAX(A, B) ((A) > (B) ? (A) : (B)) #define MIN(A, B) ((A) < (B) ? (A) : (B)) #define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B)) +#define LENGTH(X) (sizeof (X) / sizeof (X)[0]) void die(const char *fmt, ...); void *ecalloc(size_t nmemb, size_t size); -- cgit v1.2.3