dwm

dynamic window manager

git clone https://9o.is/git/dwm.git

commit 8066adbbeb8bb12244e4494312b364f9f70c244e
parent 9fe72f38758c54ecad1af757a3729043ddb95e91
Author: Jul <jul@9o.is>
Date:   Sun,  1 Feb 2026 03:52:16 -0500

preserve clients on old tags when restarting

Diffstat:
Mdwm.c | 40+++++++++++++++++++++++++++++++++++++++-
1 file changed, 39 insertions(+), 1 deletion(-)

diff --git a/dwm.c b/dwm.c @@ -61,7 +61,7 @@ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ enum { SchemeNorm, SchemeSel }; /* color schemes */ enum { NetSupported, NetWMName, NetWMState, NetWMCheck, NetWMFullscreen, NetActiveWindow, NetWMWindowType, - NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ + NetWMWindowTypeDialog, NetClientList, NetClientInfo, NetLast }; /* EWMH atoms */ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ @@ -197,6 +197,7 @@ static void scan(void); static int sendevent(Client *c, Atom proto); static void sendmon(Client *c, Monitor *m); static void setclientstate(Client *c, long state); +static void setclienttagprop(Client *c); static void setfocus(Client *c); static void setfullscreen(Client *c, int fullscreen); static void setlayout(const Arg *arg); @@ -228,6 +229,7 @@ static void updatetitle(Client *c); static void updatewindowtype(Client *c); static void updatewmhints(Client *c); static void updatecentered(Client *c); +static void updatetagprop(Client *c); static void view(const Arg *arg); static Client *wintoclient(Window w); static Monitor *wintomon(Window w); @@ -1073,6 +1075,7 @@ manage(Window w, XWindowAttributes *wa) updatesizehints(c); updatewmhints(c); updatecentered(c); + updatetagprop(c); XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); grabbuttons(c, 0); if (!c->isfloating) @@ -1435,6 +1438,7 @@ sendmon(Client *c, Monitor *m) c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ attach(c); attachstack(c); + setclienttagprop(c); focus(NULL); arrange(NULL); } @@ -1448,6 +1452,14 @@ setclientstate(Client *c, long state) PropModeReplace, (unsigned char *)data, 2); } +void +setclienttagprop(Client *c) +{ + long data[] = { (long) c->tags, (long) c->mon->num }; + XChangeProperty(dpy, c->win, netatom[NetClientInfo], XA_CARDINAL, 32, + PropModeReplace, (unsigned char *) data, 2); +} + int sendevent(Client *c, Atom proto) { @@ -1597,6 +1609,7 @@ 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); + netatom[NetClientInfo] = XInternAtom(dpy, "_NET_CLIENT_INFO", False); /* init cursors */ cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); cursor[CurResize] = drw_cur_create(drw, XC_sizing); @@ -1620,6 +1633,7 @@ setup(void) XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, PropModeReplace, (unsigned char *) netatom, NetLast); XDeleteProperty(dpy, root, netatom[NetClientList]); + XDeleteProperty(dpy, root, netatom[NetClientInfo]); /* select events */ wa.cursor = cursor[CurNormal]->cursor; wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask @@ -1703,6 +1717,7 @@ tag(const Arg *arg) { if (selmon->sel && arg->ui & TAGMASK) { selmon->sel->tags = arg->ui & TAGMASK; + setclienttagprop(selmon->sel); focus(NULL); arrange(selmon); } @@ -1777,6 +1792,7 @@ toggletag(const Arg *arg) newtags = selmon->sel->tags ^ (arg->ui & TAGMASK); if (newtags) { selmon->sel->tags = newtags; + setclienttagprop(selmon->sel); focus(NULL); arrange(selmon); } @@ -2090,6 +2106,28 @@ updatecentered(Client *c) } void +updatetagprop(Client *c) +{ + int format; + unsigned long *data, n, extra; + Monitor *m; + Atom atom; + if (XGetWindowProperty(dpy, c->win, netatom[NetClientInfo], 0L, 2L, False, XA_CARDINAL, + &atom, &format, &n, &extra, (unsigned char **)&data) == Success && n == 2) { + c->tags = *data; + for (m = mons; m; m = m->next) { + if (m->num == *(data+1)) { + c->mon = m; + break; + } + } + } + if (n > 0) + XFree(data); + setclienttagprop(c); +} + +void view(const Arg *arg) { if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])