diff --git a/dwm.c b/dwm.c index 6cee884..dd3595e 100644 --- a/dwm.c +++ b/dwm.c @@ -55,6 +55,7 @@ #define WIDTH(X) ((X)->w + 2 * (X)->bw + gappx) #define HEIGHT(X) ((X)->h + 2 * (X)->bw + gappx) #define TAGMASK ((1 << LENGTH(tags)) - 1) +#define TAGSLENGTH (LENGTH(tags)) #define TEXTW(X) (drw_text(drw, 0, 0, 0, 0, (X), 0) + drw->fonts[0]->h) /* enums */ @@ -62,7 +63,7 @@ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ enum { SchemeNorm, SchemeSel, SchemeLast }; /* color schemes */ enum { NetSupported, NetWMName, NetWMState, NetWMFullscreen, NetActiveWindow, NetWMWindowType, - NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ + NetWMWindowTypeDialog, NetClientList, NetDesktopNames, NetDesktopViewport, NetNumberOfDesktops, NetCurrentDesktop, NetLast }; /* EWMH atoms */ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ @@ -200,11 +201,15 @@ 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 setcurrentdesktop(void); +static void setdesktopnames(void); static void setfocus(Client *c); static void setfullscreen(Client *c, int fullscreen); static void setlayout(const Arg *arg); static void setmfact(const Arg *arg); +static void setnumdesktops(void); static void setup(void); +static void setviewport(void); static void showhide(Client *c); static void sigchld(int unused); static void spawn(const Arg *arg); @@ -218,6 +223,7 @@ static void toggleview(const Arg *arg); static void unfocus(Client *c, int setfocus); static void unmanage(Client *c, int destroyed); static void unmapnotify(XEvent *e); +static void updatecurrentdesktop(void); static int updategeom(void); static void updatebarpos(Monitor *m); static void updatebars(void); @@ -1518,6 +1524,18 @@ setclientstate(Client *c, long state) XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, PropModeReplace, (unsigned char *)data, 2); } +void +setcurrentdesktop(void){ + long data[] = { 0 }; + XChangeProperty(dpy, root, netatom[NetCurrentDesktop], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); +} + +void +setdesktopnames(void){ + XTextProperty text; + Xutf8TextListToTextProperty(dpy, tags, TAGSLENGTH, XUTF8StringStyle, &text); + XSetTextProperty(dpy, root, &text, netatom[NetDesktopNames]); +} int sendevent(Client *c, Atom proto) @@ -1615,6 +1633,11 @@ setmfact(const Arg *arg) selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; arrange(selmon); } +void +setnumdesktops(void){ + long data[] = { TAGSLENGTH }; + XChangeProperty(dpy, root, netatom[NetNumberOfDesktops], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); +} void setup(void) @@ -1648,6 +1671,10 @@ 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[NetDesktopViewport] = XInternAtom(dpy, "_NET_DESKTOP_VIEWPORT", False); + netatom[NetNumberOfDesktops] = XInternAtom(dpy, "_NET_NUMBER_OF_DESKTOPS", False); + netatom[NetCurrentDesktop] = XInternAtom(dpy, "_NET_CURRENT_DESKTOP", False); + netatom[NetDesktopNames] = XInternAtom(dpy, "_NET_DESKTOP_NAMES", False); /* init cursors */ cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); cursor[CurResize] = drw_cur_create(drw, XC_sizing); @@ -1665,6 +1692,10 @@ setup(void) /* EWMH support per view */ XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, PropModeReplace, (unsigned char *) netatom, NetLast); + setnumdesktops(); + setcurrentdesktop(); + setdesktopnames(); + setviewport(); XDeleteProperty(dpy, root, netatom[NetClientList]); /* select for events */ wa.cursor = cursor[CurNormal]->cursor; @@ -1676,6 +1707,12 @@ setup(void) focus(NULL); } +void +setviewport(void){ + long data[] = { 0, 0 }; + XChangeProperty(dpy, root, netatom[NetDesktopViewport], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 2); +} + void showhide(Client *c) { @@ -1798,6 +1835,7 @@ toggletag(const Arg *arg) focus(NULL); arrange(selmon); } + updatecurrentdesktop(); } void @@ -1932,6 +1970,17 @@ updateclientlist() (unsigned char *) &(c->win), 1); } +void +updatecurrentdesktop(void){ + long rawdata[] = { selmon->tagset[selmon->seltags] }; + int i=0; + while(*rawdata >> i+1){ + i++; + } + long data[] = { i }; + XChangeProperty(dpy, root, netatom[NetCurrentDesktop], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); +} + int updategeom(void) { @@ -2153,6 +2202,7 @@ view(const Arg *arg) togglebar(NULL); focus(NULL); arrange(selmon); + updatecurrentdesktop(); } Client * diff --git a/dwm.c.orig b/dwm.c.orig index 4deb268..6cee884 100644 --- a/dwm.c.orig +++ b/dwm.c.orig @@ -111,6 +111,7 @@ typedef struct { void (*arrange)(Monitor *); } Layout; +typedef struct Pertag Pertag; struct Monitor { char ltsymbol[16]; float mfact; @@ -130,6 +131,7 @@ struct Monitor { Monitor *next; Window barwin; const Layout *lt[2]; + Pertag *pertag; }; typedef struct { @@ -270,6 +272,16 @@ static Window root; /* configuration, allows nested code to access above variables */ #include "config.h" +struct Pertag { + unsigned int curtag, prevtag; /* current and previous tag */ + int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ + float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ + unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */ + const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */ + Bool showbars[LENGTH(tags) + 1]; /* display bar for the current tag */ + Client *prevzooms[LENGTH(tags) + 1]; /* store zoom information */ +}; + /* compile-time check if all tags fit into an unsigned int bit array. */ struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; @@ -532,6 +544,7 @@ clientmessage(XEvent *e) { XClientMessageEvent *cme = &e->xclient; Client *c = wintoclient(cme->window); + int i; if (!c) return; @@ -543,6 +556,8 @@ clientmessage(XEvent *e) if (!ISVISIBLE(c)) { c->mon->seltags ^= 1; c->mon->tagset[c->mon->seltags] = c->tags; + for(i=0; !(c->tags & 1 << i); i++); + view(&(Arg){.ui = 1 << i}); } pop(c); } @@ -646,6 +661,7 @@ Monitor * createmon(void) { Monitor *m; + int i; m = ecalloc(1, sizeof(Monitor)); m->tagset[0] = m->tagset[1] = 1; @@ -656,6 +672,27 @@ createmon(void) m->lt[0] = &layouts[0]; m->lt[1] = &layouts[1 % LENGTH(layouts)]; strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); + if (!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag)))) + die("fatal: could not malloc() %u bytes\n", sizeof(Pertag)); + m->pertag->curtag = m->pertag->prevtag = 1; + for(i=0; i <= LENGTH(tags); i++) { + /* init nmaster */ + m->pertag->nmasters[i] = m->nmaster; + + /* init mfacts */ + m->pertag->mfacts[i] = m->mfact; + + /* init layouts */ + m->pertag->ltidxs[i][0] = m->lt[0]; + m->pertag->ltidxs[i][1] = m->lt[1]; + m->pertag->sellts[i] = m->sellt; + + /* init showbar */ + m->pertag->showbars[i] = m->showbar; + + /* swap focus and zoomswap*/ + m->pertag->prevzooms[i] = NULL; + } return m; } @@ -990,7 +1027,7 @@ grabkeys(void) void incnmaster(const Arg *arg) { - selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); arrange(selmon); } @@ -1550,10 +1587,13 @@ setfullscreen(Client *c, int fullscreen) void setlayout(const Arg *arg) { - if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) - selmon->sellt ^= 1; + if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) { + selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; + } if (arg && arg->v) - selmon->lt[selmon->sellt] = (Layout *)arg->v; + selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); if (selmon->sel) arrange(selmon); @@ -1572,7 +1612,7 @@ setmfact(const Arg *arg) f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; if (f < 0.1 || f > 0.9) return; - selmon->mfact = f; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; arrange(selmon); } @@ -1725,7 +1765,7 @@ tile(Monitor *m) void togglebar(const Arg *arg) { - selmon->showbar = !selmon->showbar; + selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; updatebarpos(selmon); XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); arrange(selmon); @@ -1764,9 +1804,29 @@ void toggleview(const Arg *arg) { unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); + int i; if (newtagset) { + if (newtagset == ~0) { + selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->pertag->curtag = 0; + } + /* test if the user did not select the same tag */ + if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) { + selmon->pertag->prevtag = selmon->pertag->curtag; + for (i=0; !(newtagset & 1 << i); i++) ; + selmon->pertag->curtag = i + 1; + } selmon->tagset[selmon->seltags] = newtagset; + + /* apply settings for this view */ + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; + if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) + togglebar(NULL); focus(NULL); arrange(selmon); } @@ -2064,11 +2124,33 @@ updatewmhints(Client *c) void view(const Arg *arg) { + int i; + unsigned int tmptag; + if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) return; selmon->seltags ^= 1; /* toggle sel tagset */ - if (arg->ui & TAGMASK) + if (arg->ui & TAGMASK) { + selmon->pertag->prevtag = selmon->pertag->curtag; selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; + if (arg->ui == ~0) + selmon->pertag->curtag = 0; + else { + for (i=0; !(arg->ui & 1 << i); i++) ; + selmon->pertag->curtag = i + 1; + } + } else { + tmptag = selmon->pertag->prevtag; + selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->pertag->curtag = tmptag; + } + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; + if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) + togglebar(NULL); focus(NULL); arrange(selmon); } diff --git a/patches/dwm-ewmhtags-6.1.diff b/patches/dwm-ewmhtags-6.1.diff new file mode 100644 index 0000000..7bcfa11 --- /dev/null +++ b/patches/dwm-ewmhtags-6.1.diff @@ -0,0 +1,144 @@ +diff -up dwm-6.1/dwm.c dwm-modified/dwm.c +--- dwm-6.1/dwm.c 2015-11-08 17:39:37.000000000 -0500 ++++ dwm-modified/dwm.c 2017-12-31 16:54:23.549914920 -0500 +@@ -55,6 +55,7 @@ + #define WIDTH(X) ((X)->w + 2 * (X)->bw) + #define HEIGHT(X) ((X)->h + 2 * (X)->bw) + #define TAGMASK ((1 << LENGTH(tags)) - 1) ++#define TAGSLENGTH (LENGTH(tags)) + #define TEXTW(X) (drw_text(drw, 0, 0, 0, 0, (X), 0) + drw->fonts[0]->h) + + /* enums */ +@@ -62,7 +63,7 @@ enum { CurNormal, CurResize, CurMove, Cu + enum { SchemeNorm, SchemeSel, SchemeLast }; /* color schemes */ + enum { NetSupported, NetWMName, NetWMState, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, +- NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ ++ NetWMWindowTypeDialog, NetClientList, NetDesktopNames, NetDesktopViewport, NetNumberOfDesktops, NetCurrentDesktop, NetLast }; /* EWMH atoms */ + enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ + enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, + ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ +@@ -198,11 +199,15 @@ 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 setcurrentdesktop(void); ++static void setdesktopnames(void); + static void setfocus(Client *c); + static void setfullscreen(Client *c, int fullscreen); + static void setlayout(const Arg *arg); + static void setmfact(const Arg *arg); ++static void setnumdesktops(void); + static void setup(void); ++static void setviewport(void); + static void showhide(Client *c); + static void sigchld(int unused); + static void spawn(const Arg *arg); +@@ -216,6 +221,7 @@ static void toggleview(const Arg *arg); + static void unfocus(Client *c, int setfocus); + static void unmanage(Client *c, int destroyed); + static void unmapnotify(XEvent *e); ++static void updatecurrentdesktop(void); + static int updategeom(void); + static void updatebarpos(Monitor *m); + static void updatebars(void); +@@ -1448,6 +1454,18 @@ setclientstate(Client *c, long state) + XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, + PropModeReplace, (unsigned char *)data, 2); + } ++void ++setcurrentdesktop(void){ ++ long data[] = { 0 }; ++ XChangeProperty(dpy, root, netatom[NetCurrentDesktop], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); ++} ++ ++void ++setdesktopnames(void){ ++ XTextProperty text; ++ Xutf8TextListToTextProperty(dpy, tags, TAGSLENGTH, XUTF8StringStyle, &text); ++ XSetTextProperty(dpy, root, &text, netatom[NetDesktopNames]); ++} + + int + sendevent(Client *c, Atom proto) +@@ -1542,6 +1560,11 @@ setmfact(const Arg *arg) + selmon->mfact = f; + arrange(selmon); + } ++void ++setnumdesktops(void){ ++ long data[] = { TAGSLENGTH }; ++ XChangeProperty(dpy, root, netatom[NetNumberOfDesktops], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); ++} + + void + setup(void) +@@ -1575,6 +1598,10 @@ 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[NetDesktopViewport] = XInternAtom(dpy, "_NET_DESKTOP_VIEWPORT", False); ++ netatom[NetNumberOfDesktops] = XInternAtom(dpy, "_NET_NUMBER_OF_DESKTOPS", False); ++ netatom[NetCurrentDesktop] = XInternAtom(dpy, "_NET_CURRENT_DESKTOP", False); ++ netatom[NetDesktopNames] = XInternAtom(dpy, "_NET_DESKTOP_NAMES", False); + /* init cursors */ + cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); + cursor[CurResize] = drw_cur_create(drw, XC_sizing); +@@ -1592,6 +1619,10 @@ setup(void) + /* EWMH support per view */ + XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, + PropModeReplace, (unsigned char *) netatom, NetLast); ++ setnumdesktops(); ++ setcurrentdesktop(); ++ setdesktopnames(); ++ setviewport(); + XDeleteProperty(dpy, root, netatom[NetClientList]); + /* select for events */ + wa.cursor = cursor[CurNormal]->cursor; +@@ -1604,6 +1635,12 @@ setup(void) + } + + void ++setviewport(void){ ++ long data[] = { 0, 0 }; ++ XChangeProperty(dpy, root, netatom[NetDesktopViewport], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 2); ++} ++ ++void + showhide(Client *c) + { + if (!c) +@@ -1737,6 +1774,7 @@ toggleview(const Arg *arg) + focus(NULL); + arrange(selmon); + } ++ updatecurrentdesktop(); + } + + void +@@ -1839,6 +1877,17 @@ updateclientlist() + (unsigned char *) &(c->win), 1); + } + ++void ++updatecurrentdesktop(void){ ++ long rawdata[] = { selmon->tagset[selmon->seltags] }; ++ int i=0; ++ while(*rawdata >> i+1){ ++ i++; ++ } ++ long data[] = { i }; ++ XChangeProperty(dpy, root, netatom[NetCurrentDesktop], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); ++} ++ + int + updategeom(void) + { +@@ -2038,6 +2087,7 @@ view(const Arg *arg) + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; + focus(NULL); + arrange(selmon); ++ updatecurrentdesktop(); + } + + Client *