summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAbhinav Prasai <abhinav.prsai@gmail.com>2025-11-22 15:35:59 +0000
committerAbhinav Prasai <abhinav.prsai@gmail.com>2025-11-22 15:35:59 +0000
commit587059c2ee76a82709693659689577f2772b6b2a (patch)
tree538cdba56009a51638d69a262b11a85a03887fe3 /src
parent236e857f22be5aee9814f0dc7e02ba2cf88a5e4c (diff)
fix mishandling of struts
Diffstat (limited to 'src')
-rw-r--r--src/sxwm.c154
1 files changed, 132 insertions, 22 deletions
diff --git a/src/sxwm.c b/src/sxwm.c
index a91f072..23a5544 100644
--- a/src/sxwm.c
+++ b/src/sxwm.c
@@ -3193,17 +3193,25 @@ void update_struts(void)
{
/* reset all reserves */
for (int i = 0; i < n_mons; i++) {
- mons[i].reserve_left = mons[i].reserve_right = mons[i].reserve_top = mons[i].reserve_bottom = 0;
+ mons[i].reserve_left = 0;
+ mons[i].reserve_right = 0;
+ mons[i].reserve_top = 0;
+ mons[i].reserve_bottom = 0;
}
- Window root_ret, parent_ret, *children;
- unsigned int nchildren;
+ Window root_ret;
+ Window parent_ret;
+ Window *children = NULL;
+ unsigned int n_children = 0;
- if (!XQueryTree(dpy, root, &root_ret, &parent_ret, &children, &nchildren)) {
+ if (!XQueryTree(dpy, root, &root_ret, &parent_ret, &children, &n_children)) {
return;
}
- for (unsigned int i = 0; i < nchildren; i++) {
+ int screen_w = scr_width;
+ int screen_h = scr_height;
+
+ for (unsigned int i = 0; i < n_children; i++) {
Window w = children[i];
Atom actual_type;
@@ -3211,8 +3219,9 @@ void update_struts(void)
unsigned long n_items, bytes_after;
Atom *types = NULL;
- if (XGetWindowProperty(dpy, w, _NET_WM_WINDOW_TYPE, 0, 4, False, XA_ATOM, &actual_type, &actual_format,
- &n_items, &bytes_after, (unsigned char **)&types) != Success || !types) {
+ if (XGetWindowProperty(dpy, w, _NET_WM_WINDOW_TYPE, 0, 4, False, XA_ATOM,
+ &actual_type, &actual_format, &n_items, &bytes_after,
+ (unsigned char **)&types) != Success || !types) {
continue;
}
@@ -3231,27 +3240,128 @@ void update_struts(void)
long *str = NULL;
Atom actual;
int sfmt;
- unsigned long len, rem;
+ unsigned long len;
+ unsigned long rem;
+
+ if (XGetWindowProperty(dpy, w, _NET_WM_STRUT_PARTIAL, 0, 12, False, XA_CARDINAL,
+ &actual, &sfmt, &len, &rem,
+ (unsigned char **)&str) == Success && str && len >= 12) {
+
+ /*
+ ewmh:
+ [0] left, [1] right, [2] top, [3] bottom
+
+ [4] left_start_y, [5] left_end_y
+ [6] right_start_y, [7] right_end_y
+ [8] top_start_x, [9] top_end_x
+ [10] bottom_start_x,[11] bottom_end_x
+
+ all coords are in root space.
+ */
+ long left = str[0];
+ long right = str[1];
+ long top = str[2];
+ long bottom = str[3];
+ long left_start_y = str[4];
+ long left_end_y = str[5];
+ long right_start_y = str[6];
+ long right_end_y = str[7];
+ long top_start_x = str[8];
+ long top_end_x = str[9];
+ long bot_start_x = str[10];
+ long bot_end_x = str[11];
- if (XGetWindowProperty(dpy, w, _NET_WM_STRUT_PARTIAL, 0, 12, False, XA_CARDINAL, &actual, &sfmt, &len, &rem,
- (unsigned char **)&str) == Success && str && len >= 4) {
- XWindowAttributes wa;
- if (XGetWindowAttributes(dpy, w, &wa)) {
- /* find the monitor this dock belongs to */
- for (int m = 0; m < n_mons; m++) {
- if (wa.x >= mons[m].x && wa.x < mons[m].x + mons[m].w && wa.y >= mons[m].y &&
- wa.y < mons[m].y + mons[m].h) {
- mons[m].reserve_left = MAX(mons[m].reserve_left, str[0]);
- mons[m].reserve_right = MAX(mons[m].reserve_right, str[1]);
- mons[m].reserve_top = MAX(mons[m].reserve_top, str[2]);
- mons[m].reserve_bottom = MAX(mons[m].reserve_bottom, str[3]);
+ XFree(str);
+
+ /* skip empty struts */
+ if (!left && !right && !top && !bottom) {
+ continue;
+ }
+
+ for (int m = 0; m < n_mons; m++) {
+ int mx = mons[m].x;
+ int my = mons[m].y;
+ int mw = mons[m].w;
+ int mh = mons[m].h;
+
+ /* strip monitors whose vertical span dostn intersect */
+ if (left > 0) {
+ long span_start = left_start_y;
+ long span_end = left_end_y;
+ if (span_end >= my && span_start <= my + mh - 1) {
+ /*
+ left is distance from root left edge to reserved area
+ to map to mon, the portion is:
+ reserve_left = MAX(0, left - mx)
+ */
+ int reserve = (int)MAX(0, left - mx);
+ if (reserve > 0) {
+ mons[m].reserve_left = MAX(mons[m].reserve_left, reserve);
+ }
+ }
+ }
+
+ if (right > 0) {
+ long span_start = right_start_y;
+ long span_end = right_end_y;
+ if (span_end >= my && span_start <= my + mh - 1) {
+ /*
+ right is distance from root right edge to reserved area:
+ right edge = screen_w
+ mons right edge = mx + mw
+ amount that cuts into monitor = MAX(0, (screen_w - right) - mx)
+ */
+ int global_reserved_left = screen_w - (int)right;
+ int overlap = (mx + mw) - global_reserved_left;
+ int reserve = MAX(0, overlap);
+ if (reserve > 0) {
+ mons[m].reserve_right = MAX(mons[m].reserve_right, reserve);
+ }
+ }
+ }
+
+ if (top > 0) {
+ long span_start = top_start_x;
+ long span_end = top_end_x;
+ if (span_end >= mx && span_start <= mx + mw - 1) {
+ /*
+ top is distance from root top to reserved area
+ mons top is at my, amount eaten:
+ reserve_top = MAX(0, top - my)
+ */
+ int reserve = (int)MAX(0, top - my);
+ if (reserve > 0) {
+ mons[m].reserve_top = MAX(mons[m].reserve_top, reserve);
+ }
+ }
+ }
+
+ if (bottom > 0) {
+ long span_start = bot_start_x;
+ long span_end = bot_end_x;
+ if (span_end >= mx && span_start <= mx + mw - 1) {
+ /*
+ bottom is distance from root bottom to reserved area
+ global_reserved_top = screen_h - bottom;
+ overlap to mon:
+ overlap = (my + mh) - global_reserved_top;
+ reserve_bottom = MAX(0, overlap)
+ */
+ int global_reserved_top = screen_h - (int)bottom;
+ int overlap = (my + mh) - global_reserved_top;
+ int reserve = MAX(0, overlap);
+ if (reserve > 0) {
+ mons[m].reserve_bottom = MAX(mons[m].reserve_bottom, reserve);
+ }
}
}
}
- XFree(str);
}
}
- XFree(children);
+
+ if (children) {
+ XFree(children);
+ }
update_workarea();
}