commit: f1fb34c656fdd7dc17375214deeb3a21ea580148
parent: 8a891e2aa685f1a59505a6e39c382c8e23dcefcb
author: Chris Noxz <chris@noxz.tech>
date: Mon, 6 Feb 2023 14:34:42 +0100
Add features for a persistent state
M | dwm.c | 114 | +++++++++++++++----- |
1 file changed, 89 insertions(+), 25 deletions(-)
diff --git a/dwm.c b/dwm.c
@@ -70,7 +70,7 @@ enum { SchemeNorm, SchemeSel, SchemeTagsNorm, SchemeTagsIncl, SchemeTagsSel,
SchemeStatusAct, SchemeStatusDist, SchemeStatusNoti }; /* color schemes */
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
- NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
+ NetWMWindowTypeDialog, NetClientList, NetClientInfo, NetTagState, NetLast }; /* EWMH atoms */
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
@@ -206,7 +206,8 @@ static void grabbuttons(Client *c, int focused);
static void incgaps(const Arg *arg);
static void incnmaster(const Arg *arg);
static void killclient(const Arg *arg);
-static void load_xresources(void);
+static void loadxresources(void);
+static void loadstate(int atom_type, Window win, Client *c);
static void manage(Window w, XWindowAttributes *wa);
static void maprequest(XEvent *e);
static void monocle(Monitor *m);
@@ -219,7 +220,7 @@ static Monitor *recttomon(int x, int y, int w, int h);
static void resize(Client *c, int x, int y, int w, int h, int interact);
static void resizeclient(Client *c, int x, int y, int w, int h);
static void resizemouse(const Arg *arg);
-static void resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst);
+static void resourceload(XrmDatabase db, char *name, enum resource_type rtype, void *dst);
static void restack(Monitor *m);
static void movestack(const Arg *arg);
static void rotatestack(const Arg *arg);
@@ -228,9 +229,11 @@ 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);
+static void settagstate(void);
static void togglelayout(const Arg *arg);
static void rotatelayout(const Arg *arg);
static void setup(void);
@@ -948,7 +951,7 @@ drawbar(Monitor *m)
tagw[i] = w = TEXTW(masterclientontag[i]);
drw_setscheme(drw,
scheme[m->tagset[m->seltags] & 1 << i ? SchemeTagsSel /* selected tag */
- : selmon && selmon->sel && selmon->sel->tags & 1 << i ? SchemeTagsIncl /* client in tag */
+ : selmon && selmon->sel && selmon->sel->tags & 1 << i ? SchemeTagsIncl /* client in tag */
: SchemeTagsNorm]);
drw_text(drw, x, 0, w, bh, lrpad / 2, masterclientontag[i], urg & 1 << i);
if (m->tagset[m->seltags] & 1 << i)
@@ -1233,6 +1236,53 @@ killclient(const Arg *arg)
}
}
+void
+loadxresources(void)
+{
+ Display *display;
+ char *resm;
+ XrmDatabase db;
+ ResourcePref *p;
+
+ display = XOpenDisplay(NULL);
+ resm = XResourceManagerString(display);
+ if (!resm)
+ return;
+
+ db = XrmGetStringDatabase(resm);
+ for (p = resources; p < resources + LENGTH(resources); p++)
+ resourceload(db, p->name, p->type, p->dst);
+ XCloseDisplay(display);
+}
+
+void
+loadstate(int atom_type, Window win, Client *c)
+{
+ int format;
+ unsigned long *data, n, extra, length = (
+ atom_type == NetClientInfo ? 2L
+ : atom_type == NetTagState ? 1L
+ : 0L);
+ Monitor *m;
+ Atom atom, req_type = (
+ atom_type == NetClientInfo ? XA_CARDINAL
+ : atom_type == NetTagState ? XA_INTEGER
+ : AnyPropertyType);
+
+ if (XGetWindowProperty(dpy, win, netatom[atom_type], 0L, length, False, req_type, &atom, &format, &n, &extra, (unsigned char **)&data) == Success) {
+ if (atom_type == NetClientInfo && n == 2) {
+ c->tags = *data;
+ for (m = mons; m; m = m->next)
+ if (m->num == *(data+1) && (c->mon = m) == m)
+ break;
+ } else if (atom_type == NetTagState && n == 1) {
+ selmon->tagset[selmon->seltags] = (unsigned int)*data;
+ }
+ }
+ if (n > 0) /* clean up */
+ XFree(data);
+}
+
void
manage(Window w, XWindowAttributes *wa)
{
@@ -1278,6 +1328,9 @@ manage(Window w, XWindowAttributes *wa)
updatewindowtype(c);
updatesizehints(c);
updatewmhints(c);
+ loadstate(NetClientInfo, c->win, c);
+ setclienttagprop(c);
+
XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
grabbuttons(c, 0);
if (!c->isfloating)
@@ -1726,6 +1779,7 @@ sendmon(Client *c, Monitor *m)
c->tags = (m->tagset[m->seltags] ? m->tagset[m->seltags] : 1);
attachabove(c);
attachstack(c);
+ setclienttagprop(c);
focus(NULL);
arrange(NULL);
}
@@ -1739,6 +1793,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)
{
@@ -1818,6 +1880,15 @@ setlayout(const Arg *arg)
drawbar(selmon);
}
+void
+settagstate(void)
+{
+ if (running) {
+ long data[] = { (long)selmon->tagset[selmon->seltags] };
+ XChangeProperty(dpy, root, netatom[NetTagState], XA_INTEGER, 32, PropModeReplace, (unsigned char *) data, 1);
+ }
+}
+
void
togglelayout(const Arg *arg)
{
@@ -1896,6 +1967,8 @@ 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);
+ netatom[NetTagState] = XInternAtom(dpy, "_NET_TAG_STATE", False);
/* init cursors */
cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
cursor[CurResize] = drw_cur_create(drw, XC_sizing);
@@ -1919,6 +1992,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
@@ -1928,6 +2002,9 @@ setup(void)
XSelectInput(dpy, root, wa.event_mask);
focus(NULL);
+ /* load tag state */
+ loadstate(NetTagState, root, NULL);
+
/* fifo */
mkfifo(dwmfifo, 0600);
fifofd = open(dwmfifo, O_RDWR | O_NONBLOCK);
@@ -1993,6 +2070,7 @@ tag(const Arg *arg)
{
if (selmon->sel && arg->ui & TAGMASK) {
selmon->sel->tags = arg->ui & TAGMASK;
+ setclienttagprop(selmon->sel);
focus(NULL);
arrange(selmon);
if (viewontag)
@@ -2171,6 +2249,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);
}
@@ -2208,6 +2287,8 @@ toggleview(const Arg *arg)
focus(NULL);
arrange(selmon);
}
+
+ settagstate();
}
void
@@ -2531,6 +2612,8 @@ view(const Arg *arg)
togglebar(NULL);
focus(NULL);
arrange(selmon);
+
+ settagstate();
}
Client *
@@ -2614,7 +2697,7 @@ zoom(const Arg *arg)
}
void
-resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst)
+resourceload(XrmDatabase db, char *name, enum resource_type rtype, void *dst)
{
char *sdst = NULL;
int *idst = NULL;
@@ -2648,25 +2731,6 @@ resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst)
}
}
-void
-load_xresources(void)
-{
- Display *display;
- char *resm;
- XrmDatabase db;
- ResourcePref *p;
-
- display = XOpenDisplay(NULL);
- resm = XResourceManagerString(display);
- if (!resm)
- return;
-
- db = XrmGetStringDatabase(resm);
- for (p = resources; p < resources + LENGTH(resources); p++)
- resource_load(db, p->name, p->type, p->dst);
- XCloseDisplay(display);
-}
-
int
main(int argc, char *argv[])
{
@@ -2680,7 +2744,7 @@ main(int argc, char *argv[])
die("dwm: cannot open display");
checkotherwm();
XrmInitialize();
- load_xresources();
+ loadxresources();
setup();
#ifdef __OpenBSD__
if (pledge("stdio rpath proc exec", NULL) == -1)