mirror of
https://codeberg.org/dwl/dwl-patches.git
synced 2026-06-11 10:23:19 +00:00
btrtile: Spring update pt2
- Simplified the resizing logic to avoid full arrange calls from motionnotify - Minor intend fixes
This commit is contained in:
@@ -1,23 +1,24 @@
|
|||||||
From ad32bb92157d5238340eb53322254dc8127477db Mon Sep 17 00:00:00 2001
|
From 1520d1f200ef0fb381683c1bcd58e553b52ac289 Mon Sep 17 00:00:00 2001
|
||||||
From: julmajustus <julmajustus@tutanota.com>
|
From: julmajustus <julmajustus@tutanota.com>
|
||||||
Date: Sun, 17 May 2026 22:49:07 +0300
|
Date: Thu, 21 May 2026 00:42:07 +0300
|
||||||
Subject: [PATCH] btrtile resizing refactor
|
Subject: [PATCH] btrtile: Spring update pt2
|
||||||
|
|
||||||
- Refactored the tiled client resizing logic to be more logical. Insted
|
- Simplified the resizing logic to avoid full arrange calls from
|
||||||
of resizing based on clients split nodes, now btrtile handles client resizing based on the nearest edge client edge on the resize direction. Now it handles also resizing of the clientless splitnodes and should feel more intuitive.
|
motionnotify
|
||||||
|
- Minor intend fixes
|
||||||
---
|
---
|
||||||
btrtile.c | 582 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
btrtile.c | 583 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
config.def.h | 12 ++
|
config.def.h | 12 ++
|
||||||
dwl.c | 160 +++++++++++---
|
dwl.c | 152 +++++++++++---
|
||||||
3 files changed, 727 insertions(+), 27 deletions(-)
|
3 files changed, 720 insertions(+), 27 deletions(-)
|
||||||
create mode 100644 btrtile.c
|
create mode 100644 btrtile.c
|
||||||
|
|
||||||
diff --git a/btrtile.c b/btrtile.c
|
diff --git a/btrtile.c b/btrtile.c
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 0000000..c63e59f
|
index 0000000..f05a30f
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/btrtile.c
|
+++ b/btrtile.c
|
||||||
@@ -0,0 +1,582 @@
|
@@ -0,0 +1,583 @@
|
||||||
+/* ************************************************************************** */
|
+/* ************************************************************************** */
|
||||||
+/* @@@ @@@@@@@@ */
|
+/* @@@ @@@@@@@@ */
|
||||||
+/* @@@ @@@@@@@@@@ */
|
+/* @@@ @@@@@@@@@@ */
|
||||||
@@ -28,7 +29,7 @@ index 0000000..c63e59f
|
|||||||
+/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */
|
+/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */
|
||||||
+/* ::! :!: !:! */
|
+/* ::! :!: !:! */
|
||||||
+/* Created: 2024/12/15 00:26:07 by julmajustus :: ::::::: :: */
|
+/* Created: 2024/12/15 00:26:07 by julmajustus :: ::::::: :: */
|
||||||
+/* Updated: 2026/05/17 22:00:31 by julmajustus : : : : : : */
|
+/* Updated: 2026/05/20 22:38:02 by julmajustus : : : : : : */
|
||||||
+/* */
|
+/* */
|
||||||
+/* ************************************************************************** */
|
+/* ************************************************************************** */
|
||||||
+
|
+
|
||||||
@@ -63,7 +64,6 @@ index 0000000..c63e59f
|
|||||||
+static unsigned int visible_count(LayoutNode *node, Monitor *m);
|
+static unsigned int visible_count(LayoutNode *node, Monitor *m);
|
||||||
+static Client *xytoclient(double x, double y);
|
+static Client *xytoclient(double x, double y);
|
||||||
+
|
+
|
||||||
+static int resizing_from_mouse = 0;
|
|
||||||
+static double resize_last_update_x, resize_last_update_y;
|
+static double resize_last_update_x, resize_last_update_y;
|
||||||
+static uint32_t last_resize_time = 0;
|
+static uint32_t last_resize_time = 0;
|
||||||
+
|
+
|
||||||
@@ -91,6 +91,9 @@ index 0000000..c63e59f
|
|||||||
+ c = node->client;
|
+ c = node->client;
|
||||||
+ if (!c || !VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
+ if (!c || !VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||||
+ return;
|
+ return;
|
||||||
|
+ if (area.x == c->old_geom.x && area.y == c->old_geom.y &&
|
||||||
|
+ area.width == c->old_geom.width && area.height == c->old_geom.height)
|
||||||
|
+ return;
|
||||||
+ resize(c, area, 0);
|
+ resize(c, area, 0);
|
||||||
+ c->old_geom = area;
|
+ c->old_geom = area;
|
||||||
+ return;
|
+ return;
|
||||||
@@ -169,16 +172,16 @@ index 0000000..c63e59f
|
|||||||
+ LayoutNode *found;
|
+ LayoutNode *found;
|
||||||
+ struct wlr_box full_area;
|
+ struct wlr_box full_area;
|
||||||
+
|
+
|
||||||
+ if (!m)
|
+ if (!m)
|
||||||
+ return;
|
+ return;
|
||||||
+
|
+
|
||||||
+ /* Remove non tiled clients from tree. */
|
+ /* Remove non tiled clients from tree. */
|
||||||
+ wl_list_for_each(c, &clients, link) {
|
+ wl_list_for_each(c, &clients, link) {
|
||||||
+ if (c->mon == m && !c->isfloating && !c->isfullscreen) {
|
+ if (c->mon == m && !c->isfloating && !c->isfullscreen) {
|
||||||
+ } else {
|
+ } else {
|
||||||
+ remove_client(m, c);
|
+ remove_client(m, c);
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ /* If no client is found under cursor, fallback to focustop(m) */
|
+ /* If no client is found under cursor, fallback to focustop(m) */
|
||||||
+ if (!(focused = xytoclient(cursor->x, cursor->y)))
|
+ if (!(focused = xytoclient(cursor->x, cursor->y)))
|
||||||
@@ -272,7 +275,7 @@ index 0000000..c63e59f
|
|||||||
+
|
+
|
||||||
+LayoutNode *
|
+LayoutNode *
|
||||||
+find_suitable_split(Monitor *m, LayoutNode *start_node,
|
+find_suitable_split(Monitor *m, LayoutNode *start_node,
|
||||||
+ unsigned int need_vertical, int focused_on_left)
|
+ unsigned int need_vertical, int focused_on_left)
|
||||||
+{
|
+{
|
||||||
+ LayoutNode *n = start_node, *child = NULL;
|
+ LayoutNode *n = start_node, *child = NULL;
|
||||||
+
|
+
|
||||||
@@ -444,11 +447,11 @@ index 0000000..c63e59f
|
|||||||
+ if (!client_node)
|
+ if (!client_node)
|
||||||
+ return;
|
+ return;
|
||||||
+
|
+
|
||||||
+ focused_on_left = (arg->f >= 0.0f);
|
+ focused_on_left = (arg->f >= 0.0f);
|
||||||
+
|
+
|
||||||
+ split_node = find_suitable_split(selmon, client_node, need_vertical, focused_on_left);
|
+ split_node = find_suitable_split(selmon, client_node, need_vertical, focused_on_left);
|
||||||
+
|
+
|
||||||
+ if (!split_node)
|
+ if (!split_node)
|
||||||
+ split_node = find_suitable_split(selmon, client_node, need_vertical, !focused_on_left);
|
+ split_node = find_suitable_split(selmon, client_node, need_vertical, !focused_on_left);
|
||||||
+ if (!split_node)
|
+ if (!split_node)
|
||||||
+ return;
|
+ return;
|
||||||
@@ -460,10 +463,9 @@ index 0000000..c63e59f
|
|||||||
+ new_ratio = 0.95f;
|
+ new_ratio = 0.95f;
|
||||||
+ split_node->split_ratio = new_ratio;
|
+ split_node->split_ratio = new_ratio;
|
||||||
+
|
+
|
||||||
|
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
||||||
+ /* Skip the arrange when called from motionnotify; that path calls
|
+ /* Skip the arrange when called from motionnotify; that path calls
|
||||||
+ * arrange itself after rate-limiting. */
|
+ * arrange itself after rate-limiting. */
|
||||||
+ if (!resizing_from_mouse)
|
|
||||||
+ arrange(selmon);
|
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+void
|
+void
|
||||||
@@ -479,69 +481,69 @@ index 0000000..c63e59f
|
|||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+void swapclients(const Arg *arg) {
|
+void swapclients(const Arg *arg) {
|
||||||
+ Client *c, *tmp, *target = NULL, *sel = focustop(selmon);
|
+ Client *c, *tmp, *target = NULL, *sel = focustop(selmon);
|
||||||
+ LayoutNode *sel_node, *target_node;
|
+ LayoutNode *sel_node, *target_node;
|
||||||
+ int closest_dist = INT_MAX, dist, sel_center_x, sel_center_y,
|
+ int closest_dist = INT_MAX, dist, sel_center_x, sel_center_y,
|
||||||
+ cand_center_x, cand_center_y;
|
+ cand_center_x, cand_center_y;
|
||||||
+
|
+
|
||||||
+ if (!sel || sel->isfullscreen ||
|
+ if (!sel || sel->isfullscreen ||
|
||||||
+ !selmon->root || !selmon->lt[selmon->sellt]->arrange)
|
+ !selmon->root || !selmon->lt[selmon->sellt]->arrange)
|
||||||
+ return;
|
+ return;
|
||||||
+
|
+
|
||||||
+
|
+
|
||||||
+ /* Get the center coordinates of the selected client */
|
+ /* Get the center coordinates of the selected client */
|
||||||
+ sel_center_x = sel->geom.x + sel->geom.width / 2;
|
+ sel_center_x = sel->geom.x + sel->geom.width / 2;
|
||||||
+ sel_center_y = sel->geom.y + sel->geom.height / 2;
|
+ sel_center_y = sel->geom.y + sel->geom.height / 2;
|
||||||
+
|
+
|
||||||
+ wl_list_for_each(c, &clients, link) {
|
+ wl_list_for_each(c, &clients, link) {
|
||||||
+ if (!VISIBLEON(c, selmon) || c->isfloating || c->isfullscreen || c == sel)
|
+ if (!VISIBLEON(c, selmon) || c->isfloating || c->isfullscreen || c == sel)
|
||||||
+ continue;
|
+ continue;
|
||||||
+
|
+
|
||||||
+ /* Get the center of candidate client */
|
+ /* Get the center of candidate client */
|
||||||
+ cand_center_x = c->geom.x + c->geom.width / 2;
|
+ cand_center_x = c->geom.x + c->geom.width / 2;
|
||||||
+ cand_center_y = c->geom.y + c->geom.height / 2;
|
+ cand_center_y = c->geom.y + c->geom.height / 2;
|
||||||
+
|
+
|
||||||
+ /* Check that the candidate lies in the requested direction. */
|
+ /* Check that the candidate lies in the requested direction. */
|
||||||
+ switch (arg->ui) {
|
+ switch (arg->ui) {
|
||||||
+ case 0:
|
+ case 0:
|
||||||
+ if (cand_center_x >= sel_center_x)
|
+ if (cand_center_x >= sel_center_x)
|
||||||
+ continue;
|
+ continue;
|
||||||
+ break;
|
+ break;
|
||||||
+ case 1:
|
+ case 1:
|
||||||
+ if (cand_center_x <= sel_center_x)
|
+ if (cand_center_x <= sel_center_x)
|
||||||
+ continue;
|
+ continue;
|
||||||
+ break;
|
+ break;
|
||||||
+ case 2:
|
+ case 2:
|
||||||
+ if (cand_center_y >= sel_center_y)
|
+ if (cand_center_y >= sel_center_y)
|
||||||
+ continue;
|
+ continue;
|
||||||
+ break;
|
+ break;
|
||||||
+ case 3:
|
+ case 3:
|
||||||
+ if (cand_center_y <= sel_center_y)
|
+ if (cand_center_y <= sel_center_y)
|
||||||
+ continue;
|
+ continue;
|
||||||
+ break;
|
+ break;
|
||||||
+ default:
|
+ default:
|
||||||
+ continue;
|
+ continue;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ /* Get distance between the centers */
|
+ /* Get distance between the centers */
|
||||||
+ dist = abs(sel_center_x - cand_center_x) + abs(sel_center_y - cand_center_y);
|
+ dist = abs(sel_center_x - cand_center_x) + abs(sel_center_y - cand_center_y);
|
||||||
+ if (dist < closest_dist) {
|
+ if (dist < closest_dist) {
|
||||||
+ closest_dist = dist;
|
+ closest_dist = dist;
|
||||||
+ target = c;
|
+ target = c;
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ /* If target is found, swap the two clients’ positions in the layout tree */
|
+ /* If target is found, swap the two clients’ positions in the layout tree */
|
||||||
+ if (target) {
|
+ if (target) {
|
||||||
+ sel_node = find_client_node(selmon->root, sel);
|
+ sel_node = find_client_node(selmon->root, sel);
|
||||||
+ target_node = find_client_node(selmon->root, target);
|
+ target_node = find_client_node(selmon->root, target);
|
||||||
+ if (sel_node && target_node) {
|
+ if (sel_node && target_node) {
|
||||||
+ tmp = sel_node->client;
|
+ tmp = sel_node->client;
|
||||||
+ sel_node->client = target_node->client;
|
+ sel_node->client = target_node->client;
|
||||||
+ target_node->client = tmp;
|
+ target_node->client = tmp;
|
||||||
+ arrange(selmon);
|
+ arrange(selmon);
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+unsigned int
|
+unsigned int
|
||||||
@@ -564,7 +566,7 @@ index 0000000..c63e59f
|
|||||||
+
|
+
|
||||||
+Client *
|
+Client *
|
||||||
+xytoclient(double x, double y) {
|
+xytoclient(double x, double y) {
|
||||||
+ Monitor *m = xytomon(x, y);
|
+ Monitor *m = xytomon(x, y);
|
||||||
+ Client *c, *closest = NULL;
|
+ Client *c, *closest = NULL;
|
||||||
+ double dist, mindist = INT_MAX, dx, dy;
|
+ double dist, mindist = INT_MAX, dx, dy;
|
||||||
+
|
+
|
||||||
@@ -639,7 +641,7 @@ index 8a6eda0..bc04e3f 100644
|
|||||||
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
|
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
|
||||||
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
||||||
diff --git a/dwl.c b/dwl.c
|
diff --git a/dwl.c b/dwl.c
|
||||||
index 44f3ad9..d37e235 100644
|
index 44f3ad9..a121efc 100644
|
||||||
--- a/dwl.c
|
--- a/dwl.c
|
||||||
+++ b/dwl.c
|
+++ b/dwl.c
|
||||||
@@ -1,6 +1,7 @@
|
@@ -1,6 +1,7 @@
|
||||||
@@ -721,7 +723,7 @@ index 44f3ad9..d37e235 100644
|
|||||||
b->func(&b->arg);
|
b->func(&b->arg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -655,6 +664,27 @@ buttonpress(struct wl_listener *listener, void *data)
|
@@ -655,6 +664,21 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||||
/* If you released any buttons, we exit interactive move/resize mode. */
|
/* If you released any buttons, we exit interactive move/resize mode. */
|
||||||
/* TODO: should reset to the pointer focus's current setcursor */
|
/* TODO: should reset to the pointer focus's current setcursor */
|
||||||
if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
|
if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
|
||||||
@@ -736,20 +738,14 @@ index 44f3ad9..d37e235 100644
|
|||||||
+ selmon->root = create_client_node(c);
|
+ selmon->root = create_client_node(c);
|
||||||
+
|
+
|
||||||
+ setfloating(c, 0);
|
+ setfloating(c, 0);
|
||||||
+ arrange(selmon);
|
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
||||||
+
|
|
||||||
+ } else if (cursor_mode == CurResize && !c->isfloating) {
|
|
||||||
+ resizing_from_mouse = 0;
|
|
||||||
+ }
|
+ }
|
||||||
+ } else {
|
|
||||||
+ if (cursor_mode == CurResize && resizing_from_mouse)
|
|
||||||
+ resizing_from_mouse = 0;
|
|
||||||
+ }
|
+ }
|
||||||
+ /* Default behaviour */
|
+ /* Default behaviour */
|
||||||
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
||||||
cursor_mode = CurNormal;
|
cursor_mode = CurNormal;
|
||||||
/* Drop the window off on its new monitor */
|
/* Drop the window off on its new monitor */
|
||||||
@@ -746,6 +776,7 @@ cleanupmon(struct wl_listener *listener, void *data)
|
@@ -746,6 +770,7 @@ cleanupmon(struct wl_listener *listener, void *data)
|
||||||
wlr_output_layout_remove(output_layout, m->wlr_output);
|
wlr_output_layout_remove(output_layout, m->wlr_output);
|
||||||
wlr_scene_output_destroy(m->scene_output);
|
wlr_scene_output_destroy(m->scene_output);
|
||||||
|
|
||||||
@@ -757,7 +753,7 @@ index 44f3ad9..d37e235 100644
|
|||||||
closemon(m);
|
closemon(m);
|
||||||
wlr_scene_node_destroy(&m->fullscreen_bg->node);
|
wlr_scene_node_destroy(&m->fullscreen_bg->node);
|
||||||
free(m);
|
free(m);
|
||||||
@@ -1090,6 +1121,7 @@ createmon(struct wl_listener *listener, void *data)
|
@@ -1090,6 +1115,7 @@ createmon(struct wl_listener *listener, void *data)
|
||||||
|
|
||||||
wl_list_insert(&mons, &m->link);
|
wl_list_insert(&mons, &m->link);
|
||||||
printstatus();
|
printstatus();
|
||||||
@@ -765,22 +761,25 @@ index 44f3ad9..d37e235 100644
|
|||||||
|
|
||||||
/* The xdg-protocol specifies:
|
/* The xdg-protocol specifies:
|
||||||
*
|
*
|
||||||
@@ -1332,6 +1364,14 @@ destroynotify(struct wl_listener *listener, void *data)
|
@@ -1329,9 +1355,17 @@ destroynotify(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
|
/* Called when the xdg_toplevel is destroyed. */
|
||||||
|
Client *c = wl_container_of(listener, c, destroy);
|
||||||
|
+ Monitor *mon;
|
||||||
wl_list_remove(&c->destroy.link);
|
wl_list_remove(&c->destroy.link);
|
||||||
wl_list_remove(&c->set_title.link);
|
wl_list_remove(&c->set_title.link);
|
||||||
wl_list_remove(&c->fullscreen.link);
|
wl_list_remove(&c->fullscreen.link);
|
||||||
+ /* We check if the destroyed client was part of any tiled_list, to catch
|
+ /* We check if the destroyed client was part of any tiled_list, to catch
|
||||||
+ * client removals even if they would not be currently managed by btrtile */
|
+ * client removals even if they would not be currently managed by btrtile */
|
||||||
+ Monitor *mon;
|
+ wl_list_for_each(mon, &mons, link) {
|
||||||
+ wl_list_for_each(mon, &mons, link) {
|
+ if (mon->root) {
|
||||||
+ if (mon->root) {
|
+ remove_client(mon, c);
|
||||||
+ remove_client(mon, c);
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+ }
|
|
||||||
#ifdef XWAYLAND
|
#ifdef XWAYLAND
|
||||||
if (c->type != XDGShell) {
|
if (c->type != XDGShell) {
|
||||||
wl_list_remove(&c->activate.link);
|
wl_list_remove(&c->activate.link);
|
||||||
@@ -1862,7 +1902,8 @@ void
|
@@ -1862,7 +1896,8 @@ void
|
||||||
motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy,
|
motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy,
|
||||||
double dx_unaccel, double dy_unaccel)
|
double dx_unaccel, double dy_unaccel)
|
||||||
{
|
{
|
||||||
@@ -790,13 +789,13 @@ index 44f3ad9..d37e235 100644
|
|||||||
Client *c = NULL, *w = NULL;
|
Client *c = NULL, *w = NULL;
|
||||||
LayerSurface *l = NULL;
|
LayerSurface *l = NULL;
|
||||||
struct wlr_surface *surface = NULL;
|
struct wlr_surface *surface = NULL;
|
||||||
@@ -1916,18 +1957,56 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
|
@@ -1916,18 +1951,55 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
|
||||||
/* Update drag icon's position */
|
/* Update drag icon's position */
|
||||||
wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y));
|
wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y));
|
||||||
|
|
||||||
- /* If we are currently grabbing the mouse, handle and return */
|
- /* If we are currently grabbing the mouse, handle and return */
|
||||||
+ /* Skip if internal call or already resizing */
|
+ /* Skip if internal call */
|
||||||
+ if (time == 0 && resizing_from_mouse)
|
+ if (time == 0)
|
||||||
+ goto focus;
|
+ goto focus;
|
||||||
+
|
+
|
||||||
+ tiled = grabc && !grabc->isfloating && !grabc->isfullscreen;
|
+ tiled = grabc && !grabc->isfloating && !grabc->isfullscreen;
|
||||||
@@ -818,7 +817,7 @@ index 44f3ad9..d37e235 100644
|
|||||||
- resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y,
|
- resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y,
|
||||||
- .width = (int)round(cursor->x) - grabc->geom.x, .height = (int)round(cursor->y) - grabc->geom.y}, 1);
|
- .width = (int)round(cursor->x) - grabc->geom.x, .height = (int)round(cursor->y) - grabc->geom.y}, 1);
|
||||||
- return;
|
- return;
|
||||||
+ if (tiled && resizing_from_mouse) {
|
+ if (tiled) {
|
||||||
+ dx_total = cursor->x - resize_last_update_x;
|
+ dx_total = cursor->x - resize_last_update_x;
|
||||||
+ dy_total = cursor->y - resize_last_update_y;
|
+ dy_total = cursor->y - resize_last_update_y;
|
||||||
+
|
+
|
||||||
@@ -831,7 +830,6 @@ index 44f3ad9..d37e235 100644
|
|||||||
+ a.f = (float)(dy_total * resize_factor);
|
+ a.f = (float)(dy_total * resize_factor);
|
||||||
+ setratio_v(&a);
|
+ setratio_v(&a);
|
||||||
+ }
|
+ }
|
||||||
+ arrange(selmon);
|
|
||||||
+
|
+
|
||||||
+ last_resize_time = time;
|
+ last_resize_time = time;
|
||||||
+ resize_last_update_x = cursor->x;
|
+ resize_last_update_x = cursor->x;
|
||||||
@@ -854,7 +852,7 @@ index 44f3ad9..d37e235 100644
|
|||||||
/* If there's no client surface under the cursor, set the cursor image to a
|
/* If there's no client surface under the cursor, set the cursor image to a
|
||||||
* default. This is what makes the cursor image appear when you move it
|
* default. This is what makes the cursor image appear when you move it
|
||||||
* off of a client or over its border. */
|
* off of a client or over its border. */
|
||||||
@@ -1961,22 +2040,41 @@ moveresize(const Arg *arg)
|
@@ -1961,22 +2033,40 @@ moveresize(const Arg *arg)
|
||||||
if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
|
if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -889,7 +887,6 @@ index 44f3ad9..d37e235 100644
|
|||||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
||||||
+ resize_last_update_x = cursor->x;
|
+ resize_last_update_x = cursor->x;
|
||||||
+ resize_last_update_y = cursor->y;
|
+ resize_last_update_y = cursor->y;
|
||||||
+ resizing_from_mouse = 1;
|
|
||||||
+ break;
|
+ break;
|
||||||
+ }
|
+ }
|
||||||
+ } else {
|
+ } else {
|
||||||
@@ -912,17 +909,17 @@ index 44f3ad9..d37e235 100644
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2826,6 +2924,14 @@ unmapnotify(struct wl_listener *listener, void *data)
|
@@ -2826,6 +2916,14 @@ unmapnotify(struct wl_listener *listener, void *data)
|
||||||
focusclient(focustop(selmon), 1);
|
focusclient(focustop(selmon), 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
+ // btrtile remove clients for each monitor
|
+ /* btrtile remove clients for each monitor */
|
||||||
+ Monitor *mon;
|
+ Monitor *mon;
|
||||||
+ wl_list_for_each(mon, &mons, link) {
|
+ wl_list_for_each(mon, &mons, link) {
|
||||||
+ if (mon->root) {
|
+ if (mon->root) {
|
||||||
+ remove_client(mon, c);
|
+ remove_client(mon, c);
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
wl_list_remove(&c->link);
|
wl_list_remove(&c->link);
|
||||||
setmon(c, NULL, 0);
|
setmon(c, NULL, 0);
|
||||||
|
|||||||
+111
-114
@@ -1,23 +1,24 @@
|
|||||||
From 7ef8c161eb3cd801f608784e7d888fe12e94b9d4 Mon Sep 17 00:00:00 2001
|
From 618e3b70204520b6eb2c5040e072087ac0a3b3f7 Mon Sep 17 00:00:00 2001
|
||||||
From: julmajustus <julmajustus@tutanota.com>
|
From: julmajustus <julmajustus@tutanota.com>
|
||||||
Date: Sun, 17 May 2026 22:39:30 +0300
|
Date: Thu, 21 May 2026 00:40:54 +0300
|
||||||
Subject: [PATCH] btrtile resizing refactor
|
Subject: [PATCH] btrtile: Spring update pt2
|
||||||
|
|
||||||
- Refactored the tiled client resizing logic to be more logical. Insted
|
- Simplified the resizing logic to avoid full arrange calls from
|
||||||
of resizing based on clients split nodes, now btrtile handles client resizing based on the nearest edge client edge on the resize direction. Now it handles also resizing of the clientless splitnodes and should feel more intuitive.
|
motionnotify
|
||||||
|
- Minor intend fixes
|
||||||
---
|
---
|
||||||
btrtile.c | 563 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
btrtile.c | 564 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
config.def.h | 12 ++
|
config.def.h | 12 ++
|
||||||
dwl.c | 160 ++++++++++++---
|
dwl.c | 152 +++++++++++---
|
||||||
3 files changed, 708 insertions(+), 27 deletions(-)
|
3 files changed, 701 insertions(+), 27 deletions(-)
|
||||||
create mode 100644 btrtile.c
|
create mode 100644 btrtile.c
|
||||||
|
|
||||||
diff --git a/btrtile.c b/btrtile.c
|
diff --git a/btrtile.c b/btrtile.c
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 0000000..ad810bf
|
index 0000000..357ffb9
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/btrtile.c
|
+++ b/btrtile.c
|
||||||
@@ -0,0 +1,563 @@
|
@@ -0,0 +1,564 @@
|
||||||
+/* ************************************************************************** */
|
+/* ************************************************************************** */
|
||||||
+/* @@@ @@@@@@@@ */
|
+/* @@@ @@@@@@@@ */
|
||||||
+/* @@@ @@@@@@@@@@ */
|
+/* @@@ @@@@@@@@@@ */
|
||||||
@@ -28,7 +29,7 @@ index 0000000..ad810bf
|
|||||||
+/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */
|
+/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */
|
||||||
+/* ::! :!: !:! */
|
+/* ::! :!: !:! */
|
||||||
+/* Created: 2024/12/15 00:26:07 by julmajustus :: ::::::: :: */
|
+/* Created: 2024/12/15 00:26:07 by julmajustus :: ::::::: :: */
|
||||||
+/* Updated: 2026/05/17 22:09:15 by julmajustus : : : : : : */
|
+/* Updated: 2026/05/20 22:51:54 by julmajustus : : : : : : */
|
||||||
+/* */
|
+/* */
|
||||||
+/* ************************************************************************** */
|
+/* ************************************************************************** */
|
||||||
+
|
+
|
||||||
@@ -63,7 +64,6 @@ index 0000000..ad810bf
|
|||||||
+static unsigned int visible_count(LayoutNode *node, Monitor *m);
|
+static unsigned int visible_count(LayoutNode *node, Monitor *m);
|
||||||
+static Client *xytoclient(double x, double y);
|
+static Client *xytoclient(double x, double y);
|
||||||
+
|
+
|
||||||
+static int resizing_from_mouse = 0;
|
|
||||||
+static double resize_last_update_x, resize_last_update_y;
|
+static double resize_last_update_x, resize_last_update_y;
|
||||||
+static uint32_t last_resize_time = 0;
|
+static uint32_t last_resize_time = 0;
|
||||||
+
|
+
|
||||||
@@ -84,6 +84,9 @@ index 0000000..ad810bf
|
|||||||
+ c = node->client;
|
+ c = node->client;
|
||||||
+ if (!c || !VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
+ if (!c || !VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||||
+ return;
|
+ return;
|
||||||
|
+ if (area.x == c->old_geom.x && area.y == c->old_geom.y &&
|
||||||
|
+ area.width == c->old_geom.width && area.height == c->old_geom.height)
|
||||||
|
+ return;
|
||||||
+ resize(c, area, 0);
|
+ resize(c, area, 0);
|
||||||
+ c->old_geom = area;
|
+ c->old_geom = area;
|
||||||
+ return;
|
+ return;
|
||||||
@@ -150,16 +153,16 @@ index 0000000..ad810bf
|
|||||||
+ LayoutNode *found;
|
+ LayoutNode *found;
|
||||||
+ struct wlr_box full_area;
|
+ struct wlr_box full_area;
|
||||||
+
|
+
|
||||||
+ if (!m)
|
+ if (!m)
|
||||||
+ return;
|
+ return;
|
||||||
+
|
+
|
||||||
+ /* Remove non tiled clients from tree. */
|
+ /* Remove non tiled clients from tree. */
|
||||||
+ wl_list_for_each(c, &clients, link) {
|
+ wl_list_for_each(c, &clients, link) {
|
||||||
+ if (c->mon == m && !c->isfloating && !c->isfullscreen) {
|
+ if (c->mon == m && !c->isfloating && !c->isfullscreen) {
|
||||||
+ } else {
|
+ } else {
|
||||||
+ remove_client(m, c);
|
+ remove_client(m, c);
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ /* If no client is found under cursor, fallback to focustop(m) */
|
+ /* If no client is found under cursor, fallback to focustop(m) */
|
||||||
+ if (!(focused = xytoclient(cursor->x, cursor->y)))
|
+ if (!(focused = xytoclient(cursor->x, cursor->y)))
|
||||||
@@ -253,7 +256,7 @@ index 0000000..ad810bf
|
|||||||
+
|
+
|
||||||
+LayoutNode *
|
+LayoutNode *
|
||||||
+find_suitable_split(Monitor *m, LayoutNode *start_node,
|
+find_suitable_split(Monitor *m, LayoutNode *start_node,
|
||||||
+ unsigned int need_vertical, int focused_on_left)
|
+ unsigned int need_vertical, int focused_on_left)
|
||||||
+{
|
+{
|
||||||
+ LayoutNode *n = start_node, *child = NULL;
|
+ LayoutNode *n = start_node, *child = NULL;
|
||||||
+
|
+
|
||||||
@@ -425,11 +428,11 @@ index 0000000..ad810bf
|
|||||||
+ if (!client_node)
|
+ if (!client_node)
|
||||||
+ return;
|
+ return;
|
||||||
+
|
+
|
||||||
+ focused_on_left = (arg->f >= 0.0f);
|
+ focused_on_left = (arg->f >= 0.0f);
|
||||||
+
|
+
|
||||||
+ split_node = find_suitable_split(selmon, client_node, need_vertical, focused_on_left);
|
+ split_node = find_suitable_split(selmon, client_node, need_vertical, focused_on_left);
|
||||||
+
|
+
|
||||||
+ if (!split_node)
|
+ if (!split_node)
|
||||||
+ split_node = find_suitable_split(selmon, client_node, need_vertical, !focused_on_left);
|
+ split_node = find_suitable_split(selmon, client_node, need_vertical, !focused_on_left);
|
||||||
+ if (!split_node)
|
+ if (!split_node)
|
||||||
+ return;
|
+ return;
|
||||||
@@ -441,10 +444,9 @@ index 0000000..ad810bf
|
|||||||
+ new_ratio = 0.95f;
|
+ new_ratio = 0.95f;
|
||||||
+ split_node->split_ratio = new_ratio;
|
+ split_node->split_ratio = new_ratio;
|
||||||
+
|
+
|
||||||
|
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
||||||
+ /* Skip the arrange when called from motionnotify; that path calls
|
+ /* Skip the arrange when called from motionnotify; that path calls
|
||||||
+ * arrange itself after rate-limiting. */
|
+ * arrange itself after rate-limiting. */
|
||||||
+ if (!resizing_from_mouse)
|
|
||||||
+ arrange(selmon);
|
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+void
|
+void
|
||||||
@@ -460,69 +462,69 @@ index 0000000..ad810bf
|
|||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+void swapclients(const Arg *arg) {
|
+void swapclients(const Arg *arg) {
|
||||||
+ Client *c, *tmp, *target = NULL, *sel = focustop(selmon);
|
+ Client *c, *tmp, *target = NULL, *sel = focustop(selmon);
|
||||||
+ LayoutNode *sel_node, *target_node;
|
+ LayoutNode *sel_node, *target_node;
|
||||||
+ int closest_dist = INT_MAX, dist, sel_center_x, sel_center_y,
|
+ int closest_dist = INT_MAX, dist, sel_center_x, sel_center_y,
|
||||||
+ cand_center_x, cand_center_y;
|
+ cand_center_x, cand_center_y;
|
||||||
+
|
+
|
||||||
+ if (!sel || sel->isfullscreen ||
|
+ if (!sel || sel->isfullscreen ||
|
||||||
+ !selmon->root || !selmon->lt[selmon->sellt]->arrange)
|
+ !selmon->root || !selmon->lt[selmon->sellt]->arrange)
|
||||||
+ return;
|
+ return;
|
||||||
+
|
+
|
||||||
+
|
+
|
||||||
+ /* Get the center coordinates of the selected client */
|
+ /* Get the center coordinates of the selected client */
|
||||||
+ sel_center_x = sel->geom.x + sel->geom.width / 2;
|
+ sel_center_x = sel->geom.x + sel->geom.width / 2;
|
||||||
+ sel_center_y = sel->geom.y + sel->geom.height / 2;
|
+ sel_center_y = sel->geom.y + sel->geom.height / 2;
|
||||||
+
|
+
|
||||||
+ wl_list_for_each(c, &clients, link) {
|
+ wl_list_for_each(c, &clients, link) {
|
||||||
+ if (!VISIBLEON(c, selmon) || c->isfloating || c->isfullscreen || c == sel)
|
+ if (!VISIBLEON(c, selmon) || c->isfloating || c->isfullscreen || c == sel)
|
||||||
+ continue;
|
+ continue;
|
||||||
+
|
+
|
||||||
+ /* Get the center of candidate client */
|
+ /* Get the center of candidate client */
|
||||||
+ cand_center_x = c->geom.x + c->geom.width / 2;
|
+ cand_center_x = c->geom.x + c->geom.width / 2;
|
||||||
+ cand_center_y = c->geom.y + c->geom.height / 2;
|
+ cand_center_y = c->geom.y + c->geom.height / 2;
|
||||||
+
|
+
|
||||||
+ /* Check that the candidate lies in the requested direction. */
|
+ /* Check that the candidate lies in the requested direction. */
|
||||||
+ switch (arg->ui) {
|
+ switch (arg->ui) {
|
||||||
+ case 0:
|
+ case 0:
|
||||||
+ if (cand_center_x >= sel_center_x)
|
+ if (cand_center_x >= sel_center_x)
|
||||||
+ continue;
|
+ continue;
|
||||||
+ break;
|
+ break;
|
||||||
+ case 1:
|
+ case 1:
|
||||||
+ if (cand_center_x <= sel_center_x)
|
+ if (cand_center_x <= sel_center_x)
|
||||||
+ continue;
|
+ continue;
|
||||||
+ break;
|
+ break;
|
||||||
+ case 2:
|
+ case 2:
|
||||||
+ if (cand_center_y >= sel_center_y)
|
+ if (cand_center_y >= sel_center_y)
|
||||||
+ continue;
|
+ continue;
|
||||||
+ break;
|
+ break;
|
||||||
+ case 3:
|
+ case 3:
|
||||||
+ if (cand_center_y <= sel_center_y)
|
+ if (cand_center_y <= sel_center_y)
|
||||||
+ continue;
|
+ continue;
|
||||||
+ break;
|
+ break;
|
||||||
+ default:
|
+ default:
|
||||||
+ continue;
|
+ continue;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ /* Get distance between the centers */
|
+ /* Get distance between the centers */
|
||||||
+ dist = abs(sel_center_x - cand_center_x) + abs(sel_center_y - cand_center_y);
|
+ dist = abs(sel_center_x - cand_center_x) + abs(sel_center_y - cand_center_y);
|
||||||
+ if (dist < closest_dist) {
|
+ if (dist < closest_dist) {
|
||||||
+ closest_dist = dist;
|
+ closest_dist = dist;
|
||||||
+ target = c;
|
+ target = c;
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ /* If target is found, swap the two clients’ positions in the layout tree */
|
+ /* If target is found, swap the two clients’ positions in the layout tree */
|
||||||
+ if (target) {
|
+ if (target) {
|
||||||
+ sel_node = find_client_node(selmon->root, sel);
|
+ sel_node = find_client_node(selmon->root, sel);
|
||||||
+ target_node = find_client_node(selmon->root, target);
|
+ target_node = find_client_node(selmon->root, target);
|
||||||
+ if (sel_node && target_node) {
|
+ if (sel_node && target_node) {
|
||||||
+ tmp = sel_node->client;
|
+ tmp = sel_node->client;
|
||||||
+ sel_node->client = target_node->client;
|
+ sel_node->client = target_node->client;
|
||||||
+ target_node->client = tmp;
|
+ target_node->client = tmp;
|
||||||
+ arrange(selmon);
|
+ arrange(selmon);
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+unsigned int
|
+unsigned int
|
||||||
@@ -545,7 +547,7 @@ index 0000000..ad810bf
|
|||||||
+
|
+
|
||||||
+Client *
|
+Client *
|
||||||
+xytoclient(double x, double y) {
|
+xytoclient(double x, double y) {
|
||||||
+ Monitor *m = xytomon(x, y);
|
+ Monitor *m = xytomon(x, y);
|
||||||
+ Client *c, *closest = NULL;
|
+ Client *c, *closest = NULL;
|
||||||
+ double dist, mindist = INT_MAX, dx, dy;
|
+ double dist, mindist = INT_MAX, dx, dy;
|
||||||
+
|
+
|
||||||
@@ -620,7 +622,7 @@ index 8a6eda0..bc04e3f 100644
|
|||||||
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
|
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
|
||||||
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
||||||
diff --git a/dwl.c b/dwl.c
|
diff --git a/dwl.c b/dwl.c
|
||||||
index 44f3ad9..d37e235 100644
|
index 44f3ad9..a121efc 100644
|
||||||
--- a/dwl.c
|
--- a/dwl.c
|
||||||
+++ b/dwl.c
|
+++ b/dwl.c
|
||||||
@@ -1,6 +1,7 @@
|
@@ -1,6 +1,7 @@
|
||||||
@@ -702,7 +704,7 @@ index 44f3ad9..d37e235 100644
|
|||||||
b->func(&b->arg);
|
b->func(&b->arg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -655,6 +664,27 @@ buttonpress(struct wl_listener *listener, void *data)
|
@@ -655,6 +664,21 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||||
/* If you released any buttons, we exit interactive move/resize mode. */
|
/* If you released any buttons, we exit interactive move/resize mode. */
|
||||||
/* TODO: should reset to the pointer focus's current setcursor */
|
/* TODO: should reset to the pointer focus's current setcursor */
|
||||||
if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
|
if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
|
||||||
@@ -717,20 +719,14 @@ index 44f3ad9..d37e235 100644
|
|||||||
+ selmon->root = create_client_node(c);
|
+ selmon->root = create_client_node(c);
|
||||||
+
|
+
|
||||||
+ setfloating(c, 0);
|
+ setfloating(c, 0);
|
||||||
+ arrange(selmon);
|
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
||||||
+
|
|
||||||
+ } else if (cursor_mode == CurResize && !c->isfloating) {
|
|
||||||
+ resizing_from_mouse = 0;
|
|
||||||
+ }
|
+ }
|
||||||
+ } else {
|
|
||||||
+ if (cursor_mode == CurResize && resizing_from_mouse)
|
|
||||||
+ resizing_from_mouse = 0;
|
|
||||||
+ }
|
+ }
|
||||||
+ /* Default behaviour */
|
+ /* Default behaviour */
|
||||||
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
||||||
cursor_mode = CurNormal;
|
cursor_mode = CurNormal;
|
||||||
/* Drop the window off on its new monitor */
|
/* Drop the window off on its new monitor */
|
||||||
@@ -746,6 +776,7 @@ cleanupmon(struct wl_listener *listener, void *data)
|
@@ -746,6 +770,7 @@ cleanupmon(struct wl_listener *listener, void *data)
|
||||||
wlr_output_layout_remove(output_layout, m->wlr_output);
|
wlr_output_layout_remove(output_layout, m->wlr_output);
|
||||||
wlr_scene_output_destroy(m->scene_output);
|
wlr_scene_output_destroy(m->scene_output);
|
||||||
|
|
||||||
@@ -738,7 +734,7 @@ index 44f3ad9..d37e235 100644
|
|||||||
closemon(m);
|
closemon(m);
|
||||||
wlr_scene_node_destroy(&m->fullscreen_bg->node);
|
wlr_scene_node_destroy(&m->fullscreen_bg->node);
|
||||||
free(m);
|
free(m);
|
||||||
@@ -1090,6 +1121,7 @@ createmon(struct wl_listener *listener, void *data)
|
@@ -1090,6 +1115,7 @@ createmon(struct wl_listener *listener, void *data)
|
||||||
|
|
||||||
wl_list_insert(&mons, &m->link);
|
wl_list_insert(&mons, &m->link);
|
||||||
printstatus();
|
printstatus();
|
||||||
@@ -746,22 +742,25 @@ index 44f3ad9..d37e235 100644
|
|||||||
|
|
||||||
/* The xdg-protocol specifies:
|
/* The xdg-protocol specifies:
|
||||||
*
|
*
|
||||||
@@ -1332,6 +1364,14 @@ destroynotify(struct wl_listener *listener, void *data)
|
@@ -1329,9 +1355,17 @@ destroynotify(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
|
/* Called when the xdg_toplevel is destroyed. */
|
||||||
|
Client *c = wl_container_of(listener, c, destroy);
|
||||||
|
+ Monitor *mon;
|
||||||
wl_list_remove(&c->destroy.link);
|
wl_list_remove(&c->destroy.link);
|
||||||
wl_list_remove(&c->set_title.link);
|
wl_list_remove(&c->set_title.link);
|
||||||
wl_list_remove(&c->fullscreen.link);
|
wl_list_remove(&c->fullscreen.link);
|
||||||
+ /* We check if the destroyed client was part of any tiled_list, to catch
|
+ /* We check if the destroyed client was part of any tiled_list, to catch
|
||||||
+ * client removals even if they would not be currently managed by btrtile */
|
+ * client removals even if they would not be currently managed by btrtile */
|
||||||
+ Monitor *mon;
|
+ wl_list_for_each(mon, &mons, link) {
|
||||||
+ wl_list_for_each(mon, &mons, link) {
|
+ if (mon->root) {
|
||||||
+ if (mon->root) {
|
+ remove_client(mon, c);
|
||||||
+ remove_client(mon, c);
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+ }
|
|
||||||
#ifdef XWAYLAND
|
#ifdef XWAYLAND
|
||||||
if (c->type != XDGShell) {
|
if (c->type != XDGShell) {
|
||||||
wl_list_remove(&c->activate.link);
|
wl_list_remove(&c->activate.link);
|
||||||
@@ -1862,7 +1902,8 @@ void
|
@@ -1862,7 +1896,8 @@ void
|
||||||
motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy,
|
motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy,
|
||||||
double dx_unaccel, double dy_unaccel)
|
double dx_unaccel, double dy_unaccel)
|
||||||
{
|
{
|
||||||
@@ -771,13 +770,13 @@ index 44f3ad9..d37e235 100644
|
|||||||
Client *c = NULL, *w = NULL;
|
Client *c = NULL, *w = NULL;
|
||||||
LayerSurface *l = NULL;
|
LayerSurface *l = NULL;
|
||||||
struct wlr_surface *surface = NULL;
|
struct wlr_surface *surface = NULL;
|
||||||
@@ -1916,18 +1957,56 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
|
@@ -1916,18 +1951,55 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
|
||||||
/* Update drag icon's position */
|
/* Update drag icon's position */
|
||||||
wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y));
|
wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y));
|
||||||
|
|
||||||
- /* If we are currently grabbing the mouse, handle and return */
|
- /* If we are currently grabbing the mouse, handle and return */
|
||||||
+ /* Skip if internal call or already resizing */
|
+ /* Skip if internal call */
|
||||||
+ if (time == 0 && resizing_from_mouse)
|
+ if (time == 0)
|
||||||
+ goto focus;
|
+ goto focus;
|
||||||
+
|
+
|
||||||
+ tiled = grabc && !grabc->isfloating && !grabc->isfullscreen;
|
+ tiled = grabc && !grabc->isfloating && !grabc->isfullscreen;
|
||||||
@@ -799,7 +798,7 @@ index 44f3ad9..d37e235 100644
|
|||||||
- resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y,
|
- resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y,
|
||||||
- .width = (int)round(cursor->x) - grabc->geom.x, .height = (int)round(cursor->y) - grabc->geom.y}, 1);
|
- .width = (int)round(cursor->x) - grabc->geom.x, .height = (int)round(cursor->y) - grabc->geom.y}, 1);
|
||||||
- return;
|
- return;
|
||||||
+ if (tiled && resizing_from_mouse) {
|
+ if (tiled) {
|
||||||
+ dx_total = cursor->x - resize_last_update_x;
|
+ dx_total = cursor->x - resize_last_update_x;
|
||||||
+ dy_total = cursor->y - resize_last_update_y;
|
+ dy_total = cursor->y - resize_last_update_y;
|
||||||
+
|
+
|
||||||
@@ -812,7 +811,6 @@ index 44f3ad9..d37e235 100644
|
|||||||
+ a.f = (float)(dy_total * resize_factor);
|
+ a.f = (float)(dy_total * resize_factor);
|
||||||
+ setratio_v(&a);
|
+ setratio_v(&a);
|
||||||
+ }
|
+ }
|
||||||
+ arrange(selmon);
|
|
||||||
+
|
+
|
||||||
+ last_resize_time = time;
|
+ last_resize_time = time;
|
||||||
+ resize_last_update_x = cursor->x;
|
+ resize_last_update_x = cursor->x;
|
||||||
@@ -835,7 +833,7 @@ index 44f3ad9..d37e235 100644
|
|||||||
/* If there's no client surface under the cursor, set the cursor image to a
|
/* If there's no client surface under the cursor, set the cursor image to a
|
||||||
* default. This is what makes the cursor image appear when you move it
|
* default. This is what makes the cursor image appear when you move it
|
||||||
* off of a client or over its border. */
|
* off of a client or over its border. */
|
||||||
@@ -1961,22 +2040,41 @@ moveresize(const Arg *arg)
|
@@ -1961,22 +2033,40 @@ moveresize(const Arg *arg)
|
||||||
if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
|
if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -870,7 +868,6 @@ index 44f3ad9..d37e235 100644
|
|||||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
||||||
+ resize_last_update_x = cursor->x;
|
+ resize_last_update_x = cursor->x;
|
||||||
+ resize_last_update_y = cursor->y;
|
+ resize_last_update_y = cursor->y;
|
||||||
+ resizing_from_mouse = 1;
|
|
||||||
+ break;
|
+ break;
|
||||||
+ }
|
+ }
|
||||||
+ } else {
|
+ } else {
|
||||||
@@ -893,17 +890,17 @@ index 44f3ad9..d37e235 100644
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2826,6 +2924,14 @@ unmapnotify(struct wl_listener *listener, void *data)
|
@@ -2826,6 +2916,14 @@ unmapnotify(struct wl_listener *listener, void *data)
|
||||||
focusclient(focustop(selmon), 1);
|
focusclient(focustop(selmon), 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
+ // btrtile remove clients for each monitor
|
+ /* btrtile remove clients for each monitor */
|
||||||
+ Monitor *mon;
|
+ Monitor *mon;
|
||||||
+ wl_list_for_each(mon, &mons, link) {
|
+ wl_list_for_each(mon, &mons, link) {
|
||||||
+ if (mon->root) {
|
+ if (mon->root) {
|
||||||
+ remove_client(mon, c);
|
+ remove_client(mon, c);
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
wl_list_remove(&c->link);
|
wl_list_remove(&c->link);
|
||||||
setmon(c, NULL, 0);
|
setmon(c, NULL, 0);
|
||||||
|
|||||||
@@ -1,23 +1,24 @@
|
|||||||
From b8d84c87f13681118865b83312387a881ab10b73 Mon Sep 17 00:00:00 2001
|
From c11b1a8c93c27fad3782e9dbc1b094a4a7b78088 Mon Sep 17 00:00:00 2001
|
||||||
From: julmajustus <julmajustus@tutanota.com>
|
From: julmajustus <julmajustus@tutanota.com>
|
||||||
Date: Sun, 17 May 2026 23:10:49 +0300
|
Date: Thu, 21 May 2026 00:38:45 +0300
|
||||||
Subject: [PATCH] btrtile resizing refactor
|
Subject: [PATCH] btrtile: Spring update pt2
|
||||||
|
|
||||||
- Refactored the tiled client resizing logic to be more logical. Insted
|
- Simplified the resizing logic to avoid full arrange calls from
|
||||||
of resizing based on clients split nodes, now btrtile handles client resizing based on the nearest edge client edge on the resize direction. Now it handles also resizing of the clientless splitnodes and should feel more intuitive.
|
motionnotify
|
||||||
|
- Minor intend fixes
|
||||||
---
|
---
|
||||||
btrtile.c | 582 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
btrtile.c | 583 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
config.def.h | 12 ++
|
config.def.h | 12 ++
|
||||||
dwl.c | 161 +++++++++++---
|
dwl.c | 152 +++++++++++---
|
||||||
3 files changed, 728 insertions(+), 27 deletions(-)
|
3 files changed, 720 insertions(+), 27 deletions(-)
|
||||||
create mode 100644 btrtile.c
|
create mode 100644 btrtile.c
|
||||||
|
|
||||||
diff --git a/btrtile.c b/btrtile.c
|
diff --git a/btrtile.c b/btrtile.c
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 0000000..c63e59f
|
index 0000000..f05a30f
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/btrtile.c
|
+++ b/btrtile.c
|
||||||
@@ -0,0 +1,582 @@
|
@@ -0,0 +1,583 @@
|
||||||
+/* ************************************************************************** */
|
+/* ************************************************************************** */
|
||||||
+/* @@@ @@@@@@@@ */
|
+/* @@@ @@@@@@@@ */
|
||||||
+/* @@@ @@@@@@@@@@ */
|
+/* @@@ @@@@@@@@@@ */
|
||||||
@@ -28,7 +29,7 @@ index 0000000..c63e59f
|
|||||||
+/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */
|
+/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */
|
||||||
+/* ::! :!: !:! */
|
+/* ::! :!: !:! */
|
||||||
+/* Created: 2024/12/15 00:26:07 by julmajustus :: ::::::: :: */
|
+/* Created: 2024/12/15 00:26:07 by julmajustus :: ::::::: :: */
|
||||||
+/* Updated: 2026/05/17 22:00:31 by julmajustus : : : : : : */
|
+/* Updated: 2026/05/20 22:38:02 by julmajustus : : : : : : */
|
||||||
+/* */
|
+/* */
|
||||||
+/* ************************************************************************** */
|
+/* ************************************************************************** */
|
||||||
+
|
+
|
||||||
@@ -63,7 +64,6 @@ index 0000000..c63e59f
|
|||||||
+static unsigned int visible_count(LayoutNode *node, Monitor *m);
|
+static unsigned int visible_count(LayoutNode *node, Monitor *m);
|
||||||
+static Client *xytoclient(double x, double y);
|
+static Client *xytoclient(double x, double y);
|
||||||
+
|
+
|
||||||
+static int resizing_from_mouse = 0;
|
|
||||||
+static double resize_last_update_x, resize_last_update_y;
|
+static double resize_last_update_x, resize_last_update_y;
|
||||||
+static uint32_t last_resize_time = 0;
|
+static uint32_t last_resize_time = 0;
|
||||||
+
|
+
|
||||||
@@ -91,6 +91,9 @@ index 0000000..c63e59f
|
|||||||
+ c = node->client;
|
+ c = node->client;
|
||||||
+ if (!c || !VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
+ if (!c || !VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||||
+ return;
|
+ return;
|
||||||
|
+ if (area.x == c->old_geom.x && area.y == c->old_geom.y &&
|
||||||
|
+ area.width == c->old_geom.width && area.height == c->old_geom.height)
|
||||||
|
+ return;
|
||||||
+ resize(c, area, 0);
|
+ resize(c, area, 0);
|
||||||
+ c->old_geom = area;
|
+ c->old_geom = area;
|
||||||
+ return;
|
+ return;
|
||||||
@@ -169,16 +172,16 @@ index 0000000..c63e59f
|
|||||||
+ LayoutNode *found;
|
+ LayoutNode *found;
|
||||||
+ struct wlr_box full_area;
|
+ struct wlr_box full_area;
|
||||||
+
|
+
|
||||||
+ if (!m)
|
+ if (!m)
|
||||||
+ return;
|
+ return;
|
||||||
+
|
+
|
||||||
+ /* Remove non tiled clients from tree. */
|
+ /* Remove non tiled clients from tree. */
|
||||||
+ wl_list_for_each(c, &clients, link) {
|
+ wl_list_for_each(c, &clients, link) {
|
||||||
+ if (c->mon == m && !c->isfloating && !c->isfullscreen) {
|
+ if (c->mon == m && !c->isfloating && !c->isfullscreen) {
|
||||||
+ } else {
|
+ } else {
|
||||||
+ remove_client(m, c);
|
+ remove_client(m, c);
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ /* If no client is found under cursor, fallback to focustop(m) */
|
+ /* If no client is found under cursor, fallback to focustop(m) */
|
||||||
+ if (!(focused = xytoclient(cursor->x, cursor->y)))
|
+ if (!(focused = xytoclient(cursor->x, cursor->y)))
|
||||||
@@ -272,7 +275,7 @@ index 0000000..c63e59f
|
|||||||
+
|
+
|
||||||
+LayoutNode *
|
+LayoutNode *
|
||||||
+find_suitable_split(Monitor *m, LayoutNode *start_node,
|
+find_suitable_split(Monitor *m, LayoutNode *start_node,
|
||||||
+ unsigned int need_vertical, int focused_on_left)
|
+ unsigned int need_vertical, int focused_on_left)
|
||||||
+{
|
+{
|
||||||
+ LayoutNode *n = start_node, *child = NULL;
|
+ LayoutNode *n = start_node, *child = NULL;
|
||||||
+
|
+
|
||||||
@@ -444,11 +447,11 @@ index 0000000..c63e59f
|
|||||||
+ if (!client_node)
|
+ if (!client_node)
|
||||||
+ return;
|
+ return;
|
||||||
+
|
+
|
||||||
+ focused_on_left = (arg->f >= 0.0f);
|
+ focused_on_left = (arg->f >= 0.0f);
|
||||||
+
|
+
|
||||||
+ split_node = find_suitable_split(selmon, client_node, need_vertical, focused_on_left);
|
+ split_node = find_suitable_split(selmon, client_node, need_vertical, focused_on_left);
|
||||||
+
|
+
|
||||||
+ if (!split_node)
|
+ if (!split_node)
|
||||||
+ split_node = find_suitable_split(selmon, client_node, need_vertical, !focused_on_left);
|
+ split_node = find_suitable_split(selmon, client_node, need_vertical, !focused_on_left);
|
||||||
+ if (!split_node)
|
+ if (!split_node)
|
||||||
+ return;
|
+ return;
|
||||||
@@ -460,10 +463,9 @@ index 0000000..c63e59f
|
|||||||
+ new_ratio = 0.95f;
|
+ new_ratio = 0.95f;
|
||||||
+ split_node->split_ratio = new_ratio;
|
+ split_node->split_ratio = new_ratio;
|
||||||
+
|
+
|
||||||
|
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
||||||
+ /* Skip the arrange when called from motionnotify; that path calls
|
+ /* Skip the arrange when called from motionnotify; that path calls
|
||||||
+ * arrange itself after rate-limiting. */
|
+ * arrange itself after rate-limiting. */
|
||||||
+ if (!resizing_from_mouse)
|
|
||||||
+ arrange(selmon);
|
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+void
|
+void
|
||||||
@@ -479,69 +481,69 @@ index 0000000..c63e59f
|
|||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+void swapclients(const Arg *arg) {
|
+void swapclients(const Arg *arg) {
|
||||||
+ Client *c, *tmp, *target = NULL, *sel = focustop(selmon);
|
+ Client *c, *tmp, *target = NULL, *sel = focustop(selmon);
|
||||||
+ LayoutNode *sel_node, *target_node;
|
+ LayoutNode *sel_node, *target_node;
|
||||||
+ int closest_dist = INT_MAX, dist, sel_center_x, sel_center_y,
|
+ int closest_dist = INT_MAX, dist, sel_center_x, sel_center_y,
|
||||||
+ cand_center_x, cand_center_y;
|
+ cand_center_x, cand_center_y;
|
||||||
+
|
+
|
||||||
+ if (!sel || sel->isfullscreen ||
|
+ if (!sel || sel->isfullscreen ||
|
||||||
+ !selmon->root || !selmon->lt[selmon->sellt]->arrange)
|
+ !selmon->root || !selmon->lt[selmon->sellt]->arrange)
|
||||||
+ return;
|
+ return;
|
||||||
+
|
+
|
||||||
+
|
+
|
||||||
+ /* Get the center coordinates of the selected client */
|
+ /* Get the center coordinates of the selected client */
|
||||||
+ sel_center_x = sel->geom.x + sel->geom.width / 2;
|
+ sel_center_x = sel->geom.x + sel->geom.width / 2;
|
||||||
+ sel_center_y = sel->geom.y + sel->geom.height / 2;
|
+ sel_center_y = sel->geom.y + sel->geom.height / 2;
|
||||||
+
|
+
|
||||||
+ wl_list_for_each(c, &clients, link) {
|
+ wl_list_for_each(c, &clients, link) {
|
||||||
+ if (!VISIBLEON(c, selmon) || c->isfloating || c->isfullscreen || c == sel)
|
+ if (!VISIBLEON(c, selmon) || c->isfloating || c->isfullscreen || c == sel)
|
||||||
+ continue;
|
+ continue;
|
||||||
+
|
+
|
||||||
+ /* Get the center of candidate client */
|
+ /* Get the center of candidate client */
|
||||||
+ cand_center_x = c->geom.x + c->geom.width / 2;
|
+ cand_center_x = c->geom.x + c->geom.width / 2;
|
||||||
+ cand_center_y = c->geom.y + c->geom.height / 2;
|
+ cand_center_y = c->geom.y + c->geom.height / 2;
|
||||||
+
|
+
|
||||||
+ /* Check that the candidate lies in the requested direction. */
|
+ /* Check that the candidate lies in the requested direction. */
|
||||||
+ switch (arg->ui) {
|
+ switch (arg->ui) {
|
||||||
+ case 0:
|
+ case 0:
|
||||||
+ if (cand_center_x >= sel_center_x)
|
+ if (cand_center_x >= sel_center_x)
|
||||||
+ continue;
|
+ continue;
|
||||||
+ break;
|
+ break;
|
||||||
+ case 1:
|
+ case 1:
|
||||||
+ if (cand_center_x <= sel_center_x)
|
+ if (cand_center_x <= sel_center_x)
|
||||||
+ continue;
|
+ continue;
|
||||||
+ break;
|
+ break;
|
||||||
+ case 2:
|
+ case 2:
|
||||||
+ if (cand_center_y >= sel_center_y)
|
+ if (cand_center_y >= sel_center_y)
|
||||||
+ continue;
|
+ continue;
|
||||||
+ break;
|
+ break;
|
||||||
+ case 3:
|
+ case 3:
|
||||||
+ if (cand_center_y <= sel_center_y)
|
+ if (cand_center_y <= sel_center_y)
|
||||||
+ continue;
|
+ continue;
|
||||||
+ break;
|
+ break;
|
||||||
+ default:
|
+ default:
|
||||||
+ continue;
|
+ continue;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ /* Get distance between the centers */
|
+ /* Get distance between the centers */
|
||||||
+ dist = abs(sel_center_x - cand_center_x) + abs(sel_center_y - cand_center_y);
|
+ dist = abs(sel_center_x - cand_center_x) + abs(sel_center_y - cand_center_y);
|
||||||
+ if (dist < closest_dist) {
|
+ if (dist < closest_dist) {
|
||||||
+ closest_dist = dist;
|
+ closest_dist = dist;
|
||||||
+ target = c;
|
+ target = c;
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ /* If target is found, swap the two clients’ positions in the layout tree */
|
+ /* If target is found, swap the two clients’ positions in the layout tree */
|
||||||
+ if (target) {
|
+ if (target) {
|
||||||
+ sel_node = find_client_node(selmon->root, sel);
|
+ sel_node = find_client_node(selmon->root, sel);
|
||||||
+ target_node = find_client_node(selmon->root, target);
|
+ target_node = find_client_node(selmon->root, target);
|
||||||
+ if (sel_node && target_node) {
|
+ if (sel_node && target_node) {
|
||||||
+ tmp = sel_node->client;
|
+ tmp = sel_node->client;
|
||||||
+ sel_node->client = target_node->client;
|
+ sel_node->client = target_node->client;
|
||||||
+ target_node->client = tmp;
|
+ target_node->client = tmp;
|
||||||
+ arrange(selmon);
|
+ arrange(selmon);
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+unsigned int
|
+unsigned int
|
||||||
@@ -564,7 +566,7 @@ index 0000000..c63e59f
|
|||||||
+
|
+
|
||||||
+Client *
|
+Client *
|
||||||
+xytoclient(double x, double y) {
|
+xytoclient(double x, double y) {
|
||||||
+ Monitor *m = xytomon(x, y);
|
+ Monitor *m = xytomon(x, y);
|
||||||
+ Client *c, *closest = NULL;
|
+ Client *c, *closest = NULL;
|
||||||
+ double dist, mindist = INT_MAX, dx, dy;
|
+ double dist, mindist = INT_MAX, dx, dy;
|
||||||
+
|
+
|
||||||
@@ -639,7 +641,7 @@ index 8a6eda0..bc04e3f 100644
|
|||||||
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
|
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
|
||||||
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
||||||
diff --git a/dwl.c b/dwl.c
|
diff --git a/dwl.c b/dwl.c
|
||||||
index 8101ffa..32a94c4 100644
|
index 8101ffa..c9650c1 100644
|
||||||
--- a/dwl.c
|
--- a/dwl.c
|
||||||
+++ b/dwl.c
|
+++ b/dwl.c
|
||||||
@@ -1,6 +1,7 @@
|
@@ -1,6 +1,7 @@
|
||||||
@@ -721,7 +723,7 @@ index 8101ffa..32a94c4 100644
|
|||||||
b->func(&b->arg);
|
b->func(&b->arg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -659,6 +668,27 @@ buttonpress(struct wl_listener *listener, void *data)
|
@@ -659,6 +668,21 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||||
/* If you released any buttons, we exit interactive move/resize mode. */
|
/* If you released any buttons, we exit interactive move/resize mode. */
|
||||||
/* TODO: should reset to the pointer focus's current setcursor */
|
/* TODO: should reset to the pointer focus's current setcursor */
|
||||||
if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
|
if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
|
||||||
@@ -736,20 +738,14 @@ index 8101ffa..32a94c4 100644
|
|||||||
+ selmon->root = create_client_node(c);
|
+ selmon->root = create_client_node(c);
|
||||||
+
|
+
|
||||||
+ setfloating(c, 0);
|
+ setfloating(c, 0);
|
||||||
+ arrange(selmon);
|
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
||||||
+
|
|
||||||
+ } else if (cursor_mode == CurResize && !c->isfloating) {
|
|
||||||
+ resizing_from_mouse = 0;
|
|
||||||
+ }
|
+ }
|
||||||
+ } else {
|
|
||||||
+ if (cursor_mode == CurResize && resizing_from_mouse)
|
|
||||||
+ resizing_from_mouse = 0;
|
|
||||||
+ }
|
+ }
|
||||||
+ /* Default behaviour */
|
+ /* Default behaviour */
|
||||||
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
||||||
cursor_mode = CurNormal;
|
cursor_mode = CurNormal;
|
||||||
/* Drop the window off on its new monitor */
|
/* Drop the window off on its new monitor */
|
||||||
@@ -750,6 +780,7 @@ cleanupmon(struct wl_listener *listener, void *data)
|
@@ -750,6 +774,7 @@ cleanupmon(struct wl_listener *listener, void *data)
|
||||||
wlr_output_layout_remove(output_layout, m->wlr_output);
|
wlr_output_layout_remove(output_layout, m->wlr_output);
|
||||||
wlr_scene_output_destroy(m->scene_output);
|
wlr_scene_output_destroy(m->scene_output);
|
||||||
|
|
||||||
@@ -757,7 +753,7 @@ index 8101ffa..32a94c4 100644
|
|||||||
closemon(m);
|
closemon(m);
|
||||||
wlr_scene_node_destroy(&m->fullscreen_bg->node);
|
wlr_scene_node_destroy(&m->fullscreen_bg->node);
|
||||||
free(m);
|
free(m);
|
||||||
@@ -1094,6 +1125,7 @@ createmon(struct wl_listener *listener, void *data)
|
@@ -1094,6 +1119,7 @@ createmon(struct wl_listener *listener, void *data)
|
||||||
|
|
||||||
wl_list_insert(&mons, &m->link);
|
wl_list_insert(&mons, &m->link);
|
||||||
printstatus();
|
printstatus();
|
||||||
@@ -765,23 +761,26 @@ index 8101ffa..32a94c4 100644
|
|||||||
|
|
||||||
/* The xdg-protocol specifies:
|
/* The xdg-protocol specifies:
|
||||||
*
|
*
|
||||||
@@ -1336,6 +1368,15 @@ destroynotify(struct wl_listener *listener, void *data)
|
@@ -1332,10 +1358,18 @@ void
|
||||||
|
destroynotify(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
|
/* Called when the xdg_toplevel is destroyed. */
|
||||||
|
+ Monitor *mon;
|
||||||
|
Client *c = wl_container_of(listener, c, destroy);
|
||||||
wl_list_remove(&c->destroy.link);
|
wl_list_remove(&c->destroy.link);
|
||||||
wl_list_remove(&c->set_title.link);
|
wl_list_remove(&c->set_title.link);
|
||||||
wl_list_remove(&c->fullscreen.link);
|
wl_list_remove(&c->fullscreen.link);
|
||||||
+ /* We check if the destroyed client was part of any tiled_list, to catch
|
+ /* We check if the destroyed client was part of any tiled_list, to catch
|
||||||
+ * client removals even if they would not be currently managed by btrtile */
|
+ * client removals even if they would not be currently managed by btrtile */
|
||||||
+ // btrtile remove clients for each monitor
|
+ wl_list_for_each(mon, &mons, link) {
|
||||||
+ Monitor *mon;
|
+ if (mon->root) {
|
||||||
+ wl_list_for_each(mon, &mons, link) {
|
+ remove_client(mon, c);
|
||||||
+ if (mon->root) {
|
+ }
|
||||||
+ remove_client(mon, c);
|
+ }
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
#ifdef XWAYLAND
|
#ifdef XWAYLAND
|
||||||
if (c->type != XDGShell) {
|
if (c->type != XDGShell) {
|
||||||
wl_list_remove(&c->activate.link);
|
wl_list_remove(&c->activate.link);
|
||||||
@@ -1866,7 +1907,8 @@ void
|
@@ -1866,7 +1900,8 @@ void
|
||||||
motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy,
|
motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy,
|
||||||
double dx_unaccel, double dy_unaccel)
|
double dx_unaccel, double dy_unaccel)
|
||||||
{
|
{
|
||||||
@@ -791,13 +790,13 @@ index 8101ffa..32a94c4 100644
|
|||||||
Client *c = NULL, *w = NULL;
|
Client *c = NULL, *w = NULL;
|
||||||
LayerSurface *l = NULL;
|
LayerSurface *l = NULL;
|
||||||
struct wlr_surface *surface = NULL;
|
struct wlr_surface *surface = NULL;
|
||||||
@@ -1920,18 +1962,56 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
|
@@ -1920,18 +1955,55 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
|
||||||
/* Update drag icon's position */
|
/* Update drag icon's position */
|
||||||
wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y));
|
wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y));
|
||||||
|
|
||||||
- /* If we are currently grabbing the mouse, handle and return */
|
- /* If we are currently grabbing the mouse, handle and return */
|
||||||
+ /* Skip if internal call or already resizing */
|
+ /* Skip if internal call */
|
||||||
+ if (time == 0 && resizing_from_mouse)
|
+ if (time == 0)
|
||||||
+ goto focus;
|
+ goto focus;
|
||||||
+
|
+
|
||||||
+ tiled = grabc && !grabc->isfloating && !grabc->isfullscreen;
|
+ tiled = grabc && !grabc->isfloating && !grabc->isfullscreen;
|
||||||
@@ -819,7 +818,7 @@ index 8101ffa..32a94c4 100644
|
|||||||
- resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y,
|
- resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y,
|
||||||
- .width = (int)round(cursor->x) - grabc->geom.x, .height = (int)round(cursor->y) - grabc->geom.y}, 1);
|
- .width = (int)round(cursor->x) - grabc->geom.x, .height = (int)round(cursor->y) - grabc->geom.y}, 1);
|
||||||
- return;
|
- return;
|
||||||
+ if (tiled && resizing_from_mouse) {
|
+ if (tiled) {
|
||||||
+ dx_total = cursor->x - resize_last_update_x;
|
+ dx_total = cursor->x - resize_last_update_x;
|
||||||
+ dy_total = cursor->y - resize_last_update_y;
|
+ dy_total = cursor->y - resize_last_update_y;
|
||||||
+
|
+
|
||||||
@@ -832,7 +831,6 @@ index 8101ffa..32a94c4 100644
|
|||||||
+ a.f = (float)(dy_total * resize_factor);
|
+ a.f = (float)(dy_total * resize_factor);
|
||||||
+ setratio_v(&a);
|
+ setratio_v(&a);
|
||||||
+ }
|
+ }
|
||||||
+ arrange(selmon);
|
|
||||||
+
|
+
|
||||||
+ last_resize_time = time;
|
+ last_resize_time = time;
|
||||||
+ resize_last_update_x = cursor->x;
|
+ resize_last_update_x = cursor->x;
|
||||||
@@ -855,7 +853,7 @@ index 8101ffa..32a94c4 100644
|
|||||||
/* If there's no client surface under the cursor, set the cursor image to a
|
/* If there's no client surface under the cursor, set the cursor image to a
|
||||||
* default. This is what makes the cursor image appear when you move it
|
* default. This is what makes the cursor image appear when you move it
|
||||||
* off of a client or over its border. */
|
* off of a client or over its border. */
|
||||||
@@ -1965,22 +2045,41 @@ moveresize(const Arg *arg)
|
@@ -1965,22 +2037,40 @@ moveresize(const Arg *arg)
|
||||||
if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
|
if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -890,7 +888,6 @@ index 8101ffa..32a94c4 100644
|
|||||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
||||||
+ resize_last_update_x = cursor->x;
|
+ resize_last_update_x = cursor->x;
|
||||||
+ resize_last_update_y = cursor->y;
|
+ resize_last_update_y = cursor->y;
|
||||||
+ resizing_from_mouse = 1;
|
|
||||||
+ break;
|
+ break;
|
||||||
+ }
|
+ }
|
||||||
+ } else {
|
+ } else {
|
||||||
@@ -913,17 +910,17 @@ index 8101ffa..32a94c4 100644
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2833,6 +2932,14 @@ unmapnotify(struct wl_listener *listener, void *data)
|
@@ -2833,6 +2923,14 @@ unmapnotify(struct wl_listener *listener, void *data)
|
||||||
focusclient(focustop(selmon), 1);
|
focusclient(focustop(selmon), 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
+ // btrtile remove clients for each monitor
|
+ /* btrtile remove clients for each monitor */
|
||||||
+ Monitor *mon;
|
+ Monitor *mon;
|
||||||
+ wl_list_for_each(mon, &mons, link) {
|
+ wl_list_for_each(mon, &mons, link) {
|
||||||
+ if (mon->root) {
|
+ if (mon->root) {
|
||||||
+ remove_client(mon, c);
|
+ remove_client(mon, c);
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
wl_list_remove(&c->link);
|
wl_list_remove(&c->link);
|
||||||
setmon(c, NULL, 0);
|
setmon(c, NULL, 0);
|
||||||
|
|||||||
@@ -1,23 +1,24 @@
|
|||||||
From 3c78ee7e48fb24276d1a8d722ca1e715ea07d17f Mon Sep 17 00:00:00 2001
|
From 47cb7ad9f669643765cafa4c2ecd1a4850bca893 Mon Sep 17 00:00:00 2001
|
||||||
From: julmajustus <julmajustus@tutanota.com>
|
From: julmajustus <julmajustus@tutanota.com>
|
||||||
Date: Sun, 17 May 2026 23:28:41 +0300
|
Date: Thu, 21 May 2026 00:39:56 +0300
|
||||||
Subject: [PATCH] btrtile resizing refactor
|
Subject: [PATCH] btrtile: Spring update pt2
|
||||||
|
|
||||||
- Refactored the tiled client resizing logic to be more logical. Insted
|
- Simplified the resizing logic to avoid full arrange calls from
|
||||||
of resizing based on clients split nodes, now btrtile handles client resizing based on the nearest edge client edge on the resize direction. Now it handles also resizing of the clientless splitnodes and should feel more intuitive.
|
motionnotify
|
||||||
|
- Minor intend fixes
|
||||||
---
|
---
|
||||||
btrtile.c | 563 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
btrtile.c | 564 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
config.def.h | 12 ++
|
config.def.h | 12 ++
|
||||||
dwl.c | 161 ++++++++++++---
|
dwl.c | 152 +++++++++++---
|
||||||
3 files changed, 709 insertions(+), 27 deletions(-)
|
3 files changed, 701 insertions(+), 27 deletions(-)
|
||||||
create mode 100644 btrtile.c
|
create mode 100644 btrtile.c
|
||||||
|
|
||||||
diff --git a/btrtile.c b/btrtile.c
|
diff --git a/btrtile.c b/btrtile.c
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 0000000..7e70478
|
index 0000000..357ffb9
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/btrtile.c
|
+++ b/btrtile.c
|
||||||
@@ -0,0 +1,563 @@
|
@@ -0,0 +1,564 @@
|
||||||
+/* ************************************************************************** */
|
+/* ************************************************************************** */
|
||||||
+/* @@@ @@@@@@@@ */
|
+/* @@@ @@@@@@@@ */
|
||||||
+/* @@@ @@@@@@@@@@ */
|
+/* @@@ @@@@@@@@@@ */
|
||||||
@@ -28,7 +29,7 @@ index 0000000..7e70478
|
|||||||
+/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */
|
+/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */
|
||||||
+/* ::! :!: !:! */
|
+/* ::! :!: !:! */
|
||||||
+/* Created: 2024/12/15 00:26:07 by julmajustus :: ::::::: :: */
|
+/* Created: 2024/12/15 00:26:07 by julmajustus :: ::::::: :: */
|
||||||
+/* Updated: 2026/05/17 23:26:25 by julmajustus : : : : : : */
|
+/* Updated: 2026/05/20 22:51:54 by julmajustus : : : : : : */
|
||||||
+/* */
|
+/* */
|
||||||
+/* ************************************************************************** */
|
+/* ************************************************************************** */
|
||||||
+
|
+
|
||||||
@@ -63,7 +64,6 @@ index 0000000..7e70478
|
|||||||
+static unsigned int visible_count(LayoutNode *node, Monitor *m);
|
+static unsigned int visible_count(LayoutNode *node, Monitor *m);
|
||||||
+static Client *xytoclient(double x, double y);
|
+static Client *xytoclient(double x, double y);
|
||||||
+
|
+
|
||||||
+static int resizing_from_mouse = 0;
|
|
||||||
+static double resize_last_update_x, resize_last_update_y;
|
+static double resize_last_update_x, resize_last_update_y;
|
||||||
+static uint32_t last_resize_time = 0;
|
+static uint32_t last_resize_time = 0;
|
||||||
+
|
+
|
||||||
@@ -84,6 +84,9 @@ index 0000000..7e70478
|
|||||||
+ c = node->client;
|
+ c = node->client;
|
||||||
+ if (!c || !VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
+ if (!c || !VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||||
+ return;
|
+ return;
|
||||||
|
+ if (area.x == c->old_geom.x && area.y == c->old_geom.y &&
|
||||||
|
+ area.width == c->old_geom.width && area.height == c->old_geom.height)
|
||||||
|
+ return;
|
||||||
+ resize(c, area, 0);
|
+ resize(c, area, 0);
|
||||||
+ c->old_geom = area;
|
+ c->old_geom = area;
|
||||||
+ return;
|
+ return;
|
||||||
@@ -150,16 +153,16 @@ index 0000000..7e70478
|
|||||||
+ LayoutNode *found;
|
+ LayoutNode *found;
|
||||||
+ struct wlr_box full_area;
|
+ struct wlr_box full_area;
|
||||||
+
|
+
|
||||||
+ if (!m)
|
+ if (!m)
|
||||||
+ return;
|
+ return;
|
||||||
+
|
+
|
||||||
+ /* Remove non tiled clients from tree. */
|
+ /* Remove non tiled clients from tree. */
|
||||||
+ wl_list_for_each(c, &clients, link) {
|
+ wl_list_for_each(c, &clients, link) {
|
||||||
+ if (c->mon == m && !c->isfloating && !c->isfullscreen) {
|
+ if (c->mon == m && !c->isfloating && !c->isfullscreen) {
|
||||||
+ } else {
|
+ } else {
|
||||||
+ remove_client(m, c);
|
+ remove_client(m, c);
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ /* If no client is found under cursor, fallback to focustop(m) */
|
+ /* If no client is found under cursor, fallback to focustop(m) */
|
||||||
+ if (!(focused = xytoclient(cursor->x, cursor->y)))
|
+ if (!(focused = xytoclient(cursor->x, cursor->y)))
|
||||||
@@ -253,7 +256,7 @@ index 0000000..7e70478
|
|||||||
+
|
+
|
||||||
+LayoutNode *
|
+LayoutNode *
|
||||||
+find_suitable_split(Monitor *m, LayoutNode *start_node,
|
+find_suitable_split(Monitor *m, LayoutNode *start_node,
|
||||||
+ unsigned int need_vertical, int focused_on_left)
|
+ unsigned int need_vertical, int focused_on_left)
|
||||||
+{
|
+{
|
||||||
+ LayoutNode *n = start_node, *child = NULL;
|
+ LayoutNode *n = start_node, *child = NULL;
|
||||||
+
|
+
|
||||||
@@ -425,11 +428,11 @@ index 0000000..7e70478
|
|||||||
+ if (!client_node)
|
+ if (!client_node)
|
||||||
+ return;
|
+ return;
|
||||||
+
|
+
|
||||||
+ focused_on_left = (arg->f >= 0.0f);
|
+ focused_on_left = (arg->f >= 0.0f);
|
||||||
+
|
+
|
||||||
+ split_node = find_suitable_split(selmon, client_node, need_vertical, focused_on_left);
|
+ split_node = find_suitable_split(selmon, client_node, need_vertical, focused_on_left);
|
||||||
+
|
+
|
||||||
+ if (!split_node)
|
+ if (!split_node)
|
||||||
+ split_node = find_suitable_split(selmon, client_node, need_vertical, !focused_on_left);
|
+ split_node = find_suitable_split(selmon, client_node, need_vertical, !focused_on_left);
|
||||||
+ if (!split_node)
|
+ if (!split_node)
|
||||||
+ return;
|
+ return;
|
||||||
@@ -441,10 +444,9 @@ index 0000000..7e70478
|
|||||||
+ new_ratio = 0.95f;
|
+ new_ratio = 0.95f;
|
||||||
+ split_node->split_ratio = new_ratio;
|
+ split_node->split_ratio = new_ratio;
|
||||||
+
|
+
|
||||||
|
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
||||||
+ /* Skip the arrange when called from motionnotify; that path calls
|
+ /* Skip the arrange when called from motionnotify; that path calls
|
||||||
+ * arrange itself after rate-limiting. */
|
+ * arrange itself after rate-limiting. */
|
||||||
+ if (!resizing_from_mouse)
|
|
||||||
+ arrange(selmon);
|
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+void
|
+void
|
||||||
@@ -460,69 +462,69 @@ index 0000000..7e70478
|
|||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+void swapclients(const Arg *arg) {
|
+void swapclients(const Arg *arg) {
|
||||||
+ Client *c, *tmp, *target = NULL, *sel = focustop(selmon);
|
+ Client *c, *tmp, *target = NULL, *sel = focustop(selmon);
|
||||||
+ LayoutNode *sel_node, *target_node;
|
+ LayoutNode *sel_node, *target_node;
|
||||||
+ int closest_dist = INT_MAX, dist, sel_center_x, sel_center_y,
|
+ int closest_dist = INT_MAX, dist, sel_center_x, sel_center_y,
|
||||||
+ cand_center_x, cand_center_y;
|
+ cand_center_x, cand_center_y;
|
||||||
+
|
+
|
||||||
+ if (!sel || sel->isfullscreen ||
|
+ if (!sel || sel->isfullscreen ||
|
||||||
+ !selmon->root || !selmon->lt[selmon->sellt]->arrange)
|
+ !selmon->root || !selmon->lt[selmon->sellt]->arrange)
|
||||||
+ return;
|
+ return;
|
||||||
+
|
+
|
||||||
+
|
+
|
||||||
+ /* Get the center coordinates of the selected client */
|
+ /* Get the center coordinates of the selected client */
|
||||||
+ sel_center_x = sel->geom.x + sel->geom.width / 2;
|
+ sel_center_x = sel->geom.x + sel->geom.width / 2;
|
||||||
+ sel_center_y = sel->geom.y + sel->geom.height / 2;
|
+ sel_center_y = sel->geom.y + sel->geom.height / 2;
|
||||||
+
|
+
|
||||||
+ wl_list_for_each(c, &clients, link) {
|
+ wl_list_for_each(c, &clients, link) {
|
||||||
+ if (!VISIBLEON(c, selmon) || c->isfloating || c->isfullscreen || c == sel)
|
+ if (!VISIBLEON(c, selmon) || c->isfloating || c->isfullscreen || c == sel)
|
||||||
+ continue;
|
+ continue;
|
||||||
+
|
+
|
||||||
+ /* Get the center of candidate client */
|
+ /* Get the center of candidate client */
|
||||||
+ cand_center_x = c->geom.x + c->geom.width / 2;
|
+ cand_center_x = c->geom.x + c->geom.width / 2;
|
||||||
+ cand_center_y = c->geom.y + c->geom.height / 2;
|
+ cand_center_y = c->geom.y + c->geom.height / 2;
|
||||||
+
|
+
|
||||||
+ /* Check that the candidate lies in the requested direction. */
|
+ /* Check that the candidate lies in the requested direction. */
|
||||||
+ switch (arg->ui) {
|
+ switch (arg->ui) {
|
||||||
+ case 0:
|
+ case 0:
|
||||||
+ if (cand_center_x >= sel_center_x)
|
+ if (cand_center_x >= sel_center_x)
|
||||||
+ continue;
|
+ continue;
|
||||||
+ break;
|
+ break;
|
||||||
+ case 1:
|
+ case 1:
|
||||||
+ if (cand_center_x <= sel_center_x)
|
+ if (cand_center_x <= sel_center_x)
|
||||||
+ continue;
|
+ continue;
|
||||||
+ break;
|
+ break;
|
||||||
+ case 2:
|
+ case 2:
|
||||||
+ if (cand_center_y >= sel_center_y)
|
+ if (cand_center_y >= sel_center_y)
|
||||||
+ continue;
|
+ continue;
|
||||||
+ break;
|
+ break;
|
||||||
+ case 3:
|
+ case 3:
|
||||||
+ if (cand_center_y <= sel_center_y)
|
+ if (cand_center_y <= sel_center_y)
|
||||||
+ continue;
|
+ continue;
|
||||||
+ break;
|
+ break;
|
||||||
+ default:
|
+ default:
|
||||||
+ continue;
|
+ continue;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ /* Get distance between the centers */
|
+ /* Get distance between the centers */
|
||||||
+ dist = abs(sel_center_x - cand_center_x) + abs(sel_center_y - cand_center_y);
|
+ dist = abs(sel_center_x - cand_center_x) + abs(sel_center_y - cand_center_y);
|
||||||
+ if (dist < closest_dist) {
|
+ if (dist < closest_dist) {
|
||||||
+ closest_dist = dist;
|
+ closest_dist = dist;
|
||||||
+ target = c;
|
+ target = c;
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ /* If target is found, swap the two clients’ positions in the layout tree */
|
+ /* If target is found, swap the two clients’ positions in the layout tree */
|
||||||
+ if (target) {
|
+ if (target) {
|
||||||
+ sel_node = find_client_node(selmon->root, sel);
|
+ sel_node = find_client_node(selmon->root, sel);
|
||||||
+ target_node = find_client_node(selmon->root, target);
|
+ target_node = find_client_node(selmon->root, target);
|
||||||
+ if (sel_node && target_node) {
|
+ if (sel_node && target_node) {
|
||||||
+ tmp = sel_node->client;
|
+ tmp = sel_node->client;
|
||||||
+ sel_node->client = target_node->client;
|
+ sel_node->client = target_node->client;
|
||||||
+ target_node->client = tmp;
|
+ target_node->client = tmp;
|
||||||
+ arrange(selmon);
|
+ arrange(selmon);
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+unsigned int
|
+unsigned int
|
||||||
@@ -545,7 +547,7 @@ index 0000000..7e70478
|
|||||||
+
|
+
|
||||||
+Client *
|
+Client *
|
||||||
+xytoclient(double x, double y) {
|
+xytoclient(double x, double y) {
|
||||||
+ Monitor *m = xytomon(x, y);
|
+ Monitor *m = xytomon(x, y);
|
||||||
+ Client *c, *closest = NULL;
|
+ Client *c, *closest = NULL;
|
||||||
+ double dist, mindist = INT_MAX, dx, dy;
|
+ double dist, mindist = INT_MAX, dx, dy;
|
||||||
+
|
+
|
||||||
@@ -620,7 +622,7 @@ index 8a6eda0..bc04e3f 100644
|
|||||||
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
|
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
|
||||||
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
||||||
diff --git a/dwl.c b/dwl.c
|
diff --git a/dwl.c b/dwl.c
|
||||||
index 8101ffa..32a94c4 100644
|
index 8101ffa..bf52c6c 100644
|
||||||
--- a/dwl.c
|
--- a/dwl.c
|
||||||
+++ b/dwl.c
|
+++ b/dwl.c
|
||||||
@@ -1,6 +1,7 @@
|
@@ -1,6 +1,7 @@
|
||||||
@@ -702,7 +704,7 @@ index 8101ffa..32a94c4 100644
|
|||||||
b->func(&b->arg);
|
b->func(&b->arg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -659,6 +668,27 @@ buttonpress(struct wl_listener *listener, void *data)
|
@@ -659,6 +668,21 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||||
/* If you released any buttons, we exit interactive move/resize mode. */
|
/* If you released any buttons, we exit interactive move/resize mode. */
|
||||||
/* TODO: should reset to the pointer focus's current setcursor */
|
/* TODO: should reset to the pointer focus's current setcursor */
|
||||||
if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
|
if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
|
||||||
@@ -717,20 +719,14 @@ index 8101ffa..32a94c4 100644
|
|||||||
+ selmon->root = create_client_node(c);
|
+ selmon->root = create_client_node(c);
|
||||||
+
|
+
|
||||||
+ setfloating(c, 0);
|
+ setfloating(c, 0);
|
||||||
+ arrange(selmon);
|
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
||||||
+
|
|
||||||
+ } else if (cursor_mode == CurResize && !c->isfloating) {
|
|
||||||
+ resizing_from_mouse = 0;
|
|
||||||
+ }
|
+ }
|
||||||
+ } else {
|
|
||||||
+ if (cursor_mode == CurResize && resizing_from_mouse)
|
|
||||||
+ resizing_from_mouse = 0;
|
|
||||||
+ }
|
+ }
|
||||||
+ /* Default behaviour */
|
+ /* Default behaviour */
|
||||||
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
||||||
cursor_mode = CurNormal;
|
cursor_mode = CurNormal;
|
||||||
/* Drop the window off on its new monitor */
|
/* Drop the window off on its new monitor */
|
||||||
@@ -750,6 +780,7 @@ cleanupmon(struct wl_listener *listener, void *data)
|
@@ -750,6 +774,7 @@ cleanupmon(struct wl_listener *listener, void *data)
|
||||||
wlr_output_layout_remove(output_layout, m->wlr_output);
|
wlr_output_layout_remove(output_layout, m->wlr_output);
|
||||||
wlr_scene_output_destroy(m->scene_output);
|
wlr_scene_output_destroy(m->scene_output);
|
||||||
|
|
||||||
@@ -738,7 +734,7 @@ index 8101ffa..32a94c4 100644
|
|||||||
closemon(m);
|
closemon(m);
|
||||||
wlr_scene_node_destroy(&m->fullscreen_bg->node);
|
wlr_scene_node_destroy(&m->fullscreen_bg->node);
|
||||||
free(m);
|
free(m);
|
||||||
@@ -1094,6 +1125,7 @@ createmon(struct wl_listener *listener, void *data)
|
@@ -1094,6 +1119,7 @@ createmon(struct wl_listener *listener, void *data)
|
||||||
|
|
||||||
wl_list_insert(&mons, &m->link);
|
wl_list_insert(&mons, &m->link);
|
||||||
printstatus();
|
printstatus();
|
||||||
@@ -746,23 +742,25 @@ index 8101ffa..32a94c4 100644
|
|||||||
|
|
||||||
/* The xdg-protocol specifies:
|
/* The xdg-protocol specifies:
|
||||||
*
|
*
|
||||||
@@ -1336,6 +1368,15 @@ destroynotify(struct wl_listener *listener, void *data)
|
@@ -1333,9 +1359,17 @@ destroynotify(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
|
/* Called when the xdg_toplevel is destroyed. */
|
||||||
|
Client *c = wl_container_of(listener, c, destroy);
|
||||||
|
+ Monitor *mon;
|
||||||
wl_list_remove(&c->destroy.link);
|
wl_list_remove(&c->destroy.link);
|
||||||
wl_list_remove(&c->set_title.link);
|
wl_list_remove(&c->set_title.link);
|
||||||
wl_list_remove(&c->fullscreen.link);
|
wl_list_remove(&c->fullscreen.link);
|
||||||
+ /* We check if the destroyed client was part of any tiled_list, to catch
|
+ /* We check if the destroyed client was part of any tiled_list, to catch
|
||||||
+ * client removals even if they would not be currently managed by btrtile */
|
+ * client removals even if they would not be currently managed by btrtile */
|
||||||
+ // btrtile remove clients for each monitor
|
+ wl_list_for_each(mon, &mons, link) {
|
||||||
+ Monitor *mon;
|
+ if (mon->root) {
|
||||||
+ wl_list_for_each(mon, &mons, link) {
|
+ remove_client(mon, c);
|
||||||
+ if (mon->root) {
|
+ }
|
||||||
+ remove_client(mon, c);
|
+ }
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
#ifdef XWAYLAND
|
#ifdef XWAYLAND
|
||||||
if (c->type != XDGShell) {
|
if (c->type != XDGShell) {
|
||||||
wl_list_remove(&c->activate.link);
|
wl_list_remove(&c->activate.link);
|
||||||
@@ -1866,7 +1907,8 @@ void
|
@@ -1866,7 +1900,8 @@ void
|
||||||
motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy,
|
motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy,
|
||||||
double dx_unaccel, double dy_unaccel)
|
double dx_unaccel, double dy_unaccel)
|
||||||
{
|
{
|
||||||
@@ -772,13 +770,13 @@ index 8101ffa..32a94c4 100644
|
|||||||
Client *c = NULL, *w = NULL;
|
Client *c = NULL, *w = NULL;
|
||||||
LayerSurface *l = NULL;
|
LayerSurface *l = NULL;
|
||||||
struct wlr_surface *surface = NULL;
|
struct wlr_surface *surface = NULL;
|
||||||
@@ -1920,18 +1962,56 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
|
@@ -1920,18 +1955,55 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
|
||||||
/* Update drag icon's position */
|
/* Update drag icon's position */
|
||||||
wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y));
|
wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y));
|
||||||
|
|
||||||
- /* If we are currently grabbing the mouse, handle and return */
|
- /* If we are currently grabbing the mouse, handle and return */
|
||||||
+ /* Skip if internal call or already resizing */
|
+ /* Skip if internal call */
|
||||||
+ if (time == 0 && resizing_from_mouse)
|
+ if (time == 0)
|
||||||
+ goto focus;
|
+ goto focus;
|
||||||
+
|
+
|
||||||
+ tiled = grabc && !grabc->isfloating && !grabc->isfullscreen;
|
+ tiled = grabc && !grabc->isfloating && !grabc->isfullscreen;
|
||||||
@@ -800,7 +798,7 @@ index 8101ffa..32a94c4 100644
|
|||||||
- resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y,
|
- resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y,
|
||||||
- .width = (int)round(cursor->x) - grabc->geom.x, .height = (int)round(cursor->y) - grabc->geom.y}, 1);
|
- .width = (int)round(cursor->x) - grabc->geom.x, .height = (int)round(cursor->y) - grabc->geom.y}, 1);
|
||||||
- return;
|
- return;
|
||||||
+ if (tiled && resizing_from_mouse) {
|
+ if (tiled) {
|
||||||
+ dx_total = cursor->x - resize_last_update_x;
|
+ dx_total = cursor->x - resize_last_update_x;
|
||||||
+ dy_total = cursor->y - resize_last_update_y;
|
+ dy_total = cursor->y - resize_last_update_y;
|
||||||
+
|
+
|
||||||
@@ -813,7 +811,6 @@ index 8101ffa..32a94c4 100644
|
|||||||
+ a.f = (float)(dy_total * resize_factor);
|
+ a.f = (float)(dy_total * resize_factor);
|
||||||
+ setratio_v(&a);
|
+ setratio_v(&a);
|
||||||
+ }
|
+ }
|
||||||
+ arrange(selmon);
|
|
||||||
+
|
+
|
||||||
+ last_resize_time = time;
|
+ last_resize_time = time;
|
||||||
+ resize_last_update_x = cursor->x;
|
+ resize_last_update_x = cursor->x;
|
||||||
@@ -836,7 +833,7 @@ index 8101ffa..32a94c4 100644
|
|||||||
/* If there's no client surface under the cursor, set the cursor image to a
|
/* If there's no client surface under the cursor, set the cursor image to a
|
||||||
* default. This is what makes the cursor image appear when you move it
|
* default. This is what makes the cursor image appear when you move it
|
||||||
* off of a client or over its border. */
|
* off of a client or over its border. */
|
||||||
@@ -1965,22 +2045,41 @@ moveresize(const Arg *arg)
|
@@ -1965,22 +2037,40 @@ moveresize(const Arg *arg)
|
||||||
if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
|
if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -871,7 +868,6 @@ index 8101ffa..32a94c4 100644
|
|||||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
||||||
+ resize_last_update_x = cursor->x;
|
+ resize_last_update_x = cursor->x;
|
||||||
+ resize_last_update_y = cursor->y;
|
+ resize_last_update_y = cursor->y;
|
||||||
+ resizing_from_mouse = 1;
|
|
||||||
+ break;
|
+ break;
|
||||||
+ }
|
+ }
|
||||||
+ } else {
|
+ } else {
|
||||||
@@ -894,17 +890,17 @@ index 8101ffa..32a94c4 100644
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2833,6 +2932,14 @@ unmapnotify(struct wl_listener *listener, void *data)
|
@@ -2833,6 +2923,14 @@ unmapnotify(struct wl_listener *listener, void *data)
|
||||||
focusclient(focustop(selmon), 1);
|
focusclient(focustop(selmon), 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
+ // btrtile remove clients for each monitor
|
+ /* btrtile remove clients for each monitor */
|
||||||
+ Monitor *mon;
|
+ Monitor *mon;
|
||||||
+ wl_list_for_each(mon, &mons, link) {
|
+ wl_list_for_each(mon, &mons, link) {
|
||||||
+ if (mon->root) {
|
+ if (mon->root) {
|
||||||
+ remove_client(mon, c);
|
+ remove_client(mon, c);
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
wl_list_remove(&c->link);
|
wl_list_remove(&c->link);
|
||||||
setmon(c, NULL, 0);
|
setmon(c, NULL, 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user