mirror of
https://codeberg.org/dwl/dwl-patches.git
synced 2026-06-20 15:02:45 +00:00
Compare commits
10 Commits
7f06b4c1a3
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| d8046ab6ec | |||
| 0935f95e01 | |||
| e2ba7017ea | |||
| 493dc4c408 | |||
| 33acb045a8 | |||
| bbe1199e40 | |||
| 1f0e82bf5d | |||
| 5483e1d437 | |||
| 30c33ed26c | |||
| 03de6e2ada |
@@ -4,7 +4,7 @@
|
||||
|
||||
It provides a focus-driven, mouse- and keyboard-friendly tiling layout that grants you granular control over how clients are placed and resized.
|
||||
|
||||

|
||||

|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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>
|
||||
Date: Sun, 17 May 2026 22:49:07 +0300
|
||||
Subject: [PATCH] btrtile resizing refactor
|
||||
Date: Thu, 21 May 2026 00:42:07 +0300
|
||||
Subject: [PATCH] btrtile: Spring update pt2
|
||||
|
||||
- Refactored the tiled client resizing logic to be more logical. Insted
|
||||
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.
|
||||
- Simplified the resizing logic to avoid full arrange calls from
|
||||
motionnotify
|
||||
- Minor intend fixes
|
||||
---
|
||||
btrtile.c | 582 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
btrtile.c | 583 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
config.def.h | 12 ++
|
||||
dwl.c | 160 +++++++++++---
|
||||
3 files changed, 727 insertions(+), 27 deletions(-)
|
||||
dwl.c | 152 +++++++++++---
|
||||
3 files changed, 720 insertions(+), 27 deletions(-)
|
||||
create mode 100644 btrtile.c
|
||||
|
||||
diff --git a/btrtile.c b/btrtile.c
|
||||
new file mode 100644
|
||||
index 0000000..c63e59f
|
||||
index 0000000..f05a30f
|
||||
--- /dev/null
|
||||
+++ b/btrtile.c
|
||||
@@ -0,0 +1,582 @@
|
||||
@@ -0,0 +1,583 @@
|
||||
+/* ************************************************************************** */
|
||||
+/* @@@ @@@@@@@@ */
|
||||
+/* @@@ @@@@@@@@@@ */
|
||||
@@ -28,7 +29,7 @@ index 0000000..c63e59f
|
||||
+/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */
|
||||
+/* ::! :!: !:! */
|
||||
+/* 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 Client *xytoclient(double x, double y);
|
||||
+
|
||||
+static int resizing_from_mouse = 0;
|
||||
+static double resize_last_update_x, resize_last_update_y;
|
||||
+static uint32_t last_resize_time = 0;
|
||||
+
|
||||
@@ -91,6 +91,9 @@ index 0000000..c63e59f
|
||||
+ c = node->client;
|
||||
+ if (!c || !VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||
+ 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);
|
||||
+ c->old_geom = area;
|
||||
+ return;
|
||||
@@ -460,10 +463,9 @@ index 0000000..c63e59f
|
||||
+ new_ratio = 0.95f;
|
||||
+ split_node->split_ratio = new_ratio;
|
||||
+
|
||||
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
||||
+ /* Skip the arrange when called from motionnotify; that path calls
|
||||
+ * arrange itself after rate-limiting. */
|
||||
+ if (!resizing_from_mouse)
|
||||
+ arrange(selmon);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
@@ -639,7 +641,7 @@ index 8a6eda0..bc04e3f 100644
|
||||
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
|
||||
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 44f3ad9..d37e235 100644
|
||||
index 44f3ad9..a121efc 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -1,6 +1,7 @@
|
||||
@@ -721,7 +723,7 @@ index 44f3ad9..d37e235 100644
|
||||
b->func(&b->arg);
|
||||
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. */
|
||||
/* TODO: should reset to the pointer focus's current setcursor */
|
||||
if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
|
||||
@@ -736,20 +738,14 @@ index 44f3ad9..d37e235 100644
|
||||
+ selmon->root = create_client_node(c);
|
||||
+
|
||||
+ setfloating(c, 0);
|
||||
+ arrange(selmon);
|
||||
+
|
||||
+ } else if (cursor_mode == CurResize && !c->isfloating) {
|
||||
+ resizing_from_mouse = 0;
|
||||
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (cursor_mode == CurResize && resizing_from_mouse)
|
||||
+ resizing_from_mouse = 0;
|
||||
+ }
|
||||
+ /* Default behaviour */
|
||||
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
||||
cursor_mode = CurNormal;
|
||||
/* 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_scene_output_destroy(m->scene_output);
|
||||
|
||||
@@ -757,7 +753,7 @@ index 44f3ad9..d37e235 100644
|
||||
closemon(m);
|
||||
wlr_scene_node_destroy(&m->fullscreen_bg->node);
|
||||
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);
|
||||
printstatus();
|
||||
@@ -765,13 +761,16 @@ index 44f3ad9..d37e235 100644
|
||||
|
||||
/* 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->set_title.link);
|
||||
wl_list_remove(&c->fullscreen.link);
|
||||
+ /* 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 */
|
||||
+ Monitor *mon;
|
||||
+ wl_list_for_each(mon, &mons, link) {
|
||||
+ if (mon->root) {
|
||||
+ remove_client(mon, c);
|
||||
@@ -780,7 +779,7 @@ index 44f3ad9..d37e235 100644
|
||||
#ifdef XWAYLAND
|
||||
if (c->type != XDGShell) {
|
||||
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,
|
||||
double dx_unaccel, double dy_unaccel)
|
||||
{
|
||||
@@ -790,13 +789,13 @@ index 44f3ad9..d37e235 100644
|
||||
Client *c = NULL, *w = NULL;
|
||||
LayerSurface *l = 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 */
|
||||
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 */
|
||||
+ /* Skip if internal call or already resizing */
|
||||
+ if (time == 0 && resizing_from_mouse)
|
||||
+ /* Skip if internal call */
|
||||
+ if (time == 0)
|
||||
+ goto focus;
|
||||
+
|
||||
+ 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,
|
||||
- .width = (int)round(cursor->x) - grabc->geom.x, .height = (int)round(cursor->y) - grabc->geom.y}, 1);
|
||||
- return;
|
||||
+ if (tiled && resizing_from_mouse) {
|
||||
+ if (tiled) {
|
||||
+ dx_total = cursor->x - resize_last_update_x;
|
||||
+ dy_total = cursor->y - resize_last_update_y;
|
||||
+
|
||||
@@ -831,7 +830,6 @@ index 44f3ad9..d37e235 100644
|
||||
+ a.f = (float)(dy_total * resize_factor);
|
||||
+ setratio_v(&a);
|
||||
+ }
|
||||
+ arrange(selmon);
|
||||
+
|
||||
+ last_resize_time = time;
|
||||
+ 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
|
||||
* default. This is what makes the cursor image appear when you move it
|
||||
* 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)
|
||||
return;
|
||||
|
||||
@@ -889,7 +887,6 @@ index 44f3ad9..d37e235 100644
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
||||
+ resize_last_update_x = cursor->x;
|
||||
+ resize_last_update_y = cursor->y;
|
||||
+ resizing_from_mouse = 1;
|
||||
+ break;
|
||||
+ }
|
||||
+ } else {
|
||||
@@ -912,11 +909,11 @@ 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);
|
||||
}
|
||||
} else {
|
||||
+ // btrtile remove clients for each monitor
|
||||
+ /* btrtile remove clients for each monitor */
|
||||
+ Monitor *mon;
|
||||
+ wl_list_for_each(mon, &mons, link) {
|
||||
+ if (mon->root) {
|
||||
|
||||
@@ -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>
|
||||
Date: Sun, 17 May 2026 22:39:30 +0300
|
||||
Subject: [PATCH] btrtile resizing refactor
|
||||
Date: Thu, 21 May 2026 00:40:54 +0300
|
||||
Subject: [PATCH] btrtile: Spring update pt2
|
||||
|
||||
- Refactored the tiled client resizing logic to be more logical. Insted
|
||||
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.
|
||||
- Simplified the resizing logic to avoid full arrange calls from
|
||||
motionnotify
|
||||
- Minor intend fixes
|
||||
---
|
||||
btrtile.c | 563 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
btrtile.c | 564 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
config.def.h | 12 ++
|
||||
dwl.c | 160 ++++++++++++---
|
||||
3 files changed, 708 insertions(+), 27 deletions(-)
|
||||
dwl.c | 152 +++++++++++---
|
||||
3 files changed, 701 insertions(+), 27 deletions(-)
|
||||
create mode 100644 btrtile.c
|
||||
|
||||
diff --git a/btrtile.c b/btrtile.c
|
||||
new file mode 100644
|
||||
index 0000000..ad810bf
|
||||
index 0000000..357ffb9
|
||||
--- /dev/null
|
||||
+++ b/btrtile.c
|
||||
@@ -0,0 +1,563 @@
|
||||
@@ -0,0 +1,564 @@
|
||||
+/* ************************************************************************** */
|
||||
+/* @@@ @@@@@@@@ */
|
||||
+/* @@@ @@@@@@@@@@ */
|
||||
@@ -28,7 +29,7 @@ index 0000000..ad810bf
|
||||
+/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */
|
||||
+/* ::! :!: !:! */
|
||||
+/* 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 Client *xytoclient(double x, double y);
|
||||
+
|
||||
+static int resizing_from_mouse = 0;
|
||||
+static double resize_last_update_x, resize_last_update_y;
|
||||
+static uint32_t last_resize_time = 0;
|
||||
+
|
||||
@@ -84,6 +84,9 @@ index 0000000..ad810bf
|
||||
+ c = node->client;
|
||||
+ if (!c || !VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||
+ 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);
|
||||
+ c->old_geom = area;
|
||||
+ return;
|
||||
@@ -441,10 +444,9 @@ index 0000000..ad810bf
|
||||
+ new_ratio = 0.95f;
|
||||
+ split_node->split_ratio = new_ratio;
|
||||
+
|
||||
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
||||
+ /* Skip the arrange when called from motionnotify; that path calls
|
||||
+ * arrange itself after rate-limiting. */
|
||||
+ if (!resizing_from_mouse)
|
||||
+ arrange(selmon);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
@@ -620,7 +622,7 @@ index 8a6eda0..bc04e3f 100644
|
||||
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
|
||||
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 44f3ad9..d37e235 100644
|
||||
index 44f3ad9..a121efc 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -1,6 +1,7 @@
|
||||
@@ -702,7 +704,7 @@ index 44f3ad9..d37e235 100644
|
||||
b->func(&b->arg);
|
||||
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. */
|
||||
/* TODO: should reset to the pointer focus's current setcursor */
|
||||
if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
|
||||
@@ -717,20 +719,14 @@ index 44f3ad9..d37e235 100644
|
||||
+ selmon->root = create_client_node(c);
|
||||
+
|
||||
+ setfloating(c, 0);
|
||||
+ arrange(selmon);
|
||||
+
|
||||
+ } else if (cursor_mode == CurResize && !c->isfloating) {
|
||||
+ resizing_from_mouse = 0;
|
||||
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (cursor_mode == CurResize && resizing_from_mouse)
|
||||
+ resizing_from_mouse = 0;
|
||||
+ }
|
||||
+ /* Default behaviour */
|
||||
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
||||
cursor_mode = CurNormal;
|
||||
/* 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_scene_output_destroy(m->scene_output);
|
||||
|
||||
@@ -738,7 +734,7 @@ index 44f3ad9..d37e235 100644
|
||||
closemon(m);
|
||||
wlr_scene_node_destroy(&m->fullscreen_bg->node);
|
||||
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);
|
||||
printstatus();
|
||||
@@ -746,13 +742,16 @@ index 44f3ad9..d37e235 100644
|
||||
|
||||
/* 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->set_title.link);
|
||||
wl_list_remove(&c->fullscreen.link);
|
||||
+ /* 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 */
|
||||
+ Monitor *mon;
|
||||
+ wl_list_for_each(mon, &mons, link) {
|
||||
+ if (mon->root) {
|
||||
+ remove_client(mon, c);
|
||||
@@ -761,7 +760,7 @@ index 44f3ad9..d37e235 100644
|
||||
#ifdef XWAYLAND
|
||||
if (c->type != XDGShell) {
|
||||
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,
|
||||
double dx_unaccel, double dy_unaccel)
|
||||
{
|
||||
@@ -771,13 +770,13 @@ index 44f3ad9..d37e235 100644
|
||||
Client *c = NULL, *w = NULL;
|
||||
LayerSurface *l = 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 */
|
||||
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 */
|
||||
+ /* Skip if internal call or already resizing */
|
||||
+ if (time == 0 && resizing_from_mouse)
|
||||
+ /* Skip if internal call */
|
||||
+ if (time == 0)
|
||||
+ goto focus;
|
||||
+
|
||||
+ 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,
|
||||
- .width = (int)round(cursor->x) - grabc->geom.x, .height = (int)round(cursor->y) - grabc->geom.y}, 1);
|
||||
- return;
|
||||
+ if (tiled && resizing_from_mouse) {
|
||||
+ if (tiled) {
|
||||
+ dx_total = cursor->x - resize_last_update_x;
|
||||
+ dy_total = cursor->y - resize_last_update_y;
|
||||
+
|
||||
@@ -812,7 +811,6 @@ index 44f3ad9..d37e235 100644
|
||||
+ a.f = (float)(dy_total * resize_factor);
|
||||
+ setratio_v(&a);
|
||||
+ }
|
||||
+ arrange(selmon);
|
||||
+
|
||||
+ last_resize_time = time;
|
||||
+ 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
|
||||
* default. This is what makes the cursor image appear when you move it
|
||||
* 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)
|
||||
return;
|
||||
|
||||
@@ -870,7 +868,6 @@ index 44f3ad9..d37e235 100644
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
||||
+ resize_last_update_x = cursor->x;
|
||||
+ resize_last_update_y = cursor->y;
|
||||
+ resizing_from_mouse = 1;
|
||||
+ break;
|
||||
+ }
|
||||
+ } else {
|
||||
@@ -893,11 +890,11 @@ 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);
|
||||
}
|
||||
} else {
|
||||
+ // btrtile remove clients for each monitor
|
||||
+ /* btrtile remove clients for each monitor */
|
||||
+ Monitor *mon;
|
||||
+ wl_list_for_each(mon, &mons, link) {
|
||||
+ if (mon->root) {
|
||||
|
||||
@@ -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>
|
||||
Date: Sun, 17 May 2026 23:10:49 +0300
|
||||
Subject: [PATCH] btrtile resizing refactor
|
||||
Date: Thu, 21 May 2026 00:38:45 +0300
|
||||
Subject: [PATCH] btrtile: Spring update pt2
|
||||
|
||||
- Refactored the tiled client resizing logic to be more logical. Insted
|
||||
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.
|
||||
- Simplified the resizing logic to avoid full arrange calls from
|
||||
motionnotify
|
||||
- Minor intend fixes
|
||||
---
|
||||
btrtile.c | 582 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
btrtile.c | 583 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
config.def.h | 12 ++
|
||||
dwl.c | 161 +++++++++++---
|
||||
3 files changed, 728 insertions(+), 27 deletions(-)
|
||||
dwl.c | 152 +++++++++++---
|
||||
3 files changed, 720 insertions(+), 27 deletions(-)
|
||||
create mode 100644 btrtile.c
|
||||
|
||||
diff --git a/btrtile.c b/btrtile.c
|
||||
new file mode 100644
|
||||
index 0000000..c63e59f
|
||||
index 0000000..f05a30f
|
||||
--- /dev/null
|
||||
+++ b/btrtile.c
|
||||
@@ -0,0 +1,582 @@
|
||||
@@ -0,0 +1,583 @@
|
||||
+/* ************************************************************************** */
|
||||
+/* @@@ @@@@@@@@ */
|
||||
+/* @@@ @@@@@@@@@@ */
|
||||
@@ -28,7 +29,7 @@ index 0000000..c63e59f
|
||||
+/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */
|
||||
+/* ::! :!: !:! */
|
||||
+/* 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 Client *xytoclient(double x, double y);
|
||||
+
|
||||
+static int resizing_from_mouse = 0;
|
||||
+static double resize_last_update_x, resize_last_update_y;
|
||||
+static uint32_t last_resize_time = 0;
|
||||
+
|
||||
@@ -91,6 +91,9 @@ index 0000000..c63e59f
|
||||
+ c = node->client;
|
||||
+ if (!c || !VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||
+ 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);
|
||||
+ c->old_geom = area;
|
||||
+ return;
|
||||
@@ -460,10 +463,9 @@ index 0000000..c63e59f
|
||||
+ new_ratio = 0.95f;
|
||||
+ split_node->split_ratio = new_ratio;
|
||||
+
|
||||
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
||||
+ /* Skip the arrange when called from motionnotify; that path calls
|
||||
+ * arrange itself after rate-limiting. */
|
||||
+ if (!resizing_from_mouse)
|
||||
+ arrange(selmon);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
@@ -639,7 +641,7 @@ index 8a6eda0..bc04e3f 100644
|
||||
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
|
||||
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 8101ffa..32a94c4 100644
|
||||
index 8101ffa..c9650c1 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -1,6 +1,7 @@
|
||||
@@ -721,7 +723,7 @@ index 8101ffa..32a94c4 100644
|
||||
b->func(&b->arg);
|
||||
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. */
|
||||
/* TODO: should reset to the pointer focus's current setcursor */
|
||||
if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
|
||||
@@ -736,20 +738,14 @@ index 8101ffa..32a94c4 100644
|
||||
+ selmon->root = create_client_node(c);
|
||||
+
|
||||
+ setfloating(c, 0);
|
||||
+ arrange(selmon);
|
||||
+
|
||||
+ } else if (cursor_mode == CurResize && !c->isfloating) {
|
||||
+ resizing_from_mouse = 0;
|
||||
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (cursor_mode == CurResize && resizing_from_mouse)
|
||||
+ resizing_from_mouse = 0;
|
||||
+ }
|
||||
+ /* Default behaviour */
|
||||
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
||||
cursor_mode = CurNormal;
|
||||
/* 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_scene_output_destroy(m->scene_output);
|
||||
|
||||
@@ -757,7 +753,7 @@ index 8101ffa..32a94c4 100644
|
||||
closemon(m);
|
||||
wlr_scene_node_destroy(&m->fullscreen_bg->node);
|
||||
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);
|
||||
printstatus();
|
||||
@@ -765,14 +761,17 @@ index 8101ffa..32a94c4 100644
|
||||
|
||||
/* 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->set_title.link);
|
||||
wl_list_remove(&c->fullscreen.link);
|
||||
+ /* 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 */
|
||||
+ // btrtile remove clients for each monitor
|
||||
+ Monitor *mon;
|
||||
+ wl_list_for_each(mon, &mons, link) {
|
||||
+ if (mon->root) {
|
||||
+ remove_client(mon, c);
|
||||
@@ -781,7 +780,7 @@ index 8101ffa..32a94c4 100644
|
||||
#ifdef XWAYLAND
|
||||
if (c->type != XDGShell) {
|
||||
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,
|
||||
double dx_unaccel, double dy_unaccel)
|
||||
{
|
||||
@@ -791,13 +790,13 @@ index 8101ffa..32a94c4 100644
|
||||
Client *c = NULL, *w = NULL;
|
||||
LayerSurface *l = 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 */
|
||||
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 */
|
||||
+ /* Skip if internal call or already resizing */
|
||||
+ if (time == 0 && resizing_from_mouse)
|
||||
+ /* Skip if internal call */
|
||||
+ if (time == 0)
|
||||
+ goto focus;
|
||||
+
|
||||
+ 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,
|
||||
- .width = (int)round(cursor->x) - grabc->geom.x, .height = (int)round(cursor->y) - grabc->geom.y}, 1);
|
||||
- return;
|
||||
+ if (tiled && resizing_from_mouse) {
|
||||
+ if (tiled) {
|
||||
+ dx_total = cursor->x - resize_last_update_x;
|
||||
+ dy_total = cursor->y - resize_last_update_y;
|
||||
+
|
||||
@@ -832,7 +831,6 @@ index 8101ffa..32a94c4 100644
|
||||
+ a.f = (float)(dy_total * resize_factor);
|
||||
+ setratio_v(&a);
|
||||
+ }
|
||||
+ arrange(selmon);
|
||||
+
|
||||
+ last_resize_time = time;
|
||||
+ 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
|
||||
* default. This is what makes the cursor image appear when you move it
|
||||
* 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)
|
||||
return;
|
||||
|
||||
@@ -890,7 +888,6 @@ index 8101ffa..32a94c4 100644
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
||||
+ resize_last_update_x = cursor->x;
|
||||
+ resize_last_update_y = cursor->y;
|
||||
+ resizing_from_mouse = 1;
|
||||
+ break;
|
||||
+ }
|
||||
+ } else {
|
||||
@@ -913,11 +910,11 @@ 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);
|
||||
}
|
||||
} else {
|
||||
+ // btrtile remove clients for each monitor
|
||||
+ /* btrtile remove clients for each monitor */
|
||||
+ Monitor *mon;
|
||||
+ wl_list_for_each(mon, &mons, link) {
|
||||
+ if (mon->root) {
|
||||
|
||||
@@ -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>
|
||||
Date: Sun, 17 May 2026 23:28:41 +0300
|
||||
Subject: [PATCH] btrtile resizing refactor
|
||||
Date: Thu, 21 May 2026 00:39:56 +0300
|
||||
Subject: [PATCH] btrtile: Spring update pt2
|
||||
|
||||
- Refactored the tiled client resizing logic to be more logical. Insted
|
||||
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.
|
||||
- Simplified the resizing logic to avoid full arrange calls from
|
||||
motionnotify
|
||||
- Minor intend fixes
|
||||
---
|
||||
btrtile.c | 563 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
btrtile.c | 564 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
config.def.h | 12 ++
|
||||
dwl.c | 161 ++++++++++++---
|
||||
3 files changed, 709 insertions(+), 27 deletions(-)
|
||||
dwl.c | 152 +++++++++++---
|
||||
3 files changed, 701 insertions(+), 27 deletions(-)
|
||||
create mode 100644 btrtile.c
|
||||
|
||||
diff --git a/btrtile.c b/btrtile.c
|
||||
new file mode 100644
|
||||
index 0000000..7e70478
|
||||
index 0000000..357ffb9
|
||||
--- /dev/null
|
||||
+++ b/btrtile.c
|
||||
@@ -0,0 +1,563 @@
|
||||
@@ -0,0 +1,564 @@
|
||||
+/* ************************************************************************** */
|
||||
+/* @@@ @@@@@@@@ */
|
||||
+/* @@@ @@@@@@@@@@ */
|
||||
@@ -28,7 +29,7 @@ index 0000000..7e70478
|
||||
+/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */
|
||||
+/* ::! :!: !:! */
|
||||
+/* 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 Client *xytoclient(double x, double y);
|
||||
+
|
||||
+static int resizing_from_mouse = 0;
|
||||
+static double resize_last_update_x, resize_last_update_y;
|
||||
+static uint32_t last_resize_time = 0;
|
||||
+
|
||||
@@ -84,6 +84,9 @@ index 0000000..7e70478
|
||||
+ c = node->client;
|
||||
+ if (!c || !VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||
+ 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);
|
||||
+ c->old_geom = area;
|
||||
+ return;
|
||||
@@ -441,10 +444,9 @@ index 0000000..7e70478
|
||||
+ new_ratio = 0.95f;
|
||||
+ split_node->split_ratio = new_ratio;
|
||||
+
|
||||
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
||||
+ /* Skip the arrange when called from motionnotify; that path calls
|
||||
+ * arrange itself after rate-limiting. */
|
||||
+ if (!resizing_from_mouse)
|
||||
+ arrange(selmon);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
@@ -620,7 +622,7 @@ index 8a6eda0..bc04e3f 100644
|
||||
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
|
||||
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 8101ffa..32a94c4 100644
|
||||
index 8101ffa..bf52c6c 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -1,6 +1,7 @@
|
||||
@@ -702,7 +704,7 @@ index 8101ffa..32a94c4 100644
|
||||
b->func(&b->arg);
|
||||
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. */
|
||||
/* TODO: should reset to the pointer focus's current setcursor */
|
||||
if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
|
||||
@@ -717,20 +719,14 @@ index 8101ffa..32a94c4 100644
|
||||
+ selmon->root = create_client_node(c);
|
||||
+
|
||||
+ setfloating(c, 0);
|
||||
+ arrange(selmon);
|
||||
+
|
||||
+ } else if (cursor_mode == CurResize && !c->isfloating) {
|
||||
+ resizing_from_mouse = 0;
|
||||
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (cursor_mode == CurResize && resizing_from_mouse)
|
||||
+ resizing_from_mouse = 0;
|
||||
+ }
|
||||
+ /* Default behaviour */
|
||||
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
||||
cursor_mode = CurNormal;
|
||||
/* 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_scene_output_destroy(m->scene_output);
|
||||
|
||||
@@ -738,7 +734,7 @@ index 8101ffa..32a94c4 100644
|
||||
closemon(m);
|
||||
wlr_scene_node_destroy(&m->fullscreen_bg->node);
|
||||
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);
|
||||
printstatus();
|
||||
@@ -746,14 +742,16 @@ index 8101ffa..32a94c4 100644
|
||||
|
||||
/* 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->set_title.link);
|
||||
wl_list_remove(&c->fullscreen.link);
|
||||
+ /* 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 */
|
||||
+ // btrtile remove clients for each monitor
|
||||
+ Monitor *mon;
|
||||
+ wl_list_for_each(mon, &mons, link) {
|
||||
+ if (mon->root) {
|
||||
+ remove_client(mon, c);
|
||||
@@ -762,7 +760,7 @@ index 8101ffa..32a94c4 100644
|
||||
#ifdef XWAYLAND
|
||||
if (c->type != XDGShell) {
|
||||
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,
|
||||
double dx_unaccel, double dy_unaccel)
|
||||
{
|
||||
@@ -772,13 +770,13 @@ index 8101ffa..32a94c4 100644
|
||||
Client *c = NULL, *w = NULL;
|
||||
LayerSurface *l = 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 */
|
||||
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 */
|
||||
+ /* Skip if internal call or already resizing */
|
||||
+ if (time == 0 && resizing_from_mouse)
|
||||
+ /* Skip if internal call */
|
||||
+ if (time == 0)
|
||||
+ goto focus;
|
||||
+
|
||||
+ 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,
|
||||
- .width = (int)round(cursor->x) - grabc->geom.x, .height = (int)round(cursor->y) - grabc->geom.y}, 1);
|
||||
- return;
|
||||
+ if (tiled && resizing_from_mouse) {
|
||||
+ if (tiled) {
|
||||
+ dx_total = cursor->x - resize_last_update_x;
|
||||
+ dy_total = cursor->y - resize_last_update_y;
|
||||
+
|
||||
@@ -813,7 +811,6 @@ index 8101ffa..32a94c4 100644
|
||||
+ a.f = (float)(dy_total * resize_factor);
|
||||
+ setratio_v(&a);
|
||||
+ }
|
||||
+ arrange(selmon);
|
||||
+
|
||||
+ last_resize_time = time;
|
||||
+ 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
|
||||
* default. This is what makes the cursor image appear when you move it
|
||||
* 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)
|
||||
return;
|
||||
|
||||
@@ -871,7 +868,6 @@ index 8101ffa..32a94c4 100644
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
||||
+ resize_last_update_x = cursor->x;
|
||||
+ resize_last_update_y = cursor->y;
|
||||
+ resizing_from_mouse = 1;
|
||||
+ break;
|
||||
+ }
|
||||
+ } else {
|
||||
@@ -894,11 +890,11 @@ 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);
|
||||
}
|
||||
} else {
|
||||
+ // btrtile remove clients for each monitor
|
||||
+ /* btrtile remove clients for each monitor */
|
||||
+ Monitor *mon;
|
||||
+ wl_list_for_each(mon, &mons, link) {
|
||||
+ if (mon->root) {
|
||||
|
||||
@@ -13,8 +13,8 @@ This allows the user to change size and placement of floating windows using only
|
||||
| <kbd>MODKEY</kbd> + <kbd>Shift</kbd> + <kbd>Right</kbd> | grow width 40px |
|
||||
|
||||
### Download
|
||||
- [git branch](https://codeberg.org/wochap/dwl/src/branch/v0.5/moveresizekb)
|
||||
- [v0.5](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/moveresizekb/moveresizekb.patch)
|
||||
- [v0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/moveresizekb/moveresizekb.patch)
|
||||
|
||||
### Authors
|
||||
- [cana](https://codeberg.org/cana)
|
||||
- [wochap](https://codeberg.org/wochap)
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
From c8af428f964679089599e4ffbe7d28d08a4e875f Mon Sep 17 00:00:00 2001
|
||||
From: wochap <gean.marroquin@gmail.com>
|
||||
Date: Tue, 5 Mar 2024 23:42:55 -0500
|
||||
Subject: [PATCH] implement keybindings to move and resize focused floating
|
||||
window
|
||||
From f19c162ba64c2c4860e5d16e48e08cebd7a7e46c Mon Sep 17 00:00:00 2001
|
||||
From: C4FE1 <heitorcdesousa13@gmail.com>
|
||||
Date: Wed, 10 Jun 2026 19:50:26 -0300
|
||||
Subject: [PATCH] Change moveresizekb logic to allow it's use in floating
|
||||
(NULL) Layout
|
||||
|
||||
---
|
||||
config.def.h | 8 ++++++++
|
||||
dwl.c | 19 +++++++++++++++++++
|
||||
2 files changed, 27 insertions(+)
|
||||
dwl.c | 23 +++++++++++++++++++++++
|
||||
2 files changed, 31 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index db0babc..d0570b8 100644
|
||||
index 8a6eda0..b8398f9 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -135,6 +135,14 @@ static const Key keys[] = {
|
||||
@@ -138,6 +138,14 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_space, setlayout, {0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
|
||||
{ MODKEY, XKB_KEY_e, togglefullscreen, {0} },
|
||||
@@ -29,10 +29,10 @@ index db0babc..d0570b8 100644
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} },
|
||||
{ MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} },
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index ef27a1d..251472b 100644
|
||||
index 44f3ad9..a6450f5 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -313,6 +313,7 @@ static void tagmon(const Arg *arg);
|
||||
@@ -336,6 +336,7 @@ static void tagmon(const Arg *arg);
|
||||
static void tile(Monitor *m);
|
||||
static void togglefloating(const Arg *arg);
|
||||
static void togglefullscreen(const Arg *arg);
|
||||
@@ -40,7 +40,7 @@ index ef27a1d..251472b 100644
|
||||
static void toggletag(const Arg *arg);
|
||||
static void toggleview(const Arg *arg);
|
||||
static void unlocksession(struct wl_listener *listener, void *data);
|
||||
@@ -2454,6 +2455,24 @@ togglefullscreen(const Arg *arg)
|
||||
@@ -2760,6 +2761,28 @@ togglefullscreen(const Arg *arg)
|
||||
setfullscreen(sel, !sel->isfullscreen);
|
||||
}
|
||||
|
||||
@@ -50,7 +50,11 @@ index ef27a1d..251472b 100644
|
||||
+ Client *c = focustop(selmon);
|
||||
+ Monitor *m = selmon;
|
||||
+
|
||||
+ if(!(m && arg && arg->v && c && c->isfloating)) {
|
||||
+ if(!(m && arg && arg->v && c)){
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if(!(c->isfloating || m->lt[m->sellt]->arrange == NULL)){
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
@@ -66,5 +70,5 @@ index ef27a1d..251472b 100644
|
||||
toggletag(const Arg *arg)
|
||||
{
|
||||
--
|
||||
2.42.0
|
||||
2.54.0
|
||||
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
Moves clients to their old output when it is reattached.
|
||||
|
||||
### Download
|
||||
- [git branch](https://codeberg.org/eyusupov/dwl/src/branch/restore-monitor)
|
||||
- [2024-04-07](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/restore-monitor/restore-monitor.patch)
|
||||
- [git branch](https://codeberg.org/6z7y/dwl-patches/src/branch/restore-monitor)
|
||||
- [2026-06-20](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/restore-monitor/restore-monitor.patch)
|
||||
### Authors
|
||||
#### Current
|
||||
- [6z7y](https://codeberg.org/6z7y)
|
||||
#### Historic
|
||||
- [eyusupov](https://codeberg.org/eyusupov)
|
||||
|
||||
|
||||
@@ -1,25 +1,40 @@
|
||||
From e42ca1c539437d3098d80983cfe2ad6f938d7a08 Mon Sep 17 00:00:00 2001
|
||||
From: Eldar Yusupov <eyusupov@gmail.com>
|
||||
Date: Sun, 17 Mar 2024 19:12:29 +0300
|
||||
Subject: [PATCH] Restore correct monitor for client when it is reattached
|
||||
Subject: [PATCH] Restore correct monitor and floating position when reattached
|
||||
|
||||
---
|
||||
dwl.c | 24 ++++++++++++++++++++++--
|
||||
1 file changed, 22 insertions(+), 2 deletions(-)
|
||||
dwl.c | 33 ++++++++++++++++++++++++++++++---
|
||||
1 file changed, 30 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index bf763df..d8d8139 100644
|
||||
index 44f3ad9..41548cd 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -107,6 +107,7 @@ typedef struct {
|
||||
@@ -106,6 +106,8 @@ typedef struct {
|
||||
unsigned int type; /* XDGShell or X11* */
|
||||
struct wlr_box geom; /* layout-relative, includes border */
|
||||
|
||||
Monitor *mon;
|
||||
+ char *output;
|
||||
+ struct wlr_box floatgeom; /* saved geom for floating restore after monitor reconnect */
|
||||
struct wlr_scene_tree *scene;
|
||||
struct wlr_scene_rect *border[4]; /* top, bottom, left, right */
|
||||
struct wlr_scene_tree *scene_surface;
|
||||
@@ -869,6 +870,7 @@ createmon(struct wl_listener *listener, void *data)
|
||||
@@ -807,6 +809,13 @@ closemon(Monitor *m)
|
||||
}
|
||||
|
||||
wl_list_for_each(c, &clients, link) {
|
||||
+
|
||||
+ /* Save floating geom now, before destroymon modifies it below.
|
||||
+ * destroymon subtracts m->w.width from c->geom.x for floating
|
||||
+ * windows, which corrupts the layout-absolute position we need
|
||||
+ * to restore on reconnect. */
|
||||
+ if (c->isfloating && c->mon == m) c->floatgeom = c->geom;
|
||||
+
|
||||
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,
|
||||
.width = c->geom.width, .height = c->geom.height}, 0);
|
||||
@@ -1045,6 +1054,7 @@ createmon(struct wl_listener *listener, void *data)
|
||||
size_t i;
|
||||
struct wlr_output_state state;
|
||||
Monitor *m;
|
||||
@@ -27,53 +42,54 @@ index bf763df..d8d8139 100644
|
||||
|
||||
if (!wlr_output_init_render(wlr_output, alloc, drw))
|
||||
return;
|
||||
@@ -938,6 +940,13 @@ createmon(struct wl_listener *listener, void *data)
|
||||
@@ -1114,6 +1124,15 @@ createmon(struct wl_listener *listener, void *data)
|
||||
wlr_output_layout_add_auto(output_layout, wlr_output);
|
||||
else
|
||||
wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y);
|
||||
+
|
||||
+ wl_list_for_each(c, &clients, link) {
|
||||
+ if (strcmp(wlr_output->name, c->output) == 0) {
|
||||
+ if (!c->output || strcmp(wlr_output->name, c->output) != 0)
|
||||
+ continue;
|
||||
+ c->mon = m;
|
||||
+ }
|
||||
+ if (c->isfloating)
|
||||
+ resize(c, c->floatgeom, 0);
|
||||
+ }
|
||||
+ updatemons(NULL, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1186,6 +1195,7 @@ destroynotify(struct wl_listener *listener, void *data)
|
||||
wl_list_remove(&c->map.link);
|
||||
@@ -1347,7 +1366,8 @@ destroynotify(struct wl_listener *listener, void *data)
|
||||
wl_list_remove(&c->unmap.link);
|
||||
wl_list_remove(&c->maximize.link);
|
||||
}
|
||||
- free(c);
|
||||
+ free(c->output);
|
||||
free(c);
|
||||
+ free(c);
|
||||
}
|
||||
|
||||
@@ -1618,6 +1628,10 @@ mapnotify(struct wl_listener *listener, void *data)
|
||||
void
|
||||
@@ -1792,6 +1812,9 @@ mapnotify(struct wl_listener *listener, void *data)
|
||||
} else {
|
||||
applyrules(c);
|
||||
}
|
||||
+ c->output = strdup(c->mon->wlr_output->name);
|
||||
+ if (c->output == NULL) {
|
||||
+ die("oom");
|
||||
+ }
|
||||
+ if (c->output == NULL) die("oom");
|
||||
+
|
||||
printstatus();
|
||||
|
||||
unset_fullscreen:
|
||||
@@ -2565,8 +2579,14 @@ void
|
||||
@@ -2705,8 +2728,12 @@ void
|
||||
tagmon(const Arg *arg)
|
||||
{
|
||||
Client *sel = focustop(selmon);
|
||||
- if (sel)
|
||||
- setmon(sel, dirtomon(arg->i), 0);
|
||||
+ if (!sel)
|
||||
+ return;
|
||||
+ if (!sel) return;
|
||||
+
|
||||
+ setmon(sel, dirtomon(arg->i), 0);
|
||||
+ free(sel->output);
|
||||
+ sel->output = strdup(sel->mon->wlr_output->name);
|
||||
+ if (sel->output == NULL) {
|
||||
+ die("oom");
|
||||
+ }
|
||||
+ if (sel->output == NULL) die("oom");
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
# simple_scratchpad — A very simple scratchpad utility.
|
||||
|
||||
Adds functions to add, toggle and remove clients to/from scratchpad client list.
|
||||

|
||||
Adds functions to add, toggle and remove clients to/from scratchpad client lists.
|
||||

|
||||
|
||||
---
|
||||
|
||||
@@ -16,11 +16,14 @@ Adds functions to add, toggle and remove clients to/from scratchpad client list.
|
||||
3. **removescratchpad**
|
||||
- Removes client from scratchpad client list.
|
||||
|
||||
4. **setscratchpad**
|
||||
- Sets current scratchpad number
|
||||
|
||||
|
||||
### Download
|
||||
- [git branch](https://codeberg.org/julmajustus/dwl/src/branch/simple_scratchpad)
|
||||
- [scratchpad-wlroots-next-f4249db.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/simple_scratchpad/simple_scratchpad-f4249db.patch)
|
||||
- [scratchpad-0.8.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/simple_scratchpad/simple_scratchpad-0.8.patch)
|
||||
- [scratchpad-wlroots-next-d41ecb7.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/simple_scratchpad/simple_scratchpad-wlroots-next-d41ecb7.patch)
|
||||
- [scratchpad-v0.8.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/simple_scratchpad/simple_scratchpad-v0.8.patch)
|
||||
|
||||
### Authors
|
||||
- [julmajustus](https://codeberg.org/julmajustus)
|
||||
|
||||
@@ -1,211 +0,0 @@
|
||||
From 0d603b179ccccbb4270fd202a14a2db18d0a5413 Mon Sep 17 00:00:00 2001
|
||||
From: A Frederick Christensen <dwl@ivories.org>
|
||||
Date: Thu, 26 Feb 2026 17:09:28 -0600
|
||||
Subject: [PATCH] Apply simple_scratchpad patch
|
||||
|
||||
---
|
||||
config.def.h | 3 ++
|
||||
dwl.c | 34 +++++++++++++++++++++--
|
||||
simple_scratchpad.c | 68 +++++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 103 insertions(+), 2 deletions(-)
|
||||
create mode 100644 simple_scratchpad.c
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 8a6eda0..6254fc9 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -132,6 +132,9 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_Return, zoom, {0} },
|
||||
{ MODKEY, XKB_KEY_Tab, view, {0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_c, killclient, {0} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_z, addscratchpad, {0} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_z, togglescratchpad, {0} },
|
||||
+ { MODKEY, XKB_KEY_z, removescratchpad, {0} },
|
||||
{ MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
|
||||
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 44f3ad9..215f630 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -139,6 +139,7 @@ typedef struct {
|
||||
uint32_t tags;
|
||||
int isfloating, isurgent, isfullscreen;
|
||||
uint32_t resize; /* configure serial of a pending resize */
|
||||
+ struct wl_list link_temp;
|
||||
} Client;
|
||||
|
||||
typedef struct {
|
||||
@@ -240,6 +241,7 @@ typedef struct {
|
||||
} SessionLock;
|
||||
|
||||
/* function declarations */
|
||||
+static void addscratchpad(const Arg *arg);
|
||||
static void applybounds(Client *c, struct wlr_box *bbox);
|
||||
static void applyrules(Client *c);
|
||||
static void arrange(Monitor *m);
|
||||
@@ -314,6 +316,7 @@ static void printstatus(void);
|
||||
static void powermgrsetmode(struct wl_listener *listener, void *data);
|
||||
static void quit(const Arg *arg);
|
||||
static void rendermon(struct wl_listener *listener, void *data);
|
||||
+static void removescratchpad(const Arg *arg);
|
||||
static void requestdecorationmode(struct wl_listener *listener, void *data);
|
||||
static void requeststartdrag(struct wl_listener *listener, void *data);
|
||||
static void requestmonstate(struct wl_listener *listener, void *data);
|
||||
@@ -336,6 +339,7 @@ static void tagmon(const Arg *arg);
|
||||
static void tile(Monitor *m);
|
||||
static void togglefloating(const Arg *arg);
|
||||
static void togglefullscreen(const Arg *arg);
|
||||
+static void togglescratchpad(const Arg *arg);
|
||||
static void toggletag(const Arg *arg);
|
||||
static void toggleview(const Arg *arg);
|
||||
static void unlocksession(struct wl_listener *listener, void *data);
|
||||
@@ -406,6 +410,9 @@ static struct wlr_box sgeom;
|
||||
static struct wl_list mons;
|
||||
static Monitor *selmon;
|
||||
|
||||
+static struct wl_list scratchpad_clients;
|
||||
+static int scratchpad_visible = 1;
|
||||
+
|
||||
/* global event handlers */
|
||||
static struct wl_listener cursor_axis = {.notify = axisnotify};
|
||||
static struct wl_listener cursor_button = {.notify = buttonpress};
|
||||
@@ -455,6 +462,8 @@ static struct wlr_xwayland *xwayland;
|
||||
/* attempt to encapsulate suck into one file */
|
||||
#include "client.h"
|
||||
|
||||
+#include "simple_scratchpad.c"
|
||||
+
|
||||
/* function implementations */
|
||||
void
|
||||
applybounds(Client *c, struct wlr_box *bbox)
|
||||
@@ -1328,10 +1337,20 @@ void
|
||||
destroynotify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
/* Called when the xdg_toplevel is destroyed. */
|
||||
- Client *c = wl_container_of(listener, c, destroy);
|
||||
+ Client *sc, *c = wl_container_of(listener, c, destroy);
|
||||
wl_list_remove(&c->destroy.link);
|
||||
wl_list_remove(&c->set_title.link);
|
||||
wl_list_remove(&c->fullscreen.link);
|
||||
+ /* Check if destroyed client was part of scratchpad_clients
|
||||
+ * and clean it from the list if so. */
|
||||
+ if (c && wl_list_length(&scratchpad_clients) > 0) {
|
||||
+ wl_list_for_each(sc, &scratchpad_clients, link_temp) {
|
||||
+ if (sc == c) {
|
||||
+ wl_list_remove(&c->link_temp);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
#ifdef XWAYLAND
|
||||
if (c->type != XDGShell) {
|
||||
wl_list_remove(&c->activate.link);
|
||||
@@ -2333,11 +2352,21 @@ setcursorshape(struct wl_listener *listener, void *data)
|
||||
void
|
||||
setfloating(Client *c, int floating)
|
||||
{
|
||||
- Client *p = client_get_parent(c);
|
||||
+ Client *sc, *p = client_get_parent(c);
|
||||
c->isfloating = floating;
|
||||
/* If in floating layout do not change the client's layer */
|
||||
if (!c->mon || !client_surface(c)->mapped || !c->mon->lt[c->mon->sellt]->arrange)
|
||||
return;
|
||||
+ /* Check if unfloated client was part of scratchpad_clients
|
||||
+ * and remove it from scratchpad_clients list if so */
|
||||
+ if (!floating && wl_list_length(&scratchpad_clients) > 0) {
|
||||
+ wl_list_for_each(sc, &scratchpad_clients, link_temp) {
|
||||
+ if (sc == c) {
|
||||
+ wl_list_remove(&c->link_temp);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen ||
|
||||
(p && p->isfullscreen) ? LyrFS
|
||||
: c->isfloating ? LyrFloat : LyrTile]);
|
||||
@@ -2554,6 +2583,7 @@ setup(void)
|
||||
*/
|
||||
wl_list_init(&clients);
|
||||
wl_list_init(&fstack);
|
||||
+ wl_list_init(&scratchpad_clients);
|
||||
|
||||
xdg_shell = wlr_xdg_shell_create(dpy, 6);
|
||||
wl_signal_add(&xdg_shell->events.new_toplevel, &new_xdg_toplevel);
|
||||
diff --git a/simple_scratchpad.c b/simple_scratchpad.c
|
||||
new file mode 100644
|
||||
index 0000000..26d6b66
|
||||
--- /dev/null
|
||||
+++ b/simple_scratchpad.c
|
||||
@@ -0,0 +1,68 @@
|
||||
+/* ************************************************************************** */
|
||||
+/* */
|
||||
+/* ::: :::::::: */
|
||||
+/* simple_scratchpad.c :+: :+: :+: */
|
||||
+/* +:+ +:+ +:+ */
|
||||
+/* By: jmakkone <jmakkone@student.hive.fi> +#+ +:+ +#+ */
|
||||
+/* +#+#+#+#+#+ +#+ */
|
||||
+/* Created: 2024/12/19 19:35:02 by jmakkone #+# #+# */
|
||||
+/* Updated: 2025/01/04 13:35:50 by jmakkone ### ########.fr */
|
||||
+/* */
|
||||
+/* ************************************************************************** */
|
||||
+
|
||||
+void
|
||||
+addscratchpad(const Arg *arg)
|
||||
+{
|
||||
+ Client *cc, *c = focustop(selmon);
|
||||
+
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+ /* Check if the added client is already a scratchpad client */
|
||||
+ wl_list_for_each(cc, &scratchpad_clients, link_temp) {
|
||||
+ if (cc == c)
|
||||
+ return;
|
||||
+ }
|
||||
+ if (!c->isfloating) {
|
||||
+ setfloating(c, 1);
|
||||
+ }
|
||||
+ wl_list_insert(&scratchpad_clients, &c->link_temp);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+togglescratchpad(const Arg *arg)
|
||||
+{
|
||||
+ Client *c;
|
||||
+ Monitor *m = selmon;
|
||||
+
|
||||
+ scratchpad_visible = !scratchpad_visible;
|
||||
+ if (scratchpad_visible) {
|
||||
+ wl_list_for_each(c, &scratchpad_clients, link_temp) {
|
||||
+ c->mon = m;
|
||||
+ c->tags = m->tagset[m->seltags];
|
||||
+ arrange(m);
|
||||
+ focusclient(c, 1);
|
||||
+ }
|
||||
+ } else {
|
||||
+ wl_list_for_each(c, &scratchpad_clients, link_temp) {
|
||||
+ c->tags = 0;
|
||||
+ focusclient(focustop(m), 1);
|
||||
+ arrange(m);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+removescratchpad(const Arg *arg)
|
||||
+{
|
||||
+ Client *sc, *c = focustop(selmon);
|
||||
+
|
||||
+ if (c && wl_list_length(&scratchpad_clients) > 0) {
|
||||
+ /* Check if c is in scratchpad_clients */
|
||||
+ wl_list_for_each(sc, &scratchpad_clients, link_temp) {
|
||||
+ if (sc == c) {
|
||||
+ wl_list_remove(&c->link_temp);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
From 09c708876afe3675f68f7b35c3f17263b134ceee Mon Sep 17 00:00:00 2001
|
||||
From: julmajustus <julmajustus@tutanota.com>
|
||||
Date: Thu, 21 May 2026 00:28:15 +0300
|
||||
Subject: [PATCH] simple_scratchpad: Spring update scratchpad V2
|
||||
|
||||
- Added support for multiple scratchpads
|
||||
---
|
||||
config.def.h | 7 ++++
|
||||
dwl.c | 43 +++++++++++++++++++++--
|
||||
simple_scratchpad.c | 85 +++++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 133 insertions(+), 2 deletions(-)
|
||||
create mode 100644 simple_scratchpad.c
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 8a6eda0..a527e09 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -14,6 +14,7 @@ static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
||||
static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */
|
||||
|
||||
+#define SCRATCHPAD_COUNT 3
|
||||
/* tagging - TAGCOUNT must be no greater than 31 */
|
||||
#define TAGCOUNT (9)
|
||||
|
||||
@@ -132,6 +133,9 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_Return, zoom, {0} },
|
||||
{ MODKEY, XKB_KEY_Tab, view, {0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_c, killclient, {0} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_z, addscratchpad, {0} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_z, togglescratchpad, {0} },
|
||||
+ { MODKEY, XKB_KEY_z, removescratchpad, {0} },
|
||||
{ MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
|
||||
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
|
||||
@@ -144,6 +148,9 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less, tagmon, {.i = WLR_DIRECTION_LEFT} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} },
|
||||
+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_1, setscratchpad, {.i = 0} },
|
||||
+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_2, setscratchpad, {.i = 1} },
|
||||
+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_3, setscratchpad, {.i = 2} },
|
||||
TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0),
|
||||
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
|
||||
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 44f3ad9..f54bbda 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -139,6 +139,7 @@ typedef struct {
|
||||
uint32_t tags;
|
||||
int isfloating, isurgent, isfullscreen;
|
||||
uint32_t resize; /* configure serial of a pending resize */
|
||||
+ struct wl_list link_temp;
|
||||
} Client;
|
||||
|
||||
typedef struct {
|
||||
@@ -240,6 +241,7 @@ typedef struct {
|
||||
} SessionLock;
|
||||
|
||||
/* function declarations */
|
||||
+static void addscratchpad(const Arg *arg);
|
||||
static void applybounds(Client *c, struct wlr_box *bbox);
|
||||
static void applyrules(Client *c);
|
||||
static void arrange(Monitor *m);
|
||||
@@ -314,6 +316,7 @@ static void printstatus(void);
|
||||
static void powermgrsetmode(struct wl_listener *listener, void *data);
|
||||
static void quit(const Arg *arg);
|
||||
static void rendermon(struct wl_listener *listener, void *data);
|
||||
+static void removescratchpad(const Arg *arg);
|
||||
static void requestdecorationmode(struct wl_listener *listener, void *data);
|
||||
static void requeststartdrag(struct wl_listener *listener, void *data);
|
||||
static void requestmonstate(struct wl_listener *listener, void *data);
|
||||
@@ -327,6 +330,7 @@ static void setlayout(const Arg *arg);
|
||||
static void setmfact(const Arg *arg);
|
||||
static void setmon(Client *c, Monitor *m, uint32_t newtags);
|
||||
static void setpsel(struct wl_listener *listener, void *data);
|
||||
+static void setscratchpad(const Arg *arg);
|
||||
static void setsel(struct wl_listener *listener, void *data);
|
||||
static void setup(void);
|
||||
static void spawn(const Arg *arg);
|
||||
@@ -336,6 +340,7 @@ static void tagmon(const Arg *arg);
|
||||
static void tile(Monitor *m);
|
||||
static void togglefloating(const Arg *arg);
|
||||
static void togglefullscreen(const Arg *arg);
|
||||
+static void togglescratchpad(const Arg *arg);
|
||||
static void toggletag(const Arg *arg);
|
||||
static void toggleview(const Arg *arg);
|
||||
static void unlocksession(struct wl_listener *listener, void *data);
|
||||
@@ -455,6 +460,11 @@ static struct wlr_xwayland *xwayland;
|
||||
/* attempt to encapsulate suck into one file */
|
||||
#include "client.h"
|
||||
|
||||
+static struct wl_list scratchpad_clients[SCRATCHPAD_COUNT];
|
||||
+static int scratchpad_visible[SCRATCHPAD_COUNT];
|
||||
+static int scratchpad_sel = 0;
|
||||
+#include "simple_scratchpad.c"
|
||||
+
|
||||
/* function implementations */
|
||||
void
|
||||
applybounds(Client *c, struct wlr_box *bbox)
|
||||
@@ -1328,10 +1338,21 @@ void
|
||||
destroynotify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
/* Called when the xdg_toplevel is destroyed. */
|
||||
- Client *c = wl_container_of(listener, c, destroy);
|
||||
+ Client *sc, *c = wl_container_of(listener, c, destroy);
|
||||
wl_list_remove(&c->destroy.link);
|
||||
wl_list_remove(&c->set_title.link);
|
||||
wl_list_remove(&c->fullscreen.link);
|
||||
+ /* Check if destroyed client was part of any scratchpad slot
|
||||
+ * and clean it from the list if so. */
|
||||
+ for (int i = 0; i < SCRATCHPAD_COUNT; i++) {
|
||||
+ wl_list_for_each(sc, &scratchpad_clients[i], link_temp) {
|
||||
+ if (sc == c) {
|
||||
+ wl_list_remove(&c->link_temp);
|
||||
+ goto scratchpad_destroy_done;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+scratchpad_destroy_done:;
|
||||
#ifdef XWAYLAND
|
||||
if (c->type != XDGShell) {
|
||||
wl_list_remove(&c->activate.link);
|
||||
@@ -2333,11 +2354,24 @@ setcursorshape(struct wl_listener *listener, void *data)
|
||||
void
|
||||
setfloating(Client *c, int floating)
|
||||
{
|
||||
- Client *p = client_get_parent(c);
|
||||
+ Client *sc, *p = client_get_parent(c);
|
||||
c->isfloating = floating;
|
||||
/* If in floating layout do not change the client's layer */
|
||||
if (!c->mon || !client_surface(c)->mapped || !c->mon->lt[c->mon->sellt]->arrange)
|
||||
return;
|
||||
+ /* Check if unfloated client was part of any scratchpad slot
|
||||
+ * and remove it from that slot if so */
|
||||
+ if (!floating) {
|
||||
+ for (int i = 0; i < SCRATCHPAD_COUNT; i++) {
|
||||
+ wl_list_for_each(sc, &scratchpad_clients[i], link_temp) {
|
||||
+ if (sc == c) {
|
||||
+ wl_list_remove(&c->link_temp);
|
||||
+ goto scratchpad_float_done;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+scratchpad_float_done:;
|
||||
+ }
|
||||
wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen ||
|
||||
(p && p->isfullscreen) ? LyrFS
|
||||
: c->isfloating ? LyrFloat : LyrTile]);
|
||||
@@ -2554,6 +2588,11 @@ setup(void)
|
||||
*/
|
||||
wl_list_init(&clients);
|
||||
wl_list_init(&fstack);
|
||||
+ wl_list_init(&fstack);
|
||||
+ for (int j = 0; j < SCRATCHPAD_COUNT; j++) {
|
||||
+ wl_list_init(&scratchpad_clients[j]);
|
||||
+ scratchpad_visible[j] = 1;
|
||||
+ }
|
||||
|
||||
xdg_shell = wlr_xdg_shell_create(dpy, 6);
|
||||
wl_signal_add(&xdg_shell->events.new_toplevel, &new_xdg_toplevel);
|
||||
diff --git a/simple_scratchpad.c b/simple_scratchpad.c
|
||||
new file mode 100644
|
||||
index 0000000..cd62d83
|
||||
--- /dev/null
|
||||
+++ b/simple_scratchpad.c
|
||||
@@ -0,0 +1,85 @@
|
||||
+/* ************************************************************************** */
|
||||
+/* @@@ @@@@@@@@ */
|
||||
+/* @@@ @@@@@@@@@@ */
|
||||
+/* @@! @@! @@@@ */
|
||||
+/* !@! !@! @!@!@ */
|
||||
+/* simple_scratchpad.c @!! @!@ @! !@! */
|
||||
+/* !!! !@!!! !!! */
|
||||
+/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */
|
||||
+/* ::! :!: !:! */
|
||||
+/* Created: 2024/12/19 19:35:02 by jmakkone :: ::::::: :: */
|
||||
+/* Updated: 2026/05/20 23:58:16 by julmajustus : : : : : : */
|
||||
+/* */
|
||||
+/* ************************************************************************** */
|
||||
+
|
||||
+void
|
||||
+addscratchpad(const Arg *arg)
|
||||
+{
|
||||
+ Client *cc, *c = focustop(selmon);
|
||||
+
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+ /* Check if the added client is already a scratchpad client */
|
||||
+ for (int i = 0; i < SCRATCHPAD_COUNT; i++) {
|
||||
+ wl_list_for_each(cc, &scratchpad_clients[i], link_temp) {
|
||||
+ if (cc == c)
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ if (!c->isfloating) {
|
||||
+ setfloating(c, 1);
|
||||
+ }
|
||||
+ wl_list_insert(&scratchpad_clients[scratchpad_sel], &c->link_temp);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+togglescratchpad(const Arg *arg)
|
||||
+{
|
||||
+ Client *c;
|
||||
+ Monitor *m = selmon;
|
||||
+
|
||||
+ scratchpad_visible[scratchpad_sel] = !scratchpad_visible[scratchpad_sel];
|
||||
+ if (scratchpad_visible[scratchpad_sel]) {
|
||||
+ wl_list_for_each(c, &scratchpad_clients[scratchpad_sel], link_temp) {
|
||||
+ c->mon = m;
|
||||
+ c->tags = m->tagset[m->seltags];
|
||||
+ arrange(m);
|
||||
+ focusclient(c, 1);
|
||||
+ }
|
||||
+ } else {
|
||||
+ wl_list_for_each(c, &scratchpad_clients[scratchpad_sel], link_temp) {
|
||||
+ c->tags = 0;
|
||||
+ focusclient(focustop(m), 1);
|
||||
+ arrange(m);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+removescratchpad(const Arg *arg)
|
||||
+{
|
||||
+ Client *sc, *c = focustop(selmon);
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+ for (int i = 0; i < SCRATCHPAD_COUNT; i++) {
|
||||
+ /* Check if c is in scratchpad_clients */
|
||||
+ wl_list_for_each(sc, &scratchpad_clients[i], link_temp) {
|
||||
+ if (sc == c) {
|
||||
+ wl_list_remove(&c->link_temp);
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+setscratchpad(const Arg *arg)
|
||||
+{
|
||||
+ int idx = arg->i;
|
||||
+
|
||||
+ if (idx < 0)
|
||||
+ idx = 0;
|
||||
+ else if (idx >= SCRATCHPAD_COUNT)
|
||||
+ idx = SCRATCHPAD_COUNT - 1;
|
||||
+ scratchpad_sel = idx;
|
||||
+}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
From be4f7488eac6ea502e0e9d1cc5595e01d97cb345 Mon Sep 17 00:00:00 2001
|
||||
From: julmajustus <julmajustus@tutanota.com>
|
||||
Date: Thu, 21 May 2026 00:28:41 +0300
|
||||
Subject: [PATCH] simple_scratchpad: Spring update scratchpad V2
|
||||
|
||||
- Added support for multiple scratchpads
|
||||
---
|
||||
config.def.h | 7 ++++
|
||||
dwl.c | 43 +++++++++++++++++++++--
|
||||
simple_scratchpad.c | 85 +++++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 133 insertions(+), 2 deletions(-)
|
||||
create mode 100644 simple_scratchpad.c
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 8a6eda0..a527e09 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -14,6 +14,7 @@ static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
||||
static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */
|
||||
|
||||
+#define SCRATCHPAD_COUNT 3
|
||||
/* tagging - TAGCOUNT must be no greater than 31 */
|
||||
#define TAGCOUNT (9)
|
||||
|
||||
@@ -132,6 +133,9 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_Return, zoom, {0} },
|
||||
{ MODKEY, XKB_KEY_Tab, view, {0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_c, killclient, {0} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_z, addscratchpad, {0} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_z, togglescratchpad, {0} },
|
||||
+ { MODKEY, XKB_KEY_z, removescratchpad, {0} },
|
||||
{ MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
|
||||
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
|
||||
@@ -144,6 +148,9 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less, tagmon, {.i = WLR_DIRECTION_LEFT} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} },
|
||||
+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_1, setscratchpad, {.i = 0} },
|
||||
+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_2, setscratchpad, {.i = 1} },
|
||||
+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_3, setscratchpad, {.i = 2} },
|
||||
TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0),
|
||||
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
|
||||
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 8101ffa..1c858a8 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -143,6 +143,7 @@ typedef struct {
|
||||
uint32_t tags;
|
||||
int isfloating, isurgent, isfullscreen;
|
||||
uint32_t resize; /* configure serial of a pending resize */
|
||||
+ struct wl_list link_temp;
|
||||
} Client;
|
||||
|
||||
typedef struct {
|
||||
@@ -244,6 +245,7 @@ typedef struct {
|
||||
} SessionLock;
|
||||
|
||||
/* function declarations */
|
||||
+static void addscratchpad(const Arg *arg);
|
||||
static void applybounds(Client *c, struct wlr_box *bbox);
|
||||
static void applyrules(Client *c);
|
||||
static void arrange(Monitor *m);
|
||||
@@ -318,6 +320,7 @@ static void printstatus(void);
|
||||
static void powermgrsetmode(struct wl_listener *listener, void *data);
|
||||
static void quit(const Arg *arg);
|
||||
static void rendermon(struct wl_listener *listener, void *data);
|
||||
+static void removescratchpad(const Arg *arg);
|
||||
static void requestdecorationmode(struct wl_listener *listener, void *data);
|
||||
static void requeststartdrag(struct wl_listener *listener, void *data);
|
||||
static void requestmonstate(struct wl_listener *listener, void *data);
|
||||
@@ -331,6 +334,7 @@ static void setlayout(const Arg *arg);
|
||||
static void setmfact(const Arg *arg);
|
||||
static void setmon(Client *c, Monitor *m, uint32_t newtags);
|
||||
static void setpsel(struct wl_listener *listener, void *data);
|
||||
+static void setscratchpad(const Arg *arg);
|
||||
static void setsel(struct wl_listener *listener, void *data);
|
||||
static void setup(void);
|
||||
static void spawn(const Arg *arg);
|
||||
@@ -340,6 +344,7 @@ static void tagmon(const Arg *arg);
|
||||
static void tile(Monitor *m);
|
||||
static void togglefloating(const Arg *arg);
|
||||
static void togglefullscreen(const Arg *arg);
|
||||
+static void togglescratchpad(const Arg *arg);
|
||||
static void toggletag(const Arg *arg);
|
||||
static void toggleview(const Arg *arg);
|
||||
static void unlocksession(struct wl_listener *listener, void *data);
|
||||
@@ -459,6 +464,11 @@ static struct wlr_xwayland *xwayland;
|
||||
/* attempt to encapsulate suck into one file */
|
||||
#include "client.h"
|
||||
|
||||
+static struct wl_list scratchpad_clients[SCRATCHPAD_COUNT];
|
||||
+static int scratchpad_visible[SCRATCHPAD_COUNT];
|
||||
+static int scratchpad_sel = 0;
|
||||
+#include "simple_scratchpad.c"
|
||||
+
|
||||
/* function implementations */
|
||||
void
|
||||
applybounds(Client *c, struct wlr_box *bbox)
|
||||
@@ -1332,10 +1342,21 @@ void
|
||||
destroynotify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
/* Called when the xdg_toplevel is destroyed. */
|
||||
- Client *c = wl_container_of(listener, c, destroy);
|
||||
+ Client *sc, *c = wl_container_of(listener, c, destroy);
|
||||
wl_list_remove(&c->destroy.link);
|
||||
wl_list_remove(&c->set_title.link);
|
||||
wl_list_remove(&c->fullscreen.link);
|
||||
+ /* Check if destroyed client was part of any scratchpad slot
|
||||
+ * and clean it from the list if so. */
|
||||
+ for (int i = 0; i < SCRATCHPAD_COUNT; i++) {
|
||||
+ wl_list_for_each(sc, &scratchpad_clients[i], link_temp) {
|
||||
+ if (sc == c) {
|
||||
+ wl_list_remove(&c->link_temp);
|
||||
+ goto scratchpad_destroy_done;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+scratchpad_destroy_done:;
|
||||
#ifdef XWAYLAND
|
||||
if (c->type != XDGShell) {
|
||||
wl_list_remove(&c->activate.link);
|
||||
@@ -2337,11 +2358,24 @@ setcursorshape(struct wl_listener *listener, void *data)
|
||||
void
|
||||
setfloating(Client *c, int floating)
|
||||
{
|
||||
- Client *p = client_get_parent(c);
|
||||
+ Client *sc, *p = client_get_parent(c);
|
||||
c->isfloating = floating;
|
||||
/* If in floating layout do not change the client's layer */
|
||||
if (!c->mon || !client_surface(c)->mapped || !c->mon->lt[c->mon->sellt]->arrange)
|
||||
return;
|
||||
+ /* Check if unfloated client was part of any scratchpad slot
|
||||
+ * and remove it from that slot if so */
|
||||
+ if (!floating) {
|
||||
+ for (int i = 0; i < SCRATCHPAD_COUNT; i++) {
|
||||
+ wl_list_for_each(sc, &scratchpad_clients[i], link_temp) {
|
||||
+ if (sc == c) {
|
||||
+ wl_list_remove(&c->link_temp);
|
||||
+ goto scratchpad_float_done;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+scratchpad_float_done:;
|
||||
+ }
|
||||
wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen ||
|
||||
(p && p->isfullscreen) ? LyrFS
|
||||
: c->isfloating ? LyrFloat : LyrTile]);
|
||||
@@ -2561,6 +2595,11 @@ setup(void)
|
||||
*/
|
||||
wl_list_init(&clients);
|
||||
wl_list_init(&fstack);
|
||||
+ wl_list_init(&fstack);
|
||||
+ for (int j = 0; j < SCRATCHPAD_COUNT; j++) {
|
||||
+ wl_list_init(&scratchpad_clients[j]);
|
||||
+ scratchpad_visible[j] = 1;
|
||||
+ }
|
||||
|
||||
xdg_shell = wlr_xdg_shell_create(dpy, 6);
|
||||
wl_signal_add(&xdg_shell->events.new_toplevel, &new_xdg_toplevel);
|
||||
diff --git a/simple_scratchpad.c b/simple_scratchpad.c
|
||||
new file mode 100644
|
||||
index 0000000..0e23ddd
|
||||
--- /dev/null
|
||||
+++ b/simple_scratchpad.c
|
||||
@@ -0,0 +1,85 @@
|
||||
+/* ************************************************************************** */
|
||||
+/* @@@ @@@@@@@@ */
|
||||
+/* @@@ @@@@@@@@@@ */
|
||||
+/* @@! @@! @@@@ */
|
||||
+/* !@! !@! @!@!@ */
|
||||
+/* simple_scratchpad.c @!! @!@ @! !@! */
|
||||
+/* !!! !@!!! !!! */
|
||||
+/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */
|
||||
+/* ::! :!: !:! */
|
||||
+/* Created: 2024/12/19 19:35:02 by jmakkone :: ::::::: :: */
|
||||
+/* Updated: 2026/05/20 23:56:35 by julmajustus : : : : : : */
|
||||
+/* */
|
||||
+/* ************************************************************************** */
|
||||
+
|
||||
+void
|
||||
+addscratchpad(const Arg *arg)
|
||||
+{
|
||||
+ Client *cc, *c = focustop(selmon);
|
||||
+
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+ /* Check if the added client is already a scratchpad client */
|
||||
+ for (int i = 0; i < SCRATCHPAD_COUNT; i++) {
|
||||
+ wl_list_for_each(cc, &scratchpad_clients[i], link_temp) {
|
||||
+ if (cc == c)
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ if (!c->isfloating) {
|
||||
+ setfloating(c, 1);
|
||||
+ }
|
||||
+ wl_list_insert(&scratchpad_clients[scratchpad_sel], &c->link_temp);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+togglescratchpad(const Arg *arg)
|
||||
+{
|
||||
+ Client *c;
|
||||
+ Monitor *m = selmon;
|
||||
+
|
||||
+ scratchpad_visible[scratchpad_sel] = !scratchpad_visible[scratchpad_sel];
|
||||
+ if (scratchpad_visible[scratchpad_sel]) {
|
||||
+ wl_list_for_each(c, &scratchpad_clients[scratchpad_sel], link_temp) {
|
||||
+ c->mon = m;
|
||||
+ c->tags = m->tagset[m->seltags];
|
||||
+ arrange(m);
|
||||
+ focusclient(c, 1);
|
||||
+ }
|
||||
+ } else {
|
||||
+ wl_list_for_each(c, &scratchpad_clients[scratchpad_sel], link_temp) {
|
||||
+ c->tags = 0;
|
||||
+ focusclient(focustop(m), 1);
|
||||
+ arrange(m);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+removescratchpad(const Arg *arg)
|
||||
+{
|
||||
+ Client *sc, *c = focustop(selmon);
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+ for (int i = 0; i < SCRATCHPAD_COUNT; i++) {
|
||||
+ /* Check if c is in scratchpad_clients */
|
||||
+ wl_list_for_each(sc, &scratchpad_clients[i], link_temp) {
|
||||
+ if (sc == c) {
|
||||
+ wl_list_remove(&c->link_temp);
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+setscratchpad(const Arg *arg)
|
||||
+{
|
||||
+ int idx = arg->i;
|
||||
+
|
||||
+ if (idx < 0)
|
||||
+ idx = 0;
|
||||
+ else if (idx >= SCRATCHPAD_COUNT)
|
||||
+ idx = SCRATCHPAD_COUNT - 1;
|
||||
+ scratchpad_sel = idx;
|
||||
+}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@@ -1,219 +0,0 @@
|
||||
From 94e649317328c7af091516fe3441ea80a814d1e4 Mon Sep 17 00:00:00 2001
|
||||
From: A Frederick Christensen <dwl@ivories.org>
|
||||
Date: Thu, 26 Feb 2026 17:18:17 -0600
|
||||
Subject: [PATCH] Apply simple_scratchpad patch
|
||||
|
||||
---
|
||||
config.def.h | 4 ++-
|
||||
dwl.c | 34 +++++++++++++++++++++--
|
||||
simple_scratchpad.c | 68 +++++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 103 insertions(+), 3 deletions(-)
|
||||
create mode 100644 simple_scratchpad.c
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 8a6eda0..bd6cb40 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -132,6 +132,9 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_Return, zoom, {0} },
|
||||
{ MODKEY, XKB_KEY_Tab, view, {0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_c, killclient, {0} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_z, addscratchpad, {0} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_z, togglescratchpad, {0} },
|
||||
+ { MODKEY, XKB_KEY_z, removescratchpad, {0} },
|
||||
{ MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
|
||||
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
|
||||
@@ -154,7 +157,6 @@ static const Key keys[] = {
|
||||
TAGKEYS( XKB_KEY_8, XKB_KEY_asterisk, 7),
|
||||
TAGKEYS( XKB_KEY_9, XKB_KEY_parenleft, 8),
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_q, quit, {0} },
|
||||
-
|
||||
/* Ctrl-Alt-Backspace and Ctrl-Alt-Fx used to be handled by X server */
|
||||
{ WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_Terminate_Server, quit, {0} },
|
||||
/* Ctrl-Alt-Fx is used to switch to another VT, if you don't know what a VT is
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 8a9715d..6ae7707 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -141,6 +141,7 @@ typedef struct {
|
||||
uint32_t tags;
|
||||
int isfloating, isurgent, isfullscreen;
|
||||
uint32_t resize; /* configure serial of a pending resize */
|
||||
+ struct wl_list link_temp;
|
||||
} Client;
|
||||
|
||||
typedef struct {
|
||||
@@ -242,6 +243,7 @@ typedef struct {
|
||||
} SessionLock;
|
||||
|
||||
/* function declarations */
|
||||
+static void addscratchpad(const Arg *arg);
|
||||
static void applybounds(Client *c, struct wlr_box *bbox);
|
||||
static void applyrules(Client *c);
|
||||
static void arrange(Monitor *m);
|
||||
@@ -316,6 +318,7 @@ static void printstatus(void);
|
||||
static void powermgrsetmode(struct wl_listener *listener, void *data);
|
||||
static void quit(const Arg *arg);
|
||||
static void rendermon(struct wl_listener *listener, void *data);
|
||||
+static void removescratchpad(const Arg *arg);
|
||||
static void requestdecorationmode(struct wl_listener *listener, void *data);
|
||||
static void requeststartdrag(struct wl_listener *listener, void *data);
|
||||
static void requestmonstate(struct wl_listener *listener, void *data);
|
||||
@@ -338,6 +341,7 @@ static void tagmon(const Arg *arg);
|
||||
static void tile(Monitor *m);
|
||||
static void togglefloating(const Arg *arg);
|
||||
static void togglefullscreen(const Arg *arg);
|
||||
+static void togglescratchpad(const Arg *arg);
|
||||
static void toggletag(const Arg *arg);
|
||||
static void toggleview(const Arg *arg);
|
||||
static void unlocksession(struct wl_listener *listener, void *data);
|
||||
@@ -408,6 +412,9 @@ static struct wlr_box sgeom;
|
||||
static struct wl_list mons;
|
||||
static Monitor *selmon;
|
||||
|
||||
+static struct wl_list scratchpad_clients;
|
||||
+static int scratchpad_visible = 1;
|
||||
+
|
||||
/* global event handlers */
|
||||
static struct wl_listener cursor_axis = {.notify = axisnotify};
|
||||
static struct wl_listener cursor_button = {.notify = buttonpress};
|
||||
@@ -457,6 +464,8 @@ static struct wlr_xwayland *xwayland;
|
||||
/* attempt to encapsulate suck into one file */
|
||||
#include "client.h"
|
||||
|
||||
+#include "simple_scratchpad.c"
|
||||
+
|
||||
/* function implementations */
|
||||
void
|
||||
applybounds(Client *c, struct wlr_box *bbox)
|
||||
@@ -1330,10 +1339,20 @@ void
|
||||
destroynotify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
/* Called when the xdg_toplevel is destroyed. */
|
||||
- Client *c = wl_container_of(listener, c, destroy);
|
||||
+ Client *sc, *c = wl_container_of(listener, c, destroy);
|
||||
wl_list_remove(&c->destroy.link);
|
||||
wl_list_remove(&c->set_title.link);
|
||||
wl_list_remove(&c->fullscreen.link);
|
||||
+ /* Check if destroyed client was part of scratchpad_clients
|
||||
+ * and clean it from the list if so. */
|
||||
+ if (c && wl_list_length(&scratchpad_clients) > 0) {
|
||||
+ wl_list_for_each(sc, &scratchpad_clients, link_temp) {
|
||||
+ if (sc == c) {
|
||||
+ wl_list_remove(&c->link_temp);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
#ifdef XWAYLAND
|
||||
if (c->type != XDGShell) {
|
||||
wl_list_remove(&c->activate.link);
|
||||
@@ -2335,11 +2354,21 @@ setcursorshape(struct wl_listener *listener, void *data)
|
||||
void
|
||||
setfloating(Client *c, int floating)
|
||||
{
|
||||
- Client *p = client_get_parent(c);
|
||||
+ Client *sc, *p = client_get_parent(c);
|
||||
c->isfloating = floating;
|
||||
/* If in floating layout do not change the client's layer */
|
||||
if (!c->mon || !client_surface(c)->mapped || !c->mon->lt[c->mon->sellt]->arrange)
|
||||
return;
|
||||
+ /* Check if unfloated client was part of scratchpad_clients
|
||||
+ * and remove it from scratchpad_clients list if so */
|
||||
+ if (!floating && wl_list_length(&scratchpad_clients) > 0) {
|
||||
+ wl_list_for_each(sc, &scratchpad_clients, link_temp) {
|
||||
+ if (sc == c) {
|
||||
+ wl_list_remove(&c->link_temp);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen ||
|
||||
(p && p->isfullscreen) ? LyrFS
|
||||
: c->isfloating ? LyrFloat : LyrTile]);
|
||||
@@ -2557,6 +2586,7 @@ setup(void)
|
||||
*/
|
||||
wl_list_init(&clients);
|
||||
wl_list_init(&fstack);
|
||||
+ wl_list_init(&scratchpad_clients);
|
||||
|
||||
xdg_shell = wlr_xdg_shell_create(dpy, 6);
|
||||
wl_signal_add(&xdg_shell->events.new_toplevel, &new_xdg_toplevel);
|
||||
diff --git a/simple_scratchpad.c b/simple_scratchpad.c
|
||||
new file mode 100644
|
||||
index 0000000..26d6b66
|
||||
--- /dev/null
|
||||
+++ b/simple_scratchpad.c
|
||||
@@ -0,0 +1,68 @@
|
||||
+/* ************************************************************************** */
|
||||
+/* */
|
||||
+/* ::: :::::::: */
|
||||
+/* simple_scratchpad.c :+: :+: :+: */
|
||||
+/* +:+ +:+ +:+ */
|
||||
+/* By: jmakkone <jmakkone@student.hive.fi> +#+ +:+ +#+ */
|
||||
+/* +#+#+#+#+#+ +#+ */
|
||||
+/* Created: 2024/12/19 19:35:02 by jmakkone #+# #+# */
|
||||
+/* Updated: 2025/01/04 13:35:50 by jmakkone ### ########.fr */
|
||||
+/* */
|
||||
+/* ************************************************************************** */
|
||||
+
|
||||
+void
|
||||
+addscratchpad(const Arg *arg)
|
||||
+{
|
||||
+ Client *cc, *c = focustop(selmon);
|
||||
+
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+ /* Check if the added client is already a scratchpad client */
|
||||
+ wl_list_for_each(cc, &scratchpad_clients, link_temp) {
|
||||
+ if (cc == c)
|
||||
+ return;
|
||||
+ }
|
||||
+ if (!c->isfloating) {
|
||||
+ setfloating(c, 1);
|
||||
+ }
|
||||
+ wl_list_insert(&scratchpad_clients, &c->link_temp);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+togglescratchpad(const Arg *arg)
|
||||
+{
|
||||
+ Client *c;
|
||||
+ Monitor *m = selmon;
|
||||
+
|
||||
+ scratchpad_visible = !scratchpad_visible;
|
||||
+ if (scratchpad_visible) {
|
||||
+ wl_list_for_each(c, &scratchpad_clients, link_temp) {
|
||||
+ c->mon = m;
|
||||
+ c->tags = m->tagset[m->seltags];
|
||||
+ arrange(m);
|
||||
+ focusclient(c, 1);
|
||||
+ }
|
||||
+ } else {
|
||||
+ wl_list_for_each(c, &scratchpad_clients, link_temp) {
|
||||
+ c->tags = 0;
|
||||
+ focusclient(focustop(m), 1);
|
||||
+ arrange(m);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+removescratchpad(const Arg *arg)
|
||||
+{
|
||||
+ Client *sc, *c = focustop(selmon);
|
||||
+
|
||||
+ if (c && wl_list_length(&scratchpad_clients) > 0) {
|
||||
+ /* Check if c is in scratchpad_clients */
|
||||
+ wl_list_for_each(sc, &scratchpad_clients, link_temp) {
|
||||
+ if (sc == c) {
|
||||
+ wl_list_remove(&c->link_temp);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
### Description
|
||||
Swapfocus adds a new function on dwl: a shortcut to change the focus to the last focused window. If the last focused window is in another tag, then the focus will change to that tag.
|
||||
Swapfocus adds a new function on dwl: a shortcut to change the focus to the last focused window.
|
||||
- If the last focused window is in another tag, then the focus will change to that tag.
|
||||
- Alternatively: edit the patch and uncomment and comment out the lines instructed to keep the swapfocus shortcut from changing to another tag.
|
||||
|
||||
### Download
|
||||
- [v0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/swapfocus/swapfocus.patch)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
From c4a9254ef63bbe1bae9ed525250e0b187668397f Mon Sep 17 00:00:00 2001
|
||||
From 364b9f20b830886b9c0e6539ddba2cc206a286eb Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Andr=C3=A9=20Desgualdo=20Pereira?= <desgua@gmail.com>
|
||||
Date: Fri, 1 May 2026 08:17:28 -0300
|
||||
Subject: [PATCH] swapfocus patch improvement
|
||||
Date: Thu, 21 May 2026 09:50:03 -0300
|
||||
Subject: [PATCH] swapfocus patch
|
||||
|
||||
---
|
||||
config.def.h | 1 +
|
||||
dwl.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 48 insertions(+)
|
||||
dwl.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 91 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 8a6eda0..23e502d 100644
|
||||
@@ -21,7 +21,7 @@ index 8a6eda0..23e502d 100644
|
||||
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 101a45f..5e78719 100644
|
||||
index 101a45f..c512323 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -332,6 +332,7 @@ static void setsel(struct wl_listener *listener, void *data);
|
||||
@@ -61,7 +61,7 @@ index 101a45f..5e78719 100644
|
||||
/* Put the new client atop the focus stack and select its monitor */
|
||||
if (c && !client_is_unmanaged(c)) {
|
||||
wl_list_remove(&c->flink);
|
||||
@@ -2679,6 +2688,44 @@ spawn(const Arg *arg)
|
||||
@@ -2679,6 +2688,87 @@ spawn(const Arg *arg)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,13 +93,56 @@ index 101a45f..5e78719 100644
|
||||
+ Arg a = {.ui = prevclient->tags};
|
||||
+ selmon = prevclient->mon;
|
||||
+ view(&a);
|
||||
+
|
||||
+ /* Comment out the 3 lines above and
|
||||
+ * uncommment the following lines
|
||||
+ * if changing tags isn't desired */
|
||||
+
|
||||
+// int current_tag_clients = 0;
|
||||
+// Client *tmp;
|
||||
+// wl_list_for_each(tmp, &clients, link) {
|
||||
+// /* Make sure it's on the current monitor, visible on the current tag, and mapped */
|
||||
+// if (tmp->mon == selmon && (tmp->tags & selmon->tagset[selmon->seltags]) && !client_is_unmanaged(tmp)) {
|
||||
+// current_tag_clients++;
|
||||
+// }
|
||||
+// }
|
||||
+//
|
||||
+// /* If there's more than 1 window here, mimic Mod+k instead of switching tags */
|
||||
+// if (current_tag_clients > 1) {
|
||||
+// Arg arg_focus = {.i = -1};
|
||||
+// focusstack(&arg_focus);
|
||||
+// }
|
||||
+
|
||||
+ /* End of not changing tags logic */
|
||||
+ } else {
|
||||
+ /* Tag IS visible: Just swap focus within the same view */
|
||||
+ focusclient(prevclient, 1);
|
||||
+ }
|
||||
+ } else {
|
||||
+ Arg a = {.ui = 0};
|
||||
+ selmon = prevclient->mon;
|
||||
+ view(&a);
|
||||
+
|
||||
+ /* Comment out the 3 lines above and
|
||||
+ * uncommment the following lines
|
||||
+ * if changing tags isn't desired */
|
||||
+
|
||||
+ /* use the following if changing tags isn't desired */
|
||||
+// int current_tag_clients = 0;
|
||||
+// Client *tmp;
|
||||
+// wl_list_for_each(tmp, &clients, link) {
|
||||
+// /* Make sure it's on the current monitor, visible on the current tag, and mapped */
|
||||
+// if (tmp->mon == selmon && (tmp->tags & selmon->tagset[selmon->seltags]) && !client_is_unmanaged(tmp)) {
|
||||
+// current_tag_clients++;
|
||||
+// }
|
||||
+// }
|
||||
+//
|
||||
+// /* If there's more than 1 window here, mimic Mod+k instead of switching tags */
|
||||
+// if (current_tag_clients > 1) {
|
||||
+// Arg arg_focus = {.i = -1};
|
||||
+// focusstack(&arg_focus);
|
||||
+// }
|
||||
+ /* end of not changing tags logic */
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
|
||||
@@ -8,13 +8,19 @@ KNOWN BUGS:
|
||||
- [git branch](https://codeberg.org/fauxmight/dwl/src/branch/touch-input)
|
||||
- [touch-input-wlroots-next-f4249db.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/touch-input/touch-input-wlroots-next-f4249db.patch)
|
||||
- [touch-input-0.8.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/touch-input/touch-input-0.8.patch)
|
||||
- [touch-input-0.8-osu-ver.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/touch-input/touch-input-0.8-osu-ver.patch)
|
||||
|
||||
### Authors
|
||||
#### Current
|
||||
- [fauxmight](https://codeberg.org/fauxmight)
|
||||
- [6z7y](https://codeberg.org/6z7y) -- maintaining `osu!` version of the `touch-input` patch
|
||||
#### Historic
|
||||
- [minego](https://codeberg.org/minego)
|
||||
- [Unprex](https://github.com/Unprex)
|
||||
|
||||
|
||||
### Changelog
|
||||
- 2026-06-15 Add support for osu! fullscreen touch input (fix cursor stuck issue)
|
||||
- 2026-02-26 Update patch for dwl v0.8 and dwl wlroots-next branch commit f4249db
|
||||
- 2025-01-01 @fauxmight took over maintenance. Previous maintainer @minego notes [lack of available time](https://codeberg.org/dwl/dwl-patches/pulls/102#issuecomment-2557944)
|
||||
- 2024-02-11 Corrected issue where motion events where not sending notifications for unfocused clients such as an on screen keyboard
|
||||
|
||||
+279
@@ -0,0 +1,279 @@
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 44f3ad9..977f2c8 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <wlr/types/wlr_data_device.h>
|
||||
#include <wlr/types/wlr_drm.h>
|
||||
#include <wlr/types/wlr_export_dmabuf_v1.h>
|
||||
+#include <wlr/types/wlr_ext_data_control_v1.h>
|
||||
#include <wlr/types/wlr_fractional_scale_v1.h>
|
||||
#include <wlr/types/wlr_gamma_control_v1.h>
|
||||
#include <wlr/types/wlr_idle_inhibit_v1.h>
|
||||
@@ -51,6 +52,7 @@
|
||||
#include <wlr/types/wlr_session_lock_v1.h>
|
||||
#include <wlr/types/wlr_single_pixel_buffer_v1.h>
|
||||
#include <wlr/types/wlr_subcompositor.h>
|
||||
+#include <wlr/types/wlr_touch.h>
|
||||
#include <wlr/types/wlr_viewporter.h>
|
||||
#include <wlr/types/wlr_virtual_keyboard_v1.h>
|
||||
#include <wlr/types/wlr_virtual_pointer_v1.h>
|
||||
@@ -161,6 +163,12 @@ typedef struct {
|
||||
struct wl_listener destroy;
|
||||
} KeyboardGroup;
|
||||
|
||||
+typedef struct TouchGroup {
|
||||
+ struct wl_list link;
|
||||
+ struct wlr_touch *touch;
|
||||
+ Monitor *m;
|
||||
+} TouchGroup;
|
||||
+
|
||||
typedef struct {
|
||||
/* Must keep this field first */
|
||||
unsigned int type; /* LayerShell */
|
||||
@@ -269,6 +277,7 @@ static void createpointer(struct wlr_pointer *pointer);
|
||||
static void createpointerconstraint(struct wl_listener *listener, void *data);
|
||||
static void createpopup(struct wl_listener *listener, void *data);
|
||||
static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint);
|
||||
+static void createtouch(struct wlr_touch *touch);
|
||||
static void cursorframe(struct wl_listener *listener, void *data);
|
||||
static void cursorwarptohint(void);
|
||||
static void destroydecoration(struct wl_listener *listener, void *data);
|
||||
@@ -338,6 +347,10 @@ static void togglefloating(const Arg *arg);
|
||||
static void togglefullscreen(const Arg *arg);
|
||||
static void toggletag(const Arg *arg);
|
||||
static void toggleview(const Arg *arg);
|
||||
+static void touchdown(struct wl_listener *listener, void *data);
|
||||
+static void touchup(struct wl_listener *listener, void *data);
|
||||
+static void touchframe(struct wl_listener *listener, void *data);
|
||||
+static void touchmotion(struct wl_listener *listener, void *data);
|
||||
static void unlocksession(struct wl_listener *listener, void *data);
|
||||
static void unmaplayersurfacenotify(struct wl_listener *listener, void *data);
|
||||
static void unmapnotify(struct wl_listener *listener, void *data);
|
||||
@@ -405,6 +418,7 @@ static struct wlr_output_layout *output_layout;
|
||||
static struct wlr_box sgeom;
|
||||
static struct wl_list mons;
|
||||
static Monitor *selmon;
|
||||
+static struct wl_list touches;
|
||||
|
||||
/* global event handlers */
|
||||
static struct wl_listener cursor_axis = {.notify = axisnotify};
|
||||
@@ -434,6 +448,10 @@ static struct wl_listener request_set_sel = {.notify = setsel};
|
||||
static struct wl_listener request_set_cursor_shape = {.notify = setcursorshape};
|
||||
static struct wl_listener request_start_drag = {.notify = requeststartdrag};
|
||||
static struct wl_listener start_drag = {.notify = startdrag};
|
||||
+static struct wl_listener touch_down = {.notify = touchdown};
|
||||
+static struct wl_listener touch_frame = {.notify = touchframe};
|
||||
+static struct wl_listener touch_motion = {.notify = touchmotion};
|
||||
+static struct wl_listener touch_up = {.notify = touchup};
|
||||
static struct wl_listener new_session_lock = {.notify = locksession};
|
||||
|
||||
#ifdef XWAYLAND
|
||||
@@ -585,7 +603,7 @@ arrangelayers(Monitor *m)
|
||||
arrange(m);
|
||||
}
|
||||
|
||||
- /* Arrange non-exlusive surfaces from top->bottom */
|
||||
+ /* Arrange non-exclusive surfaces from top->bottom */
|
||||
for (i = 3; i >= 0; i--)
|
||||
arrangelayer(m, &m->layers[i], &usable_area, 0);
|
||||
|
||||
@@ -781,6 +799,10 @@ cleanuplisteners(void)
|
||||
wl_list_remove(&request_set_cursor_shape.link);
|
||||
wl_list_remove(&request_start_drag.link);
|
||||
wl_list_remove(&start_drag.link);
|
||||
+ wl_list_remove(&touch_down.link);
|
||||
+ wl_list_remove(&touch_frame.link);
|
||||
+ wl_list_remove(&touch_motion.link);
|
||||
+ wl_list_remove(&touch_up.link);
|
||||
wl_list_remove(&new_session_lock.link);
|
||||
#ifdef XWAYLAND
|
||||
wl_list_remove(&new_xwayland_surface.link);
|
||||
@@ -1199,6 +1221,16 @@ createpopup(struct wl_listener *listener, void *data)
|
||||
LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup);
|
||||
}
|
||||
|
||||
+void
|
||||
+createtouch(struct wlr_touch *wlr_touch)
|
||||
+{
|
||||
+ TouchGroup *touch = ecalloc(1, sizeof(TouchGroup));
|
||||
+
|
||||
+ touch->touch = wlr_touch;
|
||||
+ wl_list_insert(&touches, &touch->link);
|
||||
+ wlr_cursor_attach_input_device(cursor, &wlr_touch->base);
|
||||
+}
|
||||
+
|
||||
void
|
||||
cursorconstrain(struct wlr_pointer_constraint_v1 *constraint)
|
||||
{
|
||||
@@ -1590,6 +1622,9 @@ inputdevice(struct wl_listener *listener, void *data)
|
||||
case WLR_INPUT_DEVICE_POINTER:
|
||||
createpointer(wlr_pointer_from_input_device(device));
|
||||
break;
|
||||
+ case WLR_INPUT_DEVICE_TOUCH:
|
||||
+ createtouch(wlr_touch_from_input_device(device));
|
||||
+ break;
|
||||
default:
|
||||
/* TODO handle other input device types */
|
||||
break;
|
||||
@@ -1602,6 +1637,8 @@ inputdevice(struct wl_listener *listener, void *data)
|
||||
caps = WL_SEAT_CAPABILITY_POINTER;
|
||||
if (!wl_list_empty(&kb_group->wlr_group->devices))
|
||||
caps |= WL_SEAT_CAPABILITY_KEYBOARD;
|
||||
+ if (!wl_list_empty(&touches))
|
||||
+ caps |= WL_SEAT_CAPABILITY_TOUCH;
|
||||
wlr_seat_set_capabilities(seat, caps);
|
||||
}
|
||||
|
||||
@@ -2133,7 +2170,7 @@ powermgrsetmode(struct wl_listener *listener, void *data)
|
||||
if (!m)
|
||||
return;
|
||||
|
||||
- m->gamma_lut_changed = 1; /* Reapply gamma LUT when re-enabling the ouput */
|
||||
+ m->gamma_lut_changed = 1; /* Reapply gamma LUT when re-enabling the output */
|
||||
wlr_output_state_set_enabled(&state, event->mode);
|
||||
wlr_output_commit_state(m->wlr_output, &state);
|
||||
|
||||
@@ -2455,7 +2492,7 @@ setup(void)
|
||||
wlr_log_init(log_level, NULL);
|
||||
|
||||
/* The Wayland display is managed by libwayland. It handles accepting
|
||||
- * clients from the Unix socket, manging Wayland globals, and so on. */
|
||||
+ * clients from the Unix socket, managing Wayland globals, and so on. */
|
||||
dpy = wl_display_create();
|
||||
event_loop = wl_display_get_event_loop(dpy);
|
||||
|
||||
@@ -2518,6 +2555,7 @@ setup(void)
|
||||
wlr_export_dmabuf_manager_v1_create(dpy);
|
||||
wlr_screencopy_manager_v1_create(dpy);
|
||||
wlr_data_control_manager_v1_create(dpy);
|
||||
+ wlr_ext_data_control_manager_v1_create(dpy, 1);
|
||||
wlr_primary_selection_v1_device_manager_create(dpy);
|
||||
wlr_viewporter_create(dpy);
|
||||
wlr_single_pixel_buffer_manager_v1_create(dpy);
|
||||
@@ -2615,6 +2653,13 @@ setup(void)
|
||||
wl_signal_add(&cursor->events.axis, &cursor_axis);
|
||||
wl_signal_add(&cursor->events.frame, &cursor_frame);
|
||||
|
||||
+ wl_list_init(&touches);
|
||||
+
|
||||
+ wl_signal_add(&cursor->events.touch_down, &touch_down);
|
||||
+ wl_signal_add(&cursor->events.touch_frame, &touch_frame);
|
||||
+ wl_signal_add(&cursor->events.touch_motion, &touch_motion);
|
||||
+ wl_signal_add(&cursor->events.touch_up, &touch_up);
|
||||
+
|
||||
cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1);
|
||||
wl_signal_add(&cursor_shape_mgr->events.request_set_shape, &request_set_cursor_shape);
|
||||
|
||||
@@ -2787,6 +2832,111 @@ toggleview(const Arg *arg)
|
||||
printstatus();
|
||||
}
|
||||
|
||||
+void
|
||||
+touchdown(struct wl_listener *listener, void *data)
|
||||
+{
|
||||
+ struct wlr_touch_down_event *event = data;
|
||||
+ double lx, ly;
|
||||
+ double sx, sy;
|
||||
+ struct wlr_surface *surface;
|
||||
+ Client *c = NULL;
|
||||
+ Monitor *m;
|
||||
+
|
||||
+ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
||||
+
|
||||
+ // Map the input to the appropriate output
|
||||
+ wl_list_for_each(m, &mons, link) {
|
||||
+ if (m == NULL || m->wlr_output == NULL)
|
||||
+ continue;
|
||||
+ if (event->touch->output_name != NULL &&
|
||||
+ 0 != strcmp(event->touch->output_name, m->wlr_output->name))
|
||||
+ continue;
|
||||
+ wlr_cursor_map_input_to_output(cursor, &event->touch->base, m->wlr_output);
|
||||
+ }
|
||||
+
|
||||
+ wlr_cursor_absolute_to_layout_coords(cursor, &event->touch->base,
|
||||
+ event->x, event->y, &lx, &ly);
|
||||
+
|
||||
+ /* Find the client under the touch point */
|
||||
+ xytonode(lx, ly, &surface, &c, NULL, &sx, &sy);
|
||||
+ if (sloppyfocus && c)
|
||||
+ focusclient(c, 0);
|
||||
+
|
||||
+ // Send touch event to client (if any)
|
||||
+ if (surface != NULL) {
|
||||
+ wlr_seat_touch_notify_down(seat, surface, event->time_msec,
|
||||
+ event->touch_id, sx, sy);
|
||||
+ }
|
||||
+
|
||||
+ // ALWAYS move cursor and send click - no conditions!
|
||||
+ wlr_cursor_warp_closest(cursor, NULL, lx, ly);
|
||||
+ motionnotify(0, NULL, 0, 0, 0, 0);
|
||||
+
|
||||
+ wlr_seat_pointer_notify_button(seat, event->time_msec,
|
||||
+ BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED);
|
||||
+ wlr_seat_pointer_notify_frame(seat);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+touchup(struct wl_listener *listener, void *data)
|
||||
+{
|
||||
+ struct wlr_touch_up_event *event = data;
|
||||
+
|
||||
+ if (!wlr_seat_touch_get_point(seat, event->touch_id))
|
||||
+ return;
|
||||
+
|
||||
+ wlr_seat_touch_notify_up(seat, event->time_msec, event->touch_id);
|
||||
+
|
||||
+ // Always send click release
|
||||
+ wlr_seat_pointer_notify_button(seat, event->time_msec,
|
||||
+ BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED);
|
||||
+ wlr_seat_pointer_notify_frame(seat);
|
||||
+
|
||||
+ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+touchframe(struct wl_listener *listener, void *data)
|
||||
+{
|
||||
+ wlr_seat_touch_notify_frame(seat);
|
||||
+ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+touchmotion(struct wl_listener *listener, void *data)
|
||||
+{
|
||||
+ struct wlr_touch_motion_event *event = data;
|
||||
+ double lx, ly;
|
||||
+ double sx, sy;
|
||||
+ struct wlr_surface *surface;
|
||||
+ Client *c = NULL;
|
||||
+
|
||||
+ if (!wlr_seat_touch_get_point(seat, event->touch_id)) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ wlr_cursor_absolute_to_layout_coords(cursor, &event->touch->base, event->x, event->y, &lx, &ly);
|
||||
+ wlr_cursor_warp_closest(cursor, NULL, lx, ly);
|
||||
+ motionnotify(0, NULL, 0, 0, 0, 0);
|
||||
+ wlr_seat_pointer_notify_frame(seat);
|
||||
+
|
||||
+ xytonode(lx, ly, &surface, &c, NULL, &sx, &sy);
|
||||
+
|
||||
+ if (c != NULL && surface != NULL) {
|
||||
+ if (sloppyfocus)
|
||||
+ focusclient(c, 0);
|
||||
+ wlr_seat_touch_point_focus(seat, surface, event->time_msec, event->touch_id, sx, sy);
|
||||
+ } else {
|
||||
+ if (sloppyfocus)
|
||||
+ focusclient(NULL, 0);
|
||||
+ wlr_seat_touch_point_clear_focus(seat, event->time_msec, event->touch_id);
|
||||
+ }
|
||||
+ wlr_seat_touch_notify_motion(seat, event->time_msec, event->touch_id, sx, sy);
|
||||
+
|
||||
+ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
||||
+}
|
||||
+
|
||||
+
|
||||
void
|
||||
unlocksession(struct wl_listener *listener, void *data)
|
||||
{
|
||||
@@ -9,8 +9,9 @@ This patch comes in **two versions**:
|
||||
- **`zerotag.patch`** - No dependencies.
|
||||
|
||||
### Download
|
||||
- [git branch](https://codeberg.org/6z7y/dwl-patches/raw/branch/main/patches/zerotag/zerotag.patch)
|
||||
- [git branch](https://codeberg.org/6z7y/dwl-patches/raw/branch/zerotag/patches/zerotag/zerotag.patch)
|
||||
- [main 2026-02-25](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/zerotag/zerotag.patch)
|
||||
|
||||
### Authors
|
||||
- [6z7y](https://codeberg.org/6z7y)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user