diff --git a/dwm/.dwm/config.def.h b/dwm/.dwm/config.def.h index 833e343..be03226 100644 --- a/dwm/.dwm/config.def.h +++ b/dwm/.dwm/config.def.h @@ -25,6 +25,7 @@ static char *colors[][3] = { /* fg bg border */ [SchemeNorm] = { normfgcolor, normbgcolor, normbordercolor }, [SchemeSel] = { selfgcolor, selbgcolor, selbordercolor }, + [SchemeHid] = { selbordercolor, normbgcolor, selbordercolor }, }; /* tagging */ @@ -82,8 +83,10 @@ static const Key keys[] = { { MODKEY, XK_grave, togglescratch, {.v = scratchpadcmd } }, { MODKEY, XK_b, togglebar, {0} }, { MODKEY, XK_w, tabmode, {-1} }, - { 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} }, @@ -106,6 +109,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} }, { MODKEY, XK_F5, xrdb, {.v = NULL } }, TAGKEYS( XK_1, 0) TAGKEYS( XK_2, 1) @@ -126,6 +132,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/.dwm/config.def.h.orig b/dwm/.dwm/config.def.h.orig index 378e25e..833e343 100644 --- a/dwm/.dwm/config.def.h.orig +++ b/dwm/.dwm/config.def.h.orig @@ -7,6 +7,12 @@ 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 int user_bh = 0; /* 0 means that dwm will calculate bar height, >= 1 means dwm will user_bh as bar height */ +/* Display modes of the tab bar: never shown, always shown, shown only in */ +/* monocle mode in the presence of several windows. */ +/* Modes after showtab_nmodes are disabled. */ +enum showtab_modes { showtab_never, showtab_auto, showtab_nmodes, showtab_always}; +static const int showtab = showtab_auto; /* Default tab bar show mode */ +static const int toptab = False; /* False means bottom tab bar */ static const char *fonts[] = { "monospace:size=10" }; static const char dmenufont[] = "monospace:size=10"; static char normbgcolor[] = "#222222"; @@ -75,6 +81,7 @@ static const Key keys[] = { { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, { MODKEY, XK_grave, togglescratch, {.v = scratchpadcmd } }, { MODKEY, XK_b, togglebar, {0} }, + { MODKEY, XK_w, tabmode, {-1} }, { MODKEY, XK_j, focusstack, {.i = +1 } }, { MODKEY, XK_k, focusstack, {.i = -1 } }, { MODKEY, XK_i, incnmaster, {.i = +1 } }, @@ -128,5 +135,6 @@ static const Button buttons[] = { { ClkTagBar, 0, Button3, toggleview, {0} }, { ClkTagBar, MODKEY, Button1, tag, {0} }, { ClkTagBar, MODKEY, Button3, toggletag, {0} }, + { ClkTabBar, 0, Button1, focuswin, {0} }, }; diff --git a/dwm/.dwm/config.def.h.rej b/dwm/.dwm/config.def.h.rej index c5a67f3..836fac2 100644 --- a/dwm/.dwm/config.def.h.rej +++ b/dwm/.dwm/config.def.h.rej @@ -1,16 +1,33 @@ ---- config.def.h 2019-02-02 04:55:28.000000000 -0800 -+++ config.def.h 2019-07-12 11:40:50.530164308 -0700 -@@ -5,6 +5,13 @@ static const unsigned int borderpx = 1; - 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 */ -+/* Display modes of the tab bar: never shown, always shown, shown only in */ -+/* monocle mode in the presence of several windows. */ -+/* Modes after showtab_nmodes are disabled. */ -+enum showtab_modes { showtab_never, showtab_auto, showtab_nmodes, showtab_always}; -+static const int showtab = showtab_auto; /* Default tab bar show mode */ -+static const int toptab = False; /* False means bottom tab bar */ -+ - static const char *fonts[] = { "monospace:size=10" }; - static const char dmenufont[] = "monospace:size=10"; - static const char col_gray1[] = "#222222"; +--- config.def.h ++++ 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 */ +@@ -65,8 +66,10 @@ static 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} }, +@@ -85,6 +88,9 @@ static 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) diff --git a/dwm/.dwm/dwm.c b/dwm/.dwm/dwm.c index a5d14bb..467cda9 100644 --- a/dwm/.dwm/dwm.c +++ b/dwm/.dwm/dwm.c @@ -53,6 +53,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 + gappx) @@ -77,7 +78,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 */ @@ -138,6 +139,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 ty; /* tab bar geometry */ int mx, my, mw, mh; /* screen size */ int wx, wy, ww, wh; /* window area */ @@ -148,6 +151,7 @@ struct Monitor { int showtab; int topbar; int toptab; + int hidsel; Client *clients; Client *sel; Client *stack; @@ -198,7 +202,9 @@ 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 void focuswin(const Arg* arg); static Atom getatomprop(Client *c, Atom prop); static int getrootptr(int *x, int *y); @@ -206,6 +212,8 @@ 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); @@ -238,6 +246,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 sighup(int unused); static void sigterm(int unused); @@ -251,6 +262,7 @@ static void togglefloating(const Arg *arg); static void togglescratch(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); @@ -473,6 +485,7 @@ attachstack(Client *c) void buttonpress(XEvent *e) { + int blw = TEXTW(selmon->ltsymbol); unsigned int i, x, click; Arg arg = {0}; Client *c; @@ -496,10 +509,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 += blw; + 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; + } + } } if(ev->window == selmon->tabwin) { i = 0; x = 0; @@ -526,7 +554,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 || click == ClkTabBar) && 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); } } @@ -808,7 +836,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; @@ -825,6 +853,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; @@ -845,16 +875,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); } @@ -1001,9 +1051,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; @@ -1048,28 +1106,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; + } } } @@ -1202,6 +1284,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) { @@ -1343,12 +1455,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); } @@ -1469,7 +1583,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; } @@ -1525,6 +1639,16 @@ void quit(const Arg *arg) { if(arg->i) restart = 1; + // 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; } @@ -2012,6 +2136,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) { @@ -2188,6 +2348,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/dwm/.dwm/dwm.c.orig b/dwm/.dwm/dwm.c.orig index f9dafdd..a5d14bb 100644 --- a/dwm/.dwm/dwm.c.orig +++ b/dwm/.dwm/dwm.c.orig @@ -82,7 +82,7 @@ enum { NetSupported, NetWMName, NetWMState, NetWMCheck, NetWMFullscreen, NetActiveWindow, NetWMWindowType, NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ -enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, +enum { ClkTagBar, ClkTabBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ typedef union { @@ -130,24 +130,32 @@ typedef struct { void (*arrange)(Monitor *); } Layout; +#define MAXTABS 50 + struct Monitor { char ltsymbol[16]; float mfact; int nmaster; int num; int by; /* bar geometry */ + int ty; /* tab bar geometry */ int mx, my, mw, mh; /* screen size */ int wx, wy, ww, wh; /* window area */ unsigned int seltags; unsigned int sellt; unsigned int tagset[2]; int showbar; + int showtab; int topbar; + int toptab; Client *clients; Client *sel; Client *stack; Monitor *next; Window barwin; + Window tabwin; + int ntabs; + int tab_widths[MAXTABS]; const Layout *lt[2]; }; @@ -183,12 +191,15 @@ static void detachstack(Client *c); static Monitor *dirtomon(int dir); static void drawbar(Monitor *m); static void drawbars(void); +static void drawtab(Monitor *m); +static void drawtabs(void); static void enternotify(XEvent *e); 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 focuswin(const Arg* arg); static Atom getatomprop(Client *c, Atom prop); static int getrootptr(int *x, int *y); static long getstate(Window w); @@ -231,6 +242,7 @@ static void showhide(Client *c); static void sighup(int unused); static void sigterm(int unused); static void spawn(const Arg *arg); +static void tabmode(const Arg *arg); static void tag(const Arg *arg); static void tagmon(const Arg *arg); static void tile(Monitor *m); @@ -273,6 +285,7 @@ static char stext[256]; static int screen; static int sw, sh; /* X display screen geometry width, height */ static int bh; /* bar height */ +static int th = 0; /* tab bar geometry */ static int lrpad; /* sum of left and right padding for text */ static int (*xerrorxlib)(Display *, XErrorEvent *); static unsigned int numlockmask = 0; @@ -435,8 +448,9 @@ arrange(Monitor *m) } void -arrangemon(Monitor *m) -{ +arrangemon(Monitor *m) { + updatebarpos(m); + XMoveResizeWindow(dpy, m->tabwin, m->wx, m->ty, m->ww, th); strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); if (m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); @@ -486,7 +500,24 @@ buttonpress(XEvent *e) click = ClkStatusText; else click = ClkWinTitle; - } else if ((c = wintoclient(ev->window))) { + } + if(ev->window == selmon->tabwin) { + i = 0; x = 0; + for(c = selmon->clients; c; c = c->next){ + if(!ISVISIBLE(c)) continue; + x += selmon->tab_widths[i]; + if (ev->x > x) + ++i; + else + break; + if(i >= m->ntabs) break; + } + if(c) { + click = ClkTabBar; + arg.ui = i; + } + } + else if((c = wintoclient(ev->window))) { focus(c); restack(selmon); XAllowEvents(dpy, ReplayPointer, CurrentTime); @@ -494,8 +525,9 @@ 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); + && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)){ + buttons[i].func(((click == ClkTagBar || click == ClkTabBar) && buttons[i].arg.i == 0) ? &arg : &buttons[i].arg); + } } void @@ -550,6 +582,8 @@ cleanupmon(Monitor *mon) } XUnmapWindow(dpy, mon->barwin); XDestroyWindow(dpy, mon->barwin); + XUnmapWindow(dpy, mon->tabwin); + XDestroyWindow(dpy, mon->tabwin); free(mon); } @@ -713,7 +747,10 @@ createmon(void) m->mfact = mfact; m->nmaster = nmaster; m->showbar = showbar; + m->showtab = showtab; m->topbar = topbar; + m->toptab = toptab; + m->ntabs = 0; m->lt[0] = &layouts[0]; m->lt[1] = &layouts[1 % LENGTH(layouts)]; strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); @@ -830,6 +867,105 @@ drawbars(void) drawbar(m); } +void +drawtabs(void) { + Monitor *m; + + for(m = mons; m; m = m->next) + drawtab(m); +} + +static int +cmpint(const void *p1, const void *p2) { + /* The actual arguments to this function are "pointers to + pointers to char", but strcmp(3) arguments are "pointers + to char", hence the following cast plus dereference */ + return *((int*) p1) > * (int*) p2; +} + + +void +drawtab(Monitor *m) { + Client *c; + int i; + int itag = -1; + char view_info[50]; + int view_info_w = 0; + int sorted_label_widths[MAXTABS]; + int tot_width; + int maxsize = bh; + int x = 0; + int w = 0; + + //view_info: indicate the tag which is displayed in the view + for(i = 0; i < LENGTH(tags); ++i){ + if((selmon->tagset[selmon->seltags] >> i) & 1) { + if(itag >=0){ //more than one tag selected + itag = -1; + break; + } + itag = i; + } + } + + if(0 <= itag && itag < LENGTH(tags)){ + snprintf(view_info, sizeof view_info, "[%s]", tags[itag]); + } else { + strncpy(view_info, "[...]", sizeof view_info); + } + view_info[sizeof(view_info) - 1 ] = 0; + view_info_w = TEXTW(view_info); + tot_width = view_info_w; + + /* Calculates number of labels and their width */ + m->ntabs = 0; + for(c = m->clients; c; c = c->next){ + if(!ISVISIBLE(c)) continue; + m->tab_widths[m->ntabs] = TEXTW(c->name); + tot_width += m->tab_widths[m->ntabs]; + ++m->ntabs; + if(m->ntabs >= MAXTABS) break; + } + + if(tot_width > m->ww){ //not enough space to display the labels, they need to be truncated + memcpy(sorted_label_widths, m->tab_widths, sizeof(int) * m->ntabs); + qsort(sorted_label_widths, m->ntabs, sizeof(int), cmpint); + tot_width = view_info_w; + for(i = 0; i < m->ntabs; ++i){ + if(tot_width + (m->ntabs - i) * sorted_label_widths[i] > m->ww) + break; + tot_width += sorted_label_widths[i]; + } + maxsize = (m->ww - tot_width) / (m->ntabs - i); + } else{ + maxsize = m->ww; + } + i = 0; + for(c = m->clients; c; c = c->next){ + if(!ISVISIBLE(c)) continue; + if(i >= m->ntabs) break; + if(m->tab_widths[i] > maxsize) m->tab_widths[i] = maxsize; + w = m->tab_widths[i]; + drw_setscheme(drw, scheme[(c == m->sel) ? SchemeSel : SchemeNorm]); + drw_text(drw, x, 0, w, th, 0, c->name, 0); + x += w; + ++i; + } + + drw_setscheme(drw, scheme[SchemeNorm]); + + /* cleans interspace between window names and current viewed tag label */ + w = m->ww - view_info_w - x; + drw_text(drw, x, 0, w, th, 0, "", 0); + + /* view info */ + x += w; + w = view_info_w; + drw_text(drw, x, 0, w, th, 0, view_info, 0); + + drw_map(drw, m->tabwin, 0, 0, m->ww, th); +} + void enternotify(XEvent *e) { @@ -855,8 +991,10 @@ expose(XEvent *e) Monitor *m; XExposeEvent *ev = &e->xexpose; - if (ev->count == 0 && (m = wintomon(ev->window))) + if(ev->count == 0 && (m = wintomon(ev->window))){ drawbar(m); + drawtab(m); + } } void @@ -882,6 +1020,7 @@ focus(Client *c) } selmon->sel = c; drawbars(); + drawtabs(); } /* there are some broken focus acquiring clients needing extra handling */ @@ -934,6 +1073,19 @@ focusstack(const Arg *arg) } } +void +focuswin(const Arg* arg){ + int iwin = arg->i; + Client* c = NULL; + for(c = selmon->clients; c && (iwin || !ISVISIBLE(c)) ; c = c->next){ + if(ISVISIBLE(c)) --iwin; + }; + if(c) { + focus(c); + restack(selmon); + } +} + Atom getatomprop(Client *c, Atom prop) { @@ -1355,12 +1507,14 @@ propertynotify(XEvent *e) case XA_WM_HINTS: updatewmhints(c); drawbars(); + drawtabs(); break; } if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { updatetitle(c); if (c == c->mon->sel) drawbar(c->mon); + drawtab(c->mon); } if (ev->atom == netatom[NetWMWindowType]) updatewindowtype(c); @@ -1499,6 +1653,7 @@ restack(Monitor *m) XWindowChanges wc; drawbar(m); + drawtab(m); if (!m->sel) return; if (m->sel->isfloating || !m->lt[m->sellt]->arrange) @@ -1793,6 +1948,7 @@ setup(void) die("no fonts could be loaded."); lrpad = drw->fonts->h; bh = user_bh ? user_bh : drw->fonts->h + 2; + th = bh; updategeom(); /* init atoms */ utf8string = XInternAtom(dpy, "UTF8_STRING", False); @@ -1958,6 +2114,17 @@ togglebar(const Arg *arg) arrange(selmon); } +void +tabmode(const Arg *arg) +{ + if(arg && arg->i >= 0) + selmon->showtab = arg->ui % showtab_nmodes; + else + selmon->showtab = (selmon->showtab + 1 ) % showtab_nmodes; + arrange(selmon); +} + + void togglefloating(const Arg *arg) { @@ -2092,6 +2259,11 @@ updatebars(void) CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); XMapRaised(dpy, m->barwin); + m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->ww, th, 0, DefaultDepth(dpy, screen), + CopyFromParent, DefaultVisual(dpy, screen), + CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + XDefineCursor(dpy, m->tabwin, cursor[CurNormal]->cursor); + XMapRaised(dpy, m->tabwin); XSetClassHint(dpy, m->barwin, &ch); } } @@ -2099,14 +2271,33 @@ updatebars(void) void updatebarpos(Monitor *m) { + Client *c; + int nvis = 0; + m->wy = m->my; m->wh = m->mh; if (m->showbar) { m->wh -= bh; m->by = m->topbar ? m->wy : m->wy + m->wh; - m->wy = m->topbar ? m->wy + bh : m->wy; - } else + if ( m->topbar ) + m->wy += bh; + } else { m->by = -bh; + } + + for(c = m->clients; c; c = c->next) { + if(ISVISIBLE(c)) ++nvis; + } + + if(m->showtab == showtab_always + || ((m->showtab == showtab_auto) && (nvis > 1) && (m->lt[m->sellt]->arrange == monocle))) { + m->wh -= th; + m->ty = m->toptab ? m->wy : m->wy + m->wh; + if ( m->toptab ) + m->wy += th; + } else { + m->ty = -th; + } } void @@ -2344,7 +2535,7 @@ wintomon(Window w) if (w == root && getrootptr(&x, &y)) return recttomon(x, y, 1, 1); for (m = mons; m; m = m->next) - if (w == m->barwin) + if (w == m->barwin || w == m->tabwin) return m; if ((c = wintoclient(w))) return c->mon; diff --git a/dwm/.dwm/dwm.c.rej b/dwm/.dwm/dwm.c.rej index f9353ac..53b2d31 100644 --- a/dwm/.dwm/dwm.c.rej +++ b/dwm/.dwm/dwm.c.rej @@ -1,34 +1,93 @@ ---- dwm.c 2019-02-02 04:55:28.000000000 -0800 -+++ dwm.c 2019-07-12 11:47:37.726846244 -0700 -@@ -171,12 +179,15 @@ static void detachstack(Client *c); - static Monitor *dirtomon(int dir); - static void drawbar(Monitor *m); - static void drawbars(void); -+static void drawtab(Monitor *m); -+static void drawtabs(void); - static void enternotify(XEvent *e); - static void expose(XEvent *e); +--- dwm.c ++++ dwm.c +@@ -118,6 +119,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; +@@ -125,6 +128,7 @@ struct Monitor { + unsigned int tagset[2]; + int showbar; + int topbar; ++ int hidsel; + Client *clients; + Client *sel; + Client *stack; +@@ -169,13 +173,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 focuswin(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); -@@ -249,6 +261,7 @@ static char stext[256]; - static int screen; - static int sw, sh; /* X display screen geometry width, height */ - static int bh, blw = 0; /* bar geometry */ -+static int th = 0; /* tab bar geometry */ - static int lrpad; /* sum of left and right padding for text */ - static int (*xerrorxlib)(Display *, XErrorEvent *); - static unsigned int numlockmask = 0; -@@ -1697,6 +1852,7 @@ setup(void) - die("no fonts could be loaded."); - lrpad = drw->fonts->h; - bh = drw->fonts->h + 2; -+ th = bh; - updategeom(); - /* init atoms */ - utf8string = XInternAtom(dpy, "UTF8_STRING", False); + 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); +@@ -445,10 +457,25 @@ buttonpress(XEvent *e) + arg.ui = 1 << i; + } else if (ev->x < x + blw) + 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 += blw; ++ 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); +@@ -458,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 +@@ -1343,6 +1456,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; + } + diff --git a/dwm/.dwm/patches/dwm-awesomebar-20200907-6.2.diff b/dwm/.dwm/patches/dwm-awesomebar-20200907-6.2.diff deleted file mode 100644 index 1cb92a9..0000000 --- a/dwm/.dwm/patches/dwm-awesomebar-20200907-6.2.diff +++ /dev/null @@ -1,431 +0,0 @@ -diff --git a/config.def.h b/config.def.h -index 1c0b587..bb8f3f7 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 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,8 @@ static 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, XK_h, hide, {0} }, - TAGKEYS( XK_1, 0) - TAGKEYS( XK_2, 1) - TAGKEYS( XK_3, 2) -@@ -102,6 +107,7 @@ static 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 4465af1..e780189 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,12 +172,16 @@ 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 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 +211,8 @@ 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 showwin(Client *c); - static void showhide(Client *c); - static void sigchld(int unused); - static void spawn(const Arg *arg); -@@ -213,6 +223,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); -@@ -439,10 +450,25 @@ buttonpress(XEvent *e) - arg.ui = 1 << i; - } else if (ev->x < x + blw) - click = ClkLtSymbol; -- else if (ev->x > selmon->ww - TEXTW(stext)) -+ /* 2px right padding */ -+ else if (ev->x > selmon->ww - TEXTW(stext) + lrpad - 2) - click = ClkStatusText; -- else -- click = ClkWinTitle; -+ else { -+ x += blw; -+ 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); -@@ -452,7 +478,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 -@@ -695,7 +721,7 @@ dirtomon(int dir) - void - drawbar(Monitor *m) - { -- int x, w, sw = 0; -+ int x, w, sw = 0, n = 0, scm; - int boxs = drw->fonts->h / 9; - int boxw = drw->fonts->h / 6 + 2; - unsigned int i, occ = 0, urg = 0; -@@ -709,6 +735,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; -@@ -729,16 +757,37 @@ drawbar(Monitor *m) - x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); - - if ((w = m->ww - sw - 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); - } - -@@ -784,9 +833,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; -@@ -830,28 +887,57 @@ 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) -+ if (!selmon->sel && !hid) - 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; -+ } - } - } - -@@ -963,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) - { -@@ -1067,12 +1183,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); - } - -@@ -1195,7 +1313,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; - } - -@@ -1248,6 +1366,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 +1738,25 @@ seturgent(Client *c, int urg) - XFree(wmh); - } - -+void -+show(const Arg *arg) -+{ -+ if (selmon->hidsel) -+ selmon->hidsel = 0; -+ showwin(selmon->sel); -+} -+ -+void -+showwin(Client *c) -+{ -+ if (!c || !HIDDEN(c)) -+ return; -+ -+ XMapWindow(dpy, c->win); -+ setclientstate(c, NormalState); -+ arrange(c->mon); -+} -+ - void - showhide(Client *c) - { -@@ -1746,6 +1893,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) - {