diff options
| author | moadAlami <moadalami40@gmail.com> | 2025-08-31 08:59:10 +0100 |
|---|---|---|
| committer | moadAlami <moadalami40@gmail.com> | 2025-08-31 08:59:10 +0100 |
| commit | a4f7c2f7771f8240f56f0dff354d541068e33aa2 (patch) | |
| tree | 8b09431b613d3c734f72d26241c10cba23b02523 | |
| parent | c847f160d951cf7c5130809fd3e0a07111075f13 (diff) | |
bump to 6.6 and added systray
| -rw-r--r-- | Makefile | 10 | ||||
| -rw-r--r-- | README | 6 | ||||
| -rw-r--r-- | config.h | 116 | ||||
| -rw-r--r-- | config.mk | 5 | ||||
| -rw-r--r-- | drw.c | 116 | ||||
| -rw-r--r-- | dwm.c | 974 | ||||
| -rw-r--r-- | movestack.c | 2 | ||||
| -rw-r--r-- | util.c | 13 | ||||
| -rw-r--r-- | util.h | 1 |
9 files changed, 722 insertions, 521 deletions
@@ -6,13 +6,7 @@ include config.mk SRC = drw.c dwm.c util.c OBJ = ${SRC:.c=.o} -all: options dwm - -options: - @echo dwm build options: - @echo "CFLAGS = ${CFLAGS}" - @echo "LDFLAGS = ${LDFLAGS}" - @echo "CC = ${CC}" +all: dwm .c.o: ${CC} -c ${CFLAGS} $< @@ -48,4 +42,4 @@ uninstall: rm -f ${DESTDIR}${PREFIX}/bin/dwm\ ${DESTDIR}${MANPREFIX}/man1/dwm.1 -.PHONY: all options clean dist install uninstall +.PHONY: all clean dist install uninstall @@ -47,6 +47,6 @@ Configuration The configuration of dwm is done by creating a custom config.h and (re)compiling the source code. -Patches applied ---------------- -zoomswap - scratchpad - sticky - statuscmd - pertag - noborder - movestack - hide vacant tags - actualfullscreen - bar height - alpha monocle layout - alternativetags - bidi - togglefakefullscreen - swallow - moveresize +Patches +------- +systray - zoomswap - scratchpad - sticky - pertag - noborder - movestack - hide vacant tags - bar height - actualfullscreen - alpha monocle layout - bidi - fakefullscreenclient - moveresize - statuscmd @@ -3,13 +3,18 @@ /* appearance */ static const unsigned int borderpx = 4; /* border pixel of windows */ static const unsigned int snap = 32; /* snap pixel */ -static const int swallowfloating = 0; /* 1 means swallow floating windows by default */ +static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ +static const unsigned int systrayonleft = 0; /* 0: systray in the right corner, >0: systray on left of status text */ +static const unsigned int systrayspacing = 2; /* systray spacing */ +static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/ +static const int showsystray = 1; /* 0 means no systray */ static const int showbar = 1; /* 0 means no bar */ static const int topbar = 1; /* 0 means bottom bar */ static const int user_bh = 2; /* 2 is the default spacing around the bar's font */ - -static const char *fonts[] = { "monospace:size=11", - "Noto Color Emoji:pixelsize=11:antialias=true:autohint=true"}; +static const char *fonts[] = { + "monospace:size=11", + "Noto Color Emoji:pixelsize=11:antialias=true:autohint=true" +}; static const char dmenufont[] = "monospace:size=12"; static const char normbgcolor[] = "#222222"; static const char normbordercolor[] = "#444444"; @@ -23,15 +28,14 @@ static const char *colors[][3] = { [SchemeSel] = { selfgcolor , selbgcolor , selbordercolor }, }; -#include "movestack.c" #include <X11/XF86keysym.h> + /* volume control */ static const char *inc_vol[] = {"/home/mouad/.local/bin/volume/inc_vol", NULL}; static const char *dec_vol[] = {"/home/mouad/.local/bin/volume/dec_vol", NULL}; static const char *toggle_vol[] = {"/home/mouad/.local/bin/volume/toggle_vol", NULL}; static const char *wallpaper[] = {"/home/mouad/.local/bin/background", NULL}; - static const char *turnoff[] = {"/home/mouad/.local/bin/turnoff", NULL}; /* brightness control */ @@ -46,20 +50,20 @@ static const Rule rules[] = { * WM_CLASS(STRING) = instance, class * WM_NAME(STRING) = title */ - /* class instance title tags mask isfloating isterminal noswallow monitor */ - { "zoom", NULL, NULL, 1 << 0, 0, 0, 0, -1 }, - { "discord", NULL, NULL, 1 << 3, 0, 0, 0, -1 }, - { NULL, NULL, "Steam", 1 << 4, 0, 0, 0, -1 }, - { "qgis", NULL, NULL, 1 << 7, 0, 0, 0, -1 }, - { "Slack", NULL, NULL, 1 << 8, 0, 0, 0, -1 }, - { NULL, NULL, "st", 0, 0, 1, 0, -1 }, - { NULL, NULL, "Event Tester", 0, 0, 0, 1, -1 }, /* xev */ + /* class instance title tags mask isfloating monitor */ + { "discord", NULL, NULL, 1 << 3, 0, -1 }, + { NULL, NULL, "Steam", 1 << 4, 0, -1 }, + { "Gimp", NULL, NULL, 1 << 5, 0, -1 }, + { "qgis", NULL, NULL, 1 << 7, 0, -1 }, + { "Slack", NULL, NULL, 1 << 8, 0, -1 }, }; +/* layout(s) */ static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ static const int nmaster = 1; /* number of clients in master area */ static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ -static const int lockfullscreen = 0; /* 1 will force focus on the fullscreen window */ +static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ +static const int refreshrate = 120; /* refresh rate (per second) for client move/resize */ static const Layout layouts[] = { /* symbol arrange function */ @@ -87,11 +91,12 @@ static const char *termcmd[] = { "st", NULL }; static const char scratchpadname[] = { "scratchpad" }; static const char *scratchpadcmd[] = { "/home/mouad/.local/bin/scratch.sh", NULL }; +#include "movestack.c" static const Key keys[] = { /* modifier key function argument */ { MODKEY, XK_d, spawn, {.v = dmenucmd } }, - { MODKEY, XK_Return, spawn, {.v = termcmd } }, - { MODKEY, XK_a, togglescratch, {.v = scratchpadcmd } }, + { MODKEY, XK_a, togglescratch, {.v = scratchpadcmd } }, + { MODKEY, XK_Return, spawn, {.v = termcmd } }, { MODKEY, XK_b, togglebar, {0} }, { MODKEY, XK_j, focusstack, {.i = +1 } }, { MODKEY, XK_k, focusstack, {.i = -1 } }, @@ -99,70 +104,69 @@ static const Key keys[] = { { MODKEY, XK_p, incnmaster, {.i = -1 } }, { MODKEY, XK_h, setmfact, {.f = -0.02} }, { MODKEY, XK_l, setmfact, {.f = +0.02} }, - { MODKEY|ShiftMask, XK_j, movestack, {.i = +1 } }, - { MODKEY|ShiftMask, XK_k, movestack, {.i = -1 } }, + { MODKEY|ShiftMask, XK_j, movestack, {.i = +1 } }, + { MODKEY|ShiftMask, XK_k, movestack, {.i = -1 } }, { MODKEY|ShiftMask, XK_f, zoom, {0} }, { MODKEY, XK_Tab, view, {0} }, { MODKEY|ShiftMask, XK_q, killclient, {0} }, + { MODKEY, XK_s, togglesticky, {0} }, { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, { MODKEY, XK_m, setlayout, {.v = &layouts[1]} }, { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, - { MODKEY, XK_f, togglefullscr, {0} }, + { MODKEY, XK_f, togglefullscr, {0} }, { MODKEY|ShiftMask, XK_t, togglefakefullscreen, {0} }, + { Mod1Mask|ControlMask, XK_j, moveresize, {.v = "0x 25y 0w 0h" } }, + { Mod1Mask|ControlMask, XK_k, moveresize, {.v = "0x -25y 0w 0h" } }, + { Mod1Mask|ControlMask, XK_l, moveresize, {.v = "25x 0y 0w 0h" } }, + { Mod1Mask|ControlMask, XK_h, moveresize, {.v = "-25x 0y 0w 0h" } }, + { Mod1Mask|ShiftMask, XK_j, moveresize, {.v = "0x 0y 0w 25h" } }, + { Mod1Mask|ShiftMask, XK_k, moveresize, {.v = "0x 0y 0w -25h" } }, + { Mod1Mask|ShiftMask, XK_l, moveresize, {.v = "0x 0y 25w 0h" } }, + { Mod1Mask|ShiftMask, XK_h, moveresize, {.v = "0x 0y -25w 0h" } }, + { MODKEY|ControlMask, XK_Up, moveresizeedge, {.v = "t"} }, + { MODKEY|ControlMask, XK_Down, moveresizeedge, {.v = "b"} }, + { MODKEY|ControlMask, XK_Left, moveresizeedge, {.v = "l"} }, + { MODKEY|ControlMask, XK_Right, moveresizeedge, {.v = "r"} }, + { MODKEY|ControlMask|ShiftMask, XK_Up, moveresizeedge, {.v = "T"} }, + { MODKEY|ControlMask|ShiftMask, XK_Down, moveresizeedge, {.v = "B"} }, + { MODKEY|ControlMask|ShiftMask, XK_Left, moveresizeedge, {.v = "L"} }, + { MODKEY|ControlMask|ShiftMask, XK_Right, moveresizeedge, {.v = "R"} }, { 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 } }, - {MODKEY, XK_s, togglesticky, {0}}, - TAGKEYS(XK_1 , 0) - TAGKEYS(XK_2 , 1) - TAGKEYS(XK_3 , 2) - TAGKEYS(XK_4 , 3) - TAGKEYS(XK_5 , 4) - TAGKEYS(XK_6 , 5) - TAGKEYS(XK_7 , 6) - TAGKEYS(XK_8 , 7) - TAGKEYS(XK_9 , 8) - /* Custom commands */ + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) + TAGKEYS( XK_4, 3) + TAGKEYS( XK_5, 4) + TAGKEYS( XK_6, 5) + TAGKEYS( XK_7, 6) + TAGKEYS( XK_8, 7) + TAGKEYS( XK_9, 8) {MODKEY | ShiftMask, XK_o, spawn, {.v = turnoff}}, {MODKEY | ShiftMask, XK_l, spawn, SHCMD("slock")}, - /* keyboard layout */ {Mod1Mask | ShiftMask, XK_e, spawn, SHCMD("setxkbmap -option caps:escape && setxkbmap -layout us && kill -45 $(pidof dwmblocks) && xmodmap /home/mouad/.Xmodmap")}, {Mod1Mask | ShiftMask, XK_f, spawn, SHCMD("setxkbmap -option caps:escape && setxkbmap -layout fr && kill -45 $(pidof dwmblocks) && xmodmap /home/mouad/.Xmodmap")}, - /* dunst control */ - {ControlMask, XK_7, spawn, SHCMD("dunstctl history-pop")}, - {ControlMask, XK_space, spawn, SHCMD("dunstctl close")}, + {ControlMask, XK_7, spawn, SHCMD("dunstctl history-pop")}, + {ControlMask, XK_space, spawn, SHCMD("dunstctl close")}, {ControlMask | ShiftMask, XK_space, spawn, SHCMD("dunstctl close-all")}, - { Mod1Mask|ControlMask, XK_j, moveresize, {.v = "0x 25y 0w 0h" } }, - { Mod1Mask|ControlMask, XK_k, moveresize, {.v = "0x -25y 0w 0h" } }, - { Mod1Mask|ControlMask, XK_l, moveresize, {.v = "25x 0y 0w 0h" } }, - { Mod1Mask|ControlMask, XK_h, moveresize, {.v = "-25x 0y 0w 0h" } }, - { Mod1Mask|ShiftMask, XK_j, moveresize, {.v = "0x 0y 0w 25h" } }, - { Mod1Mask|ShiftMask, XK_k, moveresize, {.v = "0x 0y 0w -25h" } }, - { Mod1Mask|ShiftMask, XK_l, moveresize, {.v = "0x 0y 25w 0h" } }, - { Mod1Mask|ShiftMask, XK_h, moveresize, {.v = "0x 0y -25w 0h" } }, - - {0, XF86XK_MonBrightnessUp, spawn, {.v = inc_bright}}, - {0, XF86XK_MonBrightnessDown, spawn, {.v = dec_bright}}, - - {0, XF86XK_AudioRaiseVolume, spawn, {.v = inc_vol}}, - {0, XF86XK_AudioLowerVolume, spawn, {.v = dec_vol}}, - {0, XF86XK_AudioMute, spawn, {.v = toggle_vol}}, + {0, XF86XK_MonBrightnessUp, spawn, {.v = inc_bright}}, + {0, XF86XK_MonBrightnessDown, spawn, {.v = dec_bright}}, + {0, XF86XK_AudioRaiseVolume, spawn, {.v = inc_vol}}, + {0, XF86XK_AudioLowerVolume, spawn, {.v = dec_vol}}, + {0, XF86XK_AudioMute, spawn, {.v = toggle_vol}}, {MODKEY, XK_r, spawn, {.v = wallpaper}}, - {MODKEY, XK_F1, spawn, {.v = dec_vol}}, - {MODKEY, XK_F2, spawn, {.v = inc_vol}}, - {MODKEY, XK_F3, spawn, {.v = toggle_vol}}, - {Mod1Mask, XK_F1, spawn, SHCMD("mpc prev")}, {Mod1Mask, XK_F2, spawn, SHCMD("mpc toggle")}, {Mod1Mask, XK_F3, spawn, SHCMD("mpc next")}, @@ -188,8 +192,6 @@ static const Button buttons[] = { { ClkStatusText, 0, Button1, sigstatusbar, {.i = 1} }, { ClkStatusText, 0, Button2, sigstatusbar, {.i = 2} }, { ClkStatusText, 0, Button3, sigstatusbar, {.i = 3} }, - { ClkStatusText, 0, Button4, sigstatusbar, {.i = 4} }, - { ClkStatusText, 0, Button5, sigstatusbar, {.i = 5} }, { ClkClientWin, MODKEY, Button1, movemouse, {0} }, { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, @@ -1,5 +1,5 @@ # dwm version -VERSION = 6.4 +VERSION = 6.6 # Customize below to fit your system @@ -22,13 +22,12 @@ FREETYPEINC = /usr/include/freetype2 # OpenBSD (uncomment) #FREETYPEINC = ${X11INC}/freetype2 #MANPREFIX = ${PREFIX}/man -#KVMLIB = -lkvm BDLIBS = -lfribidi # includes and libs INCS = -I${X11INC} -I${FREETYPEINC} -I$(BDINC) -LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} $(BDLIBS) -lX11-xcb -lxcb -lxcb-res ${KVMLIB} +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} $(BDLIBS) # flags CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} @@ -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; } @@ -238,11 +224,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; @@ -251,9 +237,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; @@ -263,6 +248,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)); @@ -273,12 +260,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) { @@ -300,9 +289,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; } @@ -310,7 +299,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; @@ -325,6 +314,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); @@ -338,11 +333,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); @@ -371,7 +369,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; } @@ -41,12 +41,6 @@ #include <X11/extensions/Xinerama.h> #endif /* XINERAMA */ #include <X11/Xft/Xft.h> -#include <X11/Xlib-xcb.h> -#include <xcb/res.h> -#ifdef __OpenBSD__ -#include <sys/sysctl.h> -#include <kvm.h> -#endif /* __OpenBSD */ #include "drw.h" #include "util.h" @@ -57,19 +51,33 @@ #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]) || C->issticky) -#define LENGTH(X) (sizeof X / sizeof X[0]) #define MOUSEMASK (BUTTONMASK|PointerMotionMask) #define WIDTH(X) ((X)->w + 2 * (X)->bw) #define HEIGHT(X) ((X)->h + 2 * (X)->bw) #define TAGMASK ((1 << LENGTH(tags)) - 1) #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) +#define SYSTEM_TRAY_REQUEST_DOCK 0 +/* XEMBED messages */ +#define XEMBED_EMBEDDED_NOTIFY 0 +#define XEMBED_WINDOW_ACTIVATE 1 +#define XEMBED_FOCUS_IN 4 +#define XEMBED_MODALITY_ON 10 +#define XEMBED_MAPPED (1 << 0) +#define XEMBED_WINDOW_ACTIVATE 1 +#define XEMBED_WINDOW_DEACTIVATE 2 +#define VERSION_MAJOR 0 +#define VERSION_MINOR 0 +#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR + /* enums */ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ enum { SchemeNorm, SchemeSel }; /* color schemes */ enum { NetSupported, NetWMName, NetWMState, NetWMCheck, + NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz, NetWMFullscreen, NetWMSticky, NetActiveWindow, NetWMWindowType, NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ +enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ @@ -99,12 +107,10 @@ struct Client { int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid; int bw, oldbw; unsigned int tags; - int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, issticky, isterminal, noswallow; - pid_t pid; + int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, issticky; int fakefullscreen; Client *next; Client *snext; - Client *swallowing; Monitor *mon; Window win; }; @@ -150,11 +156,15 @@ typedef struct { const char *title; unsigned int tags; int isfloating; - int isterminal; - int noswallow; int monitor; } Rule; +typedef struct Systray Systray; +struct Systray { + Window win; + Client *icons; +}; + /* function declarations */ static void apply_fribidi(char *str); static void applyrules(Client *c); @@ -189,6 +199,7 @@ static Atom getatomprop(Client *c, Atom prop); static int getrootptr(int *x, int *y); static long getstate(Window w); static pid_t getstatusbarpid(); +static unsigned int getsystraywidth(); static int gettextprop(Window w, Atom atom, char *text, unsigned int size); static void grabbuttons(Client *c, int focused); static void grabkeys(void); @@ -201,19 +212,21 @@ static void maprequest(XEvent *e); static void monocle(Monitor *m); static void motionnotify(XEvent *e); static void moveresize(const Arg *arg); +static void moveresizeedge(const Arg *arg); static void movemouse(const Arg *arg); static Client *nexttiled(Client *c); -/* static void pop(Client *c); */ static void propertynotify(XEvent *e); -/* static void quit(const Arg *arg); */ static Monitor *recttomon(int x, int y, int w, int h); +static void removesystrayicon(Client *i); static void resize(Client *c, int x, int y, int w, int h, int interact); +static void resizebarwin(Monitor *m); static void resizeclient(Client *c, int x, int y, int w, int h); static void resizemouse(const Arg *arg); +static void resizerequest(XEvent *e); static void restack(Monitor *m); static void run(void); static void scan(void); -static int sendevent(Client *c, Atom proto); +static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4); static void sendmon(Client *c, Monitor *m); static void setclientstate(Client *c, long state); static void setfocus(Client *c); @@ -226,14 +239,15 @@ static void seturgent(Client *c, int urg); static void showhide(Client *c); static void sigstatusbar(const Arg *arg); static void spawn(const Arg *arg); +static Monitor *systraytomon(Monitor *m); static void tag(const Arg *arg); static void tagmon(const Arg *arg); static void tile(Monitor *m); static void togglebar(const Arg *arg); static void togglefakefullscreen(const Arg *arg); static void togglefloating(const Arg *arg); -static void togglesticky(const Arg *arg); static void togglefullscr(const Arg *arg); +static void togglesticky(const Arg *arg); static void togglescratch(const Arg *arg); static void toggletag(const Arg *arg); static void toggleview(const Arg *arg); @@ -247,25 +261,24 @@ static int updategeom(void); static void updatenumlockmask(void); static void updatesizehints(Client *c); static void updatestatus(void); +static void updatesystray(void); +static void updatesystrayicongeom(Client *i, int w, int h); +static void updatesystrayiconstate(Client *i, XPropertyEvent *ev); static void updatetitle(Client *c); static void updatewindowtype(Client *c); static void updatewmhints(Client *c); static void view(const Arg *arg); static Client *wintoclient(Window w); static Monitor *wintomon(Window w); +static Client *wintosystrayicon(Window w); static int xerror(Display *dpy, XErrorEvent *ee); static int xerrordummy(Display *dpy, XErrorEvent *ee); static int xerrorstart(Display *dpy, XErrorEvent *ee); static void zoom(const Arg *arg); -static pid_t getparentprocess(pid_t p); -static int isdescprocess(pid_t p, pid_t c); -static Client *swallowingclient(Window w); -static Client *termforwin(const Client *c); -static pid_t winpid(Window w); - /* variables */ static Client *prevzoom = NULL; +static Systray *systray = NULL; static const char broken[] = "broken"; static char stext[256]; static char fribidi_text[256]; @@ -292,9 +305,10 @@ static void (*handler[LASTEvent]) (XEvent *) = { [MapRequest] = maprequest, [MotionNotify] = motionnotify, [PropertyNotify] = propertynotify, + [ResizeRequest] = resizerequest, [UnmapNotify] = unmapnotify }; -static Atom wmatom[WMLast], netatom[NetLast]; +static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast]; static int running = 1; static Cur *cursor[CurLast]; static Clr **scheme; @@ -303,11 +317,11 @@ static Drw *drw; static Monitor *mons, *selmon; static Window root, wmcheckwin; -static xcb_connection_t *xcon; - /* configuration, allows nested code to access above variables */ #include "config.h" +static unsigned int scratchtag = 1 << LENGTH(tags); + struct Pertag { unsigned int curtag, prevtag; /* current and previous tag */ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ @@ -317,8 +331,6 @@ struct Pertag { int showbars[LENGTH(tags) + 1]; /* display bar for the current tag */ }; -static unsigned int scratchtag = 1 << LENGTH(tags); - /* compile-time check if all tags fit into an unsigned int bit array. */ struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; @@ -360,8 +372,6 @@ applyrules(Client *c) && (!r->class || strstr(class, r->class)) && (!r->instance || strstr(instance, r->instance))) { - c->isterminal = r->isterminal; - c->noswallow = r->noswallow; c->isfloating = r->isfloating; c->tags |= r->tags; for (m = mons; m && m->num != r->monitor; m = m->next); @@ -481,53 +491,6 @@ attachstack(Client *c) } void -swallow(Client *p, Client *c) -{ - - if (c->noswallow || c->isterminal) - return; - if (c->noswallow && !swallowfloating && c->isfloating) - return; - - detach(c); - detachstack(c); - - setclientstate(c, WithdrawnState); - XUnmapWindow(dpy, p->win); - - p->swallowing = c; - c->mon = p->mon; - - Window w = p->win; - p->win = c->win; - c->win = w; - updatetitle(p); - XMoveResizeWindow(dpy, p->win, p->x, p->y, p->w, p->h); - arrange(p->mon); - configure(p); - updateclientlist(); -} - -void -unswallow(Client *c) -{ - c->win = c->swallowing->win; - - free(c->swallowing); - c->swallowing = NULL; - - /* unfullscreen the client */ - setfullscreen(c, 0); - updatetitle(c); - arrange(c->mon); - XMapWindow(dpy, c->win); - XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); - setclientstate(c, NormalState); - focus(NULL); - arrange(c->mon); -} - -void buttonpress(XEvent *e) { unsigned int i, x, click; @@ -548,7 +511,7 @@ buttonpress(XEvent *e) i = x = 0; unsigned int occ = 0; for(c = m->clients; c; c=c->next) - occ |= c->tags; + occ |= c->tags == TAGMASK ? 0 : c->tags; do { /* Do not reserve space for vacant tags */ if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) @@ -560,8 +523,9 @@ buttonpress(XEvent *e) arg.ui = 1 << i; } else if (ev->x < x + TEXTW(selmon->ltsymbol)) click = ClkLtSymbol; - else if (ev->x > selmon->ww - statusw) { - x = selmon->ww - statusw; + else if (ev->x > selmon->ww - statusw - getsystraywidth()) { + x = selmon->ww - statusw - getsystraywidth(); //This wasn't there before + // x = selmon->ww - statusw; click = ClkStatusText; statussig = 0; for (text = s = stext; *s && x <= ev->x; s++) { @@ -573,7 +537,11 @@ buttonpress(XEvent *e) text = s + 1; if (x >= ev->x) break; - statussig = ch; + /* reset on matching signal raw byte */ + if (ch == statussig) + statussig = 0; + else + statussig = ch; } } } else @@ -617,6 +585,13 @@ cleanup(void) XUngrabKey(dpy, AnyKey, AnyModifier, root); while (mons) cleanupmon(mons); + + if (showsystray) { + XUnmapWindow(dpy, systray->win); + XDestroyWindow(dpy, systray->win); + free(systray); + } + for (i = 0; i < CurLast; i++) drw_cur_free(drw, cursor[i]); for (i = 0; i < LENGTH(colors); i++) @@ -648,9 +623,58 @@ cleanupmon(Monitor *mon) void clientmessage(XEvent *e) { + XWindowAttributes wa; + XSetWindowAttributes swa; XClientMessageEvent *cme = &e->xclient; Client *c = wintoclient(cme->window); + if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) { + /* add systray icons */ + if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { + if (!(c = (Client *)calloc(1, sizeof(Client)))) + die("fatal: could not malloc() %u bytes\n", sizeof(Client)); + if (!(c->win = cme->data.l[2])) { + free(c); + return; + } + c->mon = selmon; + c->next = systray->icons; + systray->icons = c; + if (!XGetWindowAttributes(dpy, c->win, &wa)) { + /* use sane defaults */ + wa.width = bh; + wa.height = bh; + wa.border_width = 0; + } + c->x = c->oldx = c->y = c->oldy = 0; + c->w = c->oldw = wa.width; + c->h = c->oldh = wa.height; + c->oldbw = wa.border_width; + c->bw = 0; + c->isfloating = True; + /* reuse tags field as mapped status */ + c->tags = 1; + updatesizehints(c); + updatesystrayicongeom(c, wa.width, wa.height); + XAddToSaveSet(dpy, c->win); + XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); + XReparentWindow(dpy, c->win, systray->win, 0, 0); + /* use parents background color */ + swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; + XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa); + sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION); + /* FIXME not sure if I have to send these events, too */ + sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION); + sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION); + sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION); + XSync(dpy, False); + resizebarwin(selmon); + updatesystray(); + setclientstate(c, NormalState); + } + return; + } + if (!c) return; if (cme->message_type == netatom[NetWMState]) { @@ -707,7 +731,7 @@ configurenotify(XEvent *e) for (c = m->clients; c; c = c->next) if (c->isfullscreen && c->fakefullscreen != 1) resizeclient(c, m->mx, m->my, m->mw, m->mh); - XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); + resizebarwin(m); } focus(NULL); arrange(NULL); @@ -807,9 +831,11 @@ destroynotify(XEvent *e) if ((c = wintoclient(ev->window))) unmanage(c, 1); - - else if ((c = swallowingclient(ev->window))) - unmanage(c->swallowing, 1); + else if ((c = wintosystrayicon(ev->window))) { + removesystrayicon(c); + resizebarwin(selmon); + updatesystray(); + } } void @@ -853,7 +879,7 @@ dirtomon(int dir) void drawbar(Monitor *m) { - int x, w, tw = 0; + int x, w, tw = 0, stw = 0; int boxs = drw->fonts->h / 9; int boxw = drw->fonts->h / 6 + 2; unsigned int i, occ = 0, urg = 0; @@ -862,6 +888,9 @@ drawbar(Monitor *m) if (!m->showbar) return; + if(showsystray && m == systraytomon(m) && !systrayonleft) + stw = getsystraywidth(); + /* draw status first so it can be overdrawn by tags later */ if (m == selmon) { /* status is only drawn on selected monitor */ char *text, *s, ch; @@ -873,19 +902,20 @@ drawbar(Monitor *m) ch = *s; *s = '\0'; tw = TEXTW(text) - lrpad; - drw_text(drw, m->ww - statusw + x, 0, tw, bh, 0, text, 0); + drw_text(drw, m->ww - statusw - stw + x, 0, tw, bh, 0, text, 0); x += tw; *s = ch; text = s + 1; } } tw = TEXTW(text) - lrpad + 2; - drw_text(drw, m->ww - statusw + x, 0, tw, bh, 0, text, 0); + drw_text(drw, m->ww - statusw - stw + x, 0, tw, bh, 0, text, 0); tw = statusw; } + resizebarwin(m); for (c = m->clients; c; c = c->next) { - occ |= c->tags; + occ |= c->tags == TAGMASK ? 0 : c->tags; if (c->isurgent) urg |= c->tags; } @@ -903,7 +933,7 @@ drawbar(Monitor *m) drw_setscheme(drw, scheme[SchemeNorm]); x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); - if ((w = m->ww - tw - x) > bh) { + if ((w = m->ww - tw - stw - x) > bh) { if (m->sel) { drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); apply_fribidi(m->sel->name); @@ -915,7 +945,7 @@ drawbar(Monitor *m) drw_rect(drw, x, 0, w, bh, 1, 1); } } - drw_map(drw, m->barwin, 0, 0, m->ww, bh); + drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh); } void @@ -952,8 +982,11 @@ expose(XEvent *e) Monitor *m; XExposeEvent *ev = &e->xexpose; - if (ev->count == 0 && (m = wintomon(ev->window))) + if (ev->count == 0 && (m = wintomon(ev->window))) { drawbar(m); + if (m == selmon) + updatesystray(); + } } Client * @@ -966,7 +999,6 @@ findbefore(Client *c) return tmp; } - void focus(Client *c) { @@ -1052,14 +1084,31 @@ getatomprop(Client *c, Atom prop) unsigned char *p = NULL; Atom da, atom = None; - if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, + /* FIXME getatomprop should return the number of items and a pointer to + * the stored data instead of this workaround */ + Atom req = XA_ATOM; + if (prop == xatom[XembedInfo]) + req = xatom[XembedInfo]; + + if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req, &da, &di, &dl, &dl, &p) == Success && p) { atom = *(Atom *)p; + if (da == xatom[XembedInfo] && dl == 2) + atom = ((Atom *)p)[1]; XFree(p); } return atom; } +unsigned int +getsystraywidth() +{ + unsigned int w = 0; + Client *i; + if(showsystray) + for(i = systray->icons; i; w += i->w + systrayspacing, i = i->next) ; + return w ? w + systrayspacing : 1; +} pid_t getstatusbarpid() @@ -1085,6 +1134,7 @@ getstatusbarpid() return strtol(buf, NULL, 10); } + int getrootptr(int *x, int *y) { @@ -1225,7 +1275,8 @@ killclient(const Arg *arg) { if (!selmon->sel) return; - if (!sendevent(selmon->sel, wmatom[WMDelete])) { + + if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) { XGrabServer(dpy); XSetErrorHandler(xerrordummy); XSetCloseDownMode(dpy, DestroyAll); @@ -1239,13 +1290,12 @@ killclient(const Arg *arg) void manage(Window w, XWindowAttributes *wa) { - Client *c, *t = NULL, *term = NULL; + Client *c, *t = NULL; Window trans = None; XWindowChanges wc; c = ecalloc(1, sizeof(Client)); c->win = w; - c->pid = winpid(w); /* geometry */ c->x = c->oldx = wa->x; c->y = c->oldy = wa->y; @@ -1260,7 +1310,6 @@ manage(Window w, XWindowAttributes *wa) } else { c->mon = selmon; applyrules(c); - term = termforwin(c); } if (c->x + WIDTH(c) > c->mon->wx + c->mon->ww) @@ -1303,8 +1352,6 @@ manage(Window w, XWindowAttributes *wa) c->mon->sel = c; arrange(c->mon); XMapWindow(dpy, c->win); - if (term) - swallow(term, c); focus(NULL); } @@ -1324,6 +1371,13 @@ maprequest(XEvent *e) static XWindowAttributes wa; XMapRequestEvent *ev = &e->xmaprequest; + Client *i; + if ((i = wintosystrayicon(ev->window))) { + sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION); + resizebarwin(selmon); + updatesystray(); + } + if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_redirect) return; if (!wintoclient(ev->window)) @@ -1399,7 +1453,7 @@ movemouse(const Arg *arg) handler[ev.type](&ev); break; case MotionNotify: - if ((ev.xmotion.time - lasttime) <= (1000 / 60)) + if ((ev.xmotion.time - lasttime) <= (1000 / refreshrate)) continue; lasttime = ev.xmotion.time; @@ -1429,6 +1483,159 @@ movemouse(const Arg *arg) } } +void +moveresize(const Arg *arg) { + /* only floating windows can be moved */ + 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; + + /* compute new window position; prevent window from be positioned outside the current monitor */ + 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 caused by the sloppy focus */ + 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); + } +} + +void +moveresizeedge(const Arg *arg) { + /* move or resize floating window to edge of screen */ + Client *c; + c = selmon->sel; + char e; + int nx, ny, nw, nh, ox, oy, ow, oh, bp; + int msx, msy, dx, dy, nmx, nmy; + int starty; + unsigned int dui; + Window dummy; + + nx = c->x; + ny = c->y; + nw = c->w; + nh = c->h; + + starty = selmon->showbar && topbar ? bh : 0; + bp = selmon->showbar && !topbar ? bh : 0; + + if (!c || !arg) + return; + if (selmon->lt[selmon->sellt]->arrange && !c->isfloating) + return; + if(sscanf((char *)arg->v, "%c", &e) != 1) + return; + + if(e == 't') + ny = starty; + + if(e == 'b') + ny = c->h > selmon->mh - 2 * c->bw ? c->h - bp : selmon->mh - c->h - 2 * c->bw - bp; + + if(e == 'l') + nx = selmon->mx; + + if(e == 'r') + nx = c->w > selmon->mw - 2 * c->bw ? selmon->mx + c->w : selmon->mx + selmon->mw - c->w - 2 * c->bw; + + if(e == 'T') { + /* if you click to resize again, it will return to old size/position */ + if(c->h + starty == c->oldh + c->oldy) { + nh = c->oldh; + ny = c->oldy; + } else { + nh = c->h + c->y - starty; + ny = starty; + } + } + + if(e == 'B') + nh = c->h + c->y + 2 * c->bw + bp == selmon->mh ? c->oldh : selmon->mh - c->y - 2 * c->bw - bp; + + if(e == 'L') { + if(selmon->mx + c->w == c->oldw + c->oldx) { + nw = c->oldw; + nx = c->oldx; + } else { + nw = c->w + c->x - selmon->mx; + nx = selmon->mx; + } + } + + if(e == 'R') + nw = c->w + c->x + 2 * c->bw == selmon->mx + selmon->mw ? c->oldw : selmon->mx + selmon->mw - c->x - 2 * c->bw; + + 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); + resizeclient(c, nx, ny, nw, nh); + + /* move cursor along with the window to avoid problems caused by the sloppy focus */ + 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); + } +} + + Client * nexttiled(Client *c) { @@ -1436,15 +1643,6 @@ nexttiled(Client *c) return c; } -/* void */ -/* pop(Client *c) */ -/* { */ -/* detach(c); */ -/* attach(c); */ -/* focus(c); */ -/* arrange(c->mon); */ -/* } */ - void propertynotify(XEvent *e) { @@ -1452,6 +1650,17 @@ propertynotify(XEvent *e) Window trans; XPropertyEvent *ev = &e->xproperty; + if ((c = wintosystrayicon(ev->window))) { + if (ev->atom == XA_WM_NORMAL_HINTS) { + updatesizehints(c); + updatesystrayicongeom(c, c->w, c->h); + } + else + updatesystrayiconstate(c, ev); + resizebarwin(selmon); + updatesystray(); + } + if ((ev->window == root) && (ev->atom == XA_WM_NAME)) updatestatus(); else if (ev->state == PropertyDelete) @@ -1482,12 +1691,6 @@ propertynotify(XEvent *e) } } -/* void */ -/* quit(const Arg *arg) */ -/* { */ -/* running = 0; */ -/* } */ - Monitor * recttomon(int x, int y, int w, int h) { @@ -1503,6 +1706,19 @@ recttomon(int x, int y, int w, int h) } void +removesystrayicon(Client *i) +{ + Client **ii; + + if (!showsystray || !i) + return; + for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next); + if (ii) + *ii = i->next; + free(i); +} + +void resize(Client *c, int x, int y, int w, int h, int interact) { if (applysizehints(c, &x, &y, &w, &h, interact)) @@ -1510,6 +1726,14 @@ resize(Client *c, int x, int y, int w, int h, int interact) } void +resizebarwin(Monitor *m) { + unsigned int w = m->ww; + if (showsystray && m == systraytomon(m) && !systrayonleft) + w -= getsystraywidth(); + XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh); +} + +void resizeclient(Client *c, int x, int y, int w, int h) { XWindowChanges wc; @@ -1536,6 +1760,19 @@ resizeclient(Client *c, int x, int y, int w, int h) } void +resizerequest(XEvent *e) +{ + XResizeRequestEvent *ev = &e->xresizerequest; + Client *i; + + if ((i = wintosystrayicon(ev->window))) { + updatesystrayicongeom(i, ev->width, ev->height); + resizebarwin(selmon); + updatesystray(); + } +} + +void resizemouse(const Arg *arg) { int ocx, ocy, nw, nh; @@ -1564,7 +1801,7 @@ resizemouse(const Arg *arg) handler[ev.type](&ev); break; case MotionNotify: - if ((ev.xmotion.time - lasttime) <= (1000 / 60)) + if ((ev.xmotion.time - lasttime) <= (1000 / refreshrate)) continue; lasttime = ev.xmotion.time; @@ -1681,26 +1918,37 @@ setclientstate(Client *c, long state) } int -sendevent(Client *c, Atom proto) +sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) { int n; - Atom *protocols; + Atom *protocols, mt; int exists = 0; XEvent ev; - if (XGetWMProtocols(dpy, c->win, &protocols, &n)) { - while (!exists && n--) - exists = protocols[n] == proto; - XFree(protocols); + if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { + mt = wmatom[WMProtocols]; + if (XGetWMProtocols(dpy, w, &protocols, &n)) { + while (!exists && n--) + exists = protocols[n] == proto; + XFree(protocols); + } } + else { + exists = True; + mt = proto; + } + if (exists) { ev.type = ClientMessage; - ev.xclient.window = c->win; - ev.xclient.message_type = wmatom[WMProtocols]; + ev.xclient.window = w; + ev.xclient.message_type = mt; ev.xclient.format = 32; - ev.xclient.data.l[0] = proto; - ev.xclient.data.l[1] = CurrentTime; - XSendEvent(dpy, c->win, False, NoEventMask, &ev); + ev.xclient.data.l[0] = d0; + ev.xclient.data.l[1] = d1; + ev.xclient.data.l[2] = d2; + ev.xclient.data.l[3] = d3; + ev.xclient.data.l[4] = d4; + XSendEvent(dpy, w, False, mask, &ev); } return exists; } @@ -1714,7 +1962,7 @@ setfocus(Client *c) XA_WINDOW, 32, PropModeReplace, (unsigned char *) &(c->win), 1); } - sendevent(c, wmatom[WMTakeFocus]); + sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); } void @@ -1756,14 +2004,14 @@ setsticky(Client *c, int sticky) { if(sticky && !c->issticky) { - XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, - PropModeReplace, (unsigned char *) &netatom[NetWMSticky], 1); - c->issticky = 1; + XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, + PropModeReplace, (unsigned char *) &netatom[NetWMSticky], 1); + c->issticky = 1; } else if(!sticky && c->issticky){ - XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, - PropModeReplace, (unsigned char *)0, 0); - c->issticky = 0; - arrange(c->mon); + XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, + PropModeReplace, (unsigned char *)0, 0); + c->issticky = 0; + arrange(c->mon); } } @@ -1832,6 +2080,10 @@ setup(void) wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); + netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False); + netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False); + netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False); + netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False); netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False); @@ -1840,6 +2092,9 @@ setup(void) netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False); + xatom[Manager] = XInternAtom(dpy, "MANAGER", False); + xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False); + xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False); /* init cursors */ cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); cursor[CurResize] = drw_cur_create(drw, XC_sizing); @@ -1848,6 +2103,8 @@ setup(void) scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); for (i = 0; i < LENGTH(colors); i++) scheme[i] = drw_scm_create(drw, colors[i], 3); + /* init system tray */ + updatesystray(); /* init bars */ updatebars(); updatestatus(); @@ -1993,7 +2250,18 @@ togglebar(const Arg *arg) { selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; updatebarpos(selmon); - XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); + resizebarwin(selmon); + if (showsystray) { + XWindowChanges wc; + if (!selmon->showbar) + wc.y = -bh; + else if (selmon->showbar) { + wc.y = 0; + if (!selmon->topbar) + wc.y = selmon->mh - bh; + } + XConfigureWindow(dpy, systray->win, CWY, &wc); + } arrange(selmon); } @@ -2048,22 +2316,6 @@ togglefloating(const Arg *arg) } void -togglefullscr(const Arg *arg) -{ - if(selmon->sel) - setfullscreen(selmon->sel, !selmon->sel->isfullscreen); -} - -void -togglesticky(const Arg *arg) -{ - if (!selmon->sel) - return; - setsticky(selmon->sel, !selmon->sel->issticky); - arrange(selmon); -} - -void togglescratch(const Arg *arg) { Client *c; @@ -2085,6 +2337,21 @@ togglescratch(const Arg *arg) spawn(arg); } +void +togglesticky(const Arg *arg) +{ + if (!selmon->sel) + return; + setsticky(selmon->sel, !selmon->sel->issticky); + arrange(selmon); +} + +void +togglefullscr(const Arg *arg) +{ + if(selmon->sel) + setfullscreen(selmon->sel, !selmon->sel->isfullscreen); +} void toggletag(const Arg *arg) @@ -2156,20 +2423,6 @@ unmanage(Client *c, int destroyed) Monitor *m = c->mon; XWindowChanges wc; - if (c->swallowing) { - unswallow(c); - return; - } - - Client *s = swallowingclient(c->win); - if (s) { - free(s->swallowing); - s->swallowing = NULL; - arrange(m); - focus(NULL); - return; - } - detach(c); detachstack(c); if (!destroyed) { @@ -2185,13 +2438,9 @@ unmanage(Client *c, int destroyed) XUngrabServer(dpy); } free(c); - - if (!s) { - arrange(m); - focus(NULL); - updateclientlist(); - } - + focus(NULL); + updateclientlist(); + arrange(m); } void @@ -2206,11 +2455,18 @@ unmapnotify(XEvent *e) else unmanage(c, 0); } + else if ((c = wintosystrayicon(ev->window))) { + /* KLUDGE! sometimes icons occasionally unmap their windows, but do + * _not_ destroy them. We map those windows back */ + XMapRaised(dpy, c->win); + updatesystray(); + } } void updatebars(void) { + unsigned int w; Monitor *m; XSetWindowAttributes wa = { .override_redirect = True, @@ -2221,10 +2477,15 @@ updatebars(void) for (m = mons; m; m = m->next) { if (m->barwin) continue; - m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen), + w = m->ww; + if (showsystray && m == systraytomon(m)) + w -= getsystraywidth(); + m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen), CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); + if (showsystray && m == systraytomon(m)) + XMapRaised(dpy, systray->win); XMapRaised(dpy, m->barwin); XSetClassHint(dpy, m->barwin, &ch); } @@ -2244,7 +2505,7 @@ updatebarpos(Monitor *m) } void -updateclientlist() +updateclientlist(void) { Client *c; Monitor *m; @@ -2400,7 +2661,6 @@ updatestatus(void) { if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) { strcpy(stext, "dwm-"VERSION); - statusw = TEXTW(stext) - lrpad + 2; } else { char *text, *s, ch; @@ -2419,6 +2679,125 @@ updatestatus(void) } drawbar(selmon); + updatesystray(); +} + + +void +updatesystrayicongeom(Client *i, int w, int h) +{ + if (i) { + i->h = bh; + if (w == h) + i->w = bh; + else if (h == bh) + i->w = w; + else + i->w = (int) ((float)bh * ((float)w / (float)h)); + applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False); + /* force icons into the systray dimensions if they don't want to */ + if (i->h > bh) { + if (i->w == i->h) + i->w = bh; + else + i->w = (int) ((float)bh * ((float)i->w / (float)i->h)); + i->h = bh; + } + } +} + +void +updatesystrayiconstate(Client *i, XPropertyEvent *ev) +{ + long flags; + int code = 0; + + if (!showsystray || !i || ev->atom != xatom[XembedInfo] || + !(flags = getatomprop(i, xatom[XembedInfo]))) + return; + + if (flags & XEMBED_MAPPED && !i->tags) { + i->tags = 1; + code = XEMBED_WINDOW_ACTIVATE; + XMapRaised(dpy, i->win); + setclientstate(i, NormalState); + } + else if (!(flags & XEMBED_MAPPED) && i->tags) { + i->tags = 0; + code = XEMBED_WINDOW_DEACTIVATE; + XUnmapWindow(dpy, i->win); + setclientstate(i, WithdrawnState); + } + else + return; + sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0, + systray->win, XEMBED_EMBEDDED_VERSION); +} + +void +updatesystray(void) +{ + XSetWindowAttributes wa; + XWindowChanges wc; + Client *i; + Monitor *m = systraytomon(NULL); + unsigned int x = m->mx + m->mw; + unsigned int sw = TEXTW(stext) - lrpad + systrayspacing; + unsigned int w = 1; + + if (!showsystray) + return; + if (systrayonleft) + x -= sw + lrpad / 2; + if (!systray) { + /* init systray */ + if (!(systray = (Systray *)calloc(1, sizeof(Systray)))) + die("fatal: could not malloc() %u bytes\n", sizeof(Systray)); + systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel][ColBg].pixel); + wa.event_mask = ButtonPressMask | ExposureMask; + wa.override_redirect = True; + wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; + XSelectInput(dpy, systray->win, SubstructureNotifyMask); + XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32, + PropModeReplace, (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1); + XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel, &wa); + XMapRaised(dpy, systray->win); + XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime); + if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) { + sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0); + XSync(dpy, False); + } + else { + fprintf(stderr, "dwm: unable to obtain system tray.\n"); + free(systray); + systray = NULL; + return; + } + } + for (w = 0, i = systray->icons; i; i = i->next) { + /* make sure the background color stays the same */ + wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; + XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa); + XMapRaised(dpy, i->win); + w += systrayspacing; + i->x = w; + XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h); + w += i->w; + if (i->mon != m) + i->mon = m; + } + w = w ? w + systrayspacing : 1; + x -= w; + XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh); + wc.x = x; wc.y = m->by; wc.width = w; wc.height = bh; + wc.stack_mode = Above; wc.sibling = m->barwin; + XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc); + XMapWindow(dpy, systray->win); + XMapSubwindows(dpy, systray->win); + /* redraw background */ + XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel); + XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh); + XSync(dpy, False); } void @@ -2436,13 +2815,13 @@ updatewindowtype(Client *c) Atom state = getatomprop(c, netatom[NetWMState]); Atom wtype = getatomprop(c, netatom[NetWMWindowType]); - if (state == netatom[NetWMFullscreen]) - setfullscreen(c, 1); - if (state == netatom[NetWMSticky]) { - setsticky(c, 1); - } - if (wtype == netatom[NetWMWindowTypeDialog]) - c->isfloating = 1; + if (state == netatom[NetWMFullscreen]) + setfullscreen(c, 1); + if (state == netatom[NetWMSticky]) { + setsticky(c, 1); + } + if (wtype == netatom[NetWMWindowTypeDialog]) + c->isfloating = 1; } void @@ -2502,136 +2881,6 @@ view(const Arg *arg) arrange(selmon); } -pid_t -winpid(Window w) -{ - - pid_t result = 0; - -#ifdef __linux__ - xcb_res_client_id_spec_t spec = {0}; - spec.client = w; - spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID; - - xcb_generic_error_t *e = NULL; - xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec); - xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e); - - if (!r) - return (pid_t)0; - - xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r); - for (; i.rem; xcb_res_client_id_value_next(&i)) { - spec = i.data->spec; - if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) { - uint32_t *t = xcb_res_client_id_value_value(i.data); - result = *t; - break; - } - } - - free(r); - - if (result == (pid_t)-1) - result = 0; - -#endif /* __linux__ */ - -#ifdef __OpenBSD__ - Atom type; - int format; - unsigned long len, bytes; - unsigned char *prop; - pid_t ret; - - if (XGetWindowProperty(dpy, w, XInternAtom(dpy, "_NET_WM_PID", 0), 0, 1, False, AnyPropertyType, &type, &format, &len, &bytes, &prop) != Success || !prop) - return 0; - - ret = *(pid_t*)prop; - XFree(prop); - result = ret; - -#endif /* __OpenBSD__ */ - return result; -} - -pid_t -getparentprocess(pid_t p) -{ - unsigned int v = 0; - -#ifdef __linux__ - FILE *f; - char buf[256]; - snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p); - - if (!(f = fopen(buf, "r"))) - return 0; - - fscanf(f, "%*u %*s %*c %u", &v); - fclose(f); -#endif /* __linux__*/ - -#ifdef __OpenBSD__ - int n; - kvm_t *kd; - struct kinfo_proc *kp; - - kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL); - if (!kd) - return 0; - - kp = kvm_getprocs(kd, KERN_PROC_PID, p, sizeof(*kp), &n); - v = kp->p_ppid; -#endif /* __OpenBSD__ */ - - return (pid_t)v; -} - -int -isdescprocess(pid_t p, pid_t c) -{ - while (p != c && c != 0) - c = getparentprocess(c); - - return (int)c; -} - -Client * -termforwin(const Client *w) -{ - Client *c; - Monitor *m; - - if (!w->pid || w->isterminal) - return NULL; - - for (m = mons; m; m = m->next) { - for (c = m->clients; c; c = c->next) { - if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid)) - return c; - } - } - - return NULL; -} - -Client * -swallowingclient(Window w) -{ - Client *c; - Monitor *m; - - for (m = mons; m; m = m->next) { - for (c = m->clients; c; c = c->next) { - if (c->swallowing && c->swallowing->win == w) - return c; - } - } - - return NULL; -} - Client * wintoclient(Window w) { @@ -2645,6 +2894,16 @@ wintoclient(Window w) return NULL; } +Client * +wintosystrayicon(Window w) { + Client *i = NULL; + + if (!showsystray || !w) + return i; + for (i = systray->icons; i && i->win != w; i = i->next) ; + return i; +} + Monitor * wintomon(Window w) { @@ -2698,11 +2957,28 @@ xerrorstart(Display *dpy, XErrorEvent *ee) return -1; } +Monitor * +systraytomon(Monitor *m) { + Monitor *t; + int i, n; + if(!systraypinning) { + if(!m) + return selmon; + return m == selmon ? m : NULL; + } + for(n = 1, t = mons; t && t->next; n++, t = t->next) ; + for(i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) ; + if(systraypinningfailfirst && n < systraypinning) + return mons; + return t; +} + void zoom(const Arg *arg) { Client *c = selmon->sel; Client *at = NULL, *cold, *cprevious = NULL; + if (!selmon->lt[selmon->sellt]->arrange || !c || c->isfloating) return; if (c == nexttiled(selmon->clients)) { @@ -2734,7 +3010,6 @@ zoom(const Arg *arg) arrange(c->mon); } - int main(int argc, char *argv[]) { @@ -2746,12 +3021,10 @@ main(int argc, char *argv[]) fputs("warning: no locale support\n", stderr); if (!(dpy = XOpenDisplay(NULL))) die("dwm: cannot open display"); - if (!(xcon = XGetXCBConnection(dpy))) - die("dwm: cannot get xcb connection\n"); checkotherwm(); setup(); #ifdef __OpenBSD__ - if (pledge("stdio rpath proc exec ps", NULL) == -1) + if (pledge("stdio rpath proc exec", NULL) == -1) die("pledge"); #endif /* __OpenBSD__ */ scan(); @@ -2760,70 +3033,3 @@ main(int argc, char *argv[]) XCloseDisplay(dpy); return EXIT_SUCCESS; } - -void -moveresize(const Arg *arg) { - /* only floating windows can be moved */ - 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; - - /* compute new window position; prevent window from be positioned outside the current monitor */ - 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 caused by the sloppy focus */ - 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); - } -} diff --git a/movestack.c b/movestack.c index 520f4ae..8d22a6b 100644 --- a/movestack.c +++ b/movestack.c @@ -45,4 +45,4 @@ movestack(const Arg *arg) { arrange(selmon); } -}
\ No newline at end of file +} @@ -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); } @@ -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); |
