|
@@ -54,6 +54,7 @@
|
|
|
(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)
|
|
@@ -251,6 +252,7 @@ static unsigned int getsystraywidth();
|
|
|
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(Client *c);
|
|
|
static void incnmaster(const Arg *arg);
|
|
|
static void keypress(XEvent *e);
|
|
|
static void killclient(const Arg *arg);
|
|
@@ -291,6 +293,7 @@ static void setnumdesktops(void);
|
|
|
static void setup(void);
|
|
|
static void setviewport(void);
|
|
|
static void seturgent(Client *c, int urg);
|
|
|
+static void show(Client *c);
|
|
|
static void showhide(Client *c);
|
|
|
static void showtagpreview(int tag);
|
|
|
static void sigchld(int unused);
|
|
@@ -307,6 +310,8 @@ static void togglefloating(const Arg *arg);
|
|
|
static void togglefullscr(const Arg *arg);
|
|
|
static void toggletag(const Arg *arg);
|
|
|
static void toggleview(const Arg *arg);
|
|
|
+static void hidewin(const Arg *arg);
|
|
|
+static void restorewin(const Arg *arg);
|
|
|
static void unfocus(Client *c, int setfocus);
|
|
|
static void unmanage(Client *c, int destroyed);
|
|
|
static void unmapnotify(XEvent *e);
|
|
@@ -371,6 +376,10 @@ static Drw *drw;
|
|
|
static Monitor *mons, *selmon;
|
|
|
static Window root, wmcheckwin;
|
|
|
|
|
|
+#define hiddenWinStackMax 100
|
|
|
+static int hiddenWinStackTop = -1;
|
|
|
+static Client* hiddenWinStack[hiddenWinStackMax];
|
|
|
+
|
|
|
/* configuration, allows nested code to access above variables */
|
|
|
#include "config.h"
|
|
|
|
|
@@ -1561,8 +1570,8 @@ void expose(XEvent *e) {
|
|
|
}
|
|
|
|
|
|
void focus(Client *c) {
|
|
|
- if (!c || !ISVISIBLE(c))
|
|
|
- for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext)
|
|
|
+ if (!c || (!ISVISIBLE(c) || HIDDEN(c)))
|
|
|
+ for (c = selmon->stack; c && (!ISVISIBLE(c) || HIDDEN(c)); c = c->snext)
|
|
|
;
|
|
|
if (selmon->sel && selmon->sel != c)
|
|
|
unfocus(selmon->sel, 0);
|
|
@@ -1760,6 +1769,31 @@ void grabkeys(void) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+void
|
|
|
+hide(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);
|
|
|
+
|
|
|
+ focus(c->snext);
|
|
|
+ arrange(c->mon);
|
|
|
+}
|
|
|
+
|
|
|
void incnmaster(const Arg *arg) {
|
|
|
selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
|
|
|
arrange(selmon);
|
|
@@ -1883,12 +1917,14 @@ void manage(Window w, XWindowAttributes *wa) {
|
|
|
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);
|
|
|
}
|
|
|
|
|
@@ -2049,7 +2085,7 @@ void 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;
|
|
|
}
|
|
@@ -2111,6 +2147,16 @@ void propertynotify(XEvent *e) {
|
|
|
void quit(const Arg *arg) {
|
|
|
if (arg->i)
|
|
|
restart = 1;
|
|
|
+
|
|
|
+ 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)) show(c);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
running = 0;
|
|
|
}
|
|
|
|
|
@@ -2601,6 +2647,17 @@ void seturgent(Client *c, int urg) {
|
|
|
XFree(wmh);
|
|
|
}
|
|
|
|
|
|
+void
|
|
|
+show(Client *c)
|
|
|
+{
|
|
|
+ if (!c || !HIDDEN(c))
|
|
|
+ return;
|
|
|
+
|
|
|
+ XMapWindow(dpy, c->win);
|
|
|
+ setclientstate(c, NormalState);
|
|
|
+ arrange(c->mon);
|
|
|
+}
|
|
|
+
|
|
|
void showhide(Client *c) {
|
|
|
if (!c)
|
|
|
return;
|
|
@@ -2782,6 +2839,31 @@ void toggleview(const Arg *arg) {
|
|
|
updatecurrentdesktop();
|
|
|
}
|
|
|
|
|
|
+void hidewin(const Arg *arg) {
|
|
|
+ if (!selmon->sel)
|
|
|
+ return;
|
|
|
+ Client *c = (Client*)selmon->sel;
|
|
|
+ hide(c);
|
|
|
+ hiddenWinStack[++hiddenWinStackTop] = c;
|
|
|
+}
|
|
|
+
|
|
|
+void restorewin(const Arg *arg) {
|
|
|
+ int i = hiddenWinStackTop;
|
|
|
+ while (i > -1) {
|
|
|
+ if (HIDDEN(hiddenWinStack[i]) && hiddenWinStack[i]->tags == selmon->tagset[selmon->seltags]) {
|
|
|
+ show(hiddenWinStack[i]);
|
|
|
+ focus(hiddenWinStack[i]);
|
|
|
+ restack(selmon);
|
|
|
+ for (int j = i; j < hiddenWinStackTop; ++j) {
|
|
|
+ hiddenWinStack[j] = hiddenWinStack[j + 1];
|
|
|
+ }
|
|
|
+ --hiddenWinStackTop;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ --i;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
void unfocus(Client *c, int setfocus) {
|
|
|
if (!c)
|
|
|
return;
|