summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README6
-rw-r--r--config.h194
-rw-r--r--drw.c118
-rw-r--r--dwm.1162
-rw-r--r--dwm.c585
-rw-r--r--util.c13
-rw-r--r--util.h1
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 <X11/XF86keysym.h>
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 <errno.h>
#include <locale.h>
-#include <stdbool.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
@@ -37,11 +36,12 @@
#include <X11/Xlib.h>
#include <X11/Xproto.h>
#include <X11/Xutil.h>
+#ifdef XINERAMA
#include <X11/extensions/Xinerama.h>
+#endif /* XINERAMA */
#include <X11/Xft/Xft.h>
#include <X11/Xlib-xcb.h>
#include <xcb/res.h>
-#include <xcb/xcb.h>
#ifdef __OpenBSD__
#include <sys/sysctl.h>
#include <kvm.h>
@@ -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 <<i) {
- tag_width += TEXTW(tags[i]);
- }
- }
- int center_x = (m->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 <<i)) continue;
- if (showtags || n == 0) {
+ x = 0;
+ if (showtags == 1) {
+ for (i = 0; i < LENGTH(tags); i++) {
+ if(!(occ & 1 << i || m->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);
}
}
@@ -1200,36 +1084,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)
{
selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
@@ -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);
@@ -2043,42 +1803,14 @@ seturgent(Client *c, int urg)
}
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)
{
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)
+ 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)
@@ -2196,20 +1928,13 @@ togglefloating(const Arg *arg)
}
void
-togglefullscr(const Arg *arg)
-{
- if(selmon->sel)
- setfullscreen(selmon->sel, !selmon->sel->isfullscreen);
-}
-
-void
toggletag(const Arg *arg)
{
unsigned int newtags;
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 <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -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);