shod

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 00e8f07797f89e31a7dc59e57a0636534525b53e
parent 70ff3a796becdc442cb4eb30439687d14bc2333e
Author: seninha <lucas@seninha.org>
Date:   Sat, 17 Sep 2022 15:31:09 -0300

add Plan 9's rio hidden windows behavior

On Plan 9's rio, when a window is obscured by other windows, it is
listed as hidden.

I incorpored this behavior in shod.  This behavior however can be
disabled with -h (which is not a help flag).

I also merged the four container lists based on stacking order (one for
each Z-axis layer) into a single container list with dummy containers to
indicate the top of each Z-axis layer.

Diffstat:
Mconfig.c | 1+
Mshod.1 | 8+++++++-
Mshod.c | 43+++++++++++++++++++++++++++----------------
Mshod.h | 40++++++++++++++++++++++------------------
Mxbar.c | 2+-
Mxcontainer.c | 159++++++++++++++++++++++++++++++++++++-------------------------------------------
Mxdock.c | 2+-
Mxevents.c | 22++++++++++------------
Mxhints.c | 108+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Mxmon.c | 7++++---
Mxsplash.c | 2+-
11 files changed, 213 insertions(+), 181 deletions(-)

diff --git a/config.c b/config.c @@ -13,6 +13,7 @@ struct Config config = { .sloppyfocus = 0, /* set to 1 to use sloppy focus */ .honorconfig = 0, /* set to 1 to honor configure requests */ .disablealttab = 0, /* set to 1 to disable alt-tab */ + .disablehidden = 0, /* set to 1 to disable notification of hidden window as minimized */ /* general configuration */ .altkeysym = XK_Alt_L, diff --git a/shod.1 b/shod.1 @@ -7,7 +7,7 @@ .Nd mouse-focused window manager .Sh SYNOPSIS .Nm shod -.Op Fl cdst +.Op Fl cdhst .Op Fl m Ar keysym .Op Ar file .Pp @@ -95,6 +95,12 @@ Make dialogs float. By default, dialog windows are mapped inside the client window. With this option, dialogs are floating windows instead. (Technically, this option makes dialog windows behave the same as menu windows). +.It Fl h +Disable setting obscured windows as hidden. +By default, windows whose containers are obscured by other containers are set as +hidden (aka minimized). +This default behavior emulates the way Plan9's rio lists obscured windows as hidden. +With this option set, only manually minimized containers are set as hidden. .It Fl m Ar keysym Specifies the key symbol that is used for the container cycling, and that provides the modifier to move and resize windows with the mouse pointer. diff --git a/shod.c b/shod.c @@ -29,7 +29,7 @@ struct Dock dock; static void usage(void) { - (void)fprintf(stderr, "usage: shod [-cdst] [-m modifier] [file]\n"); + (void)fprintf(stderr, "usage: shod [-cdhst] [-m modifier] [file]\n"); exit(1); } @@ -176,7 +176,7 @@ getoptions(int argc, char *argv[]) { int c; - while ((c = getopt(argc, argv, "cdm:st")) != -1) { + while ((c = getopt(argc, argv, "cdhm:st")) != -1) { switch (c) { case 'c': config.honorconfig = 1; @@ -184,6 +184,9 @@ getoptions(int argc, char *argv[]) case 'd': config.floatdialog = 1; break; + case 'h': + config.disablehidden = 1; + break; case 'm': if ((config.altkeysym = XStringToKeysym(optarg)) == NoSymbol) errx(1, "supplied key does not match any key symbol: %s", optarg); @@ -283,12 +286,22 @@ initdock(void) static void initdummywindows(void) { + Window wins[2]; int i; for (i = 0; i < LAYER_LAST; i++) { - wm.layerwins[i] = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0); - XRaiseWindow(dpy, wm.layerwins[i]); + wm.layers[i].ncols = 0; + wm.layers[i].frame = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0); + XRaiseWindow(dpy, wm.layers[i].frame); + TAILQ_INSERT_HEAD(&wm.stackq, &wm.layers[i], raiseentry); } + + /* the layer of docks/bars are just below fullscreen containers */ + wm.docklayer = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0); + wins[0] = wm.layers[LAYER_FULLSCREEN].frame; + wins[1] = wm.docklayer; + XRestackWindows(dpy, wins, 2); + wm.wmcheckwin = XCreateWindow( dpy, root, - (2 * config.borderwidth + config.titlewidth), @@ -338,8 +351,9 @@ cleandummywindows(void) XFreePixmap(dpy, wm.wmcheckpix); XDestroyWindow(dpy, wm.wmcheckwin); + XDestroyWindow(dpy, wm.docklayer); for (i = 0; i < LAYER_LAST; i++) { - XDestroyWindow(dpy, wm.layerwins[i]); + XDestroyWindow(dpy, wm.layers[i].frame); } } @@ -412,6 +426,14 @@ main(int argc, char *argv[]) if (config.sloppyfocus) clientswa.event_mask |= EnterWindowMask; + /* initialize queues */ + TAILQ_INIT(&wm.monq); + TAILQ_INIT(&wm.barq); + TAILQ_INIT(&wm.splashq); + TAILQ_INIT(&wm.notifq); + TAILQ_INIT(&wm.focusq); + TAILQ_INIT(&wm.stackq); + /* initialize */ initsignal(); initcursors(); @@ -421,17 +443,6 @@ main(int argc, char *argv[]) inittheme(); initdock(); - /* initialize queues */ - TAILQ_INIT(&wm.monq); - TAILQ_INIT(&wm.barq); - TAILQ_INIT(&wm.splashq); - TAILQ_INIT(&wm.notifq); - TAILQ_INIT(&wm.focusq); - TAILQ_INIT(&wm.fullq); - TAILQ_INIT(&wm.aboveq); - TAILQ_INIT(&wm.centerq); - TAILQ_INIT(&wm.belowq); - /* set up list of monitors */ monupdate(); wm.selmon = TAILQ_FIRST(&wm.monq); diff --git a/shod.h b/shod.h @@ -13,6 +13,7 @@ #define DOCKBORDER 2 #define LEN(x) (sizeof(x) / sizeof((x)[0])) #define _SHOD_MOVERESIZE_RELATIVE ((long)(1 << 16)) +#define ISDUMMY(c) ((c)->ncols == 0) #define TITLEWIDTH(c) (((c)->isfullscreen && (c)->ncols == 1 && TAILQ_FIRST(&(c)->colq)->nrows == 1) ? 0 : config.titlewidth) @@ -94,12 +95,9 @@ enum { enum { /* window layer array indices */ - LAYER_DESKTOP, LAYER_BELOW, LAYER_NORMAL, LAYER_ABOVE, - LAYER_DOCK, - LAYER_SPLASH, LAYER_FULLSCREEN, LAYER_LAST }; @@ -305,6 +303,9 @@ struct Container { * A row contains a list of tabs. * A tab contains an application window and a list of menus and * a list of dialogs. + * + * A container with no column is a dummy container, used as + * placeholders on the Z-axis list. */ struct ColumnQueue colq; /* list of columns in container */ struct Column *selcol; /* pointer to selected container */ @@ -362,9 +363,10 @@ struct Container { */ int ismaximized, issticky; /* window states */ int isminimized, isshaded; /* window states */ + int isobscured; /* whether container is obscured */ int isfullscreen; /* whether container is fullscreen */ int ishidden; /* whether container is hidden */ - int layer; /* stacking order */ + int abovebelow; /* stacking order */ }; TAILQ_HEAD(MonitorQueue, Monitor); @@ -525,14 +527,20 @@ struct WM { int nclients; /* total number of container windows */ /* - * Containers are listed by the focusq queue. However, a - * container can also be listed under another list according to - * its layer on the Z-axis. + * Containers are listed by the focusq queue; they are also + * listed under the stackq list, ordered by its position on + * the Z-axis. + * + * Since there are 4 layers on the Z-axis and we often need + * to move a container to the top of its layer, we have four + * "dummy" containers used as placeholder as the top of each + * layer on the stackq list. + * + * There is also a dummy window to place the dock. */ - struct ContainerQueue fullq; /* queue of containers ordered from topmost to bottommost */ - struct ContainerQueue aboveq; /* queue of containers ordered from topmost to bottommost */ - struct ContainerQueue centerq; /* queue of containers ordered from topmost to bottommost */ - struct ContainerQueue belowq; /* queue of containers ordered from topmost to bottommost */ + struct ContainerQueue stackq; + struct Container layers[LAYER_LAST]; + Window docklayer; /* dummy window used to set dock layer */ /* * We maintain a pointer to the focused container and the @@ -559,12 +567,6 @@ struct WM { Window wmcheckwin; /* dummy window required by EWMH */ Pixmap wmcheckpix; - /* - * Shod uses an array of dummy windows to raise the containers - * into the layers of the Z-axis. - */ - Window layerwins[LAYER_LAST]; /* dummy windows used to set stacking order */ - Cursor cursors[CURSOR_LAST]; /* cursors for the mouse pointer */ int showingdesk; /* whether the desktop is being shown */ int minsize; /* minimum size of a container */ @@ -586,6 +588,7 @@ struct Config { KeySym altkeysym; /* key to trigger alt-tab */ KeySym tabkeysym; /* key to cycle alt-tab */ + int disablehidden; /* whether -h is passed */ int disablealttab; /* whether -t is passed */ int floatdialog; /* whether -d is passed */ int honorconfig; /* whether -c is passed */ @@ -636,7 +639,7 @@ typedef int Unmanagefunc(struct Object *obj, int ignoreunmap); struct Container *containerraisetemp(struct Container *prevc, int backward); void containerbacktoplace(struct Container *c, int restack); void containerdel(struct Container *c); -void containermoveresize(struct Container *c); +void containermoveresize(struct Container *c, int checkstack); void containerdecorate(struct Container *c, struct Column *cdiv, struct Row *rdiv, int recursive, enum Octant o); void containerredecorate(struct Container *c, struct Column *cdiv, struct Row *rdiv, enum Octant o); void containercalccols(struct Container *c, int recalcfact, int recursive); @@ -664,6 +667,7 @@ void deskfocus(struct Monitor *mon, int desk, int focus); void deskshow(int show); int tabattach(struct Container *c, struct Tab *t, int x, int y); int containerisshaded(struct Container *c); +int containerisvisible(struct Container *c, struct Monitor *mon, int desk); /* other object routines */ void barstrut(struct Bar *bar); diff --git a/xbar.c b/xbar.c @@ -36,7 +36,7 @@ managebar(struct Tab *tab, struct Monitor *mon, int desk, Window win, Window lea (void)rect; (void)state; (void)ignoreunmap; - Window wins[2] = {wm.layerwins[LAYER_DOCK], win}; + Window wins[2] = {wm.docklayer, win}; bar = emalloc(sizeof(*bar)); *bar = (struct Bar){ diff --git a/xcontainer.c b/xcontainer.c @@ -2,13 +2,6 @@ #define DIV 15 /* see containerplace() for details */ -/* check whether container is sticky or is on given desktop */ -static int -containerisvisible(struct Container *c, int desk) -{ - return c->issticky || c->desk == desk; -} - /* get next focused container after old on given monitor and desktop */ static struct Container * getnextfocused(struct Monitor *mon, int desk) @@ -16,7 +9,7 @@ getnextfocused(struct Monitor *mon, int desk) struct Container *c; TAILQ_FOREACH(c, &wm.focusq, entry) - if (!c->isminimized && c->mon == mon && containerisvisible(c, desk)) + if (containerisvisible(c, mon, desk)) return c; return NULL; } @@ -38,8 +31,7 @@ snaptoedge(int *x, int *y, int w, int h) if (abs(*x + w - wm.selmon->wx - wm.selmon->ww) < config.snap) *x = wm.selmon->wx + wm.selmon->ww - w; TAILQ_FOREACH(c, &wm.focusq, entry) { - if (!c->isminimized && c->mon == wm.selmon && - containerisvisible(c, wm.selmon->seldesk)) { + if (containerisvisible(c, wm.selmon, wm.selmon->seldesk)) { if (*x + w >= c->x && *x <= c->x + c->w) { if (abs(*y + h - c->y) < config.snap) { *y = c->y - h; @@ -604,20 +596,19 @@ menuraise(struct Tab *tab) struct Container *c; struct Object *p; struct Menu *menu; - Window wins[2], layer; + Window wins[2]; c = tab->row->col->c; if (c == NULL || c->isminimized) return; if (c->isfullscreen) - layer = wm.layerwins[LAYER_FULLSCREEN]; - else if (c->layer > 0) - layer = wm.layerwins[LAYER_ABOVE]; - else if (c->layer < 0) - layer = wm.layerwins[LAYER_BELOW]; + wins[0] = wm.layers[LAYER_FULLSCREEN].frame; + else if (c->abovebelow > 0) + wins[0] = wm.layers[LAYER_ABOVE].frame; + else if (c->abovebelow < 0) + wins[0] = wm.layers[LAYER_BELOW].frame; else - layer = wm.layerwins[LAYER_NORMAL]; - wins[0] = layer; + wins[0] = wm.layers[LAYER_NORMAL].frame; TAILQ_FOREACH(p, &tab->menuq, entry) { menu = (struct Menu *)p; wins[1] = menu->frame; @@ -632,8 +623,8 @@ getfullscreen(struct Monitor *mon, int desk) { struct Container *c; - TAILQ_FOREACH(c, &wm.fullq, raiseentry) - if (!c->isminimized && c->mon == mon && containerisvisible(c, desk)) + for (c = &wm.layers[LAYER_FULLSCREEN]; !ISDUMMY(c); c = TAILQ_NEXT(c, raiseentry)) + if (containerisvisible(c, mon, desk)) return c; return NULL; } @@ -649,15 +640,16 @@ containerinsertfocus(struct Container *c) static void containerinsertraise(struct Container *c) { - if (c->isfullscreen) { - TAILQ_INSERT_HEAD(&wm.fullq, c, raiseentry); - } else if (c->layer > 0) { - TAILQ_INSERT_HEAD(&wm.aboveq, c, raiseentry); - } else if (c->layer < 0) { - TAILQ_INSERT_HEAD(&wm.belowq, c, raiseentry); - } else { - TAILQ_INSERT_HEAD(&wm.centerq, c, raiseentry); - } + int layer; + + layer = LAYER_NORMAL; + if (c->isfullscreen) + layer = LAYER_FULLSCREEN; + else if (c->abovebelow > 0) + layer = LAYER_ABOVE; + else if (c->abovebelow < 0) + layer = LAYER_BELOW; + TAILQ_INSERT_AFTER(&wm.stackq, &wm.layers[layer], c, raiseentry); } /* remove container from the focus list */ @@ -681,23 +673,7 @@ containeraddfocus(struct Container *c) static void containerdelraise(struct Container *c) { - if (c->isfullscreen) { - if (!TAILQ_EMPTY(&wm.fullq)) { - TAILQ_REMOVE(&wm.fullq, c, raiseentry); - } - } else if (c->layer > 0) { - if (!TAILQ_EMPTY(&wm.aboveq)) { - TAILQ_REMOVE(&wm.aboveq, c, raiseentry); - } - } else if (c->layer < 0) { - if (!TAILQ_EMPTY(&wm.belowq)) { - TAILQ_REMOVE(&wm.belowq, c, raiseentry); - } - } else { - if (!TAILQ_EMPTY(&wm.centerq)) { - TAILQ_REMOVE(&wm.centerq, c, raiseentry); - } - } + TAILQ_REMOVE(&wm.stackq, c, raiseentry); } /* hide container */ @@ -762,7 +738,7 @@ containersendtodesk(struct Container *c, struct Monitor *mon, unsigned long desk c->issticky = 0; if ((int)desk != mon->seldesk) /* container was sent to invisible desktop */ containerhide(c, 1); - containerraise(c, c->isfullscreen, c->layer); + containerraise(c, c->isfullscreen, c->abovebelow); } else { return; } @@ -775,13 +751,13 @@ static void containerfullscreen(struct Container *c, int fullscreen) { if (fullscreen != REMOVE && !c->isfullscreen) - containerraise(c, 1, c->layer); + containerraise(c, 1, c->abovebelow); else if (fullscreen != ADD && c->isfullscreen) - containerraise(c, 0, c->layer); + containerraise(c, 0, c->abovebelow); else return; containercalccols(c, 0, 1); - containermoveresize(c); + containermoveresize(c, 1); containerredecorate(c, NULL, NULL, 0); ewmhsetstate(c); } @@ -797,7 +773,7 @@ containermaximize(struct Container *c, int maximize) else return; containercalccols(c, 0, 1); - containermoveresize(c); + containermoveresize(c, 1); containerredecorate(c, NULL, NULL, 0); } @@ -820,7 +796,7 @@ containerminimize(struct Container *c, int minimize, int focus) } else if (minimize != ADD && c->isminimized) { c->isminimized = 0; containersendtodesk(c, wm.selmon, wm.selmon->seldesk); - containermoveresize(c); + containermoveresize(c, 1); containerhide(c, 0); tabfocus(c->selcol->selrow->seltab, 0); } else { @@ -848,7 +824,7 @@ containershade(struct Container *c, int shade) return; } containercalccols(c, 0, 1); - containermoveresize(c); + containermoveresize(c, 1); containerredecorate(c, NULL, NULL, 0); if (c == wm.focused) { tabfocus(c->selcol->selrow->seltab, 0); @@ -874,9 +850,9 @@ containerstick(struct Container *c, int stick) static void containerabove(struct Container *c, int above) { - if (above != REMOVE && c->layer != 1) + if (above != REMOVE && c->abovebelow != 1) containerraise(c, c->isfullscreen, 1); - else if (above != ADD && c->layer != 0) + else if (above != ADD && c->abovebelow != 0) containerraise(c, c->isfullscreen, 0); else return; @@ -886,9 +862,9 @@ containerabove(struct Container *c, int above) static void containerbelow(struct Container *c, int below) { - if (below != REMOVE && c->layer != -1) + if (below != REMOVE && c->abovebelow != -1) containerraise(c, c->isfullscreen, -1); - else if (below != ADD && c->layer != 0) + else if (below != ADD && c->abovebelow != 0) containerraise(c, c->isfullscreen, 0); else return; @@ -916,10 +892,12 @@ containernew(int x, int y, int w, int h, int state) .isminimized = (state & MINIMIZED), .issticky = (state & STICKY), .isshaded = (state & SHADED), - .layer = (state & ABOVE) ? +1 : (state & BELOW) ? -1 : 0, + .ishidden = 0, + .isobscured = 0, + .abovebelow = (state & ABOVE) ? +1 : (state & BELOW) ? -1 : 0, }; TAILQ_INIT(&c->colq); - c->frame = XCreateWindow(dpy, root, c->x, c->y, c->w, c->h, 0, depth, CopyFromParent, visual, clientmask, &clientswa); + c->frame = XCreateWindow(dpy, root, c->x, c->y, c->w, c->h, 0, depth, InputOutput, visual, clientmask, &clientswa); c->curswin[BORDER_N] = XCreateWindow( dpy, c->frame, 0, 0, 1, 1, 0, CopyFromParent, InputOnly, CopyFromParent, @@ -1015,7 +993,7 @@ containerdel(struct Container *c) /* commit container size and position */ void -containermoveresize(struct Container *c) +containermoveresize(struct Container *c, int checkstack) { struct Object *t, *d; struct Column *col; @@ -1081,6 +1059,9 @@ containermoveresize(struct Container *c) } } } + if (!config.disablehidden && checkstack) { + ewmhsetclientsstacking(); + } } /* draw decoration on container frame */ @@ -1281,29 +1262,26 @@ containerincrmove(struct Container *c, int x, int y) /* raise container */ void -containerraise(struct Container *c, int isfullscreen, int layer) +containerraise(struct Container *c, int isfullscreen, int abovebelow) { Window wins[2]; + int layer; if (c == NULL || c->isminimized) return; containerdelraise(c); wins[1] = c->frame; - if (isfullscreen) { - TAILQ_INSERT_HEAD(&wm.fullq, c, raiseentry); - wins[0] = wm.layerwins[LAYER_FULLSCREEN]; - } else if (layer > 0) { - TAILQ_INSERT_HEAD(&wm.aboveq, c, raiseentry); - wins[0] = wm.layerwins[LAYER_ABOVE]; - } else if (layer < 0) { - TAILQ_INSERT_HEAD(&wm.belowq, c, raiseentry); - wins[0] = wm.layerwins[LAYER_BELOW]; - } else { - TAILQ_INSERT_HEAD(&wm.centerq, c, raiseentry); - wins[0] = wm.layerwins[LAYER_NORMAL]; - } + layer = LAYER_NORMAL; + if (isfullscreen) + layer = LAYER_FULLSCREEN; + else if (abovebelow > 0) + layer = LAYER_ABOVE; + else if (abovebelow < 0) + layer = LAYER_BELOW; + TAILQ_INSERT_AFTER(&wm.stackq, &wm.layers[layer], c, raiseentry); + wins[0] = wm.layers[layer].frame; c->isfullscreen = isfullscreen; - c->layer = layer; + c->abovebelow = abovebelow; XRestackWindows(dpy, wins, 2); menuraise(c->selcol->selrow->seltab); ewmhsetclientsstacking(); @@ -1324,7 +1302,7 @@ containerconfigure(struct Container *c, unsigned int valuemask, XWindowChanges * if ((valuemask & CWHeight) && wc->height >= wm.minsize) c->nh = wc->height; containercalccols(c, 0, 1); - containermoveresize(c); + containermoveresize(c, 1); containerredecorate(c, NULL, NULL, 0); } @@ -1469,6 +1447,13 @@ containerplace(struct Container *c, struct Monitor *mon, int desk, int userplace containercalccols(c, 0, 1); } +/* check whether container is sticky or is on given desktop */ +int +containerisvisible(struct Container *c, struct Monitor *mon, int desk) +{ + return !c->isminimized && c->mon == mon && (c->issticky || c->desk == desk); +} + /* check if container can be shaded */ int containerisshaded(struct Container *c) @@ -1559,7 +1544,7 @@ found: XMapSubwindows(dpy, c->frame); /* no need to call shodgrouptab() and shodgroupcontainer(); tabfocus() already calls them */ ewmhsetclientsstacking(); - containermoveresize(c); + containermoveresize(c, 0); containerredecorate(c, NULL, NULL, 0); return 1; } @@ -1590,7 +1575,7 @@ containerdelrow(struct Row *row) } if (recalc) { containercalccols(c, 1, 1); - containermoveresize(c); + containermoveresize(c, 0); shodgrouptab(c); shodgroupcontainer(c); if (redraw) { @@ -1612,7 +1597,7 @@ containerraisetemp(struct Container *prevc, int backward) for (newc = prevc; newc != NULL; newc = TAILQ_PREV(newc, ContainerQueue, entry)) { if (newc != prevc && newc->mon == prevc->mon && - containerisvisible(newc, prevc->desk)) { + containerisvisible(newc, prevc->mon, prevc->desk)) { break; } } @@ -1620,7 +1605,7 @@ containerraisetemp(struct Container *prevc, int backward) TAILQ_FOREACH_REVERSE(newc, &wm.focusq, ContainerQueue, entry) { if (newc != prevc && newc->mon == prevc->mon && - containerisvisible(newc, prevc->desk)) { + containerisvisible(newc, prevc->mon, prevc->desk)) { break; } } @@ -1629,7 +1614,7 @@ containerraisetemp(struct Container *prevc, int backward) for (newc = prevc; newc != NULL; newc = TAILQ_NEXT(newc, entry)) { if (newc != prevc && newc->mon == prevc->mon && - containerisvisible(newc, prevc->desk)) { + containerisvisible(newc, prevc->mon, prevc->desk)) { break; } } @@ -1637,7 +1622,7 @@ containerraisetemp(struct Container *prevc, int backward) TAILQ_FOREACH(newc, &wm.focusq, entry) { if (newc != prevc && newc->mon == prevc->mon && - containerisvisible(newc, prevc->desk)) { + containerisvisible(newc, prevc->mon, prevc->desk)) { break; } } @@ -1740,7 +1725,7 @@ tabfocus(struct Tab *tab, int gotodesk) containeraddfocus(c); containerdecorate(c, NULL, NULL, 1, 0); containerminimize(c, 0, 0); - containerraise(c, c->isfullscreen, c->layer); + containerraise(c, c->isfullscreen, c->abovebelow); shodgrouptab(c); shodgroupcontainer(c); ewmhsetstate(c); @@ -1834,7 +1819,7 @@ rowstack(struct Column *col, struct Row *row) } } colcalcrows(col, 0, 1); - containermoveresize(col->c); + containermoveresize(col->c, 0); } /* configure dialog window */ @@ -2033,11 +2018,11 @@ managetab(struct Tab *tab, struct Monitor *mon, int desk, Window win, Window lea XMapSubwindows(dpy, c->frame); if (!c->isminimized) { containerplace(c, mon, desk, (state & USERPLACED)); - containermoveresize(c); + containermoveresize(c, 0); containerhide(c, 0); tabfocus(tab, 0); } else { - containermoveresize(c); + containermoveresize(c, 0); } /* no need to call shodgrouptab() and shodgroupcontainer(); tabfocus() already calls them */ ewmhsetwmdesktop(c); @@ -2131,7 +2116,7 @@ unmanagetab(struct Object *obj, int ignoreunmap) } if (moveresize) { containercalccols(c, 1, 1); - containermoveresize(c); + containermoveresize(c, 0); containerredecorate(c, NULL, NULL, 0); shodgrouptab(c); shodgroupcontainer(c); diff --git a/xdock.c b/xdock.c @@ -289,7 +289,7 @@ dockupdate(void) dockupdateresizeable(); } dockdecorate(); - wins[0] = wm.layerwins[LAYER_DOCK]; + wins[0] = wm.docklayer; wins[1] = dock.win; XMoveResizeWindow(dpy, dock.win, dock.x, dock.y, dock.w, dock.h); XRestackWindows(dpy, wins, 2); diff --git a/xevents.c b/xevents.c @@ -589,9 +589,7 @@ manage(Window win, XRectangle rect, int ignoreunmap) type = getwintype(win, &leader, &tab, &state); if (type == TYPE_DESKTOP) { /* we do not handle desktop windows */ - Window wins[2] = {wm.layerwins[LAYER_DESKTOP], win}; - - XRestackWindows(dpy, wins, 2); + XLowerWindow(dpy, win); XMapWindow(dpy, win); return; } @@ -663,7 +661,7 @@ mouseretab(struct Tab *tab, int xroot, int yroot, int x, int y) if (XGrabPointer(dpy, root, False, ButtonReleaseMask | PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime) != GrabSuccess) goto done; tabdetach(tab, xroot - x, yroot - y); - containermoveresize(c); + containermoveresize(c, 0); XUnmapWindow(dpy, tab->title); XMoveWindow( dpy, wm.wmcheckwin, @@ -859,7 +857,7 @@ mouseresize(int type, void *obj, int xroot, int yroot, enum Octant o) menudecorate(menu, 0); } else { containercalccols(c, 0, 1); - containermoveresize(c); + containermoveresize(c, 0); containerredecorate(c, NULL, NULL, o); } lasttime = ev.xmotion.time; @@ -875,7 +873,7 @@ done: menudecorate(menu, 0); } else { containercalccols(c, 0, 1); - containermoveresize(c); + containermoveresize(c, 1); containerdecorate(c, NULL, NULL, 0, 0); } XUngrabPointer(dpy, CurrentTime); @@ -935,7 +933,7 @@ done: menumoveresize(menu); menudecorate(menu, 0); } else { - containermoveresize(c); + containermoveresize(c, 1); containerdecorate(c, NULL, NULL, 0, 0); } XUngrabPointer(dpy, CurrentTime); @@ -1066,7 +1064,7 @@ mouseretile(struct Container *c, struct Column *cdiv, struct Row *rdiv, int xroo } if (update) { containercalccols(c, 1, 1); - containermoveresize(c); + containermoveresize(c, 0); containerdecorate(c, cdiv, rdiv, 0, 0); lasttime = ev.xmotion.time; update = 0; @@ -1078,7 +1076,7 @@ mouseretile(struct Container *c, struct Column *cdiv, struct Row *rdiv, int xroo } done: containercalccols(c, 1, 1); - containermoveresize(c); + containermoveresize(c, 0); tabfocus(c->selcol->selrow->seltab, 0); XUngrabPointer(dpy, CurrentTime); } @@ -1167,7 +1165,7 @@ xeventbuttonpress(XEvent *e) /* raise client */ if (ev->button == Button1) - containerraise(c, c->isfullscreen, c->layer); + containerraise(c, c->isfullscreen, c->abovebelow); /* get pointer position */ if (!XTranslateCoordinates(dpy, ev->window, c->frame, ev->x, ev->y, &x, &y, &dw)) @@ -1454,7 +1452,7 @@ xeventconfigurerequest(XEvent *e) if (config.honorconfig) { containerconfigure(((struct Tab *)obj)->row->col->c, ev->value_mask, &wc); } else { - containermoveresize(((struct Tab *)obj)->row->col->c); + containermoveresize(((struct Tab *)obj)->row->col->c, 1); } } } @@ -1732,5 +1730,5 @@ void (*xevents[LASTEvent])(XEvent *) = { [MapRequest] = xeventmaprequest, [MappingNotify] = xeventmappingnotify, [PropertyNotify] = xeventpropertynotify, - [UnmapNotify] = xeventunmapnotify + [UnmapNotify] = xeventunmapnotify, }; diff --git a/xhints.c b/xhints.c @@ -1,38 +1,5 @@ #include "shod.h" -#define LOOPSTACKING(array, list, index) { \ - struct Container *c; \ - struct Column *col; \ - struct Row *row; \ - struct Object *p; \ - struct Tab *t; \ - \ - TAILQ_FOREACH(c, &(list), raiseentry) { \ - TAILQ_FOREACH(col, &c->colq, entry) { \ - if (col->selrow->seltab != NULL) \ - (array)[--(index)] = col->selrow->seltab->obj.win; \ - TAILQ_FOREACH(p, &col->selrow->tabq, entry) { \ - t = (struct Tab *)p; \ - if (t != col->selrow->seltab) { \ - (array)[--(index)] = t->obj.win; \ - } \ - } \ - TAILQ_FOREACH(row, &col->rowq, entry) { \ - if (row == col->selrow) \ - continue; \ - if (row->seltab != NULL) \ - (array)[--(index)] = row->seltab->obj.win; \ - TAILQ_FOREACH(p, &row->tabq, entry) { \ - t = (struct Tab *)p; \ - if (t != row->seltab) { \ - (array)[--(index)] = t->obj.win; \ - } \ - } \ - } \ - } \ - } \ -} - /* get window name */ static char * getwinname(Window win) @@ -59,6 +26,32 @@ getwinname(Window win) return name; } +/* check if given geometry is obscured by containers above it */ +static int +isobscured(struct Container *c, struct Monitor *mon, int desk, int x, int y, int w, int h) +{ + if (config.disablehidden || w <= 0 || h <= 0 || c == NULL) + return 0; + while ((c = TAILQ_PREV(c, ContainerQueue, raiseentry)) != NULL) { + if (ISDUMMY(c) || !containerisvisible(c, mon, desk)) + continue; + if (y < c->y) + if (!isobscured(c, mon, desk, x, y, w, c->y - y)) + return 0; + if (x < c->x) + if (!isobscured(c, mon, desk, x, y, c->x - x, y)) + return 0; + if (y + h > c->y + c->h) + if (!isobscured(c, mon, desk, x, c->y + c->h, w, h)) + return 0; + if (x + w > c->x + c->w) + if (!isobscured(c, mon, desk, c->x + c->w, y, w, h)) + return 0; + return 1; + } + return 0; +} + /* set desktop for a given window */ static void ewmhsetdesktop(Window win, long d) @@ -125,7 +118,12 @@ void ewmhsetclientsstacking(void) { Window *wins = NULL; - int i = 0; + struct Container *c; + struct Column *col; + struct Row *row; + struct Object *p; + struct Tab *t; + int prevobscured, i; if (wm.nclients < 1) { XChangeProperty(dpy, root, atoms[_NET_CLIENT_LIST_STACKING], XA_WINDOW, 32, PropModeReplace, NULL, 0); @@ -133,10 +131,38 @@ ewmhsetclientsstacking(void) } wins = ecalloc(wm.nclients, sizeof *wins); i = wm.nclients; - LOOPSTACKING(wins, wm.fullq, i) - LOOPSTACKING(wins, wm.aboveq, i) - LOOPSTACKING(wins, wm.centerq, i) - LOOPSTACKING(wins, wm.belowq, i) + TAILQ_FOREACH(c, &wm.stackq, raiseentry) { + if (ISDUMMY(c)) + continue; + prevobscured = c->isobscured; + if (!config.disablehidden) + c->isobscured = isobscured(c, c->mon, c->desk, c->x, c->y, c->w, c->h); + TAILQ_FOREACH(col, &c->colq, entry) { + if (col->selrow->seltab != NULL) + wins[--i] = col->selrow->seltab->obj.win; + TAILQ_FOREACH(p, &col->selrow->tabq, entry) { + t = (struct Tab *)p; + if (t != col->selrow->seltab) { + wins[--i] = t->obj.win; + } + } + TAILQ_FOREACH(row, &col->rowq, entry) { + if (row == col->selrow) + continue; + if (row->seltab != NULL) + wins[--i] = row->seltab->obj.win; + TAILQ_FOREACH(p, &row->tabq, entry) { + t = (struct Tab *)p; + if (t != row->seltab) { + wins[--i] = t->obj.win; + } + } + } + } + if (prevobscured != c->isobscured) { + ewmhsetstate(c); + } + } XChangeProperty(dpy, root, atoms[_NET_CLIENT_LIST_STACKING], XA_WINDOW, 32, PropModeReplace, (unsigned char *)wins+i, wm.nclients-i); free(wins); } @@ -190,15 +216,15 @@ ewmhsetstate(struct Container *c) data[n++] = atoms[_NET_WM_STATE_STICKY]; if (c->isshaded) data[n++] = atoms[_NET_WM_STATE_SHADED]; - if (c->isminimized) + if (c->isminimized || c->isobscured) data[n++] = atoms[_NET_WM_STATE_HIDDEN]; if (c->ismaximized) { data[n++] = atoms[_NET_WM_STATE_MAXIMIZED_VERT]; data[n++] = atoms[_NET_WM_STATE_MAXIMIZED_HORZ]; } - if (c->layer > 0) + if (c->abovebelow > 0) data[n++] = atoms[_NET_WM_STATE_ABOVE]; - else if (c->layer < 0) + else if (c->abovebelow < 0) data[n++] = atoms[_NET_WM_STATE_BELOW]; TAB_FOREACH_BEGIN(c, t){ XChangeProperty(dpy, t->win, atoms[_NET_WM_STATE], XA_ATOM, 32, PropModeReplace, (unsigned char *)data, n); diff --git a/xmon.c b/xmon.c @@ -128,7 +128,7 @@ monupdate(void) c->mon = wm.selmon; c->desk = wm.selmon->seldesk; containerplace(c, wm.selmon, wm.selmon->seldesk, 0); - containermoveresize(c); + containermoveresize(c, 0); /* move menus to new monitor */ TAB_FOREACH_BEGIN(c, t) { @@ -145,7 +145,7 @@ monupdate(void) splashplace((struct Splash *)s); if (focus != NULL) /* if a contained changed desktop, focus it */ tabfocus(focus->selcol->selrow->seltab, 1); - + ewmhsetclientsstacking(); free(unique); } @@ -226,10 +226,11 @@ monupdatearea(void) TAILQ_FOREACH(c, &wm.focusq, entry) { if (c->ismaximized) { containercalccols(c, 0, 1); - containermoveresize(c); + containermoveresize(c, 0); containerredecorate(c, NULL, NULL, 0); } } + ewmhsetclientsstacking(); } /* if window is bigger than monitor, resize it while maintaining proportion */ diff --git a/xsplash.c b/xsplash.c @@ -28,7 +28,7 @@ splashplace(struct Splash *splash) splash->x = wm.selmon->wx + (wm.selmon->ww - splash->w) / 2; splash->y = wm.selmon->wy + (wm.selmon->wh - splash->h) / 2; wins[1] = splash->obj.win; - wins[0] = wm.layerwins[LAYER_SPLASH]; + wins[0] = wm.layers[LAYER_NORMAL].frame; XMoveWindow(dpy, splash->obj.win, splash->x, splash->y); XRestackWindows(dpy, wins, 2); }