commit 5a3328b970110c5964f3525c3ff7d64e5f8394f6
parent 33eddb5a6668620e9bc49a75f4ea4751e50621d3
Author: Lucas de Sena <lucas@seninha.org>
Date: Tue, 20 Dec 2022 16:37:49 -0300
some changes and bug fixes:
new stuff:
- add `resized` state to resize dockapp to dock's width.
- add checking for menus when placing new clients on the screen.
- add `SHOD_CONTAINER_LIST` property listing all containers
(actually it lists the currently focused window of each container).
changed stuff:
- now only clicking on window area focus a monitor rather than clicking
anywhere
bug fixes:
- fix focusing after changing a container's current desktop.
- fix typo in manual.
- fix dockapp placing on dock (they were not centered, now they are).
- fix border drawing on full-sized dockbar.
- fix recalculation of dock's position and size after plugging monitor.
- fix algorithm to check whether a container is obscured.
refactoration:
- call ewmhsetclients() only once, after handling current x event
Diffstat:
M | shod.1 | | | 9 | ++++++++- |
M | shod.c | | | 12 | ++++++++---- |
M | shod.h | | | 12 | ++++++++++-- |
M | xcontainer.c | | | 157 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------- |
M | xdock.c | | | 39 | +++++++++++++++++++++++++++++++-------- |
M | xdraw.c | | | 6 | +++--- |
M | xevents.c | | | 36 | +++++++++++++++++++++++++++--------- |
M | xhints.c | | | 56 | +++++++++++++++++--------------------------------------- |
M | xmon.c | | | 6 | +++--- |
M | xutil.c | | | 1 | + |
M | xutil.h | | | 1 | + |
11 files changed, 216 insertions(+), 119 deletions(-)
diff --git a/shod.1 b/shod.1
@@ -653,9 +653,14 @@ has its slot resized to the size of the dockapp itself.
.Pp
An
.Dq Em "extended"
-dockapp has is resized to fit all the remaining unused space of the dock.
+dockapp is resized to fit all the remaining unused space of the dock.
For example, if the only content of the dock is an extended taskbar dockapp,
this dockapp is resized to fit all the dock.
+.Pp
+an
+.Dq Em "resized"
+dockapp is resized to fit the width of the dock
+(that is, the width of a vertical dock or the height of an horizontal dock).
.Sh RESOURCES
.Nm shod
understands the following X resources.
@@ -764,6 +769,8 @@ and
Possible states for dockapp windows are
.Cm extend ,
and
+.Cm resized ,
+and
.Cm shrunk .
.It Ic shod.CLASS.NAME.ROLE.dockpos
Define the position in the dock of a docked application matching the given class, name and role.
diff --git a/shod.c b/shod.c
@@ -375,7 +375,6 @@ main(int argc, char *argv[])
ewmhsetcurrentdesktop(0);
ewmhsetshowingdesktop(0);
ewmhsetclients();
- ewmhsetclientsstacking();
ewmhsetactivewindow(None);
/* run sh script */
@@ -389,9 +388,15 @@ main(int argc, char *argv[])
setmod();
/* run main event loop */
- while (running && !XNextEvent(dpy, &ev))
- if (xevents[ev.type])
+ while (running && !XNextEvent(dpy, &ev)) {
+ if (xevents[ev.type]) {
+ wm.setclientlist = 0;
(*xevents[ev.type])(&ev);
+ if (wm.setclientlist) {
+ ewmhsetclients();
+ }
+ }
+ }
/* clean up */
cleandummywindows();
@@ -401,7 +406,6 @@ main(int argc, char *argv[])
/* clear ewmh hints */
ewmhsetclients();
- ewmhsetclientsstacking();
ewmhsetactivewindow(None);
/* close connection to server */
diff --git a/shod.h b/shod.h
@@ -10,7 +10,7 @@
#define DROPPIXELS 30 /* number of pixels from the border where a tab can be dropped in */
#define RESIZETIME 64 /* time to redraw containers during resizing */
#define MOVETIME 32 /* time to redraw containers during moving */
-#define DOCKBORDER 2
+#define DOCKBORDER 1
#define LEN(x) (sizeof(x) / sizeof((x)[0]))
#define _SHOD_MOVERESIZE_RELATIVE ((long)(1 << 16))
#define ISDUMMY(c) ((c)->ncols == 0)
@@ -135,6 +135,7 @@ enum {
/* dockapp states bits */
EXTEND = 0x100,
SHRUNK = 0x200,
+ RESIZED = 0x400,
};
enum {
@@ -580,6 +581,14 @@ struct WM {
Cursor cursors[CURSOR_LAST]; /* cursors for the mouse pointer */
int showingdesk; /* whether the desktop is being shown */
int minsize; /* minimum size of a container */
+
+ /*
+ * Some operations need to reset the list of clients, to do it
+ * only once when more than one of such operations, we use this
+ * value we check at the end of each main loop iteration and
+ * reset at the beginning of each main loop iteration
+ */
+ int setclientlist;
};
struct Dock {
@@ -710,7 +719,6 @@ void ewmhinit(const char *wmname);
void ewmhsetdesktop(Window win, long d);
void ewmhsetframeextents(Window win, int b, int t);
void ewmhsetclients(void);
-void ewmhsetclientsstacking(void);
void ewmhsetstate(struct Container *c);
void ewmhsetwmdesktop(struct Container *c);
void ewmhsetactivewindow(Window w);
diff --git a/xcontainer.c b/xcontainer.c
@@ -162,6 +162,13 @@ dialognew(Window win, int maxw, int maxh, int ignoreunmap)
return dial;
}
+/* check if given tab accepts given menu */
+static int
+istabformenu(struct Tab *tab, struct Menu *menu)
+{
+ return (menu->leader == tab->obj.win || menu->leader == tab->leader);
+}
+
/* map menus */
static void
tabhidemenus(struct Tab *tab, int hide)
@@ -173,7 +180,7 @@ tabhidemenus(struct Tab *tab, int hide)
return;
TAILQ_FOREACH(obj, &wm.menuq, entry) {
menu = ((struct Menu *)obj);
- if (menu->leader != tab->obj.win && menu->leader != tab->leader)
+ if (!istabformenu(tab, menu))
continue;
if (hide) {
XUnmapWindow(dpy, ((struct Menu *)obj)->frame);
@@ -623,14 +630,14 @@ containeraddcol(struct Container *c, struct Column *col, struct Column *prev)
}
}
-/* send container to desktop and raise it */
-static void
+/* send container to desktop and raise it; return nonzero if it was actually sent anywhere */
+static int
containersendtodesk(struct Container *c, struct Monitor *mon, unsigned long desk)
{
void containerstick(struct Container *c, int stick);
if (c == NULL || c->isminimized)
- return;
+ return 0;
if (desk == 0xFFFFFFFF) {
containerstick(c, ADD);
} else if ((int)desk < config.ndesktops) {
@@ -641,12 +648,15 @@ 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);
+ else
+ containerhide(c, 0);
containerraise(c, c->isfullscreen, c->abovebelow);
} else {
- return;
+ return 0;
}
ewmhsetwmdesktop(c);
ewmhsetstate(c);
+ return 1;
}
/* make a container occupy the whole monitor */
@@ -698,7 +708,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);
+ (void)containersendtodesk(c, wm.selmon, wm.selmon->seldesk);
containermoveresize(c, 1);
containerhide(c, 0);
tabfocus(c->selcol->selrow->seltab, 0);
@@ -743,7 +753,7 @@ containerstick(struct Container *c, int stick)
ewmhsetwmdesktop(c);
} else if (stick != ADD && c->issticky) {
c->issticky = 0;
- containersendtodesk(c, c->mon, c->mon->seldesk);
+ (void)containersendtodesk(c, c->mon, c->mon->seldesk);
} else {
return;
}
@@ -963,7 +973,7 @@ containermoveresize(struct Container *c, int checkstack)
}
}
if (!config.disablehidden && checkstack) {
- ewmhsetclientsstacking();
+ wm.setclientlist = 1;
}
}
@@ -1116,19 +1126,51 @@ containercalccols(struct Container *c, int recalcfact, int recursive)
/* send container to desktop and focus another on the original desktop */
void
-containersendtodeskandfocus(struct Container *c, struct Monitor *mon, unsigned long desk)
+containersendtodeskandfocus(struct Container *c, struct Monitor *mon, unsigned long d)
{
- int prevdesk;
+ struct Monitor *prevmon;
+ int prevdesk, desk;
if (c == NULL)
return;
+ prevmon = c->mon;
prevdesk = c->desk;
- containersendtodesk(c, mon, desk);
- c = getnextfocused(mon, prevdesk);
- if (c != NULL) {
- tabfocus(c->selcol->selrow->seltab, 0);
- } else {
- tabfocus(NULL, 0);
+ desk = d;
+
+ /* is it necessary to send the container to the desktop */
+ if (c->mon != mon || c->desk != desk) {
+ /*
+ * Container sent to a desktop which is not the same
+ * as the one it was originally at.
+ */
+ if (!containersendtodesk(c, mon, d)) {
+ /*
+ * container could not be sent to given desktop;
+ */
+ return;
+ }
+ }
+
+ /* is it necessary to focus something? */
+ if (mon == wm.selmon && desk == wm.selmon->seldesk) {
+ /*
+ * Container sent to the focused desktop.
+ * Focus it, if visible.
+ */
+ if (containerisvisible(c, mon, wm.selmon->seldesk)) {
+ tabfocus(c->selcol->selrow->seltab, 0);
+ }
+ } else if (prevmon == wm.selmon && prevdesk == wm.selmon->seldesk) {
+ /*
+ * Container moved from the focused desktop.
+ * Focus the next visible container, if existing;
+ * or nothing, if there's no visible container.
+ */
+ if ((c = getnextfocused(mon, prevdesk)) != NULL) {
+ tabfocus(c->selcol->selrow->seltab, 0);
+ } else {
+ tabfocus(NULL, 0);
+ }
}
}
@@ -1155,7 +1197,7 @@ containerincrmove(struct Container *c, int x, int y)
if (!c->issticky) {
monto = getmon(c->nx + c->nw / 2, c->ny + c->nh / 2);
if (monto != NULL && monto != c->mon) {
- containersendtodesk(c, monto, monto->seldesk);
+ (void)containersendtodesk(c, monto, monto->seldesk);
if (wm.focused == c) {
deskupdate(monto, monto->seldesk);
}
@@ -1195,14 +1237,14 @@ containerraise(struct Container *c, int isfullscreen, int abovebelow)
wins[0] = wm.layers[LAYER_MENU].frame;
TAILQ_FOREACH(obj, &wm.menuq, entry) {
menu = ((struct Menu *)obj);
- if (menu->leader != tab->obj.win && menu->leader != tab->leader)
+ if (!istabformenu(tab, menu))
continue;
menu = (struct Menu *)obj;
wins[1] = menu->frame;
XRestackWindows(dpy, wins, 2);
wins[0] = menu->frame;
}
- ewmhsetclientsstacking();
+ wm.setclientlist = 1;
}
/* configure container size and position */
@@ -1262,16 +1304,45 @@ containersetstate(struct Tab *tab, Atom *props, unsigned long set)
ewmhsetstate(c);
}
+/* fill placement grid for given rectangle */
+static void
+fillgrid(struct Monitor *mon, int x, int y, int w, int h, int grid[DIV][DIV])
+{
+ int i, j;
+ int ha, hb, wa, wb;
+ int ya, yb, xa, xb;
+
+ for (i = 0; i < DIV; i++) {
+ for (j = 0; j < DIV; j++) {
+ ha = mon->wy + (mon->wh * i)/DIV;
+ hb = mon->wy + (mon->wh * (i + 1))/DIV;
+ wa = mon->wx + (mon->ww * j)/DIV;
+ wb = mon->wx + (mon->ww * (j + 1))/DIV;
+ ya = y;
+ yb = y + h;
+ xa = x;
+ xb = x + w;
+ if (ya <= hb && ha <= yb && xa <= wb && wa <= xb) {
+ if (ya < ha && yb > hb)
+ grid[i][j]++;
+ if (xa < wa && xb > wb)
+ grid[i][j]++;
+ grid[i][j]++;
+ }
+ }
+ }
+}
+
/* find best position to place a container on screen */
void
containerplace(struct Container *c, struct Monitor *mon, int desk, int userplaced)
{
struct Container *tmp;
+ struct Object *obj;
+ struct Menu *menu;
int grid[DIV][DIV] = {{0}, {0}};
int lowest;
int i, j, k, w, h;
- int ha, hb, wa, wb;
- int ya, yb, xa, xb;
int subx, suby; /* position of the larger subregion */
int subw, subh; /* larger subregion width and height */
@@ -1303,26 +1374,14 @@ containerplace(struct Container *c, struct Monitor *mon, int desk, int userplace
/* increment cells of grid a window is in */
TAILQ_FOREACH(tmp, &wm.focusq, entry) {
- if (tmp != c && !tmp->isminimized && ((tmp->issticky && tmp->mon == mon) || tmp->desk == desk)) {
- for (i = 0; i < DIV; i++) {
- for (j = 0; j < DIV; j++) {
- ha = mon->wy + (mon->wh * i)/DIV;
- hb = mon->wy + (mon->wh * (i + 1))/DIV;
- wa = mon->wx + (mon->ww * j)/DIV;
- wb = mon->wx + (mon->ww * (j + 1))/DIV;
- ya = tmp->ny;
- yb = tmp->ny + tmp->nh;
- xa = tmp->nx;
- xb = tmp->nx + tmp->nw;
- if (ya <= hb && ha <= yb && xa <= wb && wa <= xb) {
- if (ya < ha && yb > hb)
- grid[i][j]++;
- if (xa < wa && xb > wb)
- grid[i][j]++;
- grid[i][j]++;
- }
- }
- }
+ if (tmp != c && containerisvisible(tmp, c->mon, c->desk)) {
+ fillgrid(mon, tmp->nx, tmp->ny, tmp->nw, tmp->nh, grid);
+ }
+ }
+ TAILQ_FOREACH(obj, &wm.menuq, entry) {
+ menu = ((struct Menu *)obj);
+ if (istabformenu(c->selcol->selrow->seltab, menu)) {
+ fillgrid(mon, menu->x, menu->y, menu->w, menu->h, grid);
}
}
@@ -1390,6 +1449,8 @@ tabattach(struct Container *c, struct Tab *det, int x, int y)
struct Object *obj;
int flag;
+ if (c == NULL)
+ return 0;
flag = CREATTAB;
col = NULL;
row = NULL;
@@ -1462,7 +1523,6 @@ found:
XMapSubwindows(dpy, c->frame);
/* no need to call shodgrouptab() and shodgroupcontainer(); tabfocus() already calls them */
ewmhsetdesktop(det->obj.win, c->desk);
- ewmhsetclientsstacking();
containermoveresize(c, 0);
containerredecorate(c, NULL, NULL, 0);
return 1;
@@ -1611,6 +1671,8 @@ tabfocus(struct Tab *tab, int gotodesk)
struct Dialog *dial;
wm.prevfocused = wm.focused;
+ if (wm.prevfocused != NULL && tab != wm.prevfocused->selcol->selrow->seltab)
+ tabhidemenus(wm.prevfocused->selcol->selrow->seltab, ADD);
if (tab == NULL) {
wm.focused = NULL;
XSetInputFocus(dpy, wm.wmcheckwin, RevertToParent, CurrentTime);
@@ -1650,8 +1712,6 @@ tabfocus(struct Tab *tab, int gotodesk)
ewmhsetstate(c);
}
if (wm.prevfocused != NULL && wm.prevfocused != wm.focused) {
- if (tab != wm.prevfocused->selcol->selrow->seltab)
- tabhidemenus(wm.prevfocused->selcol->selrow->seltab, ADD);
containerdecorate(wm.prevfocused, NULL, NULL, 1, 0);
ewmhsetstate(wm.prevfocused);
}
@@ -1805,8 +1865,7 @@ containernewwithtab(struct Tab *tab, struct Monitor *mon, int desk, XRectangle r
}
/* no need to call shodgrouptab() and shodgroupcontainer(); tabfocus() already calls them */
ewmhsetwmdesktop(c);
- ewmhsetclients();
- ewmhsetclientsstacking();
+ wm.setclientlist = 1;
}
/* create container for tab */
@@ -1827,8 +1886,7 @@ managecontainer(struct Tab *prev, struct Monitor *mon, int desk, Window win, Win
rowaddtab(row, tab, prev);
rowcalctabs(row);
ewmhsetdesktop(win, c->desk);
- ewmhsetclients();
- ewmhsetclientsstacking();
+ wm.setclientlist = 1;
containermoveresize(c, 0);
containerredecorate(c, NULL, NULL, 0);
XMapSubwindows(dpy, c->frame);
@@ -1857,8 +1915,7 @@ managedialog(struct Tab *tab, struct Monitor *mon, int desk, Window win, Window
XMapRaised(dpy, dial->frame);
if (wm.focused != NULL && wm.focused->selcol->selrow->seltab == tab)
tabfocus(tab, 0);
- ewmhsetclients();
- ewmhsetclientsstacking();
+ wm.setclientlist = 1;
}
/* unmanage tab (and delete its row if it is the only tab); return whether deletion occurred */
diff --git a/xdock.c b/xdock.c
@@ -80,6 +80,13 @@ dockappnew(Window win, int w, int h, int dockpos, int state, int ignoreunmap)
);
}
+/* compute dockapp position given its width or height */
+static int
+dockapppos(int pos)
+{
+ return max(0, config.dockwidth / 2 - pos / 2);
+}
+
/* update dock position; create it, if necessary */
void
dockupdateresizeable(void)
@@ -93,20 +100,28 @@ dockupdateresizeable(void)
dapp = (struct Dockapp *)p;
switch (config.dockgravity[0]) {
case 'N':
+ if (dapp->state & RESIZED)
+ dapp->h = config.dockwidth;
dapp->x = DOCKBORDER + size + max(0, (dapp->slotsize - dapp->w) / 2);
- dapp->y = DOCKBORDER + max(0, (config.dockwidth - dapp->h) / 2);
+ dapp->y = DOCKBORDER + dockapppos(dapp->h);
break;
case 'S':
+ if (dapp->state & RESIZED)
+ dapp->h = config.dockwidth;
dapp->x = DOCKBORDER + size + max(0, (dapp->slotsize - dapp->w) / 2);
- dapp->y = DOCKBORDER + max(0, (config.dockwidth - dapp->h) / 2);
+ dapp->y = DOCKBORDER + dockapppos(dapp->h);
break;
case 'W':
- dapp->x = DOCKBORDER + max(0, (config.dockwidth - dapp->w) / 2);
+ if (dapp->state & RESIZED)
+ dapp->w = config.dockwidth;
+ dapp->x = DOCKBORDER + dockapppos(dapp->w);
dapp->y = DOCKBORDER + size + max(0, (dapp->slotsize - dapp->h) / 2);
break;
case 'E':
default:
- dapp->x = DOCKBORDER + max(0, (config.dockwidth - dapp->w) / 2);
+ if (dapp->state & RESIZED)
+ dapp->w = config.dockwidth;
+ dapp->x = DOCKBORDER + dockapppos(dapp->w);
dapp->y = DOCKBORDER + size + max(0, (dapp->slotsize - dapp->h) / 2);
break;
}
@@ -251,6 +266,8 @@ dockupdatefull(void)
dapp = (struct Dockapp *)p;
switch (config.dockgravity[0]) {
case 'N':
+ if (dapp->state & RESIZED)
+ dapp->h = config.dockwidth - DOCKBORDER;
if (dapp->state & EXTEND) {
dapp->w = max(1, (i + 1) * part - i * part);
n = dapp->w;
@@ -258,9 +275,11 @@ dockupdatefull(void)
n = dapp->slotsize;
}
dapp->x = size + max(0, (n - dapp->w) / 2);
- dapp->y = DOCKBORDER + max(0, (config.dockwidth - dapp->h) / 2);
+ dapp->y = DOCKBORDER + dockapppos(dapp->h);
break;
case 'S':
+ if (dapp->state & RESIZED)
+ dapp->h = config.dockwidth - DOCKBORDER;
if (dapp->state & EXTEND) {
dapp->w = max(1, (i + 1) * part - i * part);
n = dapp->w;
@@ -268,27 +287,31 @@ dockupdatefull(void)
n = dapp->slotsize;
}
dapp->x = size + max(0, (n - dapp->w) / 2);
- dapp->y = DOCKBORDER + max(0, (config.dockwidth - dapp->h) / 2);
+ dapp->y = DOCKBORDER + dockapppos(dapp->h);
break;
case 'W':
+ if (dapp->state & RESIZED)
+ dapp->w = config.dockwidth - DOCKBORDER;
if (dapp->state & EXTEND) {
dapp->h = max(1, (i + 1) * part - i * part);
n = dapp->h;
} else {
n = dapp->slotsize;
}
- dapp->x = DOCKBORDER + max(0, (config.dockwidth - dapp->w) / 2);
+ dapp->x = DOCKBORDER + dockapppos(dapp->w);
dapp->y = size + max(0, (n - dapp->h) / 2);
break;
case 'E':
default:
+ if (dapp->state & RESIZED)
+ dapp->w = config.dockwidth - DOCKBORDER;
if (dapp->state & EXTEND) {
dapp->h = max(1, (i + 1) * part - i * part);
n = dapp->h;
} else {
n = dapp->slotsize;
}
- dapp->x = DOCKBORDER + max(0, (config.dockwidth - dapp->w) / 2);
+ dapp->x = DOCKBORDER + dockapppos(dapp->w);
dapp->y = size + max(0, (n - dapp->h) / 2);
break;
}
diff --git a/xdraw.c b/xdraw.c
@@ -493,17 +493,17 @@ drawdock(Pixmap pix, int w, int h)
if (config.dockgravity[0] != '\0' && (config.dockgravity[1] == 'F' || config.dockgravity[1] == 'f')) {
switch (config.dockgravity[0]) {
case 'N':
- XFillRectangle(dpy, pix, gc, 0, h - DOCKBORDER, w, 1);
+ XFillRectangle(dpy, pix, gc, 0, h - DOCKBORDER, w, DOCKBORDER);
break;
case 'S':
XFillRectangle(dpy, pix, gc, 0, 0, w, 1);
break;
case 'W':
- XFillRectangle(dpy, pix, gc, w - DOCKBORDER, 0, 1, h);
+ XFillRectangle(dpy, pix, gc, w - DOCKBORDER, 0, DOCKBORDER, h);
break;
default:
case 'E':
- XFillRectangle(dpy, pix, gc, 0, 0, 1, h);
+ XFillRectangle(dpy, pix, gc, 0, 0, DOCKBORDER, h);
break;
}
return;
diff --git a/xevents.c b/xevents.c
@@ -438,6 +438,9 @@ getwintype(Window win, Window *leader, struct Tab **tab, int *state, XRectangle
if (strcasestr(xval.addr, "shrunk") != NULL) {
*state |= SHRUNK;
}
+ if (strcasestr(xval.addr, "resized") != NULL) {
+ *state |= RESIZED;
+ }
}
/* check for dockapp position */
@@ -693,10 +696,11 @@ manage(Window win, XRectangle rect, int ignoreunmap)
static void
alttab(XEvent *e)
{
- struct Container *c;
+ struct Container *c, *prevfocused;
XEvent ev;
int raised;
+ prevfocused = wm.focused;
if ((c = TAILQ_FIRST(&wm.focusq)) == NULL)
return;
ev = *e;
@@ -733,6 +737,7 @@ done:
return;
if (raised) {
containerbacktoplace(c, raised);
+ wm.focused = prevfocused;
tabfocus(c->selcol->selrow->seltab, 0);
}
}
@@ -751,7 +756,7 @@ mouseretab(struct Tab *tab, int xroot, int yroot, int x, int y)
row = tab->row;
c = row->col->c;
if (XGrabPointer(dpy, root, False, ButtonReleaseMask | PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime) != GrabSuccess)
- goto done;
+ goto error;
tabdetach(tab, xroot - x, yroot - y);
containermoveresize(c, 0);
XUnmapWindow(dpy, tab->title);
@@ -792,7 +797,11 @@ done:
c = ((struct Tab *)obj)->row->col->c;
XTranslateCoordinates(dpy, ev.xbutton.window, c->frame, ev.xbutton.x_root, ev.xbutton.y_root, &x, &y, &win);
}
- if (c == NULL || !tabattach(c, tab, x, y)) {
+ if (row->col->c != c) {
+ XUnmapWindow(dpy, tab->frame);
+ XReparentWindow(dpy, tab->frame, root, x, y);
+ }
+ if (!tabattach(c, tab, x, y)) {
mon = getmon(x, y);
if (mon == NULL)
mon = wm.selmon;
@@ -808,6 +817,8 @@ done:
);
}
containerdelrow(row);
+ ewmhsetactivewindow(tab->obj.win);
+error:
XUngrabPointer(dpy, CurrentTime);
}
@@ -1220,9 +1231,16 @@ xeventbuttonpress(XEvent *e)
ev = &e->xbutton;
if ((obj = getmanaged(ev->window)) == NULL) {
- /* if user clicked in no window, focus the monitor below cursor */
- if ((mon = getmon(ev->x_root, ev->y_root)) != NULL)
+ /*
+ * If user clicked in no managed window, focus the
+ * monitor below the cursor, but only if the click
+ * occurred inside monitor's window area.
+ */
+ if ((mon = getmon(ev->x_root, ev->y_root)) != NULL &&
+ ev->x_root >= mon->wx && ev->x_root < mon->wx + mon->ww &&
+ ev->y_root >= mon->wy && ev->y_root < mon->wy + mon->wh) {
deskfocus(mon, mon->seldesk);
+ }
goto done;
}
@@ -1516,7 +1534,9 @@ xeventconfigurenotify(XEvent *e)
ev = &e->xconfigure;
if (ev->window == root) {
monupdate();
+ monupdatearea();
notifplace();
+ dockupdate();
}
}
@@ -1564,8 +1584,7 @@ xeventdestroynotify(XEvent *e)
ev = &e->xdestroywindow;
if ((obj = getmanaged(ev->window)) != NULL) {
if (obj->win == ev->window && (*unmanagefuncs[obj->type])(obj, 0)) {
- ewmhsetclients();
- ewmhsetclientsstacking();
+ wm.setclientlist = 1;
}
}
}
@@ -1752,8 +1771,7 @@ xeventunmapnotify(XEvent *e)
ev = &e->xunmap;
if ((obj = getmanaged(ev->window)) != NULL) {
if (obj->win == ev->window && (*unmanagefuncs[obj->type])(obj, 1)) {
- ewmhsetclients();
- ewmhsetclientsstacking();
+ wm.setclientlist = 1;
}
}
}
diff --git a/xhints.c b/xhints.c
@@ -30,24 +30,17 @@ getwinname(Window win)
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)
+ if (config.disablehidden || c == NULL)
return 0;
+ if (w <= 0 || h <= 0)
+ return 1;
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, h))
- 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 isobscured(c, mon, desk, x, y, w, c->y - y) &&
+ isobscured(c, mon, desk, x, y, c->x - x, h) &&
+ isobscured(c, mon, desk, x, c->y + c->h, w, y + h - (c->y + c->h)) &&
+ isobscured(c, mon, desk, c->x + c->w, y, x + w - (c->x + c->w), h);
}
return 0;
}
@@ -90,50 +83,32 @@ ewmhsetshowingdesktop(int n)
XChangeProperty(dpy, root, atoms[_NET_SHOWING_DESKTOP], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&n, 1);
}
-/* set list of clients hint */
-void
-ewmhsetclients(void)
-{
- struct Object *tab;
- struct Container *c;
- Window *wins = NULL;
- int i = 0;
-
- if (wm.nclients < 1) {
- XChangeProperty(dpy, root, atoms[_NET_CLIENT_LIST], XA_WINDOW, 32, PropModeReplace, NULL, 0);
- return;
- }
- wins = ecalloc(wm.nclients, sizeof *wins);
- TAILQ_FOREACH(c, &wm.focusq, entry) {
- TAB_FOREACH_BEGIN(c, tab){
- wins[i++] = tab->win;
- }TAB_FOREACH_END
- }
- XChangeProperty(dpy, root, atoms[_NET_CLIENT_LIST], XA_WINDOW, 32, PropModeReplace, (unsigned char *)wins, i);
- free(wins);
-}
-
/* set stacking list of clients hint */
void
-ewmhsetclientsstacking(void)
+ewmhsetclients(void)
{
Window *wins = NULL;
+ Window *cnts = NULL;
struct Container *c;
struct Column *col;
struct Row *row;
struct Object *p;
struct Tab *t;
- int prevobscured, i;
+ int prevobscured, i, j = 0;
if (wm.nclients < 1) {
+ XChangeProperty(dpy, root, atoms[_NET_CLIENT_LIST], XA_WINDOW, 32, PropModeReplace, NULL, 0);
XChangeProperty(dpy, root, atoms[_NET_CLIENT_LIST_STACKING], XA_WINDOW, 32, PropModeReplace, NULL, 0);
+ XChangeProperty(dpy, root, atoms[_SHOD_CONTAINER_LIST], XA_WINDOW, 32, PropModeReplace, NULL, 0);
return;
}
wins = ecalloc(wm.nclients, sizeof *wins);
+ cnts = ecalloc(wm.nclients, sizeof *cnts);
i = wm.nclients;
TAILQ_FOREACH(c, &wm.stackq, raiseentry) {
if (ISDUMMY(c))
continue;
+ cnts[j++] = c->selcol->selrow->seltab->obj.win;
prevobscured = c->isobscured;
if (!config.disablehidden)
c->isobscured = isobscured(c, c->mon, c->desk, c->x, c->y, c->w, c->h);
@@ -163,8 +138,11 @@ ewmhsetclientsstacking(void)
ewmhsetstate(c);
}
}
+ XChangeProperty(dpy, root, atoms[_NET_CLIENT_LIST], XA_WINDOW, 32, PropModeReplace, (unsigned char *)wins, wm.nclients-i);
XChangeProperty(dpy, root, atoms[_NET_CLIENT_LIST_STACKING], XA_WINDOW, 32, PropModeReplace, (unsigned char *)wins+i, wm.nclients-i);
+ XChangeProperty(dpy, root, atoms[_SHOD_CONTAINER_LIST], XA_WINDOW, 32, PropModeReplace, (unsigned char *)cnts, j);
free(wins);
+ free(cnts);
}
/* set active window hint */
diff --git a/xmon.c b/xmon.c
@@ -61,7 +61,7 @@ getmon(int x, int y)
struct Monitor *mon;
TAILQ_FOREACH(mon, &wm.monq, entry)
- if (x >= mon->mx && x <= mon->mx + mon->mw && y >= mon->my && y <= mon->my + mon->mh)
+ if (x >= mon->mx && x < mon->mx + mon->mw && y >= mon->my && y < mon->my + mon->mh)
return mon;
return NULL;
}
@@ -148,7 +148,7 @@ monupdate(void)
splashplace(wm.selmon, (struct Splash *)s);
if (focus != NULL) /* if a contained changed desktop, focus it */
tabfocus(focus->selcol->selrow->seltab, 1);
- ewmhsetclientsstacking();
+ wm.setclientlist = 1;
free(unique);
}
@@ -233,7 +233,7 @@ monupdatearea(void)
containerredecorate(c, NULL, NULL, 0);
}
}
- ewmhsetclientsstacking();
+ wm.setclientlist = 1;
}
/* if window is bigger than monitor, resize it while maintaining proportion */
diff --git a/xutil.c b/xutil.c
@@ -57,6 +57,7 @@ static char *atomnames[ATOM_LAST] = {
[_MOTIF_WM_HINTS] = "_MOTIF_WM_HINTS",
[_SHOD_GROUP_TAB] = "_SHOD_GROUP_TAB",
[_SHOD_GROUP_CONTAINER] = "_SHOD_GROUP_CONTAINER",
+ [_SHOD_CONTAINER_LIST] = "_SHOD_CONTAINER_LIST",
};
Visual *visual;
diff --git a/xutil.h b/xutil.h
@@ -68,6 +68,7 @@ enum {
/* shod atoms */
_SHOD_GROUP_TAB,
_SHOD_GROUP_CONTAINER,
+ _SHOD_CONTAINER_LIST,
ATOM_LAST
};