Compare commits

...

7 Commits

Author SHA1 Message Date
Dhruva Sambrani a44a71ab0f add gamepad-bindings patch 2026-07-18 23:04:54 +02:00
A Frederick Christensen c9f31f29ea simpleborders: Update for 0.8 and for wlroots-next-f4249db
Abandoned simpleborders patch updated by @fauxmight
2026-07-16 06:09:31 +02:00
Viktor Woloszczuk 8085c4759f inputdevicerules: update for v0.8 dwl
addresses issue #623
2026-07-12 20:19:16 +01:00
skeetamine 514ad37ea9 per-app-cast: prefix var with ext_ for compatibility with other patches 2026-07-02 17:43:32 +03:00
nshan651 fd64a18e6f namedscratchpads: update for v0.8 dwl. 2026-06-29 12:37:42 +02:00
julmajustus ba9c29477d fullscreen_adaptive_sync: Minor bug fixes
- Fixed missing (void) function type in the implementation
- Minor indentation fixes
2026-06-22 23:24:09 +03:00
julmajustus 706d6350cb btrtile: bug fixes and readability improvements
- Removed client old_geom caching for simplicity; fixes: https://codeberg.org/dwl/dwl-patches/issues/647
- Improved readability of the client sanitization loop inside btrtile()
- Removed fullscreened clients from the sanitization loop to retain their geometry
2026-06-22 23:17:56 +03:00
18 changed files with 1122 additions and 401 deletions
+30 -40
View File
@@ -1,24 +1,24 @@
From 1520d1f200ef0fb381683c1bcd58e553b52ac289 Mon Sep 17 00:00:00 2001 From 42e35a6a8a93f0e6d886ad69686c85c1d58536d6 Mon Sep 17 00:00:00 2001
From: julmajustus <julmajustus@tutanota.com> From: julmajustus <julmajustus@tutanota.com>
Date: Thu, 21 May 2026 00:42:07 +0300 Date: Mon, 22 Jun 2026 22:54:11 +0300
Subject: [PATCH] btrtile: Spring update pt2 Subject: [PATCH] btrtile: bug fixes and readability improvement
- Simplified the resizing logic to avoid full arrange calls from - Removed client old_geom caching for simplicity fixes: https://codeberg.org/dwl/dwl-patches/issues/647
motionnotify - Improved readability of the client sanitization loop inside btrtile function
- Minor intend fixes - Removed fullscreened client's from the sanitization loop to retain their geometry
--- ---
btrtile.c | 583 +++++++++++++++++++++++++++++++++++++++++++++++++++ btrtile.c | 575 +++++++++++++++++++++++++++++++++++++++++++++++++++
config.def.h | 12 ++ config.def.h | 12 ++
dwl.c | 152 +++++++++++--- dwl.c | 151 +++++++++++---
3 files changed, 720 insertions(+), 27 deletions(-) 3 files changed, 711 insertions(+), 27 deletions(-)
create mode 100644 btrtile.c create mode 100644 btrtile.c
diff --git a/btrtile.c b/btrtile.c diff --git a/btrtile.c b/btrtile.c
new file mode 100644 new file mode 100644
index 0000000..f05a30f index 0000000..24bf4d9
--- /dev/null --- /dev/null
+++ b/btrtile.c +++ b/btrtile.c
@@ -0,0 +1,583 @@ @@ -0,0 +1,575 @@
+/* ************************************************************************** */ +/* ************************************************************************** */
+/* @@@ @@@@@@@@ */ +/* @@@ @@@@@@@@ */
+/* @@@ @@@@@@@@@@ */ +/* @@@ @@@@@@@@@@ */
@@ -29,7 +29,7 @@ index 0000000..f05a30f
+/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */ +/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */
+/* ::! :!: !:! */ +/* ::! :!: !:! */
+/* Created: 2024/12/15 00:26:07 by julmajustus :: ::::::: :: */ +/* Created: 2024/12/15 00:26:07 by julmajustus :: ::::::: :: */
+/* Updated: 2026/05/20 22:38:02 by julmajustus : : : : : : */ +/* Updated: 2026/06/22 22:54:06 by julmajustus : : : : : : */
+/* */ +/* */
+/* ************************************************************************** */ +/* ************************************************************************** */
+ +
@@ -91,11 +91,7 @@ index 0000000..f05a30f
+ c = node->client; + c = node->client;
+ if (!c || !VISIBLEON(c, m) || c->isfloating || c->isfullscreen) + if (!c || !VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
+ return; + return;
+ if (area.x == c->old_geom.x && area.y == c->old_geom.y &&
+ area.width == c->old_geom.width && area.height == c->old_geom.height)
+ return;
+ resize(c, area, 0); + resize(c, area, 0);
+ c->old_geom = area;
+ return; + return;
+ } + }
+ +
@@ -175,12 +171,10 @@ index 0000000..f05a30f
+ if (!m) + if (!m)
+ return; + return;
+ +
+ /* Remove non tiled clients from tree. */ + /* Remove floating and moved clients */
+ wl_list_for_each(c, &clients, link) { + wl_list_for_each(c, &clients, link) {
+ if (c->mon == m && !c->isfloating && !c->isfullscreen) { + if (c->mon != m || c->isfloating)
+ } else {
+ remove_client(m, c); + remove_client(m, c);
+ }
+ } + }
+ +
+ /* If no client is found under cursor, fallback to focustop(m) */ + /* If no client is found under cursor, fallback to focustop(m) */
@@ -464,8 +458,6 @@ index 0000000..f05a30f
+ split_node->split_ratio = new_ratio; + split_node->split_ratio = new_ratio;
+ +
+ apply_layout(selmon, selmon->root, selmon->w, 1); + apply_layout(selmon, selmon->root, selmon->w, 1);
+ /* Skip the arrange when called from motionnotify; that path calls
+ * arrange itself after rate-limiting. */
+} +}
+ +
+void +void
@@ -641,7 +633,7 @@ index 8a6eda0..bc04e3f 100644
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1), TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2), TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
diff --git a/dwl.c b/dwl.c diff --git a/dwl.c b/dwl.c
index 44f3ad9..a121efc 100644 index 44f3ad9..2529e1f 100644
--- a/dwl.c --- a/dwl.c
+++ b/dwl.c +++ b/dwl.c
@@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
@@ -660,18 +652,16 @@ index 44f3ad9..a121efc 100644
typedef struct Monitor Monitor; typedef struct Monitor Monitor;
typedef struct { typedef struct {
/* Must keep this field first */ /* Must keep this field first */
@@ -137,8 +139,9 @@ typedef struct { @@ -137,7 +139,7 @@ typedef struct {
#endif #endif
unsigned int bw; unsigned int bw;
uint32_t tags; uint32_t tags;
- int isfloating, isurgent, isfullscreen; - int isfloating, isurgent, isfullscreen;
+ int isfloating, isurgent, isfullscreen, was_tiled; + int isfloating, isurgent, isfullscreen, was_tiled;
uint32_t resize; /* configure serial of a pending resize */ uint32_t resize; /* configure serial of a pending resize */
+ struct wlr_box old_geom;
} Client; } Client;
typedef struct { @@ -205,6 +207,7 @@ struct Monitor {
@@ -205,6 +208,7 @@ struct Monitor {
int nmaster; int nmaster;
char ltsymbol[16]; char ltsymbol[16];
int asleep; int asleep;
@@ -679,7 +669,7 @@ index 44f3ad9..a121efc 100644
}; };
typedef struct { typedef struct {
@@ -247,6 +251,7 @@ static void arrangelayer(Monitor *m, struct wl_list *list, @@ -247,6 +250,7 @@ static void arrangelayer(Monitor *m, struct wl_list *list,
struct wlr_box *usable_area, int exclusive); struct wlr_box *usable_area, int exclusive);
static void arrangelayers(Monitor *m); static void arrangelayers(Monitor *m);
static void axisnotify(struct wl_listener *listener, void *data); static void axisnotify(struct wl_listener *listener, void *data);
@@ -687,7 +677,7 @@ index 44f3ad9..a121efc 100644
static void buttonpress(struct wl_listener *listener, void *data); static void buttonpress(struct wl_listener *listener, void *data);
static void chvt(const Arg *arg); static void chvt(const Arg *arg);
static void checkidleinhibitor(struct wlr_surface *exclude); static void checkidleinhibitor(struct wlr_surface *exclude);
@@ -329,6 +334,9 @@ static void setmon(Client *c, Monitor *m, uint32_t newtags); @@ -329,6 +333,9 @@ static void setmon(Client *c, Monitor *m, uint32_t newtags);
static void setpsel(struct wl_listener *listener, void *data); static void setpsel(struct wl_listener *listener, void *data);
static void setsel(struct wl_listener *listener, void *data); static void setsel(struct wl_listener *listener, void *data);
static void setup(void); static void setup(void);
@@ -697,7 +687,7 @@ index 44f3ad9..a121efc 100644
static void spawn(const Arg *arg); static void spawn(const Arg *arg);
static void startdrag(struct wl_listener *listener, void *data); static void startdrag(struct wl_listener *listener, void *data);
static void tag(const Arg *arg); static void tag(const Arg *arg);
@@ -454,6 +462,7 @@ static struct wlr_xwayland *xwayland; @@ -454,6 +461,7 @@ static struct wlr_xwayland *xwayland;
/* attempt to encapsulate suck into one file */ /* attempt to encapsulate suck into one file */
#include "client.h" #include "client.h"
@@ -705,7 +695,7 @@ index 44f3ad9..a121efc 100644
/* function implementations */ /* function implementations */
void void
@@ -624,7 +633,7 @@ buttonpress(struct wl_listener *listener, void *data) @@ -624,7 +632,7 @@ buttonpress(struct wl_listener *listener, void *data)
struct wlr_pointer_button_event *event = data; struct wlr_pointer_button_event *event = data;
struct wlr_keyboard *keyboard; struct wlr_keyboard *keyboard;
uint32_t mods; uint32_t mods;
@@ -714,7 +704,7 @@ index 44f3ad9..a121efc 100644
const Button *b; const Button *b;
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
@@ -645,7 +654,7 @@ buttonpress(struct wl_listener *listener, void *data) @@ -645,7 +653,7 @@ buttonpress(struct wl_listener *listener, void *data)
mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
for (b = buttons; b < END(buttons); b++) { for (b = buttons; b < END(buttons); b++) {
if (CLEANMASK(mods) == CLEANMASK(b->mod) && if (CLEANMASK(mods) == CLEANMASK(b->mod) &&
@@ -723,7 +713,7 @@ index 44f3ad9..a121efc 100644
b->func(&b->arg); b->func(&b->arg);
return; return;
} }
@@ -655,6 +664,21 @@ buttonpress(struct wl_listener *listener, void *data) @@ -655,6 +663,21 @@ buttonpress(struct wl_listener *listener, void *data)
/* If you released any buttons, we exit interactive move/resize mode. */ /* If you released any buttons, we exit interactive move/resize mode. */
/* TODO: should reset to the pointer focus's current setcursor */ /* TODO: should reset to the pointer focus's current setcursor */
if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) { if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
@@ -745,7 +735,7 @@ index 44f3ad9..a121efc 100644
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
cursor_mode = CurNormal; cursor_mode = CurNormal;
/* Drop the window off on its new monitor */ /* Drop the window off on its new monitor */
@@ -746,6 +770,7 @@ cleanupmon(struct wl_listener *listener, void *data) @@ -746,6 +769,7 @@ cleanupmon(struct wl_listener *listener, void *data)
wlr_output_layout_remove(output_layout, m->wlr_output); wlr_output_layout_remove(output_layout, m->wlr_output);
wlr_scene_output_destroy(m->scene_output); wlr_scene_output_destroy(m->scene_output);
@@ -753,7 +743,7 @@ index 44f3ad9..a121efc 100644
closemon(m); closemon(m);
wlr_scene_node_destroy(&m->fullscreen_bg->node); wlr_scene_node_destroy(&m->fullscreen_bg->node);
free(m); free(m);
@@ -1090,6 +1115,7 @@ createmon(struct wl_listener *listener, void *data) @@ -1090,6 +1114,7 @@ createmon(struct wl_listener *listener, void *data)
wl_list_insert(&mons, &m->link); wl_list_insert(&mons, &m->link);
printstatus(); printstatus();
@@ -761,7 +751,7 @@ index 44f3ad9..a121efc 100644
/* The xdg-protocol specifies: /* The xdg-protocol specifies:
* *
@@ -1329,9 +1355,17 @@ destroynotify(struct wl_listener *listener, void *data) @@ -1329,9 +1354,17 @@ destroynotify(struct wl_listener *listener, void *data)
{ {
/* Called when the xdg_toplevel is destroyed. */ /* Called when the xdg_toplevel is destroyed. */
Client *c = wl_container_of(listener, c, destroy); Client *c = wl_container_of(listener, c, destroy);
@@ -779,7 +769,7 @@ index 44f3ad9..a121efc 100644
#ifdef XWAYLAND #ifdef XWAYLAND
if (c->type != XDGShell) { if (c->type != XDGShell) {
wl_list_remove(&c->activate.link); wl_list_remove(&c->activate.link);
@@ -1862,7 +1896,8 @@ void @@ -1862,7 +1895,8 @@ void
motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy, motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy,
double dx_unaccel, double dy_unaccel) double dx_unaccel, double dy_unaccel)
{ {
@@ -789,7 +779,7 @@ index 44f3ad9..a121efc 100644
Client *c = NULL, *w = NULL; Client *c = NULL, *w = NULL;
LayerSurface *l = NULL; LayerSurface *l = NULL;
struct wlr_surface *surface = NULL; struct wlr_surface *surface = NULL;
@@ -1916,18 +1951,55 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d @@ -1916,18 +1950,55 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
/* Update drag icon's position */ /* Update drag icon's position */
wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y)); wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y));
@@ -852,7 +842,7 @@ index 44f3ad9..a121efc 100644
/* If there's no client surface under the cursor, set the cursor image to a /* If there's no client surface under the cursor, set the cursor image to a
* default. This is what makes the cursor image appear when you move it * default. This is what makes the cursor image appear when you move it
* off of a client or over its border. */ * off of a client or over its border. */
@@ -1961,22 +2033,40 @@ moveresize(const Arg *arg) @@ -1961,22 +2032,40 @@ moveresize(const Arg *arg)
if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen) if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
return; return;
@@ -909,7 +899,7 @@ index 44f3ad9..a121efc 100644
} }
} }
@@ -2826,6 +2916,14 @@ unmapnotify(struct wl_listener *listener, void *data) @@ -2826,6 +2915,14 @@ unmapnotify(struct wl_listener *listener, void *data)
focusclient(focustop(selmon), 1); focusclient(focustop(selmon), 1);
} }
} else { } else {
+30 -40
View File
@@ -1,24 +1,24 @@
From 618e3b70204520b6eb2c5040e072087ac0a3b3f7 Mon Sep 17 00:00:00 2001 From 04d7c04a0a88e381df788e1ec60398d956543f8b Mon Sep 17 00:00:00 2001
From: julmajustus <julmajustus@tutanota.com> From: julmajustus <julmajustus@tutanota.com>
Date: Thu, 21 May 2026 00:40:54 +0300 Date: Mon, 22 Jun 2026 22:52:57 +0300
Subject: [PATCH] btrtile: Spring update pt2 Subject: [PATCH] btrtile: bug fixes and readability improvement
- Simplified the resizing logic to avoid full arrange calls from - Removed client old_geom caching for simplicity fixes: https://codeberg.org/dwl/dwl-patches/issues/647
motionnotify - Improved readability of the client sanitization loop inside btrtile function
- Minor intend fixes - Removed fullscreened client's from the sanitization loop to retain their geometry
--- ---
btrtile.c | 564 +++++++++++++++++++++++++++++++++++++++++++++++++++ btrtile.c | 556 +++++++++++++++++++++++++++++++++++++++++++++++++++
config.def.h | 12 ++ config.def.h | 12 ++
dwl.c | 152 +++++++++++--- dwl.c | 151 +++++++++++---
3 files changed, 701 insertions(+), 27 deletions(-) 3 files changed, 692 insertions(+), 27 deletions(-)
create mode 100644 btrtile.c create mode 100644 btrtile.c
diff --git a/btrtile.c b/btrtile.c diff --git a/btrtile.c b/btrtile.c
new file mode 100644 new file mode 100644
index 0000000..357ffb9 index 0000000..6055871
--- /dev/null --- /dev/null
+++ b/btrtile.c +++ b/btrtile.c
@@ -0,0 +1,564 @@ @@ -0,0 +1,556 @@
+/* ************************************************************************** */ +/* ************************************************************************** */
+/* @@@ @@@@@@@@ */ +/* @@@ @@@@@@@@ */
+/* @@@ @@@@@@@@@@ */ +/* @@@ @@@@@@@@@@ */
@@ -29,7 +29,7 @@ index 0000000..357ffb9
+/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */ +/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */
+/* ::! :!: !:! */ +/* ::! :!: !:! */
+/* Created: 2024/12/15 00:26:07 by julmajustus :: ::::::: :: */ +/* Created: 2024/12/15 00:26:07 by julmajustus :: ::::::: :: */
+/* Updated: 2026/05/20 22:51:54 by julmajustus : : : : : : */ +/* Updated: 2026/06/22 22:52:52 by julmajustus : : : : : : */
+/* */ +/* */
+/* ************************************************************************** */ +/* ************************************************************************** */
+ +
@@ -84,11 +84,7 @@ index 0000000..357ffb9
+ c = node->client; + c = node->client;
+ if (!c || !VISIBLEON(c, m) || c->isfloating || c->isfullscreen) + if (!c || !VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
+ return; + return;
+ if (area.x == c->old_geom.x && area.y == c->old_geom.y &&
+ area.width == c->old_geom.width && area.height == c->old_geom.height)
+ return;
+ resize(c, area, 0); + resize(c, area, 0);
+ c->old_geom = area;
+ return; + return;
+ } + }
+ +
@@ -156,12 +152,10 @@ index 0000000..357ffb9
+ if (!m) + if (!m)
+ return; + return;
+ +
+ /* Remove non tiled clients from tree. */ + /* Remove floating and moved clients */
+ wl_list_for_each(c, &clients, link) { + wl_list_for_each(c, &clients, link) {
+ if (c->mon == m && !c->isfloating && !c->isfullscreen) { + if (c->mon != m || c->isfloating)
+ } else {
+ remove_client(m, c); + remove_client(m, c);
+ }
+ } + }
+ +
+ /* If no client is found under cursor, fallback to focustop(m) */ + /* If no client is found under cursor, fallback to focustop(m) */
@@ -445,8 +439,6 @@ index 0000000..357ffb9
+ split_node->split_ratio = new_ratio; + split_node->split_ratio = new_ratio;
+ +
+ apply_layout(selmon, selmon->root, selmon->w, 1); + apply_layout(selmon, selmon->root, selmon->w, 1);
+ /* Skip the arrange when called from motionnotify; that path calls
+ * arrange itself after rate-limiting. */
+} +}
+ +
+void +void
@@ -622,7 +614,7 @@ index 8a6eda0..bc04e3f 100644
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1), TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2), TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
diff --git a/dwl.c b/dwl.c diff --git a/dwl.c b/dwl.c
index 44f3ad9..a121efc 100644 index 44f3ad9..2529e1f 100644
--- a/dwl.c --- a/dwl.c
+++ b/dwl.c +++ b/dwl.c
@@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
@@ -641,18 +633,16 @@ index 44f3ad9..a121efc 100644
typedef struct Monitor Monitor; typedef struct Monitor Monitor;
typedef struct { typedef struct {
/* Must keep this field first */ /* Must keep this field first */
@@ -137,8 +139,9 @@ typedef struct { @@ -137,7 +139,7 @@ typedef struct {
#endif #endif
unsigned int bw; unsigned int bw;
uint32_t tags; uint32_t tags;
- int isfloating, isurgent, isfullscreen; - int isfloating, isurgent, isfullscreen;
+ int isfloating, isurgent, isfullscreen, was_tiled; + int isfloating, isurgent, isfullscreen, was_tiled;
uint32_t resize; /* configure serial of a pending resize */ uint32_t resize; /* configure serial of a pending resize */
+ struct wlr_box old_geom;
} Client; } Client;
typedef struct { @@ -205,6 +207,7 @@ struct Monitor {
@@ -205,6 +208,7 @@ struct Monitor {
int nmaster; int nmaster;
char ltsymbol[16]; char ltsymbol[16];
int asleep; int asleep;
@@ -660,7 +650,7 @@ index 44f3ad9..a121efc 100644
}; };
typedef struct { typedef struct {
@@ -247,6 +251,7 @@ static void arrangelayer(Monitor *m, struct wl_list *list, @@ -247,6 +250,7 @@ static void arrangelayer(Monitor *m, struct wl_list *list,
struct wlr_box *usable_area, int exclusive); struct wlr_box *usable_area, int exclusive);
static void arrangelayers(Monitor *m); static void arrangelayers(Monitor *m);
static void axisnotify(struct wl_listener *listener, void *data); static void axisnotify(struct wl_listener *listener, void *data);
@@ -668,7 +658,7 @@ index 44f3ad9..a121efc 100644
static void buttonpress(struct wl_listener *listener, void *data); static void buttonpress(struct wl_listener *listener, void *data);
static void chvt(const Arg *arg); static void chvt(const Arg *arg);
static void checkidleinhibitor(struct wlr_surface *exclude); static void checkidleinhibitor(struct wlr_surface *exclude);
@@ -329,6 +334,9 @@ static void setmon(Client *c, Monitor *m, uint32_t newtags); @@ -329,6 +333,9 @@ static void setmon(Client *c, Monitor *m, uint32_t newtags);
static void setpsel(struct wl_listener *listener, void *data); static void setpsel(struct wl_listener *listener, void *data);
static void setsel(struct wl_listener *listener, void *data); static void setsel(struct wl_listener *listener, void *data);
static void setup(void); static void setup(void);
@@ -678,7 +668,7 @@ index 44f3ad9..a121efc 100644
static void spawn(const Arg *arg); static void spawn(const Arg *arg);
static void startdrag(struct wl_listener *listener, void *data); static void startdrag(struct wl_listener *listener, void *data);
static void tag(const Arg *arg); static void tag(const Arg *arg);
@@ -454,6 +462,7 @@ static struct wlr_xwayland *xwayland; @@ -454,6 +461,7 @@ static struct wlr_xwayland *xwayland;
/* attempt to encapsulate suck into one file */ /* attempt to encapsulate suck into one file */
#include "client.h" #include "client.h"
@@ -686,7 +676,7 @@ index 44f3ad9..a121efc 100644
/* function implementations */ /* function implementations */
void void
@@ -624,7 +633,7 @@ buttonpress(struct wl_listener *listener, void *data) @@ -624,7 +632,7 @@ buttonpress(struct wl_listener *listener, void *data)
struct wlr_pointer_button_event *event = data; struct wlr_pointer_button_event *event = data;
struct wlr_keyboard *keyboard; struct wlr_keyboard *keyboard;
uint32_t mods; uint32_t mods;
@@ -695,7 +685,7 @@ index 44f3ad9..a121efc 100644
const Button *b; const Button *b;
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
@@ -645,7 +654,7 @@ buttonpress(struct wl_listener *listener, void *data) @@ -645,7 +653,7 @@ buttonpress(struct wl_listener *listener, void *data)
mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
for (b = buttons; b < END(buttons); b++) { for (b = buttons; b < END(buttons); b++) {
if (CLEANMASK(mods) == CLEANMASK(b->mod) && if (CLEANMASK(mods) == CLEANMASK(b->mod) &&
@@ -704,7 +694,7 @@ index 44f3ad9..a121efc 100644
b->func(&b->arg); b->func(&b->arg);
return; return;
} }
@@ -655,6 +664,21 @@ buttonpress(struct wl_listener *listener, void *data) @@ -655,6 +663,21 @@ buttonpress(struct wl_listener *listener, void *data)
/* If you released any buttons, we exit interactive move/resize mode. */ /* If you released any buttons, we exit interactive move/resize mode. */
/* TODO: should reset to the pointer focus's current setcursor */ /* TODO: should reset to the pointer focus's current setcursor */
if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) { if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
@@ -726,7 +716,7 @@ index 44f3ad9..a121efc 100644
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
cursor_mode = CurNormal; cursor_mode = CurNormal;
/* Drop the window off on its new monitor */ /* Drop the window off on its new monitor */
@@ -746,6 +770,7 @@ cleanupmon(struct wl_listener *listener, void *data) @@ -746,6 +769,7 @@ cleanupmon(struct wl_listener *listener, void *data)
wlr_output_layout_remove(output_layout, m->wlr_output); wlr_output_layout_remove(output_layout, m->wlr_output);
wlr_scene_output_destroy(m->scene_output); wlr_scene_output_destroy(m->scene_output);
@@ -734,7 +724,7 @@ index 44f3ad9..a121efc 100644
closemon(m); closemon(m);
wlr_scene_node_destroy(&m->fullscreen_bg->node); wlr_scene_node_destroy(&m->fullscreen_bg->node);
free(m); free(m);
@@ -1090,6 +1115,7 @@ createmon(struct wl_listener *listener, void *data) @@ -1090,6 +1114,7 @@ createmon(struct wl_listener *listener, void *data)
wl_list_insert(&mons, &m->link); wl_list_insert(&mons, &m->link);
printstatus(); printstatus();
@@ -742,7 +732,7 @@ index 44f3ad9..a121efc 100644
/* The xdg-protocol specifies: /* The xdg-protocol specifies:
* *
@@ -1329,9 +1355,17 @@ destroynotify(struct wl_listener *listener, void *data) @@ -1329,9 +1354,17 @@ destroynotify(struct wl_listener *listener, void *data)
{ {
/* Called when the xdg_toplevel is destroyed. */ /* Called when the xdg_toplevel is destroyed. */
Client *c = wl_container_of(listener, c, destroy); Client *c = wl_container_of(listener, c, destroy);
@@ -760,7 +750,7 @@ index 44f3ad9..a121efc 100644
#ifdef XWAYLAND #ifdef XWAYLAND
if (c->type != XDGShell) { if (c->type != XDGShell) {
wl_list_remove(&c->activate.link); wl_list_remove(&c->activate.link);
@@ -1862,7 +1896,8 @@ void @@ -1862,7 +1895,8 @@ void
motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy, motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy,
double dx_unaccel, double dy_unaccel) double dx_unaccel, double dy_unaccel)
{ {
@@ -770,7 +760,7 @@ index 44f3ad9..a121efc 100644
Client *c = NULL, *w = NULL; Client *c = NULL, *w = NULL;
LayerSurface *l = NULL; LayerSurface *l = NULL;
struct wlr_surface *surface = NULL; struct wlr_surface *surface = NULL;
@@ -1916,18 +1951,55 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d @@ -1916,18 +1950,55 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
/* Update drag icon's position */ /* Update drag icon's position */
wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y)); wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y));
@@ -833,7 +823,7 @@ index 44f3ad9..a121efc 100644
/* If there's no client surface under the cursor, set the cursor image to a /* If there's no client surface under the cursor, set the cursor image to a
* default. This is what makes the cursor image appear when you move it * default. This is what makes the cursor image appear when you move it
* off of a client or over its border. */ * off of a client or over its border. */
@@ -1961,22 +2033,40 @@ moveresize(const Arg *arg) @@ -1961,22 +2032,40 @@ moveresize(const Arg *arg)
if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen) if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
return; return;
@@ -890,7 +880,7 @@ index 44f3ad9..a121efc 100644
} }
} }
@@ -2826,6 +2916,14 @@ unmapnotify(struct wl_listener *listener, void *data) @@ -2826,6 +2915,14 @@ unmapnotify(struct wl_listener *listener, void *data)
focusclient(focustop(selmon), 1); focusclient(focustop(selmon), 1);
} }
} else { } else {
@@ -1,24 +1,26 @@
From c11b1a8c93c27fad3782e9dbc1b094a4a7b78088 Mon Sep 17 00:00:00 2001 From efb796ce92e7212aa392141705c7322fedc45dba Mon Sep 17 00:00:00 2001
From: julmajustus <julmajustus@tutanota.com> From: julmajustus <julmajustus@tutanota.com>
Date: Thu, 21 May 2026 00:38:45 +0300 Date: Mon, 22 Jun 2026 22:46:19 +0300
Subject: [PATCH] btrtile: Spring update pt2 Subject: [PATCH] btrtile: bug fixes and readability improvement
- Simplified the resizing logic to avoid full arrange calls from - Removed client old_geom caching for simplicity fixes: https://codeberg.org/dwl/dwl-patches/issues/647
motionnotify - Improved readability of the client sanitization loop inside btrtile function
- Minor intend fixes - Removed fullscreened client's from the sanitization loop to retain simple_scratchpad: Spring update scratchpad V2
- Added support for multiple scratchpads their geometry
--- ---
btrtile.c | 583 +++++++++++++++++++++++++++++++++++++++++++++++++++ btrtile.c | 575 +++++++++++++++++++++++++++++++++++++++++++++++++++
config.def.h | 12 ++ config.def.h | 12 ++
dwl.c | 152 +++++++++++--- dwl.c | 151 +++++++++++---
3 files changed, 720 insertions(+), 27 deletions(-) 3 files changed, 711 insertions(+), 27 deletions(-)
create mode 100644 btrtile.c create mode 100644 btrtile.c
diff --git a/btrtile.c b/btrtile.c diff --git a/btrtile.c b/btrtile.c
new file mode 100644 new file mode 100644
index 0000000..f05a30f index 0000000..645b741
--- /dev/null --- /dev/null
+++ b/btrtile.c +++ b/btrtile.c
@@ -0,0 +1,583 @@ @@ -0,0 +1,575 @@
+/* ************************************************************************** */ +/* ************************************************************************** */
+/* @@@ @@@@@@@@ */ +/* @@@ @@@@@@@@ */
+/* @@@ @@@@@@@@@@ */ +/* @@@ @@@@@@@@@@ */
@@ -29,7 +31,7 @@ index 0000000..f05a30f
+/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */ +/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */
+/* ::! :!: !:! */ +/* ::! :!: !:! */
+/* Created: 2024/12/15 00:26:07 by julmajustus :: ::::::: :: */ +/* Created: 2024/12/15 00:26:07 by julmajustus :: ::::::: :: */
+/* Updated: 2026/05/20 22:38:02 by julmajustus : : : : : : */ +/* Updated: 2026/06/22 22:34:11 by julmajustus : : : : : : */
+/* */ +/* */
+/* ************************************************************************** */ +/* ************************************************************************** */
+ +
@@ -91,11 +93,7 @@ index 0000000..f05a30f
+ c = node->client; + c = node->client;
+ if (!c || !VISIBLEON(c, m) || c->isfloating || c->isfullscreen) + if (!c || !VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
+ return; + return;
+ if (area.x == c->old_geom.x && area.y == c->old_geom.y &&
+ area.width == c->old_geom.width && area.height == c->old_geom.height)
+ return;
+ resize(c, area, 0); + resize(c, area, 0);
+ c->old_geom = area;
+ return; + return;
+ } + }
+ +
@@ -175,12 +173,10 @@ index 0000000..f05a30f
+ if (!m) + if (!m)
+ return; + return;
+ +
+ /* Remove non tiled clients from tree. */ + /* Remove floating and moved clients */
+ wl_list_for_each(c, &clients, link) { + wl_list_for_each(c, &clients, link) {
+ if (c->mon == m && !c->isfloating && !c->isfullscreen) { + if (c->mon != m || c->isfloating)
+ } else {
+ remove_client(m, c); + remove_client(m, c);
+ }
+ } + }
+ +
+ /* If no client is found under cursor, fallback to focustop(m) */ + /* If no client is found under cursor, fallback to focustop(m) */
@@ -464,8 +460,6 @@ index 0000000..f05a30f
+ split_node->split_ratio = new_ratio; + split_node->split_ratio = new_ratio;
+ +
+ apply_layout(selmon, selmon->root, selmon->w, 1); + apply_layout(selmon, selmon->root, selmon->w, 1);
+ /* Skip the arrange when called from motionnotify; that path calls
+ * arrange itself after rate-limiting. */
+} +}
+ +
+void +void
@@ -641,7 +635,7 @@ index 8a6eda0..bc04e3f 100644
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1), TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2), TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
diff --git a/dwl.c b/dwl.c diff --git a/dwl.c b/dwl.c
index 8101ffa..c9650c1 100644 index 8101ffa..7abf390 100644
--- a/dwl.c --- a/dwl.c
+++ b/dwl.c +++ b/dwl.c
@@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
@@ -660,18 +654,16 @@ index 8101ffa..c9650c1 100644
typedef struct Monitor Monitor; typedef struct Monitor Monitor;
typedef struct { typedef struct {
/* Must keep this field first */ /* Must keep this field first */
@@ -141,8 +143,9 @@ typedef struct { @@ -141,7 +143,7 @@ typedef struct {
#endif #endif
unsigned int bw; unsigned int bw;
uint32_t tags; uint32_t tags;
- int isfloating, isurgent, isfullscreen; - int isfloating, isurgent, isfullscreen;
+ int isfloating, isurgent, isfullscreen, was_tiled; + int isfloating, isurgent, isfullscreen, was_tiled;
uint32_t resize; /* configure serial of a pending resize */ uint32_t resize; /* configure serial of a pending resize */
+ struct wlr_box old_geom;
} Client; } Client;
typedef struct { @@ -209,6 +211,7 @@ struct Monitor {
@@ -209,6 +212,7 @@ struct Monitor {
int nmaster; int nmaster;
char ltsymbol[16]; char ltsymbol[16];
int asleep; int asleep;
@@ -679,7 +671,7 @@ index 8101ffa..c9650c1 100644
}; };
typedef struct { typedef struct {
@@ -251,6 +255,7 @@ static void arrangelayer(Monitor *m, struct wl_list *list, @@ -251,6 +254,7 @@ static void arrangelayer(Monitor *m, struct wl_list *list,
struct wlr_box *usable_area, int exclusive); struct wlr_box *usable_area, int exclusive);
static void arrangelayers(Monitor *m); static void arrangelayers(Monitor *m);
static void axisnotify(struct wl_listener *listener, void *data); static void axisnotify(struct wl_listener *listener, void *data);
@@ -687,7 +679,7 @@ index 8101ffa..c9650c1 100644
static void buttonpress(struct wl_listener *listener, void *data); static void buttonpress(struct wl_listener *listener, void *data);
static void chvt(const Arg *arg); static void chvt(const Arg *arg);
static void checkidleinhibitor(struct wlr_surface *exclude); static void checkidleinhibitor(struct wlr_surface *exclude);
@@ -333,6 +338,9 @@ static void setmon(Client *c, Monitor *m, uint32_t newtags); @@ -333,6 +337,9 @@ static void setmon(Client *c, Monitor *m, uint32_t newtags);
static void setpsel(struct wl_listener *listener, void *data); static void setpsel(struct wl_listener *listener, void *data);
static void setsel(struct wl_listener *listener, void *data); static void setsel(struct wl_listener *listener, void *data);
static void setup(void); static void setup(void);
@@ -697,7 +689,7 @@ index 8101ffa..c9650c1 100644
static void spawn(const Arg *arg); static void spawn(const Arg *arg);
static void startdrag(struct wl_listener *listener, void *data); static void startdrag(struct wl_listener *listener, void *data);
static void tag(const Arg *arg); static void tag(const Arg *arg);
@@ -458,6 +466,7 @@ static struct wlr_xwayland *xwayland; @@ -458,6 +465,7 @@ static struct wlr_xwayland *xwayland;
/* attempt to encapsulate suck into one file */ /* attempt to encapsulate suck into one file */
#include "client.h" #include "client.h"
@@ -705,7 +697,7 @@ index 8101ffa..c9650c1 100644
/* function implementations */ /* function implementations */
void void
@@ -628,7 +637,7 @@ buttonpress(struct wl_listener *listener, void *data) @@ -628,7 +636,7 @@ buttonpress(struct wl_listener *listener, void *data)
struct wlr_pointer_button_event *event = data; struct wlr_pointer_button_event *event = data;
struct wlr_keyboard *keyboard; struct wlr_keyboard *keyboard;
uint32_t mods; uint32_t mods;
@@ -714,7 +706,7 @@ index 8101ffa..c9650c1 100644
const Button *b; const Button *b;
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
@@ -649,7 +658,7 @@ buttonpress(struct wl_listener *listener, void *data) @@ -649,7 +657,7 @@ buttonpress(struct wl_listener *listener, void *data)
mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
for (b = buttons; b < END(buttons); b++) { for (b = buttons; b < END(buttons); b++) {
if (CLEANMASK(mods) == CLEANMASK(b->mod) && if (CLEANMASK(mods) == CLEANMASK(b->mod) &&
@@ -723,7 +715,7 @@ index 8101ffa..c9650c1 100644
b->func(&b->arg); b->func(&b->arg);
return; return;
} }
@@ -659,6 +668,21 @@ buttonpress(struct wl_listener *listener, void *data) @@ -659,6 +667,21 @@ buttonpress(struct wl_listener *listener, void *data)
/* If you released any buttons, we exit interactive move/resize mode. */ /* If you released any buttons, we exit interactive move/resize mode. */
/* TODO: should reset to the pointer focus's current setcursor */ /* TODO: should reset to the pointer focus's current setcursor */
if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) { if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
@@ -745,7 +737,7 @@ index 8101ffa..c9650c1 100644
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
cursor_mode = CurNormal; cursor_mode = CurNormal;
/* Drop the window off on its new monitor */ /* Drop the window off on its new monitor */
@@ -750,6 +774,7 @@ cleanupmon(struct wl_listener *listener, void *data) @@ -750,6 +773,7 @@ cleanupmon(struct wl_listener *listener, void *data)
wlr_output_layout_remove(output_layout, m->wlr_output); wlr_output_layout_remove(output_layout, m->wlr_output);
wlr_scene_output_destroy(m->scene_output); wlr_scene_output_destroy(m->scene_output);
@@ -753,7 +745,7 @@ index 8101ffa..c9650c1 100644
closemon(m); closemon(m);
wlr_scene_node_destroy(&m->fullscreen_bg->node); wlr_scene_node_destroy(&m->fullscreen_bg->node);
free(m); free(m);
@@ -1094,6 +1119,7 @@ createmon(struct wl_listener *listener, void *data) @@ -1094,6 +1118,7 @@ createmon(struct wl_listener *listener, void *data)
wl_list_insert(&mons, &m->link); wl_list_insert(&mons, &m->link);
printstatus(); printstatus();
@@ -761,7 +753,7 @@ index 8101ffa..c9650c1 100644
/* The xdg-protocol specifies: /* The xdg-protocol specifies:
* *
@@ -1332,10 +1358,18 @@ void @@ -1332,10 +1357,18 @@ void
destroynotify(struct wl_listener *listener, void *data) destroynotify(struct wl_listener *listener, void *data)
{ {
/* Called when the xdg_toplevel is destroyed. */ /* Called when the xdg_toplevel is destroyed. */
@@ -780,7 +772,7 @@ index 8101ffa..c9650c1 100644
#ifdef XWAYLAND #ifdef XWAYLAND
if (c->type != XDGShell) { if (c->type != XDGShell) {
wl_list_remove(&c->activate.link); wl_list_remove(&c->activate.link);
@@ -1866,7 +1900,8 @@ void @@ -1866,7 +1899,8 @@ void
motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy, motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy,
double dx_unaccel, double dy_unaccel) double dx_unaccel, double dy_unaccel)
{ {
@@ -790,7 +782,7 @@ index 8101ffa..c9650c1 100644
Client *c = NULL, *w = NULL; Client *c = NULL, *w = NULL;
LayerSurface *l = NULL; LayerSurface *l = NULL;
struct wlr_surface *surface = NULL; struct wlr_surface *surface = NULL;
@@ -1920,18 +1955,55 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d @@ -1920,18 +1954,55 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
/* Update drag icon's position */ /* Update drag icon's position */
wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y)); wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y));
@@ -853,7 +845,7 @@ index 8101ffa..c9650c1 100644
/* If there's no client surface under the cursor, set the cursor image to a /* If there's no client surface under the cursor, set the cursor image to a
* default. This is what makes the cursor image appear when you move it * default. This is what makes the cursor image appear when you move it
* off of a client or over its border. */ * off of a client or over its border. */
@@ -1965,22 +2037,40 @@ moveresize(const Arg *arg) @@ -1965,22 +2036,40 @@ moveresize(const Arg *arg)
if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen) if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
return; return;
@@ -910,7 +902,7 @@ index 8101ffa..c9650c1 100644
} }
} }
@@ -2833,6 +2923,14 @@ unmapnotify(struct wl_listener *listener, void *data) @@ -2833,6 +2922,14 @@ unmapnotify(struct wl_listener *listener, void *data)
focusclient(focustop(selmon), 1); focusclient(focustop(selmon), 1);
} }
} else { } else {
@@ -1,24 +1,24 @@
From 47cb7ad9f669643765cafa4c2ecd1a4850bca893 Mon Sep 17 00:00:00 2001 From 3500e732fc34aa849cd3babeff7d2545a0230fa9 Mon Sep 17 00:00:00 2001
From: julmajustus <julmajustus@tutanota.com> From: julmajustus <julmajustus@tutanota.com>
Date: Thu, 21 May 2026 00:39:56 +0300 Date: Mon, 22 Jun 2026 22:33:17 +0300
Subject: [PATCH] btrtile: Spring update pt2 Subject: [PATCH] btrtile: bug fixes and readability improvement
- Simplified the resizing logic to avoid full arrange calls from - Removed client old_geom caching for simplicity fixes: https://codeberg.org/dwl/dwl-patches/issues/647
motionnotify - Improved readability of the client sanitization loop inside btrtile function
- Minor intend fixes - Removed fullscreened client's from the sanitization loop to retain their geometry
--- ---
btrtile.c | 564 +++++++++++++++++++++++++++++++++++++++++++++++++++ btrtile.c | 556 +++++++++++++++++++++++++++++++++++++++++++++++++++
config.def.h | 12 ++ config.def.h | 12 ++
dwl.c | 152 +++++++++++--- dwl.c | 151 +++++++++++---
3 files changed, 701 insertions(+), 27 deletions(-) 3 files changed, 692 insertions(+), 27 deletions(-)
create mode 100644 btrtile.c create mode 100644 btrtile.c
diff --git a/btrtile.c b/btrtile.c diff --git a/btrtile.c b/btrtile.c
new file mode 100644 new file mode 100644
index 0000000..357ffb9 index 0000000..b4f6f43
--- /dev/null --- /dev/null
+++ b/btrtile.c +++ b/btrtile.c
@@ -0,0 +1,564 @@ @@ -0,0 +1,556 @@
+/* ************************************************************************** */ +/* ************************************************************************** */
+/* @@@ @@@@@@@@ */ +/* @@@ @@@@@@@@ */
+/* @@@ @@@@@@@@@@ */ +/* @@@ @@@@@@@@@@ */
@@ -29,7 +29,7 @@ index 0000000..357ffb9
+/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */ +/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */
+/* ::! :!: !:! */ +/* ::! :!: !:! */
+/* Created: 2024/12/15 00:26:07 by julmajustus :: ::::::: :: */ +/* Created: 2024/12/15 00:26:07 by julmajustus :: ::::::: :: */
+/* Updated: 2026/05/20 22:51:54 by julmajustus : : : : : : */ +/* Updated: 2026/06/22 22:30:19 by julmajustus : : : : : : */
+/* */ +/* */
+/* ************************************************************************** */ +/* ************************************************************************** */
+ +
@@ -84,11 +84,7 @@ index 0000000..357ffb9
+ c = node->client; + c = node->client;
+ if (!c || !VISIBLEON(c, m) || c->isfloating || c->isfullscreen) + if (!c || !VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
+ return; + return;
+ if (area.x == c->old_geom.x && area.y == c->old_geom.y &&
+ area.width == c->old_geom.width && area.height == c->old_geom.height)
+ return;
+ resize(c, area, 0); + resize(c, area, 0);
+ c->old_geom = area;
+ return; + return;
+ } + }
+ +
@@ -156,12 +152,10 @@ index 0000000..357ffb9
+ if (!m) + if (!m)
+ return; + return;
+ +
+ /* Remove non tiled clients from tree. */ + /* Remove floating and moved clients */
+ wl_list_for_each(c, &clients, link) { + wl_list_for_each(c, &clients, link) {
+ if (c->mon == m && !c->isfloating && !c->isfullscreen) { + if (c->mon != m || c->isfloating)
+ } else {
+ remove_client(m, c); + remove_client(m, c);
+ }
+ } + }
+ +
+ /* If no client is found under cursor, fallback to focustop(m) */ + /* If no client is found under cursor, fallback to focustop(m) */
@@ -445,8 +439,6 @@ index 0000000..357ffb9
+ split_node->split_ratio = new_ratio; + split_node->split_ratio = new_ratio;
+ +
+ apply_layout(selmon, selmon->root, selmon->w, 1); + apply_layout(selmon, selmon->root, selmon->w, 1);
+ /* Skip the arrange when called from motionnotify; that path calls
+ * arrange itself after rate-limiting. */
+} +}
+ +
+void +void
@@ -622,7 +614,7 @@ index 8a6eda0..bc04e3f 100644
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1), TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2), TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
diff --git a/dwl.c b/dwl.c diff --git a/dwl.c b/dwl.c
index 8101ffa..bf52c6c 100644 index 8101ffa..31446ed 100644
--- a/dwl.c --- a/dwl.c
+++ b/dwl.c +++ b/dwl.c
@@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
@@ -641,18 +633,16 @@ index 8101ffa..bf52c6c 100644
typedef struct Monitor Monitor; typedef struct Monitor Monitor;
typedef struct { typedef struct {
/* Must keep this field first */ /* Must keep this field first */
@@ -141,8 +143,9 @@ typedef struct { @@ -141,7 +143,7 @@ typedef struct {
#endif #endif
unsigned int bw; unsigned int bw;
uint32_t tags; uint32_t tags;
- int isfloating, isurgent, isfullscreen; - int isfloating, isurgent, isfullscreen;
+ int isfloating, isurgent, isfullscreen, was_tiled; + int isfloating, isurgent, isfullscreen, was_tiled;
uint32_t resize; /* configure serial of a pending resize */ uint32_t resize; /* configure serial of a pending resize */
+ struct wlr_box old_geom;
} Client; } Client;
typedef struct { @@ -209,6 +211,7 @@ struct Monitor {
@@ -209,6 +212,7 @@ struct Monitor {
int nmaster; int nmaster;
char ltsymbol[16]; char ltsymbol[16];
int asleep; int asleep;
@@ -660,7 +650,7 @@ index 8101ffa..bf52c6c 100644
}; };
typedef struct { typedef struct {
@@ -251,6 +255,7 @@ static void arrangelayer(Monitor *m, struct wl_list *list, @@ -251,6 +254,7 @@ static void arrangelayer(Monitor *m, struct wl_list *list,
struct wlr_box *usable_area, int exclusive); struct wlr_box *usable_area, int exclusive);
static void arrangelayers(Monitor *m); static void arrangelayers(Monitor *m);
static void axisnotify(struct wl_listener *listener, void *data); static void axisnotify(struct wl_listener *listener, void *data);
@@ -668,7 +658,7 @@ index 8101ffa..bf52c6c 100644
static void buttonpress(struct wl_listener *listener, void *data); static void buttonpress(struct wl_listener *listener, void *data);
static void chvt(const Arg *arg); static void chvt(const Arg *arg);
static void checkidleinhibitor(struct wlr_surface *exclude); static void checkidleinhibitor(struct wlr_surface *exclude);
@@ -333,6 +338,9 @@ static void setmon(Client *c, Monitor *m, uint32_t newtags); @@ -333,6 +337,9 @@ static void setmon(Client *c, Monitor *m, uint32_t newtags);
static void setpsel(struct wl_listener *listener, void *data); static void setpsel(struct wl_listener *listener, void *data);
static void setsel(struct wl_listener *listener, void *data); static void setsel(struct wl_listener *listener, void *data);
static void setup(void); static void setup(void);
@@ -678,7 +668,7 @@ index 8101ffa..bf52c6c 100644
static void spawn(const Arg *arg); static void spawn(const Arg *arg);
static void startdrag(struct wl_listener *listener, void *data); static void startdrag(struct wl_listener *listener, void *data);
static void tag(const Arg *arg); static void tag(const Arg *arg);
@@ -458,6 +466,7 @@ static struct wlr_xwayland *xwayland; @@ -458,6 +465,7 @@ static struct wlr_xwayland *xwayland;
/* attempt to encapsulate suck into one file */ /* attempt to encapsulate suck into one file */
#include "client.h" #include "client.h"
@@ -686,7 +676,7 @@ index 8101ffa..bf52c6c 100644
/* function implementations */ /* function implementations */
void void
@@ -628,7 +637,7 @@ buttonpress(struct wl_listener *listener, void *data) @@ -628,7 +636,7 @@ buttonpress(struct wl_listener *listener, void *data)
struct wlr_pointer_button_event *event = data; struct wlr_pointer_button_event *event = data;
struct wlr_keyboard *keyboard; struct wlr_keyboard *keyboard;
uint32_t mods; uint32_t mods;
@@ -695,7 +685,7 @@ index 8101ffa..bf52c6c 100644
const Button *b; const Button *b;
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
@@ -649,7 +658,7 @@ buttonpress(struct wl_listener *listener, void *data) @@ -649,7 +657,7 @@ buttonpress(struct wl_listener *listener, void *data)
mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
for (b = buttons; b < END(buttons); b++) { for (b = buttons; b < END(buttons); b++) {
if (CLEANMASK(mods) == CLEANMASK(b->mod) && if (CLEANMASK(mods) == CLEANMASK(b->mod) &&
@@ -704,7 +694,7 @@ index 8101ffa..bf52c6c 100644
b->func(&b->arg); b->func(&b->arg);
return; return;
} }
@@ -659,6 +668,21 @@ buttonpress(struct wl_listener *listener, void *data) @@ -659,6 +667,21 @@ buttonpress(struct wl_listener *listener, void *data)
/* If you released any buttons, we exit interactive move/resize mode. */ /* If you released any buttons, we exit interactive move/resize mode. */
/* TODO: should reset to the pointer focus's current setcursor */ /* TODO: should reset to the pointer focus's current setcursor */
if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) { if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
@@ -726,7 +716,7 @@ index 8101ffa..bf52c6c 100644
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
cursor_mode = CurNormal; cursor_mode = CurNormal;
/* Drop the window off on its new monitor */ /* Drop the window off on its new monitor */
@@ -750,6 +774,7 @@ cleanupmon(struct wl_listener *listener, void *data) @@ -750,6 +773,7 @@ cleanupmon(struct wl_listener *listener, void *data)
wlr_output_layout_remove(output_layout, m->wlr_output); wlr_output_layout_remove(output_layout, m->wlr_output);
wlr_scene_output_destroy(m->scene_output); wlr_scene_output_destroy(m->scene_output);
@@ -734,7 +724,7 @@ index 8101ffa..bf52c6c 100644
closemon(m); closemon(m);
wlr_scene_node_destroy(&m->fullscreen_bg->node); wlr_scene_node_destroy(&m->fullscreen_bg->node);
free(m); free(m);
@@ -1094,6 +1119,7 @@ createmon(struct wl_listener *listener, void *data) @@ -1094,6 +1118,7 @@ createmon(struct wl_listener *listener, void *data)
wl_list_insert(&mons, &m->link); wl_list_insert(&mons, &m->link);
printstatus(); printstatus();
@@ -742,7 +732,7 @@ index 8101ffa..bf52c6c 100644
/* The xdg-protocol specifies: /* The xdg-protocol specifies:
* *
@@ -1333,9 +1359,17 @@ destroynotify(struct wl_listener *listener, void *data) @@ -1333,9 +1358,17 @@ destroynotify(struct wl_listener *listener, void *data)
{ {
/* Called when the xdg_toplevel is destroyed. */ /* Called when the xdg_toplevel is destroyed. */
Client *c = wl_container_of(listener, c, destroy); Client *c = wl_container_of(listener, c, destroy);
@@ -760,7 +750,7 @@ index 8101ffa..bf52c6c 100644
#ifdef XWAYLAND #ifdef XWAYLAND
if (c->type != XDGShell) { if (c->type != XDGShell) {
wl_list_remove(&c->activate.link); wl_list_remove(&c->activate.link);
@@ -1866,7 +1900,8 @@ void @@ -1866,7 +1899,8 @@ void
motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy, motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy,
double dx_unaccel, double dy_unaccel) double dx_unaccel, double dy_unaccel)
{ {
@@ -770,7 +760,7 @@ index 8101ffa..bf52c6c 100644
Client *c = NULL, *w = NULL; Client *c = NULL, *w = NULL;
LayerSurface *l = NULL; LayerSurface *l = NULL;
struct wlr_surface *surface = NULL; struct wlr_surface *surface = NULL;
@@ -1920,18 +1955,55 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d @@ -1920,18 +1954,55 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
/* Update drag icon's position */ /* Update drag icon's position */
wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y)); wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y));
@@ -833,7 +823,7 @@ index 8101ffa..bf52c6c 100644
/* If there's no client surface under the cursor, set the cursor image to a /* If there's no client surface under the cursor, set the cursor image to a
* default. This is what makes the cursor image appear when you move it * default. This is what makes the cursor image appear when you move it
* off of a client or over its border. */ * off of a client or over its border. */
@@ -1965,22 +2037,40 @@ moveresize(const Arg *arg) @@ -1965,22 +2036,40 @@ moveresize(const Arg *arg)
if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen) if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
return; return;
@@ -890,7 +880,7 @@ index 8101ffa..bf52c6c 100644
} }
} }
@@ -2833,6 +2923,14 @@ unmapnotify(struct wl_listener *listener, void *data) @@ -2833,6 +2922,14 @@ unmapnotify(struct wl_listener *listener, void *data)
focusclient(focustop(selmon), 1); focusclient(focustop(selmon), 1);
} }
} else { } else {
-1
View File
@@ -23,7 +23,6 @@ Adds a function that automatically enables adaptive sync/VRR when a fullscreen c
### Download ### Download
- [git branch](https://codeberg.org/julmajustus/dwl/src/branch/fullscreenadaptivesync-wlroots-next) - [git branch](https://codeberg.org/julmajustus/dwl/src/branch/fullscreenadaptivesync-wlroots-next)
- [0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/fullscreenadaptivesync/fullscreenadaptivesync-v0.7.patch)
- [0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/fullscreenadaptivesync/fullscreenadaptivesync-v0.8.patch) - [0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/fullscreenadaptivesync/fullscreenadaptivesync-v0.8.patch)
- [wlroots-next-d41ecb7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/fullscreenadaptivesync/fullscreenadaptivesync-wlroots-next-d41ecb7.patch) - [wlroots-next-d41ecb7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/fullscreenadaptivesync/fullscreenadaptivesync-wlroots-next-d41ecb7.patch)
@@ -1,144 +0,0 @@
From 85dccbec7e6d2e967646a8c182a7a24224632c68 Mon Sep 17 00:00:00 2001
From: julmajustus <julmajustus@tutanota.com>
Date: Mon, 18 May 2026 00:03:41 +0300
Subject: [PATCH] fullscreen_adaptive_sync: Minor bug fixes
- Fixed logic error inside unmapnotify
- Added no-op guards inside set_adaptive_sync
- Added extra check for the config commit success
---
config.def.h | 1 +
dwl.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 53 insertions(+)
diff --git a/config.def.h b/config.def.h
index 22d2171..886f1ab 100644
--- a/config.def.h
+++ b/config.def.h
@@ -142,6 +142,7 @@ 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} },
+ { MODKEY, XKB_KEY_F5, togglefullscreenadaptivesync, {0} },
{ MODKEY, XKB_KEY_0, view, {.ui = ~0} },
{ 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 a2711f6..1b0682d 100644
--- a/dwl.c
+++ b/dwl.c
@@ -322,6 +322,7 @@ static void requeststartdrag(struct wl_listener *listener, void *data);
static void requestmonstate(struct wl_listener *listener, void *data);
static void resize(Client *c, struct wlr_box geo, int interact);
static void run(char *startup_cmd);
+static void set_adaptive_sync(Monitor *m, int enabled);
static void setcursor(struct wl_listener *listener, void *data);
static void setcursorshape(struct wl_listener *listener, void *data);
static void setfloating(Client *c, int floating);
@@ -340,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 togglefullscreenadaptivesync(const Arg *arg);
static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
static void unlocksession(struct wl_listener *listener, void *data);
@@ -413,6 +415,8 @@ static struct wlr_box sgeom;
static struct wl_list mons;
static Monitor *selmon;
+static int fullscreen_adaptive_sync_enabled = 1;
+
#ifdef XWAYLAND
static void activatex11(struct wl_listener *listener, void *data);
static void associatex11(struct wl_listener *listener, void *data);
@@ -2269,6 +2273,42 @@ run(char *startup_cmd)
wl_display_run(dpy);
}
+set_adaptive_sync(Monitor *m, int enable)
+{
+ struct wlr_output_state state;
+ struct wlr_output_configuration_v1 *config;
+ struct wlr_output_configuration_head_v1 *config_head;
+
+ if (!m || !m->wlr_output || !m->wlr_output->enabled
+ || !fullscreen_adaptive_sync_enabled)
+ return;
+
+ if (enable && m->wlr_output->adaptive_sync_status
+ == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED)
+ return;
+
+ if (!enable && m->wlr_output->adaptive_sync_status
+ == WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED)
+ return;
+
+ config = wlr_output_configuration_v1_create();
+ config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output);
+
+ /* Set and commit the adaptive sync state change */
+ wlr_output_state_init(&state);
+ wlr_output_state_set_adaptive_sync_enabled(&state, enable);
+ if (!wlr_output_commit_state(m->wlr_output, &state)) {
+ wlr_output_state_finish(&state);
+ wlr_output_configuration_v1_destroy(config);
+ return;
+ }
+ wlr_output_state_finish(&state);
+
+ /* Broadcast the adaptive sync state change to output_mgr */
+ config_head->state.adaptive_sync_enabled = enable;
+ wlr_output_manager_v1_set_configuration(output_mgr, config);
+}
+
void
setcursor(struct wl_listener *listener, void *data)
{
@@ -2332,10 +2372,12 @@ setfullscreen(Client *c, int fullscreen)
if (fullscreen) {
c->prev = c->geom;
resize(c, c->mon->m, 0);
+ set_adaptive_sync(c->mon, 1);
} else {
/* restore previous size instead of arrange for floating windows since
* client positions are set by the user and cannot be recalculated */
resize(c, c->prev, 0);
+ set_adaptive_sync(c->mon, 0);
}
arrange(c->mon);
printstatus();
@@ -2739,6 +2781,12 @@ togglefullscreen(const Arg *arg)
setfullscreen(sel, !sel->isfullscreen);
}
+void
+togglefullscreenadaptivesync(const Arg *arg)
+{
+ fullscreen_adaptive_sync_enabled = !fullscreen_adaptive_sync_enabled;
+}
+
void
toggletag(const Arg *arg)
{
@@ -2794,6 +2842,7 @@ unmapnotify(struct wl_listener *listener, void *data)
{
/* Called when the surface is unmapped, and should no longer be shown. */
Client *c = wl_container_of(listener, c, unmap);
+ Monitor *lastmon = c->mon; // fullscreen_adaptive_sync
if (c == grabc) {
cursor_mode = CurNormal;
grabc = NULL;
@@ -2809,6 +2858,9 @@ unmapnotify(struct wl_listener *listener, void *data)
setmon(c, NULL, 0);
wl_list_remove(&c->flink);
}
+ /* Toggle adaptive sync off when fullscreen client is unmapped */
+ if (c->isfullscreen)
+ set_adaptive_sync(lastmon, 0);
wlr_scene_node_destroy(&c->scene->node);
printstatus();
--
2.53.0
@@ -1,6 +1,6 @@
From 60af6f9dab09710234475b51393a104c21918db3 Mon Sep 17 00:00:00 2001 From b9bb8d48e1be3008d72da414f6f418d77f3ca16b Mon Sep 17 00:00:00 2001
From: julmajustus <julmajustus@tutanota.com> From: julmajustus <julmajustus@tutanota.com>
Date: Mon, 18 May 2026 00:12:31 +0300 Date: Mon, 22 Jun 2026 23:01:00 +0300
Subject: [PATCH] fullscreen_adaptive_sync: Minor bug fixes Subject: [PATCH] fullscreen_adaptive_sync: Minor bug fixes
- Fixed logic error inside unmapnotify - Fixed logic error inside unmapnotify
@@ -8,8 +8,8 @@ Subject: [PATCH] fullscreen_adaptive_sync: Minor bug fixes
- Added extra check for the config commit success - Added extra check for the config commit success
--- ---
config.def.h | 1 + config.def.h | 1 +
dwl.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ dwl.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 53 insertions(+) 2 files changed, 54 insertions(+)
diff --git a/config.def.h b/config.def.h diff --git a/config.def.h b/config.def.h
index 8a6eda0..06b3153 100644 index 8a6eda0..06b3153 100644
@@ -24,7 +24,7 @@ index 8a6eda0..06b3153 100644
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} },
{ MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} }, { MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} },
diff --git a/dwl.c b/dwl.c diff --git a/dwl.c b/dwl.c
index 44f3ad9..737f089 100644 index 44f3ad9..e4f6a9d 100644
--- a/dwl.c --- a/dwl.c
+++ b/dwl.c +++ b/dwl.c
@@ -319,6 +319,7 @@ static void requeststartdrag(struct wl_listener *listener, void *data); @@ -319,6 +319,7 @@ static void requeststartdrag(struct wl_listener *listener, void *data);
@@ -52,10 +52,11 @@ index 44f3ad9..737f089 100644
#ifdef XWAYLAND #ifdef XWAYLAND
static void activatex11(struct wl_listener *listener, void *data); static void activatex11(struct wl_listener *listener, void *data);
static void associatex11(struct wl_listener *listener, void *data); static void associatex11(struct wl_listener *listener, void *data);
@@ -2296,6 +2300,42 @@ run(char *startup_cmd) @@ -2296,6 +2300,43 @@ run(char *startup_cmd)
wl_display_run(dpy); wl_display_run(dpy);
} }
+void
+set_adaptive_sync(Monitor *m, int enable) +set_adaptive_sync(Monitor *m, int enable)
+{ +{
+ struct wlr_output_state state; + struct wlr_output_state state;
@@ -66,13 +67,13 @@ index 44f3ad9..737f089 100644
+ || !fullscreen_adaptive_sync_enabled) + || !fullscreen_adaptive_sync_enabled)
+ return; + return;
+ +
+ if (enable && m->wlr_output->adaptive_sync_status + if (enable && m->wlr_output->adaptive_sync_status
+ == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED) + == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED)
+ return; + return;
+ +
+ if (!enable && m->wlr_output->adaptive_sync_status + if (!enable && m->wlr_output->adaptive_sync_status
+ == WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED) + == WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED)
+ return; + return;
+ +
+ config = wlr_output_configuration_v1_create(); + config = wlr_output_configuration_v1_create();
+ config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output); + config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output);
@@ -80,12 +81,12 @@ index 44f3ad9..737f089 100644
+ /* Set and commit the adaptive sync state change */ + /* Set and commit the adaptive sync state change */
+ wlr_output_state_init(&state); + wlr_output_state_init(&state);
+ wlr_output_state_set_adaptive_sync_enabled(&state, enable); + wlr_output_state_set_adaptive_sync_enabled(&state, enable);
+ if (!wlr_output_commit_state(m->wlr_output, &state)) { + if (!wlr_output_commit_state(m->wlr_output, &state)) {
+ wlr_output_state_finish(&state); + wlr_output_state_finish(&state);
+ wlr_output_configuration_v1_destroy(config); + wlr_output_configuration_v1_destroy(config);
+ return; + return;
+ } + }
+ wlr_output_state_finish(&state); + wlr_output_state_finish(&state);
+ +
+ /* Broadcast the adaptive sync state change to output_mgr */ + /* Broadcast the adaptive sync state change to output_mgr */
+ config_head->state.adaptive_sync_enabled = enable; + config_head->state.adaptive_sync_enabled = enable;
@@ -95,7 +96,7 @@ index 44f3ad9..737f089 100644
void void
setcursor(struct wl_listener *listener, void *data) setcursor(struct wl_listener *listener, void *data)
{ {
@@ -2359,10 +2399,12 @@ setfullscreen(Client *c, int fullscreen) @@ -2359,10 +2400,12 @@ setfullscreen(Client *c, int fullscreen)
if (fullscreen) { if (fullscreen) {
c->prev = c->geom; c->prev = c->geom;
resize(c, c->mon->m, 0); resize(c, c->mon->m, 0);
@@ -108,7 +109,7 @@ index 44f3ad9..737f089 100644
} }
arrange(c->mon); arrange(c->mon);
printstatus(); printstatus();
@@ -2760,6 +2802,12 @@ togglefullscreen(const Arg *arg) @@ -2760,6 +2803,12 @@ togglefullscreen(const Arg *arg)
setfullscreen(sel, !sel->isfullscreen); setfullscreen(sel, !sel->isfullscreen);
} }
@@ -121,21 +122,21 @@ index 44f3ad9..737f089 100644
void void
toggletag(const Arg *arg) toggletag(const Arg *arg)
{ {
@@ -2815,6 +2863,7 @@ unmapnotify(struct wl_listener *listener, void *data) @@ -2815,6 +2864,7 @@ unmapnotify(struct wl_listener *listener, void *data)
{ {
/* Called when the surface is unmapped, and should no longer be shown. */ /* Called when the surface is unmapped, and should no longer be shown. */
Client *c = wl_container_of(listener, c, unmap); Client *c = wl_container_of(listener, c, unmap);
+ Monitor *lastmon = c->mon; // fullscreen_adaptive_sync + Monitor *lastmon = c->mon; // fullscreen_adaptive_sync
if (c == grabc) { if (c == grabc) {
cursor_mode = CurNormal; cursor_mode = CurNormal;
grabc = NULL; grabc = NULL;
@@ -2830,6 +2879,9 @@ unmapnotify(struct wl_listener *listener, void *data) @@ -2830,6 +2880,9 @@ unmapnotify(struct wl_listener *listener, void *data)
setmon(c, NULL, 0); setmon(c, NULL, 0);
wl_list_remove(&c->flink); wl_list_remove(&c->flink);
} }
+ /* Toggle adaptive sync off when fullscreen client is unmapped */ + /* Toggle adaptive sync off when fullscreen client is unmapped */
+ if (c->isfullscreen) + if (c->isfullscreen)
+ set_adaptive_sync(lastmon, 0); + set_adaptive_sync(lastmon, 0);
wlr_scene_node_destroy(&c->scene->node); wlr_scene_node_destroy(&c->scene->node);
printstatus(); printstatus();
@@ -1,6 +1,6 @@
From cf817259dbb1235d1ffc073d4e0f128676552666 Mon Sep 17 00:00:00 2001 From 5d475f7afe7ba7cee389a5c5ed4fa676b408fee5 Mon Sep 17 00:00:00 2001
From: julmajustus <julmajustus@tutanota.com> From: julmajustus <julmajustus@tutanota.com>
Date: Mon, 18 May 2026 00:15:18 +0300 Date: Mon, 22 Jun 2026 23:02:25 +0300
Subject: [PATCH] fullscreen_adaptive_sync: Minor bug fixes Subject: [PATCH] fullscreen_adaptive_sync: Minor bug fixes
- Fixed logic error inside unmapnotify - Fixed logic error inside unmapnotify
@@ -8,8 +8,8 @@ Subject: [PATCH] fullscreen_adaptive_sync: Minor bug fixes
- Added extra check for the config commit success - Added extra check for the config commit success
--- ---
config.def.h | 1 + config.def.h | 1 +
dwl.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ dwl.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 53 insertions(+) 2 files changed, 57 insertions(+), 3 deletions(-)
diff --git a/config.def.h b/config.def.h diff --git a/config.def.h b/config.def.h
index 8a6eda0..06b3153 100644 index 8a6eda0..06b3153 100644
@@ -24,7 +24,7 @@ index 8a6eda0..06b3153 100644
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} },
{ MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} }, { MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} },
diff --git a/dwl.c b/dwl.c diff --git a/dwl.c b/dwl.c
index 8101ffa..2f1c80b 100644 index 8101ffa..aabd882 100644
--- a/dwl.c --- a/dwl.c
+++ b/dwl.c +++ b/dwl.c
@@ -323,6 +323,7 @@ static void requeststartdrag(struct wl_listener *listener, void *data); @@ -323,6 +323,7 @@ static void requeststartdrag(struct wl_listener *listener, void *data);
@@ -52,10 +52,11 @@ index 8101ffa..2f1c80b 100644
#ifdef XWAYLAND #ifdef XWAYLAND
static void activatex11(struct wl_listener *listener, void *data); static void activatex11(struct wl_listener *listener, void *data);
static void associatex11(struct wl_listener *listener, void *data); static void associatex11(struct wl_listener *listener, void *data);
@@ -2300,6 +2304,42 @@ run(char *startup_cmd) @@ -2300,6 +2304,43 @@ run(char *startup_cmd)
wl_display_run(dpy); wl_display_run(dpy);
} }
+void
+set_adaptive_sync(Monitor *m, int enable) +set_adaptive_sync(Monitor *m, int enable)
+{ +{
+ struct wlr_output_state state; + struct wlr_output_state state;
@@ -66,13 +67,13 @@ index 8101ffa..2f1c80b 100644
+ || !fullscreen_adaptive_sync_enabled) + || !fullscreen_adaptive_sync_enabled)
+ return; + return;
+ +
+ if (enable && m->wlr_output->adaptive_sync_status + if (enable && m->wlr_output->adaptive_sync_status
+ == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED) + == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED)
+ return; + return;
+ +
+ if (!enable && m->wlr_output->adaptive_sync_status + if (!enable && m->wlr_output->adaptive_sync_status
+ == WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED) + == WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED)
+ return; + return;
+ +
+ config = wlr_output_configuration_v1_create(); + config = wlr_output_configuration_v1_create();
+ config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output); + config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output);
@@ -80,12 +81,12 @@ index 8101ffa..2f1c80b 100644
+ /* Set and commit the adaptive sync state change */ + /* Set and commit the adaptive sync state change */
+ wlr_output_state_init(&state); + wlr_output_state_init(&state);
+ wlr_output_state_set_adaptive_sync_enabled(&state, enable); + wlr_output_state_set_adaptive_sync_enabled(&state, enable);
+ if (!wlr_output_commit_state(m->wlr_output, &state)) { + if (!wlr_output_commit_state(m->wlr_output, &state)) {
+ wlr_output_state_finish(&state); + wlr_output_state_finish(&state);
+ wlr_output_configuration_v1_destroy(config); + wlr_output_configuration_v1_destroy(config);
+ return; + return;
+ } + }
+ wlr_output_state_finish(&state); + wlr_output_state_finish(&state);
+ +
+ /* Broadcast the adaptive sync state change to output_mgr */ + /* Broadcast the adaptive sync state change to output_mgr */
+ config_head->state.adaptive_sync_enabled = enable; + config_head->state.adaptive_sync_enabled = enable;
@@ -95,7 +96,7 @@ index 8101ffa..2f1c80b 100644
void void
setcursor(struct wl_listener *listener, void *data) setcursor(struct wl_listener *listener, void *data)
{ {
@@ -2363,10 +2403,12 @@ setfullscreen(Client *c, int fullscreen) @@ -2363,10 +2404,12 @@ setfullscreen(Client *c, int fullscreen)
if (fullscreen) { if (fullscreen) {
c->prev = c->geom; c->prev = c->geom;
resize(c, c->mon->m, 0); resize(c, c->mon->m, 0);
@@ -108,7 +109,27 @@ index 8101ffa..2f1c80b 100644
} }
arrange(c->mon); arrange(c->mon);
printstatus(); printstatus();
@@ -2767,6 +2809,12 @@ togglefullscreen(const Arg *arg) @@ -2546,7 +2589,7 @@ setup(void)
output_layout = wlr_output_layout_create(dpy);
wl_signal_add(&output_layout->events.change, &layout_change);
- wlr_xdg_output_manager_v1_create(dpy, output_layout);
+ wlr_xdg_output_manager_v1_create(dpy, output_layout);
/* Configure a listener to be notified when new outputs are available on the
* backend. */
@@ -2636,8 +2679,8 @@ setup(void)
wl_signal_add(&virtual_keyboard_mgr->events.new_virtual_keyboard,
&new_virtual_keyboard);
virtual_pointer_mgr = wlr_virtual_pointer_manager_v1_create(dpy);
- wl_signal_add(&virtual_pointer_mgr->events.new_virtual_pointer,
- &new_virtual_pointer);
+ wl_signal_add(&virtual_pointer_mgr->events.new_virtual_pointer,
+ &new_virtual_pointer);
seat = wlr_seat_create(dpy, "seat0");
wl_signal_add(&seat->events.request_set_cursor, &request_cursor);
@@ -2767,6 +2810,12 @@ togglefullscreen(const Arg *arg)
setfullscreen(sel, !sel->isfullscreen); setfullscreen(sel, !sel->isfullscreen);
} }
@@ -121,21 +142,21 @@ index 8101ffa..2f1c80b 100644
void void
toggletag(const Arg *arg) toggletag(const Arg *arg)
{ {
@@ -2822,6 +2870,7 @@ unmapnotify(struct wl_listener *listener, void *data) @@ -2822,6 +2871,7 @@ unmapnotify(struct wl_listener *listener, void *data)
{ {
/* Called when the surface is unmapped, and should no longer be shown. */ /* Called when the surface is unmapped, and should no longer be shown. */
Client *c = wl_container_of(listener, c, unmap); Client *c = wl_container_of(listener, c, unmap);
+ Monitor *lastmon = c->mon; // fullscreen_adaptive_sync + Monitor *lastmon = c->mon; // fullscreen_adaptive_sync
if (c == grabc) { if (c == grabc) {
cursor_mode = CurNormal; cursor_mode = CurNormal;
grabc = NULL; grabc = NULL;
@@ -2837,6 +2886,9 @@ unmapnotify(struct wl_listener *listener, void *data) @@ -2837,6 +2887,9 @@ unmapnotify(struct wl_listener *listener, void *data)
setmon(c, NULL, 0); setmon(c, NULL, 0);
wl_list_remove(&c->flink); wl_list_remove(&c->flink);
} }
+ /* Toggle adaptive sync off when fullscreen client is unmapped */ + /* Toggle adaptive sync off when fullscreen client is unmapped */
+ if (c->isfullscreen) + if (c->isfullscreen)
+ set_adaptive_sync(lastmon, 0); + set_adaptive_sync(lastmon, 0);
wlr_scene_node_destroy(&c->scene->node); wlr_scene_node_destroy(&c->scene->node);
printstatus(); printstatus();
+8
View File
@@ -0,0 +1,8 @@
### Description
Gamepad bindings to dwl. Press `LB + RB` toggle gamepad bindings.
### Download
- [2026-07-18](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/gamepad-bindings/gamepad-bindings.patch)
### Authors
- [dhruva_sambrani](https://codeberg.org/dhruva_sambrani)
@@ -0,0 +1,423 @@
diff --git a/Makefile b/Makefile
index 578194f..601c70e 100644
--- a/Makefile
+++ b/Makefile
@@ -12,16 +12,17 @@ DWLDEVCFLAGS = -g -Wpedantic -Wall -Wextra -Wdeclaration-after-statement \
-Wfloat-conversion
# CFLAGS / LDFLAGS
-PKGS = wayland-server xkbcommon libinput $(XLIBS)
+PKGS = wayland-server xkbcommon libinput libevdev libudev $(XLIBS)
DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(WLR_INCS) $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS)
LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(WLR_LIBS) -lm $(LIBS)
all: dwl
-dwl: dwl.o util.o
- $(CC) dwl.o util.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@
-dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h \
+dwl: dwl.o gamepad.o util.o
+ $(CC) dwl.o gamepad.o util.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@
+dwl.o: dwl.c client.h gamepad.h config.h config.mk cursor-shape-v1-protocol.h \
pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h \
wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h
+gamepad.o: gamepad.c gamepad.h
util.o: util.c util.h
# wayland-scanner is a tool which generates C headers and rigging for Wayland
@@ -54,7 +55,7 @@ clean:
dist: clean
mkdir -p dwl-$(VERSION)
cp -R LICENSE* Makefile CHANGELOG.md README.md client.h config.def.h \
- config.mk protocols dwl.1 dwl.c util.c util.h dwl.desktop \
+ config.mk protocols dwl.1 dwl.c gamepad.c gamepad.h util.c util.h dwl.desktop \
dwl-$(VERSION)
tar -caf dwl-$(VERSION).tar.gz dwl-$(VERSION)
rm -rf dwl-$(VERSION)
diff --git a/config.def.h b/config.def.h
index 8a6eda0..48270f6 100644
--- a/config.def.h
+++ b/config.def.h
@@ -165,6 +165,22 @@ static const Key keys[] = {
CHVT(7), CHVT(8), CHVT(9), CHVT(10), CHVT(11), CHVT(12),
};
+static const GamepadButton gamepadbuttons[] = {
+ { BTN_DPAD_DOWN, focusstack, {.i = +1} },
+ { BTN_DPAD_UP, focusstack, {.i = -1} },
+ { BTN_DPAD_LEFT, setmfact, {.f = -0.05f} },
+ { BTN_DPAD_RIGHT, setmfact, {.f = +0.05f} },
+ { BTN_SOUTH, zoom, {0} },
+ { BTN_EAST, setlayout, {.v = &layouts[0]} },
+ { BTN_NORTH, setlayout, {.v = &layouts[1]} },
+ { BTN_WEST, setlayout, {.v = &layouts[2]} },
+ { ABS_Z, focusmon, {.i = WLR_DIRECTION_LEFT} },
+ { ABS_RZ, focusmon, {.i = WLR_DIRECTION_RIGHT} },
+ { BTN_START, spawn, SHCMD("wmenu-run") },
+ { BTN_SELECT, winview, {0} },
+ { BTN_MODE, spawn, { "steam", NULL }},
+};
+
static const Button buttons[] = {
{ MODKEY, BTN_LEFT, moveresize, {.ui = CurMove} },
{ MODKEY, BTN_MIDDLE, togglefloating, {0} },
diff --git a/dwl.c b/dwl.c
index 101a45f..96e1c01 100644
--- a/dwl.c
+++ b/dwl.c
@@ -63,6 +63,7 @@
#include <wlr/util/log.h>
#include <wlr/util/region.h>
#include <xkbcommon/xkbcommon.h>
+#include "gamepad.h"
#ifdef XWAYLAND
#include <wlr/xwayland.h>
#include <xcb/xcb.h>
@@ -149,6 +150,12 @@ typedef struct {
const Arg arg;
} Key;
+typedef struct {
+ unsigned int button;
+ void (*func)(const Arg *);
+ const Arg arg;
+} GamepadButton;
+
typedef struct {
struct wlr_keyboard_group *wlr_group;
@@ -289,6 +296,7 @@ static void focusstack(const Arg *arg);
static Client *focustop(Monitor *m);
static void fullscreennotify(struct wl_listener *listener, void *data);
static void gpureset(struct wl_listener *listener, void *data);
+static void gamepadbutton(unsigned int button, int state);
static void handlesig(int signo);
static void incnmaster(const Arg *arg);
static void inputdevice(struct wl_listener *listener, void *data);
@@ -398,6 +406,7 @@ static struct wlr_session_lock_v1 *cur_lock;
static struct wlr_seat *seat;
static KeyboardGroup *kb_group;
+static struct gamepad *gamepad;
static unsigned int cursor_mode;
static Client *grabc;
static int grabcx, grabcy; /* client-relative */
@@ -713,6 +722,7 @@ cleanup(void)
wlr_xcursor_manager_destroy(cursor_mgr);
destroykeyboardgroup(&kb_group->destroy, NULL);
+ gamepad_destroy(gamepad);
/* If it's not destroyed manually, it will cause a use-after-free of wlr_seat.
* Destroy it until it's fixed on the wlroots side */
@@ -1558,6 +1568,21 @@ gpureset(struct wl_listener *listener, void *data)
wlr_renderer_destroy(old_drw);
}
+void
+gamepadbutton(unsigned int button, int state)
+{
+ const GamepadButton *b;
+ if (!state || locked)
+ return;
+ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
+ for (b = gamepadbuttons; b < END(gamepadbuttons); b++) {
+ if (button == b->button && b->func) {
+ b->func(&b->arg);
+ break;
+ }
+ }
+}
+
void
handlesig(int signo)
{
@@ -2643,6 +2668,7 @@ setup(void)
kb_group = createkeyboardgroup();
wl_list_init(&kb_group->destroy.link);
+ gamepad = gamepad_create(event_loop, session, gamepadbutton);
output_mgr = wlr_output_manager_v1_create(dpy);
wl_signal_add(&output_mgr->events.apply, &output_mgr_apply);
diff --git a/gamepad.c b/gamepad.c
new file mode 100644
index 0000000..6bad2f6
--- /dev/null
+++ b/gamepad.c
@@ -0,0 +1,255 @@
+#include <fcntl.h>
+#include <libevdev/libevdev.h>
+#include <libudev.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wayland-server-core.h>
+#include <wlr/backend/session.h>
+
+#include "gamepad.h"
+
+struct pad {
+ struct wl_list link;
+ char *path;
+ int fd;
+ struct libevdev *dev;
+ struct wl_event_source *src;
+ unsigned char key[KEY_CNT];
+ unsigned char abs[ABS_CNT];
+ int enabled;
+ GamepadHandler fn;
+};
+
+struct gamepad {
+ struct udev *udev;
+ struct udev_monitor *mon;
+ struct wl_event_source *msrc;
+ struct wl_event_loop *loop;
+ struct wl_list pads;
+ GamepadHandler fn;
+};
+
+static int
+ispad(struct udev_device *d)
+{
+ const char *p;
+
+ p = udev_device_get_property_value(d, "ID_INPUT_JOYSTICK");
+ return !strcmp(udev_device_get_subsystem(d), "input")
+ && !strncmp(udev_device_get_sysname(d), "event", 5)
+ && p && !strcmp(p, "1");
+}
+
+static void
+padstop(struct pad *p)
+{
+ if (p->src)
+ wl_event_source_remove(p->src);
+ if (p->dev)
+ libevdev_free(p->dev);
+ if (p->fd >= 0)
+ close(p->fd);
+ p->src = NULL;
+ p->dev = NULL;
+ p->fd = -1;
+}
+
+static void
+padclose(struct pad *p)
+{
+ padstop(p);
+ wl_list_remove(&p->link);
+ free(p->path);
+ free(p);
+}
+
+static int
+padin(int fd, uint32_t mask, void *data)
+{
+ struct pad *p = data;
+ struct input_event e;
+ int r, v;
+
+ if (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR)) {
+ padclose(p);
+ return 0;
+ }
+ while ((r = libevdev_next_event(p->dev, LIBEVDEV_READ_FLAG_NORMAL, &e)) == 0
+ || r == LIBEVDEV_READ_STATUS_SYNC) {
+ if (e.type == EV_KEY) {
+ v = !!e.value;
+ if (p->key[e.code] != v) {
+ p->key[e.code] = v;
+ if (p->enabled)
+ p->fn(e.code, v);
+ if ((e.code == BTN_TL || e.code == BTN_TR)
+ && p->key[BTN_TL] && p->key[BTN_TR] && v)
+ p->enabled ^= 1;
+ }
+ } else if (e.type == EV_ABS && (e.code == ABS_Z || e.code == ABS_RZ
+ || e.code == ABS_GAS || e.code == ABS_BRAKE)) {
+ const struct input_absinfo *a = libevdev_get_abs_info(p->dev, e.code);
+
+ v = e.value > (a->minimum + a->maximum) / 2;
+ if (p->abs[e.code] != v) {
+ p->abs[e.code] = v;
+ if (p->enabled)
+ p->fn(e.code, v);
+ }
+ } else if (e.type == EV_ABS && e.code == ABS_HAT0X) {
+ v = e.value + 1;
+ if (p->abs[e.code] != v) {
+ if (p->enabled) {
+ p->fn(BTN_DPAD_LEFT, 0);
+ p->fn(BTN_DPAD_RIGHT, 0);
+ }
+ p->abs[e.code] = v;
+ if (p->enabled) {
+ p->fn(BTN_DPAD_LEFT, e.value < 0);
+ p->fn(BTN_DPAD_RIGHT, e.value > 0);
+ }
+ }
+ } else if (e.type == EV_ABS && e.code == ABS_HAT0Y) {
+ v = e.value + 1;
+ if (p->abs[e.code] != v) {
+ if (p->enabled) {
+ p->fn(BTN_DPAD_UP, 0);
+ p->fn(BTN_DPAD_DOWN, 0);
+ }
+ p->abs[e.code] = v;
+ if (p->enabled) {
+ p->fn(BTN_DPAD_UP, e.value < 0);
+ p->fn(BTN_DPAD_DOWN, e.value > 0);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static void
+padstart(struct pad *p, struct wl_event_loop *loop)
+{
+ if (p->fd >= 0 || (p->fd = open(p->path, O_RDONLY | O_NONBLOCK | O_CLOEXEC)) < 0)
+ return;
+ if (libevdev_new_from_fd(p->fd, &p->dev)) {
+ close(p->fd);
+ p->fd = -1;
+ return;
+ }
+ if (!(p->src = wl_event_loop_add_fd(loop, p->fd, WL_EVENT_READABLE, padin, p)))
+ padstop(p);
+}
+
+static void
+padadd(struct gamepad *g, struct udev_device *d)
+{
+ struct pad *p;
+ struct pad *q;
+ const char *path;
+
+ if (!ispad(d) || !(path = udev_device_get_devnode(d)))
+ return;
+ wl_list_for_each(q, &g->pads, link) {
+ if (!strcmp(q->path, path))
+ return;
+ }
+ if (!(p = calloc(1, sizeof(*p))))
+ return;
+ if (!(p->path = strdup(path))) {
+ free(p);
+ return;
+ }
+ p->fd = -1;
+ p->enabled = 1;
+ p->fn = g->fn;
+ wl_list_insert(&g->pads, &p->link);
+ padstart(p, g->loop);
+}
+
+static void
+padremove(struct gamepad *g, const char *path)
+{
+ struct pad *p, *t;
+
+ wl_list_for_each_safe(p, t, &g->pads, link) {
+ if (!strcmp(p->path, path)) {
+ padclose(p);
+ break;
+ }
+ }
+}
+
+static int
+monin(int fd, uint32_t mask, void *data)
+{
+ struct gamepad *g = data;
+ struct udev_device *d;
+ const char *a;
+ const char *path;
+
+ if (!(d = udev_monitor_receive_device(g->mon)))
+ return 0;
+ a = udev_device_get_action(d);
+ path = udev_device_get_devnode(d);
+ if (a && !strcmp(a, "add"))
+ padadd(g, d);
+ else if (a && !strcmp(a, "remove") && path)
+ padremove(g, path);
+ udev_device_unref(d);
+ return 0;
+}
+
+struct gamepad *
+gamepad_create(struct wl_event_loop *loop, struct wlr_session *s, GamepadHandler fn)
+{
+ struct gamepad *g;
+ struct udev_enumerate *e;
+ struct udev_list_entry *l;
+ struct udev_device *d;
+
+ if (!s || !(g = calloc(1, sizeof(*g))) || !(g->udev = udev_new()))
+ return NULL;
+ g->loop = loop;
+ g->fn = fn;
+ wl_list_init(&g->pads);
+ if ((e = udev_enumerate_new(g->udev))) {
+ udev_enumerate_add_match_subsystem(e, "input");
+ udev_enumerate_scan_devices(e);
+ udev_list_entry_foreach(l, udev_enumerate_get_list_entry(e)) {
+ d = udev_device_new_from_syspath(g->udev, udev_list_entry_get_name(l));
+ if (d) {
+ padadd(g, d);
+ udev_device_unref(d);
+ }
+ }
+ udev_enumerate_unref(e);
+ }
+ if (!(g->mon = udev_monitor_new_from_netlink(g->udev, "udev"))
+ || udev_monitor_filter_add_match_subsystem_devtype(g->mon, "input", NULL)
+ || udev_monitor_enable_receiving(g->mon)
+ || !(g->msrc = wl_event_loop_add_fd(loop, udev_monitor_get_fd(g->mon), WL_EVENT_READABLE, monin, g))) {
+ gamepad_destroy(g);
+ return NULL;
+ }
+ return g;
+}
+
+void
+gamepad_destroy(struct gamepad *g)
+{
+ struct pad *p, *t;
+
+ if (!g)
+ return;
+ wl_list_for_each_safe(p, t, &g->pads, link)
+ padclose(p);
+ if (g->msrc)
+ wl_event_source_remove(g->msrc);
+ if (g->mon)
+ udev_monitor_unref(g->mon);
+ if (g->udev)
+ udev_unref(g->udev);
+ free(g);
+}
diff --git a/gamepad.h b/gamepad.h
new file mode 100644
index 0000000..5d45d28
--- /dev/null
+++ b/gamepad.h
@@ -0,0 +1,15 @@
+#ifndef GAMEPAD_H
+#define GAMEPAD_H
+
+#include <linux/input.h>
+
+struct gamepad;
+struct wl_event_loop;
+struct wlr_session;
+
+typedef void (*GamepadHandler)(unsigned int, int);
+
+struct gamepad *gamepad_create(struct wl_event_loop *, struct wlr_session *, GamepadHandler);
+void gamepad_destroy(struct gamepad *);
+
+#endif
+2 -1
View File
@@ -10,9 +10,10 @@ Examples provided:
- exclude certain keyboards (eg ydotool) from keyboard group - exclude certain keyboards (eg ydotool) from keyboard group
### Download ### Download
- [git branch](https://codeberg.org/bencc/dwl/src/branch/inputdevicerules) - [v0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/inputdevicerules/inputdevicerules-v0.8.patch)
- [v0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/inputdevicerules/inputdevicerules-v0.7.patch) - [v0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/inputdevicerules/inputdevicerules-v0.7.patch)
- [v0.6](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/inputdevicerules/inputdevicerules-v0.6.patch) - [v0.6](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/inputdevicerules/inputdevicerules-v0.6.patch)
### Authors ### Authors
- [Viktor Woloszczuk](https://codeberg.org/vwoloszczuk)
- [Ben Collerson](https://codeberg.org/bencc) - [Ben Collerson](https://codeberg.org/bencc)
@@ -0,0 +1,173 @@
From 31c8493d7f2a863949a91cd14769e28894f259e7 Mon Sep 17 00:00:00 2001
From: Viktor Woloszczuk <viktor@woloszcz.uk>
Date: Wed, 11 Mar 2026 19:41:02 +0000
Subject: [PATCH] input device rules (v0.8)
* customise input device handling
* ignore unwanted input devices
* configure a toggle for an input device
---
config.def.h | 13 ++++++++++
dwl.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 79 insertions(+), 2 deletions(-)
diff --git a/config.def.h b/config.def.h
index 8a6eda0..4dbcfd1 100644
--- a/config.def.h
+++ b/config.def.h
@@ -56,6 +56,18 @@ static const struct xkb_rule_names xkb_rules = {
.options = NULL,
};
+/* input devices */
+static const InputRule inputrules[] = {
+ /* name kbcreate ptrcreate */
+ /* ignore bad device - like a touchpad ;) */
+ { "BAD DEVICE", NULL, NULL },
+ /* ungroup ydotool device - fixes a bug */
+ { "ydotoold virtual device", createungroupedkeyboard, createpointer },
+ /* put your touchpad name here to enable toggle touchpad */
+ { "Elan Touchpad", createkeyboard, createtogglepointer },
+ { NULL, createkeyboard, createpointer },
+};
+
static const int repeat_rate = 25;
static const int repeat_delay = 600;
@@ -138,6 +150,7 @@ 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} },
+ { MODKEY, XKB_KEY_u, togglepointer, {0} },
{ MODKEY, XKB_KEY_0, view, {.ui = ~0} },
{ 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 44f3ad9..42557fe 100644
--- a/dwl.c
+++ b/dwl.c
@@ -141,6 +141,12 @@ typedef struct {
uint32_t resize; /* configure serial of a pending resize */
} Client;
+typedef struct {
+ const char *name;
+ void (*kbcreate)(struct wlr_keyboard *);
+ void (*ptrcreate)(struct wlr_pointer *);
+} InputRule;
+
typedef struct {
uint32_t mod;
xkb_keysym_t keysym;
@@ -268,6 +274,8 @@ static void createnotify(struct wl_listener *listener, void *data);
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 createtogglepointer(struct wlr_pointer *pointer);
+static void createungroupedkeyboard(struct wlr_keyboard *keyboard);
static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint);
static void cursorframe(struct wl_listener *listener, void *data);
static void cursorwarptohint(void);
@@ -336,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 togglepointer(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 +415,8 @@ static struct wlr_box sgeom;
static struct wl_list mons;
static Monitor *selmon;
+static struct libinput_device *togglepointerdevice = NULL;
+
/* global event handlers */
static struct wl_listener cursor_axis = {.notify = axisnotify};
static struct wl_listener cursor_button = {.notify = buttonpress};
@@ -1199,6 +1210,33 @@ createpopup(struct wl_listener *listener, void *data)
LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup);
}
+void
+createtogglepointer(struct wlr_pointer *pointer)
+{
+ struct libinput_device *device;
+
+ createpointer(pointer);
+
+ if (wlr_input_device_is_libinput(&pointer->base)
+ && (device = wlr_libinput_get_device_handle(&pointer->base))) {
+ togglepointerdevice = device;
+ }
+}
+
+void
+createungroupedkeyboard(struct wlr_keyboard *keyboard)
+{
+ /* for keyboards that need their own keyboard group */
+ KeyboardGroup *group = createkeyboardgroup();
+
+ /* Set the keymap to match the group keymap */
+ wlr_keyboard_set_keymap(keyboard, group->wlr_group->keyboard.keymap);
+ LISTEN(&keyboard->base.events.destroy, &group->destroy, destroykeyboardgroup);
+
+ /* Add the new keyboard to the group */
+ wlr_keyboard_group_add_keyboard(group->wlr_group, keyboard);
+}
+
void
cursorconstrain(struct wlr_pointer_constraint_v1 *constraint)
{
@@ -1582,13 +1620,27 @@ inputdevice(struct wl_listener *listener, void *data)
* available. */
struct wlr_input_device *device = data;
uint32_t caps;
+ const InputRule *r;
switch (device->type) {
case WLR_INPUT_DEVICE_KEYBOARD:
- createkeyboard(wlr_keyboard_from_input_device(device));
+ for (r = inputrules; r < END(inputrules); r++) {
+ if (!r->name || strstr(device->name, r->name)) {
+ if (r->kbcreate)
+ r->kbcreate(wlr_keyboard_from_input_device(device));
+ break;
+ }
+ }
+
break;
case WLR_INPUT_DEVICE_POINTER:
- createpointer(wlr_pointer_from_input_device(device));
+ for (r = inputrules; r < END(inputrules); r++) {
+ if (!r->name || strstr(device->name, r->name)) {
+ if (r->ptrcreate)
+ r->ptrcreate(wlr_pointer_from_input_device(device));
+ break;
+ }
+ }
break;
default:
/* TODO handle other input device types */
@@ -2760,6 +2812,18 @@ togglefullscreen(const Arg *arg)
setfullscreen(sel, !sel->isfullscreen);
}
+void
+togglepointer(const Arg *arg)
+{
+ if (!togglepointerdevice)
+ return;
+
+ libinput_device_config_send_events_set_mode(
+ togglepointerdevice,
+ libinput_device_config_send_events_get_mode(togglepointerdevice) ^ LIBINPUT_CONFIG_SEND_EVENTS_DISABLED
+ );
+}
+
void
toggletag(const Arg *arg)
{
--
2.53.0
+2 -1
View File
@@ -10,10 +10,11 @@ This patch adds the following functions:
If you don't assign keybindings to any of the above functions and so get a compiler warning about them not being used, just remove them from your dwl branch to stop the warning. If you don't assign keybindings to any of the above functions and so get a compiler warning about them not being used, just remove them from your dwl branch to stop the warning.
### Download ### Download
- [git branch (v0.6)](https://codeberg.org/bencc/dwl/src/branch/namedscratchpads)
- [2024-07-13 (v0.6)](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/namedscratchpads/namedscratchpads.patch) - [2024-07-13 (v0.6)](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/namedscratchpads/namedscratchpads.patch)
- [namedscratchpads-0.8.patch](/dwl/dwl-patches/raw/branch/main/patches/namedscratchpads/namedscratchpads-0.8.patch)
### Authors ### Authors
- [nshan651](https://codeberg.org/nshan651)
- [Ben Collerson](https://codeberg.org/bencc) - [Ben Collerson](https://codeberg.org/bencc)
- [wochap](https://codeberg.org/wochap) - [wochap](https://codeberg.org/wochap)
- [Louis-Michel Raynauld](https://github.com/loumray) - [Louis-Michel Raynauld](https://github.com/loumray)
@@ -0,0 +1,277 @@
From 40ef197886f402c44a5a5c6856478cad5277e0bb Mon Sep 17 00:00:00 2001
From: nshan651 <nshan651@proton.me>
Date: Fri, 19 Jun 2026 13:04:21 -0500
Subject: [PATCH 1/2] namedscratchpads: v0.8 compatibility
---
config.def.h | 11 ++++++++---
dwl.c | 39 +++++++++++++++++++++++++++++++++++++++
2 files changed, 47 insertions(+), 3 deletions(-)
diff --git a/config.def.h b/config.def.h
index 8a6eda0..79b4efb 100644
--- a/config.def.h
+++ b/config.def.h
@@ -21,9 +21,10 @@ static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You ca
static int log_level = WLR_ERROR;
static const Rule rules[] = {
- /* app_id title tags mask isfloating monitor */
- { "Gimp_EXAMPLE", NULL, 0, 1, -1 }, /* Start on currently visible tags floating, not tiled */
- { "firefox_EXAMPLE", NULL, 1 << 8, 0, -1 }, /* Start on ONLY tag "9" */
+ /* app_id title tags mask isfloating monitor scratchkey */
+ { "Gimp_EXAMPLE", NULL, 0, 1, -1, 0 }, /* Start on currently visible tags floating, not tiled */
+ { "firefox_EXAMPLE", NULL, 1 << 8, 0, -1, 0 }, /* Start on ONLY tag "9" */
+ { NULL, "scratchpad", 0, 1, -1, 's' },
/* default/example rule: can be changed but cannot be eliminated; at least one rule must exist */
};
@@ -118,11 +119,15 @@ static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TA
static const char *termcmd[] = { "foot", NULL };
static const char *menucmd[] = { "wmenu-run", NULL };
+/* named scratchpads - First arg only serves to match against key in rules*/
+static const char *scratchpadcmd[] = { "s", "foot", "-T", "scratchpad", NULL };
+
static const Key keys[] = {
/* Note that Shift changes certain key codes: 2 -> at, etc. */
/* modifier key function argument */
{ MODKEY, XKB_KEY_p, spawn, {.v = menucmd} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
+ { MODKEY, XKB_KEY_grave, togglescratch, {.v = scratchpadcmd } },
{ MODKEY, XKB_KEY_j, focusstack, {.i = +1} },
{ MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
{ MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
diff --git a/dwl.c b/dwl.c
index 44f3ad9..3e3db4c 100644
--- a/dwl.c
+++ b/dwl.c
@@ -138,6 +138,7 @@ typedef struct {
unsigned int bw;
uint32_t tags;
int isfloating, isurgent, isfullscreen;
+ char scratchkey;
uint32_t resize; /* configure serial of a pending resize */
} Client;
@@ -228,6 +229,7 @@ typedef struct {
uint32_t tags;
int isfloating;
int monitor;
+ const char scratchkey;
} Rule;
typedef struct {
@@ -330,12 +332,14 @@ static void setpsel(struct wl_listener *listener, void *data);
static void setsel(struct wl_listener *listener, void *data);
static void setup(void);
static void spawn(const Arg *arg);
+static void spawnscratch(const Arg *arg);
static void startdrag(struct wl_listener *listener, void *data);
static void tag(const Arg *arg);
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 togglescratch(const Arg *arg);
static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
static void unlocksession(struct wl_listener *listener, void *data);
@@ -483,6 +487,7 @@ applyrules(Client *c)
const Rule *r;
Monitor *mon = selmon, *m;
+ c->scratchkey = 0;
appid = client_get_appid(c);
title = client_get_title(c);
@@ -490,6 +495,7 @@ applyrules(Client *c)
if ((!r->title || strstr(title, r->title))
&& (!r->id || strstr(appid, r->id))) {
c->isfloating = r->isfloating;
+ c->scratchkey = r->scratchkey;
newtags |= r->tags;
i = 0;
wl_list_for_each(m, &mons, link) {
@@ -2677,6 +2683,16 @@ spawn(const Arg *arg)
}
}
+void spawnscratch(const Arg *arg)
+{
+ if (fork() == 0) {
+ dup2(STDERR_FILENO, STDOUT_FILENO);
+ setsid();
+ execvp(((char **)arg->v)[1], ((char **)arg->v)+1);
+ die("dwl: execvp %s failed:", ((char **)arg->v)[1]);
+ }
+}
+
void
startdrag(struct wl_listener *listener, void *data)
{
@@ -2760,6 +2776,29 @@ togglefullscreen(const Arg *arg)
setfullscreen(sel, !sel->isfullscreen);
}
+void
+togglescratch(const Arg *arg)
+{
+ Client *c;
+ unsigned int found = 0;
+
+ /* search for first window that matches the scratchkey */
+ wl_list_for_each(c, &clients, link)
+ if (c->scratchkey == ((char**)arg->v)[0][0]) {
+ found = 1;
+ break;
+ }
+
+ if (found) {
+ c->tags = VISIBLEON(c, selmon) ? 0 : selmon->tagset[selmon->seltags];
+
+ focusclient(c->tags == 0 ? focustop(selmon) : c, 1);
+ arrange(selmon);
+ } else{
+ spawnscratch(arg);
+ }
+}
+
void
toggletag(const Arg *arg)
{
--
2.52.0
From e21146a0924c5940c7fb912d0c99790e2553b613 Mon Sep 17 00:00:00 2001
From: nshan651 <nshan651@proton.me>
Date: Fri, 19 Jun 2026 13:05:33 -0500
Subject: [PATCH 2/2] namedscratchpads: focusortoggle functions v0.8
---
config.def.h | 2 ++
dwl.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 89 insertions(+)
diff --git a/config.def.h b/config.def.h
index 79b4efb..e253862 100644
--- a/config.def.h
+++ b/config.def.h
@@ -128,6 +128,8 @@ static const Key keys[] = {
{ MODKEY, XKB_KEY_p, spawn, {.v = menucmd} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
{ MODKEY, XKB_KEY_grave, togglescratch, {.v = scratchpadcmd } },
+ // { MODKEY, XKB_KEY_grave, focusortogglescratch, {.v = scratchpadcmd } },
+ // { MODKEY, XKB_KEY_grave, focusortogglematchingscratch, {.v = scratchpadcmd } },
{ MODKEY, XKB_KEY_j, focusstack, {.i = +1} },
{ MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
{ MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
diff --git a/dwl.c b/dwl.c
index 3e3db4c..0f406d9 100644
--- a/dwl.c
+++ b/dwl.c
@@ -286,6 +286,8 @@ static void destroykeyboardgroup(struct wl_listener *listener, void *data);
static Monitor *dirtomon(enum wlr_direction dir);
static void focusclient(Client *c, int lift);
static void focusmon(const Arg *arg);
+static void focusortogglematchingscratch(const Arg *arg);
+static void focusortogglescratch(const Arg *arg);
static void focusstack(const Arg *arg);
static Client *focustop(Monitor *m);
static void fullscreennotify(struct wl_listener *listener, void *data);
@@ -1491,6 +1493,91 @@ focusmon(const Arg *arg)
focusclient(focustop(selmon), 1);
}
+void
+focusortogglematchingscratch(const Arg *arg)
+{
+ Client *c;
+ unsigned int found = 0;
+ unsigned int hide = 0;
+
+ wl_list_for_each(c, &clients, link) {
+ if (c->scratchkey == 0) {
+ continue;
+ }
+ if (c->scratchkey == ((char**)arg->v)[0][0]) {
+ if (VISIBLEON(c, selmon)) {
+ if (found == 1) {
+ if (hide == 1) {
+ c->tags = 0;
+ focusclient(focustop(selmon), 1);
+ }
+ continue;
+ }
+ if (focustop(selmon) == c) {
+ // hide
+ c->tags = 0;
+ focusclient(focustop(selmon), 1);
+ hide = 1;
+ } else {
+ // focus
+ focusclient(c, 1);
+ }
+ } else {
+ // show
+ c->tags = selmon->tagset[selmon->seltags];
+ // focus
+ focusclient(c, 1);
+ }
+ found = 1;
+ continue;
+ }
+ if (VISIBLEON(c, selmon)) {
+ // hide
+ c->tags = 0;
+ }
+ }
+
+ if (found) {
+ arrange(selmon);
+ } else {
+ spawnscratch(arg);
+ }
+}
+
+void
+focusortogglescratch(const Arg *arg)
+{
+ Client *c;
+ unsigned int found = 0;
+
+ /* search for first window that matches the scratchkey */
+ wl_list_for_each(c, &clients, link)
+ if (c->scratchkey == ((char**)arg->v)[0][0]) {
+ found = 1;
+ break;
+ }
+
+ if (found) {
+ if (VISIBLEON(c, selmon)) {
+ if (focustop(selmon) == c) {
+ // hide
+ c->tags = 0;
+ focusclient(focustop(selmon), 1);
+ } else {
+ // focus
+ focusclient(c, 1);
+ }
+ } else {
+ // show
+ c->tags = selmon->tagset[selmon->seltags];
+ focusclient(c, 1);
+ }
+ arrange(selmon);
+ } else{
+ spawnscratch(arg);
+ }
+}
+
void
focusstack(const Arg *arg)
{
--
2.52.0
@@ -27,7 +27,7 @@ index 8101ffa..7f4d059 100644
struct wlr_xwayland_surface *xwayland; struct wlr_xwayland_surface *xwayland;
} surface; } surface;
struct wlr_xdg_toplevel_decoration_v1 *decoration; struct wlr_xdg_toplevel_decoration_v1 *decoration;
+ struct wlr_ext_foreign_toplevel_handle_v1 *foreign_toplevel; + struct wlr_ext_foreign_toplevel_handle_v1 *ext_foreign_toplevel;
struct wl_listener commit; struct wl_listener commit;
struct wl_listener map; struct wl_listener map;
struct wl_listener maximize; struct wl_listener maximize;
@@ -63,9 +63,9 @@ index 8101ffa..7f4d059 100644
static struct wlr_scene_rect *locked_bg; static struct wlr_scene_rect *locked_bg;
static struct wlr_session_lock_v1 *cur_lock; static struct wlr_session_lock_v1 *cur_lock;
+static struct wlr_ext_foreign_toplevel_list_v1 *foreign_toplevel_list; +static struct wlr_ext_foreign_toplevel_list_v1 *ext_foreign_toplevel_list;
+static struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 *toplevel_capture_mgr; +static struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 *toplevel_capture_mgr;
+static struct wl_listener foreign_toplevel_capture_request = {.notify = handlecapturerequest}; +static struct wl_listener ext_foreign_toplevel_capture_request = {.notify = handlecapturerequest};
+ +
static struct wlr_seat *seat; static struct wlr_seat *seat;
static KeyboardGroup *kb_group; static KeyboardGroup *kb_group;
@@ -90,7 +90,7 @@ index 8101ffa..7f4d059 100644
wl_list_remove(&request_start_drag.link); wl_list_remove(&request_start_drag.link);
wl_list_remove(&start_drag.link); wl_list_remove(&start_drag.link);
wl_list_remove(&new_session_lock.link); wl_list_remove(&new_session_lock.link);
+ wl_list_remove(&foreign_toplevel_capture_request.link); + wl_list_remove(&ext_foreign_toplevel_capture_request.link);
#ifdef XWAYLAND #ifdef XWAYLAND
wl_list_remove(&new_xwayland_surface.link); wl_list_remove(&new_xwayland_surface.link);
wl_list_remove(&xwayland_ready.link); wl_list_remove(&xwayland_ready.link);
@@ -107,7 +107,7 @@ index 8101ffa..7f4d059 100644
+ struct wlr_ext_image_capture_source_v1 *source; + struct wlr_ext_image_capture_source_v1 *source;
+ +
+ wl_list_for_each(c, &clients, link) { + wl_list_for_each(c, &clients, link) {
+ if (c->foreign_toplevel != req->toplevel_handle) + if (c->ext_foreign_toplevel != req->toplevel_handle)
+ continue; + continue;
+ +
+ cs = ecalloc(1, sizeof(*cs)); + cs = ecalloc(1, sizeof(*cs));
@@ -145,7 +145,7 @@ index 8101ffa..7f4d059 100644
+ .title = client_get_title(c), + .title = client_get_title(c),
+ .app_id = client_get_appid(c), + .app_id = client_get_appid(c),
+ }; + };
+ c->foreign_toplevel = wlr_ext_foreign_toplevel_handle_v1_create(foreign_toplevel_list, &ft_state); + c->ext_foreign_toplevel = wlr_ext_foreign_toplevel_handle_v1_create(ext_foreign_toplevel_list, &ft_state);
+ } + }
+ +
/* Set initial monitor, tags, floating status, and focus: /* Set initial monitor, tags, floating status, and focus:
@@ -155,9 +155,9 @@ index 8101ffa..7f4d059 100644
wlr_presentation_create(dpy, backend, 2); wlr_presentation_create(dpy, backend, 2);
wlr_alpha_modifier_v1_create(dpy); wlr_alpha_modifier_v1_create(dpy);
+ foreign_toplevel_list = wlr_ext_foreign_toplevel_list_v1_create(dpy, 1); + ext_foreign_toplevel_list = wlr_ext_foreign_toplevel_list_v1_create(dpy, 1);
+ toplevel_capture_mgr = wlr_ext_foreign_toplevel_image_capture_source_manager_v1_create(dpy, 1); + toplevel_capture_mgr = wlr_ext_foreign_toplevel_image_capture_source_manager_v1_create(dpy, 1);
+ wl_signal_add(&toplevel_capture_mgr->events.new_request, &foreign_toplevel_capture_request); + wl_signal_add(&toplevel_capture_mgr->events.new_request, &ext_foreign_toplevel_capture_request);
+ +
/* Initializes the interface used to implement urgency hints */ /* Initializes the interface used to implement urgency hints */
activation = wlr_xdg_activation_v1_create(dpy); activation = wlr_xdg_activation_v1_create(dpy);
@@ -166,9 +166,9 @@ index 8101ffa..7f4d059 100644
wl_list_remove(&c->flink); wl_list_remove(&c->flink);
} }
+ if (c->foreign_toplevel) { + if (c->ext_foreign_toplevel) {
+ wlr_ext_foreign_toplevel_handle_v1_destroy(c->foreign_toplevel); + wlr_ext_foreign_toplevel_handle_v1_destroy(c->ext_foreign_toplevel);
+ c->foreign_toplevel = NULL; + c->ext_foreign_toplevel = NULL;
+ } + }
+ +
wlr_scene_node_destroy(&c->scene->node); wlr_scene_node_destroy(&c->scene->node);
@@ -179,12 +179,12 @@ index 8101ffa..7f4d059 100644
if (c == focustop(c->mon)) if (c == focustop(c->mon))
printstatus(); printstatus();
+ +
+ if (c->foreign_toplevel) { + if (c->ext_foreign_toplevel) {
+ struct wlr_ext_foreign_toplevel_handle_v1_state ft_state = { + struct wlr_ext_foreign_toplevel_handle_v1_state ft_state = {
+ .title = client_get_title(c), + .title = client_get_title(c),
+ .app_id = client_get_appid(c), + .app_id = client_get_appid(c),
+ }; + };
+ wlr_ext_foreign_toplevel_handle_v1_update_state(c->foreign_toplevel, &ft_state); + wlr_ext_foreign_toplevel_handle_v1_update_state(c->ext_foreign_toplevel, &ft_state);
+ } + }
} }
+4 -5
View File
@@ -2,12 +2,11 @@
Like smartborders. Don't put borders when there is only one window on the screen. Like smartborders. Don't put borders when there is only one window on the screen.
The patch for tag v0.7 below appears to apply cleanly to the current HEAD of
upstream/main as at 2024-10-11.
### Download ### Download
- [git branch](https://codeberg.org/bencc/dwl/src/branch/simpleborders) - [git branch](https://codeberg.org/bencc/dwl/src/branch/simpleborders)
- [v0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/simpleborders/simpleborders-v0.7.patch) - [simpleborders-wlroots-next-f4249db](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/simpleborders/simpleborders-wlroots-next-f4249db.patch)
- [v0.6](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/simpleborders/simpleborders-v0.6.patch) - [simpleborders-0.8.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/simpleborders/simpleborders-v0.8.patch)
### Authors ### Authors
- [A Frederick Christensen](https://codeberg.org/fauxmight)
- [Ben Collerson](https://codeberg.org/bencc) - [Ben Collerson](https://codeberg.org/bencc)
@@ -1,34 +1,34 @@
From 681e520deaeee460647de36f5312af3cb0c31f4a Mon Sep 17 00:00:00 2001 From 41eb0c0d196d302790ae87a5ca1a4da660864f10 Mon Sep 17 00:00:00 2001
From: Ben Collerson <benc@benc.cc> From: A Frederick Christensen <dwl@ivories.org>
Date: Sat, 30 Dec 2023 13:39:31 +1000 Date: Wed, 25 Feb 2026 20:11:56 -0600
Subject: [PATCH] simpleborders Subject: [PATCH] Apply simpleborders patch
--- ---
dwl.c | 22 ++++++++++++++++++++++ dwl.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+) 1 file changed, 22 insertions(+)
diff --git a/dwl.c b/dwl.c diff --git a/dwl.c b/dwl.c
index 4d19357..900e651 100644 index 44f3ad9..defe2a8 100644
--- a/dwl.c --- a/dwl.c
+++ b/dwl.c +++ b/dwl.c
@@ -245,6 +245,7 @@ static void cleanupmon(struct wl_listener *listener, void *data); @@ -257,6 +257,7 @@ static void closemon(Monitor *m);
static void closemon(Monitor *m);
static void commitlayersurfacenotify(struct wl_listener *listener, void *data); static void commitlayersurfacenotify(struct wl_listener *listener, void *data);
static void commitnotify(struct wl_listener *listener, void *data); static void commitnotify(struct wl_listener *listener, void *data);
static void commitpopup(struct wl_listener *listener, void *data);
+static int countclients(Monitor *m); +static int countclients(Monitor *m);
static void createdecoration(struct wl_listener *listener, void *data); static void createdecoration(struct wl_listener *listener, void *data);
static void createidleinhibitor(struct wl_listener *listener, void *data); static void createidleinhibitor(struct wl_listener *listener, void *data);
static void createkeyboard(struct wlr_keyboard *keyboard); static void createkeyboard(struct wlr_keyboard *keyboard);
@@ -286,6 +287,7 @@ static void motionabsolute(struct wl_listener *listener, void *data); @@ -305,6 +306,7 @@ static void motionnotify(uint32_t time, struct wlr_input_device *device, double
static void motionnotify(uint32_t time); double sy, double sx_unaccel, double sy_unaccel);
static void motionrelative(struct wl_listener *listener, void *data); static void motionrelative(struct wl_listener *listener, void *data);
static void moveresize(const Arg *arg); static void moveresize(const Arg *arg);
+static int needsborder(Client *c); +static int needsborder(Client *c);
static void outputmgrapply(struct wl_listener *listener, void *data); static void outputmgrapply(struct wl_listener *listener, void *data);
static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test); static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test);
static void outputmgrtest(struct wl_listener *listener, void *data); static void outputmgrtest(struct wl_listener *listener, void *data);
@@ -739,6 +741,17 @@ commitnotify(struct wl_listener *listener, void *data) @@ -915,6 +917,17 @@ commitpopup(struct wl_listener *listener, void *data)
c->resize = 0; free(listener);
} }
+int +int
@@ -45,7 +45,7 @@ index 4d19357..900e651 100644
void void
createdecoration(struct wl_listener *listener, void *data) createdecoration(struct wl_listener *listener, void *data)
{ {
@@ -1697,6 +1710,14 @@ moveresize(const Arg *arg) @@ -1980,6 +1993,14 @@ moveresize(const Arg *arg)
} }
} }
@@ -60,8 +60,8 @@ index 4d19357..900e651 100644
void void
outputmgrapply(struct wl_listener *listener, void *data) outputmgrapply(struct wl_listener *listener, void *data)
{ {
@@ -1930,6 +1951,7 @@ resize(Client *c, struct wlr_box geo, int interact) @@ -2215,6 +2236,7 @@ resize(Client *c, struct wlr_box geo, int interact)
struct wlr_box clip;
client_set_bounds(c, geo.width, geo.height); client_set_bounds(c, geo.width, geo.height);
c->geom = geo; c->geom = geo;
+ c->bw = needsborder(c) ? borderpx : 0; + c->bw = needsborder(c) ? borderpx : 0;
@@ -69,5 +69,5 @@ index 4d19357..900e651 100644
/* Update scene-graph, including borders */ /* Update scene-graph, including borders */
-- --
2.43.0 2.52.0
@@ -1,14 +1,14 @@
From 09759c3ef75158c366e9fc63814485fbb31a3ccf Mon Sep 17 00:00:00 2001 From 33364ee84f8063813fbdb8b319965a87f63e2694 Mon Sep 17 00:00:00 2001
From: Ben Collerson <benc@benc.cc> From: A Frederick Christensen <dwl@ivories.org>
Date: Sat, 30 Dec 2023 13:39:31 +1000 Date: Wed, 25 Feb 2026 20:14:28 -0600
Subject: [PATCH] simpleborders Subject: [PATCH] Apply simpleborders patch
--- ---
dwl.c | 22 ++++++++++++++++++++++ dwl.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+) 1 file changed, 22 insertions(+)
diff --git a/dwl.c b/dwl.c diff --git a/dwl.c b/dwl.c
index a2711f67..415fe1a0 100644 index 8a9715d..a3caac8 100644
--- a/dwl.c --- a/dwl.c
+++ b/dwl.c +++ b/dwl.c
@@ -259,6 +259,7 @@ static void closemon(Monitor *m); @@ -259,6 +259,7 @@ static void closemon(Monitor *m);
@@ -19,7 +19,7 @@ index a2711f67..415fe1a0 100644
static void createdecoration(struct wl_listener *listener, void *data); static void createdecoration(struct wl_listener *listener, void *data);
static void createidleinhibitor(struct wl_listener *listener, void *data); static void createidleinhibitor(struct wl_listener *listener, void *data);
static void createkeyboard(struct wlr_keyboard *keyboard); static void createkeyboard(struct wlr_keyboard *keyboard);
@@ -308,6 +309,7 @@ static void motionnotify(uint32_t time, struct wlr_input_device *device, double @@ -307,6 +308,7 @@ static void motionnotify(uint32_t time, struct wlr_input_device *device, double
double sy, double sx_unaccel, double sy_unaccel); double sy, double sx_unaccel, double sy_unaccel);
static void motionrelative(struct wl_listener *listener, void *data); static void motionrelative(struct wl_listener *listener, void *data);
static void moveresize(const Arg *arg); static void moveresize(const Arg *arg);
@@ -27,8 +27,8 @@ index a2711f67..415fe1a0 100644
static void outputmgrapply(struct wl_listener *listener, void *data); static void outputmgrapply(struct wl_listener *listener, void *data);
static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test); static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test);
static void outputmgrtest(struct wl_listener *listener, void *data); static void outputmgrtest(struct wl_listener *listener, void *data);
@@ -849,6 +851,17 @@ commitpopup(struct wl_listener *listener, void *data) @@ -917,6 +919,17 @@ commitpopup(struct wl_listener *listener, void *data)
wl_list_remove(&listener->link); free(listener);
} }
+int +int
@@ -45,7 +45,7 @@ index a2711f67..415fe1a0 100644
void void
createdecoration(struct wl_listener *listener, void *data) createdecoration(struct wl_listener *listener, void *data)
{ {
@@ -1927,6 +1940,14 @@ moveresize(const Arg *arg) @@ -1982,6 +1995,14 @@ moveresize(const Arg *arg)
} }
} }
@@ -60,7 +60,7 @@ index a2711f67..415fe1a0 100644
void void
outputmgrapply(struct wl_listener *listener, void *data) outputmgrapply(struct wl_listener *listener, void *data)
{ {
@@ -2190,6 +2211,7 @@ resize(Client *c, struct wlr_box geo, int interact) @@ -2217,6 +2238,7 @@ resize(Client *c, struct wlr_box geo, int interact)
client_set_bounds(c, geo.width, geo.height); client_set_bounds(c, geo.width, geo.height);
c->geom = geo; c->geom = geo;
@@ -69,5 +69,5 @@ index a2711f67..415fe1a0 100644
/* Update scene-graph, including borders */ /* Update scene-graph, including borders */
-- --
2.45.2 2.52.0