Second version of tmux-borders patch

This commit is contained in:
kerberoge 2025-06-01 17:07:15 +02:00
parent cd083aa858
commit 585949952f
2 changed files with 203 additions and 124 deletions

View File

@ -2,7 +2,8 @@
This patch replaces the window borders of tiled windows with borders that are similar to those found in tmux. The result is that there are no more unnecessary borders along the monitor edges in tiled mode. Borders of floating windows are not affected.
### Preview
![two clients](screenshot1.png)\
![two clients](screenshot1.png)
![three clients](screenshot2.png)
### Download

View File

@ -1,12 +1,12 @@
From 7561af3d37179bf6b1de00741e65e0afcc6ec961 Mon Sep 17 00:00:00 2001
From 5129a2fb5d6a1e95a1d57943aeea5ba319949ba1 Mon Sep 17 00:00:00 2001
From: kerberoge <sjoerdenjh@gmail.com>
Date: Thu, 22 May 2025 20:34:32 +0200
Subject: [PATCH 1/1] Created tmux-borders patch
Date: Sun, 1 Jun 2025 17:03:09 +0200
Subject: [PATCH 1/1] Created tmux-borders patch for stock dwl
---
client.h | 6 ++
dwl.c | 249 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 235 insertions(+), 20 deletions(-)
dwl.c | 290 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 274 insertions(+), 22 deletions(-)
diff --git a/client.h b/client.h
index 42f225f..007ab7d 100644
@ -26,14 +26,14 @@ index 42f225f..007ab7d 100644
client_notify_enter(struct wlr_surface *s, struct wlr_keyboard *kb)
{
diff --git a/dwl.c b/dwl.c
index a2711f6..5df3e68 100644
index a2711f6..fa0e1c8 100644
--- a/dwl.c
+++ b/dwl.c
@@ -191,6 +191,7 @@ struct Monitor {
struct wlr_output *wlr_output;
struct wlr_scene_output *scene_output;
struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */
+ struct wlr_scene_tree *borders, *fborders;
+ struct wlr_scene_tree *borders, *fborders, *uborders;
struct wl_listener frame;
struct wl_listener destroy;
struct wl_listener request_state;
@ -50,40 +50,40 @@ index a2711f6..5df3e68 100644
static void createdecoration(struct wl_listener *listener, void *data);
static void createidleinhibitor(struct wl_listener *listener, void *data);
static void createkeyboard(struct wlr_keyboard *keyboard);
@@ -285,6 +288,10 @@ static void destroysessionlock(struct wl_listener *listener, void *data);
@@ -273,6 +276,7 @@ static void createpopup(struct wl_listener *listener, void *data);
static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint);
static void cursorframe(struct wl_listener *listener, void *data);
static void cursorwarptohint(void);
+static void destroyborders(struct wlr_scene_tree *t);
static void destroydecoration(struct wl_listener *listener, void *data);
static void destroydragicon(struct wl_listener *listener, void *data);
static void destroyidleinhibitor(struct wl_listener *listener, void *data);
@@ -285,6 +289,13 @@ static void destroysessionlock(struct wl_listener *listener, void *data);
static void destroysessionmgr(struct wl_listener *listener, void *data);
static void destroykeyboardgroup(struct wl_listener *listener, void *data);
static Monitor *dirtomon(enum wlr_direction dir);
+static void drawborder(struct wlr_scene_tree *t,
+ int x, int y, int w, int h, const float c[static 4]);
+static void drawclientborders(struct wlr_scene_tree *t, Client *c,
+ int cidx, int n, const float color[static 4]);
+static void drawrect(struct wlr_scene_tree *t,
+ int x, int y, int w, int h, const float color[static 4]);
+static void drawborders(Monitor *m);
+static void drawfborders(Monitor *m);
+static void drawuborders(Monitor *m);
static void focusclient(Client *c, int lift);
static void focusmon(const Arg *arg);
static void focusstack(const Arg *arg);
@@ -517,6 +524,10 @@ arrange(Monitor *m)
@@ -517,6 +528,11 @@ arrange(Monitor *m)
if (m->lt[m->sellt]->arrange)
m->lt[m->sellt]->arrange(m);
+
+ drawborders(m);
+ drawuborders(m);
+ drawfborders(m);
+
motionnotify(0, NULL, 0, 0, 0, 0);
checkidleinhibitor(NULL);
}
@@ -712,6 +723,11 @@ cleanupmon(struct wl_listener *listener, void *data)
wlr_layer_surface_v1_destroy(l->layer_surface);
}
+ if (m->borders)
+ wlr_scene_node_destroy(&m->borders->node);
+ if (m->fborders)
+ wlr_scene_node_destroy(&m->fborders->node);
+
wl_list_remove(&m->destroy.link);
wl_list_remove(&m->frame.link);
wl_list_remove(&m->link);
@@ -725,6 +741,27 @@ cleanupmon(struct wl_listener *listener, void *data)
free(m);
}
@ -112,7 +112,18 @@ index a2711f6..5df3e68 100644
void
closemon(Monitor *m)
{
@@ -849,6 +886,19 @@ commitpopup(struct wl_listener *listener, void *data)
@@ -743,6 +780,10 @@ closemon(Monitor *m)
selmon = NULL;
}
+ wlr_scene_node_destroy(&m->borders->node);
+ wlr_scene_node_destroy(&m->fborders->node);
+ wlr_scene_node_destroy(&m->uborders->node);
+
wl_list_for_each(c, &clients, link) {
if (c->isfloating && c->geom.x > m->m.width)
resize(c, (struct wlr_box){.x = c->geom.x - m->w.width, .y = c->geom.y,
@@ -849,6 +890,19 @@ commitpopup(struct wl_listener *listener, void *data)
wl_list_remove(&listener->link);
}
@ -132,123 +143,60 @@ index a2711f6..5df3e68 100644
void
createdecoration(struct wl_listener *listener, void *data)
{
@@ -985,6 +1035,8 @@ createmon(struct wl_listener *listener, void *data)
@@ -985,6 +1039,9 @@ createmon(struct wl_listener *listener, void *data)
m = wlr_output->data = ecalloc(1, sizeof(*m));
m->wlr_output = wlr_output;
+ m->borders = NULL;
+ m->fborders = NULL;
+ m->borders = wlr_scene_tree_create(layers[LyrTile]);
+ m->fborders = wlr_scene_tree_create(layers[LyrTile]);
+ m->uborders = wlr_scene_tree_create(layers[LyrTile]);
for (i = 0; i < LENGTH(m->layers); i++)
wl_list_init(&m->layers[i]);
@@ -1336,6 +1388,135 @@ dirtomon(enum wlr_direction dir)
@@ -1171,6 +1228,15 @@ cursorwarptohint(void)
}
}
+void
+destroyborders(struct wlr_scene_tree *t)
+{
+ struct wlr_scene_node *node, *tmp;
+
+ wl_list_for_each_safe(node, tmp, &t->children, link)
+ wlr_scene_node_destroy(node);
+}
+
void
destroydecoration(struct wl_listener *listener, void *data)
{
@@ -1336,6 +1402,154 @@ dirtomon(enum wlr_direction dir)
return selmon;
}
+void
+drawborder(struct wlr_scene_tree *t, int x, int y, int w, int h, const float c[static 4])
+drawclientborders(struct wlr_scene_tree *t, Client *c, int cidx, int n, const float color[static 4])
+{
+ struct wlr_scene_rect *r;
+
+ r = wlr_scene_rect_create(t, w, h, c);
+ wlr_scene_node_set_position(&r->node, x, y);
+}
+
+void
+drawborders(Monitor *m)
+{
+ int n, i;
+ int mw, tw, my = 0, ty = 0;
+
+ if (!m)
+ return;
+
+ if (m->borders) {
+ wlr_scene_node_destroy(&m->borders->node);
+ m->borders = NULL;
+ }
+
+ n = countclients(m);
+
+ if (!n || m->lt[m->sellt]->arrange != tile)
+ return;
+
+ m->borders = wlr_scene_tree_create(layers[LyrTile]);
+
+ if (m->nmaster > 0 && n > m->nmaster)
+ mw = (int)round(m->w.width * m->mfact - 0.5 * borderpx);
+ else if (n <= m->nmaster)
+ mw = m->w.width;
+ else
+ mw = 0;
+
+ if (mw > 0)
+ tw = m->w.width - mw - borderpx;
+ else
+ tw = m->w.width;
+
+ /* Vertical center line */
+ if (mw > 0 && mw < m->w.width)
+ drawborder(m->borders, m->w.x + mw, m->w.y, borderpx, m->w.height, bordercolor);
+
+ /* Lines between master clients */
+ for (i = 0; i < MIN(n, m->nmaster) - 1; i++) {
+ my += (m->w.height - my - borderpx * (MIN(n, m->nmaster) - i - 1))
+ / (MIN(n, m->nmaster) - i);
+ drawborder(m->borders, m->w.x, m->w.y + my, mw, borderpx, bordercolor);
+ my += borderpx;
+ }
+
+ /* Lines between clients on the stack */
+ for (i = m->nmaster; i < n - 1; i++) {
+ ty += (m->w.height - ty - borderpx * (n - i - 1)) / (n - i);
+ drawborder(m->borders, m->m.x + (mw ? mw + borderpx : 0), m->w.y + ty,
+ tw, borderpx, bordercolor);
+ ty += borderpx;
+ }
+}
+
+void
+drawfborders(Monitor *m)
+{
+ Client *fc;
+ int n, cidx;
+ Monitor *m;
+ int mw, x, y, w, h;
+
+ if (!m)
+ return;
+
+ if (m->fborders) {
+ wlr_scene_node_destroy(&m->fborders->node);
+ m->fborders = NULL;
+ }
+
+ fc = focustop(m);
+ n = countclients(m);
+ cidx = clientindex(m, fc);
+
+ if (!n || cidx == -1)
+ return;
+
+ m->fborders = wlr_scene_tree_create(layers[LyrTile]);
+ m = c->mon;
+ mw = (int)round(m->w.width * m->mfact - 0.5 * borderpx);
+
+ if (m->nmaster == 1 && n == 2) {
+ /* Half vertical center line */
+ y = m->w.y + (cidx == 1 ? m->w.height / 2 : 0);
+ h = (int)round(0.5 * m->w.height);
+ drawborder(m->fborders, m->w.x + mw, y, borderpx, h, focuscolor);
+ } else if (m->nmaster == 2 && n == 2) {
+ drawrect(t, m->w.x + mw, y, borderpx, h, color);
+ } else if (m->nmaster != 1 && n == 2) {
+ /* Half horizontal center line */
+ x = m->w.x + (cidx == 1 ? m->w.width / 2 : 0);
+ y = m->w.y + (int)round(0.5 * m->w.height - 0.5 * borderpx);
+ w = (int)round(0.5 * m->w.width);
+ drawborder(m->fborders, x, y, w, borderpx, focuscolor);
+ drawrect(t, x, y, w, borderpx, color);
+ } else {
+ if (m->nmaster && n > m->nmaster)
+ /* Vertical line next to client */
+ drawborder(m->fborders, m->w.x + mw, fc->geom.y,
+ borderpx, fc->geom.height, focuscolor);
+ drawrect(t, m->w.x + mw, c->geom.y, borderpx, c->geom.height, color);
+
+ if (n > m->nmaster && cidx < m->nmaster) {
+ /* Left half */
@ -266,28 +214,134 @@ index a2711f6..5df3e68 100644
+
+ if ((cidx > 0 && cidx < m->nmaster) || (cidx > m->nmaster))
+ /* Line above client */
+ drawborder(m->fborders, x, fc->geom.y - borderpx, w, borderpx, focuscolor);
+ drawrect(t, x, c->geom.y - borderpx, w, borderpx, color);
+
+ if ((cidx < m->nmaster - 1) || (cidx >= m->nmaster && cidx < n - 1))
+ /* Line below client */
+ drawborder(m->fborders, x, fc->geom.y + fc->geom.height, w, borderpx, focuscolor);
+ drawrect(t, x, c->geom.y + c->geom.height, w, borderpx, color);
+ }
+}
+
+void
+drawrect(struct wlr_scene_tree *t, int x, int y, int w, int h, const float color[static 4])
+{
+ struct wlr_scene_rect *r;
+
+ r = wlr_scene_rect_create(t, w, h, color);
+ wlr_scene_node_set_position(&r->node, x, y);
+}
+
+void
+drawborders(Monitor *m)
+{
+ int n, i;
+ int mw, tw, my = 0, ty = 0;
+
+ if (!m)
+ return;
+
+ destroyborders(m->borders);
+ n = countclients(m);
+
+ if (n <= 1 || m->lt[m->sellt]->arrange != tile)
+ return;
+
+ if (m->nmaster > 0 && n > m->nmaster)
+ mw = (int)round(m->w.width * m->mfact - 0.5 * borderpx);
+ else if (n <= m->nmaster)
+ mw = m->w.width;
+ else
+ mw = 0;
+
+ if (mw > 0)
+ tw = m->w.width - mw - borderpx;
+ else
+ tw = m->w.width;
+
+ /* Vertical center line */
+ if (mw > 0 && mw < m->w.width)
+ drawrect(m->borders, m->w.x + mw, m->w.y, borderpx, m->w.height, bordercolor);
+
+ /* Lines between master clients */
+ for (i = 0; i < MIN(n, m->nmaster) - 1; i++) {
+ my += (m->w.height - my - borderpx * (MIN(n, m->nmaster) - i - 1))
+ / (MIN(n, m->nmaster) - i);
+ drawrect(m->borders, m->w.x, m->w.y + my, mw, borderpx, bordercolor);
+ my += borderpx;
+ }
+
+ /* Lines between clients on the stack */
+ for (i = m->nmaster; i < n - 1; i++) {
+ ty += (m->w.height - ty - borderpx * (n - i - 1)) / (n - i);
+ drawrect(m->borders, m->m.x + (mw ? mw + borderpx : 0), m->w.y + ty,
+ tw, borderpx, bordercolor);
+ ty += borderpx;
+ }
+}
+
+void
+drawfborders(Monitor *m)
+{
+ Client *fc;
+ int n, cidx;
+
+ if (!m)
+ return;
+
+ destroyborders(m->fborders);
+ n = countclients(m);
+ fc = focustop(m);
+ cidx = clientindex(m, fc);
+
+ if (n <= 1 || cidx == -1)
+ return;
+
+ drawclientborders(m->fborders, fc, cidx, n, focuscolor);
+}
+
+void
+drawuborders(Monitor *m)
+{
+ Client *c;
+ int n, cidx;
+
+ if (!m)
+ return;
+
+ destroyborders(m->uborders);
+ n = countclients(m);
+
+ if (n <= 1)
+ return;
+
+ wl_list_for_each(c, &clients, link) {
+ cidx = clientindex(m, c);
+ if (cidx != -1 && c->isurgent)
+ drawclientborders(m->uborders, c, cidx, n, urgentcolor);
+ }
+}
+
void
focusclient(Client *c, int lift)
{
@@ -1393,6 +1574,9 @@ focusclient(Client *c, int lift)
@@ -1366,6 +1580,7 @@ focusclient(Client *c, int lift)
wl_list_insert(&fstack, &c->flink);
selmon = c->mon;
c->isurgent = 0;
+ drawuborders(c->mon);
client_restack_surface(c);
/* Don't change border color if there is an exclusive focus or we are
@@ -1393,6 +1608,8 @@ focusclient(Client *c, int lift)
client_activate_surface(old, 0);
}
}
+
+ if (c)
+ drawfborders(c->mon);
+ drawfborders(selmon);
printstatus();
if (!c) {
@@ -2193,15 +2377,20 @@ resize(Client *c, struct wlr_box geo, int interact)
@@ -2193,15 +2410,20 @@ resize(Client *c, struct wlr_box geo, int interact)
applybounds(c, bbox);
/* Update scene-graph, including borders */
@ -315,7 +369,7 @@ index a2711f6..5df3e68 100644
/* this is a no-op if size hasn't changed */
c->resize = client_set_size(c, c->geom.width - 2 * c->bw,
@@ -2359,8 +2548,13 @@ setlayout(const Arg *arg)
@@ -2359,8 +2581,13 @@ setlayout(const Arg *arg)
return;
if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
selmon->sellt ^= 1;
@ -329,7 +383,7 @@ index a2711f6..5df3e68 100644
strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, LENGTH(selmon->ltsymbol));
arrange(selmon);
printstatus();
@@ -2692,31 +2886,46 @@ void
@@ -2692,31 +2919,46 @@ void
tile(Monitor *m)
{
unsigned int mw, my, ty;
@ -389,6 +443,30 @@ index a2711f6..5df3e68 100644
}
i++;
}
@@ -2941,8 +3183,10 @@ urgent(struct wl_listener *listener, void *data)
c->isurgent = 1;
printstatus();
- if (client_surface(c)->mapped)
+ if (client_surface(c)->mapped) {
client_set_border_color(c, urgentcolor);
+ drawuborders(c->mon);
+ }
}
void
@@ -3147,8 +3391,10 @@ sethints(struct wl_listener *listener, void *data)
c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints);
printstatus();
- if (c->isurgent && surface && surface->mapped)
+ if (c->isurgent && surface && surface->mapped) {
client_set_border_color(c, urgentcolor);
+ drawuborders(c->mon);
+ }
}
void
--
2.49.0