tImplement double-borders to make focused window stand out - glazier - window management experiments
DIR Log
DIR Files
DIR Refs
DIR Submodules
DIR README
DIR LICENSE
---
DIR commit 6f9e37ae8b9d105da3b35a4e6dca2ce4b502ffc3
DIR parent 150c2a4e6e0e3e69da4e7c2d3601a84a052222b5
HTML Author: Willy Goiffon <dev@z3bra.org>
Date: Mon, 22 Jun 2020 12:54:41 +0200
Implement double-borders to make focused window stand out
Diffstat:
M config.def.h | 3 ++-
M glazier.c | 119 +++++++++++++++++++++++++++++--
2 files changed, 115 insertions(+), 7 deletions(-)
---
DIR diff --git a/config.def.h b/config.def.h
t@@ -10,7 +10,8 @@ char *xhair[] = {
int modifier = XCB_MOD_MASK_1;
/* window borders and titlebar */
-int border = 2;
+int border = 8;
+int inner_border = 2;
uint32_t border_color = 0x666666;
uint32_t border_color_active = 0xdeadca7;
DIR diff --git a/glazier.c b/glazier.c
t@@ -142,6 +142,12 @@ adopt(xcb_window_t wid)
| XCB_EVENT_MASK_STRUCTURE_NOTIFY);
}
+/*
+ * Return the color of the pixel in one of the window corners.
+ * Each corner is tested in a clockwise fashion until an uncovered region
+ * is found. When such pixel is found, the color is returned.
+ * If no color is found a default of border_color is returned.
+ */
uint32_t
backpixel(xcb_window_t wid)
{
t@@ -173,13 +179,109 @@ backpixel(xcb_window_t wid)
return color ? color : border_color;
}
+/*
+ * Paint double borders around the window. The background is taken from
+ * the window content via backpixel(), and the border line is drawn on
+ * top of it using the colors defined in config.h.
+ *
+ * Note: drawing on the borders require specifying regions from position
+ * the top-left corner of the window itself. Drawing on the border pixmap
+ * is done by drawing outside the window, and then wrapping over to the
+ * left side. For example, assuming a window of 200x100, with a 10px
+ * border, drawing a 5px square in the top left of the border means drawing
+ * a 5x5 rectangle at position 210,110. The area does not wrap around
+ * indefinitely though, so drawing a rectangle of 10x10 or 200x10 at
+ * position 210,110 would have the same effect: draw a 10x10 square in
+ * the top right. uugh…
+ */
int
paint(xcb_window_t wid)
{
- if (wid == wm_get_focus())
- return wm_set_border(border, border_color_active, wid);
+ int val[2], w, h, b, i;
+ xcb_pixmap_t px;
+ xcb_gcontext_t gc;
+ xcb_rectangle_t r[8];
+
+ w = wm_get_attribute(wid, ATTR_W);
+ h = wm_get_attribute(wid, ATTR_H);
+ b = border;
+ i = inner_border;
+
+ wm_set_border(border, border_color, wid);
- return wm_set_border(border, backpixel(wid), wid);
+ px = xcb_generate_id(conn);
+ gc = xcb_generate_id(conn);
+
+ val[0] = backpixel(wid);
+ xcb_create_gc(conn, gc, wid, XCB_GC_FOREGROUND, val);
+ xcb_create_pixmap(conn, scrn->root_depth, px, wid, w + 2*b, h + 2*b);
+
+ /* background color */
+ r[0].x = 0;
+ r[0].y = 0;
+ r[0].width = w + 2*b;
+ r[0].height = h + 2*b;
+
+ xcb_poly_fill_rectangle(conn, px, gc, 1, r);
+
+ /* right */
+ r[0].x = w + (b-i)/2;
+ r[0].y = 0;
+ r[0].width = i;
+ r[0].height = h + (b+i)/2;
+
+ /* left */
+ r[1].x = w + b + (b-i)/2;
+ r[1].y = 0;
+ r[1].width = i;
+ r[1].height = h + (b+i)/2;
+
+ /* bottom; bottom-right corner */
+ r[2].x = 0;
+ r[2].y = h + (b-i)/2;
+ r[2].width = w + (b-i)/2 + i;
+ r[2].height = i;
+
+ /* top; top-right */
+ r[3].x = 0;
+ r[3].y = h + b + (b-i)/2;
+ r[3].width = w + (b+i)/2;
+ r[3].height = i;
+
+ /* top-left corner; top-part */
+ r[4].x = w + b + (b-i)/2;
+ r[4].y = h + b + (b-i)/2;
+ r[4].width = i + (b-i/2);
+ r[4].height = i;
+
+ /* top-left corner; left-part */
+ r[5].x = w + b + (b-i)/2;
+ r[5].y = h + b + (b-i)/2;
+ r[5].width = i;
+ r[5].height = i + (b-i/2);
+
+ /* top-right corner; right-part */
+ r[6].x = w + b + (b-i)/2;
+ r[6].y = h + (b-i)/2;
+ r[6].width = i + (b-i)/2;
+ r[6].height = i;
+
+ /* bottom-left corner; bottom-part */
+ r[7].x = w + (b-i)/2;
+ r[7].y = h + b + (b-i)/2;
+ r[7].width = i;
+ r[7].height = i + (b-i)/2;
+
+ val[0] = (wid == wm_get_focus()) ? border_color_active : border_color;
+ xcb_change_gc(conn, gc, XCB_GC_FOREGROUND, val);
+ xcb_poly_fill_rectangle(conn, px, gc, 8, r);
+
+ xcb_change_window_attributes(conn, wid, XCB_CW_BORDER_PIXMAP, &px);
+
+ xcb_free_pixmap(conn, px);
+ xcb_free_gc(conn, gc);
+
+ return 0;
}
/*
t@@ -228,8 +330,10 @@ takeover()
}
wid = wm_get_focus();
- if (wid != scrn->root)
+ if (wid != scrn->root) {
+ curwid = wid;
paint(wid);
+ }
return n;
}
t@@ -659,6 +763,9 @@ cb_configreq(xcb_generic_event_t *ev)
wm_teleport(e->window, x, y, w, h);
+ /* redraw border pixmap after move/resize */
+ paint(e->window);
+
if (e->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH)
wm_set_border(e->border_width, border_color, e->window);
t@@ -737,7 +844,7 @@ crossedge(xcb_window_t wid)
r = 1;
free(m);
-
+
return r;
}
t@@ -767,7 +874,7 @@ snaptoedge(xcb_window_t wid)
if (y + h + 2*b > m->y + m->height) y = MAX(m->y + b, m->y + m->height - h - 2*b);
wm_teleport(wid, x, y, w, h);
-
+
return 0;
}