Compare commits

22 Commits

Author SHA1 Message Date
BrunoCooper17
42cd641add MoveStack patch
This plugin allows you to move clients around in the stack and swap them
with the master. It emulates the behavior off mod+shift+j and mod+shift+k
in Xmonad. movestack(+1) will swap the client with the current focus with
the next client. movestack(-1) will swap the client with the current focus
with the previous client.
2026-01-22 09:30:17 +01:00
879aa682e8 apply patch dwm-winview-gaplessgrid-gridall-6.5.diff 2026-01-22 09:30:17 +01:00
explosion-mental
7aeb4c5156 shift-tools - shifttag, moves the current selected client to the adjacent tag - shifttagclients, moves the current selected client to the adjacent tag that has at least one client else acts as shifttag - shiftview, view adjacent tag - shiftviewclients, view the closes tag that has a client. If none acts as shiftview - shiftboth, shifttag and shiftview. Basically moves the window to the next/prev tag and follows it. - shiftswaptags, its a shift implementation on the swaptags function (see 65379c6264/config.h (L48) for more details), which in short 'swaps tags' (swaps all clients with the clients on the adjacent tag). A pretty useful example of this is chosing a tag empty and sending all your clients to that tag. - swapfunction is the 'helper' function for the shiftswaptags. remember that these functions **shift**, which means you can go from tag 1 to 9 or 9 to 1. Also remember that the default argument is 1 and you can change it. 2026-01-20 21:05:18 +01:00
6e62aa05e3 agree: dwm-goback with dwm-warp 2026-01-20 21:05:18 +01:00
Max Schillinger
2b9fb819c9 add patch/function 'goback' 2026-01-20 21:05:18 +01:00
2577fc5da2 agree: dwm-autodarkmode with dwm-awesomebar 2026-01-20 21:05:18 +01:00
dimarogiv
2a169de7d8 With this patch you can focus on any of the currently open windows on the current tagset with just one key combination 2026-01-20 21:05:18 +01:00
Cyril Cressent
403292696a Port the uselessgap patch to 6.2 2026-01-20 21:05:18 +01:00
Jonas Dujava
c797eece48 Warp patch
Warps the mouse cursor to the center of the currently focused
window or screen when the mouse cursor is
  (a) on a different screen, or
  (b) on top of a different window.

This version properly handles warping to windows that have not been
mapped yet (before it resulted in a change of the stack order).
See the discussion in (thanks goes to Bakkeby):
    https://github.com/bakkeby/patches/issues/60
2026-01-20 21:05:18 +01:00
ab679e3203 apply dwm-xinerama-monitors-xorder-6.4.diff 2026-01-20 21:05:18 +01:00
1d83868c91 agree: change dwm-autodarkmode signal to USR1 and leave restarsig signal to HUP 2026-01-20 21:05:18 +01:00
d55cfd204f apply patch dwm-autodarkmode-20250224-6.5.diff 2026-01-20 21:05:18 +01:00
ca03ca3348 apply patch dwm-awesomebar-20230431-6.4.diff 2026-01-20 21:05:18 +01:00
79a8bed5b1 apply patch dwm-exitmenu-6.3.diff 2026-01-20 20:26:37 +01:00
Arda Atci
bb014787b7 preserve clients on old tags when renewing dwm
By default, when dwm is recompiled-restarted all clients will
lose it's current tag and collapse to first tag. This patch preserves
clients on old tags, however note that layout order is not preserved.
2026-01-20 20:26:37 +01:00
Christopher Drelich
256cec2013 Modifies quit to handle restarts and adds SIGHUP and SIGTERM handlers.
Modified quit() to restart if it receives arg .i = 1
MOD+CTRL+SHIFT+Q was added to confid.def.h to do just that.

Signal handlers were handled for SIGHUP and SIGTERM.
If dwm receives these signals it calls quit() with
arg .i = to 1 or 0, respectively.

To restart dwm:
MOD+CTRL+SHIFT+Q
or
kill -HUP dwmpid

To quit dwm cleanly:
MOD+SHIFT+Q
or
kill -TERM dwmpid
2026-01-20 20:26:37 +01:00
Chris Down
a9aa0d8ffb dwm: Fix getatomprop regression from heap overflow fix
Commit 244fa852fe ("dwm: Fix heap buffer overflow in getatomprop")
introduced a check for dl > 0 before dereferencing the property pointer.
However, I missed that the variable dl is passed to XGetWindowProperty
for both nitems_return and bytes_after_return parameters:

    XGetWindowProperty(..., &dl, &dl, &p)

The final value in dl is bytes_after_return, not nitems_return. For a
successfully read property, bytes_after is typically 0 (indicating all
data was retrieved), so the check `dl > 0` is always false and dwm never
reads any atom properties. So this is safe, but not very helpful :-)

dl is probably just a dummy variable anyway, so fix by using a separate
variable for nitems, and check nitems > 0 as originally intended.
2026-01-16 14:13:51 +01:00
Hiltjo Posthuma
85fe518c1a bump version to 6.7
Put the maintainer at the top and bump years (time flies).
2026-01-10 11:31:44 +01:00
Chris Down
244fa852fe dwm: Fix heap buffer overflow in getatomprop
When getatomprop() is called, it invokes XGetWindowProperty() to
retrieve an Atom. If the property exists but has zero elements (length
0), Xlib returns Success and sets p to a valid, non-NULL memory address
containing a single null byte.

However, dl (that is, the number of items) is 0. dwm blindly casts p to
Atom* and dereferences it. While Xlib guarantees that p is safe to read
as a string (that is, it is null-terminated), it does _not_ guarantee it
is safe to read as an Atom (an unsigned long).

The Atom type is a typedef for unsigned long. Reading an Atom (which
thus will either likely be 4 or 8 bytes) from a 1-byte allocated buffer
results in a heap buffer overflow. Since property content is user
controlled, this allows any client to trigger an out of bounds read
simply by setting a property with format 32 and length 0.

An example client which reliably crashes dwm under ASAN:

    #include <X11/Xlib.h>
    #include <X11/Xatom.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>

    int main(void) {
        Display *d;
        Window root, w;
        Atom net_wm_state;

        d = XOpenDisplay(NULL);
        if (!d) return 1;

        root = DefaultRootWindow(d);
        w = XCreateSimpleWindow(d, root, 10, 10, 200, 200, 1, 0, 0);
        net_wm_state = XInternAtom(d, "_NET_WM_STATE", False);
        if (net_wm_state == None) return 1;

        XChangeProperty(d, w, net_wm_state, XA_ATOM, 32,
                        PropModeReplace, NULL, 0);
        XMapWindow(d, w);
        XSync(d, False);
        sleep(1);

        XCloseDisplay(d);
        return 0;
    }

In order to avoid this, check that the number of items returned is
greater than zero before dereferencing the pointer.
2026-01-10 11:27:23 +01:00
Hiltjo Posthuma
7c3abae4e6 drw.c: drw_scm_free: call free inside
Because drw_scm_create() allocates it.
2025-09-29 18:48:27 +02:00
Hiltjo Posthuma
93f26863d1 cleanup schemes and colors 2025-09-27 12:10:17 +02:00
Hiltjo Posthuma
74edc27caa config: make refreshrate for mouse move/resize a config option
Bump the default from 60 to 120.
2025-08-12 19:17:20 +02:00
9 changed files with 190 additions and 43 deletions

View File

@@ -1,5 +1,6 @@
MIT/X Consortium License
© 2010-2026 Hiltjo Posthuma <hiltjo@codemadness.org>
© 2006-2019 Anselm R Garbe <anselm@garbe.ca>
© 2006-2009 Jukka Salmi <jukka at salmi dot ch>
© 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com>
@@ -11,7 +12,6 @@ MIT/X Consortium License
© 2008 Martin Hurton <martin dot hurton at gmail dot com>
© 2008 Neale Pickett <neale dot woozle dot org>
© 2009 Mate Nagy <mnagy at port70 dot net>
© 2010-2016 Hiltjo Posthuma <hiltjo@codemadness.org>
© 2010-2012 Connor Lane Smith <cls@lubutu.com>
© 2011 Christoph Lohmann <20h@r-36.net>
© 2015-2016 Quentin Rameau <quinq@fifth.space>

View File

@@ -1,8 +1,9 @@
/* See LICENSE file for copyright and license details. */
#include "gaplessgrid.c"
/* appearance */
static const unsigned int borderpx = 2; /* border pixel of windows */
static const unsigned int gappx = 2; /* gaps between windows */
static const unsigned int borderpx = 1; /* border pixel of windows */
static const unsigned int gappx = 6; /* gaps between windows */
static const unsigned int snap = 32; /* snap pixel */
static const int showbar = 1; /* 0 means no bar */
static const int topbar = 1; /* 0 means bottom bar */
@@ -13,18 +14,16 @@ static const char col_gray2[] = "#444444";
static const char col_gray3[] = "#bbbbbb";
static const char col_gray4[] = "#eeeeee";
static const char col_cyan[] = "#005577";
static const char col_border_focus_light[] = "#df8c20"; // hsl(34 75% 50%)
static const char col_border_focus_dark[] = "#b25e34"; // hsl(20 55% 45%)
static const char *colorsdark[][3] = {
/* fg bg border */
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
[SchemeSel] = { col_gray4, col_cyan, col_border_focus_dark },
[SchemeSel] = { col_gray4, col_cyan, col_cyan },
[SchemeHid] = { col_cyan, col_gray1, col_cyan },
};
static const char *colorslight[][3] = {
/* fg bg border */
[SchemeNorm] = { col_gray1, col_gray3, col_gray2 },
[SchemeSel] = { col_cyan, col_gray4, col_border_focus_light },
[SchemeSel] = { col_cyan, col_gray4, col_cyan },
[SchemeHid] = { col_cyan, col_gray1, col_cyan },
};
@@ -46,16 +45,18 @@ 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 = 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 */
{ "[]=", tile }, /* first entry is default */
{ "><>", NULL }, /* no layout function means floating behavior */
{ "[M]", monocle },
{ "HHH", gaplessgrid },
};
/* key definitions */
#define MODKEY Mod4Mask
#define MODKEY Mod1Mask
#define TAGKEYS(KEY,TAG) \
{ MODKEY, KEY, view, {.ui = 1 << TAG} }, \
{ MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
@@ -70,20 +71,17 @@ static char dmenumon[2] = "0"; /* component of dmenu{dark,light}, manipulated in
static const char *dmenudark[] = { "dmenu_run", "-m", dmenumon, "-i", "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
static const char *dmenulight[] = { "dmenu_run", "-m", dmenumon, "-i", "-fn", dmenufont, "-nb", col_gray3, "-nf", col_gray1, "-sb", col_cyan, "-sf", col_gray4, NULL };
static const char *termcmd[] = { "st", NULL };
static const char *lockcmd[] = { "slock", NULL };
static const char *suspendcmd[] = { "systemctl", "suspend", NULL };
static const char *themecmd[] = { "lupan-set-theme", "toggle", NULL };
#include "shift-tools.c"
#include "exitdwm.c"
#include "exitdwm.c"
#include "movestack.c"
static const Key keys[] = {
/* modifier key function argument */
{ MODKEY, XK_p, spawndmenu, {0} },
{ MODKEY, XK_u, shiftview, { .i = +1 } },
{ MODKEY|ShiftMask, XK_u, shifttag, { .i = +1 } },
{ MODKEY|ShiftMask, XK_y, shifttag, { .i = -1 } },
{ MODKEY, XK_y, shiftview, { .i = -1 } },
{ MODKEY, XK_o, shiftviewclients, { .i = +1 } },
{ MODKEY|ShiftMask, XK_o, shiftview, { .i = +1 } },
{ MODKEY|ShiftMask, XK_i, shiftview, { .i = -1 } },
{ MODKEY, XK_i, shiftviewclients, { .i = -1 } },
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
{ MODKEY, XK_b, togglebar, {0} },
{ MODKEY, XK_j, focusstackvis, {.i = +1 } },
@@ -98,6 +96,8 @@ static const Key keys[] = {
{ MODKEY|ControlMask, XK_l, shiftswaptags, { .i = +1 } },
{ MODKEY|ShiftMask, XK_l, shiftboth, { .i = +1 } },
{ MODKEY, XK_l, setmfact, {.f = +0.05} },
{ MODKEY|ShiftMask, XK_j, movestack, {.i = +1 } },
{ MODKEY|ShiftMask, XK_k, movestack, {.i = -1 } },
{ MODKEY, XK_Return, zoom, {0} },
{ MODKEY, XK_Tab, view, {0} },
{ MODKEY, XK_g, goback, {0} },
@@ -125,22 +125,20 @@ static const Key keys[] = {
TAGKEYS( XK_7, 6)
TAGKEYS( XK_8, 7)
TAGKEYS( XK_9, 8)
{ ControlMask, XK_1, focusbynum, {.i = 0} },
{ ControlMask, XK_2, focusbynum, {.i = 1} },
{ ControlMask, XK_3, focusbynum, {.i = 2} },
{ ControlMask, XK_4, focusbynum, {.i = 3} },
{ ControlMask, XK_5, focusbynum, {.i = 4} },
{ ControlMask, XK_6, focusbynum, {.i = 5} },
{ ControlMask, XK_7, focusbynum, {.i = 6} },
{ ControlMask, XK_8, focusbynum, {.i = 7} },
{ ControlMask, XK_9, focusbynum, {.i = 8} },
{ MODKEY|ShiftMask, XK_j, focusbynum, {.i = 0} },
{ MODKEY|ShiftMask, XK_k, focusbynum, {.i = 1} },
{ MODKEY|ShiftMask, XK_l, focusbynum, {.i = 2} },
{ MODKEY|ShiftMask, XK_colon, focusbynum, {.i = 3} },
{ MODKEY|ShiftMask, XK_f, focusbynum, {.i = 4} },
{ MODKEY|ShiftMask, XK_d, focusbynum, {.i = 5} },
{ MODKEY|ShiftMask, XK_s, focusbynum, {.i = 6} },
{ MODKEY|ShiftMask, XK_a, focusbynum, {.i = 7} },
{ MODKEY|ShiftMask, XK_q, quit, {0} },
{ MODKEY|ControlMask|ShiftMask, XK_q, quit, {1} },
{ MODKEY|ShiftMask, XK_e, exitdwm, {0} },
{ MODKEY|ControlMask|ShiftMask, XK_s, spawn, {.v = suspendcmd } },
{ MODKEY|ControlMask|ShiftMask, XK_l, spawn, {.v = lockcmd } },
{ MODKEY|ControlMask|ShiftMask, XK_t, spawn, {.v = themecmd } },
{ MODKEY|ShiftMask, XK_e, exitdwm, {0} },
{ MODKEY, XK_o, winview, {0} },
{ MODKEY, XK_g, gridall, {} },
{ MODKEY, XK_r, winviewmono, {} },
};
/* button definitions */

View File

@@ -1,5 +1,5 @@
# dwm version
VERSION = 6.6
VERSION = 6.7
# Customize below to fit your system

29
drw.c
View File

@@ -178,8 +178,7 @@ drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
die("error, cannot allocate color '%s'", clrname);
}
/* Wrapper to create color schemes. The caller has to call free(3) on the
* returned color scheme when done using it. */
/* Create color schemes. */
Clr *
drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
{
@@ -187,7 +186,7 @@ drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
Clr *ret;
/* need at least two colors for a scheme */
if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor))))
if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(Clr))))
return NULL;
for (i = 0; i < clrcount; i++)
@@ -195,6 +194,30 @@ drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
return ret;
}
void
drw_clr_free(Drw *drw, Clr *c)
{
if (!drw || !c)
return;
/* c is typedef XftColor Clr */
XftColorFree(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
DefaultColormap(drw->dpy, drw->screen), c);
}
void
drw_scm_free(Drw *drw, Clr *scm, size_t clrcount)
{
size_t i;
if (!drw || !scm)
return;
for (i = 0; i < clrcount; i++)
drw_clr_free(drw, &scm[i]);
free(scm);
}
void
drw_setfontset(Drw *drw, Fnt *set)
{

2
drw.h
View File

@@ -40,7 +40,9 @@ void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned in
/* Colorscheme abstraction */
void drw_clr_create(Drw *drw, Clr *dest, const char *clrname);
void drw_clr_free(Drw *drw, Clr *c);
Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount);
void drw_scm_free(Drw *drw, Clr *scm, size_t clrcount);
/* Cursor abstraction */
Cur *drw_cur_create(Drw *drw, int shape);

3
dwm.1
View File

@@ -110,6 +110,9 @@ Increase master area size.
.B Mod1\-h
Decrease master area size.
.TP
.B Mod1\-o
Select view of the window in focus. The list of tags to be displayed is matched to the window tag list.
.TP
.B Mod1\-Return
Zooms/cycles focused window to/from master area (tiled layouts only).
.TP

54
dwm.c
View File

@@ -51,7 +51,6 @@
* 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 + gappx)
#define HEIGHT(X) ((X)->h + 2 * (X)->bw + gappx)
@@ -251,10 +250,13 @@ static void view(const Arg *arg);
static void warp(const Client *c);
static Client *wintoclient(Window w);
static Monitor *wintomon(Window w);
static void winview(const Arg* arg);
static int xerror(Display *dpy, XErrorEvent *ee);
static int xerrordummy(Display *dpy, XErrorEvent *ee);
static int xerrorstart(Display *dpy, XErrorEvent *ee);
static void zoom(const Arg *arg);
static void gridall(const Arg *arg);
static void winviewmono(const Arg *arg);
/* variables */
static const char broken[] = "broken";
@@ -528,8 +530,8 @@ cleanup(void)
for (i = 0; i < CurLast; i++)
drw_cur_free(drw, cursor[i]);
for (i = 0; i < LENGTH(colorsdark); i++) {
free(schemedark[i]);
free(schemelight[i]);
drw_scm_free(drw, schemedark[i], 3);
drw_scm_free(drw, schemelight[i], 3);
}
free(schemedark);
free(schemelight);
@@ -974,13 +976,14 @@ Atom
getatomprop(Client *c, Atom prop)
{
int di;
unsigned long dl;
unsigned long nitems, dl;
unsigned char *p = NULL;
Atom da, atom = None;
if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
&da, &di, &dl, &dl, &p) == Success && p) {
atom = *(Atom *)p;
&da, &di, &nitems, &dl, &p) == Success && p) {
if (nitems > 0)
atom = *(Atom *)p;
XFree(p);
}
return atom;
@@ -1351,7 +1354,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;
@@ -1545,7 +1548,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;
@@ -2496,6 +2499,41 @@ wintomon(Window w)
return selmon;
}
/* Selects for the view of the focused window. The list of tags */
/* to be displayed is matched to the focused window tag list. */
void
winview(const Arg* arg){
Window win, win_r, win_p, *win_c;
unsigned nc;
int unused;
Client* c;
Arg a;
if (!XGetInputFocus(dpy, &win, &unused)) return;
while(XQueryTree(dpy, win, &win_r, &win_p, &win_c, &nc)
&& win_p != win_r) win = win_p;
if (!(c = wintoclient(win))) return;
a.ui = c->tags;
view(&a);
}
/* by desgua */
void
gridall(const Arg *arg)
{
setlayout(&(Arg){.v = &layouts[3]});
view(&(Arg){.ui = ~0});
}
void
winviewmono(const Arg *arg)
{
winview(&(Arg){0});
setlayout(&(Arg){.v = &layouts[2]});
}
/* There's no way to check accesses to destroyed windows, thus those cases are
* ignored (especially on UnmapNotify's). Other types of errors call Xlibs
* default error handler, which may call exit. */

35
gaplessgrid.c Normal file
View File

@@ -0,0 +1,35 @@
void
gaplessgrid(Monitor *m) {
unsigned int n, cols, rows, cn, rn, i, cx, cy, cw, ch;
Client *c;
for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) ;
if(n == 0)
return;
/* grid dimensions */
for(cols = 0; cols <= n/2; cols++)
if(cols*cols >= n)
break;
if(n == 5) /* set layout against the general calculation: not 1:2:2, but 2:3 */
cols = 2;
rows = n/cols;
/* window geometries */
cw = cols ? m->ww / cols : m->ww;
cn = 0; /* current column number */
rn = 0; /* current row number */
for(i = 0, c = nexttiled(m->clients); c; i++, c = nexttiled(c->next)) {
if(i/rows + 1 > cols - n%cols)
rows = n/cols + 1;
ch = rows ? m->wh / rows : m->wh;
cx = m->wx + cn*cw;
cy = m->wy + rn*ch;
resize(c, cx, cy, cw - 2 * c->bw, ch - 2 * c->bw, False);
rn++;
if(rn >= rows) {
rn = 0;
cn++;
}
}
}

48
movestack.c Normal file
View File

@@ -0,0 +1,48 @@
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);
}
}