diff options
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | config.def.h | 37 | ||||
-rw-r--r-- | config.h | 121 | ||||
-rw-r--r-- | config.mk | 2 | ||||
-rw-r--r-- | dwm.c | 276 | ||||
-rw-r--r-- | patches/dwm-awesomebar-20230431-6.4.diff | 446 | ||||
-rw-r--r-- | patches/dwm-steam-6.2.diff | 63 | ||||
-rw-r--r-- | patches/dwm-swallow-6.3.diff | 412 | ||||
-rw-r--r-- | patches/dwm-warp-6.4.diff | 79 |
9 files changed, 1389 insertions, 51 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7294fca --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.o +dwm +*.rej +*.orig diff --git a/config.def.h b/config.def.h index 9efa774..f837b4b 100644 --- a/config.def.h +++ b/config.def.h @@ -5,8 +5,8 @@ static const unsigned int borderpx = 1; /* border pixel of 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 */ -static const char *fonts[] = { "monospace:size=10" }; -static const char dmenufont[] = "monospace:size=10"; +static const char *fonts[] = { "terminus:size=13" }; +static const char dmenufont[] = "terminus:size=13"; static const char col_gray1[] = "#222222"; static const char col_gray2[] = "#444444"; static const char col_gray3[] = "#bbbbbb"; @@ -16,6 +16,7 @@ static const char *colors[][3] = { /* fg bg border */ [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, [SchemeSel] = { col_gray4, col_cyan, col_cyan }, + [SchemeHid] = { col_cyan, col_gray1, col_cyan }, }; /* tagging */ @@ -26,13 +27,14 @@ static const Rule rules[] = { * WM_CLASS(STRING) = instance, class * WM_NAME(STRING) = title */ - /* class instance title tags mask isfloating monitor */ - { "Gimp", NULL, NULL, 0, 1, -1 }, - { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, + /* class instance title tags mask isfloating monitor */ + { "Gimp", NULL, NULL, 0, 1, -1 }, + { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, + { "St", NULL, "st", 0, 0, -1 }, }; /* layout(s) */ -static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ +static const float mfact = 0.45; /* 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 */ @@ -45,7 +47,7 @@ static const Layout layouts[] = { }; /* key definitions */ -#define MODKEY Mod1Mask +#define MODKEY Mod4Mask #define TAGKEYS(KEY,TAG) \ { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ @@ -62,18 +64,17 @@ static const char *termcmd[] = { "st", NULL }; static const Key keys[] = { /* modifier key function argument */ - { MODKEY, XK_p, spawn, {.v = dmenucmd } }, - { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_d, spawn, {.v = dmenucmd } }, + { MODKEY, XK_Return, spawn, {.v = termcmd } }, { MODKEY, XK_b, togglebar, {0} }, - { MODKEY, XK_j, focusstack, {.i = +1 } }, - { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY, XK_j, focusstackvis, {.i = +1 } }, + { MODKEY, XK_k, focusstackvis, {.i = -1 } }, + { MODKEY|ShiftMask, XK_j, focusstackhid, {.i = +1 } }, + { MODKEY|ShiftMask, XK_k, focusstackhid, {.i = -1 } }, { MODKEY, XK_i, incnmaster, {.i = +1 } }, - { MODKEY, XK_d, incnmaster, {.i = -1 } }, { MODKEY, XK_h, setmfact, {.f = -0.05} }, { MODKEY, XK_l, setmfact, {.f = +0.05} }, - { MODKEY, XK_Return, zoom, {0} }, - { MODKEY, XK_Tab, view, {0} }, - { MODKEY|ShiftMask, XK_c, killclient, {0} }, + { MODKEY|ShiftMask, XK_q, killclient, {0} }, { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, @@ -85,6 +86,9 @@ static const Key keys[] = { { MODKEY, XK_period, focusmon, {.i = +1 } }, { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, + { MODKEY, XK_s, show, {0} }, + { MODKEY|ShiftMask, XK_s, showall, {0} }, + { MODKEY, XK_h, hide, {0} }, TAGKEYS( XK_1, 0) TAGKEYS( XK_2, 1) TAGKEYS( XK_3, 2) @@ -94,7 +98,7 @@ static const Key keys[] = { TAGKEYS( XK_7, 6) TAGKEYS( XK_8, 7) TAGKEYS( XK_9, 8) - { MODKEY|ShiftMask, XK_q, quit, {0} }, + { MODKEY|ShiftMask, XK_e, quit, {0} }, }; /* button definitions */ @@ -103,6 +107,7 @@ static const Button buttons[] = { /* click event mask button function argument */ { ClkLtSymbol, 0, Button1, setlayout, {0} }, { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, + { ClkWinTitle, 0, Button1, togglewin, {0} }, { ClkWinTitle, 0, Button2, zoom, {0} }, { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, { ClkClientWin, MODKEY, Button1, movemouse, {0} }, diff --git a/config.h b/config.h new file mode 100644 index 0000000..f837b4b --- /dev/null +++ b/config.h @@ -0,0 +1,121 @@ +/* See LICENSE file for copyright and license details. */ + +/* appearance */ +static const unsigned int borderpx = 1; /* border pixel of 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 */ +static const char *fonts[] = { "terminus:size=13" }; +static const char dmenufont[] = "terminus:size=13"; +static const char col_gray1[] = "#222222"; +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 *colors[][3] = { + /* fg bg border */ + [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, + [SchemeSel] = { col_gray4, col_cyan, col_cyan }, + [SchemeHid] = { col_cyan, col_gray1, col_cyan }, +}; + +/* tagging */ +static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + +static const Rule rules[] = { + /* xprop(1): + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title + */ + /* class instance title tags mask isfloating monitor */ + { "Gimp", NULL, NULL, 0, 1, -1 }, + { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, + { "St", NULL, "st", 0, 0, -1 }, +}; + +/* layout(s) */ +static const float mfact = 0.45; /* 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 Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, +}; + +/* key definitions */ +#define MODKEY Mod4Mask +#define TAGKEYS(KEY,TAG) \ + { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ + { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ + { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ + { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} }, + +/* helper for spawning shell commands in the pre dwm-5.0 fashion */ +#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } + +/* commands */ +static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ +static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; +static const char *termcmd[] = { "st", NULL }; + +static const Key keys[] = { + /* modifier key function argument */ + { MODKEY, XK_d, spawn, {.v = dmenucmd } }, + { MODKEY, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_b, togglebar, {0} }, + { MODKEY, XK_j, focusstackvis, {.i = +1 } }, + { MODKEY, XK_k, focusstackvis, {.i = -1 } }, + { MODKEY|ShiftMask, XK_j, focusstackhid, {.i = +1 } }, + { MODKEY|ShiftMask, XK_k, focusstackhid, {.i = -1 } }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, + { MODKEY, XK_h, setmfact, {.f = -0.05} }, + { MODKEY, XK_l, setmfact, {.f = +0.05} }, + { MODKEY|ShiftMask, XK_q, killclient, {0} }, + { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, + { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, + { MODKEY, XK_space, setlayout, {0} }, + { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, + { 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, show, {0} }, + { MODKEY|ShiftMask, XK_s, showall, {0} }, + { MODKEY, XK_h, hide, {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) + { MODKEY|ShiftMask, XK_e, quit, {0} }, +}; + +/* button definitions */ +/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ +static const Button buttons[] = { + /* click event mask button function argument */ + { ClkLtSymbol, 0, Button1, setlayout, {0} }, + { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, + { ClkWinTitle, 0, Button1, togglewin, {0} }, + { ClkWinTitle, 0, Button2, zoom, {0} }, + { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, + { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, + { ClkTagBar, 0, Button1, view, {0} }, + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, +}; + @@ -28,7 +28,7 @@ LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} # flags CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} #CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} -CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS} +CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -O3 -ffast-math -march=native -funroll-loops ${INCS} ${CPPFLAGS} LDFLAGS = ${LIBS} # Solaris @@ -50,6 +50,7 @@ #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])) +#define HIDDEN(C) ((getstate(C->win) == IconicState)) #define MOUSEMASK (BUTTONMASK|PointerMotionMask) #define WIDTH(X) ((X)->w + 2 * (X)->bw) #define HEIGHT(X) ((X)->h + 2 * (X)->bw) @@ -58,7 +59,7 @@ /* enums */ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ -enum { SchemeNorm, SchemeSel }; /* color schemes */ +enum { SchemeNorm, SchemeSel, SchemeHid }; /* color schemes */ enum { NetSupported, NetWMName, NetWMState, NetWMCheck, NetWMFullscreen, NetActiveWindow, NetWMWindowType, NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ @@ -92,6 +93,7 @@ struct Client { int bw, oldbw; unsigned int tags; int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; + int issteam; Client *next; Client *snext; Monitor *mon; @@ -116,6 +118,8 @@ struct Monitor { int nmaster; int num; int by; /* bar geometry */ + int btw; /* width of tasks portion of bar */ + int bt; /* number of tasks */ int mx, my, mw, mh; /* screen size */ int wx, wy, ww, wh; /* window area */ unsigned int seltags; @@ -123,6 +127,7 @@ struct Monitor { unsigned int tagset[2]; int showbar; int topbar; + int hidsel; Client *clients; Client *sel; Client *stack; @@ -167,13 +172,17 @@ static void expose(XEvent *e); static void focus(Client *c); static void focusin(XEvent *e); static void focusmon(const Arg *arg); -static void focusstack(const Arg *arg); +static void focusstackvis(const Arg *arg); +static void focusstackhid(const Arg *arg); +static void focusstack(int inc, int vis); static Atom getatomprop(Client *c, Atom prop); static int getrootptr(int *x, int *y); static long getstate(Window w); static int gettextprop(Window w, Atom atom, char *text, unsigned int size); static void grabbuttons(Client *c, int focused); static void grabkeys(void); +static void hide(const Arg *arg); +static void hidewin(Client *c); static void incnmaster(const Arg *arg); static void keypress(XEvent *e); static void killclient(const Arg *arg); @@ -203,6 +212,9 @@ static void setlayout(const Arg *arg); static void setmfact(const Arg *arg); static void setup(void); static void seturgent(Client *c, int urg); +static void show(const Arg *arg); +static void showall(const Arg *arg); +static void showwin(Client *c); static void showhide(Client *c); static void spawn(const Arg *arg); static void tag(const Arg *arg); @@ -212,6 +224,7 @@ static void togglebar(const Arg *arg); static void togglefloating(const Arg *arg); static void toggletag(const Arg *arg); static void toggleview(const Arg *arg); +static void togglewin(const Arg *arg); static void unfocus(Client *c, int setfocus); static void unmanage(Client *c, int destroyed); static void unmapnotify(XEvent *e); @@ -226,6 +239,7 @@ static void updatetitle(Client *c); static void updatewindowtype(Client *c); static void updatewmhints(Client *c); static void view(const Arg *arg); +static void warp(const Client *c); static Client *wintoclient(Window w); static Monitor *wintomon(Window w); static int xerror(Display *dpy, XErrorEvent *ee); @@ -290,6 +304,9 @@ applyrules(Client *c) class = ch.res_class ? ch.res_class : broken; instance = ch.res_name ? ch.res_name : broken; + if (strstr(class, "Steam") || strstr(class, "steam_app_")) + c->issteam = 1; + for (i = 0; i < LENGTH(rules); i++) { r = &rules[i]; if ((!r->title || strstr(c->name, r->title)) @@ -440,10 +457,25 @@ buttonpress(XEvent *e) arg.ui = 1 << i; } else if (ev->x < x + TEXTW(selmon->ltsymbol)) click = ClkLtSymbol; - else if (ev->x > selmon->ww - (int)TEXTW(stext)) + /* 2px right padding */ + else if (ev->x > selmon->ww - TEXTW(stext) + lrpad - 2) click = ClkStatusText; - else - click = ClkWinTitle; + else { + x += TEXTW(selmon->ltsymbol); + c = m->clients; + + if (c) { + do { + if (!ISVISIBLE(c)) + continue; + else + x +=(1.0 / (double)m->bt) * m->btw; + } while (ev->x > x && (c = c->next)); + + click = ClkWinTitle; + arg.v = c; + } + } } else if ((c = wintoclient(ev->window))) { focus(c); restack(selmon); @@ -453,7 +485,7 @@ buttonpress(XEvent *e) for (i = 0; i < LENGTH(buttons); i++) if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) - buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); + buttons[i].func((click == ClkTagBar || click == ClkWinTitle) && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); } void @@ -590,13 +622,15 @@ configurerequest(XEvent *e) c->bw = ev->border_width; else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) { m = c->mon; - if (ev->value_mask & CWX) { - c->oldx = c->x; - c->x = m->mx + ev->x; - } - if (ev->value_mask & CWY) { - c->oldy = c->y; - c->y = m->my + ev->y; + if (!c->issteam) { + if (ev->value_mask & CWX) { + c->oldx = c->x; + c->x = m->mx + ev->x; + } + if (ev->value_mask & CWY) { + c->oldy = c->y; + c->y = m->my + ev->y; + } } if (ev->value_mask & CWWidth) { c->oldw = c->w; @@ -697,7 +731,7 @@ dirtomon(int dir) void drawbar(Monitor *m) { - int x, w, tw = 0; + int x, w, tw = 0, n = 0, scm; int boxs = drw->fonts->h / 9; int boxw = drw->fonts->h / 6 + 2; unsigned int i, occ = 0, urg = 0; @@ -714,6 +748,8 @@ drawbar(Monitor *m) } for (c = m->clients; c; c = c->next) { + if (ISVISIBLE(c)) + n++; occ |= c->tags; if (c->isurgent) urg |= c->tags; @@ -734,16 +770,36 @@ drawbar(Monitor *m) x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); if ((w = m->ww - tw - x) > bh) { - if (m->sel) { - drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); - drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); - if (m->sel->isfloating) - drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0); + if (n > 0) { + int remainder = w % n; + int tabw = (1.0 / (double)n) * w + 1; + for (c = m->clients; c; c = c->next) { + if (!ISVISIBLE(c)) + continue; + if (m->sel == c) + scm = SchemeSel; + else if (HIDDEN(c)) + scm = SchemeHid; + else + scm = SchemeNorm; + drw_setscheme(drw, scheme[scm]); + + if (remainder >= 0) { + if (remainder == 0) { + tabw--; + } + remainder--; + } + drw_text(drw, x, 0, tabw, bh, lrpad / 2, c->name, 0); + x += tabw; + } } else { drw_setscheme(drw, scheme[SchemeNorm]); drw_rect(drw, x, 0, w, bh, 1, 1); } } + m->bt = n; + m->btw = w; drw_map(drw, m->barwin, 0, 0, m->ww, bh); } @@ -789,9 +845,17 @@ void focus(Client *c) { if (!c || !ISVISIBLE(c)) - for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext); - if (selmon->sel && selmon->sel != c) + for (c = selmon->stack; c && (!ISVISIBLE(c) || HIDDEN(c)); c = c->snext); + if (selmon->sel && selmon->sel != c) { unfocus(selmon->sel, 0); + + if (selmon->hidsel) { + hidewin(selmon->sel); + if (c) + arrange(c->mon); + selmon->hidsel = 0; + } + } if (c) { if (c->mon != selmon) selmon = c->mon; @@ -832,31 +896,56 @@ focusmon(const Arg *arg) unfocus(selmon->sel, 0); selmon = m; focus(NULL); + warp(selmon->sel); +} + +void +focusstackvis(const Arg *arg) { + focusstack(arg->i, 0); } void -focusstack(const Arg *arg) +focusstackhid(const Arg *arg) { + focusstack(arg->i, 1); +} + +void +focusstack(int inc, int hid) { Client *c = NULL, *i; - - if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen)) + // if no client selected AND exclude hidden client; if client selected but fullscreened + if ((!selmon->sel && !hid) || (selmon->sel && selmon->sel->isfullscreen && lockfullscreen)) + return; + if (!selmon->clients) return; - if (arg->i > 0) { - for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); + if (inc > 0) { + if (selmon->sel) + for (c = selmon->sel->next; + c && (!ISVISIBLE(c) || (!hid && HIDDEN(c))); + c = c->next); if (!c) - for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next); + for (c = selmon->clients; + c && (!ISVISIBLE(c) || (!hid && HIDDEN(c))); + c = c->next); } else { - for (i = selmon->clients; i != selmon->sel; i = i->next) - if (ISVISIBLE(i)) - c = i; + if (selmon->sel) { + for (i = selmon->clients; i != selmon->sel; i = i->next) + if (ISVISIBLE(i) && !(!hid && HIDDEN(i))) + c = i; + } else + c = selmon->clients; if (!c) for (; i; i = i->next) - if (ISVISIBLE(i)) + if (ISVISIBLE(i) && !(!hid && HIDDEN(i))) c = i; } if (c) { focus(c); restack(selmon); + if (HIDDEN(c)) { + showwin(c); + c->mon->hidsel = 1; + } } } @@ -977,6 +1066,36 @@ grabkeys(void) } void +hide(const Arg *arg) +{ + hidewin(selmon->sel); + focus(NULL); + arrange(selmon); +} + +void +hidewin(Client *c) { + if (!c || HIDDEN(c)) + return; + + Window w = c->win; + static XWindowAttributes ra, ca; + + // more or less taken directly from blackbox's hide() function + XGrabServer(dpy); + XGetWindowAttributes(dpy, root, &ra); + XGetWindowAttributes(dpy, w, &ca); + // prevent UnmapNotify events + XSelectInput(dpy, root, ra.your_event_mask & ~SubstructureNotifyMask); + XSelectInput(dpy, w, ca.your_event_mask & ~StructureNotifyMask); + XUnmapWindow(dpy, w); + setclientstate(c, IconicState); + XSelectInput(dpy, root, ra.your_event_mask); + XSelectInput(dpy, w, ca.your_event_mask); + XUngrabServer(dpy); +} + +void incnmaster(const Arg *arg) { selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); @@ -1078,12 +1197,14 @@ manage(Window w, XWindowAttributes *wa) XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, (unsigned char *) &(c->win), 1); XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */ - setclientstate(c, NormalState); + if (!HIDDEN(c)) + setclientstate(c, NormalState); if (c->mon == selmon) unfocus(selmon->sel, 0); c->mon->sel = c; arrange(c->mon); - XMapWindow(dpy, c->win); + if (!HIDDEN(c)) + XMapWindow(dpy, c->win); focus(NULL); } @@ -1204,7 +1325,7 @@ movemouse(const Arg *arg) Client * nexttiled(Client *c) { - for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next); + for (; c && (c->isfloating || !ISVISIBLE(c) || HIDDEN(c)); c = c->next); return c; } @@ -1257,6 +1378,16 @@ propertynotify(XEvent *e) void quit(const Arg *arg) { + // fix: reloading dwm keeps all the hidden clients hidden + Monitor *m; + Client *c; + for (m = mons; m; m = m->next) { + if (m) { + for (c = m->stack; c; c = c->next) + if (c && HIDDEN(c)) showwin(c); + } + } + running = 0; } @@ -1374,6 +1505,8 @@ restack(Monitor *m) wc.sibling = c->win; } } + if (m == selmon && (m->tagset[m->seltags] & m->sel->tags) && m->lt[m->sellt]->arrange != &monocle) + warp(m->sel); XSync(dpy, False); while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); } @@ -1626,6 +1759,42 @@ seturgent(Client *c, int urg) } void +show(const Arg *arg) +{ + if (selmon->hidsel) + selmon->hidsel = 0; + showwin(selmon->sel); +} + +void +showall(const Arg *arg) +{ + Client *c = NULL; + selmon->hidsel = 0; + for (c = selmon->clients; c; c = c->next) { + if (ISVISIBLE(c)) + showwin(c); + } + if (!selmon->sel) { + for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next); + if (c) + focus(c); + } + restack(selmon); +} + +void +showwin(Client *c) +{ + if (!c || !HIDDEN(c)) + return; + + XMapWindow(dpy, c->win); + setclientstate(c, NormalState); + arrange(c->mon); +} + +void showhide(Client *c) { if (!c) @@ -1762,6 +1931,23 @@ toggleview(const Arg *arg) } void +togglewin(const Arg *arg) +{ + Client *c = (Client*)arg->v; + + if (c == selmon->sel) { + hidewin(c); + focus(NULL); + arrange(c->mon); + } else { + if (HIDDEN(c)) + showwin(c); + focus(c); + restack(selmon); + } +} + +void unfocus(Client *c, int setfocus) { if (!c) @@ -2061,6 +2247,28 @@ view(const Arg *arg) arrange(selmon); } +void +warp(const Client *c) +{ + int x, y; + + if (!c) { + XWarpPointer(dpy, None, root, 0, 0, 0, 0, selmon->wx + selmon->ww / 2, selmon->wy + selmon->wh / 2); + return; + } + + if (!getrootptr(&x, &y) || + (x > c->x - c->bw && + y > c->y - c->bw && + x < c->x + c->w + c->bw*2 && + y < c->y + c->h + c->bw*2) || + (y > c->mon->by && y < c->mon->by + bh) || + (c->mon->topbar && !y)) + return; + + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w / 2, c->h / 2); +} + Client * wintoclient(Window w) { diff --git a/patches/dwm-awesomebar-20230431-6.4.diff b/patches/dwm-awesomebar-20230431-6.4.diff new file mode 100644 index 0000000..6ef4ee2 --- /dev/null +++ b/patches/dwm-awesomebar-20230431-6.4.diff @@ -0,0 +1,446 @@ +diff --git a/config.def.h b/config.def.h +index 061ad66..05f18e5 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -16,6 +16,7 @@ static const char *colors[][3] = { + /* fg bg border */ + [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, + [SchemeSel] = { col_gray4, col_cyan, col_cyan }, ++ [SchemeHid] = { col_cyan, col_gray1, col_cyan }, + }; + + /* tagging */ +@@ -64,8 +65,10 @@ static const Key keys[] = { + { MODKEY, XK_p, spawn, {.v = dmenucmd } }, + { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_b, togglebar, {0} }, +- { MODKEY, XK_j, focusstack, {.i = +1 } }, +- { MODKEY, XK_k, focusstack, {.i = -1 } }, ++ { MODKEY, XK_j, focusstackvis, {.i = +1 } }, ++ { MODKEY, XK_k, focusstackvis, {.i = -1 } }, ++ { MODKEY|ShiftMask, XK_j, focusstackhid, {.i = +1 } }, ++ { MODKEY|ShiftMask, XK_k, focusstackhid, {.i = -1 } }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, + { MODKEY, XK_d, incnmaster, {.i = -1 } }, + { MODKEY, XK_h, setmfact, {.f = -0.05} }, +@@ -84,6 +87,9 @@ static const Key keys[] = { + { MODKEY, XK_period, focusmon, {.i = +1 } }, + { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, ++ { MODKEY, XK_s, show, {0} }, ++ { MODKEY|ShiftMask, XK_s, showall, {0} }, ++ { MODKEY, XK_h, hide, {0} }, + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) +@@ -102,6 +108,7 @@ static const Button buttons[] = { + /* click event mask button function argument */ + { ClkLtSymbol, 0, Button1, setlayout, {0} }, + { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, ++ { ClkWinTitle, 0, Button1, togglewin, {0} }, + { ClkWinTitle, 0, Button2, zoom, {0} }, + { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, +diff --git a/dwm.c b/dwm.c +index e5efb6a..0d18e1b 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -50,6 +50,7 @@ + #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])) ++#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) +@@ -59,7 +60,7 @@ + + /* enums */ + enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ +-enum { SchemeNorm, SchemeSel }; /* color schemes */ ++enum { SchemeNorm, SchemeSel, SchemeHid }; /* color schemes */ + enum { NetSupported, NetWMName, NetWMState, NetWMCheck, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ +@@ -117,6 +118,8 @@ struct Monitor { + int nmaster; + int num; + int by; /* bar geometry */ ++ int btw; /* width of tasks portion of bar */ ++ int bt; /* number of tasks */ + int mx, my, mw, mh; /* screen size */ + int wx, wy, ww, wh; /* window area */ + unsigned int seltags; +@@ -124,6 +127,7 @@ struct Monitor { + unsigned int tagset[2]; + int showbar; + int topbar; ++ int hidsel; + Client *clients; + Client *sel; + Client *stack; +@@ -168,13 +172,17 @@ static void expose(XEvent *e); + static void focus(Client *c); + static void focusin(XEvent *e); + static void focusmon(const Arg *arg); +-static void focusstack(const Arg *arg); ++static void focusstackvis(const Arg *arg); ++static void focusstackhid(const Arg *arg); ++static void focusstack(int inc, int vis); + static Atom getatomprop(Client *c, Atom prop); + static int getrootptr(int *x, int *y); + static long getstate(Window w); + static int gettextprop(Window w, Atom atom, char *text, unsigned int size); + static void grabbuttons(Client *c, int focused); + static void grabkeys(void); ++static void hide(const Arg *arg); ++static void hidewin(Client *c); + static void incnmaster(const Arg *arg); + static void keypress(XEvent *e); + static void killclient(const Arg *arg); +@@ -204,6 +212,9 @@ static void setlayout(const Arg *arg); + static void setmfact(const Arg *arg); + static void setup(void); + static void seturgent(Client *c, int urg); ++static void show(const Arg *arg); ++static void showall(const Arg *arg); ++static void showwin(Client *c); + static void showhide(Client *c); + static void sigchld(int unused); + static void spawn(const Arg *arg); +@@ -214,6 +225,7 @@ static void togglebar(const Arg *arg); + static void togglefloating(const Arg *arg); + static void toggletag(const Arg *arg); + static void toggleview(const Arg *arg); ++static void togglewin(const Arg *arg); + static void unfocus(Client *c, int setfocus); + static void unmanage(Client *c, int destroyed); + static void unmapnotify(XEvent *e); +@@ -442,10 +454,25 @@ buttonpress(XEvent *e) + arg.ui = 1 << i; + } else if (ev->x < x + TEXTW(selmon->ltsymbol)) + click = ClkLtSymbol; +- else if (ev->x > selmon->ww - (int)TEXTW(stext)) ++ /* 2px right padding */ ++ else if (ev->x > selmon->ww - TEXTW(stext) + lrpad - 2) + click = ClkStatusText; +- else +- click = ClkWinTitle; ++ else { ++ x += TEXTW(selmon->ltsymbol); ++ c = m->clients; ++ ++ if (c) { ++ do { ++ if (!ISVISIBLE(c)) ++ continue; ++ else ++ x +=(1.0 / (double)m->bt) * m->btw; ++ } while (ev->x > x && (c = c->next)); ++ ++ click = ClkWinTitle; ++ arg.v = c; ++ } ++ } + } else if ((c = wintoclient(ev->window))) { + focus(c); + restack(selmon); +@@ -455,7 +482,7 @@ buttonpress(XEvent *e) + for (i = 0; i < LENGTH(buttons); i++) + if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button + && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) +- buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); ++ buttons[i].func((click == ClkTagBar || click == ClkWinTitle) && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); + } + + void +@@ -699,7 +726,7 @@ dirtomon(int dir) + void + drawbar(Monitor *m) + { +- int x, w, tw = 0; ++ int x, w, tw = 0, n = 0, scm; + int boxs = drw->fonts->h / 9; + int boxw = drw->fonts->h / 6 + 2; + unsigned int i, occ = 0, urg = 0; +@@ -716,6 +743,8 @@ drawbar(Monitor *m) + } + + for (c = m->clients; c; c = c->next) { ++ if (ISVISIBLE(c)) ++ n++; + occ |= c->tags; + if (c->isurgent) + urg |= c->tags; +@@ -736,16 +765,36 @@ drawbar(Monitor *m) + x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); + + if ((w = m->ww - tw - x) > bh) { +- if (m->sel) { +- drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); +- drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); +- if (m->sel->isfloating) +- drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0); ++ if (n > 0) { ++ int remainder = w % n; ++ int tabw = (1.0 / (double)n) * w + 1; ++ for (c = m->clients; c; c = c->next) { ++ if (!ISVISIBLE(c)) ++ continue; ++ if (m->sel == c) ++ scm = SchemeSel; ++ else if (HIDDEN(c)) ++ scm = SchemeHid; ++ else ++ scm = SchemeNorm; ++ drw_setscheme(drw, scheme[scm]); ++ ++ if (remainder >= 0) { ++ if (remainder == 0) { ++ tabw--; ++ } ++ remainder--; ++ } ++ drw_text(drw, x, 0, tabw, bh, lrpad / 2, c->name, 0); ++ x += tabw; ++ } + } else { + drw_setscheme(drw, scheme[SchemeNorm]); + drw_rect(drw, x, 0, w, bh, 1, 1); + } + } ++ m->bt = n; ++ m->btw = w; + drw_map(drw, m->barwin, 0, 0, m->ww, bh); + } + +@@ -791,9 +840,17 @@ void + focus(Client *c) + { + if (!c || !ISVISIBLE(c)) +- for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext); +- if (selmon->sel && selmon->sel != c) ++ for (c = selmon->stack; c && (!ISVISIBLE(c) || HIDDEN(c)); c = c->snext); ++ if (selmon->sel && selmon->sel != c) { + unfocus(selmon->sel, 0); ++ ++ if (selmon->hidsel) { ++ hidewin(selmon->sel); ++ if (c) ++ arrange(c->mon); ++ selmon->hidsel = 0; ++ } ++ } + if (c) { + if (c->mon != selmon) + selmon = c->mon; +@@ -837,28 +894,52 @@ focusmon(const Arg *arg) + } + + void +-focusstack(const Arg *arg) ++focusstackvis(const Arg *arg) { ++ focusstack(arg->i, 0); ++} ++ ++void ++focusstackhid(const Arg *arg) { ++ focusstack(arg->i, 1); ++} ++ ++void ++focusstack(int inc, int hid) + { + Client *c = NULL, *i; +- +- if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen)) ++ // if no client selected AND exclude hidden client; if client selected but fullscreened ++ if ((!selmon->sel && !hid) || (selmon->sel && selmon->sel->isfullscreen && lockfullscreen)) + return; +- if (arg->i > 0) { +- for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); ++ if (!selmon->clients) ++ return; ++ if (inc > 0) { ++ if (selmon->sel) ++ for (c = selmon->sel->next; ++ c && (!ISVISIBLE(c) || (!hid && HIDDEN(c))); ++ c = c->next); + if (!c) +- for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next); ++ for (c = selmon->clients; ++ c && (!ISVISIBLE(c) || (!hid && HIDDEN(c))); ++ c = c->next); + } else { +- for (i = selmon->clients; i != selmon->sel; i = i->next) +- if (ISVISIBLE(i)) +- c = i; ++ if (selmon->sel) { ++ for (i = selmon->clients; i != selmon->sel; i = i->next) ++ if (ISVISIBLE(i) && !(!hid && HIDDEN(i))) ++ c = i; ++ } else ++ c = selmon->clients; + if (!c) + for (; i; i = i->next) +- if (ISVISIBLE(i)) ++ if (ISVISIBLE(i) && !(!hid && HIDDEN(i))) + c = i; + } + if (c) { + focus(c); + restack(selmon); ++ if (HIDDEN(c)) { ++ showwin(c); ++ c->mon->hidsel = 1; ++ } + } + } + +@@ -968,6 +1049,36 @@ grabkeys(void) + } + } + ++void ++hide(const Arg *arg) ++{ ++ hidewin(selmon->sel); ++ focus(NULL); ++ arrange(selmon); ++} ++ ++void ++hidewin(Client *c) { ++ if (!c || HIDDEN(c)) ++ return; ++ ++ Window w = c->win; ++ static XWindowAttributes ra, ca; ++ ++ // more or less taken directly from blackbox's hide() function ++ XGrabServer(dpy); ++ XGetWindowAttributes(dpy, root, &ra); ++ XGetWindowAttributes(dpy, w, &ca); ++ // prevent UnmapNotify events ++ XSelectInput(dpy, root, ra.your_event_mask & ~SubstructureNotifyMask); ++ XSelectInput(dpy, w, ca.your_event_mask & ~StructureNotifyMask); ++ XUnmapWindow(dpy, w); ++ setclientstate(c, IconicState); ++ XSelectInput(dpy, root, ra.your_event_mask); ++ XSelectInput(dpy, w, ca.your_event_mask); ++ XUngrabServer(dpy); ++} ++ + void + incnmaster(const Arg *arg) + { +@@ -1070,12 +1181,14 @@ manage(Window w, XWindowAttributes *wa) + XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, + (unsigned char *) &(c->win), 1); + XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */ +- setclientstate(c, NormalState); ++ if (!HIDDEN(c)) ++ setclientstate(c, NormalState); + if (c->mon == selmon) + unfocus(selmon->sel, 0); + c->mon->sel = c; + arrange(c->mon); +- XMapWindow(dpy, c->win); ++ if (!HIDDEN(c)) ++ XMapWindow(dpy, c->win); + focus(NULL); + } + +@@ -1196,7 +1309,7 @@ movemouse(const Arg *arg) + Client * + nexttiled(Client *c) + { +- for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next); ++ for (; c && (c->isfloating || !ISVISIBLE(c) || HIDDEN(c)); c = c->next); + return c; + } + +@@ -1249,6 +1362,16 @@ propertynotify(XEvent *e) + void + quit(const Arg *arg) + { ++ // fix: reloading dwm keeps all the hidden clients hidden ++ Monitor *m; ++ Client *c; ++ for (m = mons; m; m = m->next) { ++ if (m) { ++ for (c = m->stack; c; c = c->next) ++ if (c && HIDDEN(c)) showwin(c); ++ } ++ } ++ + running = 0; + } + +@@ -1610,6 +1733,42 @@ seturgent(Client *c, int urg) + XFree(wmh); + } + ++void ++show(const Arg *arg) ++{ ++ if (selmon->hidsel) ++ selmon->hidsel = 0; ++ showwin(selmon->sel); ++} ++ ++void ++showall(const Arg *arg) ++{ ++ Client *c = NULL; ++ selmon->hidsel = 0; ++ for (c = selmon->clients; c; c = c->next) { ++ if (ISVISIBLE(c)) ++ showwin(c); ++ } ++ if (!selmon->sel) { ++ for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next); ++ if (c) ++ focus(c); ++ } ++ restack(selmon); ++} ++ ++void ++showwin(Client *c) ++{ ++ if (!c || !HIDDEN(c)) ++ return; ++ ++ XMapWindow(dpy, c->win); ++ setclientstate(c, NormalState); ++ arrange(c->mon); ++} ++ + void + showhide(Client *c) + { +@@ -1744,6 +1903,23 @@ toggleview(const Arg *arg) + } + } + ++void ++togglewin(const Arg *arg) ++{ ++ Client *c = (Client*)arg->v; ++ ++ if (c == selmon->sel) { ++ hidewin(c); ++ focus(NULL); ++ arrange(c->mon); ++ } else { ++ if (HIDDEN(c)) ++ showwin(c); ++ focus(c); ++ restack(selmon); ++ } ++} ++ + void + unfocus(Client *c, int setfocus) + { diff --git a/patches/dwm-steam-6.2.diff b/patches/dwm-steam-6.2.diff new file mode 100644 index 0000000..6b92c2a --- /dev/null +++ b/patches/dwm-steam-6.2.diff @@ -0,0 +1,63 @@ +From 2550931c66e10e667ce56a6761cbadd12b331c52 Mon Sep 17 00:00:00 2001 +From: bakkeby <bakkeby@gmail.com> +Date: Mon, 10 Aug 2020 16:45:00 +0200 +Subject: [PATCH] Steam patch + +Steam, and steam windows (games), trigger a ConfigureNotify request every time the window +gets focus. More so, the configure event passed along from Steam tends to have the wrong +x and y coordinates which can make the window, if floating, jump around the screen. + +This patch works around this age-old issue by ignoring the x and y co-ordinates for +ConfigureNotify requests relating to Steam windows. +--- + dwm.c | 20 +++++++++++++------- + 1 file changed, 13 insertions(+), 7 deletions(-) + +diff --git a/dwm.c b/dwm.c +index 4465af1..598d36d 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -93,6 +93,7 @@ struct Client { + int bw, oldbw; + unsigned int tags; + int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; ++ int issteam; + Client *next; + Client *snext; + Monitor *mon; +@@ -291,6 +292,9 @@ applyrules(Client *c) + class = ch.res_class ? ch.res_class : broken; + instance = ch.res_name ? ch.res_name : broken; + ++ if (strstr(class, "Steam") || strstr(class, "steam_app_")) ++ c->issteam = 1; ++ + for (i = 0; i < LENGTH(rules); i++) { + r = &rules[i]; + if ((!r->title || strstr(c->name, r->title)) +@@ -588,13 +592,15 @@ configurerequest(XEvent *e) + c->bw = ev->border_width; + else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) { + m = c->mon; +- if (ev->value_mask & CWX) { +- c->oldx = c->x; +- c->x = m->mx + ev->x; +- } +- if (ev->value_mask & CWY) { +- c->oldy = c->y; +- c->y = m->my + ev->y; ++ if (!c->issteam) { ++ if (ev->value_mask & CWX) { ++ c->oldx = c->x; ++ c->x = m->mx + ev->x; ++ } ++ if (ev->value_mask & CWY) { ++ c->oldy = c->y; ++ c->y = m->my + ev->y; ++ } + } + if (ev->value_mask & CWWidth) { + c->oldw = c->w; +-- +2.19.1 + diff --git a/patches/dwm-swallow-6.3.diff b/patches/dwm-swallow-6.3.diff new file mode 100644 index 0000000..47586a0 --- /dev/null +++ b/patches/dwm-swallow-6.3.diff @@ -0,0 +1,412 @@ +From 0cf9a007511f7dfd7dd94171b172562ebac9b6d5 Mon Sep 17 00:00:00 2001 +From: Tom Schwindl <schwindl@posteo.de> +Date: Sat, 10 Sep 2022 12:51:09 +0200 +Subject: [PATCH] 6.3 swallow patch + +--- + config.def.h | 9 +- + config.mk | 3 +- + dwm.c | 235 +++++++++++++++++++++++++++++++++++++++++++++++++-- + 3 files changed, 237 insertions(+), 10 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 061ad662f82a..0b2b8ffd30d5 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -3,6 +3,7 @@ + /* appearance */ + static const unsigned int borderpx = 1; /* 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 int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 means bottom bar */ + static const char *fonts[] = { "monospace:size=10" }; +@@ -26,9 +27,11 @@ static const Rule rules[] = { + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title + */ +- /* class instance title tags mask isfloating monitor */ +- { "Gimp", NULL, NULL, 0, 1, -1 }, +- { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, ++ /* class instance title tags mask isfloating isterminal noswallow monitor */ ++ { "Gimp", NULL, NULL, 0, 1, 0, 0, -1 }, ++ { "Firefox", NULL, NULL, 1 << 8, 0, 0, -1, -1 }, ++ { "St", NULL, NULL, 0, 0, 1, 0, -1 }, ++ { NULL, NULL, "Event Tester", 0, 0, 0, 1, -1 }, /* xev */ + }; + + /* layout(s) */ +diff --git a/config.mk b/config.mk +index 81c493ef4aff..52d1ebf30bec 100644 +--- a/config.mk ++++ b/config.mk +@@ -20,10 +20,11 @@ FREETYPEINC = /usr/include/freetype2 + # OpenBSD (uncomment) + #FREETYPEINC = ${X11INC}/freetype2 + #MANPREFIX = ${PREFIX}/man ++#KVMLIB = -lkvm + + # includes and libs + INCS = -I${X11INC} -I${FREETYPEINC} +-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ++LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lX11-xcb -lxcb -lxcb-res ${KVMLIB} + + # flags + CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +diff --git a/dwm.c b/dwm.c +index e5efb6a22806..e68294b6b679 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -40,6 +40,12 @@ + #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" +@@ -92,9 +98,11 @@ 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; ++ int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow; ++ pid_t pid; + Client *next; + Client *snext; ++ Client *swallowing; + Monitor *mon; + Window win; + }; +@@ -138,6 +146,8 @@ typedef struct { + const char *title; + unsigned int tags; + int isfloating; ++ int isterminal; ++ int noswallow; + int monitor; + } Rule; + +@@ -235,6 +245,12 @@ 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 const char broken[] = "broken"; + static char stext[256]; +@@ -269,6 +285,8 @@ 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" + +@@ -298,6 +316,8 @@ 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); +@@ -416,6 +436,53 @@ attachstack(Client *c) + c->mon->stack = 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) + { +@@ -656,6 +723,9 @@ destroynotify(XEvent *e) + + if ((c = wintoclient(ev->window))) + unmanage(c, 1); ++ ++ else if ((c = swallowingclient(ev->window))) ++ unmanage(c->swallowing, 1); + } + + void +@@ -1022,12 +1092,13 @@ killclient(const Arg *arg) + void + manage(Window w, XWindowAttributes *wa) + { +- Client *c, *t = NULL; ++ Client *c, *t = NULL, *term = 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; +@@ -1042,6 +1113,7 @@ 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) +@@ -1076,6 +1148,8 @@ manage(Window w, XWindowAttributes *wa) + c->mon->sel = c; + arrange(c->mon); + XMapWindow(dpy, c->win); ++ if (term) ++ swallow(term, c); + focus(NULL); + } + +@@ -1763,6 +1837,20 @@ 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) { +@@ -1778,9 +1866,12 @@ unmanage(Client *c, int destroyed) + XUngrabServer(dpy); + } + free(c); +- focus(NULL); +- updateclientlist(); +- arrange(m); ++ ++ if (!s) { ++ arrange(m); ++ focus(NULL); ++ updateclientlist(); ++ } + } + + void +@@ -2044,6 +2135,136 @@ 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) + { +@@ -2133,10 +2354,12 @@ 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", NULL) == -1) ++ if (pledge("stdio rpath proc exec ps", NULL) == -1) + die("pledge"); + #endif /* __OpenBSD__ */ + scan(); +-- +2.37.2 + diff --git a/patches/dwm-warp-6.4.diff b/patches/dwm-warp-6.4.diff new file mode 100644 index 0000000..02fcdba --- /dev/null +++ b/patches/dwm-warp-6.4.diff @@ -0,0 +1,79 @@ +From a229c36f51ad6f8b40109ed53c643f242351962a Mon Sep 17 00:00:00 2001 +From: Jonas Dujava <jonas.dujava@gmail.com> +Date: Fri, 26 May 2023 22:14:48 +0200 +Subject: [PATCH] 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 +--- + dwm.c | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/dwm.c b/dwm.c +index e5efb6a..7ea6c14 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -228,6 +228,7 @@ static void updatetitle(Client *c); + static void updatewindowtype(Client *c); + static void updatewmhints(Client *c); + static void view(const Arg *arg); ++static void warp(const Client *c); + static Client *wintoclient(Window w); + static Monitor *wintomon(Window w); + static int xerror(Display *dpy, XErrorEvent *ee); +@@ -834,6 +835,7 @@ focusmon(const Arg *arg) + unfocus(selmon->sel, 0); + selmon = m; + focus(NULL); ++ warp(selmon->sel); + } + + void +@@ -1366,6 +1368,8 @@ restack(Monitor *m) + wc.sibling = c->win; + } + } ++ if (m == selmon && (m->tagset[m->seltags] & m->sel->tags) && m->lt[m->sellt]->arrange != &monocle) ++ warp(m->sel); + XSync(dpy, False); + while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); + } +@@ -2044,6 +2048,28 @@ view(const Arg *arg) + arrange(selmon); + } + ++void ++warp(const Client *c) ++{ ++ int x, y; ++ ++ if (!c) { ++ XWarpPointer(dpy, None, root, 0, 0, 0, 0, selmon->wx + selmon->ww / 2, selmon->wy + selmon->wh / 2); ++ return; ++ } ++ ++ if (!getrootptr(&x, &y) || ++ (x > c->x - c->bw && ++ y > c->y - c->bw && ++ x < c->x + c->w + c->bw*2 && ++ y < c->y + c->h + c->bw*2) || ++ (y > c->mon->by && y < c->mon->by + bh) || ++ (c->mon->topbar && !y)) ++ return; ++ ++ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w / 2, c->h / 2); ++} ++ + Client * + wintoclient(Window w) + { +-- +2.40.1 + |