mirror of
https://codeberg.org/dwl/dwl-patches.git
synced 2026-06-13 19:33:21 +00:00
Compare commits
138 Commits
a5ebe7260d
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 493dc4c408 | |||
| 33acb045a8 | |||
| bbe1199e40 | |||
| 1f0e82bf5d | |||
| 5483e1d437 | |||
| 30c33ed26c | |||
| 03de6e2ada | |||
| 7f06b4c1a3 | |||
| d7471ef29e | |||
| 5d2f27a9f9 | |||
| 2bfdd50f98 | |||
| ea5c2c7439 | |||
| 39f54a89fa | |||
| 1587a40514 | |||
| 4e3a344e8d | |||
| 8a67e8712a | |||
| e55349448e | |||
| f584a2dead | |||
| dbb6a3aa22 | |||
| 726164473f | |||
| 872b565e85 | |||
| 8809817422 | |||
| 4e2adff067 | |||
| c0c3761b30 | |||
| e3bf9a3d04 | |||
| 2d4463dd83 | |||
| 8a58a7c1c4 | |||
| b2c87f505f | |||
| 998808b303 | |||
| 24fa6e04ce | |||
| 039be1a6cf | |||
| ee75e70f79 | |||
| 6d4b7d3a57 | |||
| 8ac41e9d73 | |||
| 50651a80d2 | |||
| 79de70e29e | |||
| 6abdb9f50c | |||
| 05895bbe1b | |||
| 36439e54ba | |||
| 870a322831 | |||
| 5ccc71e0b5 | |||
| 52a7559a87 | |||
| ca06146655 | |||
| abba4e9ad0 | |||
| ee54a3413c | |||
| 000aa7d15c | |||
| 722f0573eb | |||
| 3ade6519ac | |||
| 1b490e51a9 | |||
| 4774631436 | |||
| 16ae2a3a87 | |||
| 6882f753c5 | |||
| 585f636ea1 | |||
| f46616216f | |||
| 341d6d1fd3 | |||
| a20a103242 | |||
| e1ad73d51c | |||
| 0f2cd0555a | |||
| 99c3aeb1ed | |||
| 9481ea7ea3 | |||
| 58e371fcb3 | |||
| 898bc7a946 | |||
| 507f76f981 | |||
| 97b9dbc1e6 | |||
| f8d1cfad11 | |||
| 0ddfff3376 | |||
| cca388a012 | |||
| c5b24427c7 | |||
| 77df1eb16e | |||
| f4039c0252 | |||
| 1b063e68bb | |||
| 1988d629ec | |||
| d36b83b31e | |||
| e1fa126693 | |||
| 3e627686a3 | |||
| 47d7e4d5ac | |||
| 32701fc108 | |||
| c916b773fd | |||
| a34e01519d | |||
| 43f5416503 | |||
| 59212b702c | |||
| 2e03d8ec91 | |||
| 76074da43e | |||
| 4530d00908 | |||
| 8c860178df | |||
| 1578f75740 | |||
| d2f3e1b77a | |||
| 06e9b2f651 | |||
| 0395bbbb8f | |||
| de70628d0a | |||
| e9916e4319 | |||
| 7f261214e1 | |||
| 17f0bd9db4 | |||
| 8e7aeec9c6 | |||
| 0870c51872 | |||
| 56dd65b30d | |||
| 14f48c24e8 | |||
| c0406e3c63 | |||
| a9c57d0698 | |||
| 613d9c8639 | |||
| e547aa64b9 | |||
| 955529b809 | |||
| e85e01efd3 | |||
| e4130ff865 | |||
| e240c8bf84 | |||
| 03e6e72b41 | |||
| 010b4b70be | |||
| 7c70e204b8 | |||
| 46021333a1 | |||
| 5493b6dd94 | |||
| 973df560ec | |||
| e104ef3495 | |||
| 6b9258972f | |||
| ca2a322d20 | |||
| d181bd4f4b | |||
| 7be608e4ed | |||
| 10a056e882 | |||
| 945c1de501 | |||
| b74ed046e6 | |||
| 0a6759e881 | |||
| 3f25b6c7d4 | |||
| 4263f5be4d | |||
| c13663c38f | |||
| e11f687751 | |||
| 3348962148 | |||
| 419d3a44e3 | |||
| 1742d5febc | |||
| 770aad7716 | |||
| be8b24ad2c | |||
| 7ffea896fa | |||
| 214d0e400d | |||
| be0f7b5674 | |||
| 161c62ae6c | |||
| adda83d5c4 | |||
| a88f72efa9 | |||
| c552c48146 | |||
| 348dc2ed33 | |||
| f85897237a |
@@ -37,8 +37,9 @@ If you target the unstable `main` branch, specify that in the `Download` link on
|
||||
^^^ "0.7" is an example. Use the release that your patch targets
|
||||
- [main YYYY-MM-DD](/dwl/dwl-patches/raw/branch/main/patches/PATCHNAME/PATCHNAME.patch)
|
||||
^^^^^^^^^^ Patches targeting the unstable "main" branch include a YYYY-MM-DD indicator
|
||||
### Authors - latest at top [Codeberg nick is mandatory; other contact methods optional]
|
||||
### Authors - latest at top
|
||||
- [YOUR_NICK](https://codeberg.org/USERNAME)
|
||||
^^^^^^^^^ Codeberg nick is mandatory; other contact methods optional
|
||||
your_email@if_you_wish_to.share.it
|
||||
your_irc_nick at [Libera IRC dwl channel](https://web.libera.chat/?channels=#dwl)
|
||||
your_discord_handle at [dwl Discord](https://discord.gg/jJxZnrGPWN)
|
||||
@@ -46,9 +47,9 @@ If you target the unstable `main` branch, specify that in the `Download` link on
|
||||
You may choose to include screenshots (hosted in your patch's subdirectory) in your `README.md`. The process is described [here](https://docs.codeberg.org/markdown/using-images/).
|
||||
|
||||
8. Use the Codeberg web interface to send a pull request to [dwl-patches] (NOT to [dwl])
|
||||
9. WHEN YOUR PULL REQUEST IS APPROVED, your Codeberg account will also be granted commit access to [dwl-patches]. Once you have write access, you can make direct modifications/upates to your patches and you are free to create new patches rather than creating pull requests.
|
||||
9. WHEN YOUR PULL REQUEST IS APPROVED, your Codeberg account will also be granted commit access to [dwl-patches]. Once you have write access, you can make direct modifications/updates to your patches and you are free to create new patches rather than creating pull requests.
|
||||
|
||||
Individuals who have made known that they no longer intend to maintain their patches will have commit access to the [dwl-pathces] repository removed.
|
||||
Individuals who have made known that they no longer intend to maintain their patches will have commit access to the [dwl-patches] repository removed.
|
||||
|
||||
A returning user who formerly had commit access is welcome to open an issue on [dwl-patches] requesting commit access be reinstated. When doing so, please link to the original issue opened that granted commit access.
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ Automatically center floating windows.
|
||||
|
||||
### Download
|
||||
- [git branch](https://codeberg.org/guidocella/dwl/src/branch/alwayscenter)
|
||||
- [2024-06-05](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/alwayscenter/alwayscenter.patch)
|
||||
- [2026-01-15](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/alwayscenter/alwayscenter.patch)
|
||||
|
||||
### Authors
|
||||
- [Guido Cella](https://codeberg.org/guidocella)
|
||||
|
||||
@@ -1,39 +1,25 @@
|
||||
From f43a49324c2ddd21100d6308d1adde9d894746e2 Mon Sep 17 00:00:00 2001
|
||||
From 48110f0443c8e1ddcd56b6fed5da46535024919c Mon Sep 17 00:00:00 2001
|
||||
From: Guido Cella <guido@guidocella.xyz>
|
||||
Date: Wed, 5 Jun 2024 12:05:16 +0200
|
||||
Date: Tue, 13 Jan 2026 21:17:22 +0100
|
||||
Subject: [PATCH] center floating windows
|
||||
|
||||
---
|
||||
dwl.c | 9 +++++++++
|
||||
1 file changed, 9 insertions(+)
|
||||
dwl.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 12f441e..c377c67 100644
|
||||
index 44f3ad9..72714f8 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -499,6 +499,11 @@ applyrules(Client *c)
|
||||
}
|
||||
@@ -2414,6 +2414,8 @@ setmon(Client *c, Monitor *m, uint32_t newtags)
|
||||
/* Make sure window actually overlaps with the monitor */
|
||||
resize(c, c->geom, 0);
|
||||
c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */
|
||||
+ c->prev.x = (m->w.width - c->prev.width) / 2 + m->m.x;
|
||||
+ c->prev.y = (m->w.height - c->prev.height) / 2 + m->m.y;
|
||||
setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */
|
||||
setfloating(c, c->isfloating);
|
||||
}
|
||||
|
||||
+ if (mon) {
|
||||
+ c->geom.x = (mon->w.width - c->geom.width) / 2 + mon->m.x;
|
||||
+ c->geom.y = (mon->w.height - c->geom.height) / 2 + mon->m.y;
|
||||
+ }
|
||||
+
|
||||
c->isfloating |= client_is_float_type(c);
|
||||
setmon(c, mon, newtags);
|
||||
}
|
||||
@@ -1787,6 +1792,10 @@ mapnotify(struct wl_listener *listener, void *data)
|
||||
* If there is no parent, apply rules */
|
||||
if ((p = client_get_parent(c))) {
|
||||
c->isfloating = 1;
|
||||
+ if (p->mon) {
|
||||
+ c->geom.x = (p->mon->w.width - c->geom.width) / 2 + p->mon->m.x;
|
||||
+ c->geom.y = (p->mon->w.height - c->geom.height) / 2 + p->mon->m.y;
|
||||
+ }
|
||||
setmon(c, p->mon, p->tags);
|
||||
} else {
|
||||
applyrules(c);
|
||||
--
|
||||
2.49.0
|
||||
2.52.0
|
||||
|
||||
|
||||
@@ -5,10 +5,11 @@ Note: Commands from array are executed using execvp(). So if you need to execute
|
||||
|
||||
### Download
|
||||
- [git branch](https://codeberg.org/sevz/dwl/src/branch/autostart)
|
||||
- [2025-01-20](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/autostart/autostart.patch)
|
||||
- [0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/autostart/autostart-0.7.patch)
|
||||
- [autostart-wlroots-next-f4249db.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/autostart/autostart-wlroots-next-f4249db.patch)
|
||||
- [autostart-0.8.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/autostart/autostart-0.8.patch)
|
||||
|
||||
### Authors
|
||||
- [fauxmight](https://codeberg.org/fauxmight)
|
||||
- [sevz](https://codeberg.org/sevz)
|
||||
- [Rayan Nakib](https://nakibrayan2.pages.dev/)
|
||||
- [NFVblog](https://github.com/nf02)
|
||||
|
||||
@@ -1,24 +1,18 @@
|
||||
From 3b0b0249d900121a90528616f4d11f733c7a5ca2 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?=
|
||||
<leohdz172@proton.me>
|
||||
Date: Sat, 8 Jul 2023 17:11:36 -0600
|
||||
Subject: [PATCH] port autostart patch from dwm
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
From d2e2e61aeb25ad71c2c559994968ba64e0974503 Mon Sep 17 00:00:00 2001
|
||||
From: A Frederick Christensen <dwl@ivories.org>
|
||||
Date: Fri, 27 Feb 2026 12:23:04 -0600
|
||||
Subject: [PATCH] Applied autostart patch
|
||||
|
||||
https://dwm.suckless.org/patches/cool_autostart/
|
||||
Signed-off-by: Leonardo Hernández Hernández <leohdz172@proton.me>
|
||||
---
|
||||
config.def.h | 7 +++++++
|
||||
config.def.h | 6 ++++++
|
||||
dwl.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++---
|
||||
2 files changed, 62 insertions(+), 3 deletions(-)
|
||||
2 files changed, 61 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 22d2171d..8dc6502c 100644
|
||||
index 8a6eda0..6eb0db4 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -20,6 +20,13 @@ static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You ca
|
||||
@@ -20,6 +20,12 @@ static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You ca
|
||||
/* logging */
|
||||
static int log_level = WLR_ERROR;
|
||||
|
||||
@@ -28,12 +22,11 @@ index 22d2171d..8dc6502c 100644
|
||||
+ NULL /* terminate */
|
||||
+};
|
||||
+
|
||||
+
|
||||
/* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g leave at least one example) */
|
||||
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 */
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index ad21e1ba..3118e07f 100644
|
||||
index 44f3ad9..e7b6199 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -246,6 +246,7 @@ static void arrange(Monitor *m);
|
||||
@@ -44,17 +37,17 @@ index ad21e1ba..3118e07f 100644
|
||||
static void axisnotify(struct wl_listener *listener, void *data);
|
||||
static void buttonpress(struct wl_listener *listener, void *data);
|
||||
static void chvt(const Arg *arg);
|
||||
@@ -455,6 +456,9 @@ static struct wlr_xwayland *xwayland;
|
||||
/* attempt to encapsulate suck into one file */
|
||||
#include "client.h"
|
||||
@@ -449,6 +450,9 @@ static struct wl_listener xwayland_ready = {.notify = xwaylandready};
|
||||
static struct wlr_xwayland *xwayland;
|
||||
#endif
|
||||
|
||||
+static pid_t *autostart_pids;
|
||||
+static size_t autostart_len;
|
||||
+
|
||||
/* function implementations */
|
||||
void
|
||||
applybounds(Client *c, struct wlr_box *bbox)
|
||||
@@ -599,6 +603,27 @@ arrangelayers(Monitor *m)
|
||||
/* configuration, allows nested code to access above variables */
|
||||
#include "config.h"
|
||||
|
||||
@@ -603,6 +607,27 @@ arrangelayers(Monitor *m)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +75,7 @@ index ad21e1ba..3118e07f 100644
|
||||
void
|
||||
axisnotify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
@@ -695,12 +720,23 @@ checkidleinhibitor(struct wlr_surface *exclude)
|
||||
@@ -699,12 +724,23 @@ checkidleinhibitor(struct wlr_surface *exclude)
|
||||
void
|
||||
cleanup(void)
|
||||
{
|
||||
@@ -106,7 +99,7 @@ index ad21e1ba..3118e07f 100644
|
||||
if (child_pid > 0) {
|
||||
kill(-child_pid, SIGTERM);
|
||||
waitpid(child_pid, NULL, 0);
|
||||
@@ -1551,10 +1587,25 @@ gpureset(struct wl_listener *listener, void *data)
|
||||
@@ -1560,10 +1596,25 @@ gpureset(struct wl_listener *listener, void *data)
|
||||
void
|
||||
handlesig(int signo)
|
||||
{
|
||||
@@ -135,7 +128,7 @@ index ad21e1ba..3118e07f 100644
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2241,6 +2292,7 @@ run(char *startup_cmd)
|
||||
@@ -2250,6 +2301,7 @@ run(char *startup_cmd)
|
||||
die("startup: backend_start");
|
||||
|
||||
/* Now that the socket exists and the backend is started, run the startup command */
|
||||
@@ -144,5 +137,5 @@ index ad21e1ba..3118e07f 100644
|
||||
int piperw[2];
|
||||
if (pipe(piperw) < 0)
|
||||
--
|
||||
2.48.0
|
||||
2.52.0
|
||||
|
||||
+38
-51
@@ -1,24 +1,18 @@
|
||||
From 787f7252d63945996f009828aff3c44afd0f7781 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?=
|
||||
<leohdz172@proton.me>
|
||||
Date: Sat, 8 Jul 2023 17:11:36 -0600
|
||||
Subject: [PATCH] port autostart patch from dwm
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
From e8932f159793012a54047c48b3710703a63c07fb Mon Sep 17 00:00:00 2001
|
||||
From: A Frederick Christensen <dwl@ivories.org>
|
||||
Date: Fri, 27 Feb 2026 12:29:02 -0600
|
||||
Subject: [PATCH] Applied autostart patch
|
||||
|
||||
https://dwm.suckless.org/patches/cool_autostart/
|
||||
Signed-off-by: Leonardo Hernández Hernández <leohdz172@proton.me>
|
||||
---
|
||||
config.def.h | 7 +++++++
|
||||
dwl.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++-----
|
||||
2 files changed, 61 insertions(+), 5 deletions(-)
|
||||
config.def.h | 6 ++++++
|
||||
dwl.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++---
|
||||
2 files changed, 61 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 22d2171..8dc6502 100644
|
||||
index 8a6eda0..6eb0db4 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -20,6 +20,13 @@ static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You ca
|
||||
@@ -20,6 +20,12 @@ static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You ca
|
||||
/* logging */
|
||||
static int log_level = WLR_ERROR;
|
||||
|
||||
@@ -28,15 +22,14 @@ index 22d2171..8dc6502 100644
|
||||
+ NULL /* terminate */
|
||||
+};
|
||||
+
|
||||
+
|
||||
/* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g leave at least one example) */
|
||||
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 */
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 5bf995e..e8b8727 100644
|
||||
index 8a9715d..3450817 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -249,6 +249,7 @@ static void arrange(Monitor *m);
|
||||
@@ -248,6 +248,7 @@ static void arrange(Monitor *m);
|
||||
static void arrangelayer(Monitor *m, struct wl_list *list,
|
||||
struct wlr_box *usable_area, int exclusive);
|
||||
static void arrangelayers(Monitor *m);
|
||||
@@ -44,17 +37,17 @@ index 5bf995e..e8b8727 100644
|
||||
static void axisnotify(struct wl_listener *listener, void *data);
|
||||
static void buttonpress(struct wl_listener *listener, void *data);
|
||||
static void chvt(const Arg *arg);
|
||||
@@ -432,6 +433,9 @@ static xcb_atom_t netatom[NetLast];
|
||||
/* attempt to encapsulate suck into one file */
|
||||
#include "client.h"
|
||||
@@ -451,6 +452,9 @@ static struct wl_listener xwayland_ready = {.notify = xwaylandready};
|
||||
static struct wlr_xwayland *xwayland;
|
||||
#endif
|
||||
|
||||
+static pid_t *autostart_pids;
|
||||
+static size_t autostart_len;
|
||||
+
|
||||
/* function implementations */
|
||||
void
|
||||
applybounds(Client *c, struct wlr_box *bbox)
|
||||
@@ -580,6 +584,27 @@ arrangelayers(Monitor *m)
|
||||
/* configuration, allows nested code to access above variables */
|
||||
#include "config.h"
|
||||
|
||||
@@ -605,6 +609,27 @@ arrangelayers(Monitor *m)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,11 +75,13 @@ index 5bf995e..e8b8727 100644
|
||||
void
|
||||
axisnotify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
@@ -676,11 +701,21 @@ checkidleinhibitor(struct wlr_surface *exclude)
|
||||
@@ -701,12 +726,23 @@ checkidleinhibitor(struct wlr_surface *exclude)
|
||||
void
|
||||
cleanup(void)
|
||||
{
|
||||
+ size_t i;
|
||||
+
|
||||
cleanuplisteners();
|
||||
#ifdef XWAYLAND
|
||||
wlr_xwayland_destroy(xwayland);
|
||||
xwayland = NULL;
|
||||
@@ -104,44 +99,36 @@ index 5bf995e..e8b8727 100644
|
||||
if (child_pid > 0) {
|
||||
kill(-child_pid, SIGTERM);
|
||||
waitpid(child_pid, NULL, 0);
|
||||
@@ -1497,18 +1532,31 @@ void
|
||||
@@ -1562,10 +1598,25 @@ gpureset(struct wl_listener *listener, void *data)
|
||||
void
|
||||
handlesig(int signo)
|
||||
{
|
||||
if (signo == SIGCHLD) {
|
||||
-#ifdef XWAYLAND
|
||||
siginfo_t in;
|
||||
/* wlroots expects to reap the XWayland process itself, so we
|
||||
* use WNOWAIT to keep the child waitable until we know it's not
|
||||
* XWayland.
|
||||
*/
|
||||
while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid
|
||||
- && (!xwayland || in.si_pid != xwayland->server->pid))
|
||||
- waitpid(in.si_pid, NULL, 0);
|
||||
-#else
|
||||
- if (signo == SIGCHLD)
|
||||
- while (waitpid(-1, NULL, WNOHANG) > 0);
|
||||
+#ifdef XWAYLAND
|
||||
+ && (!xwayland || in.si_pid != xwayland->server->pid)
|
||||
#endif
|
||||
+ ) {
|
||||
+ pid_t *p, *lim;
|
||||
+ waitpid(in.si_pid, NULL, 0);
|
||||
+ if (in.si_pid == child_pid)
|
||||
- else if (signo == SIGINT || signo == SIGTERM)
|
||||
+ if (signo == SIGCHLD) {
|
||||
+ pid_t pid, *p, *lim;
|
||||
+ while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) {
|
||||
+ if (pid == child_pid)
|
||||
+ child_pid = -1;
|
||||
+ if (!(p = autostart_pids))
|
||||
+ continue;
|
||||
+ lim = &p[autostart_len];
|
||||
+
|
||||
+ for (; p < lim; p++) {
|
||||
+ if (*p == in.si_pid) {
|
||||
+ if (*p == pid) {
|
||||
+ *p = -1;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
} else if (signo == SIGINT || signo == SIGTERM) {
|
||||
+ } else if (signo == SIGINT || signo == SIGTERM) {
|
||||
quit(NULL);
|
||||
}
|
||||
@@ -2224,6 +2272,7 @@ run(char *startup_cmd)
|
||||
+ }
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2252,6 +2303,7 @@ run(char *startup_cmd)
|
||||
die("startup: backend_start");
|
||||
|
||||
/* Now that the socket exists and the backend is started, run the startup command */
|
||||
@@ -150,5 +137,5 @@ index 5bf995e..e8b8727 100644
|
||||
int piperw[2];
|
||||
if (pipe(piperw) < 0)
|
||||
--
|
||||
2.45.2
|
||||
2.52.0
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||

|
||||
|
||||
### Description
|
||||
Adds support for app icons that can replace the tag indicator and tag name.
|
||||
This feature is configurable through an additional option in `rules`.
|
||||
|
||||
Icons should work out of the box. Emojis require a special font like
|
||||
[Noto Color Emoji](https://fonts.google.com/noto/specimen/Noto+Color+Emoji).
|
||||
|
||||
When one or more app icons are present in a tag, the tag name will be enclosed
|
||||
by the outer separators (`outer_separator_beg` and `outer_separator_end`).
|
||||
Additionally, the icons within the tag will be separated by `inner_separator`.
|
||||
|
||||
Each tag can display a maximum of `truncate_icons_after` icons, after which the
|
||||
`truncate_symbol` will be shown.
|
||||
|
||||
**Inspiration:** [XMonad's DynamicIcons](https://hackage.haskell.org/package/xmonad-contrib-0.18.1/docs/XMonad-Hooks-DynamicIcons.html)
|
||||
|
||||
### Prerequisites
|
||||
Make sure you have the [bar](/dwl/dwl-patches/raw/branch/main/patches/bar) patch.
|
||||
|
||||
### Download
|
||||
- [main_2025-10-24](/dwl/dwl-patches/raw/branch/main/patches/bar-appicons/appicons.patch)
|
||||
### Authors
|
||||
- [rumenmitov](https://codeberg.org/rumenmitov)
|
||||
@@ -0,0 +1,282 @@
|
||||
From f5d1206f7f467cafd5a0217a46c31928316ba2fe Mon Sep 17 00:00:00 2001
|
||||
From: Rumen <rumenmitov@protonmail.com>
|
||||
Date: Mon, 1 Dec 2025 20:29:49 +0100
|
||||
Subject: [PATCH] fix(bar-appicons): fixed various compiler warnings
|
||||
|
||||
---
|
||||
config.def.h | 14 +++--
|
||||
dwl.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++++--
|
||||
2 files changed, 150 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 1b7472d..a48b78d 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -26,12 +26,20 @@ static char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
|
||||
/* logging */
|
||||
static int log_level = WLR_ERROR;
|
||||
|
||||
+/* appicons */
|
||||
+/* NOTE: set to 0 to set to default (whitespace) */
|
||||
+static char outer_separator_beg = '[';
|
||||
+static char outer_separator_end = ']';
|
||||
+static char inner_separator = ' ';
|
||||
+static unsigned truncate_icons_after = 2; /* will default to 1, that is the min */
|
||||
+static char truncate_symbol[] = "...";
|
||||
+
|
||||
/* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g leave at least one example) */
|
||||
static const Rule rules[] = {
|
||||
- /* app_id title tags mask isfloating monitor */
|
||||
+ /* app_id title tags mask isfloating monitor appicon*/
|
||||
/* examples: */
|
||||
- { "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" */
|
||||
+ { "Gimp_EXAMPLE", NULL, 0, 1, -1, NULL }, /* Start on currently visible tags floating, not tiled */
|
||||
+ { "firefox_EXAMPLE", NULL, 1 << 8, 0, -1, "" }, /* Start on ONLY tag "9" */
|
||||
};
|
||||
|
||||
/* layout(s) */
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index bf340d8..e2baf66 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -143,6 +143,7 @@ typedef struct {
|
||||
struct wl_listener set_hints;
|
||||
#endif
|
||||
unsigned int bw;
|
||||
+ char *appicon;
|
||||
uint32_t tags;
|
||||
int isfloating, isurgent, isfullscreen;
|
||||
uint32_t resize; /* configure serial of a pending resize */
|
||||
@@ -221,6 +222,7 @@ struct Monitor {
|
||||
unsigned int seltags;
|
||||
unsigned int sellt;
|
||||
uint32_t tagset[2];
|
||||
+ char **tag_icons;
|
||||
float mfact;
|
||||
int gamma_lut_changed;
|
||||
int nmaster;
|
||||
@@ -252,6 +254,7 @@ typedef struct {
|
||||
uint32_t tags;
|
||||
int isfloating;
|
||||
int monitor;
|
||||
+ const char *appicon;
|
||||
} Rule;
|
||||
|
||||
typedef struct {
|
||||
@@ -313,6 +316,9 @@ static void destroypointerconstraint(struct wl_listener *listener, void *data);
|
||||
static void destroysessionlock(struct wl_listener *listener, void *data);
|
||||
static void destroykeyboardgroup(struct wl_listener *listener, void *data);
|
||||
static Monitor *dirtomon(enum wlr_direction dir);
|
||||
+static void remove_outer_separators(char **str);
|
||||
+static void appiconsappend(char **str, const char *appicon, size_t new_size);
|
||||
+static void applyappicon(char *tag_icons[], unsigned int *icons_per_tag, const Client *c);
|
||||
static void drawbar(Monitor *m);
|
||||
static void drawbars(void);
|
||||
static void focusclient(Client *c, int lift);
|
||||
@@ -527,12 +533,19 @@ applyrules(Client *c)
|
||||
const Rule *r;
|
||||
Monitor *mon = selmon, *m;
|
||||
|
||||
+ outer_separator_beg = outer_separator_beg ? outer_separator_beg : ' ';
|
||||
+ outer_separator_end = outer_separator_end ? outer_separator_end : ' ';
|
||||
+ inner_separator = inner_separator ? inner_separator : ' ';
|
||||
+ truncate_icons_after = truncate_icons_after > 0 ? truncate_icons_after : 1;
|
||||
+
|
||||
appid = client_get_appid(c);
|
||||
title = client_get_title(c);
|
||||
|
||||
for (r = rules; r < END(rules); r++) {
|
||||
if ((!r->title || strstr(title, r->title))
|
||||
&& (!r->id || strstr(appid, r->id))) {
|
||||
+ /* r->appicon is static, so lifetime is sufficient */
|
||||
+ c->appicon = (char*) r->appicon;
|
||||
c->isfloating = r->isfloating;
|
||||
newtags |= r->tags;
|
||||
i = 0;
|
||||
@@ -775,7 +788,7 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
(buffer = wlr_scene_buffer_from_node(node)) && buffer == selmon->scene_buffer) {
|
||||
cx = (cursor->x - selmon->m.x) * selmon->wlr_output->scale;
|
||||
do
|
||||
- x += TEXTW(selmon, tags[i]);
|
||||
+ x += TEXTW(selmon, selmon->tag_icons[i]);
|
||||
while (cx >= x && ++i < LENGTH(tags));
|
||||
if (i < LENGTH(tags)) {
|
||||
click = ClkTagBar;
|
||||
@@ -905,6 +918,16 @@ cleanupmon(struct wl_listener *listener, void *data)
|
||||
wlr_output_layout_remove(output_layout, m->wlr_output);
|
||||
wlr_scene_output_destroy(m->scene_output);
|
||||
|
||||
+ for (long unsigned int tag_idx = 0; tag_idx < LENGTH(tags); tag_idx++) {
|
||||
+ if (m->tag_icons[tag_idx]) free(m->tag_icons[tag_idx]);
|
||||
+ m->tag_icons[tag_idx] = NULL;
|
||||
+ }
|
||||
+
|
||||
+ if (m->tag_icons) {
|
||||
+ free(m->tag_icons);
|
||||
+ m->tag_icons = NULL;
|
||||
+ }
|
||||
+
|
||||
closemon(m);
|
||||
wlr_scene_node_destroy(&m->fullscreen_bg->node);
|
||||
wlr_scene_node_destroy(&m->scene_buffer->node);
|
||||
@@ -1227,6 +1250,13 @@ createmon(struct wl_listener *listener, void *data)
|
||||
m->lt[0] = r->lt;
|
||||
m->lt[1] = &layouts[LENGTH(layouts) > 1 && r->lt != &layouts[1]];
|
||||
strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof(m->ltsymbol));
|
||||
+
|
||||
+ m->tag_icons = (char**) malloc(LENGTH(tags) * sizeof(char*));
|
||||
+ if (m->tag_icons == NULL) perror("dwm: malloc()");
|
||||
+ for (long unsigned int tag_idx = 0; tag_idx < LENGTH(tags); tag_idx++) {
|
||||
+ m->tag_icons[tag_idx] = NULL;
|
||||
+ }
|
||||
+
|
||||
wlr_output_state_set_scale(&state, r->scale);
|
||||
wlr_output_state_set_transform(&state, r->rr);
|
||||
break;
|
||||
@@ -1566,6 +1596,98 @@ dirtomon(enum wlr_direction dir)
|
||||
return selmon;
|
||||
}
|
||||
|
||||
+void
|
||||
+remove_outer_separators(char **str)
|
||||
+{
|
||||
+ const char *clean_tag_name_beg = *str + 1;
|
||||
+ const size_t clean_tag_name_len = strlen(*str) - 2;
|
||||
+
|
||||
+ char *temp_tag_name = (char*)
|
||||
+ malloc(clean_tag_name_len + 1);
|
||||
+
|
||||
+ if (temp_tag_name == NULL) perror("dwm: malloc()");
|
||||
+
|
||||
+ memset(temp_tag_name, 0, clean_tag_name_len + 1);
|
||||
+
|
||||
+ strncpy(temp_tag_name,
|
||||
+ clean_tag_name_beg,
|
||||
+ clean_tag_name_len);
|
||||
+
|
||||
+ if (*str) free(*str);
|
||||
+ *str = temp_tag_name;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+appiconsappend(char **str, const char *appicon, size_t new_size)
|
||||
+{
|
||||
+ char *temp_tag_name = (char*) malloc(new_size);
|
||||
+ if (temp_tag_name == NULL) perror("dwm: malloc()");
|
||||
+
|
||||
+ /* NOTE: Example format of temp_tag_name (with two appicons):
|
||||
+ * <outer_sep_beg><appicon><inner_sep><appicon><outer_sep_end>
|
||||
+ */
|
||||
+ temp_tag_name = memset(temp_tag_name, 0, new_size);
|
||||
+
|
||||
+ temp_tag_name[0] = outer_separator_beg;
|
||||
+ temp_tag_name[new_size - 2] = outer_separator_end;
|
||||
+
|
||||
+ strncpy(temp_tag_name + 1, *str, strlen(*str));
|
||||
+ temp_tag_name[strlen(temp_tag_name)] = inner_separator;
|
||||
+
|
||||
+ strncpy(temp_tag_name + strlen(temp_tag_name),
|
||||
+ appicon, strlen(appicon));
|
||||
+
|
||||
+ if (*str) free(*str);
|
||||
+ *str = temp_tag_name;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+applyappicon(char *tag_icons[], unsigned int *icons_per_tag, const Client *c)
|
||||
+{
|
||||
+ const size_t outer_separators_size = 2;
|
||||
+ const size_t inner_separator_size = 1;
|
||||
+ size_t new_size = 0;
|
||||
+
|
||||
+ for (unsigned t = 1, i = 0;
|
||||
+ i < LENGTH(tags);
|
||||
+ t <<= 1, i++)
|
||||
+ {
|
||||
+ if (c->tags & t) {
|
||||
+ if (icons_per_tag[i] == 0) {
|
||||
+ if (tag_icons[i]) free(tag_icons[i]);
|
||||
+ tag_icons[i] = strndup(c->appicon, strlen(c->appicon));
|
||||
+ } else {
|
||||
+ char *icon = NULL;
|
||||
+ if (icons_per_tag[i] < truncate_icons_after)
|
||||
+ icon = c->appicon;
|
||||
+ else if (icons_per_tag[i] == truncate_icons_after)
|
||||
+ icon = truncate_symbol;
|
||||
+ else {
|
||||
+ icons_per_tag[i]++;
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ /* remove outer separators from previous iterations
|
||||
+ * otherwise they get applied recursively */
|
||||
+ if (icons_per_tag[i] > 1) {
|
||||
+ remove_outer_separators(&tag_icons[i]);
|
||||
+ }
|
||||
+
|
||||
+ new_size = strlen(tag_icons[i])
|
||||
+ + outer_separators_size
|
||||
+ + inner_separator_size
|
||||
+ + strlen(icon)
|
||||
+ + 1;
|
||||
+
|
||||
+ appiconsappend(&tag_icons[i], icon, new_size);
|
||||
+ }
|
||||
+
|
||||
+ icons_per_tag[i]++;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+
|
||||
void
|
||||
drawbar(Monitor *m)
|
||||
{
|
||||
@@ -1575,6 +1697,7 @@ drawbar(Monitor *m)
|
||||
uint32_t i, occ = 0, urg = 0;
|
||||
Client *c;
|
||||
Buffer *buf;
|
||||
+ unsigned int icons_per_tag[LENGTH(tags)];
|
||||
|
||||
if (!m->scene_buffer->node.enabled)
|
||||
return;
|
||||
@@ -1588,9 +1711,21 @@ drawbar(Monitor *m)
|
||||
drwl_text(m->drw, m->b.width - tw, 0, tw, m->b.height, 0, stext, 0);
|
||||
}
|
||||
|
||||
+ memset(icons_per_tag, 0, LENGTH(tags) * sizeof(int));
|
||||
+
|
||||
+ for (long unsigned int tag_idx = 0; tag_idx < LENGTH(tags); tag_idx++) {
|
||||
+ /* set each tag to default value */
|
||||
+ m->tag_icons[tag_idx] = strndup(tags[tag_idx], strlen(tags[tag_idx]));
|
||||
+ }
|
||||
+
|
||||
wl_list_for_each(c, &clients, link) {
|
||||
if (c->mon != m)
|
||||
continue;
|
||||
+
|
||||
+ if (c->appicon && strlen(c->appicon) > 0) {
|
||||
+ applyappicon(m->tag_icons, icons_per_tag, c);
|
||||
+ }
|
||||
+
|
||||
occ |= c->tags;
|
||||
if (c->isurgent)
|
||||
urg |= c->tags;
|
||||
@@ -1598,10 +1733,10 @@ drawbar(Monitor *m)
|
||||
x = 0;
|
||||
c = focustop(m);
|
||||
for (i = 0; i < LENGTH(tags); i++) {
|
||||
- w = TEXTW(m, tags[i]);
|
||||
+ w = TEXTW(m, m->tag_icons[i]);
|
||||
drwl_setscheme(m->drw, colors[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
|
||||
- drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, tags[i], urg & 1 << i);
|
||||
- if (occ & 1 << i)
|
||||
+ drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, m->tag_icons[i], urg & 1 << i);
|
||||
+ if (occ & 1 << i && icons_per_tag[i] ==0)
|
||||
drwl_rect(m->drw, x + boxs, boxs, boxw, boxw,
|
||||
m == selmon && c && c->tags & 1 << i,
|
||||
urg & 1 << i);
|
||||
--
|
||||
2.52.0
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 5.5 KiB |
@@ -0,0 +1,31 @@
|
||||

|
||||
|
||||
### Description
|
||||
|
||||
Add a mode indicator to bar that tells which mode you are in, just like
|
||||
river-classic's [dam](https://codeberg.org/sewn/dam) bar.
|
||||
|
||||
The string from `modes_labels` defined in `config.h` is used, while normal mode
|
||||
is ignored.
|
||||
|
||||
Another usage is to serve as a hint for each modes keybindings:
|
||||
|
||||
```c
|
||||
enum {
|
||||
BROWSER,
|
||||
};
|
||||
const char *modes_labels[] = {
|
||||
"[f]irefox [b]rave [c]hromium [q]utebrowser",
|
||||
};
|
||||
```
|
||||
|
||||
### Dependencies
|
||||
this patch depends on:
|
||||
- [bar](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/bar/) patch
|
||||
- [modes](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/modes/) patch
|
||||
|
||||
### Download
|
||||
- [v0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/bar-modes/bar-modes.patch)
|
||||
|
||||
### Authors
|
||||
- [unixchad](https://codeberg.org/unixchad/)
|
||||
@@ -0,0 +1,144 @@
|
||||
From 04b37902e0098fb69250fd25b5afbc610a284529 Mon Sep 17 00:00:00 2001
|
||||
From: nate zhou <gnuunixchad@outlook.com>
|
||||
Date: Mon, 2 Mar 2026 21:54:03 +0800
|
||||
Subject: [PATCH] Patch: bar-modes for 0.8
|
||||
|
||||
Add modes_labels indicator to bar, which behaves like river-classic's
|
||||
dam bar. This patch has to be applied after the bar and modes patch.
|
||||
---
|
||||
dwl.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++-----------
|
||||
1 file changed, 72 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index ae290ad..7229034 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -1585,19 +1585,29 @@ drawbar(Monitor *m)
|
||||
uint32_t i, occ = 0, urg = 0;
|
||||
Client *c;
|
||||
Buffer *buf;
|
||||
+ char mode_text[256] = "";
|
||||
+ int mode_width = 0;
|
||||
+ int title_width;
|
||||
+ int remaining;
|
||||
+ int status_shown = 0;
|
||||
|
||||
if (!m->scene_buffer->node.enabled)
|
||||
return;
|
||||
if (!(buf = bufmon(m)))
|
||||
return;
|
||||
|
||||
- /* draw status first so it can be overdrawn by tags later */
|
||||
- if (m == selmon) { /* status is only drawn on selected monitor */
|
||||
- drwl_setscheme(m->drw, colors[SchemeNorm]);
|
||||
- tw = TEXTW(m, stext) - m->lrpad + 2; /* 2px right padding */
|
||||
- drwl_text(m->drw, m->b.width - tw, 0, tw, m->b.height, 0, stext, 0);
|
||||
+ /* get current mode text if in a mode (not normal) */
|
||||
+ if (active_mode_index >= 0 && active_mode_index < LENGTH(modes_labels) &&
|
||||
+ modes_labels[active_mode_index]) {
|
||||
+ strncpy(mode_text, modes_labels[active_mode_index], sizeof(mode_text) - 1);
|
||||
+ mode_text[sizeof(mode_text) - 1] = '\0';
|
||||
+ mode_width = TEXTW(m, mode_text);
|
||||
}
|
||||
|
||||
+ /* calculate status text width */
|
||||
+ drwl_setscheme(m->drw, colors[SchemeNorm]);
|
||||
+ tw = TEXTW(m, stext) - m->lrpad + 2;
|
||||
+
|
||||
wl_list_for_each(c, &clients, link) {
|
||||
if (c->mon != m)
|
||||
continue;
|
||||
@@ -1607,6 +1617,8 @@ drawbar(Monitor *m)
|
||||
}
|
||||
x = 0;
|
||||
c = focustop(m);
|
||||
+
|
||||
+ /* draw tags (always shown) */
|
||||
for (i = 0; i < LENGTH(tags); i++) {
|
||||
w = TEXTW(m, tags[i]);
|
||||
drwl_setscheme(m->drw, colors[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
|
||||
@@ -1617,19 +1629,63 @@ drawbar(Monitor *m)
|
||||
urg & 1 << i);
|
||||
x += w;
|
||||
}
|
||||
+
|
||||
+ /* draw mode indicator after tags if in a mode */
|
||||
+ if (mode_text[0]) {
|
||||
+ drwl_setscheme(m->drw, colors[SchemeSel]);
|
||||
+ drwl_text(m->drw, x, 0, mode_width, m->b.height, m->lrpad / 2, mode_text, 0);
|
||||
+ x += mode_width;
|
||||
+ }
|
||||
+
|
||||
+ /* draw layout symbol after mode */
|
||||
w = TEXTW(m, m->ltsymbol);
|
||||
drwl_setscheme(m->drw, colors[SchemeNorm]);
|
||||
- x = drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, m->ltsymbol, 0);
|
||||
-
|
||||
- if ((w = m->b.width - tw - x) > m->b.height) {
|
||||
- if (c) {
|
||||
- drwl_setscheme(m->drw, colors[m == selmon ? SchemeSel : SchemeNorm]);
|
||||
- drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, client_get_title(c), 0);
|
||||
- if (c && c->isfloating)
|
||||
- drwl_rect(m->drw, x + boxs, boxs, boxw, boxw, 0, 0);
|
||||
- } else {
|
||||
+ drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, m->ltsymbol, 0);
|
||||
+ x += w;
|
||||
+
|
||||
+ remaining = m->b.width - x;
|
||||
+
|
||||
+ if (mode_text[0] && remaining >= tw) {
|
||||
+ drwl_setscheme(m->drw, colors[SchemeNorm]);
|
||||
+ drwl_text(m->drw, m->b.width - tw, 0, tw, m->b.height, 0, stext, 0);
|
||||
+ remaining -= tw;
|
||||
+ status_shown = 1;
|
||||
+ }
|
||||
+
|
||||
+ title_width = remaining;
|
||||
+
|
||||
+ if (c && title_width > m->b.height) {
|
||||
+ drwl_setscheme(m->drw, colors[m == selmon ? SchemeSel : SchemeNorm]);
|
||||
+ drwl_text(m->drw, x, 0, title_width, m->b.height, m->lrpad / 2,
|
||||
+ client_get_title(c), 0);
|
||||
+ if (c && c->isfloating)
|
||||
+ drwl_rect(m->drw, x + boxs, boxs, boxw, boxw, 0, 0);
|
||||
+ } else if (title_width > 0) {
|
||||
+ drwl_setscheme(m->drw, colors[SchemeNorm]);
|
||||
+ drwl_rect(m->drw, x, 0, title_width, m->b.height, 1, 1);
|
||||
+ }
|
||||
+
|
||||
+ if (!mode_text[0]) {
|
||||
+ /* not in a mode - normal behavior with status */
|
||||
+ if (remaining >= tw) {
|
||||
+ drwl_setscheme(m->drw, colors[SchemeNorm]);
|
||||
+ drwl_text(m->drw, m->b.width - tw, 0, tw, m->b.height, 0, stext, 0);
|
||||
+
|
||||
+ int title_space = remaining - tw;
|
||||
+ if (title_space > m->b.height && c) {
|
||||
+ drwl_setscheme(m->drw, colors[m == selmon ? SchemeSel : SchemeNorm]);
|
||||
+ drwl_text(m->drw, x, 0, title_space, m->b.height, m->lrpad / 2,
|
||||
+ client_get_title(c), 0);
|
||||
+ if (c && c->isfloating)
|
||||
+ drwl_rect(m->drw, x + boxs, boxs, boxw, boxw, 0, 0);
|
||||
+ } else if (title_space > 0) {
|
||||
+ drwl_setscheme(m->drw, colors[SchemeNorm]);
|
||||
+ drwl_rect(m->drw, x, 0, title_space, m->b.height, 1, 1);
|
||||
+ }
|
||||
+ } else if (remaining > 0) {
|
||||
drwl_setscheme(m->drw, colors[SchemeNorm]);
|
||||
- drwl_rect(m->drw, x, 0, w, m->b.height, 1, 1);
|
||||
+ drwl_text(m->drw, m->b.width - remaining, 0, remaining, m->b.height, 0,
|
||||
+ stext, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3437,6 +3493,7 @@ entermode(const Arg *arg)
|
||||
{
|
||||
active_mode_index = arg->i;
|
||||
printstatus();
|
||||
+ drawbars();
|
||||
}
|
||||
|
||||
#ifdef XWAYLAND
|
||||
--
|
||||
2.53.0
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 6.4 KiB |
@@ -0,0 +1,14 @@
|
||||
### Description
|
||||
Add a `window_title` option to toggle showing window titles in the bar, similar to the DWM `notitle` patch.
|
||||
|
||||
### Dependencies
|
||||
this patch depends on [bar](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/bar/) patch
|
||||
|
||||
### Download
|
||||
- [git branch](/pi66/dwl-patches/src/branch/bar-notitle)
|
||||
- [0.7](/dwl/dwl-patches/raw/branch/main/patches/bar-notitle/bar-notitle.patch)
|
||||
- [main 2026-02-28](/dwl/dwl-patches/raw/branch/main/patches/bar-notitle/bar-notitle.patch)
|
||||
|
||||
### Authors
|
||||
- [Pi66](https://codeberg.org/pi66)
|
||||
[website](https://pi66.xyz)
|
||||
@@ -0,0 +1,38 @@
|
||||
From 5dc83d75ff1b7dadf1fd1f96fe2303848e35d382 Mon Sep 17 00:00:00 2001
|
||||
From: pi66 <pixel2176@proton.me>
|
||||
Date: Sat, 28 Feb 2026 20:26:28 +0100
|
||||
Subject: [PATCH] add window_title option (like dwm notitle patch)
|
||||
|
||||
---
|
||||
config.def.h | 1 +
|
||||
dwl.c | 2 +-
|
||||
2 files changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 7da50d2..3d3dfe8 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -7,6 +7,7 @@
|
||||
static const int sloppyfocus = 1; /* focus follows mouse */
|
||||
static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */
|
||||
static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
+static const int window_title = 0; /* 1 means showing window titles on the bar */
|
||||
static const int showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
static const char *fonts[] = {"monospace:size=10"};
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 7fe9468..0c7262a 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -1614,7 +1614,7 @@ drawbar(Monitor *m)
|
||||
x = drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, m->ltsymbol, 0);
|
||||
|
||||
if ((w = m->b.width - tw - x) > m->b.height) {
|
||||
- if (c) {
|
||||
+ if (c && window_title) {
|
||||
drwl_setscheme(m->drw, colors[m == selmon ? SchemeSel : SchemeNorm]);
|
||||
drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, client_get_title(c), 0);
|
||||
if (c && c->isfloating)
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# Description
|
||||
Reload colorscheme on the fly without restart or recompile DWL.
|
||||
|
||||
> NOTE:
|
||||
The patch works on (main 2025-11-01) and v0.7
|
||||
|
||||
# Dependencies
|
||||
this patch depends on [bar](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/bar/) patch
|
||||
|
||||
# Download
|
||||
- [git branch](https://codeberg.org/pi66/dwl-patches/raw/branch/main/patches/bar-recolr/bar-recolr.patch)
|
||||
- [main 2025-11-01](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/bar-recolr/bar-recolr.patch)
|
||||
- [v0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/bar-recolr/bar-recolr.patch)
|
||||
|
||||
# Authors
|
||||
- [pi66](https://pi66.xyz)
|
||||
@@ -0,0 +1,80 @@
|
||||
From 89029325be300f03bbc3ca3b2d77f107d0cb5ca2 Mon Sep 17 00:00:00 2001
|
||||
From: pi66 <pixel2176@proton.me>
|
||||
Date: Tue, 25 Nov 2025 12:53:36 +0100
|
||||
Subject: [PATCH] Add: load colors from an external file
|
||||
|
||||
---
|
||||
config.def.h | 3 +++
|
||||
dwl.c | 21 +++++++++++++++++++++
|
||||
2 files changed, 24 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 1b7472d..3c04759 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -9,6 +9,8 @@ static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will
|
||||
static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
static const int showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
+static const int refresh_colors = 0; /* 1 means reloading colors when the session starts*/
|
||||
+static const char *colors_file = "/home/pixel/.cache/wal/dwl-colors"; /* change the username */
|
||||
static const char *fonts[] = {"monospace:size=10"};
|
||||
static const float rootcolor[] = COLOR(0x000000ff);
|
||||
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
||||
@@ -135,6 +137,7 @@ static const Key keys[] = {
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
|
||||
{ MODKEY, XKB_KEY_b, togglebar, {0} },
|
||||
{ MODKEY, XKB_KEY_j, focusstack, {.i = +1} },
|
||||
+ { MODKEY, XKB_KEY_n, reload_colors, {0} },
|
||||
{ MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
|
||||
{ MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
|
||||
{ MODKEY, XKB_KEY_d, incnmaster, {.i = -1} },
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index bf340d8..fc81d89 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -345,6 +345,7 @@ static void pointerfocus(Client *c, struct wlr_surface *surface,
|
||||
double sx, double sy, uint32_t time);
|
||||
static void powermgrsetmode(struct wl_listener *listener, void *data);
|
||||
static void quit(const Arg *arg);
|
||||
+static void reload_colors(const Arg *arg);
|
||||
static void rendermon(struct wl_listener *listener, void *data);
|
||||
static void requestdecorationmode(struct wl_listener *listener, void *data);
|
||||
static void requeststartdrag(struct wl_listener *listener, void *data);
|
||||
@@ -2348,6 +2349,25 @@ quit(const Arg *arg)
|
||||
wl_display_terminate(dpy);
|
||||
}
|
||||
|
||||
+void
|
||||
+reload_colors(const Arg *arg)
|
||||
+{
|
||||
+ FILE *f = fopen(colors_file, "r");
|
||||
+ if (!f) return;
|
||||
+
|
||||
+ for (int i = 0; i < (int)LENGTH(colors); i++) {
|
||||
+ unsigned int fg, bg, border;
|
||||
+ if (fscanf(f, "%x %x %x", &fg, &bg, &border) != 3)
|
||||
+ break;
|
||||
+
|
||||
+ colors[i][ColFg] = fg;
|
||||
+ colors[i][ColBg] = bg;
|
||||
+ colors[i][ColBorder] = border;
|
||||
+ }
|
||||
+ fclose(f);
|
||||
+ drawbars();
|
||||
+}
|
||||
+
|
||||
void
|
||||
rendermon(struct wl_listener *listener, void *data)
|
||||
{
|
||||
@@ -3482,6 +3502,7 @@ main(int argc, char *argv[])
|
||||
if (!getenv("XDG_RUNTIME_DIR"))
|
||||
die("XDG_RUNTIME_DIR must be set");
|
||||
setup();
|
||||
+ if (refresh_colors) reload_colors(0);
|
||||
run(startup_cmd);
|
||||
cleanup();
|
||||
return EXIT_SUCCESS;
|
||||
--
|
||||
2.51.2
|
||||
|
||||
@@ -301,7 +301,7 @@ index 0000000..125312c
|
||||
+ pipefd = ecalloc(2, sizeof(int));
|
||||
+
|
||||
+ /*
|
||||
+ * Libdbus forbids calling dbus_connection_dipatch from the
|
||||
+ * Libdbus forbids calling dbus_connection_dispatch from the
|
||||
+ * DBusDispatchStatusFunction directly. Notify the event loop of
|
||||
+ * updates via a self-pipe.
|
||||
+ */
|
||||
|
||||
@@ -13,6 +13,7 @@ slstatus -s | dwl
|
||||
* pixman
|
||||
|
||||
### Download
|
||||
- [main 2026-01-05](/dwl/dwl-patches/raw/branch/main/patches/bar/bar.patch)
|
||||
- [0.7](/dwl/dwl-patches/raw/branch/main/patches/bar/bar-0.7.patch)
|
||||
- [0.6](/dwl/dwl-patches/raw/branch/main/patches/bar/bar-0.6.patch)
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
||||
### Description
|
||||
This patch **requires** the dwl [barconfig](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/bar) patch be applied first! The barconfig patch provides configuration for the dwl bar via the variable
|
||||
`barlayout`. This determines which of the elements listed below to
|
||||
display on the bar and in which order:
|
||||
|
||||
- 't' -> the tags
|
||||
- 'l' -> the current layout symbol
|
||||
- 'n' -> the window name
|
||||
- 's' -> the status message
|
||||
- '|' -> elements on the right of this separator will be displayed from
|
||||
the right
|
||||
|
||||
**NOTE**: This patch is a dwl port of the [original](https://dwm.suckless.org/patches/barconfig/) barconfig patch for dwm.
|
||||
|
||||
### Known Issues With Patch
|
||||
Changing the location of the tags breaks the tag button presses (the buttons expect the click in the usual location of the tags). I do not have any plans to look into this, as I ported this patch for the sole purpose of having the option to omit the layout symbol from the bar.
|
||||
|
||||
### Download
|
||||
- [main 2025-10-24](/dwl/dwl-patches/raw/branch/main/patches/barconfig/barconfig.patch)
|
||||
|
||||
|
||||
### Authors - latest at top
|
||||
- Rumen Mitov
|
||||
Codeberg: [rumenmitov](https://codeberg.org/rumenmitov)
|
||||
Email: rumenmitov@protonmail.com
|
||||
@@ -0,0 +1,194 @@
|
||||
From e733fda4e498c998a104d0d5bb42b9c7373f2c9d Mon Sep 17 00:00:00 2001
|
||||
From: Rumen <rumenmitov@protonmail.com>
|
||||
Date: Fri, 24 Oct 2025 09:33:24 +0200
|
||||
Subject: [PATCH] Barconfig: Configure the dwl bar!
|
||||
|
||||
NOTE: This is a port of the original barconfig patch for dwm!
|
||||
|
||||
This patch provides configuration for the dwl bar via the variable
|
||||
`barlayout`. This determines which of the elements listed below to
|
||||
display on the bar and in which order:
|
||||
|
||||
- 't' -> the tags
|
||||
- 'l' -> the current layout symbol
|
||||
- 'n' -> the window name
|
||||
- 's' -> the status message
|
||||
- '|' -> elements on the right of this separator will be displayed from
|
||||
the right
|
||||
---
|
||||
config.def.h | 1 +
|
||||
dwl.c | 134 +++++++++++++++++++++++++++++++++++----------------
|
||||
2 files changed, 93 insertions(+), 42 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 1b7472d..c7a33d6 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -9,6 +9,7 @@ static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will
|
||||
static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
static const int showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
+static const char *barlayout = "tln|s";
|
||||
static const char *fonts[] = {"monospace:size=10"};
|
||||
static const float rootcolor[] = COLOR(0x000000ff);
|
||||
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index bf340d8..f0d72cf 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -1569,10 +1569,10 @@ dirtomon(enum wlr_direction dir)
|
||||
void
|
||||
drawbar(Monitor *m)
|
||||
{
|
||||
- int x, w, tw = 0;
|
||||
+ int x = 0, w, tw = 0, moveright = 0;
|
||||
int boxs = m->drw->font->height / 9;
|
||||
int boxw = m->drw->font->height / 6 + 2;
|
||||
- uint32_t i, occ = 0, urg = 0;
|
||||
+ uint32_t i, j, occ = 0, urg = 0;
|
||||
Client *c;
|
||||
Buffer *buf;
|
||||
|
||||
@@ -1581,48 +1581,99 @@ drawbar(Monitor *m)
|
||||
if (!(buf = bufmon(m)))
|
||||
return;
|
||||
|
||||
- /* draw status first so it can be overdrawn by tags later */
|
||||
- if (m == selmon) { /* status is only drawn on selected monitor */
|
||||
- drwl_setscheme(m->drw, colors[SchemeNorm]);
|
||||
- tw = TEXTW(m, stext) - m->lrpad + 2; /* 2px right padding */
|
||||
- drwl_text(m->drw, m->b.width - tw, 0, tw, m->b.height, 0, stext, 0);
|
||||
- }
|
||||
+ if (barlayout[0] == '\0')
|
||||
+ barlayout = "tln|s";
|
||||
+
|
||||
+ drwl_text(m->drw, 0, 0, m->w.width, m->b.height, 0, "", 0); /* draw background */
|
||||
+
|
||||
+ for (i = 0; i < strlen(barlayout); i++) {
|
||||
+ switch (barlayout[i]) {
|
||||
+ case 'l':
|
||||
+ w = TEXTW(m, m->ltsymbol);
|
||||
+ drwl_setscheme(m->drw, colors[SchemeNorm]);
|
||||
+ if (moveright) {
|
||||
+ x -= w;
|
||||
+ drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, m->ltsymbol, 0);
|
||||
+ } else
|
||||
+ x = drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, m->ltsymbol, 0);
|
||||
+ break;
|
||||
|
||||
- wl_list_for_each(c, &clients, link) {
|
||||
- if (c->mon != m)
|
||||
- continue;
|
||||
- occ |= c->tags;
|
||||
- if (c->isurgent)
|
||||
- urg |= c->tags;
|
||||
- }
|
||||
- x = 0;
|
||||
- c = focustop(m);
|
||||
- for (i = 0; i < LENGTH(tags); i++) {
|
||||
- w = TEXTW(m, tags[i]);
|
||||
- drwl_setscheme(m->drw, colors[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
|
||||
- drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, tags[i], urg & 1 << i);
|
||||
- if (occ & 1 << i)
|
||||
- drwl_rect(m->drw, x + boxs, boxs, boxw, boxw,
|
||||
- m == selmon && c && c->tags & 1 << i,
|
||||
- urg & 1 << i);
|
||||
- x += w;
|
||||
- }
|
||||
- w = TEXTW(m, m->ltsymbol);
|
||||
- drwl_setscheme(m->drw, colors[SchemeNorm]);
|
||||
- x = drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, m->ltsymbol, 0);
|
||||
-
|
||||
- if ((w = m->b.width - tw - x) > m->b.height) {
|
||||
- if (c) {
|
||||
- drwl_setscheme(m->drw, colors[m == selmon ? SchemeSel : SchemeNorm]);
|
||||
- drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, client_get_title(c), 0);
|
||||
- if (c && c->isfloating)
|
||||
- drwl_rect(m->drw, x + boxs, boxs, boxw, boxw, 0, 0);
|
||||
- } else {
|
||||
- drwl_setscheme(m->drw, colors[SchemeNorm]);
|
||||
- drwl_rect(m->drw, x, 0, w, m->b.height, 1, 1);
|
||||
- }
|
||||
- }
|
||||
+ case 'n':
|
||||
+ c = focustop(m);
|
||||
+
|
||||
+ if (c) {
|
||||
+ tw = TEXTW(m, client_get_title(c));
|
||||
+ if (moveright)
|
||||
+ x -= tw;
|
||||
+
|
||||
+ drwl_setscheme(m->drw, colors[m == selmon ? SchemeSel : SchemeNorm]);
|
||||
+ drwl_text(m->drw, x, 0, moveright ? tw : m->w.width, m->b.height, m->lrpad / 2, client_get_title(c), 0);
|
||||
+
|
||||
+ if (c && c->isfloating)
|
||||
+ drwl_rect(m->drw, x + boxs, boxs, boxw, boxw, 0, 0);
|
||||
+
|
||||
+ } else {
|
||||
+ drwl_setscheme(m->drw, colors[SchemeNorm]);
|
||||
+ drwl_rect(m->drw, x, 0, tw, m->b.height, 1, 1);
|
||||
+ }
|
||||
+
|
||||
+ if (!moveright)
|
||||
+ x += tw;
|
||||
+ break;
|
||||
+
|
||||
+ case 's':
|
||||
+ if (m == selmon) { /* status is only drawn on selected monitor */
|
||||
+ drwl_setscheme(m->drw, colors[SchemeNorm]);
|
||||
+ tw = TEXTW(m, stext) - m->lrpad + 2; /* 2px right padding */
|
||||
+ if (moveright) {
|
||||
+ x -= tw;
|
||||
+ drwl_text(m->drw, x, 0, tw, m->b.height, 0, stext, 0);
|
||||
+ } else
|
||||
+ x = drwl_text(m->drw, x, 0, tw, m->b.height, 0, stext, 0);
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ case 't':
|
||||
+ wl_list_for_each(c, &clients, link) {
|
||||
+ if (c->mon != m)
|
||||
+ continue;
|
||||
+ occ |= c->tags;
|
||||
+ if (c->isurgent)
|
||||
+ urg |= c->tags;
|
||||
+ }
|
||||
+
|
||||
+ c = focustop(m);
|
||||
+
|
||||
+ /* tags */
|
||||
+ if (moveright) {
|
||||
+ tw = 0;
|
||||
+ for (j = 0; j < LENGTH(tags); j++) {
|
||||
+ tw += TEXTW(m, tags[j]);
|
||||
+ }
|
||||
+ x -= tw;
|
||||
+ }
|
||||
+ for (j = 0; j < LENGTH(tags); j++) {
|
||||
+ w = TEXTW(m, tags[j]);
|
||||
+ drwl_setscheme(m->drw, colors[m->tagset[m->seltags] & 1 << j ? SchemeSel : SchemeNorm]);
|
||||
+ drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, tags[j], urg & 1 << j);
|
||||
+ if (occ & 1 << j)
|
||||
+ drwl_rect(m->drw, x + boxs, boxs, boxw, boxw,
|
||||
+ m == selmon && c && c->tags & 1 << j,
|
||||
+ urg & 1 << i);
|
||||
+ x += w;
|
||||
+ }
|
||||
+ if (moveright)
|
||||
+ x -= tw;
|
||||
+ break;
|
||||
+
|
||||
+ case '|':
|
||||
+ moveright = 1;
|
||||
+ x = m->w.width;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
|
||||
+
|
||||
wlr_scene_buffer_set_dest_size(m->scene_buffer,
|
||||
m->b.real_width, m->b.real_height);
|
||||
wlr_scene_node_set_position(&m->scene_buffer->node, m->m.x,
|
||||
--
|
||||
2.51.1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
From f109808140cd6323b3a100663a10e048ae32e3a0 Mon Sep 17 00:00:00 2001
|
||||
From 5fab55803d009d400f6c3fcbe6a0fc807431bbe7 Mon Sep 17 00:00:00 2001
|
||||
From: mmistika <mistikasoft@gmail.com>
|
||||
Date: Thu, 17 Jul 2025 11:59:18 +0200
|
||||
Subject: [PATCH] Add configurable window resize
|
||||
@@ -6,8 +6,8 @@ Subject: [PATCH] Add configurable window resize
|
||||
Signed-off-by: mmistika <mistikasoft@gmail.com>
|
||||
---
|
||||
config.def.h | 12 ++++++++++++
|
||||
dwl.c | 45 +++++++++++++++++++++++++++++++++++++--------
|
||||
2 files changed, 49 insertions(+), 8 deletions(-)
|
||||
dwl.c | 48 ++++++++++++++++++++++++++++++++++++++++--------
|
||||
2 files changed, 52 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 22d2171..e404549 100644
|
||||
@@ -33,7 +33,7 @@ index 22d2171..e404549 100644
|
||||
static const Rule rules[] = {
|
||||
/* app_id title tags mask isfloating monitor */
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index c717c1d..aacd074 100644
|
||||
index c717c1d..0d56b49 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -407,6 +407,7 @@ static KeyboardGroup *kb_group;
|
||||
@@ -44,7 +44,7 @@ index c717c1d..aacd074 100644
|
||||
|
||||
static struct wlr_output_layout *output_layout;
|
||||
static struct wlr_box sgeom;
|
||||
@@ -1873,8 +1874,24 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
|
||||
@@ -1873,8 +1874,27 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
|
||||
.width = grabc->geom.width, .height = grabc->geom.height}, 1);
|
||||
return;
|
||||
} else if (cursor_mode == CurResize) {
|
||||
@@ -53,6 +53,9 @@ index c717c1d..aacd074 100644
|
||||
+ int cdx = (int)round(cursor->x) - grabcx;
|
||||
+ int cdy = (int)round(cursor->y) - grabcy;
|
||||
+
|
||||
+ cdx = !(rzcorner & 1) && grabc->geom.width - 2 * (int)grabc->bw - cdx < 1 ? 0 : cdx;
|
||||
+ cdy = !(rzcorner & 2) && grabc->geom.height - 2 * (int)grabc->bw - cdy < 1 ? 0 : cdy;
|
||||
+
|
||||
+ const struct wlr_box box = {
|
||||
+ .x = grabc->geom.x + (rzcorner & 1 ? 0 : cdx),
|
||||
+ .y = grabc->geom.y + (rzcorner & 2 ? 0 : cdy),
|
||||
@@ -71,7 +74,7 @@ index c717c1d..aacd074 100644
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1920,12 +1937,24 @@ moveresize(const Arg *arg)
|
||||
@@ -1920,12 +1940,24 @@ moveresize(const Arg *arg)
|
||||
wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur");
|
||||
break;
|
||||
case CurResize:
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
### Description
|
||||
Borderless client if rule set to borderless
|
||||
|
||||
### Download
|
||||
[main 2025-11-29](/dwl/dwl-patches/raw/branch/main/patches/borderlessrule/borderlessrule.patch)
|
||||
|
||||
### Author
|
||||
- [freezboltz](https://codeberg.org/freezboltz)
|
||||
@@ -0,0 +1,71 @@
|
||||
From 2a81a809a648046f8361056af06dadf3397fecaa Mon Sep 17 00:00:00 2001
|
||||
From: Anant Murmu <freezboltz@gmail.com>
|
||||
Date: Tue, 2 Dec 2025 08:02:16 +0530
|
||||
Subject: [PATCH] fix: missing field in struct Rule isborderless
|
||||
|
||||
---
|
||||
config.def.h | 7 ++++---
|
||||
dwl.c | 7 ++++++-
|
||||
2 files changed, 10 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 95c2afa..9eee6ca 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -22,10 +22,11 @@ static int log_level = WLR_ERROR;
|
||||
|
||||
/* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g leave at least one example) */
|
||||
static const Rule rules[] = {
|
||||
- /* app_id title tags mask isfloating monitor */
|
||||
+ /* app_id title tags mask isfloating monitor isborderless */
|
||||
/* examples: */
|
||||
- { "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" */
|
||||
+ { "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" */
|
||||
+ { "foo_EXAMPLE", NULL, 0, 0, -1, 1 }, /* Start on currently visible tags with no border around it */
|
||||
};
|
||||
|
||||
/* layout(s) */
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 12f441e..572f754 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -137,7 +137,7 @@ typedef struct {
|
||||
#endif
|
||||
unsigned int bw;
|
||||
uint32_t tags;
|
||||
- int isfloating, isurgent, isfullscreen;
|
||||
+ int isfloating, isurgent, isborderless, isfullscreen;
|
||||
uint32_t resize; /* configure serial of a pending resize */
|
||||
} Client;
|
||||
|
||||
@@ -228,6 +228,7 @@ typedef struct {
|
||||
uint32_t tags;
|
||||
int isfloating;
|
||||
int monitor;
|
||||
+ int isborderless;
|
||||
} Rule;
|
||||
|
||||
typedef struct {
|
||||
@@ -490,6 +491,7 @@ applyrules(Client *c)
|
||||
if ((!r->title || strstr(title, r->title))
|
||||
&& (!r->id || strstr(appid, r->id))) {
|
||||
c->isfloating = r->isfloating;
|
||||
+ c->isborderless = r->isborderless;
|
||||
newtags |= r->tags;
|
||||
i = 0;
|
||||
wl_list_for_each(m, &mons, link) {
|
||||
@@ -2210,6 +2212,9 @@ resize(Client *c, struct wlr_box geo, int interact)
|
||||
if (!c->mon || !client_surface(c)->mapped)
|
||||
return;
|
||||
|
||||
+ if (c->isborderless)
|
||||
+ c->bw = 0;
|
||||
+
|
||||
bbox = interact ? &sgeom : &c->mon->w;
|
||||
|
||||
client_set_bounds(c, geo.width, geo.height);
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@@ -3,7 +3,7 @@ From: wochap <gean.marroquin@gmail.com>
|
||||
Date: Tue, 4 Jun 2024 16:02:25 -0500
|
||||
Subject: [PATCH] implement borders patch
|
||||
|
||||
tihs patch adds 2 extra borders relative to the client, they don't
|
||||
this patch adds 2 extra borders relative to the client, they don't
|
||||
change the size of the client
|
||||
---
|
||||
client.h | 16 +++++++++++++---
|
||||
|
||||
@@ -15,12 +15,14 @@ bstack (TTT) bstackhoriz (===)
|
||||
|
||||
|
||||
### Download
|
||||
- [v0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/bottomstack/bottomstack.patch)
|
||||
- [git branch](https://codeberg.org/wochap/dwl/src/branch/v0.6-b/bottomstack)
|
||||
- [2024-07-09](https://codeberg.org/dwl/dwl-patches/raw/commit/20de07dc8759200c8a4c9651475acb331d245890/patches/bottomstack/bottomstack.patch)
|
||||
- [2024-04-11](https://codeberg.org/dwl/dwl-patches/raw/commit/0f4e40fee49d1b8b430778e241b29496ae3b3b70/bottomstack/bottomstack.patch)
|
||||
- [v0.5](https://codeberg.org/dwl/dwl-patches/raw/commit/5368aa392c7ebf8d7d24c232b80cfae1be457d41/bottomstack/bottomstack.patch)
|
||||
|
||||
### Authors
|
||||
- [unixchad](https://codeberg.org/unixchad)
|
||||
- [wochap](https://codeberg.org/wochap)
|
||||
- [DanielMowitz](https://github.com/DanielMowitz)
|
||||
- [Abanoub8](https://github.com/Abanoub8)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
From b352fb08f40b1ee2d8c4748be4922df711e3aaa9 Mon Sep 17 00:00:00 2001
|
||||
From: wochap <gean.marroquin@gmail.com>
|
||||
Date: Fri, 5 Jul 2024 10:44:29 -0500
|
||||
Subject: [PATCH] implement bottomstack
|
||||
From 86e379b187bcc9f8f5896a87309474fcf3736de9 Mon Sep 17 00:00:00 2001
|
||||
From: nate zhou <gnuunixchad@outlook.com>
|
||||
Date: Sat, 28 Feb 2026 21:29:53 +0800
|
||||
Subject: [PATCH] Patch: bottomstack-0.8.patch
|
||||
|
||||
---
|
||||
config.def.h | 4 +++
|
||||
@@ -9,10 +9,10 @@ Subject: [PATCH] implement bottomstack
|
||||
2 files changed, 88 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 22d2171..5aac3e9 100644
|
||||
index 8a6eda0..ae87518 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -34,6 +34,8 @@ static const Layout layouts[] = {
|
||||
@@ -33,6 +33,8 @@ static const Layout layouts[] = {
|
||||
{ "[]=", tile },
|
||||
{ "><>", NULL }, /* no layout function means floating behavior */
|
||||
{ "[M]", monocle },
|
||||
@@ -21,20 +21,20 @@ index 22d2171..5aac3e9 100644
|
||||
};
|
||||
|
||||
/* monitors */
|
||||
@@ -139,6 +141,8 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
|
||||
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
|
||||
+ { MODKEY, XKB_KEY_u, setlayout, {.v = &layouts[3]} },
|
||||
+ { MODKEY, XKB_KEY_o, setlayout, {.v = &layouts[4]} },
|
||||
{ MODKEY, XKB_KEY_space, setlayout, {0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
|
||||
{ MODKEY, XKB_KEY_e, togglefullscreen, {0} },
|
||||
@@ -135,6 +137,8 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
|
||||
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
|
||||
+ { MODKEY, XKB_KEY_u, setlayout, {.v = &layouts[3]} },
|
||||
+ { MODKEY, XKB_KEY_o, setlayout, {.v = &layouts[4]} },
|
||||
{ MODKEY, XKB_KEY_space, setlayout, {0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
|
||||
{ MODKEY, XKB_KEY_e, togglefullscreen, {0} },
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index dc0437e..5648d5f 100644
|
||||
index 44f3ad9..68c25a5 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -57,6 +57,7 @@
|
||||
@@ -59,6 +59,7 @@
|
||||
#include <wlr/types/wlr_xdg_decoration_v1.h>
|
||||
#include <wlr/types/wlr_xdg_output_v1.h>
|
||||
#include <wlr/types/wlr_xdg_shell.h>
|
||||
@@ -50,8 +50,8 @@ index dc0437e..5648d5f 100644
|
||||
+static void bstackhoriz(Monitor *m);
|
||||
|
||||
/* variables */
|
||||
static const char broken[] = "broken";
|
||||
@@ -3160,3 +3163,84 @@ main(int argc, char *argv[])
|
||||
static pid_t child_pid = -1;
|
||||
@@ -3213,3 +3216,84 @@ main(int argc, char *argv[])
|
||||
usage:
|
||||
die("Usage: %s [-v] [-d] [-s startup command]", argv[0]);
|
||||
}
|
||||
@@ -137,4 +137,5 @@ index dc0437e..5648d5f 100644
|
||||
+ }
|
||||
+}
|
||||
--
|
||||
2.45.1
|
||||
2.53.0
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
It provides a focus-driven, mouse- and keyboard-friendly tiling layout that grants you granular control over how clients are placed and resized.
|
||||
|
||||

|
||||

|
||||
|
||||
---
|
||||
|
||||
@@ -61,7 +61,7 @@ When a new client appears:
|
||||
btrtile adds couple variables to config.h to fine tune the mouse resizing of tiled clients.
|
||||
|
||||
1. **resize_factor**
|
||||
- A multiplier to transfer pointer movement to client weight ratio. Depends heavily on mouse sensivity.
|
||||
- A multiplier to transfer pointer movement to client weight ratio. Depends heavily on mouse sensitivity.
|
||||
Defaults to 0.0002f.
|
||||
|
||||
2. **resize_interval_ms**
|
||||
@@ -96,8 +96,10 @@ If mouse resizing feels sluggish, you can try compiling dwl with more aggressive
|
||||
|
||||
### Download
|
||||
- [git branch](https://codeberg.org/julmajustus/dwl/src/branch/btrtile-dev)
|
||||
- [0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/btrtile/btrtile-v0.7.patch)
|
||||
- [0.7 WITH gaps](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/btrtile/btrtile-v0.7-gaps.patch)
|
||||
- [0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/btrtile/btrtile-v0.8.patch)
|
||||
- [0.8 WITH gaps](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/btrtile/btrtile-v0.8-gaps.patch)
|
||||
- [wlroots-next](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/btrtile/btrtile-wlroots-next-d41ecb7.patch)
|
||||
- [wlroots-next WITH gaps](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/btrtile/btrtile-wlroots-next-d41ecb7-gaps.patch)
|
||||
|
||||
### Authors
|
||||
- [julmajustus](https://codeberg.org/julmajustus)
|
||||
|
||||
@@ -0,0 +1,929 @@
|
||||
From 1520d1f200ef0fb381683c1bcd58e553b52ac289 Mon Sep 17 00:00:00 2001
|
||||
From: julmajustus <julmajustus@tutanota.com>
|
||||
Date: Thu, 21 May 2026 00:42:07 +0300
|
||||
Subject: [PATCH] btrtile: Spring update pt2
|
||||
|
||||
- Simplified the resizing logic to avoid full arrange calls from
|
||||
motionnotify
|
||||
- Minor intend fixes
|
||||
---
|
||||
btrtile.c | 583 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
config.def.h | 12 ++
|
||||
dwl.c | 152 +++++++++++---
|
||||
3 files changed, 720 insertions(+), 27 deletions(-)
|
||||
create mode 100644 btrtile.c
|
||||
|
||||
diff --git a/btrtile.c b/btrtile.c
|
||||
new file mode 100644
|
||||
index 0000000..f05a30f
|
||||
--- /dev/null
|
||||
+++ b/btrtile.c
|
||||
@@ -0,0 +1,583 @@
|
||||
+/* ************************************************************************** */
|
||||
+/* @@@ @@@@@@@@ */
|
||||
+/* @@@ @@@@@@@@@@ */
|
||||
+/* @@! @@! @@@@ */
|
||||
+/* !@! !@! @!@!@ */
|
||||
+/* btrtile.c @!! @!@ @! !@! */
|
||||
+/* !!! !@!!! !!! */
|
||||
+/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */
|
||||
+/* ::! :!: !:! */
|
||||
+/* Created: 2024/12/15 00:26:07 by julmajustus :: ::::::: :: */
|
||||
+/* Updated: 2026/05/20 22:38:02 by julmajustus : : : : : : */
|
||||
+/* */
|
||||
+/* ************************************************************************** */
|
||||
+
|
||||
+typedef struct LayoutNode {
|
||||
+ unsigned int is_client_node;
|
||||
+ unsigned int is_split_vertically;
|
||||
+ float split_ratio;
|
||||
+ struct LayoutNode *left;
|
||||
+ struct LayoutNode *right;
|
||||
+ struct LayoutNode *split_node;
|
||||
+ Client *client;
|
||||
+} LayoutNode;
|
||||
+
|
||||
+static void apply_layout(Monitor *m, LayoutNode *node,
|
||||
+ struct wlr_box area, unsigned int is_root);
|
||||
+static void btrtile(Monitor *m);
|
||||
+static LayoutNode *create_client_node(Client *c);
|
||||
+static LayoutNode *create_split_node(unsigned int is_split_vertically,
|
||||
+ LayoutNode *left, LayoutNode *right);
|
||||
+static void destroy_node(LayoutNode *node);
|
||||
+static void destroy_tree(Monitor *m);
|
||||
+static LayoutNode *find_client_node(LayoutNode *node, Client *c);
|
||||
+static LayoutNode *find_suitable_split(Monitor *m, LayoutNode *start,
|
||||
+ unsigned int need_vertical, int focused_on_left);
|
||||
+static void init_tree(Monitor *m);
|
||||
+static void insert_client(Monitor *m, Client *focused_client, Client *new_client);
|
||||
+static LayoutNode *remove_client_node(LayoutNode *node, Client *c);
|
||||
+static void remove_client(Monitor *m, Client *c);
|
||||
+static void setratio_h(const Arg *arg);
|
||||
+static void setratio_v(const Arg *arg);
|
||||
+static void swapclients(const Arg *arg);
|
||||
+static unsigned int visible_count(LayoutNode *node, Monitor *m);
|
||||
+static Client *xytoclient(double x, double y);
|
||||
+
|
||||
+static double resize_last_update_x, resize_last_update_y;
|
||||
+static uint32_t last_resize_time = 0;
|
||||
+
|
||||
+void
|
||||
+apply_layout(Monitor *m, LayoutNode *node,
|
||||
+ struct wlr_box area, unsigned int is_root)
|
||||
+{
|
||||
+ Client *c;
|
||||
+ float ratio;
|
||||
+ unsigned int left_count, right_count, mid, e = m->gaps;
|
||||
+ struct wlr_box left_area, right_area;
|
||||
+
|
||||
+ if (!node)
|
||||
+ return;
|
||||
+
|
||||
+ if (is_root && e) {
|
||||
+ area.x += gappx;
|
||||
+ area.y += gappx;
|
||||
+ area.width -= 2 * gappx;
|
||||
+ area.height -= 2 * gappx;
|
||||
+ }
|
||||
+
|
||||
+ /* If this node is a client node, check if it is visible. */
|
||||
+ if (node->is_client_node) {
|
||||
+ c = node->client;
|
||||
+ if (!c || !VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||
+ return;
|
||||
+ if (area.x == c->old_geom.x && area.y == c->old_geom.y &&
|
||||
+ area.width == c->old_geom.width && area.height == c->old_geom.height)
|
||||
+ return;
|
||||
+ resize(c, area, 0);
|
||||
+ c->old_geom = area;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* For a split node, we see how many visible children are on each side: */
|
||||
+ left_count = visible_count(node->left, m);
|
||||
+ right_count = visible_count(node->right, m);
|
||||
+
|
||||
+ if (left_count == 0 && right_count == 0) {
|
||||
+ return;
|
||||
+ } else if (left_count > 0 && right_count == 0) {
|
||||
+ apply_layout(m, node->left, area, 0);
|
||||
+ return;
|
||||
+ } else if (left_count == 0 && right_count > 0) {
|
||||
+ apply_layout(m, node->right, area, 0);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* If we’re here, we have visible clients in both subtrees. */
|
||||
+ ratio = node->split_ratio;
|
||||
+ if (ratio < 0.05f)
|
||||
+ ratio = 0.05f;
|
||||
+ if (ratio > 0.95f)
|
||||
+ ratio = 0.95f;
|
||||
+
|
||||
+ memset(&left_area, 0, sizeof(left_area));
|
||||
+ memset(&right_area, 0, sizeof(right_area));
|
||||
+
|
||||
+ if (node->is_split_vertically) {
|
||||
+ mid = (unsigned int)(area.width * ratio);
|
||||
+ left_area.x = area.x;
|
||||
+ left_area.y = area.y;
|
||||
+ left_area.width = mid;
|
||||
+ left_area.height = area.height;
|
||||
+
|
||||
+ right_area.x = area.x + mid;
|
||||
+ right_area.y = area.y;
|
||||
+ right_area.width = area.width - mid;
|
||||
+ right_area.height = area.height;
|
||||
+
|
||||
+ if (e) {
|
||||
+ left_area.width -= gappx / 2;
|
||||
+ right_area.x += gappx / 2;
|
||||
+ right_area.width -= gappx / 2;
|
||||
+ }
|
||||
+ } else {
|
||||
+ /* horizontal split */
|
||||
+ mid = (unsigned int)(area.height * ratio);
|
||||
+ left_area.x = area.x;
|
||||
+ left_area.y = area.y;
|
||||
+ left_area.width = area.width;
|
||||
+ left_area.height = mid;
|
||||
+
|
||||
+ right_area.x = area.x;
|
||||
+ right_area.y = area.y + mid;
|
||||
+ right_area.width = area.width;
|
||||
+ right_area.height= area.height - mid;
|
||||
+
|
||||
+ if (e) {
|
||||
+ left_area.height -= gappx / 2;
|
||||
+ right_area.y += gappx / 2;
|
||||
+ right_area.height -= gappx / 2;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ apply_layout(m, node->left, left_area, 0);
|
||||
+ apply_layout(m, node->right, right_area, 0);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+btrtile(Monitor *m)
|
||||
+{
|
||||
+ Client *c, *focused = NULL;
|
||||
+ int n = 0;
|
||||
+ LayoutNode *found;
|
||||
+ struct wlr_box full_area;
|
||||
+
|
||||
+ if (!m)
|
||||
+ return;
|
||||
+
|
||||
+ /* Remove non tiled clients from tree. */
|
||||
+ wl_list_for_each(c, &clients, link) {
|
||||
+ if (c->mon == m && !c->isfloating && !c->isfullscreen) {
|
||||
+ } else {
|
||||
+ remove_client(m, c);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* If no client is found under cursor, fallback to focustop(m) */
|
||||
+ if (!(focused = xytoclient(cursor->x, cursor->y)))
|
||||
+ focused = focustop(m);
|
||||
+
|
||||
+ /* Insert visible clients that are not part of the tree. */
|
||||
+ wl_list_for_each(c, &clients, link) {
|
||||
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen && c->mon == m) {
|
||||
+ found = find_client_node(m->root, c);
|
||||
+ if (!found) {
|
||||
+ insert_client(m, focused, c);
|
||||
+ }
|
||||
+ n++;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (n == 0)
|
||||
+ return;
|
||||
+
|
||||
+ full_area = m->w;
|
||||
+ apply_layout(m, m->root, full_area, 1);
|
||||
+}
|
||||
+
|
||||
+LayoutNode *
|
||||
+create_client_node(Client *c)
|
||||
+{
|
||||
+ LayoutNode *node = calloc(1, sizeof(LayoutNode));
|
||||
+
|
||||
+ if (!node)
|
||||
+ return NULL;
|
||||
+ node->is_client_node = 1;
|
||||
+ node->split_ratio = 0.5f;
|
||||
+ node->client = c;
|
||||
+ return node;
|
||||
+}
|
||||
+
|
||||
+LayoutNode *
|
||||
+create_split_node(unsigned int is_split_vertically,
|
||||
+ LayoutNode *left, LayoutNode *right)
|
||||
+{
|
||||
+ LayoutNode *node = calloc(1, sizeof(LayoutNode));
|
||||
+
|
||||
+ if (!node)
|
||||
+ return NULL;
|
||||
+ node->is_client_node = 0;
|
||||
+ node->split_ratio = 0.5f;
|
||||
+ node->is_split_vertically = is_split_vertically;
|
||||
+ node->left = left;
|
||||
+ node->right = right;
|
||||
+ if (left)
|
||||
+ left->split_node = node;
|
||||
+ if (right)
|
||||
+ right->split_node = node;
|
||||
+ return node;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+destroy_node(LayoutNode *node)
|
||||
+{
|
||||
+ if (!node)
|
||||
+ return;
|
||||
+ if (!node->is_client_node) {
|
||||
+ destroy_node(node->left);
|
||||
+ destroy_node(node->right);
|
||||
+ }
|
||||
+ free(node);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+destroy_tree(Monitor *m)
|
||||
+{
|
||||
+ if (!m || !m->root)
|
||||
+ return;
|
||||
+ destroy_node(m->root);
|
||||
+ m->root = NULL;
|
||||
+}
|
||||
+
|
||||
+LayoutNode *
|
||||
+find_client_node(LayoutNode *node, Client *c)
|
||||
+{
|
||||
+ LayoutNode *res;
|
||||
+
|
||||
+ if (!node || !c)
|
||||
+ return NULL;
|
||||
+ if (node->is_client_node) {
|
||||
+ return (node->client == c) ? node : NULL;
|
||||
+ }
|
||||
+ res = find_client_node(node->left, c);
|
||||
+ return res ? res : find_client_node(node->right, c);
|
||||
+}
|
||||
+
|
||||
+LayoutNode *
|
||||
+find_suitable_split(Monitor *m, LayoutNode *start_node,
|
||||
+ unsigned int need_vertical, int focused_on_left)
|
||||
+{
|
||||
+ LayoutNode *n = start_node, *child = NULL;
|
||||
+
|
||||
+ if (!m)
|
||||
+ return NULL;
|
||||
+
|
||||
+ if (n && n->is_client_node) {
|
||||
+ child = n;
|
||||
+ n = n->split_node;
|
||||
+ }
|
||||
+
|
||||
+ while (n) {
|
||||
+ if (!n->is_client_node && n->is_split_vertically == need_vertical
|
||||
+ && visible_count(n->left, m) > 0
|
||||
+ && visible_count(n->right, m) > 0) {
|
||||
+ if ((focused_on_left && n->left == child) ||
|
||||
+ (!focused_on_left && n->right == child))
|
||||
+ return n;
|
||||
+ }
|
||||
+ child = n;
|
||||
+ n = n->split_node;
|
||||
+ }
|
||||
+ return NULL;
|
||||
+}
|
||||
+void
|
||||
+init_tree(Monitor *m)
|
||||
+{
|
||||
+ if (m)
|
||||
+ m->root = NULL;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+insert_client(Monitor *m, Client *focused_client, Client *new_client)
|
||||
+{
|
||||
+ Client *old_client;
|
||||
+ LayoutNode **root = &m->root, *old_root,
|
||||
+ *focused_node, *new_client_node, *old_client_node;
|
||||
+ unsigned int wider, mid_x, mid_y;
|
||||
+
|
||||
+ /* If no root , new client becomes the root. */
|
||||
+ if (!*root) {
|
||||
+ *root = create_client_node(new_client);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* Find the focused_client node,
|
||||
+ * if not found split the root. */
|
||||
+ focused_node = focused_client ?
|
||||
+ find_client_node(*root, focused_client) : NULL;
|
||||
+ if (!focused_node) {
|
||||
+ old_root = *root;
|
||||
+ new_client_node = create_client_node(new_client);
|
||||
+ *root = create_split_node(1, old_root, new_client_node);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* Turn focused node from a client node into a split node,
|
||||
+ * and attach old_client + new_client. */
|
||||
+ old_client = focused_node->client;
|
||||
+ old_client_node = create_client_node(old_client);
|
||||
+ new_client_node = create_client_node(new_client);
|
||||
+
|
||||
+ /* Decide split direction. */
|
||||
+ wider = (focused_client->geom.width >= focused_client->geom.height);
|
||||
+ focused_node->is_client_node = 0;
|
||||
+ focused_node->client = NULL;
|
||||
+ focused_node->is_split_vertically = (wider ? 1 : 0);
|
||||
+
|
||||
+ /* Pick new_client side depending on the cursor position. */
|
||||
+ mid_x = focused_client->geom.x + focused_client->geom.width / 2;
|
||||
+ mid_y = focused_client->geom.y + focused_client->geom.height / 2;
|
||||
+
|
||||
+ if (wider) {
|
||||
+ /* vertical split => left vs right */
|
||||
+ if (cursor->x <= mid_x) {
|
||||
+ focused_node->left = new_client_node;
|
||||
+ focused_node->right = old_client_node;
|
||||
+ } else {
|
||||
+ focused_node->left = old_client_node;
|
||||
+ focused_node->right = new_client_node;
|
||||
+ }
|
||||
+ } else {
|
||||
+ /* horizontal split => top vs bottom */
|
||||
+ if (cursor->y <= mid_y) {
|
||||
+ focused_node->left = new_client_node;
|
||||
+ focused_node->right = old_client_node;
|
||||
+ } else {
|
||||
+ focused_node->left = old_client_node;
|
||||
+ focused_node->right = new_client_node;
|
||||
+ }
|
||||
+ }
|
||||
+ old_client_node->split_node = focused_node;
|
||||
+ new_client_node->split_node = focused_node;
|
||||
+ focused_node->split_ratio = 0.5f;
|
||||
+}
|
||||
+
|
||||
+LayoutNode *
|
||||
+remove_client_node(LayoutNode *node, Client *c)
|
||||
+{
|
||||
+ LayoutNode *tmp;
|
||||
+ if (!node)
|
||||
+ return NULL;
|
||||
+ if (node->is_client_node) {
|
||||
+ /* If this client_node is the client we're removing,
|
||||
+ * return NULL to remove it */
|
||||
+ if (node->client == c) {
|
||||
+ free(node);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ return node;
|
||||
+ }
|
||||
+
|
||||
+ node->left = remove_client_node(node->left, c);
|
||||
+ node->right = remove_client_node(node->right, c);
|
||||
+
|
||||
+ /* If one of the client node is NULL after removal and the other is not,
|
||||
+ * we "lift" the other client node up to replace this split node. */
|
||||
+ if (!node->left && node->right) {
|
||||
+ tmp = node->right;
|
||||
+
|
||||
+ /* Save pointer to split node */
|
||||
+ if (tmp)
|
||||
+ tmp->split_node = node->split_node;
|
||||
+
|
||||
+ free(node);
|
||||
+ return tmp;
|
||||
+ }
|
||||
+
|
||||
+ if (!node->right && node->left) {
|
||||
+ tmp = node->left;
|
||||
+
|
||||
+ /* Save pointer to split node */
|
||||
+ if (tmp)
|
||||
+ tmp->split_node = node->split_node;
|
||||
+
|
||||
+ free(node);
|
||||
+ return tmp;
|
||||
+ }
|
||||
+
|
||||
+ /* If both children exist or both are NULL (empty tree),
|
||||
+ * return node as is. */
|
||||
+ return node;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+remove_client(Monitor *m, Client *c)
|
||||
+{
|
||||
+ if (!m->root || !c)
|
||||
+ return;
|
||||
+ m->root = remove_client_node(m->root, c);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+setratio(unsigned int need_vertical, const Arg *arg)
|
||||
+{
|
||||
+ Client *sel;
|
||||
+ LayoutNode *client_node, *split_node;
|
||||
+ float new_ratio;
|
||||
+ int focused_on_left;
|
||||
+
|
||||
+ if (!selmon || !selmon->lt[selmon->sellt]->arrange)
|
||||
+ return;
|
||||
+
|
||||
+ sel = focustop(selmon);
|
||||
+ if (!sel)
|
||||
+ return;
|
||||
+
|
||||
+ client_node = find_client_node(selmon->root, sel);
|
||||
+ if (!client_node)
|
||||
+ return;
|
||||
+
|
||||
+ focused_on_left = (arg->f >= 0.0f);
|
||||
+
|
||||
+ split_node = find_suitable_split(selmon, client_node, need_vertical, focused_on_left);
|
||||
+
|
||||
+ if (!split_node)
|
||||
+ split_node = find_suitable_split(selmon, client_node, need_vertical, !focused_on_left);
|
||||
+ if (!split_node)
|
||||
+ return;
|
||||
+
|
||||
+ new_ratio = (arg->f != 0.0f) ? (split_node->split_ratio + arg->f) : 0.5f;
|
||||
+ if (new_ratio < 0.05f)
|
||||
+ new_ratio = 0.05f;
|
||||
+ if (new_ratio > 0.95f)
|
||||
+ new_ratio = 0.95f;
|
||||
+ split_node->split_ratio = new_ratio;
|
||||
+
|
||||
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
||||
+ /* Skip the arrange when called from motionnotify; that path calls
|
||||
+ * arrange itself after rate-limiting. */
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+setratio_h(const Arg *arg)
|
||||
+{
|
||||
+ setratio(1, arg);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+setratio_v(const Arg *arg)
|
||||
+{
|
||||
+ setratio(0, arg);
|
||||
+}
|
||||
+
|
||||
+void swapclients(const Arg *arg) {
|
||||
+ Client *c, *tmp, *target = NULL, *sel = focustop(selmon);
|
||||
+ LayoutNode *sel_node, *target_node;
|
||||
+ int closest_dist = INT_MAX, dist, sel_center_x, sel_center_y,
|
||||
+ cand_center_x, cand_center_y;
|
||||
+
|
||||
+ if (!sel || sel->isfullscreen ||
|
||||
+ !selmon->root || !selmon->lt[selmon->sellt]->arrange)
|
||||
+ return;
|
||||
+
|
||||
+
|
||||
+ /* Get the center coordinates of the selected client */
|
||||
+ sel_center_x = sel->geom.x + sel->geom.width / 2;
|
||||
+ sel_center_y = sel->geom.y + sel->geom.height / 2;
|
||||
+
|
||||
+ wl_list_for_each(c, &clients, link) {
|
||||
+ if (!VISIBLEON(c, selmon) || c->isfloating || c->isfullscreen || c == sel)
|
||||
+ continue;
|
||||
+
|
||||
+ /* Get the center of candidate client */
|
||||
+ cand_center_x = c->geom.x + c->geom.width / 2;
|
||||
+ cand_center_y = c->geom.y + c->geom.height / 2;
|
||||
+
|
||||
+ /* Check that the candidate lies in the requested direction. */
|
||||
+ switch (arg->ui) {
|
||||
+ case 0:
|
||||
+ if (cand_center_x >= sel_center_x)
|
||||
+ continue;
|
||||
+ break;
|
||||
+ case 1:
|
||||
+ if (cand_center_x <= sel_center_x)
|
||||
+ continue;
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ if (cand_center_y >= sel_center_y)
|
||||
+ continue;
|
||||
+ break;
|
||||
+ case 3:
|
||||
+ if (cand_center_y <= sel_center_y)
|
||||
+ continue;
|
||||
+ break;
|
||||
+ default:
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ /* Get distance between the centers */
|
||||
+ dist = abs(sel_center_x - cand_center_x) + abs(sel_center_y - cand_center_y);
|
||||
+ if (dist < closest_dist) {
|
||||
+ closest_dist = dist;
|
||||
+ target = c;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* If target is found, swap the two clients’ positions in the layout tree */
|
||||
+ if (target) {
|
||||
+ sel_node = find_client_node(selmon->root, sel);
|
||||
+ target_node = find_client_node(selmon->root, target);
|
||||
+ if (sel_node && target_node) {
|
||||
+ tmp = sel_node->client;
|
||||
+ sel_node->client = target_node->client;
|
||||
+ target_node->client = tmp;
|
||||
+ arrange(selmon);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+unsigned int
|
||||
+visible_count(LayoutNode *node, Monitor *m)
|
||||
+{
|
||||
+ Client *c;
|
||||
+
|
||||
+ if (!node)
|
||||
+ return 0;
|
||||
+ /* Check if this client is visible. */
|
||||
+ if (node->is_client_node) {
|
||||
+ c = node->client;
|
||||
+ if (c && VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen)
|
||||
+ return 1;
|
||||
+ return 0;
|
||||
+ }
|
||||
+ /* Else it’s a split node. */
|
||||
+ return visible_count(node->left, m) + visible_count(node->right, m);
|
||||
+}
|
||||
+
|
||||
+Client *
|
||||
+xytoclient(double x, double y) {
|
||||
+ Monitor *m = xytomon(x, y);
|
||||
+ Client *c, *closest = NULL;
|
||||
+ double dist, mindist = INT_MAX, dx, dy;
|
||||
+
|
||||
+ wl_list_for_each_reverse(c, &clients, link) {
|
||||
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen &&
|
||||
+ x >= c->geom.x && x <= (c->geom.x + c->geom.width) &&
|
||||
+ y >= c->geom.y && y <= (c->geom.y + c->geom.height)){
|
||||
+ return c;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* If no client was found at cursor position fallback to closest. */
|
||||
+ wl_list_for_each_reverse(c, &clients, link) {
|
||||
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen) {
|
||||
+ dx = 0, dy = 0;
|
||||
+
|
||||
+ if (x < c->geom.x)
|
||||
+ dx = c->geom.x - x;
|
||||
+ else if (x > (c->geom.x + c->geom.width))
|
||||
+ dx = x - (c->geom.x + c->geom.width);
|
||||
+
|
||||
+ if (y < c->geom.y)
|
||||
+ dy = c->geom.y - y;
|
||||
+ else if (y > (c->geom.y + c->geom.height))
|
||||
+ dy = y - (c->geom.y + c->geom.height);
|
||||
+
|
||||
+ dist = dx * dx + dy * dy;
|
||||
+ if (dist < mindist) {
|
||||
+ mindist = dist;
|
||||
+ closest = c;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return closest;
|
||||
+}
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 8a6eda0..bc04e3f 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -13,7 +13,10 @@ static const float focuscolor[] = COLOR(0x005577ff);
|
||||
static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
||||
static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */
|
||||
+static const float resize_factor = 0.0002f; /* Resize multiplier for mouse resizing, depends on mouse sensivity. */
|
||||
+static const uint32_t resize_interval_ms = 16; /* Resize interval depends on framerate and screen refresh rate. */
|
||||
|
||||
+enum Direction { DIR_LEFT, DIR_RIGHT, DIR_UP, DIR_DOWN };
|
||||
/* tagging - TAGCOUNT must be no greater than 31 */
|
||||
#define TAGCOUNT (9)
|
||||
|
||||
@@ -30,6 +33,7 @@ static const Rule rules[] = {
|
||||
/* layout(s) */
|
||||
static const Layout layouts[] = {
|
||||
/* symbol arrange function */
|
||||
+ { "|w|", btrtile },
|
||||
{ "[]=", tile },
|
||||
{ "><>", NULL }, /* no layout function means floating behavior */
|
||||
{ "[M]", monocle },
|
||||
@@ -144,6 +148,14 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less, tagmon, {.i = WLR_DIRECTION_LEFT} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Up, swapclients, {.i = DIR_UP} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Down, swapclients, {.i = DIR_DOWN} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Right, swapclients, {.i = DIR_RIGHT} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Left, swapclients, {.i = DIR_LEFT} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Right, setratio_h, {.f = +0.025f} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Left, setratio_h, {.f = -0.025f} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Up, setratio_v, {.f = -0.025f} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Down, setratio_v, {.f = +0.025f} },
|
||||
TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0),
|
||||
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
|
||||
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 44f3ad9..a121efc 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* See LICENSE file for copyright and license details.
|
||||
*/
|
||||
+#include <limits.h>
|
||||
#include <getopt.h>
|
||||
#include <libinput.h>
|
||||
#include <linux/input-event-codes.h>
|
||||
@@ -100,6 +101,7 @@ typedef struct {
|
||||
const Arg arg;
|
||||
} Button;
|
||||
|
||||
+typedef struct LayoutNode LayoutNode;
|
||||
typedef struct Monitor Monitor;
|
||||
typedef struct {
|
||||
/* Must keep this field first */
|
||||
@@ -137,8 +139,9 @@ typedef struct {
|
||||
#endif
|
||||
unsigned int bw;
|
||||
uint32_t tags;
|
||||
- int isfloating, isurgent, isfullscreen;
|
||||
+ int isfloating, isurgent, isfullscreen, was_tiled;
|
||||
uint32_t resize; /* configure serial of a pending resize */
|
||||
+ struct wlr_box old_geom;
|
||||
} Client;
|
||||
|
||||
typedef struct {
|
||||
@@ -205,6 +208,7 @@ struct Monitor {
|
||||
int nmaster;
|
||||
char ltsymbol[16];
|
||||
int asleep;
|
||||
+ LayoutNode *root;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -247,6 +251,7 @@ static void arrangelayer(Monitor *m, struct wl_list *list,
|
||||
struct wlr_box *usable_area, int exclusive);
|
||||
static void arrangelayers(Monitor *m);
|
||||
static void axisnotify(struct wl_listener *listener, void *data);
|
||||
+static void btrtile(Monitor *m);
|
||||
static void buttonpress(struct wl_listener *listener, void *data);
|
||||
static void chvt(const Arg *arg);
|
||||
static void checkidleinhibitor(struct wlr_surface *exclude);
|
||||
@@ -329,6 +334,9 @@ static void setmon(Client *c, Monitor *m, uint32_t newtags);
|
||||
static void setpsel(struct wl_listener *listener, void *data);
|
||||
static void setsel(struct wl_listener *listener, void *data);
|
||||
static void setup(void);
|
||||
+static void setratio_h(const Arg *arg);
|
||||
+static void setratio_v(const Arg *arg);
|
||||
+static void swapclients(const Arg *arg);
|
||||
static void spawn(const Arg *arg);
|
||||
static void startdrag(struct wl_listener *listener, void *data);
|
||||
static void tag(const Arg *arg);
|
||||
@@ -454,6 +462,7 @@ static struct wlr_xwayland *xwayland;
|
||||
|
||||
/* attempt to encapsulate suck into one file */
|
||||
#include "client.h"
|
||||
+#include "btrtile.c"
|
||||
|
||||
/* function implementations */
|
||||
void
|
||||
@@ -624,7 +633,7 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
struct wlr_pointer_button_event *event = data;
|
||||
struct wlr_keyboard *keyboard;
|
||||
uint32_t mods;
|
||||
- Client *c;
|
||||
+ Client *c, *target = NULL;
|
||||
const Button *b;
|
||||
|
||||
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
||||
@@ -645,7 +654,7 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
|
||||
for (b = buttons; b < END(buttons); b++) {
|
||||
if (CLEANMASK(mods) == CLEANMASK(b->mod) &&
|
||||
- event->button == b->button && b->func) {
|
||||
+ event->button == b->button && b->func) {
|
||||
b->func(&b->arg);
|
||||
return;
|
||||
}
|
||||
@@ -655,6 +664,21 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
/* If you released any buttons, we exit interactive move/resize mode. */
|
||||
/* TODO: should reset to the pointer focus's current setcursor */
|
||||
if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
|
||||
+ c = grabc;
|
||||
+ if (c && c->was_tiled && !strcmp(selmon->ltsymbol, "|w|")) {
|
||||
+ if (cursor_mode == CurMove && c->isfloating) {
|
||||
+ target = xytoclient(cursor->x, cursor->y);
|
||||
+
|
||||
+ if (target && !target->isfloating && !target->isfullscreen)
|
||||
+ insert_client(selmon, target, c);
|
||||
+ else
|
||||
+ selmon->root = create_client_node(c);
|
||||
+
|
||||
+ setfloating(c, 0);
|
||||
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
||||
+ }
|
||||
+ }
|
||||
+ /* Default behaviour */
|
||||
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
||||
cursor_mode = CurNormal;
|
||||
/* Drop the window off on its new monitor */
|
||||
@@ -746,6 +770,7 @@ cleanupmon(struct wl_listener *listener, void *data)
|
||||
wlr_output_layout_remove(output_layout, m->wlr_output);
|
||||
wlr_scene_output_destroy(m->scene_output);
|
||||
|
||||
+ destroy_tree(m);
|
||||
closemon(m);
|
||||
wlr_scene_node_destroy(&m->fullscreen_bg->node);
|
||||
free(m);
|
||||
@@ -1090,6 +1115,7 @@ createmon(struct wl_listener *listener, void *data)
|
||||
|
||||
wl_list_insert(&mons, &m->link);
|
||||
printstatus();
|
||||
+ init_tree(m);
|
||||
|
||||
/* The xdg-protocol specifies:
|
||||
*
|
||||
@@ -1329,9 +1355,17 @@ destroynotify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
/* Called when the xdg_toplevel is destroyed. */
|
||||
Client *c = wl_container_of(listener, c, destroy);
|
||||
+ Monitor *mon;
|
||||
wl_list_remove(&c->destroy.link);
|
||||
wl_list_remove(&c->set_title.link);
|
||||
wl_list_remove(&c->fullscreen.link);
|
||||
+ /* We check if the destroyed client was part of any tiled_list, to catch
|
||||
+ * client removals even if they would not be currently managed by btrtile */
|
||||
+ wl_list_for_each(mon, &mons, link) {
|
||||
+ if (mon->root) {
|
||||
+ remove_client(mon, c);
|
||||
+ }
|
||||
+ }
|
||||
#ifdef XWAYLAND
|
||||
if (c->type != XDGShell) {
|
||||
wl_list_remove(&c->activate.link);
|
||||
@@ -1862,7 +1896,8 @@ void
|
||||
motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy,
|
||||
double dx_unaccel, double dy_unaccel)
|
||||
{
|
||||
- double sx = 0, sy = 0, sx_confined, sy_confined;
|
||||
+ int tiled = 0;
|
||||
+ double sx = 0, sy = 0, sx_confined, sy_confined, dx_total, dy_total;
|
||||
Client *c = NULL, *w = NULL;
|
||||
LayerSurface *l = NULL;
|
||||
struct wlr_surface *surface = NULL;
|
||||
@@ -1916,18 +1951,55 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
|
||||
/* Update drag icon's position */
|
||||
wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y));
|
||||
|
||||
- /* If we are currently grabbing the mouse, handle and return */
|
||||
+ /* Skip if internal call */
|
||||
+ if (time == 0)
|
||||
+ goto focus;
|
||||
+
|
||||
+ tiled = grabc && !grabc->isfloating && !grabc->isfullscreen;
|
||||
if (cursor_mode == CurMove) {
|
||||
/* Move the grabbed client to the new position. */
|
||||
- resize(grabc, (struct wlr_box){.x = (int)round(cursor->x) - grabcx, .y = (int)round(cursor->y) - grabcy,
|
||||
- .width = grabc->geom.width, .height = grabc->geom.height}, 1);
|
||||
- return;
|
||||
+ if (grabc && grabc->isfloating) {
|
||||
+ resize(grabc, (struct wlr_box){
|
||||
+ .x = (int)round(cursor->x) - grabcx,
|
||||
+ .y = (int)round(cursor->y) - grabcy,
|
||||
+ .width = grabc->geom.width,
|
||||
+ .height = grabc->geom.height
|
||||
+ }, 1);
|
||||
+ return;
|
||||
+ }
|
||||
} else if (cursor_mode == CurResize) {
|
||||
- resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y,
|
||||
- .width = (int)round(cursor->x) - grabc->geom.x, .height = (int)round(cursor->y) - grabc->geom.y}, 1);
|
||||
- return;
|
||||
+ if (tiled) {
|
||||
+ dx_total = cursor->x - resize_last_update_x;
|
||||
+ dy_total = cursor->y - resize_last_update_y;
|
||||
+
|
||||
+ if (time - last_resize_time >= resize_interval_ms) {
|
||||
+ Arg a = {0};
|
||||
+ if (fabs(dx_total) > fabs(dy_total)) {
|
||||
+ a.f = (float)(dx_total * resize_factor);
|
||||
+ setratio_h(&a);
|
||||
+ } else {
|
||||
+ a.f = (float)(dy_total * resize_factor);
|
||||
+ setratio_v(&a);
|
||||
+ }
|
||||
+
|
||||
+ last_resize_time = time;
|
||||
+ resize_last_update_x = cursor->x;
|
||||
+ resize_last_update_y = cursor->y;
|
||||
+ }
|
||||
+
|
||||
+ } else if (grabc && grabc->isfloating) {
|
||||
+ /* Floating resize as original */
|
||||
+ resize(grabc, (struct wlr_box){
|
||||
+ .x = grabc->geom.x,
|
||||
+ .y = grabc->geom.y,
|
||||
+ .width = (int)round(cursor->x) - grabc->geom.x,
|
||||
+ .height = (int)round(cursor->y) - grabc->geom.y
|
||||
+ }, 1);
|
||||
+ return;
|
||||
+ }
|
||||
}
|
||||
|
||||
+focus:
|
||||
/* If there's no client surface under the cursor, set the cursor image to a
|
||||
* default. This is what makes the cursor image appear when you move it
|
||||
* off of a client or over its border. */
|
||||
@@ -1961,22 +2033,40 @@ moveresize(const Arg *arg)
|
||||
if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
|
||||
return;
|
||||
|
||||
- /* Float the window and tell motionnotify to grab it */
|
||||
- setfloating(grabc, 1);
|
||||
- switch (cursor_mode = arg->ui) {
|
||||
- case CurMove:
|
||||
- grabcx = (int)round(cursor->x) - grabc->geom.x;
|
||||
- grabcy = (int)round(cursor->y) - grabc->geom.y;
|
||||
- wlr_cursor_set_xcursor(cursor, cursor_mgr, "all-scroll");
|
||||
- break;
|
||||
- case CurResize:
|
||||
- /* Doesn't work for X11 output - the next absolute motion event
|
||||
- * returns the cursor to where it started */
|
||||
- wlr_cursor_warp_closest(cursor, NULL,
|
||||
- grabc->geom.x + grabc->geom.width,
|
||||
- grabc->geom.y + grabc->geom.height);
|
||||
- wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
||||
- break;
|
||||
+ cursor_mode = arg->ui;
|
||||
+ grabc->was_tiled = (!grabc->isfloating && !grabc->isfullscreen);
|
||||
+
|
||||
+ if (grabc->was_tiled) {
|
||||
+ switch (cursor_mode) {
|
||||
+ case CurMove:
|
||||
+ setfloating(grabc, 1);
|
||||
+ grabcx = (int)round(cursor->x) - grabc->geom.x;
|
||||
+ grabcy = (int)round(cursor->y) - grabc->geom.y;
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur");
|
||||
+ break;
|
||||
+ case CurResize:
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
||||
+ resize_last_update_x = cursor->x;
|
||||
+ resize_last_update_y = cursor->y;
|
||||
+ break;
|
||||
+ }
|
||||
+ } else {
|
||||
+ /* Default floating logic */
|
||||
+ /* Float the window and tell motionnotify to grab it */
|
||||
+ setfloating(grabc, 1);
|
||||
+ switch (cursor_mode) {
|
||||
+ case CurMove:
|
||||
+ grabcx = (int)round(cursor->x) - grabc->geom.x;
|
||||
+ grabcy = (int)round(cursor->y) - grabc->geom.y;
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur");
|
||||
+ break;
|
||||
+ case CurResize:
|
||||
+ wlr_cursor_warp_closest(cursor, NULL,
|
||||
+ grabc->geom.x + grabc->geom.width,
|
||||
+ grabc->geom.y + grabc->geom.height);
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2826,6 +2916,14 @@ unmapnotify(struct wl_listener *listener, void *data)
|
||||
focusclient(focustop(selmon), 1);
|
||||
}
|
||||
} else {
|
||||
+ /* btrtile remove clients for each monitor */
|
||||
+ Monitor *mon;
|
||||
+ wl_list_for_each(mon, &mons, link) {
|
||||
+ if (mon->root) {
|
||||
+ remove_client(mon, c);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
wl_list_remove(&c->link);
|
||||
setmon(c, NULL, 0);
|
||||
wl_list_remove(&c->flink);
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@@ -0,0 +1,910 @@
|
||||
From 618e3b70204520b6eb2c5040e072087ac0a3b3f7 Mon Sep 17 00:00:00 2001
|
||||
From: julmajustus <julmajustus@tutanota.com>
|
||||
Date: Thu, 21 May 2026 00:40:54 +0300
|
||||
Subject: [PATCH] btrtile: Spring update pt2
|
||||
|
||||
- Simplified the resizing logic to avoid full arrange calls from
|
||||
motionnotify
|
||||
- Minor intend fixes
|
||||
---
|
||||
btrtile.c | 564 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
config.def.h | 12 ++
|
||||
dwl.c | 152 +++++++++++---
|
||||
3 files changed, 701 insertions(+), 27 deletions(-)
|
||||
create mode 100644 btrtile.c
|
||||
|
||||
diff --git a/btrtile.c b/btrtile.c
|
||||
new file mode 100644
|
||||
index 0000000..357ffb9
|
||||
--- /dev/null
|
||||
+++ b/btrtile.c
|
||||
@@ -0,0 +1,564 @@
|
||||
+/* ************************************************************************** */
|
||||
+/* @@@ @@@@@@@@ */
|
||||
+/* @@@ @@@@@@@@@@ */
|
||||
+/* @@! @@! @@@@ */
|
||||
+/* !@! !@! @!@!@ */
|
||||
+/* btrtile.c @!! @!@ @! !@! */
|
||||
+/* !!! !@!!! !!! */
|
||||
+/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */
|
||||
+/* ::! :!: !:! */
|
||||
+/* Created: 2024/12/15 00:26:07 by julmajustus :: ::::::: :: */
|
||||
+/* Updated: 2026/05/20 22:51:54 by julmajustus : : : : : : */
|
||||
+/* */
|
||||
+/* ************************************************************************** */
|
||||
+
|
||||
+typedef struct LayoutNode {
|
||||
+ unsigned int is_client_node;
|
||||
+ unsigned int is_split_vertically;
|
||||
+ float split_ratio;
|
||||
+ struct LayoutNode *left;
|
||||
+ struct LayoutNode *right;
|
||||
+ struct LayoutNode *split_node;
|
||||
+ Client *client;
|
||||
+} LayoutNode;
|
||||
+
|
||||
+static void apply_layout(Monitor *m, LayoutNode *node,
|
||||
+ struct wlr_box area, unsigned int is_root);
|
||||
+static void btrtile(Monitor *m);
|
||||
+static LayoutNode *create_client_node(Client *c);
|
||||
+static LayoutNode *create_split_node(unsigned int is_split_vertically,
|
||||
+ LayoutNode *left, LayoutNode *right);
|
||||
+static void destroy_node(LayoutNode *node);
|
||||
+static void destroy_tree(Monitor *m);
|
||||
+static LayoutNode *find_client_node(LayoutNode *node, Client *c);
|
||||
+static LayoutNode *find_suitable_split(Monitor *m, LayoutNode *start,
|
||||
+ unsigned int need_vertical, int focused_on_left);
|
||||
+static void init_tree(Monitor *m);
|
||||
+static void insert_client(Monitor *m, Client *focused_client, Client *new_client);
|
||||
+static LayoutNode *remove_client_node(LayoutNode *node, Client *c);
|
||||
+static void remove_client(Monitor *m, Client *c);
|
||||
+static void setratio_h(const Arg *arg);
|
||||
+static void setratio_v(const Arg *arg);
|
||||
+static void swapclients(const Arg *arg);
|
||||
+static unsigned int visible_count(LayoutNode *node, Monitor *m);
|
||||
+static Client *xytoclient(double x, double y);
|
||||
+
|
||||
+static double resize_last_update_x, resize_last_update_y;
|
||||
+static uint32_t last_resize_time = 0;
|
||||
+
|
||||
+void
|
||||
+apply_layout(Monitor *m, LayoutNode *node,
|
||||
+ struct wlr_box area, unsigned int is_root)
|
||||
+{
|
||||
+ Client *c;
|
||||
+ float ratio;
|
||||
+ unsigned int left_count, right_count, mid;
|
||||
+ struct wlr_box left_area, right_area;
|
||||
+
|
||||
+ if (!node)
|
||||
+ return;
|
||||
+
|
||||
+ /* If this node is a client node, check if it is visible. */
|
||||
+ if (node->is_client_node) {
|
||||
+ c = node->client;
|
||||
+ if (!c || !VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||
+ return;
|
||||
+ if (area.x == c->old_geom.x && area.y == c->old_geom.y &&
|
||||
+ area.width == c->old_geom.width && area.height == c->old_geom.height)
|
||||
+ return;
|
||||
+ resize(c, area, 0);
|
||||
+ c->old_geom = area;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* For a split node, we see how many visible children are on each side: */
|
||||
+ left_count = visible_count(node->left, m);
|
||||
+ right_count = visible_count(node->right, m);
|
||||
+
|
||||
+ if (left_count == 0 && right_count == 0) {
|
||||
+ return;
|
||||
+ } else if (left_count > 0 && right_count == 0) {
|
||||
+ apply_layout(m, node->left, area, 0);
|
||||
+ return;
|
||||
+ } else if (left_count == 0 && right_count > 0) {
|
||||
+ apply_layout(m, node->right, area, 0);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* If we’re here, we have visible clients in both subtrees. */
|
||||
+ ratio = node->split_ratio;
|
||||
+ if (ratio < 0.05f)
|
||||
+ ratio = 0.05f;
|
||||
+ if (ratio > 0.95f)
|
||||
+ ratio = 0.95f;
|
||||
+
|
||||
+ memset(&left_area, 0, sizeof(left_area));
|
||||
+ memset(&right_area, 0, sizeof(right_area));
|
||||
+
|
||||
+ if (node->is_split_vertically) {
|
||||
+ mid = (unsigned int)(area.width * ratio);
|
||||
+ left_area.x = area.x;
|
||||
+ left_area.y = area.y;
|
||||
+ left_area.width = mid;
|
||||
+ left_area.height = area.height;
|
||||
+
|
||||
+ right_area.x = area.x + mid;
|
||||
+ right_area.y = area.y;
|
||||
+ right_area.width = area.width - mid;
|
||||
+ right_area.height = area.height;
|
||||
+ } else {
|
||||
+ /* horizontal split */
|
||||
+ mid = (unsigned int)(area.height * ratio);
|
||||
+ left_area.x = area.x;
|
||||
+ left_area.y = area.y;
|
||||
+ left_area.width = area.width;
|
||||
+ left_area.height = mid;
|
||||
+
|
||||
+ right_area.x = area.x;
|
||||
+ right_area.y = area.y + mid;
|
||||
+ right_area.width = area.width;
|
||||
+ right_area.height= area.height - mid;
|
||||
+ }
|
||||
+
|
||||
+ apply_layout(m, node->left, left_area, 0);
|
||||
+ apply_layout(m, node->right, right_area, 0);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+btrtile(Monitor *m)
|
||||
+{
|
||||
+ Client *c, *focused = NULL;
|
||||
+ int n = 0;
|
||||
+ LayoutNode *found;
|
||||
+ struct wlr_box full_area;
|
||||
+
|
||||
+ if (!m)
|
||||
+ return;
|
||||
+
|
||||
+ /* Remove non tiled clients from tree. */
|
||||
+ wl_list_for_each(c, &clients, link) {
|
||||
+ if (c->mon == m && !c->isfloating && !c->isfullscreen) {
|
||||
+ } else {
|
||||
+ remove_client(m, c);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* If no client is found under cursor, fallback to focustop(m) */
|
||||
+ if (!(focused = xytoclient(cursor->x, cursor->y)))
|
||||
+ focused = focustop(m);
|
||||
+
|
||||
+ /* Insert visible clients that are not part of the tree. */
|
||||
+ wl_list_for_each(c, &clients, link) {
|
||||
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen && c->mon == m) {
|
||||
+ found = find_client_node(m->root, c);
|
||||
+ if (!found) {
|
||||
+ insert_client(m, focused, c);
|
||||
+ }
|
||||
+ n++;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (n == 0)
|
||||
+ return;
|
||||
+
|
||||
+ full_area = m->w;
|
||||
+ apply_layout(m, m->root, full_area, 1);
|
||||
+}
|
||||
+
|
||||
+LayoutNode *
|
||||
+create_client_node(Client *c)
|
||||
+{
|
||||
+ LayoutNode *node = calloc(1, sizeof(LayoutNode));
|
||||
+
|
||||
+ if (!node)
|
||||
+ return NULL;
|
||||
+ node->is_client_node = 1;
|
||||
+ node->split_ratio = 0.5f;
|
||||
+ node->client = c;
|
||||
+ return node;
|
||||
+}
|
||||
+
|
||||
+LayoutNode *
|
||||
+create_split_node(unsigned int is_split_vertically,
|
||||
+ LayoutNode *left, LayoutNode *right)
|
||||
+{
|
||||
+ LayoutNode *node = calloc(1, sizeof(LayoutNode));
|
||||
+
|
||||
+ if (!node)
|
||||
+ return NULL;
|
||||
+ node->is_client_node = 0;
|
||||
+ node->split_ratio = 0.5f;
|
||||
+ node->is_split_vertically = is_split_vertically;
|
||||
+ node->left = left;
|
||||
+ node->right = right;
|
||||
+ if (left)
|
||||
+ left->split_node = node;
|
||||
+ if (right)
|
||||
+ right->split_node = node;
|
||||
+ return node;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+destroy_node(LayoutNode *node)
|
||||
+{
|
||||
+ if (!node)
|
||||
+ return;
|
||||
+ if (!node->is_client_node) {
|
||||
+ destroy_node(node->left);
|
||||
+ destroy_node(node->right);
|
||||
+ }
|
||||
+ free(node);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+destroy_tree(Monitor *m)
|
||||
+{
|
||||
+ if (!m || !m->root)
|
||||
+ return;
|
||||
+ destroy_node(m->root);
|
||||
+ m->root = NULL;
|
||||
+}
|
||||
+
|
||||
+LayoutNode *
|
||||
+find_client_node(LayoutNode *node, Client *c)
|
||||
+{
|
||||
+ LayoutNode *res;
|
||||
+
|
||||
+ if (!node || !c)
|
||||
+ return NULL;
|
||||
+ if (node->is_client_node) {
|
||||
+ return (node->client == c) ? node : NULL;
|
||||
+ }
|
||||
+ res = find_client_node(node->left, c);
|
||||
+ return res ? res : find_client_node(node->right, c);
|
||||
+}
|
||||
+
|
||||
+LayoutNode *
|
||||
+find_suitable_split(Monitor *m, LayoutNode *start_node,
|
||||
+ unsigned int need_vertical, int focused_on_left)
|
||||
+{
|
||||
+ LayoutNode *n = start_node, *child = NULL;
|
||||
+
|
||||
+ if (!m)
|
||||
+ return NULL;
|
||||
+
|
||||
+ if (n && n->is_client_node) {
|
||||
+ child = n;
|
||||
+ n = n->split_node;
|
||||
+ }
|
||||
+
|
||||
+ while (n) {
|
||||
+ if (!n->is_client_node && n->is_split_vertically == need_vertical
|
||||
+ && visible_count(n->left, m) > 0
|
||||
+ && visible_count(n->right, m) > 0) {
|
||||
+ if ((focused_on_left && n->left == child) ||
|
||||
+ (!focused_on_left && n->right == child))
|
||||
+ return n;
|
||||
+ }
|
||||
+ child = n;
|
||||
+ n = n->split_node;
|
||||
+ }
|
||||
+ return NULL;
|
||||
+}
|
||||
+void
|
||||
+init_tree(Monitor *m)
|
||||
+{
|
||||
+ if (m)
|
||||
+ m->root = NULL;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+insert_client(Monitor *m, Client *focused_client, Client *new_client)
|
||||
+{
|
||||
+ Client *old_client;
|
||||
+ LayoutNode **root = &m->root, *old_root,
|
||||
+ *focused_node, *new_client_node, *old_client_node;
|
||||
+ unsigned int wider, mid_x, mid_y;
|
||||
+
|
||||
+ /* If no root , new client becomes the root. */
|
||||
+ if (!*root) {
|
||||
+ *root = create_client_node(new_client);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* Find the focused_client node,
|
||||
+ * if not found split the root. */
|
||||
+ focused_node = focused_client ?
|
||||
+ find_client_node(*root, focused_client) : NULL;
|
||||
+ if (!focused_node) {
|
||||
+ old_root = *root;
|
||||
+ new_client_node = create_client_node(new_client);
|
||||
+ *root = create_split_node(1, old_root, new_client_node);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* Turn focused node from a client node into a split node,
|
||||
+ * and attach old_client + new_client. */
|
||||
+ old_client = focused_node->client;
|
||||
+ old_client_node = create_client_node(old_client);
|
||||
+ new_client_node = create_client_node(new_client);
|
||||
+
|
||||
+ /* Decide split direction. */
|
||||
+ wider = (focused_client->geom.width >= focused_client->geom.height);
|
||||
+ focused_node->is_client_node = 0;
|
||||
+ focused_node->client = NULL;
|
||||
+ focused_node->is_split_vertically = (wider ? 1 : 0);
|
||||
+
|
||||
+ /* Pick new_client side depending on the cursor position. */
|
||||
+ mid_x = focused_client->geom.x + focused_client->geom.width / 2;
|
||||
+ mid_y = focused_client->geom.y + focused_client->geom.height / 2;
|
||||
+
|
||||
+ if (wider) {
|
||||
+ /* vertical split => left vs right */
|
||||
+ if (cursor->x <= mid_x) {
|
||||
+ focused_node->left = new_client_node;
|
||||
+ focused_node->right = old_client_node;
|
||||
+ } else {
|
||||
+ focused_node->left = old_client_node;
|
||||
+ focused_node->right = new_client_node;
|
||||
+ }
|
||||
+ } else {
|
||||
+ /* horizontal split => top vs bottom */
|
||||
+ if (cursor->y <= mid_y) {
|
||||
+ focused_node->left = new_client_node;
|
||||
+ focused_node->right = old_client_node;
|
||||
+ } else {
|
||||
+ focused_node->left = old_client_node;
|
||||
+ focused_node->right = new_client_node;
|
||||
+ }
|
||||
+ }
|
||||
+ old_client_node->split_node = focused_node;
|
||||
+ new_client_node->split_node = focused_node;
|
||||
+ focused_node->split_ratio = 0.5f;
|
||||
+}
|
||||
+
|
||||
+LayoutNode *
|
||||
+remove_client_node(LayoutNode *node, Client *c)
|
||||
+{
|
||||
+ LayoutNode *tmp;
|
||||
+ if (!node)
|
||||
+ return NULL;
|
||||
+ if (node->is_client_node) {
|
||||
+ /* If this client_node is the client we're removing,
|
||||
+ * return NULL to remove it */
|
||||
+ if (node->client == c) {
|
||||
+ free(node);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ return node;
|
||||
+ }
|
||||
+
|
||||
+ node->left = remove_client_node(node->left, c);
|
||||
+ node->right = remove_client_node(node->right, c);
|
||||
+
|
||||
+ /* If one of the client node is NULL after removal and the other is not,
|
||||
+ * we "lift" the other client node up to replace this split node. */
|
||||
+ if (!node->left && node->right) {
|
||||
+ tmp = node->right;
|
||||
+
|
||||
+ /* Save pointer to split node */
|
||||
+ if (tmp)
|
||||
+ tmp->split_node = node->split_node;
|
||||
+
|
||||
+ free(node);
|
||||
+ return tmp;
|
||||
+ }
|
||||
+
|
||||
+ if (!node->right && node->left) {
|
||||
+ tmp = node->left;
|
||||
+
|
||||
+ /* Save pointer to split node */
|
||||
+ if (tmp)
|
||||
+ tmp->split_node = node->split_node;
|
||||
+
|
||||
+ free(node);
|
||||
+ return tmp;
|
||||
+ }
|
||||
+
|
||||
+ /* If both children exist or both are NULL (empty tree),
|
||||
+ * return node as is. */
|
||||
+ return node;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+remove_client(Monitor *m, Client *c)
|
||||
+{
|
||||
+ if (!m->root || !c)
|
||||
+ return;
|
||||
+ m->root = remove_client_node(m->root, c);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+setratio(unsigned int need_vertical, const Arg *arg)
|
||||
+{
|
||||
+ Client *sel;
|
||||
+ LayoutNode *client_node, *split_node;
|
||||
+ float new_ratio;
|
||||
+ int focused_on_left;
|
||||
+
|
||||
+ if (!selmon || !selmon->lt[selmon->sellt]->arrange)
|
||||
+ return;
|
||||
+
|
||||
+ sel = focustop(selmon);
|
||||
+ if (!sel)
|
||||
+ return;
|
||||
+
|
||||
+ client_node = find_client_node(selmon->root, sel);
|
||||
+ if (!client_node)
|
||||
+ return;
|
||||
+
|
||||
+ focused_on_left = (arg->f >= 0.0f);
|
||||
+
|
||||
+ split_node = find_suitable_split(selmon, client_node, need_vertical, focused_on_left);
|
||||
+
|
||||
+ if (!split_node)
|
||||
+ split_node = find_suitable_split(selmon, client_node, need_vertical, !focused_on_left);
|
||||
+ if (!split_node)
|
||||
+ return;
|
||||
+
|
||||
+ new_ratio = (arg->f != 0.0f) ? (split_node->split_ratio + arg->f) : 0.5f;
|
||||
+ if (new_ratio < 0.05f)
|
||||
+ new_ratio = 0.05f;
|
||||
+ if (new_ratio > 0.95f)
|
||||
+ new_ratio = 0.95f;
|
||||
+ split_node->split_ratio = new_ratio;
|
||||
+
|
||||
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
||||
+ /* Skip the arrange when called from motionnotify; that path calls
|
||||
+ * arrange itself after rate-limiting. */
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+setratio_h(const Arg *arg)
|
||||
+{
|
||||
+ setratio(1, arg);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+setratio_v(const Arg *arg)
|
||||
+{
|
||||
+ setratio(0, arg);
|
||||
+}
|
||||
+
|
||||
+void swapclients(const Arg *arg) {
|
||||
+ Client *c, *tmp, *target = NULL, *sel = focustop(selmon);
|
||||
+ LayoutNode *sel_node, *target_node;
|
||||
+ int closest_dist = INT_MAX, dist, sel_center_x, sel_center_y,
|
||||
+ cand_center_x, cand_center_y;
|
||||
+
|
||||
+ if (!sel || sel->isfullscreen ||
|
||||
+ !selmon->root || !selmon->lt[selmon->sellt]->arrange)
|
||||
+ return;
|
||||
+
|
||||
+
|
||||
+ /* Get the center coordinates of the selected client */
|
||||
+ sel_center_x = sel->geom.x + sel->geom.width / 2;
|
||||
+ sel_center_y = sel->geom.y + sel->geom.height / 2;
|
||||
+
|
||||
+ wl_list_for_each(c, &clients, link) {
|
||||
+ if (!VISIBLEON(c, selmon) || c->isfloating || c->isfullscreen || c == sel)
|
||||
+ continue;
|
||||
+
|
||||
+ /* Get the center of candidate client */
|
||||
+ cand_center_x = c->geom.x + c->geom.width / 2;
|
||||
+ cand_center_y = c->geom.y + c->geom.height / 2;
|
||||
+
|
||||
+ /* Check that the candidate lies in the requested direction. */
|
||||
+ switch (arg->ui) {
|
||||
+ case 0:
|
||||
+ if (cand_center_x >= sel_center_x)
|
||||
+ continue;
|
||||
+ break;
|
||||
+ case 1:
|
||||
+ if (cand_center_x <= sel_center_x)
|
||||
+ continue;
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ if (cand_center_y >= sel_center_y)
|
||||
+ continue;
|
||||
+ break;
|
||||
+ case 3:
|
||||
+ if (cand_center_y <= sel_center_y)
|
||||
+ continue;
|
||||
+ break;
|
||||
+ default:
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ /* Get distance between the centers */
|
||||
+ dist = abs(sel_center_x - cand_center_x) + abs(sel_center_y - cand_center_y);
|
||||
+ if (dist < closest_dist) {
|
||||
+ closest_dist = dist;
|
||||
+ target = c;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* If target is found, swap the two clients’ positions in the layout tree */
|
||||
+ if (target) {
|
||||
+ sel_node = find_client_node(selmon->root, sel);
|
||||
+ target_node = find_client_node(selmon->root, target);
|
||||
+ if (sel_node && target_node) {
|
||||
+ tmp = sel_node->client;
|
||||
+ sel_node->client = target_node->client;
|
||||
+ target_node->client = tmp;
|
||||
+ arrange(selmon);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+unsigned int
|
||||
+visible_count(LayoutNode *node, Monitor *m)
|
||||
+{
|
||||
+ Client *c;
|
||||
+
|
||||
+ if (!node)
|
||||
+ return 0;
|
||||
+ /* Check if this client is visible. */
|
||||
+ if (node->is_client_node) {
|
||||
+ c = node->client;
|
||||
+ if (c && VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen)
|
||||
+ return 1;
|
||||
+ return 0;
|
||||
+ }
|
||||
+ /* Else it’s a split node. */
|
||||
+ return visible_count(node->left, m) + visible_count(node->right, m);
|
||||
+}
|
||||
+
|
||||
+Client *
|
||||
+xytoclient(double x, double y) {
|
||||
+ Monitor *m = xytomon(x, y);
|
||||
+ Client *c, *closest = NULL;
|
||||
+ double dist, mindist = INT_MAX, dx, dy;
|
||||
+
|
||||
+ wl_list_for_each_reverse(c, &clients, link) {
|
||||
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen &&
|
||||
+ x >= c->geom.x && x <= (c->geom.x + c->geom.width) &&
|
||||
+ y >= c->geom.y && y <= (c->geom.y + c->geom.height)){
|
||||
+ return c;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* If no client was found at cursor position fallback to closest. */
|
||||
+ wl_list_for_each_reverse(c, &clients, link) {
|
||||
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen) {
|
||||
+ dx = 0, dy = 0;
|
||||
+
|
||||
+ if (x < c->geom.x)
|
||||
+ dx = c->geom.x - x;
|
||||
+ else if (x > (c->geom.x + c->geom.width))
|
||||
+ dx = x - (c->geom.x + c->geom.width);
|
||||
+
|
||||
+ if (y < c->geom.y)
|
||||
+ dy = c->geom.y - y;
|
||||
+ else if (y > (c->geom.y + c->geom.height))
|
||||
+ dy = y - (c->geom.y + c->geom.height);
|
||||
+
|
||||
+ dist = dx * dx + dy * dy;
|
||||
+ if (dist < mindist) {
|
||||
+ mindist = dist;
|
||||
+ closest = c;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return closest;
|
||||
+}
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 8a6eda0..bc04e3f 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -13,7 +13,10 @@ static const float focuscolor[] = COLOR(0x005577ff);
|
||||
static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
||||
static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */
|
||||
+static const float resize_factor = 0.0002f; /* Resize multiplier for mouse resizing, depends on mouse sensivity. */
|
||||
+static const uint32_t resize_interval_ms = 16; /* Resize interval depends on framerate and screen refresh rate. */
|
||||
|
||||
+enum Direction { DIR_LEFT, DIR_RIGHT, DIR_UP, DIR_DOWN };
|
||||
/* tagging - TAGCOUNT must be no greater than 31 */
|
||||
#define TAGCOUNT (9)
|
||||
|
||||
@@ -30,6 +33,7 @@ static const Rule rules[] = {
|
||||
/* layout(s) */
|
||||
static const Layout layouts[] = {
|
||||
/* symbol arrange function */
|
||||
+ { "|w|", btrtile },
|
||||
{ "[]=", tile },
|
||||
{ "><>", NULL }, /* no layout function means floating behavior */
|
||||
{ "[M]", monocle },
|
||||
@@ -144,6 +148,14 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less, tagmon, {.i = WLR_DIRECTION_LEFT} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Up, swapclients, {.i = DIR_UP} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Down, swapclients, {.i = DIR_DOWN} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Right, swapclients, {.i = DIR_RIGHT} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Left, swapclients, {.i = DIR_LEFT} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Right, setratio_h, {.f = +0.025f} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Left, setratio_h, {.f = -0.025f} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Up, setratio_v, {.f = -0.025f} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Down, setratio_v, {.f = +0.025f} },
|
||||
TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0),
|
||||
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
|
||||
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 44f3ad9..a121efc 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* See LICENSE file for copyright and license details.
|
||||
*/
|
||||
+#include <limits.h>
|
||||
#include <getopt.h>
|
||||
#include <libinput.h>
|
||||
#include <linux/input-event-codes.h>
|
||||
@@ -100,6 +101,7 @@ typedef struct {
|
||||
const Arg arg;
|
||||
} Button;
|
||||
|
||||
+typedef struct LayoutNode LayoutNode;
|
||||
typedef struct Monitor Monitor;
|
||||
typedef struct {
|
||||
/* Must keep this field first */
|
||||
@@ -137,8 +139,9 @@ typedef struct {
|
||||
#endif
|
||||
unsigned int bw;
|
||||
uint32_t tags;
|
||||
- int isfloating, isurgent, isfullscreen;
|
||||
+ int isfloating, isurgent, isfullscreen, was_tiled;
|
||||
uint32_t resize; /* configure serial of a pending resize */
|
||||
+ struct wlr_box old_geom;
|
||||
} Client;
|
||||
|
||||
typedef struct {
|
||||
@@ -205,6 +208,7 @@ struct Monitor {
|
||||
int nmaster;
|
||||
char ltsymbol[16];
|
||||
int asleep;
|
||||
+ LayoutNode *root;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -247,6 +251,7 @@ static void arrangelayer(Monitor *m, struct wl_list *list,
|
||||
struct wlr_box *usable_area, int exclusive);
|
||||
static void arrangelayers(Monitor *m);
|
||||
static void axisnotify(struct wl_listener *listener, void *data);
|
||||
+static void btrtile(Monitor *m);
|
||||
static void buttonpress(struct wl_listener *listener, void *data);
|
||||
static void chvt(const Arg *arg);
|
||||
static void checkidleinhibitor(struct wlr_surface *exclude);
|
||||
@@ -329,6 +334,9 @@ static void setmon(Client *c, Monitor *m, uint32_t newtags);
|
||||
static void setpsel(struct wl_listener *listener, void *data);
|
||||
static void setsel(struct wl_listener *listener, void *data);
|
||||
static void setup(void);
|
||||
+static void setratio_h(const Arg *arg);
|
||||
+static void setratio_v(const Arg *arg);
|
||||
+static void swapclients(const Arg *arg);
|
||||
static void spawn(const Arg *arg);
|
||||
static void startdrag(struct wl_listener *listener, void *data);
|
||||
static void tag(const Arg *arg);
|
||||
@@ -454,6 +462,7 @@ static struct wlr_xwayland *xwayland;
|
||||
|
||||
/* attempt to encapsulate suck into one file */
|
||||
#include "client.h"
|
||||
+#include "btrtile.c"
|
||||
|
||||
/* function implementations */
|
||||
void
|
||||
@@ -624,7 +633,7 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
struct wlr_pointer_button_event *event = data;
|
||||
struct wlr_keyboard *keyboard;
|
||||
uint32_t mods;
|
||||
- Client *c;
|
||||
+ Client *c, *target = NULL;
|
||||
const Button *b;
|
||||
|
||||
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
||||
@@ -645,7 +654,7 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
|
||||
for (b = buttons; b < END(buttons); b++) {
|
||||
if (CLEANMASK(mods) == CLEANMASK(b->mod) &&
|
||||
- event->button == b->button && b->func) {
|
||||
+ event->button == b->button && b->func) {
|
||||
b->func(&b->arg);
|
||||
return;
|
||||
}
|
||||
@@ -655,6 +664,21 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
/* If you released any buttons, we exit interactive move/resize mode. */
|
||||
/* TODO: should reset to the pointer focus's current setcursor */
|
||||
if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
|
||||
+ c = grabc;
|
||||
+ if (c && c->was_tiled && !strcmp(selmon->ltsymbol, "|w|")) {
|
||||
+ if (cursor_mode == CurMove && c->isfloating) {
|
||||
+ target = xytoclient(cursor->x, cursor->y);
|
||||
+
|
||||
+ if (target && !target->isfloating && !target->isfullscreen)
|
||||
+ insert_client(selmon, target, c);
|
||||
+ else
|
||||
+ selmon->root = create_client_node(c);
|
||||
+
|
||||
+ setfloating(c, 0);
|
||||
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
||||
+ }
|
||||
+ }
|
||||
+ /* Default behaviour */
|
||||
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
||||
cursor_mode = CurNormal;
|
||||
/* Drop the window off on its new monitor */
|
||||
@@ -746,6 +770,7 @@ cleanupmon(struct wl_listener *listener, void *data)
|
||||
wlr_output_layout_remove(output_layout, m->wlr_output);
|
||||
wlr_scene_output_destroy(m->scene_output);
|
||||
|
||||
+ destroy_tree(m);
|
||||
closemon(m);
|
||||
wlr_scene_node_destroy(&m->fullscreen_bg->node);
|
||||
free(m);
|
||||
@@ -1090,6 +1115,7 @@ createmon(struct wl_listener *listener, void *data)
|
||||
|
||||
wl_list_insert(&mons, &m->link);
|
||||
printstatus();
|
||||
+ init_tree(m);
|
||||
|
||||
/* The xdg-protocol specifies:
|
||||
*
|
||||
@@ -1329,9 +1355,17 @@ destroynotify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
/* Called when the xdg_toplevel is destroyed. */
|
||||
Client *c = wl_container_of(listener, c, destroy);
|
||||
+ Monitor *mon;
|
||||
wl_list_remove(&c->destroy.link);
|
||||
wl_list_remove(&c->set_title.link);
|
||||
wl_list_remove(&c->fullscreen.link);
|
||||
+ /* We check if the destroyed client was part of any tiled_list, to catch
|
||||
+ * client removals even if they would not be currently managed by btrtile */
|
||||
+ wl_list_for_each(mon, &mons, link) {
|
||||
+ if (mon->root) {
|
||||
+ remove_client(mon, c);
|
||||
+ }
|
||||
+ }
|
||||
#ifdef XWAYLAND
|
||||
if (c->type != XDGShell) {
|
||||
wl_list_remove(&c->activate.link);
|
||||
@@ -1862,7 +1896,8 @@ void
|
||||
motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy,
|
||||
double dx_unaccel, double dy_unaccel)
|
||||
{
|
||||
- double sx = 0, sy = 0, sx_confined, sy_confined;
|
||||
+ int tiled = 0;
|
||||
+ double sx = 0, sy = 0, sx_confined, sy_confined, dx_total, dy_total;
|
||||
Client *c = NULL, *w = NULL;
|
||||
LayerSurface *l = NULL;
|
||||
struct wlr_surface *surface = NULL;
|
||||
@@ -1916,18 +1951,55 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
|
||||
/* Update drag icon's position */
|
||||
wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y));
|
||||
|
||||
- /* If we are currently grabbing the mouse, handle and return */
|
||||
+ /* Skip if internal call */
|
||||
+ if (time == 0)
|
||||
+ goto focus;
|
||||
+
|
||||
+ tiled = grabc && !grabc->isfloating && !grabc->isfullscreen;
|
||||
if (cursor_mode == CurMove) {
|
||||
/* Move the grabbed client to the new position. */
|
||||
- resize(grabc, (struct wlr_box){.x = (int)round(cursor->x) - grabcx, .y = (int)round(cursor->y) - grabcy,
|
||||
- .width = grabc->geom.width, .height = grabc->geom.height}, 1);
|
||||
- return;
|
||||
+ if (grabc && grabc->isfloating) {
|
||||
+ resize(grabc, (struct wlr_box){
|
||||
+ .x = (int)round(cursor->x) - grabcx,
|
||||
+ .y = (int)round(cursor->y) - grabcy,
|
||||
+ .width = grabc->geom.width,
|
||||
+ .height = grabc->geom.height
|
||||
+ }, 1);
|
||||
+ return;
|
||||
+ }
|
||||
} else if (cursor_mode == CurResize) {
|
||||
- resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y,
|
||||
- .width = (int)round(cursor->x) - grabc->geom.x, .height = (int)round(cursor->y) - grabc->geom.y}, 1);
|
||||
- return;
|
||||
+ if (tiled) {
|
||||
+ dx_total = cursor->x - resize_last_update_x;
|
||||
+ dy_total = cursor->y - resize_last_update_y;
|
||||
+
|
||||
+ if (time - last_resize_time >= resize_interval_ms) {
|
||||
+ Arg a = {0};
|
||||
+ if (fabs(dx_total) > fabs(dy_total)) {
|
||||
+ a.f = (float)(dx_total * resize_factor);
|
||||
+ setratio_h(&a);
|
||||
+ } else {
|
||||
+ a.f = (float)(dy_total * resize_factor);
|
||||
+ setratio_v(&a);
|
||||
+ }
|
||||
+
|
||||
+ last_resize_time = time;
|
||||
+ resize_last_update_x = cursor->x;
|
||||
+ resize_last_update_y = cursor->y;
|
||||
+ }
|
||||
+
|
||||
+ } else if (grabc && grabc->isfloating) {
|
||||
+ /* Floating resize as original */
|
||||
+ resize(grabc, (struct wlr_box){
|
||||
+ .x = grabc->geom.x,
|
||||
+ .y = grabc->geom.y,
|
||||
+ .width = (int)round(cursor->x) - grabc->geom.x,
|
||||
+ .height = (int)round(cursor->y) - grabc->geom.y
|
||||
+ }, 1);
|
||||
+ return;
|
||||
+ }
|
||||
}
|
||||
|
||||
+focus:
|
||||
/* If there's no client surface under the cursor, set the cursor image to a
|
||||
* default. This is what makes the cursor image appear when you move it
|
||||
* off of a client or over its border. */
|
||||
@@ -1961,22 +2033,40 @@ moveresize(const Arg *arg)
|
||||
if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
|
||||
return;
|
||||
|
||||
- /* Float the window and tell motionnotify to grab it */
|
||||
- setfloating(grabc, 1);
|
||||
- switch (cursor_mode = arg->ui) {
|
||||
- case CurMove:
|
||||
- grabcx = (int)round(cursor->x) - grabc->geom.x;
|
||||
- grabcy = (int)round(cursor->y) - grabc->geom.y;
|
||||
- wlr_cursor_set_xcursor(cursor, cursor_mgr, "all-scroll");
|
||||
- break;
|
||||
- case CurResize:
|
||||
- /* Doesn't work for X11 output - the next absolute motion event
|
||||
- * returns the cursor to where it started */
|
||||
- wlr_cursor_warp_closest(cursor, NULL,
|
||||
- grabc->geom.x + grabc->geom.width,
|
||||
- grabc->geom.y + grabc->geom.height);
|
||||
- wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
||||
- break;
|
||||
+ cursor_mode = arg->ui;
|
||||
+ grabc->was_tiled = (!grabc->isfloating && !grabc->isfullscreen);
|
||||
+
|
||||
+ if (grabc->was_tiled) {
|
||||
+ switch (cursor_mode) {
|
||||
+ case CurMove:
|
||||
+ setfloating(grabc, 1);
|
||||
+ grabcx = (int)round(cursor->x) - grabc->geom.x;
|
||||
+ grabcy = (int)round(cursor->y) - grabc->geom.y;
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur");
|
||||
+ break;
|
||||
+ case CurResize:
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
||||
+ resize_last_update_x = cursor->x;
|
||||
+ resize_last_update_y = cursor->y;
|
||||
+ break;
|
||||
+ }
|
||||
+ } else {
|
||||
+ /* Default floating logic */
|
||||
+ /* Float the window and tell motionnotify to grab it */
|
||||
+ setfloating(grabc, 1);
|
||||
+ switch (cursor_mode) {
|
||||
+ case CurMove:
|
||||
+ grabcx = (int)round(cursor->x) - grabc->geom.x;
|
||||
+ grabcy = (int)round(cursor->y) - grabc->geom.y;
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur");
|
||||
+ break;
|
||||
+ case CurResize:
|
||||
+ wlr_cursor_warp_closest(cursor, NULL,
|
||||
+ grabc->geom.x + grabc->geom.width,
|
||||
+ grabc->geom.y + grabc->geom.height);
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2826,6 +2916,14 @@ unmapnotify(struct wl_listener *listener, void *data)
|
||||
focusclient(focustop(selmon), 1);
|
||||
}
|
||||
} else {
|
||||
+ /* btrtile remove clients for each monitor */
|
||||
+ Monitor *mon;
|
||||
+ wl_list_for_each(mon, &mons, link) {
|
||||
+ if (mon->root) {
|
||||
+ remove_client(mon, c);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
wl_list_remove(&c->link);
|
||||
setmon(c, NULL, 0);
|
||||
wl_list_remove(&c->flink);
|
||||
--
|
||||
2.53.0
|
||||
|
||||
+194
-186
@@ -1,30 +1,35 @@
|
||||
From 858ef20d36c2d5e6a23a69b3b5909a80fab05f97 Mon Sep 17 00:00:00 2001
|
||||
From c11b1a8c93c27fad3782e9dbc1b094a4a7b78088 Mon Sep 17 00:00:00 2001
|
||||
From: julmajustus <julmajustus@tutanota.com>
|
||||
Date: Thu, 13 Feb 2025 23:25:20 +0200
|
||||
Subject: [PATCH] btrtile-gaps with multi-tag support
|
||||
Date: Thu, 21 May 2026 00:38:45 +0300
|
||||
Subject: [PATCH] btrtile: Spring update pt2
|
||||
|
||||
- Simplified the resizing logic to avoid full arrange calls from
|
||||
motionnotify
|
||||
- Minor intend fixes
|
||||
---
|
||||
btrtile.c | 582 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
btrtile.c | 583 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
config.def.h | 12 ++
|
||||
dwl.c | 152 +++++++++++---
|
||||
3 files changed, 717 insertions(+), 29 deletions(-)
|
||||
3 files changed, 720 insertions(+), 27 deletions(-)
|
||||
create mode 100644 btrtile.c
|
||||
|
||||
diff --git a/btrtile.c b/btrtile.c
|
||||
new file mode 100644
|
||||
index 0000000..650cab5
|
||||
index 0000000..f05a30f
|
||||
--- /dev/null
|
||||
+++ b/btrtile.c
|
||||
@@ -0,0 +1,582 @@
|
||||
@@ -0,0 +1,583 @@
|
||||
+/* ************************************************************************** */
|
||||
+/* */
|
||||
+/* ::: :::::::: */
|
||||
+/* btrtile.c :+: :+: :+: */
|
||||
+/* +:+ +:+ +:+ */
|
||||
+/* By: jmakkone <jmakkone@student.hive.fi> +#+ +:+ +#+ */
|
||||
+/* +#+#+#+#+#+ +#+ */
|
||||
+/* Created: 2024/12/15 00:26:07 by jmakkone #+# #+# */
|
||||
+/* Updated: 2025/02/13 23:25:03 by jmakkone ### ########.fr */
|
||||
+/* @@@ @@@@@@@@ */
|
||||
+/* @@@ @@@@@@@@@@ */
|
||||
+/* @@! @@! @@@@ */
|
||||
+/* !@! !@! @!@!@ */
|
||||
+/* btrtile.c @!! @!@ @! !@! */
|
||||
+/* !!! !@!!! !!! */
|
||||
+/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */
|
||||
+/* ::! :!: !:! */
|
||||
+/* Created: 2024/12/15 00:26:07 by julmajustus :: ::::::: :: */
|
||||
+/* Updated: 2026/05/20 22:38:02 by julmajustus : : : : : : */
|
||||
+/* */
|
||||
+/* ************************************************************************** */
|
||||
+
|
||||
@@ -47,7 +52,8 @@ index 0000000..650cab5
|
||||
+static void destroy_node(LayoutNode *node);
|
||||
+static void destroy_tree(Monitor *m);
|
||||
+static LayoutNode *find_client_node(LayoutNode *node, Client *c);
|
||||
+static LayoutNode *find_suitable_split(LayoutNode *start, unsigned int need_vert);
|
||||
+static LayoutNode *find_suitable_split(Monitor *m, LayoutNode *start,
|
||||
+ unsigned int need_vertical, int focused_on_left);
|
||||
+static void init_tree(Monitor *m);
|
||||
+static void insert_client(Monitor *m, Client *focused_client, Client *new_client);
|
||||
+static LayoutNode *remove_client_node(LayoutNode *node, Client *c);
|
||||
@@ -58,7 +64,6 @@ index 0000000..650cab5
|
||||
+static unsigned int visible_count(LayoutNode *node, Monitor *m);
|
||||
+static Client *xytoclient(double x, double y);
|
||||
+
|
||||
+static int resizing_from_mouse = 0;
|
||||
+static double resize_last_update_x, resize_last_update_y;
|
||||
+static uint32_t last_resize_time = 0;
|
||||
+
|
||||
@@ -86,6 +91,9 @@ index 0000000..650cab5
|
||||
+ c = node->client;
|
||||
+ if (!c || !VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||
+ return;
|
||||
+ if (area.x == c->old_geom.x && area.y == c->old_geom.y &&
|
||||
+ area.width == c->old_geom.width && area.height == c->old_geom.height)
|
||||
+ return;
|
||||
+ resize(c, area, 0);
|
||||
+ c->old_geom = area;
|
||||
+ return;
|
||||
@@ -164,7 +172,7 @@ index 0000000..650cab5
|
||||
+ LayoutNode *found;
|
||||
+ struct wlr_box full_area;
|
||||
+
|
||||
+ if (!m || !m->root)
|
||||
+ if (!m)
|
||||
+ return;
|
||||
+
|
||||
+ /* Remove non tiled clients from tree. */
|
||||
@@ -266,30 +274,37 @@ index 0000000..650cab5
|
||||
+}
|
||||
+
|
||||
+LayoutNode *
|
||||
+find_suitable_split(LayoutNode *start_node, unsigned int need_vertical)
|
||||
+find_suitable_split(Monitor *m, LayoutNode *start_node,
|
||||
+ unsigned int need_vertical, int focused_on_left)
|
||||
+{
|
||||
+ LayoutNode *n = start_node;
|
||||
+ /* if we started from a client node, jump to its parent: */
|
||||
+ if (n && n->is_client_node)
|
||||
+ LayoutNode *n = start_node, *child = NULL;
|
||||
+
|
||||
+ if (!m)
|
||||
+ return NULL;
|
||||
+
|
||||
+ if (n && n->is_client_node) {
|
||||
+ child = n;
|
||||
+ n = n->split_node;
|
||||
+ }
|
||||
+
|
||||
+ while (n) {
|
||||
+ if (!n->is_client_node && n->is_split_vertically == need_vertical &&
|
||||
+ visible_count(n->left, selmon) > 0 && visible_count(n->right, selmon) > 0)
|
||||
+ return n;
|
||||
+ if (!n->is_client_node && n->is_split_vertically == need_vertical
|
||||
+ && visible_count(n->left, m) > 0
|
||||
+ && visible_count(n->right, m) > 0) {
|
||||
+ if ((focused_on_left && n->left == child) ||
|
||||
+ (!focused_on_left && n->right == child))
|
||||
+ return n;
|
||||
+ }
|
||||
+ child = n;
|
||||
+ n = n->split_node;
|
||||
+ }
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+init_tree(Monitor *m)
|
||||
+{
|
||||
+ if (!m)
|
||||
+ return;
|
||||
+ m->root = calloc(1, sizeof(LayoutNode));
|
||||
+ if (!m->root)
|
||||
+ m->root = NULL;
|
||||
+ if (m)
|
||||
+ m->root = NULL;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
@@ -413,21 +428,31 @@ index 0000000..650cab5
|
||||
+ m->root = remove_client_node(m->root, c);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+setratio_h(const Arg *arg)
|
||||
+static void
|
||||
+setratio(unsigned int need_vertical, const Arg *arg)
|
||||
+{
|
||||
+ Client *sel = focustop(selmon);
|
||||
+ Client *sel;
|
||||
+ LayoutNode *client_node, *split_node;
|
||||
+ float new_ratio;
|
||||
+ int focused_on_left;
|
||||
+
|
||||
+ if (!sel || !selmon || !selmon->lt[selmon->sellt]->arrange)
|
||||
+ if (!selmon || !selmon->lt[selmon->sellt]->arrange)
|
||||
+ return;
|
||||
+
|
||||
+ sel = focustop(selmon);
|
||||
+ if (!sel)
|
||||
+ return;
|
||||
+
|
||||
+ client_node = find_client_node(selmon->root, sel);
|
||||
+ if (!client_node)
|
||||
+ return;
|
||||
+
|
||||
+ split_node = find_suitable_split(client_node, 1);
|
||||
+ focused_on_left = (arg->f >= 0.0f);
|
||||
+
|
||||
+ split_node = find_suitable_split(selmon, client_node, need_vertical, focused_on_left);
|
||||
+
|
||||
+ if (!split_node)
|
||||
+ split_node = find_suitable_split(selmon, client_node, need_vertical, !focused_on_left);
|
||||
+ if (!split_node)
|
||||
+ return;
|
||||
+
|
||||
@@ -438,109 +463,87 @@ index 0000000..650cab5
|
||||
+ new_ratio = 0.95f;
|
||||
+ split_node->split_ratio = new_ratio;
|
||||
+
|
||||
+ /* Skip the arrange if done resizing by mouse,
|
||||
+ * we call arrange from motionotify */
|
||||
+ if (!resizing_from_mouse) {
|
||||
+ arrange(selmon);
|
||||
+ }
|
||||
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
||||
+ /* Skip the arrange when called from motionnotify; that path calls
|
||||
+ * arrange itself after rate-limiting. */
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+setratio_h(const Arg *arg)
|
||||
+{
|
||||
+ setratio(1, arg);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+setratio_v(const Arg *arg)
|
||||
+{
|
||||
+ Client *sel = focustop(selmon);
|
||||
+ LayoutNode *client_node, *split_node;
|
||||
+ float new_ratio;
|
||||
+
|
||||
+ if (!sel || !selmon || !selmon->lt[selmon->sellt]->arrange)
|
||||
+ return;
|
||||
+
|
||||
+ client_node = find_client_node(selmon->root, sel);
|
||||
+ if (!client_node)
|
||||
+ return;
|
||||
+
|
||||
+ split_node = find_suitable_split(client_node, 0);
|
||||
+ if (!split_node)
|
||||
+ return;
|
||||
+
|
||||
+ new_ratio = (arg->f != 0.0f) ? (split_node->split_ratio + arg->f) : 0.5f;
|
||||
+ if (new_ratio < 0.05f)
|
||||
+ new_ratio = 0.05f;
|
||||
+ if (new_ratio > 0.95f)
|
||||
+ new_ratio = 0.95f;
|
||||
+ split_node->split_ratio = new_ratio;
|
||||
+
|
||||
+ /* Skip the arrange if done resizing by mouse,
|
||||
+ * we call arrange from motionotify */
|
||||
+ if (!resizing_from_mouse) {
|
||||
+ arrange(selmon);
|
||||
+ }
|
||||
+ setratio(0, arg);
|
||||
+}
|
||||
+
|
||||
+void swapclients(const Arg *arg) {
|
||||
+ Client *c, *tmp, *target = NULL, *sel = focustop(selmon);
|
||||
+ Client *c, *tmp, *target = NULL, *sel = focustop(selmon);
|
||||
+ LayoutNode *sel_node, *target_node;
|
||||
+ int closest_dist = INT_MAX, dist, sel_center_x, sel_center_y,
|
||||
+ int closest_dist = INT_MAX, dist, sel_center_x, sel_center_y,
|
||||
+ cand_center_x, cand_center_y;
|
||||
+
|
||||
+ if (!sel || sel->isfullscreen ||
|
||||
+ !selmon->root || !selmon->lt[selmon->sellt]->arrange)
|
||||
+ return;
|
||||
+ if (!sel || sel->isfullscreen ||
|
||||
+ !selmon->root || !selmon->lt[selmon->sellt]->arrange)
|
||||
+ return;
|
||||
+
|
||||
+
|
||||
+ /* Get the center coordinates of the selected client */
|
||||
+ sel_center_x = sel->geom.x + sel->geom.width / 2;
|
||||
+ sel_center_y = sel->geom.y + sel->geom.height / 2;
|
||||
+ /* Get the center coordinates of the selected client */
|
||||
+ sel_center_x = sel->geom.x + sel->geom.width / 2;
|
||||
+ sel_center_y = sel->geom.y + sel->geom.height / 2;
|
||||
+
|
||||
+ wl_list_for_each(c, &clients, link) {
|
||||
+ if (!VISIBLEON(c, selmon) || c->isfloating || c->isfullscreen || c == sel)
|
||||
+ continue;
|
||||
+ wl_list_for_each(c, &clients, link) {
|
||||
+ if (!VISIBLEON(c, selmon) || c->isfloating || c->isfullscreen || c == sel)
|
||||
+ continue;
|
||||
+
|
||||
+ /* Get the center of candidate client */
|
||||
+ cand_center_x = c->geom.x + c->geom.width / 2;
|
||||
+ cand_center_y = c->geom.y + c->geom.height / 2;
|
||||
+ /* Get the center of candidate client */
|
||||
+ cand_center_x = c->geom.x + c->geom.width / 2;
|
||||
+ cand_center_y = c->geom.y + c->geom.height / 2;
|
||||
+
|
||||
+ /* Check that the candidate lies in the requested direction. */
|
||||
+ switch (arg->ui) {
|
||||
+ case 0:
|
||||
+ if (cand_center_x >= sel_center_x)
|
||||
+ continue;
|
||||
+ break;
|
||||
+ case 1:
|
||||
+ if (cand_center_x <= sel_center_x)
|
||||
+ continue;
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ if (cand_center_y >= sel_center_y)
|
||||
+ continue;
|
||||
+ break;
|
||||
+ case 3:
|
||||
+ if (cand_center_y <= sel_center_y)
|
||||
+ continue;
|
||||
+ break;
|
||||
+ default:
|
||||
+ continue;
|
||||
+ }
|
||||
+ /* Check that the candidate lies in the requested direction. */
|
||||
+ switch (arg->ui) {
|
||||
+ case 0:
|
||||
+ if (cand_center_x >= sel_center_x)
|
||||
+ continue;
|
||||
+ break;
|
||||
+ case 1:
|
||||
+ if (cand_center_x <= sel_center_x)
|
||||
+ continue;
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ if (cand_center_y >= sel_center_y)
|
||||
+ continue;
|
||||
+ break;
|
||||
+ case 3:
|
||||
+ if (cand_center_y <= sel_center_y)
|
||||
+ continue;
|
||||
+ break;
|
||||
+ default:
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ /* Get distance between the centers */
|
||||
+ dist = abs(sel_center_x - cand_center_x) + abs(sel_center_y - cand_center_y);
|
||||
+ if (dist < closest_dist) {
|
||||
+ closest_dist = dist;
|
||||
+ target = c;
|
||||
+ }
|
||||
+ }
|
||||
+ /* Get distance between the centers */
|
||||
+ dist = abs(sel_center_x - cand_center_x) + abs(sel_center_y - cand_center_y);
|
||||
+ if (dist < closest_dist) {
|
||||
+ closest_dist = dist;
|
||||
+ target = c;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* If target is found, swap the two clients’ positions in the layout tree */
|
||||
+ if (target) {
|
||||
+ sel_node = find_client_node(selmon->root, sel);
|
||||
+ target_node = find_client_node(selmon->root, target);
|
||||
+ if (sel_node && target_node) {
|
||||
+ tmp = sel_node->client;
|
||||
+ sel_node->client = target_node->client;
|
||||
+ target_node->client = tmp;
|
||||
+ arrange(selmon);
|
||||
+ }
|
||||
+ }
|
||||
+ /* If target is found, swap the two clients’ positions in the layout tree */
|
||||
+ if (target) {
|
||||
+ sel_node = find_client_node(selmon->root, sel);
|
||||
+ target_node = find_client_node(selmon->root, target);
|
||||
+ if (sel_node && target_node) {
|
||||
+ tmp = sel_node->client;
|
||||
+ sel_node->client = target_node->client;
|
||||
+ target_node->client = tmp;
|
||||
+ arrange(selmon);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+unsigned int
|
||||
@@ -563,11 +566,12 @@ index 0000000..650cab5
|
||||
+
|
||||
+Client *
|
||||
+xytoclient(double x, double y) {
|
||||
+ Monitor *m = xytomon(x, y);
|
||||
+ Client *c, *closest = NULL;
|
||||
+ double dist, mindist = INT_MAX, dx, dy;
|
||||
+
|
||||
+ wl_list_for_each_reverse(c, &clients, link) {
|
||||
+ if (VISIBLEON(c, selmon) && !c->isfloating && !c->isfullscreen &&
|
||||
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen &&
|
||||
+ x >= c->geom.x && x <= (c->geom.x + c->geom.width) &&
|
||||
+ y >= c->geom.y && y <= (c->geom.y + c->geom.height)){
|
||||
+ return c;
|
||||
@@ -576,7 +580,7 @@ index 0000000..650cab5
|
||||
+
|
||||
+ /* If no client was found at cursor position fallback to closest. */
|
||||
+ wl_list_for_each_reverse(c, &clients, link) {
|
||||
+ if (VISIBLEON(c, selmon) && !c->isfloating && !c->isfullscreen) {
|
||||
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen) {
|
||||
+ dx = 0, dy = 0;
|
||||
+
|
||||
+ if (x < c->geom.x)
|
||||
@@ -589,7 +593,7 @@ index 0000000..650cab5
|
||||
+ else if (y > (c->geom.y + c->geom.height))
|
||||
+ dy = y - (c->geom.y + c->geom.height);
|
||||
+
|
||||
+ dist = sqrt(dx * dx + dy * dy);
|
||||
+ dist = dx * dx + dy * dy;
|
||||
+ if (dist < mindist) {
|
||||
+ mindist = dist;
|
||||
+ closest = c;
|
||||
@@ -599,13 +603,13 @@ index 0000000..650cab5
|
||||
+ return closest;
|
||||
+}
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 22d2171..92f3ad6 100644
|
||||
index 8a6eda0..bc04e3f 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -13,7 +13,10 @@ static const float focuscolor[] = COLOR(0x005577ff);
|
||||
static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
||||
static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You can also use glsl colors */
|
||||
static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */
|
||||
+static const float resize_factor = 0.0002f; /* Resize multiplier for mouse resizing, depends on mouse sensivity. */
|
||||
+static const uint32_t resize_interval_ms = 16; /* Resize interval depends on framerate and screen refresh rate. */
|
||||
|
||||
@@ -613,7 +617,7 @@ index 22d2171..92f3ad6 100644
|
||||
/* tagging - TAGCOUNT must be no greater than 31 */
|
||||
#define TAGCOUNT (9)
|
||||
|
||||
@@ -31,6 +34,7 @@ static const Rule rules[] = {
|
||||
@@ -30,6 +33,7 @@ static const Rule rules[] = {
|
||||
/* layout(s) */
|
||||
static const Layout layouts[] = {
|
||||
/* symbol arrange function */
|
||||
@@ -621,23 +625,23 @@ index 22d2171..92f3ad6 100644
|
||||
{ "[]=", tile },
|
||||
{ "><>", NULL }, /* no layout function means floating behavior */
|
||||
{ "[M]", monocle },
|
||||
@@ -148,6 +152,14 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less, tagmon, {.i = WLR_DIRECTION_LEFT} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Up, swapclients, {.i = DIR_UP} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Down, swapclients, {.i = DIR_DOWN} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Right, swapclients, {.i = DIR_RIGHT} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Left, swapclients, {.i = DIR_LEFT} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Right, setratio_h, {.f = +0.025f} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Left, setratio_h, {.f = -0.025f} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Up, setratio_v, {.f = -0.025f} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Down, setratio_v, {.f = +0.025f} },
|
||||
TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0),
|
||||
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
|
||||
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
||||
@@ -144,6 +148,14 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less, tagmon, {.i = WLR_DIRECTION_LEFT} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Up, swapclients, {.i = DIR_UP} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Down, swapclients, {.i = DIR_DOWN} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Right, swapclients, {.i = DIR_RIGHT} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Left, swapclients, {.i = DIR_LEFT} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Right, setratio_h, {.f = +0.025f} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Left, setratio_h, {.f = -0.025f} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Up, setratio_v, {.f = -0.025f} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Down, setratio_v, {.f = +0.025f} },
|
||||
TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0),
|
||||
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
|
||||
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index a2711f6..e49a061 100644
|
||||
index 8101ffa..c9650c1 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -1,6 +1,7 @@
|
||||
@@ -648,15 +652,15 @@ index a2711f6..e49a061 100644
|
||||
#include <getopt.h>
|
||||
#include <libinput.h>
|
||||
#include <linux/input-event-codes.h>
|
||||
@@ -103,6 +104,7 @@ typedef struct {
|
||||
@@ -104,6 +105,7 @@ typedef struct {
|
||||
const Arg arg;
|
||||
} Button;
|
||||
|
||||
+typedef struct LayoutNode LayoutNode;
|
||||
typedef struct Monitor Monitor;
|
||||
typedef struct {
|
||||
/* Must keep these three elements in this order */
|
||||
@@ -139,8 +141,9 @@ typedef struct {
|
||||
/* Must keep this field first */
|
||||
@@ -141,8 +143,9 @@ typedef struct {
|
||||
#endif
|
||||
unsigned int bw;
|
||||
uint32_t tags;
|
||||
@@ -667,7 +671,7 @@ index a2711f6..e49a061 100644
|
||||
} Client;
|
||||
|
||||
typedef struct {
|
||||
@@ -208,6 +211,7 @@ struct Monitor {
|
||||
@@ -209,6 +212,7 @@ struct Monitor {
|
||||
int nmaster;
|
||||
char ltsymbol[16];
|
||||
int asleep;
|
||||
@@ -675,7 +679,7 @@ index a2711f6..e49a061 100644
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -250,6 +254,7 @@ static void arrangelayer(Monitor *m, struct wl_list *list,
|
||||
@@ -251,6 +255,7 @@ static void arrangelayer(Monitor *m, struct wl_list *list,
|
||||
struct wlr_box *usable_area, int exclusive);
|
||||
static void arrangelayers(Monitor *m);
|
||||
static void axisnotify(struct wl_listener *listener, void *data);
|
||||
@@ -693,7 +697,7 @@ index a2711f6..e49a061 100644
|
||||
static void spawn(const Arg *arg);
|
||||
static void startdrag(struct wl_listener *listener, void *data);
|
||||
static void tag(const Arg *arg);
|
||||
@@ -431,6 +439,7 @@ static xcb_atom_t netatom[NetLast];
|
||||
@@ -458,6 +466,7 @@ static struct wlr_xwayland *xwayland;
|
||||
|
||||
/* attempt to encapsulate suck into one file */
|
||||
#include "client.h"
|
||||
@@ -701,7 +705,7 @@ index a2711f6..e49a061 100644
|
||||
|
||||
/* function implementations */
|
||||
void
|
||||
@@ -601,7 +610,7 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
@@ -628,7 +637,7 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
struct wlr_pointer_button_event *event = data;
|
||||
struct wlr_keyboard *keyboard;
|
||||
uint32_t mods;
|
||||
@@ -710,7 +714,7 @@ index a2711f6..e49a061 100644
|
||||
const Button *b;
|
||||
|
||||
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
||||
@@ -622,7 +631,7 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
@@ -649,7 +658,7 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
|
||||
for (b = buttons; b < END(buttons); b++) {
|
||||
if (CLEANMASK(mods) == CLEANMASK(b->mod) &&
|
||||
@@ -719,9 +723,9 @@ index a2711f6..e49a061 100644
|
||||
b->func(&b->arg);
|
||||
return;
|
||||
}
|
||||
@@ -632,15 +641,36 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
@@ -659,6 +668,21 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
/* If you released any buttons, we exit interactive move/resize mode. */
|
||||
/* TODO should reset to the pointer focus's current setcursor */
|
||||
/* TODO: should reset to the pointer focus's current setcursor */
|
||||
if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
|
||||
+ c = grabc;
|
||||
+ if (c && c->was_tiled && !strcmp(selmon->ltsymbol, "|w|")) {
|
||||
@@ -734,31 +738,14 @@ index a2711f6..e49a061 100644
|
||||
+ selmon->root = create_client_node(c);
|
||||
+
|
||||
+ setfloating(c, 0);
|
||||
+ arrange(selmon);
|
||||
+
|
||||
+ } else if (cursor_mode == CurResize && !c->isfloating) {
|
||||
+ resizing_from_mouse = 0;
|
||||
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (cursor_mode == CurResize && resizing_from_mouse)
|
||||
+ resizing_from_mouse = 0;
|
||||
+ }
|
||||
+ /* Default behaviour */
|
||||
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
||||
cursor_mode = CurNormal;
|
||||
/* Drop the window off on its new monitor */
|
||||
selmon = xytomon(cursor->x, cursor->y);
|
||||
setmon(grabc, selmon, 0);
|
||||
+ grabc = NULL;
|
||||
return;
|
||||
- } else {
|
||||
- cursor_mode = CurNormal;
|
||||
}
|
||||
+ cursor_mode = CurNormal;
|
||||
break;
|
||||
}
|
||||
/* If the event wasn't handled by the compositor, notify the client with
|
||||
@@ -720,6 +750,7 @@ cleanupmon(struct wl_listener *listener, void *data)
|
||||
@@ -750,6 +774,7 @@ cleanupmon(struct wl_listener *listener, void *data)
|
||||
wlr_output_layout_remove(output_layout, m->wlr_output);
|
||||
wlr_scene_output_destroy(m->scene_output);
|
||||
|
||||
@@ -766,7 +753,7 @@ index a2711f6..e49a061 100644
|
||||
closemon(m);
|
||||
wlr_scene_node_destroy(&m->fullscreen_bg->node);
|
||||
free(m);
|
||||
@@ -1024,6 +1055,7 @@ createmon(struct wl_listener *listener, void *data)
|
||||
@@ -1094,6 +1119,7 @@ createmon(struct wl_listener *listener, void *data)
|
||||
|
||||
wl_list_insert(&mons, &m->link);
|
||||
printstatus();
|
||||
@@ -774,18 +761,26 @@ index a2711f6..e49a061 100644
|
||||
|
||||
/* The xdg-protocol specifies:
|
||||
*
|
||||
@@ -1263,6 +1295,10 @@ destroynotify(struct wl_listener *listener, void *data)
|
||||
@@ -1332,10 +1358,18 @@ void
|
||||
destroynotify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
/* Called when the xdg_toplevel is destroyed. */
|
||||
+ Monitor *mon;
|
||||
Client *c = wl_container_of(listener, c, destroy);
|
||||
wl_list_remove(&c->destroy.link);
|
||||
wl_list_remove(&c->set_title.link);
|
||||
wl_list_remove(&c->fullscreen.link);
|
||||
+ /* We check if the destroyed client was part of any tiled_list, to catch
|
||||
+ * client removals even if they would not be currently managed by btrtile */
|
||||
+ if (selmon && selmon->root)
|
||||
+ remove_client(selmon, c);
|
||||
+ wl_list_for_each(mon, &mons, link) {
|
||||
+ if (mon->root) {
|
||||
+ remove_client(mon, c);
|
||||
+ }
|
||||
+ }
|
||||
#ifdef XWAYLAND
|
||||
if (c->type != XDGShell) {
|
||||
wl_list_remove(&c->activate.link);
|
||||
@@ -1809,7 +1845,8 @@ void
|
||||
@@ -1866,7 +1900,8 @@ void
|
||||
motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy,
|
||||
double dx_unaccel, double dy_unaccel)
|
||||
{
|
||||
@@ -795,13 +790,13 @@ index a2711f6..e49a061 100644
|
||||
Client *c = NULL, *w = NULL;
|
||||
LayerSurface *l = NULL;
|
||||
struct wlr_surface *surface = NULL;
|
||||
@@ -1863,18 +1900,56 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
|
||||
@@ -1920,18 +1955,55 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
|
||||
/* Update drag icon's position */
|
||||
wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y));
|
||||
|
||||
- /* If we are currently grabbing the mouse, handle and return */
|
||||
+ /* Skip if internal call or already resizing */
|
||||
+ if (time == 0 && resizing_from_mouse)
|
||||
+ /* Skip if internal call */
|
||||
+ if (time == 0)
|
||||
+ goto focus;
|
||||
+
|
||||
+ tiled = grabc && !grabc->isfloating && !grabc->isfullscreen;
|
||||
@@ -823,7 +818,7 @@ index a2711f6..e49a061 100644
|
||||
- resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y,
|
||||
- .width = (int)round(cursor->x) - grabc->geom.x, .height = (int)round(cursor->y) - grabc->geom.y}, 1);
|
||||
- return;
|
||||
+ if (tiled && resizing_from_mouse) {
|
||||
+ if (tiled) {
|
||||
+ dx_total = cursor->x - resize_last_update_x;
|
||||
+ dy_total = cursor->y - resize_last_update_y;
|
||||
+
|
||||
@@ -836,7 +831,6 @@ index a2711f6..e49a061 100644
|
||||
+ a.f = (float)(dy_total * resize_factor);
|
||||
+ setratio_v(&a);
|
||||
+ }
|
||||
+ arrange(selmon);
|
||||
+
|
||||
+ last_resize_time = time;
|
||||
+ resize_last_update_x = cursor->x;
|
||||
@@ -859,7 +853,7 @@ index a2711f6..e49a061 100644
|
||||
/* If there's no client surface under the cursor, set the cursor image to a
|
||||
* default. This is what makes the cursor image appear when you move it
|
||||
* off of a client or over its border. */
|
||||
@@ -1908,22 +1983,41 @@ moveresize(const Arg *arg)
|
||||
@@ -1965,22 +2037,40 @@ moveresize(const Arg *arg)
|
||||
if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
|
||||
return;
|
||||
|
||||
@@ -869,7 +863,7 @@ index a2711f6..e49a061 100644
|
||||
- case CurMove:
|
||||
- grabcx = (int)round(cursor->x) - grabc->geom.x;
|
||||
- grabcy = (int)round(cursor->y) - grabc->geom.y;
|
||||
- wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur");
|
||||
- wlr_cursor_set_xcursor(cursor, cursor_mgr, "all-scroll");
|
||||
- break;
|
||||
- case CurResize:
|
||||
- /* Doesn't work for X11 output - the next absolute motion event
|
||||
@@ -894,7 +888,6 @@ index a2711f6..e49a061 100644
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
||||
+ resize_last_update_x = cursor->x;
|
||||
+ resize_last_update_y = cursor->y;
|
||||
+ resizing_from_mouse = 1;
|
||||
+ break;
|
||||
+ }
|
||||
+ } else {
|
||||
@@ -917,6 +910,21 @@ index a2711f6..e49a061 100644
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2833,6 +2923,14 @@ unmapnotify(struct wl_listener *listener, void *data)
|
||||
focusclient(focustop(selmon), 1);
|
||||
}
|
||||
} else {
|
||||
+ /* btrtile remove clients for each monitor */
|
||||
+ Monitor *mon;
|
||||
+ wl_list_for_each(mon, &mons, link) {
|
||||
+ if (mon->root) {
|
||||
+ remove_client(mon, c);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
wl_list_remove(&c->link);
|
||||
setmon(c, NULL, 0);
|
||||
wl_list_remove(&c->flink);
|
||||
--
|
||||
2.45.3
|
||||
2.53.0
|
||||
|
||||
+193
-186
@@ -1,30 +1,35 @@
|
||||
From b9789420f166c20579f29ecd171a8956c681848d Mon Sep 17 00:00:00 2001
|
||||
From 47cb7ad9f669643765cafa4c2ecd1a4850bca893 Mon Sep 17 00:00:00 2001
|
||||
From: julmajustus <julmajustus@tutanota.com>
|
||||
Date: Thu, 13 Feb 2025 23:23:40 +0200
|
||||
Subject: [PATCH] btrtile with multi-tag support
|
||||
Date: Thu, 21 May 2026 00:39:56 +0300
|
||||
Subject: [PATCH] btrtile: Spring update pt2
|
||||
|
||||
- Simplified the resizing logic to avoid full arrange calls from
|
||||
motionnotify
|
||||
- Minor intend fixes
|
||||
---
|
||||
btrtile.c | 563 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
btrtile.c | 564 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
config.def.h | 12 ++
|
||||
dwl.c | 152 +++++++++++---
|
||||
3 files changed, 698 insertions(+), 29 deletions(-)
|
||||
3 files changed, 701 insertions(+), 27 deletions(-)
|
||||
create mode 100644 btrtile.c
|
||||
|
||||
diff --git a/btrtile.c b/btrtile.c
|
||||
new file mode 100644
|
||||
index 0000000..03f4680
|
||||
index 0000000..357ffb9
|
||||
--- /dev/null
|
||||
+++ b/btrtile.c
|
||||
@@ -0,0 +1,563 @@
|
||||
@@ -0,0 +1,564 @@
|
||||
+/* ************************************************************************** */
|
||||
+/* */
|
||||
+/* ::: :::::::: */
|
||||
+/* btrtile.c :+: :+: :+: */
|
||||
+/* +:+ +:+ +:+ */
|
||||
+/* By: jmakkone <jmakkone@student.hive.fi> +#+ +:+ +#+ */
|
||||
+/* +#+#+#+#+#+ +#+ */
|
||||
+/* Created: 2024/12/15 00:26:07 by jmakkone #+# #+# */
|
||||
+/* Updated: 2025/02/13 23:22:33 by jmakkone ### ########.fr */
|
||||
+/* @@@ @@@@@@@@ */
|
||||
+/* @@@ @@@@@@@@@@ */
|
||||
+/* @@! @@! @@@@ */
|
||||
+/* !@! !@! @!@!@ */
|
||||
+/* btrtile.c @!! @!@ @! !@! */
|
||||
+/* !!! !@!!! !!! */
|
||||
+/* By: julmajustus <julmajustus@tutanota.com> !!: !!:! !!! */
|
||||
+/* ::! :!: !:! */
|
||||
+/* Created: 2024/12/15 00:26:07 by julmajustus :: ::::::: :: */
|
||||
+/* Updated: 2026/05/20 22:51:54 by julmajustus : : : : : : */
|
||||
+/* */
|
||||
+/* ************************************************************************** */
|
||||
+
|
||||
@@ -47,7 +52,8 @@ index 0000000..03f4680
|
||||
+static void destroy_node(LayoutNode *node);
|
||||
+static void destroy_tree(Monitor *m);
|
||||
+static LayoutNode *find_client_node(LayoutNode *node, Client *c);
|
||||
+static LayoutNode *find_suitable_split(LayoutNode *start, unsigned int need_vert);
|
||||
+static LayoutNode *find_suitable_split(Monitor *m, LayoutNode *start,
|
||||
+ unsigned int need_vertical, int focused_on_left);
|
||||
+static void init_tree(Monitor *m);
|
||||
+static void insert_client(Monitor *m, Client *focused_client, Client *new_client);
|
||||
+static LayoutNode *remove_client_node(LayoutNode *node, Client *c);
|
||||
@@ -58,7 +64,6 @@ index 0000000..03f4680
|
||||
+static unsigned int visible_count(LayoutNode *node, Monitor *m);
|
||||
+static Client *xytoclient(double x, double y);
|
||||
+
|
||||
+static int resizing_from_mouse = 0;
|
||||
+static double resize_last_update_x, resize_last_update_y;
|
||||
+static uint32_t last_resize_time = 0;
|
||||
+
|
||||
@@ -79,6 +84,9 @@ index 0000000..03f4680
|
||||
+ c = node->client;
|
||||
+ if (!c || !VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||
+ return;
|
||||
+ if (area.x == c->old_geom.x && area.y == c->old_geom.y &&
|
||||
+ area.width == c->old_geom.width && area.height == c->old_geom.height)
|
||||
+ return;
|
||||
+ resize(c, area, 0);
|
||||
+ c->old_geom = area;
|
||||
+ return;
|
||||
@@ -145,7 +153,7 @@ index 0000000..03f4680
|
||||
+ LayoutNode *found;
|
||||
+ struct wlr_box full_area;
|
||||
+
|
||||
+ if (!m || !m->root)
|
||||
+ if (!m)
|
||||
+ return;
|
||||
+
|
||||
+ /* Remove non tiled clients from tree. */
|
||||
@@ -247,30 +255,37 @@ index 0000000..03f4680
|
||||
+}
|
||||
+
|
||||
+LayoutNode *
|
||||
+find_suitable_split(LayoutNode *start_node, unsigned int need_vertical)
|
||||
+find_suitable_split(Monitor *m, LayoutNode *start_node,
|
||||
+ unsigned int need_vertical, int focused_on_left)
|
||||
+{
|
||||
+ LayoutNode *n = start_node;
|
||||
+ /* if we started from a client node, jump to its parent: */
|
||||
+ if (n && n->is_client_node)
|
||||
+ LayoutNode *n = start_node, *child = NULL;
|
||||
+
|
||||
+ if (!m)
|
||||
+ return NULL;
|
||||
+
|
||||
+ if (n && n->is_client_node) {
|
||||
+ child = n;
|
||||
+ n = n->split_node;
|
||||
+ }
|
||||
+
|
||||
+ while (n) {
|
||||
+ if (!n->is_client_node && n->is_split_vertically == need_vertical &&
|
||||
+ visible_count(n->left, selmon) > 0 && visible_count(n->right, selmon) > 0)
|
||||
+ return n;
|
||||
+ if (!n->is_client_node && n->is_split_vertically == need_vertical
|
||||
+ && visible_count(n->left, m) > 0
|
||||
+ && visible_count(n->right, m) > 0) {
|
||||
+ if ((focused_on_left && n->left == child) ||
|
||||
+ (!focused_on_left && n->right == child))
|
||||
+ return n;
|
||||
+ }
|
||||
+ child = n;
|
||||
+ n = n->split_node;
|
||||
+ }
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+init_tree(Monitor *m)
|
||||
+{
|
||||
+ if (!m)
|
||||
+ return;
|
||||
+ m->root = calloc(1, sizeof(LayoutNode));
|
||||
+ if (!m->root)
|
||||
+ m->root = NULL;
|
||||
+ if (m)
|
||||
+ m->root = NULL;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
@@ -394,21 +409,31 @@ index 0000000..03f4680
|
||||
+ m->root = remove_client_node(m->root, c);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+setratio_h(const Arg *arg)
|
||||
+static void
|
||||
+setratio(unsigned int need_vertical, const Arg *arg)
|
||||
+{
|
||||
+ Client *sel = focustop(selmon);
|
||||
+ Client *sel;
|
||||
+ LayoutNode *client_node, *split_node;
|
||||
+ float new_ratio;
|
||||
+ int focused_on_left;
|
||||
+
|
||||
+ if (!sel || !selmon || !selmon->lt[selmon->sellt]->arrange)
|
||||
+ if (!selmon || !selmon->lt[selmon->sellt]->arrange)
|
||||
+ return;
|
||||
+
|
||||
+ sel = focustop(selmon);
|
||||
+ if (!sel)
|
||||
+ return;
|
||||
+
|
||||
+ client_node = find_client_node(selmon->root, sel);
|
||||
+ if (!client_node)
|
||||
+ return;
|
||||
+
|
||||
+ split_node = find_suitable_split(client_node, 1);
|
||||
+ focused_on_left = (arg->f >= 0.0f);
|
||||
+
|
||||
+ split_node = find_suitable_split(selmon, client_node, need_vertical, focused_on_left);
|
||||
+
|
||||
+ if (!split_node)
|
||||
+ split_node = find_suitable_split(selmon, client_node, need_vertical, !focused_on_left);
|
||||
+ if (!split_node)
|
||||
+ return;
|
||||
+
|
||||
@@ -419,109 +444,87 @@ index 0000000..03f4680
|
||||
+ new_ratio = 0.95f;
|
||||
+ split_node->split_ratio = new_ratio;
|
||||
+
|
||||
+ /* Skip the arrange if done resizing by mouse,
|
||||
+ * we call arrange from motionotify */
|
||||
+ if (!resizing_from_mouse) {
|
||||
+ arrange(selmon);
|
||||
+ }
|
||||
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
||||
+ /* Skip the arrange when called from motionnotify; that path calls
|
||||
+ * arrange itself after rate-limiting. */
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+setratio_h(const Arg *arg)
|
||||
+{
|
||||
+ setratio(1, arg);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+setratio_v(const Arg *arg)
|
||||
+{
|
||||
+ Client *sel = focustop(selmon);
|
||||
+ LayoutNode *client_node, *split_node;
|
||||
+ float new_ratio;
|
||||
+
|
||||
+ if (!sel || !selmon || !selmon->lt[selmon->sellt]->arrange)
|
||||
+ return;
|
||||
+
|
||||
+ client_node = find_client_node(selmon->root, sel);
|
||||
+ if (!client_node)
|
||||
+ return;
|
||||
+
|
||||
+ split_node = find_suitable_split(client_node, 0);
|
||||
+ if (!split_node)
|
||||
+ return;
|
||||
+
|
||||
+ new_ratio = (arg->f != 0.0f) ? (split_node->split_ratio + arg->f) : 0.5f;
|
||||
+ if (new_ratio < 0.05f)
|
||||
+ new_ratio = 0.05f;
|
||||
+ if (new_ratio > 0.95f)
|
||||
+ new_ratio = 0.95f;
|
||||
+ split_node->split_ratio = new_ratio;
|
||||
+
|
||||
+ /* Skip the arrange if done resizing by mouse,
|
||||
+ * we call arrange from motionotify */
|
||||
+ if (!resizing_from_mouse) {
|
||||
+ arrange(selmon);
|
||||
+ }
|
||||
+ setratio(0, arg);
|
||||
+}
|
||||
+
|
||||
+void swapclients(const Arg *arg) {
|
||||
+ Client *c, *tmp, *target = NULL, *sel = focustop(selmon);
|
||||
+ Client *c, *tmp, *target = NULL, *sel = focustop(selmon);
|
||||
+ LayoutNode *sel_node, *target_node;
|
||||
+ int closest_dist = INT_MAX, dist, sel_center_x, sel_center_y,
|
||||
+ int closest_dist = INT_MAX, dist, sel_center_x, sel_center_y,
|
||||
+ cand_center_x, cand_center_y;
|
||||
+
|
||||
+ if (!sel || sel->isfullscreen ||
|
||||
+ !selmon->root || !selmon->lt[selmon->sellt]->arrange)
|
||||
+ return;
|
||||
+ if (!sel || sel->isfullscreen ||
|
||||
+ !selmon->root || !selmon->lt[selmon->sellt]->arrange)
|
||||
+ return;
|
||||
+
|
||||
+
|
||||
+ /* Get the center coordinates of the selected client */
|
||||
+ sel_center_x = sel->geom.x + sel->geom.width / 2;
|
||||
+ sel_center_y = sel->geom.y + sel->geom.height / 2;
|
||||
+ /* Get the center coordinates of the selected client */
|
||||
+ sel_center_x = sel->geom.x + sel->geom.width / 2;
|
||||
+ sel_center_y = sel->geom.y + sel->geom.height / 2;
|
||||
+
|
||||
+ wl_list_for_each(c, &clients, link) {
|
||||
+ if (!VISIBLEON(c, selmon) || c->isfloating || c->isfullscreen || c == sel)
|
||||
+ continue;
|
||||
+ wl_list_for_each(c, &clients, link) {
|
||||
+ if (!VISIBLEON(c, selmon) || c->isfloating || c->isfullscreen || c == sel)
|
||||
+ continue;
|
||||
+
|
||||
+ /* Get the center of candidate client */
|
||||
+ cand_center_x = c->geom.x + c->geom.width / 2;
|
||||
+ cand_center_y = c->geom.y + c->geom.height / 2;
|
||||
+ /* Get the center of candidate client */
|
||||
+ cand_center_x = c->geom.x + c->geom.width / 2;
|
||||
+ cand_center_y = c->geom.y + c->geom.height / 2;
|
||||
+
|
||||
+ /* Check that the candidate lies in the requested direction. */
|
||||
+ switch (arg->ui) {
|
||||
+ case 0:
|
||||
+ if (cand_center_x >= sel_center_x)
|
||||
+ continue;
|
||||
+ break;
|
||||
+ case 1:
|
||||
+ if (cand_center_x <= sel_center_x)
|
||||
+ continue;
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ if (cand_center_y >= sel_center_y)
|
||||
+ continue;
|
||||
+ break;
|
||||
+ case 3:
|
||||
+ if (cand_center_y <= sel_center_y)
|
||||
+ continue;
|
||||
+ break;
|
||||
+ default:
|
||||
+ continue;
|
||||
+ }
|
||||
+ /* Check that the candidate lies in the requested direction. */
|
||||
+ switch (arg->ui) {
|
||||
+ case 0:
|
||||
+ if (cand_center_x >= sel_center_x)
|
||||
+ continue;
|
||||
+ break;
|
||||
+ case 1:
|
||||
+ if (cand_center_x <= sel_center_x)
|
||||
+ continue;
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ if (cand_center_y >= sel_center_y)
|
||||
+ continue;
|
||||
+ break;
|
||||
+ case 3:
|
||||
+ if (cand_center_y <= sel_center_y)
|
||||
+ continue;
|
||||
+ break;
|
||||
+ default:
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ /* Get distance between the centers */
|
||||
+ dist = abs(sel_center_x - cand_center_x) + abs(sel_center_y - cand_center_y);
|
||||
+ if (dist < closest_dist) {
|
||||
+ closest_dist = dist;
|
||||
+ target = c;
|
||||
+ }
|
||||
+ }
|
||||
+ /* Get distance between the centers */
|
||||
+ dist = abs(sel_center_x - cand_center_x) + abs(sel_center_y - cand_center_y);
|
||||
+ if (dist < closest_dist) {
|
||||
+ closest_dist = dist;
|
||||
+ target = c;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* If target is found, swap the two clients’ positions in the layout tree */
|
||||
+ if (target) {
|
||||
+ sel_node = find_client_node(selmon->root, sel);
|
||||
+ target_node = find_client_node(selmon->root, target);
|
||||
+ if (sel_node && target_node) {
|
||||
+ tmp = sel_node->client;
|
||||
+ sel_node->client = target_node->client;
|
||||
+ target_node->client = tmp;
|
||||
+ arrange(selmon);
|
||||
+ }
|
||||
+ }
|
||||
+ /* If target is found, swap the two clients’ positions in the layout tree */
|
||||
+ if (target) {
|
||||
+ sel_node = find_client_node(selmon->root, sel);
|
||||
+ target_node = find_client_node(selmon->root, target);
|
||||
+ if (sel_node && target_node) {
|
||||
+ tmp = sel_node->client;
|
||||
+ sel_node->client = target_node->client;
|
||||
+ target_node->client = tmp;
|
||||
+ arrange(selmon);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+unsigned int
|
||||
@@ -544,11 +547,12 @@ index 0000000..03f4680
|
||||
+
|
||||
+Client *
|
||||
+xytoclient(double x, double y) {
|
||||
+ Monitor *m = xytomon(x, y);
|
||||
+ Client *c, *closest = NULL;
|
||||
+ double dist, mindist = INT_MAX, dx, dy;
|
||||
+
|
||||
+ wl_list_for_each_reverse(c, &clients, link) {
|
||||
+ if (VISIBLEON(c, selmon) && !c->isfloating && !c->isfullscreen &&
|
||||
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen &&
|
||||
+ x >= c->geom.x && x <= (c->geom.x + c->geom.width) &&
|
||||
+ y >= c->geom.y && y <= (c->geom.y + c->geom.height)){
|
||||
+ return c;
|
||||
@@ -557,7 +561,7 @@ index 0000000..03f4680
|
||||
+
|
||||
+ /* If no client was found at cursor position fallback to closest. */
|
||||
+ wl_list_for_each_reverse(c, &clients, link) {
|
||||
+ if (VISIBLEON(c, selmon) && !c->isfloating && !c->isfullscreen) {
|
||||
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen) {
|
||||
+ dx = 0, dy = 0;
|
||||
+
|
||||
+ if (x < c->geom.x)
|
||||
@@ -570,7 +574,7 @@ index 0000000..03f4680
|
||||
+ else if (y > (c->geom.y + c->geom.height))
|
||||
+ dy = y - (c->geom.y + c->geom.height);
|
||||
+
|
||||
+ dist = sqrt(dx * dx + dy * dy);
|
||||
+ dist = dx * dx + dy * dy;
|
||||
+ if (dist < mindist) {
|
||||
+ mindist = dist;
|
||||
+ closest = c;
|
||||
@@ -580,13 +584,13 @@ index 0000000..03f4680
|
||||
+ return closest;
|
||||
+}
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 22d2171..92f3ad6 100644
|
||||
index 8a6eda0..bc04e3f 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -13,7 +13,10 @@ static const float focuscolor[] = COLOR(0x005577ff);
|
||||
static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
||||
static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You can also use glsl colors */
|
||||
static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */
|
||||
+static const float resize_factor = 0.0002f; /* Resize multiplier for mouse resizing, depends on mouse sensivity. */
|
||||
+static const uint32_t resize_interval_ms = 16; /* Resize interval depends on framerate and screen refresh rate. */
|
||||
|
||||
@@ -594,7 +598,7 @@ index 22d2171..92f3ad6 100644
|
||||
/* tagging - TAGCOUNT must be no greater than 31 */
|
||||
#define TAGCOUNT (9)
|
||||
|
||||
@@ -31,6 +34,7 @@ static const Rule rules[] = {
|
||||
@@ -30,6 +33,7 @@ static const Rule rules[] = {
|
||||
/* layout(s) */
|
||||
static const Layout layouts[] = {
|
||||
/* symbol arrange function */
|
||||
@@ -602,23 +606,23 @@ index 22d2171..92f3ad6 100644
|
||||
{ "[]=", tile },
|
||||
{ "><>", NULL }, /* no layout function means floating behavior */
|
||||
{ "[M]", monocle },
|
||||
@@ -148,6 +152,14 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less, tagmon, {.i = WLR_DIRECTION_LEFT} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Up, swapclients, {.i = DIR_UP} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Down, swapclients, {.i = DIR_DOWN} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Right, swapclients, {.i = DIR_RIGHT} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Left, swapclients, {.i = DIR_LEFT} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Right, setratio_h, {.f = +0.025f} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Left, setratio_h, {.f = -0.025f} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Up, setratio_v, {.f = -0.025f} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Down, setratio_v, {.f = +0.025f} },
|
||||
TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0),
|
||||
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
|
||||
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
||||
@@ -144,6 +148,14 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less, tagmon, {.i = WLR_DIRECTION_LEFT} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Up, swapclients, {.i = DIR_UP} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Down, swapclients, {.i = DIR_DOWN} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Right, swapclients, {.i = DIR_RIGHT} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Left, swapclients, {.i = DIR_LEFT} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Right, setratio_h, {.f = +0.025f} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Left, setratio_h, {.f = -0.025f} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Up, setratio_v, {.f = -0.025f} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Down, setratio_v, {.f = +0.025f} },
|
||||
TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0),
|
||||
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
|
||||
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index a2711f6..e49a061 100644
|
||||
index 8101ffa..bf52c6c 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -1,6 +1,7 @@
|
||||
@@ -629,15 +633,15 @@ index a2711f6..e49a061 100644
|
||||
#include <getopt.h>
|
||||
#include <libinput.h>
|
||||
#include <linux/input-event-codes.h>
|
||||
@@ -103,6 +104,7 @@ typedef struct {
|
||||
@@ -104,6 +105,7 @@ typedef struct {
|
||||
const Arg arg;
|
||||
} Button;
|
||||
|
||||
+typedef struct LayoutNode LayoutNode;
|
||||
typedef struct Monitor Monitor;
|
||||
typedef struct {
|
||||
/* Must keep these three elements in this order */
|
||||
@@ -139,8 +141,9 @@ typedef struct {
|
||||
/* Must keep this field first */
|
||||
@@ -141,8 +143,9 @@ typedef struct {
|
||||
#endif
|
||||
unsigned int bw;
|
||||
uint32_t tags;
|
||||
@@ -648,7 +652,7 @@ index a2711f6..e49a061 100644
|
||||
} Client;
|
||||
|
||||
typedef struct {
|
||||
@@ -208,6 +211,7 @@ struct Monitor {
|
||||
@@ -209,6 +212,7 @@ struct Monitor {
|
||||
int nmaster;
|
||||
char ltsymbol[16];
|
||||
int asleep;
|
||||
@@ -656,7 +660,7 @@ index a2711f6..e49a061 100644
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -250,6 +254,7 @@ static void arrangelayer(Monitor *m, struct wl_list *list,
|
||||
@@ -251,6 +255,7 @@ static void arrangelayer(Monitor *m, struct wl_list *list,
|
||||
struct wlr_box *usable_area, int exclusive);
|
||||
static void arrangelayers(Monitor *m);
|
||||
static void axisnotify(struct wl_listener *listener, void *data);
|
||||
@@ -674,7 +678,7 @@ index a2711f6..e49a061 100644
|
||||
static void spawn(const Arg *arg);
|
||||
static void startdrag(struct wl_listener *listener, void *data);
|
||||
static void tag(const Arg *arg);
|
||||
@@ -431,6 +439,7 @@ static xcb_atom_t netatom[NetLast];
|
||||
@@ -458,6 +466,7 @@ static struct wlr_xwayland *xwayland;
|
||||
|
||||
/* attempt to encapsulate suck into one file */
|
||||
#include "client.h"
|
||||
@@ -682,7 +686,7 @@ index a2711f6..e49a061 100644
|
||||
|
||||
/* function implementations */
|
||||
void
|
||||
@@ -601,7 +610,7 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
@@ -628,7 +637,7 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
struct wlr_pointer_button_event *event = data;
|
||||
struct wlr_keyboard *keyboard;
|
||||
uint32_t mods;
|
||||
@@ -691,7 +695,7 @@ index a2711f6..e49a061 100644
|
||||
const Button *b;
|
||||
|
||||
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
||||
@@ -622,7 +631,7 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
@@ -649,7 +658,7 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
|
||||
for (b = buttons; b < END(buttons); b++) {
|
||||
if (CLEANMASK(mods) == CLEANMASK(b->mod) &&
|
||||
@@ -700,9 +704,9 @@ index a2711f6..e49a061 100644
|
||||
b->func(&b->arg);
|
||||
return;
|
||||
}
|
||||
@@ -632,15 +641,36 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
@@ -659,6 +668,21 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
/* If you released any buttons, we exit interactive move/resize mode. */
|
||||
/* TODO should reset to the pointer focus's current setcursor */
|
||||
/* TODO: should reset to the pointer focus's current setcursor */
|
||||
if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
|
||||
+ c = grabc;
|
||||
+ if (c && c->was_tiled && !strcmp(selmon->ltsymbol, "|w|")) {
|
||||
@@ -715,31 +719,14 @@ index a2711f6..e49a061 100644
|
||||
+ selmon->root = create_client_node(c);
|
||||
+
|
||||
+ setfloating(c, 0);
|
||||
+ arrange(selmon);
|
||||
+
|
||||
+ } else if (cursor_mode == CurResize && !c->isfloating) {
|
||||
+ resizing_from_mouse = 0;
|
||||
+ apply_layout(selmon, selmon->root, selmon->w, 1);
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (cursor_mode == CurResize && resizing_from_mouse)
|
||||
+ resizing_from_mouse = 0;
|
||||
+ }
|
||||
+ /* Default behaviour */
|
||||
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
||||
cursor_mode = CurNormal;
|
||||
/* Drop the window off on its new monitor */
|
||||
selmon = xytomon(cursor->x, cursor->y);
|
||||
setmon(grabc, selmon, 0);
|
||||
+ grabc = NULL;
|
||||
return;
|
||||
- } else {
|
||||
- cursor_mode = CurNormal;
|
||||
}
|
||||
+ cursor_mode = CurNormal;
|
||||
break;
|
||||
}
|
||||
/* If the event wasn't handled by the compositor, notify the client with
|
||||
@@ -720,6 +750,7 @@ cleanupmon(struct wl_listener *listener, void *data)
|
||||
@@ -750,6 +774,7 @@ cleanupmon(struct wl_listener *listener, void *data)
|
||||
wlr_output_layout_remove(output_layout, m->wlr_output);
|
||||
wlr_scene_output_destroy(m->scene_output);
|
||||
|
||||
@@ -747,7 +734,7 @@ index a2711f6..e49a061 100644
|
||||
closemon(m);
|
||||
wlr_scene_node_destroy(&m->fullscreen_bg->node);
|
||||
free(m);
|
||||
@@ -1024,6 +1055,7 @@ createmon(struct wl_listener *listener, void *data)
|
||||
@@ -1094,6 +1119,7 @@ createmon(struct wl_listener *listener, void *data)
|
||||
|
||||
wl_list_insert(&mons, &m->link);
|
||||
printstatus();
|
||||
@@ -755,18 +742,25 @@ index a2711f6..e49a061 100644
|
||||
|
||||
/* The xdg-protocol specifies:
|
||||
*
|
||||
@@ -1263,6 +1295,10 @@ destroynotify(struct wl_listener *listener, void *data)
|
||||
@@ -1333,9 +1359,17 @@ destroynotify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
/* Called when the xdg_toplevel is destroyed. */
|
||||
Client *c = wl_container_of(listener, c, destroy);
|
||||
+ Monitor *mon;
|
||||
wl_list_remove(&c->destroy.link);
|
||||
wl_list_remove(&c->set_title.link);
|
||||
wl_list_remove(&c->fullscreen.link);
|
||||
+ /* We check if the destroyed client was part of any tiled_list, to catch
|
||||
+ * client removals even if they would not be currently managed by btrtile */
|
||||
+ if (selmon && selmon->root)
|
||||
+ remove_client(selmon, c);
|
||||
+ wl_list_for_each(mon, &mons, link) {
|
||||
+ if (mon->root) {
|
||||
+ remove_client(mon, c);
|
||||
+ }
|
||||
+ }
|
||||
#ifdef XWAYLAND
|
||||
if (c->type != XDGShell) {
|
||||
wl_list_remove(&c->activate.link);
|
||||
@@ -1809,7 +1845,8 @@ void
|
||||
@@ -1866,7 +1900,8 @@ void
|
||||
motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy,
|
||||
double dx_unaccel, double dy_unaccel)
|
||||
{
|
||||
@@ -776,13 +770,13 @@ index a2711f6..e49a061 100644
|
||||
Client *c = NULL, *w = NULL;
|
||||
LayerSurface *l = NULL;
|
||||
struct wlr_surface *surface = NULL;
|
||||
@@ -1863,18 +1900,56 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
|
||||
@@ -1920,18 +1955,55 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
|
||||
/* Update drag icon's position */
|
||||
wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y));
|
||||
|
||||
- /* If we are currently grabbing the mouse, handle and return */
|
||||
+ /* Skip if internal call or already resizing */
|
||||
+ if (time == 0 && resizing_from_mouse)
|
||||
+ /* Skip if internal call */
|
||||
+ if (time == 0)
|
||||
+ goto focus;
|
||||
+
|
||||
+ tiled = grabc && !grabc->isfloating && !grabc->isfullscreen;
|
||||
@@ -804,7 +798,7 @@ index a2711f6..e49a061 100644
|
||||
- resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y,
|
||||
- .width = (int)round(cursor->x) - grabc->geom.x, .height = (int)round(cursor->y) - grabc->geom.y}, 1);
|
||||
- return;
|
||||
+ if (tiled && resizing_from_mouse) {
|
||||
+ if (tiled) {
|
||||
+ dx_total = cursor->x - resize_last_update_x;
|
||||
+ dy_total = cursor->y - resize_last_update_y;
|
||||
+
|
||||
@@ -817,7 +811,6 @@ index a2711f6..e49a061 100644
|
||||
+ a.f = (float)(dy_total * resize_factor);
|
||||
+ setratio_v(&a);
|
||||
+ }
|
||||
+ arrange(selmon);
|
||||
+
|
||||
+ last_resize_time = time;
|
||||
+ resize_last_update_x = cursor->x;
|
||||
@@ -840,7 +833,7 @@ index a2711f6..e49a061 100644
|
||||
/* If there's no client surface under the cursor, set the cursor image to a
|
||||
* default. This is what makes the cursor image appear when you move it
|
||||
* off of a client or over its border. */
|
||||
@@ -1908,22 +1983,41 @@ moveresize(const Arg *arg)
|
||||
@@ -1965,22 +2037,40 @@ moveresize(const Arg *arg)
|
||||
if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
|
||||
return;
|
||||
|
||||
@@ -850,7 +843,7 @@ index a2711f6..e49a061 100644
|
||||
- case CurMove:
|
||||
- grabcx = (int)round(cursor->x) - grabc->geom.x;
|
||||
- grabcy = (int)round(cursor->y) - grabc->geom.y;
|
||||
- wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur");
|
||||
- wlr_cursor_set_xcursor(cursor, cursor_mgr, "all-scroll");
|
||||
- break;
|
||||
- case CurResize:
|
||||
- /* Doesn't work for X11 output - the next absolute motion event
|
||||
@@ -875,7 +868,6 @@ index a2711f6..e49a061 100644
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
|
||||
+ resize_last_update_x = cursor->x;
|
||||
+ resize_last_update_y = cursor->y;
|
||||
+ resizing_from_mouse = 1;
|
||||
+ break;
|
||||
+ }
|
||||
+ } else {
|
||||
@@ -898,6 +890,21 @@ index a2711f6..e49a061 100644
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2833,6 +2923,14 @@ unmapnotify(struct wl_listener *listener, void *data)
|
||||
focusclient(focustop(selmon), 1);
|
||||
}
|
||||
} else {
|
||||
+ /* btrtile remove clients for each monitor */
|
||||
+ Monitor *mon;
|
||||
+ wl_list_for_each(mon, &mons, link) {
|
||||
+ if (mon->root) {
|
||||
+ remove_client(mon, c);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
wl_list_remove(&c->link);
|
||||
setmon(c, NULL, 0);
|
||||
wl_list_remove(&c->flink);
|
||||
--
|
||||
2.45.3
|
||||
2.53.0
|
||||
|
||||
@@ -7,7 +7,7 @@ covering the wallpaper more than necessary.
|
||||
|
||||
### Download
|
||||
- [git branch](https://codeberg.org/guidocella/dwl/src/branch/center-terminal)
|
||||
- [2024-02-06](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/center-terminal/center-terminal.patch)
|
||||
- [2026-02-09](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/center-terminal/center-terminal.patch)
|
||||
|
||||
### Authors
|
||||
- [Guido Cella](https://codeberg.org/guidocella)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
From 340cc5ef90dfcc495bdad045f3f76ae07405cffd Mon Sep 17 00:00:00 2001
|
||||
From 897765216ac8567a40654b813379a4e074ca6298 Mon Sep 17 00:00:00 2001
|
||||
From: Guido Cella <guido@guidocella.xyz>
|
||||
Date: Tue, 6 Feb 2024 09:20:48 +0100
|
||||
Date: Mon, 9 Feb 2026 10:21:33 +0100
|
||||
Subject: [PATCH] add a keybinding to center the terminal
|
||||
|
||||
Add a keybinding that toggles centering the terminally horizontally when
|
||||
@@ -14,19 +14,19 @@ covering the wallpaper more than necessary.
|
||||
2 files changed, 21 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 22d2171..8229fcc 100644
|
||||
index 8a6eda0..8c35c40 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_v, togglecenter, {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} },
|
||||
@@ -138,6 +138,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_v, togglecenter, {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 12f441e..3b15748 100644
|
||||
index 44f3ad9..9ee397a 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -8,6 +8,7 @@
|
||||
@@ -72,7 +72,7 @@ index 12f441e..3b15748 100644
|
||||
c->isfloating |= client_is_float_type(c);
|
||||
setmon(c, mon, newtags);
|
||||
}
|
||||
@@ -2730,6 +2738,11 @@ tile(Monitor *m)
|
||||
@@ -2731,6 +2739,11 @@ tile(Monitor *m)
|
||||
if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||
continue;
|
||||
if (i < m->nmaster) {
|
||||
@@ -84,7 +84,7 @@ index 12f441e..3b15748 100644
|
||||
resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + my, .width = mw,
|
||||
.height = (m->w.height - my) / (MIN(n, m->nmaster) - i)}, 0);
|
||||
my += c->geom.height;
|
||||
@@ -2742,6 +2755,13 @@ tile(Monitor *m)
|
||||
@@ -2743,6 +2756,13 @@ tile(Monitor *m)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,5 +99,5 @@ index 12f441e..3b15748 100644
|
||||
togglefloating(const Arg *arg)
|
||||
{
|
||||
--
|
||||
2.49.0
|
||||
2.52.0
|
||||
|
||||
|
||||
@@ -22,12 +22,16 @@ With one and two clients in master respectively this results in:
|
||||
+------------------------------+ +------------------------------+
|
||||
```
|
||||
|
||||
Version 0.8 includes `centeredmaster_always` setting to always center a window
|
||||
even if only 1 window is visible on a tag.
|
||||
|
||||
### Download
|
||||
- [0.7](/dwl/dwl-patches/raw/branch/main/patches/centeredmaster/centeredmaster.patch)
|
||||
- [0.8](/dwl/dwl-patches/raw/branch/main/patches/centeredmaster/centeredmaster-0.8.patch)
|
||||
- [0.7](/dwl/dwl-patches/raw/branch/main/patches/centeredmaster/centeredmaster-0.7.patch)
|
||||
- [2024-04-11](https://codeberg.org/dwl/dwl-patches/raw/commit/b104a580a80ebaf9f7e8917fe574e3e97ddd019a/centeredmaster/centeredmaster.patch)
|
||||
- [0.5](https://codeberg.org/dwl/dwl-patches/raw/commit/0f4e40fee49d1b8b430778e241b29496ae3b3b70/centeredmaster/centeredmaster.patch)
|
||||
|
||||
### Authors
|
||||
- [Nikita Ivanov](https://codeberg.org/nikitaivanov) ([GitHub](https://github.com/NikitaIvanovV))
|
||||
- [wochap](https://codeberg.org/wochap)
|
||||
- [metalcranium](https://codeberg.org/metalcranium)
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
From d3d0000c3e2baa8c2a4633581186f768c909667a Mon Sep 17 00:00:00 2001
|
||||
From: Nikita Ivanov <nikita.vyach.ivanov@gmail.com>
|
||||
Date: Mon, 13 Apr 2026 18:24:17 +0200
|
||||
Subject: [PATCH] Add centeredmaster layout
|
||||
|
||||
---
|
||||
config.def.h | 3 +++
|
||||
dwl.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 76 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 8a6eda0..15cbe32 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -7,6 +7,7 @@
|
||||
static const int sloppyfocus = 1; /* focus follows mouse */
|
||||
static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */
|
||||
static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
+static const int centeredmaster_always = 0; /* always center even if only 1 window */
|
||||
static const float rootcolor[] = COLOR(0x222222ff);
|
||||
static const float bordercolor[] = COLOR(0x444444ff);
|
||||
static const float focuscolor[] = COLOR(0x005577ff);
|
||||
@@ -33,6 +34,7 @@ static const Layout layouts[] = {
|
||||
{ "[]=", tile },
|
||||
{ "><>", NULL }, /* no layout function means floating behavior */
|
||||
{ "[M]", monocle },
|
||||
+ { "|M|", centeredmaster },
|
||||
};
|
||||
|
||||
/* monitors */
|
||||
@@ -135,6 +137,7 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
|
||||
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
|
||||
+ { MODKEY, XKB_KEY_c, setlayout, {.v = &layouts[3]} },
|
||||
{ MODKEY, XKB_KEY_space, setlayout, {0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
|
||||
{ MODKEY, XKB_KEY_e, togglefullscreen, {0} },
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 44f3ad9..98ba318 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -248,6 +248,7 @@ static void arrangelayer(Monitor *m, struct wl_list *list,
|
||||
static void arrangelayers(Monitor *m);
|
||||
static void axisnotify(struct wl_listener *listener, void *data);
|
||||
static void buttonpress(struct wl_listener *listener, void *data);
|
||||
+static void centeredmaster(Monitor *m);
|
||||
static void chvt(const Arg *arg);
|
||||
static void checkidleinhibitor(struct wlr_surface *exclude);
|
||||
static void cleanup(void);
|
||||
@@ -672,6 +673,78 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
event->time_msec, event->button, event->state);
|
||||
}
|
||||
|
||||
+void
|
||||
+centeredmaster(Monitor *m)
|
||||
+{
|
||||
+ int i, n, h, mw, mx, my, oty, ety, tw;
|
||||
+ Client *c;
|
||||
+
|
||||
+ n = 0;
|
||||
+ wl_list_for_each(c, &clients, link)
|
||||
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen)
|
||||
+ n++;
|
||||
+ if (n == 0)
|
||||
+ return;
|
||||
+
|
||||
+ /* initialize areas */
|
||||
+ if (centeredmaster_always) {
|
||||
+ mw = m->w.width / 2;
|
||||
+ mx = m->w.width / 4;
|
||||
+ } else {
|
||||
+ mw = m->w.width;
|
||||
+ mx = 0;
|
||||
+ }
|
||||
+ my = 0;
|
||||
+ tw = mw;
|
||||
+
|
||||
+ if (n > m->nmaster) {
|
||||
+ /* go mfact box in the center if more than nmaster clients */
|
||||
+ if (centeredmaster_always) {
|
||||
+ mw = m->nmaster ? (int)roundf(m->w.width / 2) : 0;
|
||||
+ tw = mw / 2;
|
||||
+ } else {
|
||||
+ mw = m->nmaster ? (int)roundf(m->w.width * m->mfact) : 0;
|
||||
+ tw = m->w.width - mw;
|
||||
+ }
|
||||
+
|
||||
+ if (n - m->nmaster > 1) {
|
||||
+ /* only one client */
|
||||
+ mx = (m->w.width - mw) / 2;
|
||||
+ tw = (m->w.width - mw) / 2;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ i = 0;
|
||||
+ oty = 0;
|
||||
+ ety = 0;
|
||||
+ wl_list_for_each(c, &clients, link) {
|
||||
+ if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||
+ continue;
|
||||
+ if (i < m->nmaster) {
|
||||
+ /* nmaster clients are stacked vertically, in the center
|
||||
+ * of the screen */
|
||||
+ h = (m->w.height - my) / (MIN(n, m->nmaster) - i);
|
||||
+ resize(c, (struct wlr_box){.x = m->w.x + mx, .y = m->w.y + my, .width = mw,
|
||||
+ .height = h}, 0);
|
||||
+ my += c->geom.height;
|
||||
+ } else {
|
||||
+ /* stack clients are stacked vertically */
|
||||
+ if ((i - m->nmaster) % 2) {
|
||||
+ h = (m->w.height - ety) / ( (1 + n - i) / 2);
|
||||
+ resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + ety, .width = tw,
|
||||
+ .height = h}, 0);
|
||||
+ ety += c->geom.height;
|
||||
+ } else {
|
||||
+ h = (m->w.height - oty) / ((1 + n - i) / 2);
|
||||
+ resize(c, (struct wlr_box){.x = m->w.x + mx + mw, .y = m->w.y + oty, .width = tw,
|
||||
+ .height = h}, 0);
|
||||
+ oty += c->geom.height;
|
||||
+ }
|
||||
+ }
|
||||
+ i++;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
chvt(const Arg *arg)
|
||||
{
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
### Description
|
||||
This patch is based on the
|
||||
[client-opacity](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/client-opacity/client-opacity.patch)
|
||||
patch. This patch adds differing opacity levels depending upon whether the client is focused or not.
|
||||
|
||||
The opacity levels can be change by short cuts.
|
||||
|
||||
```
|
||||
[MODKEY]+[Ctrl]+[k] -> increase focus opacity unfocused client
|
||||
[MODKEY]+[Ctrl]+[j] -> decrease focus opacity unfocused client
|
||||
[MODKEY]+[Ctrl]+[Shift]+[k] -> increase focus opacity focused client
|
||||
[MODKEY]+[Ctrl]+[Shift]+[j] -> decrease focus opacity focused client
|
||||
```
|
||||
|
||||
### Download
|
||||
- [git branch](https://codeberg.org/Hansvon/dwl/src/branch/client-opacity-focus)
|
||||
- [2026-04-27](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/client-opacity-focus/client-opacity-focus.patch)
|
||||
|
||||
### Authors
|
||||
- [Hansvon](https://codeberg.org/Hansvon)
|
||||
@@ -0,0 +1,204 @@
|
||||
From 57c5475d7f715b77ec05d69a2bda808b224cf0b4 Mon Sep 17 00:00:00 2001
|
||||
From: Hans von Hohenstaufen <Hans.von.Hohenstaufen@protonmail.com>
|
||||
Date: Mon, 22 Dec 2025 01:43:50 +0000
|
||||
Subject: [PATCH] Add client opacity focus
|
||||
|
||||
---
|
||||
config.def.h | 12 +++++++---
|
||||
dwl.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 74 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 95c2afa..55abf84 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -13,6 +13,8 @@ static const float focuscolor[] = COLOR(0x005577ff);
|
||||
static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
||||
static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */
|
||||
+static const float default_opacity_unfocus = 0.70f;
|
||||
+static const float default_opacity_focus = 1.00f;
|
||||
|
||||
/* tagging - TAGCOUNT must be no greater than 31 */
|
||||
#define TAGCOUNT (9)
|
||||
@@ -22,10 +24,10 @@ static int log_level = WLR_ERROR;
|
||||
|
||||
/* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g leave at least one example) */
|
||||
static const Rule rules[] = {
|
||||
- /* app_id title tags mask isfloating monitor */
|
||||
+ /* app_id title tags mask isfloating alpha focus alpha unfocus monitor */
|
||||
/* examples: */
|
||||
- { "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" */
|
||||
+ { "Gimp_EXAMPLE", NULL, 0, 1, 1.00, 0.20, -1 }, /* Start on currently visible tags floating, not tiled */
|
||||
+ { "firefox_EXAMPLE", NULL, 1 << 8, 0, 1.00, 1.00, -1 }, /* Start on ONLY tag "9" */
|
||||
};
|
||||
|
||||
/* layout(s) */
|
||||
@@ -139,6 +141,10 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
|
||||
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_k, setopacityunfocus, {.f = +0.1f} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_j, setopacityunfocus, {.f = -0.1f} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT, XKB_KEY_K, setopacityfocus, {.f = +0.1f} },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT, XKB_KEY_J, setopacityfocus, {.f = -0.1f} },
|
||||
{ MODKEY, XKB_KEY_space, setlayout, {0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
|
||||
{ MODKEY, XKB_KEY_e, togglefullscreen, {0} },
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 12f441e..e45e420 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -138,6 +138,9 @@ typedef struct {
|
||||
unsigned int bw;
|
||||
uint32_t tags;
|
||||
int isfloating, isurgent, isfullscreen;
|
||||
+ float opacity;
|
||||
+ float opacity_focus;
|
||||
+ float opacity_unfocus;
|
||||
uint32_t resize; /* configure serial of a pending resize */
|
||||
} Client;
|
||||
|
||||
@@ -227,6 +230,8 @@ typedef struct {
|
||||
const char *title;
|
||||
uint32_t tags;
|
||||
int isfloating;
|
||||
+ float opacity_focus;
|
||||
+ float opacity_unfocus;
|
||||
int monitor;
|
||||
} Rule;
|
||||
|
||||
@@ -319,6 +324,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 scenebuffersetopacity(struct wlr_scene_buffer *buffer, int sx, int sy, void *user_data);
|
||||
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);
|
||||
@@ -326,6 +332,8 @@ static void setfullscreen(Client *c, int fullscreen);
|
||||
static void setlayout(const Arg *arg);
|
||||
static void setmfact(const Arg *arg);
|
||||
static void setmon(Client *c, Monitor *m, uint32_t newtags);
|
||||
+static void setopacityunfocus(const Arg *arg);
|
||||
+static void setopacityfocus(const Arg *arg);
|
||||
static void setpsel(struct wl_listener *listener, void *data);
|
||||
static void setsel(struct wl_listener *listener, void *data);
|
||||
static void setup(void);
|
||||
@@ -490,6 +498,8 @@ applyrules(Client *c)
|
||||
if ((!r->title || strstr(title, r->title))
|
||||
&& (!r->id || strstr(appid, r->id))) {
|
||||
c->isfloating = r->isfloating;
|
||||
+ c->opacity_unfocus = r->opacity_unfocus;
|
||||
+ c->opacity_focus = r->opacity_focus;
|
||||
newtags |= r->tags;
|
||||
i = 0;
|
||||
wl_list_for_each(m, &mons, link) {
|
||||
@@ -1127,6 +1137,10 @@ createnotify(struct wl_listener *listener, void *data)
|
||||
c = toplevel->base->data = ecalloc(1, sizeof(*c));
|
||||
c->surface.xdg = toplevel->base;
|
||||
c->bw = borderpx;
|
||||
+ /* Set default opacity*/
|
||||
+ c->opacity_unfocus = default_opacity_unfocus;
|
||||
+ c->opacity_focus = default_opacity_focus;
|
||||
+ c->opacity = default_opacity_unfocus;
|
||||
|
||||
LISTEN(&toplevel->base->surface->events.commit, &c->commit, commitnotify);
|
||||
LISTEN(&toplevel->base->surface->events.map, &c->map, mapnotify);
|
||||
@@ -1429,6 +1443,7 @@ focusclient(Client *c, int lift)
|
||||
wl_list_insert(&fstack, &c->flink);
|
||||
selmon = c->mon;
|
||||
c->isurgent = 0;
|
||||
+ c->opacity = c->opacity_focus;
|
||||
|
||||
/* Don't change border color if there is an exclusive focus or we are
|
||||
* handling a drag operation */
|
||||
@@ -1453,6 +1468,7 @@ focusclient(Client *c, int lift)
|
||||
client_set_border_color(old_c, bordercolor);
|
||||
|
||||
client_activate_surface(old, 0);
|
||||
+ old_c->opacity = old_c->opacity_unfocus;
|
||||
}
|
||||
}
|
||||
printstatus();
|
||||
@@ -2159,6 +2175,7 @@ rendermon(struct wl_listener *listener, void *data)
|
||||
/* Render if no XDG clients have an outstanding resize and are visible on
|
||||
* this monitor. */
|
||||
wl_list_for_each(c, &clients, link) {
|
||||
+ wlr_scene_node_for_each_buffer(&c->scene_surface->node, scenebuffersetopacity, c);
|
||||
if (c->resize && !c->isfloating && client_is_rendered_on_mon(c, m) && !client_is_stopped(c))
|
||||
goto skip;
|
||||
}
|
||||
@@ -2295,6 +2312,15 @@ run(char *startup_cmd)
|
||||
wl_display_run(dpy);
|
||||
}
|
||||
|
||||
+void
|
||||
+scenebuffersetopacity(struct wlr_scene_buffer *buffer, int sx, int sy, void *data)
|
||||
+{
|
||||
+ Client *c = data;
|
||||
+ /* xdg-popups are children of Client.scene, we do not have to worry about
|
||||
+ * messing with them. */
|
||||
+ wlr_scene_buffer_set_opacity(buffer, c->isfullscreen ? 1 : c->opacity);
|
||||
+}
|
||||
+
|
||||
void
|
||||
setcursor(struct wl_listener *listener, void *data)
|
||||
{
|
||||
@@ -2363,6 +2389,7 @@ setfullscreen(Client *c, int fullscreen)
|
||||
* client positions are set by the user and cannot be recalculated */
|
||||
resize(c, c->prev, 0);
|
||||
}
|
||||
+ wlr_scene_node_for_each_buffer(&c->scene_surface->node, scenebuffersetopacity, c);
|
||||
arrange(c->mon);
|
||||
printstatus();
|
||||
}
|
||||
@@ -2419,6 +2446,44 @@ setmon(Client *c, Monitor *m, uint32_t newtags)
|
||||
focusclient(focustop(selmon), 1);
|
||||
}
|
||||
|
||||
+
|
||||
+void
|
||||
+setopacityunfocus(const Arg *arg)
|
||||
+{
|
||||
+ Client *sel = focustop(selmon);
|
||||
+ if (!sel)
|
||||
+ return;
|
||||
+
|
||||
+ sel->opacity_unfocus += arg->f;
|
||||
+ if (sel->opacity_unfocus > 1.0)
|
||||
+ sel->opacity_unfocus = 1.0f;
|
||||
+
|
||||
+ if (sel->opacity_unfocus < 0.1)
|
||||
+ sel->opacity_unfocus = 0.1f;
|
||||
+
|
||||
+ wlr_scene_node_for_each_buffer(&sel->scene_surface->node, scenebuffersetopacity, sel);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+setopacityfocus(const Arg *arg)
|
||||
+{
|
||||
+ Client *sel = focustop(selmon);
|
||||
+ if (!sel)
|
||||
+ return;
|
||||
+
|
||||
+ sel->opacity_focus += arg->f;
|
||||
+ if (sel->opacity_focus > 1.0)
|
||||
+ sel->opacity_focus = 1.0f;
|
||||
+
|
||||
+ if (sel->opacity_focus < 0.1)
|
||||
+ sel->opacity_focus = 0.1f;
|
||||
+
|
||||
+ /* Change opacity from current client */
|
||||
+ sel->opacity = sel->opacity_focus;
|
||||
+
|
||||
+ wlr_scene_node_for_each_buffer(&sel->scene_surface->node, scenebuffersetopacity, sel);
|
||||
+}
|
||||
+
|
||||
void
|
||||
setpsel(struct wl_listener *listener, void *data)
|
||||
{
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@@ -7,21 +7,22 @@ Subject: [PATCH] add default transparency for windows and rules for override
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Signed-off-by: Leonardo Hernández Hernández <leohdz172@proton.me>
|
||||
Modified-by: Yuki <yukii.senp@gmail.com>
|
||||
|
||||
---
|
||||
config.def.h | 9 ++++++---
|
||||
dwl.c | 39 +++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 45 insertions(+), 3 deletions(-)
|
||||
dwl.c | 36 ++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 42 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 22d2171d..0eb86874 100644
|
||||
index 95c2afa..808242a 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -13,6 +13,7 @@ static const float focuscolor[] = COLOR(0x005577ff);
|
||||
static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
||||
static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You can also use glsl colors */
|
||||
static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */
|
||||
+static const float default_opacity = 0.75;
|
||||
|
||||
/* tagging - TAGCOUNT must be no greater than 31 */
|
||||
@@ -50,7 +51,7 @@ index 22d2171d..0eb86874 100644
|
||||
{ MODKEY, XKB_KEY_Tab, view, {0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_C, killclient, {0} },
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index ad21e1ba..0554fcdf 100644
|
||||
index 12f441e..f547148 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -138,6 +138,7 @@ typedef struct {
|
||||
@@ -85,7 +86,7 @@ index ad21e1ba..0554fcdf 100644
|
||||
static void setpsel(struct wl_listener *listener, void *data);
|
||||
static void setsel(struct wl_listener *listener, void *data);
|
||||
static void setup(void);
|
||||
@@ -491,6 +495,7 @@ applyrules(Client *c)
|
||||
@@ -490,6 +494,7 @@ applyrules(Client *c)
|
||||
if ((!r->title || strstr(title, r->title))
|
||||
&& (!r->id || strstr(appid, r->id))) {
|
||||
c->isfloating = r->isfloating;
|
||||
@@ -93,26 +94,7 @@ index ad21e1ba..0554fcdf 100644
|
||||
newtags |= r->tags;
|
||||
i = 0;
|
||||
wl_list_for_each(m, &mons, link) {
|
||||
@@ -499,6 +504,8 @@ applyrules(Client *c)
|
||||
}
|
||||
}
|
||||
}
|
||||
+ if (c->scene_surface)
|
||||
+ wlr_scene_node_for_each_buffer(&c->scene_surface->node, scenebuffersetopacity, c);
|
||||
setmon(c, mon, newtags);
|
||||
}
|
||||
|
||||
@@ -874,6 +881,9 @@ commitnotify(struct wl_listener *listener, void *data)
|
||||
|
||||
resize(c, c->geom, (c->isfloating && !c->isfullscreen));
|
||||
|
||||
+ if (c->scene_surface)
|
||||
+ wlr_scene_node_for_each_buffer(&c->scene_surface->node, scenebuffersetopacity, c);
|
||||
+
|
||||
/* mark a pending resize as completed */
|
||||
if (c->resize && c->resize <= c->surface.xdg->current.configure_serial)
|
||||
c->resize = 0;
|
||||
@@ -1120,6 +1130,7 @@ createnotify(struct wl_listener *listener, void *data)
|
||||
@@ -1127,6 +1132,7 @@ createnotify(struct wl_listener *listener, void *data)
|
||||
c = toplevel->base->data = ecalloc(1, sizeof(*c));
|
||||
c->surface.xdg = toplevel->base;
|
||||
c->bw = borderpx;
|
||||
@@ -120,7 +102,16 @@ index ad21e1ba..0554fcdf 100644
|
||||
|
||||
LISTEN(&toplevel->base->surface->events.commit, &c->commit, commitnotify);
|
||||
LISTEN(&toplevel->base->surface->events.map, &c->map, mapnotify);
|
||||
@@ -2285,6 +2296,15 @@ run(char *startup_cmd)
|
||||
@@ -2159,6 +2165,8 @@ rendermon(struct wl_listener *listener, void *data)
|
||||
/* Render if no XDG clients have an outstanding resize and are visible on
|
||||
* this monitor. */
|
||||
wl_list_for_each(c, &clients, link) {
|
||||
+ wlr_scene_node_for_each_buffer(&c->scene_surface->node, scenebuffersetopacity, c);
|
||||
+
|
||||
if (c->resize && !c->isfloating && client_is_rendered_on_mon(c, m) && !client_is_stopped(c))
|
||||
goto skip;
|
||||
}
|
||||
@@ -2295,6 +2303,15 @@ run(char *startup_cmd)
|
||||
wl_display_run(dpy);
|
||||
}
|
||||
|
||||
@@ -136,7 +127,7 @@ index ad21e1ba..0554fcdf 100644
|
||||
void
|
||||
setcursor(struct wl_listener *listener, void *data)
|
||||
{
|
||||
@@ -2353,6 +2373,7 @@ setfullscreen(Client *c, int fullscreen)
|
||||
@@ -2363,6 +2380,7 @@ setfullscreen(Client *c, int fullscreen)
|
||||
* client positions are set by the user and cannot be recalculated */
|
||||
resize(c, c->prev, 0);
|
||||
}
|
||||
@@ -144,7 +135,7 @@ index ad21e1ba..0554fcdf 100644
|
||||
arrange(c->mon);
|
||||
printstatus();
|
||||
}
|
||||
@@ -2409,6 +2430,23 @@ setmon(Client *c, Monitor *m, uint32_t newtags)
|
||||
@@ -2419,6 +2437,23 @@ setmon(Client *c, Monitor *m, uint32_t newtags)
|
||||
focusclient(focustop(selmon), 1);
|
||||
}
|
||||
|
||||
@@ -168,7 +159,7 @@ index ad21e1ba..0554fcdf 100644
|
||||
void
|
||||
setpsel(struct wl_listener *listener, void *data)
|
||||
{
|
||||
@@ -3120,6 +3158,7 @@ createnotifyx11(struct wl_listener *listener, void *data)
|
||||
@@ -3130,6 +3165,7 @@ createnotifyx11(struct wl_listener *listener, void *data)
|
||||
c->surface.xwayland = xsurface;
|
||||
c->type = X11;
|
||||
c->bw = client_is_unmanaged(c) ? 0 : borderpx;
|
||||
@@ -177,5 +168,5 @@ index ad21e1ba..0554fcdf 100644
|
||||
/* Listen to the various events it can emit */
|
||||
LISTEN(&xsurface->events.associate, &c->associate, associatex11);
|
||||
--
|
||||
2.48.0
|
||||
2.51.0
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
### Description
|
||||
Adds simple support for color management using `wp_color_manager_v1`.
|
||||
|
||||
### Download
|
||||
- [git branch](/caskd/dwl/src/branch/patches/color-management)
|
||||
- [main 2025-06-18](/dwl/dwl-patches/raw/branch/main/patches/color_manager/color_manager.patch)
|
||||
### Authors
|
||||
- [caskd](https://codeberg.org/caskd)
|
||||
caskd@redxen.eu
|
||||
caskd at [Libera IRC dwl channel](https://web.libera.chat/?channels=#dwl)
|
||||
@@ -0,0 +1,178 @@
|
||||
From 54ad3a9005a127a957bf081b0be765dcaff18c5d Mon Sep 17 00:00:00 2001
|
||||
From: Alex Denes <caskd@redxen.eu>
|
||||
Date: Thu, 10 Jul 2025 12:01:29 +0000
|
||||
Subject: [PATCH] Implement color manager
|
||||
|
||||
---
|
||||
Makefile | 9 ++++++++-
|
||||
config.def.h | 24 ++++++++++++++++++++----
|
||||
dwl.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 79 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/Makefile b/Makefile
|
||||
index 3981fbb..190f29c 100644
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -22,7 +22,8 @@ dwl: dwl.o util.o
|
||||
dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h \
|
||||
ext-image-copy-capture-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
|
||||
+ wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h \
|
||||
+ color-management-v1-protocol.h color-representation-v1-protocol.h
|
||||
util.o: util.c util.h
|
||||
|
||||
# wayland-scanner is a tool which generates C headers and rigging for Wayland
|
||||
@@ -43,6 +44,12 @@ pointer-constraints-unstable-v1-protocol.h:
|
||||
wlr-layer-shell-unstable-v1-protocol.h:
|
||||
$(WAYLAND_SCANNER) enum-header \
|
||||
protocols/wlr-layer-shell-unstable-v1.xml $@
|
||||
+color-management-v1-protocol.h:
|
||||
+ $(WAYLAND_SCANNER) enum-header \
|
||||
+ $(WAYLAND_PROTOCOLS)/staging/color-management/color-management-v1.xml $@
|
||||
+color-representation-v1-protocol.h:
|
||||
+ $(WAYLAND_SCANNER) enum-header \
|
||||
+ $(WAYLAND_PROTOCOLS)/staging/color-representation/color-representation-v1.xml $@
|
||||
wlr-output-power-management-unstable-v1-protocol.h:
|
||||
$(WAYLAND_SCANNER) server-header \
|
||||
protocols/wlr-output-power-management-unstable-v1.xml $@
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 8a6eda0..d203edc 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -35,15 +35,31 @@ static const Layout layouts[] = {
|
||||
{ "[M]", monocle },
|
||||
};
|
||||
|
||||
+
|
||||
+/*
|
||||
+static struct wlr_output_image_description generic_bt2020_pq = {
|
||||
+ .primaries = WLR_COLOR_NAMED_PRIMARIES_BT2020,
|
||||
+ .transfer_function = WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ,
|
||||
+ .max_cll = 10000,
|
||||
+ .max_fall = 400,
|
||||
+ .mastering_luminance = {
|
||||
+ .min = 0,
|
||||
+ .max = 10000,
|
||||
+ },
|
||||
+};
|
||||
+*/
|
||||
+
|
||||
/* monitors */
|
||||
/* (x=-1, y=-1) is reserved as an "autoconfigure" monitor position indicator
|
||||
* WARNING: negative values other than (-1, -1) cause problems with Xwayland clients due to
|
||||
* https://gitlab.freedesktop.org/xorg/xserver/-/issues/899 */
|
||||
static const MonitorRule monrules[] = {
|
||||
- /* name mfact nmaster scale layout rotate/reflect x y
|
||||
- * example of a HiDPI laptop monitor:
|
||||
- { "eDP-1", 0.5f, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, */
|
||||
- { NULL, 0.55f, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 },
|
||||
+ /* name mfact nmaster scale layout rotate/reflect x y image_desc pixel_format
|
||||
+ * example of a HiDPI laptop monitor:
|
||||
+ { "eDP-1", 0.5f, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1, NULL, DRM_FORMAT_XRGB8888 },
|
||||
+ * HDR Example
|
||||
+ { NULL, 0.5f, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1, &generic_bt2020_pq, DRM_FORMAT_XRGB2101010 }, */
|
||||
+ { NULL, 0.55f, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1, NULL, DRM_FORMAT_XRGB8888 },
|
||||
/* default monitor rule: can be changed but cannot be eliminated; at least one monitor rule must exist */
|
||||
};
|
||||
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 8101ffa..4c3f12a 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <getopt.h>
|
||||
#include <libinput.h>
|
||||
#include <linux/input-event-codes.h>
|
||||
+#include <drm_fourcc.h>
|
||||
#include <math.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
@@ -18,6 +19,8 @@
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_alpha_modifier_v1.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
+#include <wlr/types/wlr_color_management_v1.h>
|
||||
+#include <wlr/types/wlr_color_representation_v1.h>
|
||||
#include <wlr/types/wlr_cursor.h>
|
||||
#include <wlr/types/wlr_cursor_shape_v1.h>
|
||||
#include <wlr/types/wlr_data_control_v1.h>
|
||||
@@ -219,6 +222,9 @@ typedef struct {
|
||||
const Layout *lt;
|
||||
enum wl_output_transform rr;
|
||||
int x, y;
|
||||
+
|
||||
+ struct wlr_output_image_description *image_desc;
|
||||
+ uint32_t render_format;
|
||||
} MonitorRule;
|
||||
|
||||
typedef struct {
|
||||
@@ -386,6 +392,7 @@ static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr;
|
||||
static struct wlr_virtual_pointer_manager_v1 *virtual_pointer_mgr;
|
||||
static struct wlr_cursor_shape_manager_v1 *cursor_shape_mgr;
|
||||
static struct wlr_output_power_manager_v1 *power_mgr;
|
||||
+static struct wlr_color_manager_v1 *color_mgr;
|
||||
|
||||
static struct wlr_pointer_constraints_v1 *pointer_constraints;
|
||||
static struct wlr_relative_pointer_manager_v1 *relative_pointer_mgr;
|
||||
@@ -1088,6 +1095,20 @@ createmon(struct wl_listener *listener, void *data)
|
||||
LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon);
|
||||
LISTEN(&wlr_output->events.request_state, &m->request_state, requestmonstate);
|
||||
|
||||
+ /* Enable HDR if supported and desired */
|
||||
+ if ((r->image_desc) && (drw->features.output_color_transform) &&
|
||||
+ (wlr_output->supported_primaries & r->image_desc->primaries) &&
|
||||
+ (wlr_output->supported_transfer_functions & r->image_desc->transfer_function)) {
|
||||
+ // Set framebuffer pixel format to one requested
|
||||
+ wlr_output_state_set_render_format(&state, r->render_format);
|
||||
+ // Check if unset and use default well-known primaries (white point will never be 0.0 if set)
|
||||
+ struct wlr_color_primaries *prim = &r->image_desc->mastering_display_primaries;
|
||||
+ if (prim->white.x == 0.0 && prim->white.y == 0.0) {
|
||||
+ wlr_color_primaries_from_named (&r->image_desc->mastering_display_primaries, r->image_desc->primaries);
|
||||
+ }
|
||||
+ wlr_output_state_set_image_description(&state, r->image_desc);
|
||||
+ }
|
||||
+
|
||||
wlr_output_state_set_enabled(&state, 1);
|
||||
wlr_output_commit_state(wlr_output, &state);
|
||||
wlr_output_state_finish(&state);
|
||||
@@ -2653,6 +2674,36 @@ setup(void)
|
||||
wl_signal_add(&output_mgr->events.apply, &output_mgr_apply);
|
||||
wl_signal_add(&output_mgr->events.test, &output_mgr_test);
|
||||
|
||||
+ if (drw->features.input_color_transform) {
|
||||
+ struct wlr_color_manager_v1_options *color_mgr_options;
|
||||
+ color_mgr_options = ecalloc(1, sizeof(*color_mgr_options));
|
||||
+
|
||||
+ // Enable only supported wlroots features
|
||||
+ color_mgr_options->features = (struct wlr_color_manager_v1_features){
|
||||
+ .parametric = true,
|
||||
+ .set_mastering_display_primaries = true,
|
||||
+ };
|
||||
+
|
||||
+ color_mgr_options->render_intents_len = 1;
|
||||
+ enum wp_color_manager_v1_render_intent *render_intents = ecalloc(color_mgr_options->render_intents_len, sizeof(*render_intents));
|
||||
+ render_intents[0] = WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL;
|
||||
+ color_mgr_options->render_intents = render_intents;
|
||||
+
|
||||
+ enum wp_color_manager_v1_primaries *primaries = wlr_color_manager_v1_primaries_list_from_renderer(drw, &color_mgr_options->primaries_len);
|
||||
+ color_mgr_options->primaries = primaries;
|
||||
+
|
||||
+ enum wp_color_manager_v1_transfer_function *transfer_functions = wlr_color_manager_v1_transfer_function_list_from_renderer(drw, &color_mgr_options->transfer_functions_len);
|
||||
+ color_mgr_options->transfer_functions = transfer_functions;
|
||||
+
|
||||
+ color_mgr = wlr_color_manager_v1_create(dpy, 2, color_mgr_options);
|
||||
+ wlr_scene_set_color_manager_v1(scene, color_mgr);
|
||||
+
|
||||
+ wlr_color_representation_manager_v1_create_with_renderer(dpy, 1, drw);
|
||||
+
|
||||
+ free(transfer_functions);
|
||||
+ free(primaries);
|
||||
+ }
|
||||
+
|
||||
/* Make sure XWayland clients don't connect to the parent X server,
|
||||
* e.g when running in the x11 backend or the wayland backend and the
|
||||
* compositor has Xwayland support */
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
### Description
|
||||
This patch allows a window to adjust its layout as if it was fullscreen, but it won't change its size and position, and it will stays under the control of dwl. For example a video on a browser can occupy the whole space reserved to the window, but we can still resize it and move it and see the status bar.
|
||||
|
||||
### Download
|
||||
- [dwl 0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/controlled_fullscreen/controlled_fullscreen.patch)
|
||||
- [2025-11-13](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/controlled_fullscreen/controlled_fullscreen_2025_11_13.patch)
|
||||
|
||||
- [2025-10-08](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/controlled_fullscreen/controlled_fullscreen_2025_10_08.patch)
|
||||
|
||||
### Authors
|
||||
- [André Desgualdo Pereira](https://codeberg.org/Kana)
|
||||
@@ -0,0 +1,132 @@
|
||||
From 9d34e55528ef3e558dcaba7759567707d44ed82d Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Andr=C3=A9=20Desgualdo=20Pereira?= <desgua@gmail.com>
|
||||
Date: Mon, 4 May 2026 10:49:48 -0300
|
||||
Subject: [PATCH] update controlled_fullscreen to dwl 0.8
|
||||
|
||||
---
|
||||
dwl.c | 32 ++++++++++++--------------------
|
||||
1 file changed, 12 insertions(+), 20 deletions(-)
|
||||
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 101a45f..0ec8db6 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -519,9 +519,6 @@ arrange(Monitor *m)
|
||||
}
|
||||
}
|
||||
|
||||
- wlr_scene_node_set_enabled(&m->fullscreen_bg->node,
|
||||
- (c = focustop(m)) && c->isfullscreen);
|
||||
-
|
||||
strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol));
|
||||
|
||||
/* We move all clients (except fullscreen and unmanaged) to LyrTile while
|
||||
@@ -879,7 +876,7 @@ commitnotify(struct wl_listener *listener, void *data)
|
||||
return;
|
||||
}
|
||||
|
||||
- resize(c, c->geom, (c->isfloating && !c->isfullscreen));
|
||||
+ resize(c, c->geom, (c->isfloating));
|
||||
|
||||
/* mark a pending resize as completed */
|
||||
if (c->resize && c->resize <= c->surface.xdg->current.configure_serial)
|
||||
@@ -1491,7 +1488,7 @@ focusstack(const Arg *arg)
|
||||
{
|
||||
/* Focus the next or previous client (in tiling order) on selmon */
|
||||
Client *c, *sel = focustop(selmon);
|
||||
- if (!sel || (sel->isfullscreen && !client_has_children(sel)))
|
||||
+ if (!sel)
|
||||
return;
|
||||
if (arg->i > 0) {
|
||||
wl_list_for_each(c, &sel->link, link) {
|
||||
@@ -1828,7 +1825,7 @@ monocle(Monitor *m)
|
||||
int n = 0;
|
||||
|
||||
wl_list_for_each(c, &clients, link) {
|
||||
- if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||
+ if (!VISIBLEON(c, m) || c->isfloating)
|
||||
continue;
|
||||
resize(c, m->w, 0);
|
||||
n++;
|
||||
@@ -1959,7 +1956,7 @@ moveresize(const Arg *arg)
|
||||
if (cursor_mode != CurNormal && cursor_mode != CurPressed)
|
||||
return;
|
||||
xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL);
|
||||
- if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
|
||||
+ if (!grabc || client_is_unmanaged(grabc))
|
||||
return;
|
||||
|
||||
/* Float the window and tell motionnotify to grab it */
|
||||
@@ -2334,14 +2331,12 @@ setcursorshape(struct wl_listener *listener, void *data)
|
||||
void
|
||||
setfloating(Client *c, int floating)
|
||||
{
|
||||
- Client *p = client_get_parent(c);
|
||||
c->isfloating = floating;
|
||||
/* If in floating layout do not change the client's layer */
|
||||
if (!c->mon || !client_surface(c)->mapped || !c->mon->lt[c->mon->sellt]->arrange)
|
||||
return;
|
||||
- wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen ||
|
||||
- (p && p->isfullscreen) ? LyrFS
|
||||
- : c->isfloating ? LyrFloat : LyrTile]);
|
||||
+ wlr_scene_node_reparent(&c->scene->node,
|
||||
+ layers[c->isfloating ? LyrFloat : LyrTile]);
|
||||
arrange(c->mon);
|
||||
printstatus();
|
||||
}
|
||||
@@ -2354,12 +2349,12 @@ setfullscreen(Client *c, int fullscreen)
|
||||
return;
|
||||
c->bw = fullscreen ? 0 : borderpx;
|
||||
client_set_fullscreen(c, fullscreen);
|
||||
- wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen
|
||||
- ? LyrFS : c->isfloating ? LyrFloat : LyrTile]);
|
||||
|
||||
+ wlr_scene_node_reparent(&c->scene->node,
|
||||
+ layers[c->isfloating ? LyrFloat : LyrTile]);
|
||||
if (fullscreen) {
|
||||
c->prev = c->geom;
|
||||
- resize(c, c->mon->m, 0);
|
||||
+ resize(c, c->mon->w, 0);
|
||||
} else {
|
||||
/* restore previous size instead of arrange for floating windows since
|
||||
* client positions are set by the user and cannot be recalculated */
|
||||
@@ -2719,7 +2714,7 @@ tile(Monitor *m)
|
||||
Client *c;
|
||||
|
||||
wl_list_for_each(c, &clients, link)
|
||||
- if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen)
|
||||
+ if (VISIBLEON(c, m) && !c->isfloating)
|
||||
n++;
|
||||
if (n == 0)
|
||||
return;
|
||||
@@ -2730,7 +2725,7 @@ tile(Monitor *m)
|
||||
mw = m->w.width;
|
||||
i = my = ty = 0;
|
||||
wl_list_for_each(c, &clients, link) {
|
||||
- if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||
+ if (!VISIBLEON(c, m) || c->isfloating)
|
||||
continue;
|
||||
if (i < m->nmaster) {
|
||||
resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + my, .width = mw,
|
||||
@@ -2750,7 +2745,7 @@ togglefloating(const Arg *arg)
|
||||
{
|
||||
Client *sel = focustop(selmon);
|
||||
/* return if fullscreen */
|
||||
- if (sel && !sel->isfullscreen)
|
||||
+ if (sel)
|
||||
setfloating(sel, !sel->isfloating);
|
||||
}
|
||||
|
||||
@@ -2905,9 +2900,6 @@ updatemons(struct wl_listener *listener, void *data)
|
||||
arrangelayers(m);
|
||||
/* Don't move clients to the left output when plugging monitors */
|
||||
arrange(m);
|
||||
- /* make sure fullscreen clients have the right size */
|
||||
- if ((c = focustop(m)) && c->isfullscreen)
|
||||
- resize(c, m->m, 0);
|
||||
|
||||
/* Try to re-set the gamma LUT when updating monitors,
|
||||
* it's only really needed when enabling a disabled output, but meh. */
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
From 33e9b8a227b63e344407c1e4d137b574483cbd1e Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Andr=C3=A9=20Desgualdo=20Pereira?= <desgua@gmail.com>
|
||||
Date: Wed, 8 Oct 2025 17:38:00 -0300
|
||||
Subject: [PATCH] controlled fullscreen
|
||||
|
||||
---
|
||||
dwl.c | 33 ++++++++++++---------------------
|
||||
1 file changed, 12 insertions(+), 21 deletions(-)
|
||||
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 12f441e..c74380d 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -518,9 +518,6 @@ arrange(Monitor *m)
|
||||
}
|
||||
}
|
||||
|
||||
- wlr_scene_node_set_enabled(&m->fullscreen_bg->node,
|
||||
- (c = focustop(m)) && c->isfullscreen);
|
||||
-
|
||||
strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol));
|
||||
|
||||
/* We move all clients (except fullscreen and unmanaged) to LyrTile while
|
||||
@@ -878,7 +875,7 @@ commitnotify(struct wl_listener *listener, void *data)
|
||||
return;
|
||||
}
|
||||
|
||||
- resize(c, c->geom, (c->isfloating && !c->isfullscreen));
|
||||
+ resize(c, c->geom, (c->isfloating));
|
||||
|
||||
/* mark a pending resize as completed */
|
||||
if (c->resize && c->resize <= c->surface.xdg->current.configure_serial)
|
||||
@@ -1490,7 +1487,7 @@ focusstack(const Arg *arg)
|
||||
{
|
||||
/* Focus the next or previous client (in tiling order) on selmon */
|
||||
Client *c, *sel = focustop(selmon);
|
||||
- if (!sel || (sel->isfullscreen && !client_has_children(sel)))
|
||||
+ if (!sel)
|
||||
return;
|
||||
if (arg->i > 0) {
|
||||
wl_list_for_each(c, &sel->link, link) {
|
||||
@@ -1826,7 +1823,7 @@ monocle(Monitor *m)
|
||||
int n = 0;
|
||||
|
||||
wl_list_for_each(c, &clients, link) {
|
||||
- if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||
+ if (!VISIBLEON(c, m) || c->isfloating)
|
||||
continue;
|
||||
resize(c, m->w, 0);
|
||||
n++;
|
||||
@@ -1957,7 +1954,7 @@ moveresize(const Arg *arg)
|
||||
if (cursor_mode != CurNormal && cursor_mode != CurPressed)
|
||||
return;
|
||||
xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL);
|
||||
- if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
|
||||
+ if (!grabc || client_is_unmanaged(grabc))
|
||||
return;
|
||||
|
||||
/* Float the window and tell motionnotify to grab it */
|
||||
@@ -2332,14 +2329,12 @@ setcursorshape(struct wl_listener *listener, void *data)
|
||||
void
|
||||
setfloating(Client *c, int floating)
|
||||
{
|
||||
- Client *p = client_get_parent(c);
|
||||
c->isfloating = floating;
|
||||
/* If in floating layout do not change the client's layer */
|
||||
if (!c->mon || !client_surface(c)->mapped || !c->mon->lt[c->mon->sellt]->arrange)
|
||||
return;
|
||||
- wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen ||
|
||||
- (p && p->isfullscreen) ? LyrFS
|
||||
- : c->isfloating ? LyrFloat : LyrTile]);
|
||||
+ wlr_scene_node_reparent(&c->scene->node,
|
||||
+ layers[c->isfloating ? LyrFloat : LyrTile]);
|
||||
arrange(c->mon);
|
||||
printstatus();
|
||||
}
|
||||
@@ -2352,12 +2347,12 @@ setfullscreen(Client *c, int fullscreen)
|
||||
return;
|
||||
c->bw = fullscreen ? 0 : borderpx;
|
||||
client_set_fullscreen(c, fullscreen);
|
||||
- wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen
|
||||
- ? LyrFS : c->isfloating ? LyrFloat : LyrTile]);
|
||||
|
||||
+ wlr_scene_node_reparent(&c->scene->node,
|
||||
+ layers[c->isfloating ? LyrFloat : LyrTile]);
|
||||
if (fullscreen) {
|
||||
c->prev = c->geom;
|
||||
- resize(c, c->mon->m, 0);
|
||||
+ resize(c, c->mon->w, 0);
|
||||
} else {
|
||||
/* restore previous size instead of arrange for floating windows since
|
||||
* client positions are set by the user and cannot be recalculated */
|
||||
@@ -2413,7 +2408,6 @@ setmon(Client *c, Monitor *m, uint32_t newtags)
|
||||
/* Make sure window actually overlaps with the monitor */
|
||||
resize(c, c->geom, 0);
|
||||
c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */
|
||||
- setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */
|
||||
setfloating(c, c->isfloating);
|
||||
}
|
||||
focusclient(focustop(selmon), 1);
|
||||
@@ -2716,7 +2710,7 @@ tile(Monitor *m)
|
||||
Client *c;
|
||||
|
||||
wl_list_for_each(c, &clients, link)
|
||||
- if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen)
|
||||
+ if (VISIBLEON(c, m) && !c->isfloating)
|
||||
n++;
|
||||
if (n == 0)
|
||||
return;
|
||||
@@ -2727,7 +2721,7 @@ tile(Monitor *m)
|
||||
mw = m->w.width;
|
||||
i = my = ty = 0;
|
||||
wl_list_for_each(c, &clients, link) {
|
||||
- if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||
+ if (!VISIBLEON(c, m) || c->isfloating)
|
||||
continue;
|
||||
if (i < m->nmaster) {
|
||||
resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + my, .width = mw,
|
||||
@@ -2747,7 +2741,7 @@ togglefloating(const Arg *arg)
|
||||
{
|
||||
Client *sel = focustop(selmon);
|
||||
/* return if fullscreen */
|
||||
- if (sel && !sel->isfullscreen)
|
||||
+ if (sel)
|
||||
setfloating(sel, !sel->isfloating);
|
||||
}
|
||||
|
||||
@@ -2902,9 +2896,6 @@ updatemons(struct wl_listener *listener, void *data)
|
||||
arrangelayers(m);
|
||||
/* Don't move clients to the left output when plugging monitors */
|
||||
arrange(m);
|
||||
- /* make sure fullscreen clients have the right size */
|
||||
- if ((c = focustop(m)) && c->isfullscreen)
|
||||
- resize(c, m->m, 0);
|
||||
|
||||
/* Try to re-set the gamma LUT when updating monitors,
|
||||
* it's only really needed when enabling a disabled output, but meh. */
|
||||
--
|
||||
2.51.0
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
From e0cecc228d436425c0d921a1eec5e0370d24613d Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Andr=C3=A9=20Desgualdo=20Pereira?= <desgua@gmail.com>
|
||||
Date: Thu, 13 Nov 2025 09:09:22 -0300
|
||||
Subject: [PATCH] controlled fullscreen fix
|
||||
|
||||
---
|
||||
dwl.c | 32 ++++++++++++--------------------
|
||||
1 file changed, 12 insertions(+), 20 deletions(-)
|
||||
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 12f441e..4f124eb 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -518,9 +518,6 @@ arrange(Monitor *m)
|
||||
}
|
||||
}
|
||||
|
||||
- wlr_scene_node_set_enabled(&m->fullscreen_bg->node,
|
||||
- (c = focustop(m)) && c->isfullscreen);
|
||||
-
|
||||
strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol));
|
||||
|
||||
/* We move all clients (except fullscreen and unmanaged) to LyrTile while
|
||||
@@ -878,7 +875,7 @@ commitnotify(struct wl_listener *listener, void *data)
|
||||
return;
|
||||
}
|
||||
|
||||
- resize(c, c->geom, (c->isfloating && !c->isfullscreen));
|
||||
+ resize(c, c->geom, (c->isfloating));
|
||||
|
||||
/* mark a pending resize as completed */
|
||||
if (c->resize && c->resize <= c->surface.xdg->current.configure_serial)
|
||||
@@ -1490,7 +1487,7 @@ focusstack(const Arg *arg)
|
||||
{
|
||||
/* Focus the next or previous client (in tiling order) on selmon */
|
||||
Client *c, *sel = focustop(selmon);
|
||||
- if (!sel || (sel->isfullscreen && !client_has_children(sel)))
|
||||
+ if (!sel)
|
||||
return;
|
||||
if (arg->i > 0) {
|
||||
wl_list_for_each(c, &sel->link, link) {
|
||||
@@ -1826,7 +1823,7 @@ monocle(Monitor *m)
|
||||
int n = 0;
|
||||
|
||||
wl_list_for_each(c, &clients, link) {
|
||||
- if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||
+ if (!VISIBLEON(c, m) || c->isfloating)
|
||||
continue;
|
||||
resize(c, m->w, 0);
|
||||
n++;
|
||||
@@ -1957,7 +1954,7 @@ moveresize(const Arg *arg)
|
||||
if (cursor_mode != CurNormal && cursor_mode != CurPressed)
|
||||
return;
|
||||
xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL);
|
||||
- if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
|
||||
+ if (!grabc || client_is_unmanaged(grabc))
|
||||
return;
|
||||
|
||||
/* Float the window and tell motionnotify to grab it */
|
||||
@@ -2332,14 +2329,12 @@ setcursorshape(struct wl_listener *listener, void *data)
|
||||
void
|
||||
setfloating(Client *c, int floating)
|
||||
{
|
||||
- Client *p = client_get_parent(c);
|
||||
c->isfloating = floating;
|
||||
/* If in floating layout do not change the client's layer */
|
||||
if (!c->mon || !client_surface(c)->mapped || !c->mon->lt[c->mon->sellt]->arrange)
|
||||
return;
|
||||
- wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen ||
|
||||
- (p && p->isfullscreen) ? LyrFS
|
||||
- : c->isfloating ? LyrFloat : LyrTile]);
|
||||
+ wlr_scene_node_reparent(&c->scene->node,
|
||||
+ layers[c->isfloating ? LyrFloat : LyrTile]);
|
||||
arrange(c->mon);
|
||||
printstatus();
|
||||
}
|
||||
@@ -2352,12 +2347,12 @@ setfullscreen(Client *c, int fullscreen)
|
||||
return;
|
||||
c->bw = fullscreen ? 0 : borderpx;
|
||||
client_set_fullscreen(c, fullscreen);
|
||||
- wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen
|
||||
- ? LyrFS : c->isfloating ? LyrFloat : LyrTile]);
|
||||
|
||||
+ wlr_scene_node_reparent(&c->scene->node,
|
||||
+ layers[c->isfloating ? LyrFloat : LyrTile]);
|
||||
if (fullscreen) {
|
||||
c->prev = c->geom;
|
||||
- resize(c, c->mon->m, 0);
|
||||
+ resize(c, c->mon->w, 0);
|
||||
} else {
|
||||
/* restore previous size instead of arrange for floating windows since
|
||||
* client positions are set by the user and cannot be recalculated */
|
||||
@@ -2716,7 +2711,7 @@ tile(Monitor *m)
|
||||
Client *c;
|
||||
|
||||
wl_list_for_each(c, &clients, link)
|
||||
- if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen)
|
||||
+ if (VISIBLEON(c, m) && !c->isfloating)
|
||||
n++;
|
||||
if (n == 0)
|
||||
return;
|
||||
@@ -2727,7 +2722,7 @@ tile(Monitor *m)
|
||||
mw = m->w.width;
|
||||
i = my = ty = 0;
|
||||
wl_list_for_each(c, &clients, link) {
|
||||
- if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||
+ if (!VISIBLEON(c, m) || c->isfloating)
|
||||
continue;
|
||||
if (i < m->nmaster) {
|
||||
resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + my, .width = mw,
|
||||
@@ -2747,7 +2742,7 @@ togglefloating(const Arg *arg)
|
||||
{
|
||||
Client *sel = focustop(selmon);
|
||||
/* return if fullscreen */
|
||||
- if (sel && !sel->isfullscreen)
|
||||
+ if (sel)
|
||||
setfloating(sel, !sel->isfloating);
|
||||
}
|
||||
|
||||
@@ -2902,9 +2897,6 @@ updatemons(struct wl_listener *listener, void *data)
|
||||
arrangelayers(m);
|
||||
/* Don't move clients to the left output when plugging monitors */
|
||||
arrange(m);
|
||||
- /* make sure fullscreen clients have the right size */
|
||||
- if ((c = focustop(m)) && c->isfullscreen)
|
||||
- resize(c, m->m, 0);
|
||||
|
||||
/* Try to re-set the gamma LUT when updating monitors,
|
||||
* it's only really needed when enabling a disabled output, but meh. */
|
||||
--
|
||||
2.51.0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
### Description
|
||||
Generate a coredump if dwl exited abnormally (to be more usefull you need to
|
||||
Generate a coredump if dwl exited abnormally (to be more useful you need to
|
||||
compile dwl and wlroots with debug symbols)
|
||||
|
||||
### Download
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
### Description
|
||||
Rules for floating windows support default x, y, width, height. Defaults to the center of the screen and the client size.
|
||||
|
||||
If the width or height is less than or equal to 1, then the value will be interpreted as a percentage. For example, 0.5 represents 50%, 0.25 represents 25%, and 1 represents 100%. **NOTE**: Some clients, like Thunar, have minimum width/height
|
||||
|
||||
The variable `center_relative_to_monitor` allows the user to choose whether to center relative to the monitor or relative to the window area.
|
||||
|
||||
<details>
|
||||
<summary>Explanation of center_relative_to_monitor:</summary>
|
||||
<pre>
|
||||
The "Monitor area" refers to the space enclosed by the green rectangle, while the "Window area" refers to the space enclosed by the red rectangle.
|
||||
<img src="https://i.imgur.com/xhejzPh.png"/>
|
||||
</pre>
|
||||
</details>
|
||||
|
||||
### Download
|
||||
- [git branch](https://codeberg.org/wochap/dwl/src/branch/v0.5/customfloat)
|
||||
- [2024-07-09](https://codeberg.org/dwl/dwl-patches/raw/commit/13d96b51b54500dd24544cf3a73c61b7a1414bc6/patches/customfloat/customfloat.patch)
|
||||
- [2024-04-11](https://codeberg.org/dwl/dwl-patches/raw/commit/98cba933c9f4099202e54f39acbf17e05bde828a/customfloat/customfloat.patch)
|
||||
- [v0.5](https://codeberg.org/dwl/dwl-patches/raw/commit/bf098459219e7a473d8edb4c0435aeb6a4b82e38/customfloat/customfloat.patch)
|
||||
|
||||
### Authors
|
||||
- [wochap](https://codeberg.org/wochap)
|
||||
- [Stivvo](https://github.com/Stivvo)
|
||||
### Description
|
||||
Rules for floating windows support default x, y, width, height. Defaults to the center of the screen and the client size.
|
||||
|
||||
If the width or height is less than or equal to 1, then the value will be interpreted as a percentage. For example, 0.5 represents 50%, 0.25 represents 25%, and 1 represents 100%. **NOTE**: Some clients, like Thunar, have minimum width/height
|
||||
|
||||
The variable `center_relative_to_monitor` allows the user to choose whether to center relative to the monitor or relative to the window area.
|
||||
|
||||
<details>
|
||||
<summary>Explanation of center_relative_to_monitor:</summary>
|
||||
<pre>
|
||||
The "Monitor area" refers to the space enclosed by the green rectangle, while the "Window area" refers to the space enclosed by the red rectangle.
|
||||
<img src="https://i.imgur.com/xhejzPh.png"/>
|
||||
</pre>
|
||||
</details>
|
||||
|
||||
### Download
|
||||
- [git branch](https://codeberg.org/wochap/dwl/src/branch/v0.5/customfloat)
|
||||
- [wlroots-next-f4249db](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/customfloat/customfloat-wlroots-next-f4249db.patch)
|
||||
- [0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/customfloat/customfloat-0.8.patch)
|
||||
|
||||
### Authors
|
||||
- [fauxmight](https://codeberg.org/fauxmight)
|
||||
- [wochap](https://codeberg.org/wochap)
|
||||
- [Stivvo](https://github.com/Stivvo)
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
From 96125a70b7525740a42803f1faa666ca37b9433f Mon Sep 17 00:00:00 2001
|
||||
From: A Frederick Christensen <dwl@ivories.org>
|
||||
Date: Mon, 23 Feb 2026 09:06:33 -0600
|
||||
Subject: [PATCH] Apply customfloat patch
|
||||
|
||||
---
|
||||
config.def.h | 7 ++++---
|
||||
dwl.c | 26 ++++++++++++++++++++++++++
|
||||
2 files changed, 30 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 8a6eda0..16afbb3 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -13,6 +13,7 @@ static const float focuscolor[] = COLOR(0x005577ff);
|
||||
static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
||||
static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */
|
||||
+static const int respect_monitor_reserved_area = 0; /* 1 to monitor center while respecting the monitor's reserved area, 0 to monitor center */
|
||||
|
||||
/* tagging - TAGCOUNT must be no greater than 31 */
|
||||
#define TAGCOUNT (9)
|
||||
@@ -21,9 +22,9 @@ 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 x y width height */
|
||||
+ { "Gimp_EXAMPLE", NULL, 0, 1, -1, -1, -1, 1000, 0.75 }, /* Start on currently visible tags floating, not tiled */
|
||||
+ { "firefox_EXAMPLE", NULL, 1 << 8, 0, -1, -1, -1, -1, -1 }, /* Start on ONLY tag "9" */
|
||||
/* default/example rule: can be changed but cannot be eliminated; at least one rule must exist */
|
||||
};
|
||||
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 44f3ad9..801696a 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -228,6 +228,10 @@ typedef struct {
|
||||
uint32_t tags;
|
||||
int isfloating;
|
||||
int monitor;
|
||||
+ int x;
|
||||
+ int y;
|
||||
+ float w;
|
||||
+ float h;
|
||||
} Rule;
|
||||
|
||||
typedef struct {
|
||||
@@ -482,6 +486,11 @@ applyrules(Client *c)
|
||||
int i;
|
||||
const Rule *r;
|
||||
Monitor *mon = selmon, *m;
|
||||
+ int newwidth;
|
||||
+ int newheight;
|
||||
+ int newx;
|
||||
+ int newy;
|
||||
+ int apply_resize = 0;
|
||||
|
||||
appid = client_get_appid(c);
|
||||
title = client_get_title(c);
|
||||
@@ -495,12 +504,29 @@ applyrules(Client *c)
|
||||
wl_list_for_each(m, &mons, link) {
|
||||
if (r->monitor == i++)
|
||||
mon = m;
|
||||
+ if (c->isfloating || !mon->lt[mon->sellt]->arrange) {
|
||||
+ /* client is floating or in floating layout */
|
||||
+ struct wlr_box b = respect_monitor_reserved_area ? mon->w : mon->m;
|
||||
+ newwidth = (int)round((r->w >= 0) ? (r->w <= 1 ? b.width * r->w : r->w) : c->geom.width);
|
||||
+ newheight = (int)round((r->h >= 0) ? (r->h <= 1 ? b.height * r->h : r->h) : c->geom.height);
|
||||
+ newx = (int)round((r->x >= 0) ? (r->x <= 1 ? b.width * r->x + b.x : r->x + b.x) : c->geom.x);
|
||||
+ newy = (int)round((r->y >= 0) ? (r->y <= 1 ? b.height * r->y + b.y : r->y + b.y) : c->geom.y);
|
||||
+ apply_resize = 1;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c->isfloating |= client_is_float_type(c);
|
||||
setmon(c, mon, newtags);
|
||||
+ if (apply_resize) {
|
||||
+ resize(c, (struct wlr_box){
|
||||
+ .x = newx,
|
||||
+ .y = newy,
|
||||
+ .width = newwidth,
|
||||
+ .height = newheight,
|
||||
+ }, 1);
|
||||
+ }
|
||||
}
|
||||
|
||||
void
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
From d8a861b30bf93554633ff0517d5bbdcb9b9614f0 Mon Sep 17 00:00:00 2001
|
||||
From: A Frederick Christensen <dwl@ivories.org>
|
||||
Date: Mon, 23 Feb 2026 09:18:07 -0600
|
||||
Subject: [PATCH] Apply customfloat patch
|
||||
|
||||
---
|
||||
config.def.h | 7 ++++---
|
||||
dwl.c | 26 ++++++++++++++++++++++++++
|
||||
2 files changed, 30 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 8a6eda0..16afbb3 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -13,6 +13,7 @@ static const float focuscolor[] = COLOR(0x005577ff);
|
||||
static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
||||
static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */
|
||||
+static const int respect_monitor_reserved_area = 0; /* 1 to monitor center while respecting the monitor's reserved area, 0 to monitor center */
|
||||
|
||||
/* tagging - TAGCOUNT must be no greater than 31 */
|
||||
#define TAGCOUNT (9)
|
||||
@@ -21,9 +22,9 @@ 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 x y width height */
|
||||
+ { "Gimp_EXAMPLE", NULL, 0, 1, -1, -1, -1, 1000, 0.75 }, /* Start on currently visible tags floating, not tiled */
|
||||
+ { "firefox_EXAMPLE", NULL, 1 << 8, 0, -1, -1, -1, -1, -1 }, /* Start on ONLY tag "9" */
|
||||
/* default/example rule: can be changed but cannot be eliminated; at least one rule must exist */
|
||||
};
|
||||
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 8a9715d..7de0655 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -230,6 +230,10 @@ typedef struct {
|
||||
uint32_t tags;
|
||||
int isfloating;
|
||||
int monitor;
|
||||
+ int x;
|
||||
+ int y;
|
||||
+ float w;
|
||||
+ float h;
|
||||
} Rule;
|
||||
|
||||
typedef struct {
|
||||
@@ -484,6 +488,11 @@ applyrules(Client *c)
|
||||
int i;
|
||||
const Rule *r;
|
||||
Monitor *mon = selmon, *m;
|
||||
+ int newwidth;
|
||||
+ int newheight;
|
||||
+ int newx;
|
||||
+ int newy;
|
||||
+ int apply_resize = 0;
|
||||
|
||||
appid = client_get_appid(c);
|
||||
title = client_get_title(c);
|
||||
@@ -497,12 +506,29 @@ applyrules(Client *c)
|
||||
wl_list_for_each(m, &mons, link) {
|
||||
if (r->monitor == i++)
|
||||
mon = m;
|
||||
+ if (c->isfloating || !mon->lt[mon->sellt]->arrange) {
|
||||
+ /* client is floating or in floating layout */
|
||||
+ struct wlr_box b = respect_monitor_reserved_area ? mon->w : mon->m;
|
||||
+ newwidth = (int)round((r->w >= 0) ? (r->w <= 1 ? b.width * r->w : r->w) : c->geom.width);
|
||||
+ newheight = (int)round((r->h >= 0) ? (r->h <= 1 ? b.height * r->h : r->h) : c->geom.height);
|
||||
+ newx = (int)round((r->x >= 0) ? (r->x <= 1 ? b.width * r->x + b.x : r->x + b.x) : c->geom.x);
|
||||
+ newy = (int)round((r->y >= 0) ? (r->y <= 1 ? b.height * r->y + b.y : r->y + b.y) : c->geom.y);
|
||||
+ apply_resize = 1;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c->isfloating |= client_is_float_type(c);
|
||||
setmon(c, mon, newtags);
|
||||
+ if (apply_resize) {
|
||||
+ resize(c, (struct wlr_box){
|
||||
+ .x = newx,
|
||||
+ .y = newy,
|
||||
+ .width = newwidth,
|
||||
+ .height = newheight,
|
||||
+ }, 1);
|
||||
+ }
|
||||
}
|
||||
|
||||
void
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
From 4f19f5499610d56f2616da5d44039403ac9d4c06 Mon Sep 17 00:00:00 2001
|
||||
From: wochap <gean.marroquin@gmail.com>
|
||||
Date: Tue, 9 Jul 2024 10:52:37 -0500
|
||||
Subject: [PATCH] implement customfloat and generate patches
|
||||
|
||||
---
|
||||
config.def.h | 7 ++++---
|
||||
dwl.c | 27 +++++++++++++++++++++++++++
|
||||
2 files changed, 31 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 22d2171..dee53f4 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -13,6 +13,7 @@ static const float focuscolor[] = COLOR(0x005577ff);
|
||||
static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
||||
static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You can also use glsl colors */
|
||||
+static const int respect_monitor_reserved_area = 0; /* 1 to monitor center while respecting the monitor's reserved area, 0 to monitor center */
|
||||
|
||||
/* tagging - TAGCOUNT must be no greater than 31 */
|
||||
#define TAGCOUNT (9)
|
||||
@@ -22,10 +23,10 @@ static int log_level = WLR_ERROR;
|
||||
|
||||
/* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g leave at least one example) */
|
||||
static const Rule rules[] = {
|
||||
- /* app_id title tags mask isfloating monitor */
|
||||
+ /* app_id title tags mask isfloating monitor x y width height */
|
||||
/* examples: */
|
||||
- { "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" */
|
||||
+ { "Gimp_EXAMPLE", NULL, 0, 1, -1, 0, 0, 1000, 0.75 }, /* Start on currently visible tags floating, not tiled */
|
||||
+ { "firefox_EXAMPLE", NULL, 1 << 8, 0, -1, 0, 0, 0, 0 },/* Start on ONLY tag "9" */
|
||||
};
|
||||
|
||||
/* layout(s) */
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index dc0437e..be0340f 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -230,6 +230,10 @@ typedef struct {
|
||||
uint32_t tags;
|
||||
int isfloating;
|
||||
int monitor;
|
||||
+ int x;
|
||||
+ int y;
|
||||
+ float w;
|
||||
+ float h;
|
||||
} Rule;
|
||||
|
||||
typedef struct {
|
||||
@@ -454,6 +458,11 @@ applyrules(Client *c)
|
||||
int i;
|
||||
const Rule *r;
|
||||
Monitor *mon = selmon, *m;
|
||||
+ int newwidth;
|
||||
+ int newheight;
|
||||
+ int newx;
|
||||
+ int newy;
|
||||
+ int apply_resize = 0;
|
||||
|
||||
c->isfloating = client_is_float_type(c);
|
||||
if (!(appid = client_get_appid(c)))
|
||||
@@ -471,9 +480,27 @@ applyrules(Client *c)
|
||||
if (r->monitor == i++)
|
||||
mon = m;
|
||||
}
|
||||
+ if (c->isfloating || !mon->lt[mon->sellt]->arrange) {
|
||||
+ /* client is floating or in floating layout */
|
||||
+ struct wlr_box b = respect_monitor_reserved_area ? mon->w : mon->m;
|
||||
+ newwidth = (int)round(r->w ? (r->w <= 1 ? b.width * r->w : r->w) : c->geom.width);
|
||||
+ newheight = (int)round(r->h ? (r->h <= 1 ? b.height * r->h : r->h) : c->geom.height);
|
||||
+ newx = (int)round(r->x ? (r->x <= 1 ? b.width * r->x + b.x : r->x + b.x) : c->geom.x);
|
||||
+ newy = (int)round(r->y ? (r->y <= 1 ? b.height * r->y + b.y : r->y + b.y) : c->geom.y);
|
||||
+ apply_resize = 1;
|
||||
+
|
||||
+ }
|
||||
}
|
||||
}
|
||||
setmon(c, mon, newtags);
|
||||
+ if (apply_resize) {
|
||||
+ resize(c, (struct wlr_box){
|
||||
+ .x = newx,
|
||||
+ .y = newy,
|
||||
+ .width = newwidth,
|
||||
+ .height = newheight,
|
||||
+ }, 1);
|
||||
+ }
|
||||
}
|
||||
|
||||
void
|
||||
--
|
||||
2.45.1
|
||||
@@ -0,0 +1,10 @@
|
||||
### Description
|
||||
Deck is a dwl-layout which is inspired by the dwm Deck layout (which is inspired by TTWM window manager). It applies the monocle-layout to the clients in the stack. The master-client is still visible. The stacked clients are like a deck of cards, hence the name.
|
||||
|
||||
### Download
|
||||
- [v0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/decklayout/decklayout.patch)
|
||||
- [git branch](https://codeberg.org/Kana/dwl/src/branch/decklayout)
|
||||
- [main 2025-10-08](https://codeberg.org/dwl/dwl-patches/raw/commit/f8d1cfad116c19c01593f7436468ec0cb7a3297b/patches/decklayout/decklayout.patch)
|
||||
|
||||
### Authors
|
||||
- [André Desgualdo Pereira](https://codeberg.org/Kana)
|
||||
@@ -0,0 +1,112 @@
|
||||
From c488515313e20f51ab961691002f9d483682ab16 Mon Sep 17 00:00:00 2001
|
||||
From: nate zhou <gnuunixchad@outlook.com>
|
||||
Date: Sat, 28 Feb 2026 21:32:46 +0800
|
||||
Subject: [PATCH] Patch: decklayout-0.8.patch
|
||||
|
||||
---
|
||||
config.def.h | 2 ++
|
||||
dwl.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 63 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 8a6eda0..3ec9ceb 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -33,6 +33,7 @@ static const Layout layouts[] = {
|
||||
{ "[]=", tile },
|
||||
{ "><>", NULL }, /* no layout function means floating behavior */
|
||||
{ "[M]", monocle },
|
||||
+ { "[E]", deck },
|
||||
};
|
||||
|
||||
/* monitors */
|
||||
@@ -135,6 +136,7 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
|
||||
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
|
||||
+ { MODKEY, XKB_KEY_a, setlayout, {.v = &layouts[3]} },
|
||||
{ MODKEY, XKB_KEY_space, setlayout, {0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
|
||||
{ MODKEY, XKB_KEY_e, togglefullscreen, {0} },
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 44f3ad9..f13f48b 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -278,6 +278,7 @@ static void destroylayersurfacenotify(struct wl_listener *listener, void *data);
|
||||
static void destroylock(SessionLock *lock, int unlocked);
|
||||
static void destroylocksurface(struct wl_listener *listener, void *data);
|
||||
static void destroynotify(struct wl_listener *listener, void *data);
|
||||
+static void deck(Monitor *m);
|
||||
static void destroypointerconstraint(struct wl_listener *listener, void *data);
|
||||
static void destroysessionlock(struct wl_listener *listener, void *data);
|
||||
static void destroykeyboardgroup(struct wl_listener *listener, void *data);
|
||||
@@ -1838,6 +1839,66 @@ monocle(Monitor *m)
|
||||
wlr_scene_node_raise_to_top(&c->scene->node);
|
||||
}
|
||||
|
||||
+void
|
||||
+deck(Monitor *m)
|
||||
+{
|
||||
+ unsigned int mw, my;
|
||||
+ int i, n = 0;
|
||||
+ Client *c;
|
||||
+
|
||||
+ /* count tiled clients */
|
||||
+ wl_list_for_each(c, &clients, link)
|
||||
+
|
||||
+ /* if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen) */
|
||||
+ if (VISIBLEON(c, m) && !c->isfloating)
|
||||
+ n++;
|
||||
+ if (n == 0)
|
||||
+ return;
|
||||
+
|
||||
+ /* set master width */
|
||||
+ if (n > m->nmaster)
|
||||
+ mw = m->nmaster ? (int)roundf(m->w.width * m->mfact) : 0;
|
||||
+ else
|
||||
+ mw = m->w.width;
|
||||
+
|
||||
+ /* update layout symbol with number of stack windows */
|
||||
+ /* use the following rules to count only the windows on the deck
|
||||
+ if (n > m->nmaster)
|
||||
+ snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n - m->nmaster);
|
||||
+ else
|
||||
+ snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n); */
|
||||
+
|
||||
+ /* or this one to count all windows on the tag */
|
||||
+ snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n);
|
||||
+
|
||||
+ i = my = 0;
|
||||
+ wl_list_for_each(c, &clients, link) {
|
||||
+ /* if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) */
|
||||
+ if (!VISIBLEON(c, m) || c->isfloating)
|
||||
+ continue;
|
||||
+
|
||||
+ if (i < m->nmaster) {
|
||||
+ /* master clients */
|
||||
+ resize(c, (struct wlr_box){
|
||||
+ .x = m->w.x,
|
||||
+ .y = m->w.y + my,
|
||||
+ .width = mw,
|
||||
+ .height = (m->w.height - my) / (MIN(n, m->nmaster) - i)
|
||||
+ }, 0);
|
||||
+ my += c->geom.height;
|
||||
+ } else {
|
||||
+ /* deck clients: overlap in stack area */
|
||||
+ resize(c, (struct wlr_box){
|
||||
+ .x = m->w.x + mw,
|
||||
+ .y = m->w.y,
|
||||
+ .width = m->w.width - mw,
|
||||
+ .height = m->w.height
|
||||
+ }, 0);
|
||||
+ }
|
||||
+ i++;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
motionabsolute(struct wl_listener *listener, void *data)
|
||||
{
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@@ -8,7 +8,8 @@ There are also two functions that can be bound to a `Key` or `Button`,
|
||||
2. `toggledimmingclient`: Which toggles dimming for the focused window, as if the client had `neverdim` applied to it. This overwrites an applied `Rule`.
|
||||
|
||||
### Download
|
||||
- [2024-09-18](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/dim-unfocused/dim-unfocused.patch)
|
||||
- [2026-03-10](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/dim-unfocused/dim-unfocused.patch)
|
||||
- [2024-09-18](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/dim-unfocused/dim-unfocused-20240918.patch)
|
||||
- [2024-09-03](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/dim-unfocused/dim-unfocused-20240903.patch)
|
||||
- [2024-07-14](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/dim-unfocused/dim-unfocused-20240714.patch)
|
||||
- [2024-05-16](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/dim-unfocused/dim-unfocused-20240516.patch)
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
diff --git a/client.h b/client.h
|
||||
index dabea35..3a31c25 100644
|
||||
--- a/client.h
|
||||
+++ b/client.h
|
||||
@@ -319,6 +319,12 @@ client_set_border_color(Client *c, const float color[static 4])
|
||||
wlr_scene_rect_set_color(c->border[i], color);
|
||||
}
|
||||
|
||||
+static inline void
|
||||
+client_set_dimmer_state(Client *c, const int dim)
|
||||
+{
|
||||
+ wlr_scene_node_set_enabled(&c->dimmer->node, DIMOPT && !c->neverdim && dim);
|
||||
+}
|
||||
+
|
||||
static inline void
|
||||
client_set_fullscreen(Client *c, int fullscreen)
|
||||
{
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 22d2171..4ca21c9 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -10,6 +10,7 @@ static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
static const float rootcolor[] = COLOR(0x222222ff);
|
||||
static const float bordercolor[] = COLOR(0x444444ff);
|
||||
static const float focuscolor[] = COLOR(0x005577ff);
|
||||
+static const float unfocuseddim[] = COLOR(0x00000088);
|
||||
static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
||||
static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You can also use glsl colors */
|
||||
@@ -22,10 +23,11 @@ static int log_level = WLR_ERROR;
|
||||
|
||||
/* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g leave at least one example) */
|
||||
static const Rule rules[] = {
|
||||
- /* app_id title tags mask isfloating monitor */
|
||||
- /* examples: */
|
||||
- { "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 neverdim monitor */
|
||||
+ /* examples:
|
||||
+ { "Gimp_example", NULL, 0, 1, 0, -1 },
|
||||
+ */
|
||||
+ { "firefox_example", NULL, 1 << 8, 0, 1, -1 },
|
||||
};
|
||||
|
||||
/* layout(s) */
|
||||
@@ -140,8 +142,9 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
|
||||
{ MODKEY, XKB_KEY_space, setlayout, {0} },
|
||||
+ { MODKEY, XKB_KEY_apostrophe, toggledimming, {0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
|
||||
- { MODKEY, XKB_KEY_e, togglefullscreen, {0} },
|
||||
+ { MODKEY, XKB_KEY_e, togglefullscreen, {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} },
|
||||
@@ -172,5 +175,6 @@ static const Key keys[] = {
|
||||
static const Button buttons[] = {
|
||||
{ MODKEY, BTN_LEFT, moveresize, {.ui = CurMove} },
|
||||
{ MODKEY, BTN_MIDDLE, togglefloating, {0} },
|
||||
+ { MODKEY|ShiftMask, BTN_MIDDLE, toggledimmingclient, {0} },
|
||||
{ MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize} },
|
||||
};
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index dc0c861..dcc3ece 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -112,6 +112,7 @@ typedef struct {
|
||||
Monitor *mon;
|
||||
struct wlr_scene_tree *scene;
|
||||
struct wlr_scene_rect *border[4]; /* top, bottom, left, right */
|
||||
+ struct wlr_scene_rect *dimmer;
|
||||
struct wlr_scene_tree *scene_surface;
|
||||
struct wl_list link;
|
||||
struct wl_list flink;
|
||||
@@ -141,7 +142,7 @@ typedef struct {
|
||||
#endif
|
||||
unsigned int bw;
|
||||
uint32_t tags;
|
||||
- int isfloating, isurgent, isfullscreen;
|
||||
+ int isfloating, isurgent, isfullscreen, neverdim;
|
||||
uint32_t resize; /* configure serial of a pending resize */
|
||||
} Client;
|
||||
|
||||
@@ -231,6 +232,7 @@ typedef struct {
|
||||
const char *title;
|
||||
uint32_t tags;
|
||||
int isfloating;
|
||||
+ int neverdim;
|
||||
int monitor;
|
||||
} Rule;
|
||||
|
||||
@@ -338,6 +340,8 @@ 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 toggledimming(const Arg *arg);
|
||||
+static void toggledimmingclient(const Arg *arg);
|
||||
static void togglefloating(const Arg *arg);
|
||||
static void togglefullscreen(const Arg *arg);
|
||||
static void toggletag(const Arg *arg);
|
||||
@@ -410,6 +414,7 @@ static struct wlr_output_layout *output_layout;
|
||||
static struct wlr_box sgeom;
|
||||
static struct wl_list mons;
|
||||
static Monitor *selmon;
|
||||
+static int DIMOPT = 1;
|
||||
|
||||
#ifdef XWAYLAND
|
||||
static void activatex11(struct wl_listener *listener, void *data);
|
||||
@@ -466,6 +471,7 @@ applyrules(Client *c)
|
||||
if ((!r->title || strstr(title, r->title))
|
||||
&& (!r->id || strstr(appid, r->id))) {
|
||||
c->isfloating = r->isfloating;
|
||||
+ c->neverdim = r-> neverdim;
|
||||
newtags |= r->tags;
|
||||
i = 0;
|
||||
wl_list_for_each(m, &mons, link) {
|
||||
@@ -1365,8 +1371,10 @@ focusclient(Client *c, int lift)
|
||||
|
||||
/* Don't change border color if there is an exclusive focus or we are
|
||||
* handling a drag operation */
|
||||
- if (!exclusive_focus && !seat->drag)
|
||||
+ if (!exclusive_focus && !seat->drag) {
|
||||
client_set_border_color(c, focuscolor);
|
||||
+ client_set_dimmer_state(c, 0);
|
||||
+ }
|
||||
}
|
||||
|
||||
/* Deactivate old client if focus is changing */
|
||||
@@ -1384,7 +1392,7 @@ focusclient(Client *c, int lift)
|
||||
* and probably other clients */
|
||||
} else if (old_c && !client_is_unmanaged(old_c) && (!c || !client_wants_focus(c))) {
|
||||
client_set_border_color(old_c, bordercolor);
|
||||
-
|
||||
+ client_set_dimmer_state(old_c, 1);
|
||||
client_activate_surface(old, 0);
|
||||
}
|
||||
}
|
||||
@@ -1681,8 +1689,7 @@ void
|
||||
mapnotify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
/* Called when the surface is mapped, or ready to display on-screen. */
|
||||
- Client *p = NULL;
|
||||
- Client *w, *c = wl_container_of(listener, c, map);
|
||||
+ Client *p, *w, *d, *c = wl_container_of(listener, c, map);
|
||||
Monitor *m;
|
||||
int i;
|
||||
|
||||
@@ -1716,6 +1723,10 @@ mapnotify(struct wl_listener *listener, void *data)
|
||||
c->border[i]->node.data = c;
|
||||
}
|
||||
|
||||
+ c->dimmer = wlr_scene_rect_create(c->scene, 0, 0, unfocuseddim);
|
||||
+ c->dimmer->node.data = c;
|
||||
+ client_set_dimmer_state(c, 1);
|
||||
+
|
||||
/* Initialize client geometry with room for border */
|
||||
client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT);
|
||||
c->geom.width += 2 * c->bw;
|
||||
@@ -1734,6 +1745,10 @@ mapnotify(struct wl_listener *listener, void *data)
|
||||
setmon(c, p->mon, p->tags);
|
||||
} else {
|
||||
applyrules(c);
|
||||
+ d = focustop(selmon);
|
||||
+ if (d) {
|
||||
+ client_set_dimmer_state(d, 0);
|
||||
+ }
|
||||
}
|
||||
printstatus();
|
||||
|
||||
@@ -2160,7 +2175,7 @@ resize(Client *c, struct wlr_box geo, int interact)
|
||||
c->geom = geo;
|
||||
applybounds(c, bbox);
|
||||
|
||||
- /* Update scene-graph, including borders */
|
||||
+ /* Update scene-graph, including borders and dimmer*/
|
||||
wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y);
|
||||
wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw);
|
||||
wlr_scene_rect_set_size(c->border[0], c->geom.width, c->bw);
|
||||
@@ -2170,6 +2185,8 @@ resize(Client *c, struct wlr_box geo, int interact)
|
||||
wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw);
|
||||
wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw);
|
||||
wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw);
|
||||
+ wlr_scene_rect_set_size(c->dimmer, c->geom.width - 2*c->bw, c-> geom.height - 2*c->bw);
|
||||
+ wlr_scene_node_set_position(&c->dimmer->node, c->bw, c->bw);
|
||||
|
||||
/* this is a no-op if size hasn't changed */
|
||||
c->resize = client_set_size(c, c->geom.width - 2 * c->bw,
|
||||
@@ -2681,6 +2698,27 @@ tile(Monitor *m)
|
||||
}
|
||||
}
|
||||
|
||||
+void toggledimming(const Arg *arg)
|
||||
+{
|
||||
+ Client *c;
|
||||
+ DIMOPT ^= 1;
|
||||
+ wl_list_for_each(c, &clients, link)
|
||||
+ {
|
||||
+ client_set_dimmer_state(c, 1);
|
||||
+ }
|
||||
+ c = focustop(selmon);
|
||||
+ if (c)
|
||||
+ client_set_dimmer_state(c, 0);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+toggledimmingclient(const Arg *arg)
|
||||
+{
|
||||
+ Client *sel = focustop(selmon);
|
||||
+ if (sel)
|
||||
+ sel -> neverdim ^= 1;
|
||||
+}
|
||||
+
|
||||
void
|
||||
togglefloating(const Arg *arg)
|
||||
{
|
||||
@@ -1,216 +1 @@
|
||||
diff --git a/client.h b/client.h
|
||||
index dabea35..3a31c25 100644
|
||||
--- a/client.h
|
||||
+++ b/client.h
|
||||
@@ -319,6 +319,12 @@ client_set_border_color(Client *c, const float color[static 4])
|
||||
wlr_scene_rect_set_color(c->border[i], color);
|
||||
}
|
||||
|
||||
+static inline void
|
||||
+client_set_dimmer_state(Client *c, const int dim)
|
||||
+{
|
||||
+ wlr_scene_node_set_enabled(&c->dimmer->node, DIMOPT && !c->neverdim && dim);
|
||||
+}
|
||||
+
|
||||
static inline void
|
||||
client_set_fullscreen(Client *c, int fullscreen)
|
||||
{
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 22d2171..4ca21c9 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -10,6 +10,7 @@ static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
static const float rootcolor[] = COLOR(0x222222ff);
|
||||
static const float bordercolor[] = COLOR(0x444444ff);
|
||||
static const float focuscolor[] = COLOR(0x005577ff);
|
||||
+static const float unfocuseddim[] = COLOR(0x00000088);
|
||||
static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
||||
static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You can also use glsl colors */
|
||||
@@ -22,10 +23,11 @@ static int log_level = WLR_ERROR;
|
||||
|
||||
/* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g leave at least one example) */
|
||||
static const Rule rules[] = {
|
||||
- /* app_id title tags mask isfloating monitor */
|
||||
- /* examples: */
|
||||
- { "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 neverdim monitor */
|
||||
+ /* examples:
|
||||
+ { "Gimp_example", NULL, 0, 1, 0, -1 },
|
||||
+ */
|
||||
+ { "firefox_example", NULL, 1 << 8, 0, 1, -1 },
|
||||
};
|
||||
|
||||
/* layout(s) */
|
||||
@@ -140,8 +142,9 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
|
||||
{ MODKEY, XKB_KEY_space, setlayout, {0} },
|
||||
+ { MODKEY, XKB_KEY_apostrophe, toggledimming, {0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
|
||||
- { MODKEY, XKB_KEY_e, togglefullscreen, {0} },
|
||||
+ { MODKEY, XKB_KEY_e, togglefullscreen, {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} },
|
||||
@@ -172,5 +175,6 @@ static const Key keys[] = {
|
||||
static const Button buttons[] = {
|
||||
{ MODKEY, BTN_LEFT, moveresize, {.ui = CurMove} },
|
||||
{ MODKEY, BTN_MIDDLE, togglefloating, {0} },
|
||||
+ { MODKEY|ShiftMask, BTN_MIDDLE, toggledimmingclient, {0} },
|
||||
{ MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize} },
|
||||
};
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index dc0c861..dcc3ece 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -112,6 +112,7 @@ typedef struct {
|
||||
Monitor *mon;
|
||||
struct wlr_scene_tree *scene;
|
||||
struct wlr_scene_rect *border[4]; /* top, bottom, left, right */
|
||||
+ struct wlr_scene_rect *dimmer;
|
||||
struct wlr_scene_tree *scene_surface;
|
||||
struct wl_list link;
|
||||
struct wl_list flink;
|
||||
@@ -141,7 +142,7 @@ typedef struct {
|
||||
#endif
|
||||
unsigned int bw;
|
||||
uint32_t tags;
|
||||
- int isfloating, isurgent, isfullscreen;
|
||||
+ int isfloating, isurgent, isfullscreen, neverdim;
|
||||
uint32_t resize; /* configure serial of a pending resize */
|
||||
} Client;
|
||||
|
||||
@@ -231,6 +232,7 @@ typedef struct {
|
||||
const char *title;
|
||||
uint32_t tags;
|
||||
int isfloating;
|
||||
+ int neverdim;
|
||||
int monitor;
|
||||
} Rule;
|
||||
|
||||
@@ -338,6 +340,8 @@ 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 toggledimming(const Arg *arg);
|
||||
+static void toggledimmingclient(const Arg *arg);
|
||||
static void togglefloating(const Arg *arg);
|
||||
static void togglefullscreen(const Arg *arg);
|
||||
static void toggletag(const Arg *arg);
|
||||
@@ -410,6 +414,7 @@ static struct wlr_output_layout *output_layout;
|
||||
static struct wlr_box sgeom;
|
||||
static struct wl_list mons;
|
||||
static Monitor *selmon;
|
||||
+static int DIMOPT = 1;
|
||||
|
||||
#ifdef XWAYLAND
|
||||
static void activatex11(struct wl_listener *listener, void *data);
|
||||
@@ -466,6 +471,7 @@ applyrules(Client *c)
|
||||
if ((!r->title || strstr(title, r->title))
|
||||
&& (!r->id || strstr(appid, r->id))) {
|
||||
c->isfloating = r->isfloating;
|
||||
+ c->neverdim = r-> neverdim;
|
||||
newtags |= r->tags;
|
||||
i = 0;
|
||||
wl_list_for_each(m, &mons, link) {
|
||||
@@ -1365,8 +1371,10 @@ focusclient(Client *c, int lift)
|
||||
|
||||
/* Don't change border color if there is an exclusive focus or we are
|
||||
* handling a drag operation */
|
||||
- if (!exclusive_focus && !seat->drag)
|
||||
+ if (!exclusive_focus && !seat->drag) {
|
||||
client_set_border_color(c, focuscolor);
|
||||
+ client_set_dimmer_state(c, 0);
|
||||
+ }
|
||||
}
|
||||
|
||||
/* Deactivate old client if focus is changing */
|
||||
@@ -1384,7 +1392,7 @@ focusclient(Client *c, int lift)
|
||||
* and probably other clients */
|
||||
} else if (old_c && !client_is_unmanaged(old_c) && (!c || !client_wants_focus(c))) {
|
||||
client_set_border_color(old_c, bordercolor);
|
||||
-
|
||||
+ client_set_dimmer_state(old_c, 1);
|
||||
client_activate_surface(old, 0);
|
||||
}
|
||||
}
|
||||
@@ -1681,8 +1689,7 @@ void
|
||||
mapnotify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
/* Called when the surface is mapped, or ready to display on-screen. */
|
||||
- Client *p = NULL;
|
||||
- Client *w, *c = wl_container_of(listener, c, map);
|
||||
+ Client *p, *w, *d, *c = wl_container_of(listener, c, map);
|
||||
Monitor *m;
|
||||
int i;
|
||||
|
||||
@@ -1716,6 +1723,10 @@ mapnotify(struct wl_listener *listener, void *data)
|
||||
c->border[i]->node.data = c;
|
||||
}
|
||||
|
||||
+ c->dimmer = wlr_scene_rect_create(c->scene, 0, 0, unfocuseddim);
|
||||
+ c->dimmer->node.data = c;
|
||||
+ client_set_dimmer_state(c, 1);
|
||||
+
|
||||
/* Initialize client geometry with room for border */
|
||||
client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT);
|
||||
c->geom.width += 2 * c->bw;
|
||||
@@ -1734,6 +1745,10 @@ mapnotify(struct wl_listener *listener, void *data)
|
||||
setmon(c, p->mon, p->tags);
|
||||
} else {
|
||||
applyrules(c);
|
||||
+ d = focustop(selmon);
|
||||
+ if (d) {
|
||||
+ client_set_dimmer_state(d, 0);
|
||||
+ }
|
||||
}
|
||||
printstatus();
|
||||
|
||||
@@ -2160,7 +2175,7 @@ resize(Client *c, struct wlr_box geo, int interact)
|
||||
c->geom = geo;
|
||||
applybounds(c, bbox);
|
||||
|
||||
- /* Update scene-graph, including borders */
|
||||
+ /* Update scene-graph, including borders and dimmer*/
|
||||
wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y);
|
||||
wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw);
|
||||
wlr_scene_rect_set_size(c->border[0], c->geom.width, c->bw);
|
||||
@@ -2170,6 +2185,8 @@ resize(Client *c, struct wlr_box geo, int interact)
|
||||
wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw);
|
||||
wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw);
|
||||
wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw);
|
||||
+ wlr_scene_rect_set_size(c->dimmer, c->geom.width - 2*c->bw, c-> geom.height - 2*c->bw);
|
||||
+ wlr_scene_node_set_position(&c->dimmer->node, c->bw, c->bw);
|
||||
|
||||
/* this is a no-op if size hasn't changed */
|
||||
c->resize = client_set_size(c, c->geom.width - 2 * c->bw,
|
||||
@@ -2681,6 +2698,27 @@ tile(Monitor *m)
|
||||
}
|
||||
}
|
||||
|
||||
+void toggledimming(const Arg *arg)
|
||||
+{
|
||||
+ Client *c;
|
||||
+ DIMOPT ^= 1;
|
||||
+ wl_list_for_each(c, &clients, link)
|
||||
+ {
|
||||
+ client_set_dimmer_state(c, 1);
|
||||
+ }
|
||||
+ c = focustop(selmon);
|
||||
+ if (c)
|
||||
+ client_set_dimmer_state(c, 0);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+toggledimmingclient(const Arg *arg)
|
||||
+{
|
||||
+ Client *sel = focustop(selmon);
|
||||
+ if (sel)
|
||||
+ sel -> neverdim ^= 1;
|
||||
+}
|
||||
+
|
||||
void
|
||||
togglefloating(const Arg *arg)
|
||||
{
|
||||
09
|
||||
@@ -0,0 +1,12 @@
|
||||
### Description
|
||||
Adds support for drm-lease-v1 for embedded displays such as VR headsets
|
||||
|
||||
### Download
|
||||
- [git branch](/caskd/dwl/src/branch/patches/drm_lease)
|
||||
- [main 2026-02-25](/dwl/dwl-patches/raw/branch/main/patches/drm_lease/drm_lease.patch)
|
||||
### Authors
|
||||
- [caskd](https://codeberg.org/caskd)
|
||||
caskd@redxen.eu
|
||||
caskd at [Libera IRC dwl channel](https://web.libera.chat/?channels=#dwl)
|
||||
- Micah Gorrell
|
||||
micah.gorrell@venafi.com
|
||||
@@ -0,0 +1,124 @@
|
||||
From 155578f30dc91363e7580c3020ad464ab561acd3 Mon Sep 17 00:00:00 2001
|
||||
From: Micah Gorrell <micah.gorrell@venafi.com>
|
||||
Date: Fri, 26 May 2023 08:17:20 -0600
|
||||
Subject: [PATCH] Implemented support for the DRM lease protocol, as needed to
|
||||
use devices such as VR headsets
|
||||
|
||||
---
|
||||
dwl.c | 36 ++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 36 insertions(+)
|
||||
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 101a45f..4740dfe 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <wlr/types/wlr_data_control_v1.h>
|
||||
#include <wlr/types/wlr_data_device.h>
|
||||
#include <wlr/types/wlr_drm.h>
|
||||
+#include <wlr/types/wlr_drm_lease_v1.h>
|
||||
#include <wlr/types/wlr_export_dmabuf_v1.h>
|
||||
#include <wlr/types/wlr_ext_data_control_v1.h>
|
||||
#include <wlr/types/wlr_fractional_scale_v1.h>
|
||||
@@ -316,6 +317,7 @@ static void powermgrsetmode(struct wl_listener *listener, void *data);
|
||||
static void quit(const Arg *arg);
|
||||
static void rendermon(struct wl_listener *listener, void *data);
|
||||
static void requestdecorationmode(struct wl_listener *listener, void *data);
|
||||
+static void requestdrmlease(struct wl_listener *listener, void *data);
|
||||
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);
|
||||
@@ -377,6 +379,7 @@ static struct wl_list clients; /* tiling order */
|
||||
static struct wl_list fstack; /* focus order */
|
||||
static struct wlr_idle_notifier_v1 *idle_notifier;
|
||||
static struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr;
|
||||
+static struct wlr_drm_lease_v1_manager *drm_lease_manager;
|
||||
static struct wlr_layer_shell_v1 *layer_shell;
|
||||
static struct wlr_output_manager_v1 *output_mgr;
|
||||
static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr;
|
||||
@@ -436,6 +439,7 @@ static struct wl_listener request_set_cursor_shape = {.notify = setcursorshape};
|
||||
static struct wl_listener request_start_drag = {.notify = requeststartdrag};
|
||||
static struct wl_listener start_drag = {.notify = startdrag};
|
||||
static struct wl_listener new_session_lock = {.notify = locksession};
|
||||
+static struct wl_listener drm_lease_request = {.notify = requestdrmlease};
|
||||
|
||||
#ifdef XWAYLAND
|
||||
static void activatex11(struct wl_listener *listener, void *data);
|
||||
@@ -727,10 +731,16 @@ cleanup(void)
|
||||
void
|
||||
cleanupmon(struct wl_listener *listener, void *data)
|
||||
{
|
||||
+ struct wlr_output *wlr_output = data;
|
||||
Monitor *m = wl_container_of(listener, m, destroy);
|
||||
LayerSurface *l, *tmp;
|
||||
size_t i;
|
||||
|
||||
+ if (drm_lease_manager && wlr_output->non_desktop) {
|
||||
+ wlr_drm_lease_v1_manager_withdraw_output (drm_lease_manager, wlr_output);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
/* m->layers[i] are intentionally not unlinked */
|
||||
for (i = 0; i < LENGTH(m->layers); i++) {
|
||||
wl_list_for_each_safe(l, tmp, &m->layers[i], link)
|
||||
@@ -783,6 +793,9 @@ cleanuplisteners(void)
|
||||
wl_list_remove(&request_start_drag.link);
|
||||
wl_list_remove(&start_drag.link);
|
||||
wl_list_remove(&new_session_lock.link);
|
||||
+ if (drm_lease_manager) {
|
||||
+ wl_list_remove(&drm_lease_request.link);
|
||||
+ }
|
||||
#ifdef XWAYLAND
|
||||
wl_list_remove(&new_xwayland_surface.link);
|
||||
wl_list_remove(&xwayland_ready.link);
|
||||
@@ -1047,6 +1060,11 @@ createmon(struct wl_listener *listener, void *data)
|
||||
struct wlr_output_state state;
|
||||
Monitor *m;
|
||||
|
||||
+ if (drm_lease_manager && wlr_output->non_desktop) {
|
||||
+ wlr_drm_lease_v1_manager_offer_output(drm_lease_manager, wlr_output);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
if (!wlr_output_init_render(wlr_output, alloc, drw))
|
||||
return;
|
||||
|
||||
@@ -2183,6 +2201,16 @@ requestdecorationmode(struct wl_listener *listener, void *data)
|
||||
WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
|
||||
}
|
||||
|
||||
+static void requestdrmlease(struct wl_listener *listener, void *data) {
|
||||
+ struct wlr_drm_lease_request_v1 *req = data;
|
||||
+ struct wlr_drm_lease_v1 *lease = wlr_drm_lease_request_v1_grant(req);
|
||||
+
|
||||
+ if (!lease) {
|
||||
+ fprintf(stderr, "Failed to grant lease request");
|
||||
+ wlr_drm_lease_request_v1_reject(req);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
requeststartdrag(struct wl_listener *listener, void *data)
|
||||
{
|
||||
@@ -2648,10 +2676,18 @@ setup(void)
|
||||
wl_signal_add(&output_mgr->events.apply, &output_mgr_apply);
|
||||
wl_signal_add(&output_mgr->events.test, &output_mgr_test);
|
||||
|
||||
+ drm_lease_manager = wlr_drm_lease_v1_manager_create(dpy, backend);
|
||||
+ if (drm_lease_manager) {
|
||||
+ wl_signal_add(&drm_lease_manager->events.request, &drm_lease_request);
|
||||
+ } else {
|
||||
+ fprintf(stderr, "Failed to create wlr_drm_lease_device_v1; VR will not be available\n");
|
||||
+ }
|
||||
+
|
||||
/* Make sure XWayland clients don't connect to the parent X server,
|
||||
* e.g when running in the x11 backend or the wayland backend and the
|
||||
* compositor has Xwayland support */
|
||||
unsetenv("DISPLAY");
|
||||
+
|
||||
#ifdef XWAYLAND
|
||||
/*
|
||||
* Initialise the XWayland X server.
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
### Description
|
||||
Adds a dwindle (fibonacci-style) layout to dwl.
|
||||
Windows are arranged by recursively splitting the remaining space,
|
||||
alternating between horizontal and vertical splits
|
||||
|
||||
With two windows:
|
||||
```
|
||||
┌───────────────┬────────────────┐
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
└───────────────┴────────────────┘
|
||||
```
|
||||
|
||||
With three windows:
|
||||
```
|
||||
┌───────────────┬────────────────┐
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ ├────────────────┤
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
└───────────────┴────────────────┘
|
||||
```
|
||||
|
||||
With four windows:
|
||||
```
|
||||
┌───────────────┬────────────────┐
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ ├───────┬────────┤
|
||||
│ │ │ │
|
||||
│ │ │ │
|
||||
│ │ │ │
|
||||
│ │ │ │
|
||||
└───────────────┴───────┴────────┘
|
||||
```
|
||||
### Download
|
||||
|
||||
- [0.8](/dwl/dwl-patches/raw/branch/main/patches/dwindle/dwindle.patch)
|
||||
|
||||
### Authors
|
||||
[cana cronica](https://codeberg.org/cana)
|
||||
@@ -0,0 +1,105 @@
|
||||
From 9be9c310cd546c22bd486f11c21e7ffcc09b1e8a Mon Sep 17 00:00:00 2001
|
||||
From: C4FE1 <heitorcdesousa13@gmail.com>
|
||||
Date: Fri, 20 Mar 2026 21:30:41 -0300
|
||||
Subject: [PATCH] dwl: add dwindle layout
|
||||
|
||||
dwl: add dwindle layout
|
||||
---
|
||||
config.def.h | 2 ++
|
||||
dwl.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 55 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 8a6eda0..96bb1c0 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -33,6 +33,7 @@ static const Layout layouts[] = {
|
||||
{ "[]=", tile },
|
||||
{ "><>", NULL }, /* no layout function means floating behavior */
|
||||
{ "[M]", monocle },
|
||||
+ { "[\\]", dwindle },
|
||||
};
|
||||
|
||||
/* monitors */
|
||||
@@ -135,6 +136,7 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
|
||||
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
|
||||
+ { MODKEY, XKB_KEY_r, setlayout, {.v = &layouts[3]} },
|
||||
{ MODKEY, XKB_KEY_space, setlayout, {0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
|
||||
{ MODKEY, XKB_KEY_e, togglefullscreen, {0} },
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 101a45f..5f1b762 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -335,6 +335,7 @@ 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 dwindle(Monitor *m);
|
||||
static void togglefloating(const Arg *arg);
|
||||
static void togglefullscreen(const Arg *arg);
|
||||
static void toggletag(const Arg *arg);
|
||||
@@ -2745,6 +2746,58 @@ tile(Monitor *m)
|
||||
}
|
||||
}
|
||||
|
||||
+void
|
||||
+dwindle(Monitor *m)
|
||||
+{
|
||||
+ unsigned int i, n = 0;
|
||||
+ int nx, ny, nw, nh;
|
||||
+ int horizontal;
|
||||
+ Client *c;
|
||||
+
|
||||
+ /* count clients */
|
||||
+ wl_list_for_each(c, &clients, link)
|
||||
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen)
|
||||
+ n++;
|
||||
+
|
||||
+ if (n == 0)
|
||||
+ return;
|
||||
+
|
||||
+ nx = m->w.x;
|
||||
+ ny = m->w.y;
|
||||
+ nw = m->w.width;
|
||||
+ nh = m->w.height;
|
||||
+
|
||||
+ horizontal = 1; // toggle split direction
|
||||
+ i = 0;
|
||||
+
|
||||
+ wl_list_for_each(c, &clients, link) {
|
||||
+ if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||
+ continue;
|
||||
+
|
||||
+ if (i == n - 1) {
|
||||
+ /* last window gets remaining space */
|
||||
+ resize(c, (struct wlr_box){nx, ny, nw, nh}, 0);
|
||||
+ } else if (horizontal) {
|
||||
+ int w = nw / 2;
|
||||
+
|
||||
+ resize(c, (struct wlr_box){nx, ny, w, nh}, 0);
|
||||
+
|
||||
+ nx += w;
|
||||
+ nw -= w;
|
||||
+ } else {
|
||||
+ int h = nh / 2;
|
||||
+
|
||||
+ resize(c, (struct wlr_box){nx, ny, nw, h}, 0);
|
||||
+
|
||||
+ ny += h;
|
||||
+ nh -= h;
|
||||
+ }
|
||||
+
|
||||
+ horizontal = !horizontal;
|
||||
+ i++;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
togglefloating(const Arg *arg)
|
||||
{
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
Always use the English keymap to get keycodes, so key bindings work even when using a non-English keyboard layout.
|
||||
|
||||
### Download
|
||||
- [git branch](https://codeberg.org/ForzCross/dwl/src/branch/en-keycodes.patch)
|
||||
- [v0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/en-keycodes/en-keycodes.patch)
|
||||
- [0.8](/dwl/dwl-patches/raw/branch/main/patches/en-keycodes/en-keycodes-0.8.patch)
|
||||
- [0.7](/dwl/dwl-patches/raw/branch/main/patches/en-keycodes/en-keycodes-0.7.patch)
|
||||
|
||||
### Authors
|
||||
- [ForzCross](https://codeberg.org/ForzCross)
|
||||
- [Nikita Ivanov](https://codeberg.org/nikitaivanov) ([GitHub](https://github.com/NikitaIvanovV))
|
||||
- [ForzCross](https://codeberg.org/ForzCross)
|
||||
- [dimkr](https://codeberg.org/dimkr) (<dima@dimakrasner.com>)
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
From cd61fac9cb6e9d0172e2f7a01e6a514d676ba5f0 Mon Sep 17 00:00:00 2001
|
||||
From 556e47f7ce7f729ecc1b285ece0c82744741c81c Mon Sep 17 00:00:00 2001
|
||||
From: Nikita Ivanov <nikita.vyach.ivanov@gmail.com>
|
||||
Date: Tue, 4 Feb 2025 23:53:11 +0100
|
||||
Date: Sun, 30 Nov 2025 23:16:53 +0100
|
||||
Subject: [PATCH] Always use the English keymap to get keycodes
|
||||
|
||||
---
|
||||
dwl.c | 23 +++++++++++++++++++----
|
||||
1 file changed, 19 insertions(+), 4 deletions(-)
|
||||
dwl.c | 25 +++++++++++++++++++++----
|
||||
1 file changed, 21 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index def2562..c299365 100644
|
||||
index def2562..31e98ca 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -413,6 +413,11 @@ static struct wlr_box sgeom;
|
||||
static struct wl_list mons;
|
||||
static Monitor *selmon;
|
||||
|
||||
+static const struct xkb_rule_names en_rules = {.layout = "us"};
|
||||
+static struct xkb_rule_names en_rules;
|
||||
+static struct xkb_context *en_context;
|
||||
+static struct xkb_keymap *en_keymap;
|
||||
+static struct xkb_state *en_state;
|
||||
@@ -57,11 +57,13 @@ index def2562..c299365 100644
|
||||
|
||||
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
||||
|
||||
@@ -2607,6 +2618,10 @@ setup(void)
|
||||
@@ -2607,6 +2618,12 @@ setup(void)
|
||||
* pointer, touch, and drawing tablet device. We also rig up a listener to
|
||||
* let us know when new input devices are available on the backend.
|
||||
*/
|
||||
+ en_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||
+ en_rules = xkb_rules;
|
||||
+ en_rules.layout = "us";
|
||||
+ en_keymap = xkb_keymap_new_from_names(en_context, &en_rules,
|
||||
+ XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
+ en_state = xkb_state_new(en_keymap);
|
||||
@@ -69,5 +71,5 @@ index def2562..c299365 100644
|
||||
virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy);
|
||||
LISTEN_STATIC(&virtual_keyboard_mgr->events.new_virtual_keyboard, virtualkeyboard);
|
||||
--
|
||||
2.48.1
|
||||
2.51.2
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
From cde0921304c11c2e1341539a5ada4f7b9715b178 Mon Sep 17 00:00:00 2001
|
||||
From: Nikita Ivanov <nikita.vyach.ivanov@gmail.com>
|
||||
Date: Sun, 30 Nov 2025 23:22:42 +0100
|
||||
Subject: [PATCH] Always use the English keymap to get keycodes
|
||||
|
||||
---
|
||||
dwl.c | 25 +++++++++++++++++++++----
|
||||
1 file changed, 21 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 44f3ad9..97ba897 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -436,6 +436,11 @@ static struct wl_listener request_start_drag = {.notify = requeststartdrag};
|
||||
static struct wl_listener start_drag = {.notify = startdrag};
|
||||
static struct wl_listener new_session_lock = {.notify = locksession};
|
||||
|
||||
+static struct xkb_rule_names en_rules;
|
||||
+static struct xkb_context *en_context;
|
||||
+static struct xkb_keymap *en_keymap;
|
||||
+static struct xkb_state *en_state;
|
||||
+
|
||||
#ifdef XWAYLAND
|
||||
static void activatex11(struct wl_listener *listener, void *data);
|
||||
static void associatex11(struct wl_listener *listener, void *data);
|
||||
@@ -718,6 +723,9 @@ cleanup(void)
|
||||
wlr_backend_destroy(backend);
|
||||
|
||||
wl_display_destroy(dpy);
|
||||
+ xkb_state_unref(en_state);
|
||||
+ xkb_keymap_unref(en_keymap);
|
||||
+ xkb_context_unref(en_context);
|
||||
/* Destroy after the wayland display (when the monitors are already destroyed)
|
||||
to avoid destroying them with an invalid scene output. */
|
||||
wlr_scene_node_destroy(&scene->tree.node);
|
||||
@@ -1632,16 +1640,19 @@ keypress(struct wl_listener *listener, void *data)
|
||||
/* This event is raised when a key is pressed or released. */
|
||||
KeyboardGroup *group = wl_container_of(listener, group, key);
|
||||
struct wlr_keyboard_key_event *event = data;
|
||||
+ int nsyms, handled;
|
||||
|
||||
/* Translate libinput keycode -> xkbcommon */
|
||||
uint32_t keycode = event->keycode + 8;
|
||||
/* Get a list of keysyms based on the keymap for this keyboard */
|
||||
const xkb_keysym_t *syms;
|
||||
- int nsyms = xkb_state_key_get_syms(
|
||||
- group->wlr_group->keyboard.xkb_state, keycode, &syms);
|
||||
-
|
||||
- int handled = 0;
|
||||
uint32_t mods = wlr_keyboard_get_modifiers(&group->wlr_group->keyboard);
|
||||
+ xkb_state_update_key(en_state, keycode,
|
||||
+ (event->state == WL_KEYBOARD_KEY_STATE_PRESSED)
|
||||
+ ? XKB_KEY_DOWN : XKB_KEY_UP);
|
||||
+ nsyms = xkb_state_key_get_syms(en_state, keycode, &syms);
|
||||
+
|
||||
+ handled = 0;
|
||||
|
||||
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
||||
|
||||
@@ -2624,6 +2635,12 @@ setup(void)
|
||||
* pointer, touch, and drawing tablet device. We also rig up a listener to
|
||||
* let us know when new input devices are available on the backend.
|
||||
*/
|
||||
+ en_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||
+ en_rules = xkb_rules;
|
||||
+ en_rules.layout = "us";
|
||||
+ en_keymap = xkb_keymap_new_from_names(en_context, &en_rules,
|
||||
+ XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
+ en_state = xkb_state_new(en_keymap);
|
||||
wl_signal_add(&backend->events.new_input, &new_input_device);
|
||||
virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy);
|
||||
wl_signal_add(&virtual_keyboard_mgr->events.new_virtual_keyboard,
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
### extrabar
|
||||
|
||||
Add an extra bar on the other side of the primary bar, shows additional status sections.
|
||||
_Requires_ `bar` patch to be applied first. Heavily inspired by `dwm`'s extrabar patch.
|
||||
|
||||
### Status
|
||||
|
||||
The status text on the extra bar is set using the stdin as usual, with the text being split by `;`
|
||||
|
||||
For example, if `status1;status2;status3` was set,
|
||||
then `status1` is set as the status of the primary bar,
|
||||
`status2` is set as the left status of extrabar,
|
||||
`status3` is set as the right status of extrabar.
|
||||
|
||||
### Author
|
||||
|
||||
[dhruva_sambrani](/dhruva_sambrani)
|
||||
@@ -0,0 +1,188 @@
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 7fe9468..2614a25 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -205,6 +205,7 @@ struct Monitor {
|
||||
struct wlr_output *wlr_output;
|
||||
struct wlr_scene_output *scene_output;
|
||||
struct wlr_scene_buffer *scene_buffer; /* bar buffer */
|
||||
+ struct wlr_scene_buffer *extra_scene_buffer; /* bar buffer */
|
||||
struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */
|
||||
struct wl_listener frame;
|
||||
struct wl_listener destroy;
|
||||
@@ -230,6 +231,7 @@ struct Monitor {
|
||||
int asleep;
|
||||
Drwl *drw;
|
||||
Buffer *pool[2];
|
||||
+ Buffer *extra_pool[2];
|
||||
int lrpad;
|
||||
};
|
||||
|
||||
@@ -278,7 +280,7 @@ static void bufdestroy(struct wlr_buffer *buffer);
|
||||
static bool bufdatabegin(struct wlr_buffer *buffer, uint32_t flags,
|
||||
void **data, uint32_t *format, size_t *stride);
|
||||
static void bufdataend(struct wlr_buffer *buffer);
|
||||
-static Buffer *bufmon(Monitor *m);
|
||||
+static Buffer *bufmon(Monitor *m, Buffer **pool);
|
||||
static void bufrelease(struct wl_listener *listener, void *data);
|
||||
static void buttonpress(struct wl_listener *listener, void *data);
|
||||
static void chvt(const Arg *arg);
|
||||
@@ -444,6 +446,8 @@ static struct wl_list mons;
|
||||
static Monitor *selmon;
|
||||
|
||||
static char stext[256];
|
||||
+static char stext2[256];
|
||||
+static char stext3[256];
|
||||
static struct wl_event_source *status_event_source;
|
||||
|
||||
static const struct wlr_buffer_impl buffer_impl = {
|
||||
@@ -627,6 +631,11 @@ arrangelayers(Monitor *m)
|
||||
usable_area.y += topbar ? m->b.real_height : 0;
|
||||
}
|
||||
|
||||
+ if (m->extra_scene_buffer->node.enabled) {
|
||||
+ usable_area.height -= m->b.real_height;
|
||||
+ usable_area.y += topbar ? 0 : m->b.real_height;
|
||||
+ }
|
||||
+
|
||||
/* Arrange exclusive surfaces from top->bottom */
|
||||
for (i = 3; i >= 0; i--)
|
||||
arrangelayer(m, &m->layers[i], &usable_area, 1);
|
||||
@@ -706,23 +715,23 @@ bufdataend(struct wlr_buffer *wlr_buffer)
|
||||
}
|
||||
|
||||
Buffer *
|
||||
-bufmon(Monitor *m)
|
||||
+bufmon(Monitor *m, Buffer **pool)
|
||||
{
|
||||
size_t i;
|
||||
Buffer *buf = NULL;
|
||||
|
||||
for (i = 0; i < LENGTH(m->pool); i++) {
|
||||
- if (m->pool[i]) {
|
||||
- if (m->pool[i]->busy)
|
||||
+ if (pool[i]) {
|
||||
+ if (pool[i]->busy)
|
||||
continue;
|
||||
- buf = m->pool[i];
|
||||
+ buf = pool[i];
|
||||
break;
|
||||
}
|
||||
|
||||
buf = ecalloc(1, sizeof(Buffer) + (m->b.width * 4 * m->b.height));
|
||||
buf->image = drwl_image_create(NULL, m->b.width, m->b.height, buf->data);
|
||||
wlr_buffer_init(&buf->base, &buffer_impl, m->b.width, m->b.height);
|
||||
- m->pool[i] = buf;
|
||||
+ pool[i] = buf;
|
||||
break;
|
||||
}
|
||||
if (!buf)
|
||||
@@ -1255,6 +1264,8 @@ createmon(struct wl_listener *listener, void *data)
|
||||
|
||||
m->scene_buffer = wlr_scene_buffer_create(layers[LyrBottom], NULL);
|
||||
m->scene_buffer->point_accepts_input = baracceptsinput;
|
||||
+ m->extra_scene_buffer = wlr_scene_buffer_create(layers[LyrBottom], NULL);
|
||||
+ m->extra_scene_buffer->point_accepts_input = baracceptsinput;
|
||||
updatebar(m);
|
||||
|
||||
wl_list_insert(&mons, &m->link);
|
||||
@@ -1580,7 +1591,7 @@ drawbar(Monitor *m)
|
||||
|
||||
if (!m->scene_buffer->node.enabled)
|
||||
return;
|
||||
- if (!(buf = bufmon(m)))
|
||||
+ if (!(buf = bufmon(m, m->pool)))
|
||||
return;
|
||||
|
||||
/* draw status first so it can be overdrawn by tags later */
|
||||
@@ -1633,13 +1644,47 @@ drawbar(Monitor *m)
|
||||
wlr_buffer_unlock(&buf->base);
|
||||
}
|
||||
|
||||
+void
|
||||
+extrabar(Monitor *m)
|
||||
+{
|
||||
+ int tw = 0;
|
||||
+ Buffer *buf = NULL;
|
||||
+
|
||||
+ /* Skip if the extra bar scene buffer is not initialized/enabled */
|
||||
+ if (!m->extra_scene_buffer || !m->extra_scene_buffer->node.enabled)
|
||||
+ return;
|
||||
+
|
||||
+ /* Inline bufmon logic for the extra pool to keep changes contained */
|
||||
+ if (!(buf = bufmon(m, m->extra_pool)))
|
||||
+ return;
|
||||
+
|
||||
+ drwl_setscheme(m->drw, colors[SchemeNorm]);
|
||||
+ drwl_rect(m->drw, 0, 0, m->b.width, m->b.height, 1, 1);
|
||||
+
|
||||
+ drwl_setscheme(m->drw, colors[SchemeNorm]);
|
||||
+ tw = TEXTW(m, stext2) - m->lrpad + 2; /* 2px right padding */
|
||||
+ drwl_text(m->drw, 2, 0, tw, m->b.height, 0, stext2, 0);
|
||||
+
|
||||
+ tw = TEXTW(m, stext3) - m->lrpad + 2; /* 2px right padding */
|
||||
+ drwl_text(m->drw, m->b.width - tw - 4, 0, tw, m->b.height, 0, stext3, 0);
|
||||
+
|
||||
+ wlr_scene_buffer_set_dest_size(m->extra_scene_buffer, m->b.real_width, m->b.real_height);
|
||||
+ wlr_scene_node_set_position(&m->extra_scene_buffer->node, m->m.x,
|
||||
+ m->m.y + (topbar ? m->m.height - m->b.real_height : 0));
|
||||
+
|
||||
+ wlr_scene_buffer_set_buffer(m->extra_scene_buffer, &buf->base);
|
||||
+ wlr_buffer_unlock(&buf->base);
|
||||
+}
|
||||
+
|
||||
void
|
||||
drawbars(void)
|
||||
{
|
||||
Monitor *m = NULL;
|
||||
|
||||
- wl_list_for_each(m, &mons, link)
|
||||
+ wl_list_for_each(m, &mons, link) {
|
||||
drawbar(m);
|
||||
+ extrabar(m);
|
||||
+ }
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2896,7 +2941,7 @@ startdrag(struct wl_listener *listener, void *data)
|
||||
int
|
||||
statusin(int fd, unsigned int mask, void *data)
|
||||
{
|
||||
- char status[256];
|
||||
+ char status[3*256];
|
||||
ssize_t n;
|
||||
|
||||
if (mask & WL_EVENT_ERROR)
|
||||
@@ -2911,7 +2956,18 @@ statusin(int fd, unsigned int mask, void *data)
|
||||
status[n] = '\0';
|
||||
status[strcspn(status, "\n")] = '\0';
|
||||
|
||||
- strncpy(stext, status, sizeof(stext));
|
||||
+ char *l1 = strchr(status, ';');
|
||||
+ if (l1) {
|
||||
+ *l1 = '\0';
|
||||
+ char *l2 = strchr(++l1, ';');
|
||||
+ if (l2) {
|
||||
+ *l2 = '\0';
|
||||
+ strncpy(stext3, ++l2, sizeof(stext3));
|
||||
+ }
|
||||
+ strncpy(stext2, l1, sizeof(stext2));
|
||||
+ }
|
||||
+ strncpy(stext, status, sizeof(stext));
|
||||
+
|
||||
drawbars();
|
||||
|
||||
return 0;
|
||||
@@ -3206,6 +3262,12 @@ updatebar(Monitor *m)
|
||||
m->pool[i] = NULL;
|
||||
}
|
||||
|
||||
+ for (i = 0; i < LENGTH(m->extra_pool); i++)
|
||||
+ if (m->extra_pool[i]) {
|
||||
+ wlr_buffer_drop(&m->extra_pool[i]->base);
|
||||
+ m->extra_pool[i] = NULL;
|
||||
+ }
|
||||
+
|
||||
if (m->b.scale == m->wlr_output->scale && m->drw)
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
### Description
|
||||
|
||||
By default, dwl responds to client requests to client messages by setting the urgency bit on the named window.
|
||||
This patch changes the focus to the window instead.
|
||||
Both behaviours are legitimate according to the cursed spec.
|
||||
This is the approximately the equivalent of the focusonactive patch of dwm.
|
||||
If you want a more controlled behavior, for example setting which clients can focus, check [activation-rule patch](https://codeberg.org/sevz/dwl-patches/src/branch/activation-rules).
|
||||
|
||||
### Download
|
||||
- [main dwl 0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/focusonurgent/focusonurgent.patch)
|
||||
|
||||
### Authors
|
||||
- [André Desgualdo Pereira](https://codeberg.org/Kana)
|
||||
@@ -0,0 +1,29 @@
|
||||
From 7cdba8df596d59a3ad2883521a65962dcd4fe644 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Andr=C3=A9=20Desgualdo=20Pereira?= <desgua@gmail.com>
|
||||
Date: Sat, 14 Mar 2026 17:52:25 -0300
|
||||
Subject: [PATCH] update
|
||||
|
||||
---
|
||||
dwl.c | 6 ++++--
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 101a45f..6cd2f82 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -2099,8 +2099,10 @@ printstatus(void)
|
||||
if (c->mon != m)
|
||||
continue;
|
||||
occ |= c->tags;
|
||||
- if (c->isurgent)
|
||||
- urg |= c->tags;
|
||||
+ if (c->isurgent) {
|
||||
+ view(&((Arg){ .ui = c->tags }));
|
||||
+ focusclient(c, 1);
|
||||
+ }
|
||||
}
|
||||
if ((c = focustop(m))) {
|
||||
printf("%s title %s\n", m->wlr_output->name, client_get_title(c));
|
||||
--
|
||||
2.51.0
|
||||
|
||||
@@ -22,8 +22,10 @@ Adds a function that automatically enables adaptive sync/VRR when a fullscreen c
|
||||
- Enabled by default.
|
||||
|
||||
### Download
|
||||
- [git branch](https://codeberg.org/julmajustus/dwl/src/branch/fullscreenadaptivesync)
|
||||
- [0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/fullscreenadaptivesync/fullscreenadaptivesync-v0.7.patch)
|
||||
- [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)
|
||||
- [wlroots-next-d41ecb7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/fullscreenadaptivesync/fullscreenadaptivesync-wlroots-next-d41ecb7.patch)
|
||||
|
||||
### Authors
|
||||
- [julmajustus](https://codeberg.org/julmajustus)
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
From c003f450c197a0c960bbb355511f8dca7a35e3c3 Mon Sep 17 00:00:00 2001
|
||||
From 85dccbec7e6d2e967646a8c182a7a24224632c68 Mon Sep 17 00:00:00 2001
|
||||
From: julmajustus <julmajustus@tutanota.com>
|
||||
Date: Sat, 4 Jan 2025 14:24:59 +0200
|
||||
Subject: [PATCH] add fullscreenadaptivesync
|
||||
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 | 40 ++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 41 insertions(+)
|
||||
dwl.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 53 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 22d2171..886f1ab 100644
|
||||
@@ -21,7 +24,7 @@ index 22d2171..886f1ab 100644
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} },
|
||||
{ MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} },
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index a2711f6..7be05ef 100644
|
||||
index a2711f6..1b0682d 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -322,6 +322,7 @@ static void requeststartdrag(struct wl_listener *listener, void *data);
|
||||
@@ -49,11 +52,10 @@ index a2711f6..7be05ef 100644
|
||||
#ifdef XWAYLAND
|
||||
static void activatex11(struct wl_listener *listener, void *data);
|
||||
static void associatex11(struct wl_listener *listener, void *data);
|
||||
@@ -2269,6 +2273,31 @@ run(char *startup_cmd)
|
||||
@@ -2269,6 +2273,42 @@ run(char *startup_cmd)
|
||||
wl_display_run(dpy);
|
||||
}
|
||||
|
||||
+void
|
||||
+set_adaptive_sync(Monitor *m, int enable)
|
||||
+{
|
||||
+ struct wlr_output_state state;
|
||||
@@ -64,14 +66,26 @@ index a2711f6..7be05ef 100644
|
||||
+ || !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);
|
||||
+ wlr_output_commit_state(m->wlr_output, &state);
|
||||
+ wlr_output_state_finish(&state);
|
||||
+ 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;
|
||||
@@ -81,7 +95,7 @@ index a2711f6..7be05ef 100644
|
||||
void
|
||||
setcursor(struct wl_listener *listener, void *data)
|
||||
{
|
||||
@@ -2332,10 +2361,12 @@ setfullscreen(Client *c, int fullscreen)
|
||||
@@ -2332,10 +2372,12 @@ setfullscreen(Client *c, int fullscreen)
|
||||
if (fullscreen) {
|
||||
c->prev = c->geom;
|
||||
resize(c, c->mon->m, 0);
|
||||
@@ -94,7 +108,7 @@ index a2711f6..7be05ef 100644
|
||||
}
|
||||
arrange(c->mon);
|
||||
printstatus();
|
||||
@@ -2739,6 +2770,12 @@ togglefullscreen(const Arg *arg)
|
||||
@@ -2739,6 +2781,12 @@ togglefullscreen(const Arg *arg)
|
||||
setfullscreen(sel, !sel->isfullscreen);
|
||||
}
|
||||
|
||||
@@ -107,16 +121,24 @@ index a2711f6..7be05ef 100644
|
||||
void
|
||||
toggletag(const Arg *arg)
|
||||
{
|
||||
@@ -2809,6 +2846,9 @@ unmapnotify(struct wl_listener *listener, void *data)
|
||||
@@ -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(selmon, 0);
|
||||
+ if (c->isfullscreen)
|
||||
+ set_adaptive_sync(lastmon, 0);
|
||||
|
||||
wlr_scene_node_destroy(&c->scene->node);
|
||||
printstatus();
|
||||
--
|
||||
2.45.2
|
||||
2.53.0
|
||||
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
From 60af6f9dab09710234475b51393a104c21918db3 Mon Sep 17 00:00:00 2001
|
||||
From: julmajustus <julmajustus@tutanota.com>
|
||||
Date: Mon, 18 May 2026 00:12:31 +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 8a6eda0..06b3153 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -138,6 +138,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 44f3ad9..737f089 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -319,6 +319,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);
|
||||
@@ -336,6 +337,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);
|
||||
@@ -436,6 +438,8 @@ static struct wl_listener request_start_drag = {.notify = requeststartdrag};
|
||||
static struct wl_listener start_drag = {.notify = startdrag};
|
||||
static struct wl_listener new_session_lock = {.notify = locksession};
|
||||
|
||||
+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);
|
||||
@@ -2296,6 +2300,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)
|
||||
{
|
||||
@@ -2359,10 +2399,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();
|
||||
@@ -2760,6 +2802,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)
|
||||
{
|
||||
@@ -2815,6 +2863,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;
|
||||
@@ -2830,6 +2879,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
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
From cf817259dbb1235d1ffc073d4e0f128676552666 Mon Sep 17 00:00:00 2001
|
||||
From: julmajustus <julmajustus@tutanota.com>
|
||||
Date: Mon, 18 May 2026 00:15:18 +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 8a6eda0..06b3153 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -138,6 +138,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 8101ffa..2f1c80b 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -323,6 +323,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);
|
||||
@@ -440,6 +442,8 @@ static struct wl_listener request_start_drag = {.notify = requeststartdrag};
|
||||
static struct wl_listener start_drag = {.notify = startdrag};
|
||||
static struct wl_listener new_session_lock = {.notify = locksession};
|
||||
|
||||
+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);
|
||||
@@ -2300,6 +2304,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)
|
||||
{
|
||||
@@ -2363,10 +2403,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();
|
||||
@@ -2767,6 +2809,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)
|
||||
{
|
||||
@@ -2822,6 +2870,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;
|
||||
@@ -2837,6 +2886,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
|
||||
|
||||
@@ -4,16 +4,19 @@ Arranges windows in a grid. Except it adjusts the number of windows in the first
|
||||
On widescreens (w > 2*h), it splits to three columns before splitting rows.
|
||||
|
||||
### Download
|
||||
- [2024-09-18](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/gaplessgrid/gaplessgrid.patch)
|
||||
- [v0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/gaplessgrid/gaplessgrid.patch)
|
||||
- [2025-10-31](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/gaplessgrid/gaplessgrid-20251031.patch)
|
||||
- [2024-09-18](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/gaplessgrid/gaplessgrid-20240918.patch)
|
||||
- [2024-07-14](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/gaplessgrid/gaplessgrid-20240714.patch)
|
||||
- [2023-08-01](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/gaplessgrid/gaplessgrid-20230801.patch)
|
||||
- [git branch](https://codeberg.org/dhruva_sambrani/dwl/src/branch/gaplessgrid)
|
||||
- [git branch](https://codeberg.org/Kana/dwl/src/branch/gaplessgrid)
|
||||
|
||||
## Pre-codeberg
|
||||
- [2023-11-14](https://github.com/djpohly/dwl/compare/main...Sneethe:gaplessgrid.patch)
|
||||
- [2021-07-27](https://github.com/djpohly/dwl/compare/main...vnepogodin:gaplessgrid.patch)
|
||||
|
||||
### Authors
|
||||
- [André Desgualdo Pereira](https://codeberg.org/Kana)
|
||||
- [Dhruva Sambrani](https://codeberg.org/dhruva_sambrani/) (Revived to codeberg)
|
||||
- [Sneethe](https://github.com/Sneethe/)
|
||||
- [Vladislav Nepogodin](https://github.com/vnepogodin)
|
||||
- [Dhruva Sambrani](https://codeberg.org/dhruva_sambrani/) (Revived to codeberg)
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 22d2171..014a909 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -34,6 +34,7 @@ static const Layout layouts[] = {
|
||||
{ "[]=", tile },
|
||||
{ "><>", NULL }, /* no layout function means floating behavior */
|
||||
{ "[M]", monocle },
|
||||
+ { "###", gaplessgrid },
|
||||
};
|
||||
|
||||
/* monitors */
|
||||
@@ -139,6 +140,7 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
|
||||
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
|
||||
+ { MODKEY, XKB_KEY_g, setlayout, {.v = &layouts[3]} },
|
||||
{ MODKEY, XKB_KEY_space, setlayout, {0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
|
||||
{ MODKEY, XKB_KEY_e, togglefullscreen, {0} },
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index dc0c861..875d8cd 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -292,6 +292,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 gaplessgrid(Monitor *m);
|
||||
static void handlesig(int signo);
|
||||
static void incnmaster(const Arg *arg);
|
||||
static void inputdevice(struct wl_listener *listener, void *data);
|
||||
@@ -1510,6 +1511,56 @@ handlesig(int signo)
|
||||
}
|
||||
}
|
||||
|
||||
+void
|
||||
+gaplessgrid(Monitor *m)
|
||||
+{
|
||||
+ unsigned int n = 0, i = 0, ch, cw, cn, rn, rows, cols;
|
||||
+ Client *c;
|
||||
+
|
||||
+ wl_list_for_each(c, &clients, link)
|
||||
+ if (VISIBLEON(c, m) && !c->isfloating)
|
||||
+ n++;
|
||||
+ if (n == 0)
|
||||
+ return;
|
||||
+
|
||||
+ /* grid dimensions */
|
||||
+ for (cols = 0; cols <= (n / 2); cols++)
|
||||
+ if ((cols * cols) >= n)
|
||||
+ break;
|
||||
+
|
||||
+ if (n == 5) /* set layout against the general calculation: not 1:2:2, but 2:3 */
|
||||
+ cols = 2;
|
||||
+
|
||||
+ /* widescreen is better if 3 columns */
|
||||
+ if (n >= 3 && n <= 6 && (m->w.width / m->w.height) > 1)
|
||||
+ cols = 3;
|
||||
+
|
||||
+ rows = n / cols;
|
||||
+
|
||||
+ /* window geometries */
|
||||
+ cw = cols ? m->w.width / cols : m->w.width;
|
||||
+ cn = 0; /* current column number */
|
||||
+ rn = 0; /* current row number */
|
||||
+ wl_list_for_each(c, &clients, link) {
|
||||
+ unsigned int cx, cy;
|
||||
+ if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||
+ continue;
|
||||
+
|
||||
+ if ((i / rows + 1) > (cols - n % cols))
|
||||
+ rows = n / cols + 1;
|
||||
+ ch = rows ? m->w.height / rows : m->w.height;
|
||||
+ cx = m->w.x + cn * cw;
|
||||
+ cy = m->w.y + rn * ch;
|
||||
+ resize(c, (struct wlr_box) { cx, cy, cw, ch}, 0);
|
||||
+ rn++;
|
||||
+ if (rn >= rows) {
|
||||
+ rn = 0;
|
||||
+ cn++;
|
||||
+ }
|
||||
+ i++;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
incnmaster(const Arg *arg)
|
||||
{
|
||||
@@ -0,0 +1,102 @@
|
||||
From 38427b81367e8b4d2aad708a1d463bc793aac65e Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Andr=C3=A9=20Desgualdo=20Pereira?= <desgua@gmail.com>
|
||||
Date: Fri, 31 Oct 2025 15:46:48 -0300
|
||||
Subject: [PATCH] take on gaplessgrid and fix minor indentation and typos
|
||||
|
||||
---
|
||||
config.def.h | 2 ++
|
||||
dwl.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 53 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 95c2afa..2054107 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -34,6 +34,7 @@ static const Layout layouts[] = {
|
||||
{ "[]=", tile },
|
||||
{ "><>", NULL }, /* no layout function means floating behavior */
|
||||
{ "[M]", monocle },
|
||||
+ { "###", gaplessgrid },
|
||||
};
|
||||
|
||||
/* monitors */
|
||||
@@ -139,6 +140,7 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
|
||||
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
|
||||
+ { MODKEY, XKB_KEY_g, setlayout, {.v = &layouts[3]} },
|
||||
{ MODKEY, XKB_KEY_space, setlayout, {0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
|
||||
{ MODKEY, XKB_KEY_e, togglefullscreen, {0} },
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 12f441e..7ab5323 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -288,6 +288,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 gaplessgrid(Monitor *m);
|
||||
static void handlesig(int signo);
|
||||
static void incnmaster(const Arg *arg);
|
||||
static void inputdevice(struct wl_listener *listener, void *data);
|
||||
@@ -1566,6 +1567,56 @@ handlesig(int signo)
|
||||
quit(NULL);
|
||||
}
|
||||
|
||||
+void
|
||||
+gaplessgrid(Monitor *m)
|
||||
+{
|
||||
+ int n = 0, i = 0, ch, cw, cn, rn, rows, cols;
|
||||
+ Client *c;
|
||||
+
|
||||
+ wl_list_for_each(c, &clients, link)
|
||||
+ if (VISIBLEON(c, m) && !c->isfloating)
|
||||
+ n++;
|
||||
+ if (n == 0)
|
||||
+ return;
|
||||
+
|
||||
+ /* grid dimensions */
|
||||
+ for (cols = 0; cols <= (n / 2); cols++)
|
||||
+ if ((cols * cols) >= n)
|
||||
+ break;
|
||||
+
|
||||
+ if (n == 5) /* set layout against the general calculation: not 1:2:2, but 2:3 */
|
||||
+ cols = 2;
|
||||
+
|
||||
+ /* widescreen is better if 3 columns */
|
||||
+ if (n >= 3 && n <= 6 && (m->w.width / m->w.height) > 1)
|
||||
+ cols = 3;
|
||||
+
|
||||
+ rows = n / cols;
|
||||
+
|
||||
+ /* window geometries */
|
||||
+ cw = cols ? m->w.width / cols : m->w.width;
|
||||
+ cn = 0; /* current column number */
|
||||
+ rn = 0; /* current row number */
|
||||
+ wl_list_for_each(c, &clients, link) {
|
||||
+ unsigned int cx, cy;
|
||||
+ if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||
+ continue;
|
||||
+
|
||||
+ if ((i / rows + 1) > (cols - n % cols))
|
||||
+ rows = n / cols + 1;
|
||||
+ ch = rows ? m->w.height / rows : m->w.height;
|
||||
+ cx = m->w.x + cn * cw;
|
||||
+ cy = m->w.y + rn * ch;
|
||||
+ resize(c, (struct wlr_box) { cx, cy, cw, ch}, 0);
|
||||
+ rn++;
|
||||
+ if (rn >= rows) {
|
||||
+ rn = 0;
|
||||
+ cn++;
|
||||
+ }
|
||||
+ i++;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
incnmaster(const Arg *arg)
|
||||
{
|
||||
--
|
||||
2.51.0
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
From 91d34b1c664fe273a82eb7ff01e92b828feab5a9 Mon Sep 17 00:00:00 2001
|
||||
From: nate zhou <gnuunixchad@outlook.com>
|
||||
Date: Sat, 28 Feb 2026 21:42:04 +0800
|
||||
Subject: [PATCH] Patch: gaplessgrid.patch
|
||||
|
||||
---
|
||||
config.def.h | 2 ++
|
||||
dwl.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 53 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 22d2171..014a909 100644
|
||||
index 8a6eda0..8cb1782 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -34,6 +34,7 @@ static const Layout layouts[] = {
|
||||
@@ -33,6 +33,7 @@ static const Layout layouts[] = {
|
||||
{ "[]=", tile },
|
||||
{ "><>", NULL }, /* no layout function means floating behavior */
|
||||
{ "[M]", monocle },
|
||||
@@ -10,19 +20,19 @@ index 22d2171..014a909 100644
|
||||
};
|
||||
|
||||
/* monitors */
|
||||
@@ -139,6 +140,7 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
|
||||
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
|
||||
+ { MODKEY, XKB_KEY_g, setlayout, {.v = &layouts[3]} },
|
||||
{ MODKEY, XKB_KEY_space, setlayout, {0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
|
||||
{ MODKEY, XKB_KEY_e, togglefullscreen, {0} },
|
||||
@@ -135,6 +136,7 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
|
||||
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
|
||||
+ { MODKEY, XKB_KEY_g, setlayout, {.v = &layouts[3]} },
|
||||
{ MODKEY, XKB_KEY_space, setlayout, {0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
|
||||
{ MODKEY, XKB_KEY_e, togglefullscreen, {0} },
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index dc0c861..875d8cd 100644
|
||||
index 44f3ad9..83c053f 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -292,6 +292,7 @@ static void focusstack(const Arg *arg);
|
||||
@@ -288,6 +288,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);
|
||||
@@ -30,14 +40,14 @@ index dc0c861..875d8cd 100644
|
||||
static void handlesig(int signo);
|
||||
static void incnmaster(const Arg *arg);
|
||||
static void inputdevice(struct wl_listener *listener, void *data);
|
||||
@@ -1510,6 +1511,56 @@ handlesig(int signo)
|
||||
}
|
||||
@@ -1566,6 +1567,56 @@ handlesig(int signo)
|
||||
quit(NULL);
|
||||
}
|
||||
|
||||
+void
|
||||
+gaplessgrid(Monitor *m)
|
||||
+{
|
||||
+ unsigned int n = 0, i = 0, ch, cw, cn, rn, rows, cols;
|
||||
+ int n = 0, i = 0, ch, cw, cn, rn, rows, cols;
|
||||
+ Client *c;
|
||||
+
|
||||
+ wl_list_for_each(c, &clients, link)
|
||||
@@ -54,12 +64,12 @@ index dc0c861..875d8cd 100644
|
||||
+ if (n == 5) /* set layout against the general calculation: not 1:2:2, but 2:3 */
|
||||
+ cols = 2;
|
||||
+
|
||||
+ /* widescreen is better if 3 columns */
|
||||
+ if (n >= 3 && n <= 6 && (m->w.width / m->w.height) > 1)
|
||||
+ cols = 3;
|
||||
+ /* widescreen is better if 3 columns */
|
||||
+ if (n >= 3 && n <= 6 && (m->w.width / m->w.height) > 1)
|
||||
+ cols = 3;
|
||||
+
|
||||
+ rows = n / cols;
|
||||
+
|
||||
+
|
||||
+ /* window geometries */
|
||||
+ cw = cols ? m->w.width / cols : m->w.width;
|
||||
+ cn = 0; /* current column number */
|
||||
@@ -87,3 +97,6 @@ index dc0c861..875d8cd 100644
|
||||
void
|
||||
incnmaster(const Arg *arg)
|
||||
{
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
@@ -15,10 +15,11 @@ gaps to be as big or bigger than "inner" gaps anyway.
|
||||
|
||||
### Download
|
||||
|
||||
- [0.7 2025-02-11](/dwl/dwl-patches/raw/branch/main/patches/genericgaps/genericgaps-0.7.patch):
|
||||
- [0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/genericgaps/genericgaps.patch)
|
||||
- [0.7 2025-02-11](https://codeberg.org/dwl/dwl-patches/raw/commit/58e371fcb31bde1e55f99498a77afd9b567a30c8/patches/genericgaps/genericgaps-0.7.patch):
|
||||
added support for `smartgaps` and `monoclegaps` settings and removed the suck
|
||||
from `arrange()` function
|
||||
- [0.7](/dwl/dwl-patches/raw/branch/main/patches/genericgaps/genericgaps.patch)
|
||||
- [0.7](https://codeberg.org/dwl/dwl-patches/raw/commit/f8d1cfad116c19c01593f7436468ec0cb7a3297b/patches/genericgaps/genericgaps.patch)
|
||||
|
||||
### Authors
|
||||
|
||||
|
||||
@@ -1,23 +1,25 @@
|
||||
From f2a1b84369266d252fbea57c6f1eb64253617452 Mon Sep 17 00:00:00 2001
|
||||
From: Nikita Ivanov <nikita.vyach.ivanov@gmail.com>
|
||||
Date: Thu, 12 Dec 2024 22:44:53 +0100
|
||||
Subject: [PATCH] Add genericgaps
|
||||
From ac0b983fef16eb904b77d6b5e98bd61f5cf719f5 Mon Sep 17 00:00:00 2001
|
||||
From: nate zhou <gnuunixchad@outlook.com>
|
||||
Date: Sat, 28 Feb 2026 23:28:08 +0800
|
||||
Subject: [PATCH] Patch: genericgaps-0.8.patch
|
||||
|
||||
---
|
||||
config.def.h | 22 +++++++
|
||||
dwl.c | 171 ++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 190 insertions(+), 3 deletions(-)
|
||||
config.def.h | 23 ++++++
|
||||
dwl.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 220 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 22d2171..930af12 100644
|
||||
index 8a6eda0..4adc866 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -7,6 +7,12 @@
|
||||
@@ -6,7 +6,14 @@
|
||||
/* appearance */
|
||||
static const int sloppyfocus = 1; /* focus follows mouse */
|
||||
static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */
|
||||
static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
+static const int enablegaps = 1; /* 1 means gaps are enabled */
|
||||
+static const int smartgaps = 0; /* 1 means no outer gap when there is only one window */
|
||||
+static const int monoclegaps = 0; /* 1 means outer gaps in monocle layout */
|
||||
static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
+static const unsigned int gappih = 10; /* horiz inner gap between windows */
|
||||
+static const unsigned int gappiv = 10; /* vert inner gap between windows */
|
||||
+static const unsigned int gappoh = 10; /* horiz outer gap between windows and screen edge */
|
||||
@@ -25,45 +27,38 @@ index 22d2171..930af12 100644
|
||||
static const float rootcolor[] = COLOR(0x222222ff);
|
||||
static const float bordercolor[] = COLOR(0x444444ff);
|
||||
static const float focuscolor[] = COLOR(0x005577ff);
|
||||
@@ -133,6 +139,22 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_d, incnmaster, {.i = -1} },
|
||||
{ MODKEY, XKB_KEY_h, setmfact, {.f = -0.05f} },
|
||||
{ MODKEY, XKB_KEY_l, setmfact, {.f = +0.05f} },
|
||||
+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_h, incgaps, {.i = +1 } },
|
||||
+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_l, incgaps, {.i = -1 } },
|
||||
+ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT, XKB_KEY_H, incogaps, {.i = +1 } },
|
||||
+ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT, XKB_KEY_L, incogaps, {.i = -1 } },
|
||||
+ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_CTRL, XKB_KEY_h, incigaps, {.i = +1 } },
|
||||
+ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_CTRL, XKB_KEY_l, incigaps, {.i = -1 } },
|
||||
+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_0, togglegaps, {0} },
|
||||
+ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT, XKB_KEY_parenright,defaultgaps, {0} },
|
||||
+ { MODKEY, XKB_KEY_y, incihgaps, {.i = +1 } },
|
||||
+ { MODKEY, XKB_KEY_o, incihgaps, {.i = -1 } },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_y, incivgaps, {.i = +1 } },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_o, incivgaps, {.i = -1 } },
|
||||
+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_y, incohgaps, {.i = +1 } },
|
||||
+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_o, incohgaps, {.i = -1 } },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Y, incovgaps, {.i = +1 } },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_O, incovgaps, {.i = -1 } },
|
||||
{ MODKEY, XKB_KEY_Return, zoom, {0} },
|
||||
{ MODKEY, XKB_KEY_Tab, view, {0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_C, killclient, {0} },
|
||||
@@ -129,6 +136,22 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_d, incnmaster, {.i = -1} },
|
||||
{ MODKEY, XKB_KEY_h, setmfact, {.f = -0.05f} },
|
||||
{ MODKEY, XKB_KEY_l, setmfact, {.f = +0.05f} },
|
||||
+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_h, incgaps, {.i = +1 } },
|
||||
+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_l, incgaps, {.i = -1 } },
|
||||
+ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT, XKB_KEY_H, incogaps, {.i = +1 } },
|
||||
+ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT, XKB_KEY_L, incogaps, {.i = -1 } },
|
||||
+ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_CTRL, XKB_KEY_h, incigaps, {.i = +1 } },
|
||||
+ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_CTRL, XKB_KEY_l, incigaps, {.i = -1 } },
|
||||
+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_0, togglegaps, {0} },
|
||||
+ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT, XKB_KEY_parenright,defaultgaps, {0} },
|
||||
+ { MODKEY, XKB_KEY_y, incihgaps, {.i = +1 } },
|
||||
+ { MODKEY, XKB_KEY_o, incihgaps, {.i = -1 } },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_y, incivgaps, {.i = +1 } },
|
||||
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_o, incivgaps, {.i = -1 } },
|
||||
+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_y, incohgaps, {.i = +1 } },
|
||||
+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_o, incohgaps, {.i = -1 } },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Y, incovgaps, {.i = +1 } },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_O, incovgaps, {.i = -1 } },
|
||||
{ MODKEY, XKB_KEY_Return, zoom, {0} },
|
||||
{ MODKEY, XKB_KEY_Tab, view, {0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_c, killclient, {0} },
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index def2562..c14ae43 100644
|
||||
index 44f3ad9..a3164cb 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -107,6 +107,7 @@ typedef struct Monitor Monitor;
|
||||
typedef struct {
|
||||
/* Must keep these three elements in this order */
|
||||
unsigned int type; /* XDGShell or X11* */
|
||||
+ int interact;
|
||||
struct wlr_box geom; /* layout-relative, includes border */
|
||||
Monitor *mon;
|
||||
struct wlr_scene_tree *scene;
|
||||
@@ -200,6 +201,10 @@ struct Monitor {
|
||||
@@ -197,6 +197,11 @@ struct Monitor {
|
||||
struct wlr_box w; /* window area, layout-relative */
|
||||
struct wl_list layers[4]; /* LayerSurface.link */
|
||||
const Layout *lt[2];
|
||||
+ int enablegaps; /* enable gaps, used by togglegaps */
|
||||
+ int gappih; /* horizontal gap between windows */
|
||||
+ int gappiv; /* vertical gap between windows */
|
||||
+ int gappoh; /* horizontal outer gaps */
|
||||
@@ -71,7 +66,15 @@ index def2562..c14ae43 100644
|
||||
unsigned int seltags;
|
||||
unsigned int sellt;
|
||||
uint32_t tagset[2];
|
||||
@@ -273,6 +278,7 @@ static void createpopup(struct wl_listener *listener, void *data);
|
||||
@@ -243,6 +248,7 @@ typedef struct {
|
||||
static void applybounds(Client *c, struct wlr_box *bbox);
|
||||
static void applyrules(Client *c);
|
||||
static void arrange(Monitor *m);
|
||||
+void arrangegaps(Monitor *m);
|
||||
static void arrangelayer(Monitor *m, struct wl_list *list,
|
||||
struct wlr_box *usable_area, int exclusive);
|
||||
static void arrangelayers(Monitor *m);
|
||||
@@ -271,6 +277,7 @@ static void createpopup(struct wl_listener *listener, void *data);
|
||||
static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint);
|
||||
static void cursorframe(struct wl_listener *listener, void *data);
|
||||
static void cursorwarptohint(void);
|
||||
@@ -79,7 +82,7 @@ index def2562..c14ae43 100644
|
||||
static void destroydecoration(struct wl_listener *listener, void *data);
|
||||
static void destroydragicon(struct wl_listener *listener, void *data);
|
||||
static void destroyidleinhibitor(struct wl_listener *listener, void *data);
|
||||
@@ -293,6 +299,13 @@ static void fullscreennotify(struct wl_listener *listener, void *data);
|
||||
@@ -290,6 +297,13 @@ static void fullscreennotify(struct wl_listener *listener, void *data);
|
||||
static void gpureset(struct wl_listener *listener, void *data);
|
||||
static void handlesig(int signo);
|
||||
static void incnmaster(const Arg *arg);
|
||||
@@ -93,24 +96,23 @@ index def2562..c14ae43 100644
|
||||
static void inputdevice(struct wl_listener *listener, void *data);
|
||||
static int keybinding(uint32_t mods, xkb_keysym_t sym);
|
||||
static void keypress(struct wl_listener *listener, void *data);
|
||||
@@ -320,13 +333,15 @@ static void rendermon(struct wl_listener *listener, void *data);
|
||||
static void requestdecorationmode(struct wl_listener *listener, void *data);
|
||||
static void requeststartdrag(struct wl_listener *listener, void *data);
|
||||
static void requestmonstate(struct wl_listener *listener, void *data);
|
||||
-static void resize(Client *c, struct wlr_box geo, int interact);
|
||||
+static void resizeapply(Client *c, struct wlr_box geo, int interact);
|
||||
+static void resizenoapply(Client *c, struct wlr_box geo, int interact);
|
||||
static void run(char *startup_cmd);
|
||||
static void setcursor(struct wl_listener *listener, void *data);
|
||||
@@ -310,6 +324,7 @@ static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int
|
||||
static void outputmgrtest(struct wl_listener *listener, void *data);
|
||||
static void pointerfocus(Client *c, struct wlr_surface *surface,
|
||||
double sx, double sy, uint32_t time);
|
||||
+static void preparegaps(Monitor *m);
|
||||
static void printstatus(void);
|
||||
static void powermgrsetmode(struct wl_listener *listener, void *data);
|
||||
static void quit(const Arg *arg);
|
||||
@@ -323,6 +338,7 @@ 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);
|
||||
static void setfullscreen(Client *c, int fullscreen);
|
||||
static void setgamma(struct wl_listener *listener, void *data);
|
||||
+static void setgaps(int oh, int ov, int ih, int iv);
|
||||
static void setlayout(const Arg *arg);
|
||||
static void setmfact(const Arg *arg);
|
||||
static void setmon(Client *c, Monitor *m, uint32_t newtags);
|
||||
@@ -340,6 +355,7 @@ static void tagmon(const Arg *arg);
|
||||
@@ -336,6 +352,7 @@ static void tagmon(const Arg *arg);
|
||||
static void tile(Monitor *m);
|
||||
static void togglefloating(const Arg *arg);
|
||||
static void togglefullscreen(const Arg *arg);
|
||||
@@ -118,83 +120,82 @@ index def2562..c14ae43 100644
|
||||
static void toggletag(const Arg *arg);
|
||||
static void toggleview(const Arg *arg);
|
||||
static void unlocksession(struct wl_listener *listener, void *data);
|
||||
@@ -413,6 +429,9 @@ static struct wlr_box sgeom;
|
||||
static struct wl_list mons;
|
||||
static Monitor *selmon;
|
||||
@@ -435,6 +452,7 @@ static struct wl_listener request_set_cursor_shape = {.notify = setcursorshape};
|
||||
static struct wl_listener request_start_drag = {.notify = requeststartdrag};
|
||||
static struct wl_listener start_drag = {.notify = startdrag};
|
||||
static struct wl_listener new_session_lock = {.notify = locksession};
|
||||
+static int resizelock = 0; /* do not actually resize during arrange */
|
||||
|
||||
+static int enablegaps = 1; /* enables gaps, used by togglegaps */
|
||||
+static void (*resize)(Client *c, struct wlr_box geo, int interact) = resizeapply;
|
||||
+
|
||||
#ifdef XWAYLAND
|
||||
static void activatex11(struct wl_listener *listener, void *data);
|
||||
static void associatex11(struct wl_listener *listener, void *data);
|
||||
@@ -481,9 +500,25 @@ applyrules(Client *c)
|
||||
setmon(c, mon, newtags);
|
||||
}
|
||||
|
||||
+void
|
||||
+applygaps(Client *c)
|
||||
+{
|
||||
+ struct wlr_box geom = c->geom;
|
||||
+
|
||||
+ if (!c->mon)
|
||||
+ return;
|
||||
+
|
||||
+ geom.x += c->mon->gappih + c->mon->gappoh;
|
||||
+ geom.y += c->mon->gappiv + c->mon->gappov;
|
||||
+ geom.width -= c->mon->gappih;
|
||||
+ geom.height -= c->mon->gappiv;
|
||||
+ resize(c, geom, 0);
|
||||
+}
|
||||
+
|
||||
void
|
||||
arrange(Monitor *m)
|
||||
{
|
||||
+ int save_width, save_height;
|
||||
Client *c;
|
||||
|
||||
if (!m->wlr_output->enabled)
|
||||
@@ -515,8 +550,26 @@ arrange(Monitor *m)
|
||||
@@ -537,12 +555,52 @@ arrange(Monitor *m)
|
||||
: c->scene->node.parent);
|
||||
}
|
||||
|
||||
- if (m->lt[m->sellt]->arrange)
|
||||
+ if (m->lt[m->sellt]->arrange) {
|
||||
+ save_width = m->w.width;
|
||||
+ save_height = m->w.height;
|
||||
+ if (enablegaps) {
|
||||
+ m->w.width -= m->gappih + 2 * m->gappoh;
|
||||
+ m->w.height -= m->gappiv + 2 * m->gappov;
|
||||
+ }
|
||||
+ resize = resizenoapply;
|
||||
+ preparegaps(m);
|
||||
m->lt[m->sellt]->arrange(m);
|
||||
+ wl_list_for_each(c, &clients, link) {
|
||||
+ if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||
+ continue;
|
||||
+ if (enablegaps)
|
||||
+ applygaps(c);
|
||||
+ resizeapply(c, c->geom, c->interact);
|
||||
+ }
|
||||
+ m->w.width = save_width;
|
||||
+ m->w.height = save_height;
|
||||
+ resize = resizeapply;
|
||||
+ arrangegaps(m);
|
||||
+ }
|
||||
motionnotify(0, NULL, 0, 0, 0, 0);
|
||||
checkidleinhibitor(NULL);
|
||||
}
|
||||
@@ -993,6 +1046,11 @@ createmon(struct wl_listener *listener, void *data)
|
||||
|
||||
wlr_output_state_init(&state);
|
||||
/* Initialize monitor state using configured rules */
|
||||
+void
|
||||
+arrangegaps(Monitor *m)
|
||||
+{
|
||||
+ Client *c;
|
||||
+ int n, gaps;
|
||||
+
|
||||
+ if (!m->enablegaps)
|
||||
+ return;
|
||||
+
|
||||
+ resizelock = 0;
|
||||
+
|
||||
+ n = 0;
|
||||
+ wl_list_for_each(c, &clients, link) {
|
||||
+ if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||
+ continue;
|
||||
+ n++;
|
||||
+ }
|
||||
+
|
||||
+ gaps = !(smartgaps && n == 1) &&
|
||||
+ (monoclegaps || m->lt[m->sellt]->arrange != monocle);
|
||||
+ if (gaps) {
|
||||
+ m->w.width += m->gappih + 2 * m->gappoh;
|
||||
+ m->w.height += m->gappiv + 2 * m->gappov;
|
||||
+ }
|
||||
+ wl_list_for_each(c, &clients, link) {
|
||||
+ if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||
+ continue;
|
||||
+ if (gaps) {
|
||||
+ c->geom.x += c->mon->gappih + c->mon->gappoh;
|
||||
+ c->geom.y += c->mon->gappiv + c->mon->gappov;
|
||||
+ c->geom.width -= c->mon->gappih;
|
||||
+ c->geom.height -= c->mon->gappiv;
|
||||
+ }
|
||||
+ resize(c, c->geom, 0);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int exclusive)
|
||||
{
|
||||
@@ -1055,6 +1113,12 @@ createmon(struct wl_listener *listener, void *data)
|
||||
for (i = 0; i < LENGTH(m->layers); i++)
|
||||
wl_list_init(&m->layers[i]);
|
||||
|
||||
+ m->enablegaps = enablegaps;
|
||||
+ m->gappih = gappih;
|
||||
+ m->gappiv = gappiv;
|
||||
+ m->gappoh = gappoh;
|
||||
+ m->gappov = gappov;
|
||||
+
|
||||
wlr_output_state_init(&state);
|
||||
/* Initialize monitor state using configured rules */
|
||||
m->tagset[0] = m->tagset[1] = 1;
|
||||
for (r = monrules; r < END(monrules); r++) {
|
||||
if (!r->name || strstr(wlr_output->name, r->name)) {
|
||||
@@ -1173,6 +1231,12 @@ cursorwarptohint(void)
|
||||
@@ -1237,6 +1301,12 @@ cursorwarptohint(void)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,7 +208,7 @@ index def2562..c14ae43 100644
|
||||
void
|
||||
destroydecoration(struct wl_listener *listener, void *data)
|
||||
{
|
||||
@@ -1526,6 +1590,83 @@ incnmaster(const Arg *arg)
|
||||
@@ -1575,6 +1645,83 @@ incnmaster(const Arg *arg)
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
@@ -291,31 +292,52 @@ index def2562..c14ae43 100644
|
||||
void
|
||||
inputdevice(struct wl_listener *listener, void *data)
|
||||
{
|
||||
@@ -2180,7 +2321,7 @@ requestmonstate(struct wl_listener *listener, void *data)
|
||||
}
|
||||
|
||||
void
|
||||
-resize(Client *c, struct wlr_box geo, int interact)
|
||||
+resizeapply(Client *c, struct wlr_box geo, int interact)
|
||||
{
|
||||
struct wlr_box *bbox;
|
||||
struct wlr_box clip;
|
||||
@@ -2212,6 +2353,13 @@ resize(Client *c, struct wlr_box geo, int interact)
|
||||
wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip);
|
||||
@@ -2085,6 +2232,31 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy,
|
||||
wlr_seat_pointer_notify_motion(seat, time, sx, sy);
|
||||
}
|
||||
|
||||
+void
|
||||
+resizenoapply(Client *c, struct wlr_box geo, int interact)
|
||||
+preparegaps(Monitor *m)
|
||||
+{
|
||||
+ c->geom = geo;
|
||||
+ c->interact = interact;
|
||||
+ Client *c;
|
||||
+ int n;
|
||||
+
|
||||
+ if (!m->enablegaps)
|
||||
+ return;
|
||||
+
|
||||
+ n = 0;
|
||||
+ wl_list_for_each(c, &clients, link) {
|
||||
+ if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||
+ continue;
|
||||
+ n++;
|
||||
+ }
|
||||
+
|
||||
+ resizelock = 1;
|
||||
+
|
||||
+ if ((smartgaps && n == 1) || (!monoclegaps && m->lt[m->sellt]->arrange == monocle))
|
||||
+ return;
|
||||
+
|
||||
+ m->w.width -= m->gappih + 2 * m->gappoh;
|
||||
+ m->w.height -= m->gappiv + 2 * m->gappov;
|
||||
+}
|
||||
+
|
||||
void
|
||||
run(char *startup_cmd)
|
||||
printstatus(void)
|
||||
{
|
||||
@@ -2354,6 +2502,16 @@ setgamma(struct wl_listener *listener, void *data)
|
||||
wlr_output_schedule_frame(m->wlr_output);
|
||||
@@ -2208,6 +2380,11 @@ resize(Client *c, struct wlr_box geo, int interact)
|
||||
struct wlr_box *bbox;
|
||||
struct wlr_box clip;
|
||||
|
||||
+ if (resizelock) {
|
||||
+ c->geom = geo;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
if (!c->mon || !client_surface(c)->mapped)
|
||||
return;
|
||||
|
||||
@@ -2368,6 +2545,16 @@ setfullscreen(Client *c, int fullscreen)
|
||||
printstatus();
|
||||
}
|
||||
|
||||
+void
|
||||
@@ -331,14 +353,16 @@ index def2562..c14ae43 100644
|
||||
void
|
||||
setlayout(const Arg *arg)
|
||||
{
|
||||
@@ -2741,6 +2899,13 @@ togglefullscreen(const Arg *arg)
|
||||
@@ -2760,6 +2947,15 @@ togglefullscreen(const Arg *arg)
|
||||
setfullscreen(sel, !sel->isfullscreen);
|
||||
}
|
||||
|
||||
+void
|
||||
+togglegaps(const Arg *arg)
|
||||
+{
|
||||
+ enablegaps = !enablegaps;
|
||||
+ if (!selmon)
|
||||
+ return;
|
||||
+ selmon->enablegaps = !selmon->enablegaps;
|
||||
+ arrange(selmon);
|
||||
+}
|
||||
+
|
||||
@@ -346,5 +370,5 @@ index def2562..c14ae43 100644
|
||||
toggletag(const Arg *arg)
|
||||
{
|
||||
--
|
||||
2.47.1
|
||||
2.53.0
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
### Description
|
||||
|
||||
Hide the mouse cursor when you start typing, and restore it again when the
|
||||
mouse cursor moves or a mouse button is pressed, just like
|
||||
[xbanish](https://github.com/jcs/xbanish).
|
||||
|
||||
### credits
|
||||
Some code is taken from the
|
||||
[unclutter](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/unclutter) patch.
|
||||
|
||||
### Download
|
||||
[v0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/hide-cursor-when-typing/hide-cursor-when-typing.patch)
|
||||
|
||||
### Authors
|
||||
- [unixchad](https://codeberg.org/unixchad/)
|
||||
@@ -0,0 +1,204 @@
|
||||
From a73f5a4c7dd636d999cfab15610e68e170d2f597 Mon Sep 17 00:00:00 2001
|
||||
From: nate zhou <gnuunixchad@outlook.com>
|
||||
Date: Fri, 10 Apr 2026 19:38:43 +0800
|
||||
Subject: [PATCH] Patch: hide-cursor-when-typing-0.8.patch
|
||||
|
||||
---
|
||||
config.def.h | 2 ++
|
||||
dwl.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++----
|
||||
2 files changed, 85 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 8a6eda0..6205c0a 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -102,6 +102,8 @@ LIBINPUT_CONFIG_TAP_MAP_LMR -- 1/2/3 finger tap maps to left/middle/right
|
||||
*/
|
||||
static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TAP_MAP_LRM;
|
||||
|
||||
+static const int hide_cursor_when_typing = 1;
|
||||
+
|
||||
/* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */
|
||||
#define MODKEY WLR_MODIFIER_ALT
|
||||
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 44f3ad9..7325f7a 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -288,6 +288,8 @@ 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 handlecursoractivity(void);
|
||||
+static int hidecursor(void *data);
|
||||
static void handlesig(int signo);
|
||||
static void incnmaster(const Arg *arg);
|
||||
static void inputdevice(struct wl_listener *listener, void *data);
|
||||
@@ -389,6 +391,14 @@ static struct wlr_pointer_constraint_v1 *active_constraint;
|
||||
|
||||
static struct wlr_cursor *cursor;
|
||||
static struct wlr_xcursor_manager *cursor_mgr;
|
||||
+static bool cursor_hidden = false;
|
||||
+static struct {
|
||||
+ enum wp_cursor_shape_device_v1_shape shape;
|
||||
+ struct wlr_surface *surface;
|
||||
+ int hotspot_x;
|
||||
+ int hotspot_y;
|
||||
+ struct wl_listener destroy;
|
||||
+} last_cursor;
|
||||
|
||||
static struct wlr_scene_rect *root_bg;
|
||||
static struct wlr_session_lock_manager_v1 *session_lock_mgr;
|
||||
@@ -610,6 +620,7 @@ axisnotify(struct wl_listener *listener, void *data)
|
||||
* for example when you move the scroll wheel. */
|
||||
struct wlr_pointer_axis_event *event = data;
|
||||
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
||||
+ handlecursoractivity();
|
||||
/* TODO: allow usage of scroll wheel for mousebindings, it can be implemented
|
||||
* by checking the event's orientation and the delta of the event */
|
||||
/* Notify the client with pointer focus of the axis event. */
|
||||
@@ -628,6 +639,7 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
const Button *b;
|
||||
|
||||
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
||||
+ handlecursoractivity();
|
||||
|
||||
switch (event->state) {
|
||||
case WL_POINTER_BUTTON_STATE_PRESSED:
|
||||
@@ -1566,6 +1578,33 @@ handlesig(int signo)
|
||||
quit(NULL);
|
||||
}
|
||||
|
||||
+void
|
||||
+handlecursoractivity(void)
|
||||
+{
|
||||
+ if (!cursor_hidden)
|
||||
+ return;
|
||||
+
|
||||
+ cursor_hidden = false;
|
||||
+
|
||||
+ if (last_cursor.shape) {
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr,
|
||||
+ wlr_cursor_shape_v1_name(last_cursor.shape));
|
||||
+ } else if (last_cursor.surface) {
|
||||
+ wlr_cursor_set_surface(cursor, last_cursor.surface,
|
||||
+ last_cursor.hotspot_x, last_cursor.hotspot_y);
|
||||
+ } else {
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+hidecursor(void *data)
|
||||
+{
|
||||
+ wlr_cursor_unset_image(cursor);
|
||||
+ cursor_hidden = true;
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
void
|
||||
incnmaster(const Arg *arg)
|
||||
{
|
||||
@@ -1645,6 +1684,11 @@ keypress(struct wl_listener *listener, void *data)
|
||||
|
||||
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
||||
|
||||
+ /* hide cursor when typing starts */
|
||||
+ if (hide_cursor_when_typing && !cursor_hidden && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||
+ hidecursor(NULL);
|
||||
+ }
|
||||
+
|
||||
/* On _press_ if there is no active screen locker,
|
||||
* attempt to process a compositor keybinding. */
|
||||
if (!locked && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||
@@ -1907,6 +1951,7 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
|
||||
|
||||
wlr_cursor_move(cursor, device, dx, dy);
|
||||
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
||||
+ handlecursoractivity();
|
||||
|
||||
/* Update selmon (even while dragging a window) */
|
||||
if (sloppyfocus)
|
||||
@@ -1931,7 +1976,7 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
|
||||
/* If there's no client surface under the cursor, set the cursor image to a
|
||||
* default. This is what makes the cursor image appear when you move it
|
||||
* off of a client or over its border. */
|
||||
- if (!surface && !seat->drag)
|
||||
+ if (!surface && !seat->drag && !cursor_hidden)
|
||||
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
||||
|
||||
pointerfocus(c, surface, sx, sy, time);
|
||||
@@ -2296,6 +2341,15 @@ run(char *startup_cmd)
|
||||
wl_display_run(dpy);
|
||||
}
|
||||
|
||||
+void
|
||||
+unlastcursor(struct wl_listener *listener, void *data)
|
||||
+{
|
||||
+ /* When the surface is destroyed, clear our reference to it */
|
||||
+ last_cursor.surface = NULL;
|
||||
+ wl_list_remove(&last_cursor.destroy.link);
|
||||
+ wl_list_init(&last_cursor.destroy.link);
|
||||
+}
|
||||
+
|
||||
void
|
||||
setcursor(struct wl_listener *listener, void *data)
|
||||
{
|
||||
@@ -2311,9 +2365,23 @@ setcursor(struct wl_listener *listener, void *data)
|
||||
* use the provided surface as the cursor image. It will set the
|
||||
* hardware cursor on the output that it's currently on and continue to
|
||||
* do so as the cursor moves between outputs. */
|
||||
- if (event->seat_client == seat->pointer_state.focused_client)
|
||||
- wlr_cursor_set_surface(cursor, event->surface,
|
||||
- event->hotspot_x, event->hotspot_y);
|
||||
+ if (event->seat_client == seat->pointer_state.focused_client) {
|
||||
+ last_cursor.shape = 0;
|
||||
+ last_cursor.surface = event->surface;
|
||||
+ last_cursor.hotspot_x = event->hotspot_x;
|
||||
+ last_cursor.hotspot_y = event->hotspot_y;
|
||||
+
|
||||
+ wl_list_remove(&last_cursor.destroy.link);
|
||||
+ wl_list_init(&last_cursor.destroy.link);
|
||||
+ if (event->surface) {
|
||||
+ last_cursor.destroy.notify = unlastcursor;
|
||||
+ wl_signal_add(&event->surface->events.destroy, &last_cursor.destroy);
|
||||
+ }
|
||||
+
|
||||
+ if (!cursor_hidden)
|
||||
+ wlr_cursor_set_surface(cursor, event->surface,
|
||||
+ event->hotspot_x, event->hotspot_y);
|
||||
+ }
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2325,9 +2393,14 @@ setcursorshape(struct wl_listener *listener, void *data)
|
||||
/* This can be sent by any client, so we check to make sure this one
|
||||
* actually has pointer focus first. If so, we can tell the cursor to
|
||||
* use the provided cursor shape. */
|
||||
- if (event->seat_client == seat->pointer_state.focused_client)
|
||||
- wlr_cursor_set_xcursor(cursor, cursor_mgr,
|
||||
- wlr_cursor_shape_v1_name(event->shape));
|
||||
+ if (event->seat_client == seat->pointer_state.focused_client) {
|
||||
+ last_cursor.shape = event->shape;
|
||||
+ last_cursor.surface = NULL;
|
||||
+
|
||||
+ if (!cursor_hidden)
|
||||
+ wlr_cursor_set_xcursor(cursor, cursor_mgr,
|
||||
+ wlr_cursor_shape_v1_name(event->shape));
|
||||
+ }
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2592,6 +2665,9 @@ setup(void)
|
||||
cursor = wlr_cursor_create();
|
||||
wlr_cursor_attach_output_layout(cursor, output_layout);
|
||||
|
||||
+ /* Initialize the last_cursor destroy listener link so it's safe to remove later */
|
||||
+ wl_list_init(&last_cursor.destroy.link);
|
||||
+
|
||||
/* Creates an xcursor manager, another wlroots utility which loads up
|
||||
* Xcursor themes to source cursor images from and makes sure that cursor
|
||||
* images are available at all scale factors on the screen (necessary for
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@@ -15,7 +15,7 @@ So in short:
|
||||
|
||||
#### Limitations
|
||||
Reloading the compositor will replace all functionality except for `main`, `setup`, `run` and the reload logic.
|
||||
Note that you're responsible yourself for reloading ressources like fonts, which may only get acquired once.
|
||||
Note that you're responsible yourself for reloading resources like fonts, which may only get acquired once.
|
||||
A lot of components of dwl will also only get run on a trigger (the tiling for example).
|
||||
So not every change will be immediate.
|
||||
Furthermore, any patch adding more global state to dwl cannot currently be reloaded properly since
|
||||
@@ -47,13 +47,13 @@ From the cold part there are some newly available macros:
|
||||
* `CSYM(T, v)` dynamically accesses the value of the symbol `v` of type `T` from the shared object. Use this to query values from config.h for example.
|
||||
* `LISTEN_GLOBAL(E, L)` is similar to the `LISTEN` macro. `E` is an event and `L` the name of a global
|
||||
listener. Current implementation is a bit messy and I may fix it if someone bothers me about it.
|
||||
* `UNLISTEN(L)` takes a listener and unregisteres it. This is important for reloading.
|
||||
* `UNLISTEN(L)` takes a listener and unregisters it. This is important for reloading.
|
||||
|
||||
When adding new code there are some considerations to be made. Since dwl decorates all symbols with `static` by default, we cannot access them as-is.
|
||||
C's macro system is a bit too powerful though and we use this to our advantage. We will repeatedly define and
|
||||
undefine a macro called `static` in order to replace the `static` keyword inside some sections.
|
||||
This allows us to do less refactoring and preserve a lot of the original patch compatability since we're only
|
||||
strategically adding lines. We're tring to be as minimally invasive as we can.
|
||||
This allows us to do less refactoring and preserve a lot of the original patch compatibility since we're only
|
||||
strategically adding lines. We're trying to be as minimally invasive as we can.
|
||||
As a general guide:
|
||||
* global state should be global for the cold part and `extern` in the cold part meaning it should be inside a block like this:
|
||||
```C
|
||||
@@ -87,7 +87,7 @@ Thus, we enclose them the same way we do functions:
|
||||
#ifdef HOT
|
||||
... // function definitions here
|
||||
#endif
|
||||
* enfore use of the `LISTEN_GLOBAL` and `UNLISTEN` macros (I know this sucks but what can I do, I need to get
|
||||
* enforce use of the `LISTEN_GLOBAL` and `UNLISTEN` macros (I know this sucks but what can I do, I need to get
|
||||
access to the callbacks somehow). So you want
|
||||
* `wl_list_remove(listener.link)` to become `UNLISTEN(listener)` and
|
||||
* `wl_signal_add(event, global_listener)` to become `LISTEN_GLOBAL(event, global_listener)`.
|
||||
|
||||
@@ -509,7 +509,7 @@ index def2562..1c9ab67 100644
|
||||
+ wlr_log_init(CSYM(enum wlr_log_importance, log_level), NULL);
|
||||
|
||||
/* The Wayland display is managed by libwayland. It handles accepting
|
||||
* clients from the Unix socket, manging Wayland globals, and so on. */
|
||||
* clients from the Unix socket, managing Wayland globals, and so on. */
|
||||
@@ -2454,7 +2576,7 @@ setup(void)
|
||||
|
||||
/* Initialize the scene graph used to lay out windows */
|
||||
|
||||
@@ -637,7 +637,7 @@ index 4816159..70e99be 100644
|
||||
+ wlr_log_init(CSYM(enum wlr_log_importance, log_level), NULL);
|
||||
|
||||
/* The Wayland display is managed by libwayland. It handles accepting
|
||||
* clients from the Unix socket, manging Wayland globals, and so on. */
|
||||
* clients from the Unix socket, managing Wayland globals, and so on. */
|
||||
@@ -2463,7 +2602,7 @@ setup(void)
|
||||
|
||||
/* Initialize the scene graph used to lay out windows */
|
||||
|
||||
@@ -23,8 +23,8 @@ any of these features, just disable it in `config.h`.
|
||||
|
||||
### Download
|
||||
|
||||
- [git branch](https://codeberg.org/nikitaivanov/dwl/src/branch/kblayout)
|
||||
- [0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/kblayout/kblayout.patch)
|
||||
- [0.8](/dwl/dwl-patches/raw/branch/main/patches/kblayout/kblayout-0.8.patch)
|
||||
- [0.7](/dwl/dwl-patches/raw/branch/main/patches/kblayout/kblayout-0.7.patch)
|
||||
|
||||
### Authors
|
||||
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
From c80ab5d3dacc5cf22382f88287eeba5d298be483 Mon Sep 17 00:00:00 2001
|
||||
From: Nikita Ivanov <nikita.vyach.ivanov@gmail.com>
|
||||
Date: Tue, 4 Feb 2025 23:42:10 +0100
|
||||
Subject: [PATCH] Add per client keyboard layout and status bar info
|
||||
|
||||
---
|
||||
config.def.h | 3 +++
|
||||
dwl.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 73 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 8a6eda0..09b6e57 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -13,6 +13,9 @@ static const float focuscolor[] = COLOR(0x005577ff);
|
||||
static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
||||
static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */
|
||||
+/* keyboard layout change notification for status bar */
|
||||
+static const char kblayout_file[] = "/tmp/dwl-keymap";
|
||||
+static const char *kblayout_cmd[] = {"pkill", "-RTMIN+3", "someblocks", NULL};
|
||||
|
||||
/* tagging - TAGCOUNT must be no greater than 31 */
|
||||
#define TAGCOUNT (9)
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 44f3ad9..279571b 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/backend/libinput.h>
|
||||
+#include <wlr/interfaces/wlr_keyboard.h>
|
||||
#include <wlr/render/allocator.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_alpha_modifier_v1.h>
|
||||
@@ -139,6 +140,7 @@ typedef struct {
|
||||
uint32_t tags;
|
||||
int isfloating, isurgent, isfullscreen;
|
||||
uint32_t resize; /* configure serial of a pending resize */
|
||||
+ unsigned int kblayout_idx;
|
||||
} Client;
|
||||
|
||||
typedef struct {
|
||||
@@ -291,6 +293,7 @@ static void gpureset(struct wl_listener *listener, void *data);
|
||||
static void handlesig(int signo);
|
||||
static void incnmaster(const Arg *arg);
|
||||
static void inputdevice(struct wl_listener *listener, void *data);
|
||||
+static void kblayout(KeyboardGroup *kb);
|
||||
static int keybinding(uint32_t mods, xkb_keysym_t sym);
|
||||
static void keypress(struct wl_listener *listener, void *data);
|
||||
static void keypressmod(struct wl_listener *listener, void *data);
|
||||
@@ -436,6 +439,8 @@ static struct wl_listener request_start_drag = {.notify = requeststartdrag};
|
||||
static struct wl_listener start_drag = {.notify = startdrag};
|
||||
static struct wl_listener new_session_lock = {.notify = locksession};
|
||||
|
||||
+static unsigned int kblayout_idx = -1;
|
||||
+
|
||||
#ifdef XWAYLAND
|
||||
static void activatex11(struct wl_listener *listener, void *data);
|
||||
static void associatex11(struct wl_listener *listener, void *data);
|
||||
@@ -945,6 +950,8 @@ createkeyboard(struct wlr_keyboard *keyboard)
|
||||
|
||||
/* Add the new keyboard to the group */
|
||||
wlr_keyboard_group_add_keyboard(kb_group->wlr_group, keyboard);
|
||||
+
|
||||
+ kblayout(kb_group);
|
||||
}
|
||||
|
||||
KeyboardGroup *
|
||||
@@ -1122,11 +1129,13 @@ createnotify(struct wl_listener *listener, void *data)
|
||||
/* This event is raised when a client creates a new toplevel (application window). */
|
||||
struct wlr_xdg_toplevel *toplevel = data;
|
||||
Client *c = NULL;
|
||||
+ struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat);
|
||||
|
||||
/* Allocate a Client for this surface */
|
||||
c = toplevel->base->data = ecalloc(1, sizeof(*c));
|
||||
c->surface.xdg = toplevel->base;
|
||||
c->bw = borderpx;
|
||||
+ c->kblayout_idx = kb ? kb->modifiers.group : 0;
|
||||
|
||||
LISTEN(&toplevel->base->surface->events.commit, &c->commit, commitnotify);
|
||||
LISTEN(&toplevel->base->surface->events.map, &c->map, mapnotify);
|
||||
@@ -1402,10 +1411,24 @@ dirtomon(enum wlr_direction dir)
|
||||
void
|
||||
focusclient(Client *c, int lift)
|
||||
{
|
||||
+ /* Copied from wlroots/types/wlr_keyboard_group.c */
|
||||
+ struct keyboard_group_device {
|
||||
+ struct wlr_keyboard *keyboard;
|
||||
+ struct wl_listener key;
|
||||
+ struct wl_listener modifiers;
|
||||
+ struct wl_listener keymap;
|
||||
+ struct wl_listener repeat_info;
|
||||
+ struct wl_listener destroy;
|
||||
+ struct wl_list link; // wlr_keyboard_group.devices
|
||||
+ };
|
||||
+
|
||||
struct wlr_surface *old = seat->keyboard_state.focused_surface;
|
||||
int unused_lx, unused_ly, old_client_type;
|
||||
Client *old_c = NULL;
|
||||
LayerSurface *old_l = NULL;
|
||||
+ struct keyboard_group_device *device;
|
||||
+ struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat);
|
||||
+ struct wlr_keyboard_group *group = kb ? wlr_keyboard_group_from_wlr_keyboard(kb) : NULL;
|
||||
|
||||
if (locked)
|
||||
return;
|
||||
@@ -1457,6 +1480,20 @@ focusclient(Client *c, int lift)
|
||||
}
|
||||
printstatus();
|
||||
|
||||
+ /* Update keyboard layout */
|
||||
+ if (group) {
|
||||
+ // Update the first real device, because kb or group->kb is not a real
|
||||
+ // keyboard and its effective layout gets overwritten
|
||||
+ device = wl_container_of(group->devices.next, device, link);
|
||||
+ if (device->keyboard)
|
||||
+ wlr_keyboard_notify_modifiers(device->keyboard,
|
||||
+ device->keyboard->modifiers.depressed,
|
||||
+ device->keyboard->modifiers.latched,
|
||||
+ device->keyboard->modifiers.locked,
|
||||
+ c ? c->kblayout_idx : 0
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
if (!c) {
|
||||
/* With no client, all we have left is to clear focus */
|
||||
wlr_seat_keyboard_notify_clear_focus(seat);
|
||||
@@ -1467,7 +1504,7 @@ focusclient(Client *c, int lift)
|
||||
motionnotify(0, NULL, 0, 0, 0, 0);
|
||||
|
||||
/* Have a client, so focus its top-level wlr_surface */
|
||||
- client_notify_enter(client_surface(c), wlr_seat_get_keyboard(seat));
|
||||
+ client_notify_enter(client_surface(c), kb);
|
||||
|
||||
/* Activate the new client */
|
||||
client_activate_surface(client_surface(c), 1);
|
||||
@@ -1605,6 +1642,36 @@ inputdevice(struct wl_listener *listener, void *data)
|
||||
wlr_seat_set_capabilities(seat, caps);
|
||||
}
|
||||
|
||||
+void
|
||||
+kblayout(KeyboardGroup *kb)
|
||||
+{
|
||||
+ FILE *f;
|
||||
+ Client *c;
|
||||
+ unsigned int idx = kb->wlr_group->keyboard.modifiers.group;
|
||||
+
|
||||
+ // If layout did not change, do nothing
|
||||
+ if (kblayout_idx == idx)
|
||||
+ return;
|
||||
+ kblayout_idx = idx;
|
||||
+
|
||||
+ // Update client layout
|
||||
+ if ((c = focustop(selmon)))
|
||||
+ c->kblayout_idx = kblayout_idx;
|
||||
+
|
||||
+ // Save current layout to kblayout_file
|
||||
+ if (*kblayout_file && (f = fopen(kblayout_file, "w"))) {
|
||||
+ fputs(xkb_keymap_layout_get_name(kb->wlr_group->keyboard.keymap,
|
||||
+ idx), f);
|
||||
+ fclose(f);
|
||||
+ }
|
||||
+
|
||||
+ // Run kblayout_cmd
|
||||
+ if (kblayout_cmd[0] && fork() == 0) {
|
||||
+ execvp(kblayout_cmd[0], (char *const *)kblayout_cmd);
|
||||
+ die("dwl: execvp %s failed:", kblayout_cmd[0]);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
int
|
||||
keybinding(uint32_t mods, xkb_keysym_t sym)
|
||||
{
|
||||
@@ -1683,6 +1750,8 @@ keypressmod(struct wl_listener *listener, void *data)
|
||||
/* Send modifiers to the client. */
|
||||
wlr_seat_keyboard_notify_modifiers(seat,
|
||||
&group->wlr_group->keyboard.modifiers);
|
||||
+
|
||||
+ kblayout(group);
|
||||
}
|
||||
|
||||
int
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
### Description
|
||||
A very simple patch that introduces the functionality to terminate all
|
||||
visible, unselected clients, similar to the dwm
|
||||
[killunsel](https://dwm.suckless.org/patches/killunsel/) patch.
|
||||
|
||||
|
||||
### Download
|
||||
- [main 2025-07-20](/dwl/dwl-patches/raw/branch/main/patches/killunsel/killunsel.patch)
|
||||
|
||||
### Author
|
||||
- [oli4warin](https://codeberg.org/oli4warin)
|
||||
@@ -0,0 +1,54 @@
|
||||
From 5de49db14abf96d587cbac8c041f95b3a86efb8f Mon Sep 17 00:00:00 2001
|
||||
From: Olivier Warin <wasto@gmx.ch>
|
||||
Date: Mon, 29 Sep 2025 09:55:17 +0200
|
||||
Subject: [PATCH] Add killunsel patch
|
||||
|
||||
---
|
||||
config.def.h | 1 +
|
||||
dwl.c | 11 +++++++++++
|
||||
2 files changed, 12 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 95c2afa..491d94b 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -136,6 +136,7 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_Return, zoom, {0} },
|
||||
{ MODKEY, XKB_KEY_Tab, view, {0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_C, killclient, {0} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_X, killunsel, {0} },
|
||||
{ MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
|
||||
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 12f441e..78fa8ac 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -296,6 +296,7 @@ static void keypress(struct wl_listener *listener, void *data);
|
||||
static void keypressmod(struct wl_listener *listener, void *data);
|
||||
static int keyrepeat(void *data);
|
||||
static void killclient(const Arg *arg);
|
||||
+static void killunsel(const Arg *arg);
|
||||
static void locksession(struct wl_listener *listener, void *data);
|
||||
static void mapnotify(struct wl_listener *listener, void *data);
|
||||
static void maximizenotify(struct wl_listener *listener, void *data);
|
||||
@@ -1709,6 +1710,16 @@ killclient(const Arg *arg)
|
||||
client_send_close(sel);
|
||||
}
|
||||
|
||||
+void killunsel(const Arg *arg)
|
||||
+{
|
||||
+ Client *c;
|
||||
+ wl_list_for_each(c, &clients, link)
|
||||
+ {
|
||||
+ if (c != focustop(selmon) && VISIBLEON(c, selmon))
|
||||
+ client_send_close(c);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
locksession(struct wl_listener *listener, void *data)
|
||||
{
|
||||
--
|
||||
2.51.0
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# Description
|
||||
Prevent resizing of fixed-size xdg-toplevel windows.
|
||||
|
||||
> NOTE:
|
||||
The patch works on (main 2025-12-20) and v0.7
|
||||
|
||||
# Download
|
||||
- [git branch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/lock-size/lock-size.patch)
|
||||
- [main 2025-12-20](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/lock-size/lock-size.patch)
|
||||
- [v0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/lock-size/lock-size.patch)
|
||||
|
||||
# Authors
|
||||
- [pi66](https://pi66.xyz)
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
From a622b4740ff533f0fc46923990d421bf7c0892d8 Mon Sep 17 00:00:00 2001
|
||||
From: pi66 <pixel2176@proton.me>
|
||||
Date: Sat, 20 Dec 2025 20:57:46 +0100
|
||||
Subject: [PATCH] fix: prevent resizing fixed-size xdg-toplevel clients
|
||||
|
||||
---
|
||||
dwl.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 12f441e..3a74a34 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -2210,6 +2210,12 @@ resize(Client *c, struct wlr_box geo, int interact)
|
||||
if (!c->mon || !client_surface(c)->mapped)
|
||||
return;
|
||||
|
||||
+ if (c->surface.xdg->toplevel->current.min_width==c->surface.xdg->toplevel->current.max_width)
|
||||
+ geo.width = c->geom.width;
|
||||
+
|
||||
+ if (c->surface.xdg->toplevel->current.min_height==c->surface.xdg->toplevel->current.max_height)
|
||||
+ geo.height = c->geom.height;
|
||||
+
|
||||
bbox = interact ? &sgeom : &c->mon->w;
|
||||
|
||||
client_set_bounds(c, geo.width, geo.height);
|
||||
--
|
||||
2.51.2
|
||||
|
||||
@@ -11,8 +11,9 @@ Edit `menus` array in `config.h` to add/change menus and use a different dmenu
|
||||
program (`wmenu` is the default).
|
||||
|
||||
### Download
|
||||
- [2025-03-21 v0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/menu/menu.patch)
|
||||
- [2024-07-13 v0.7](https://codeberg.org/dwl/dwl-patches/raw/commit/65ea99519bbf7a52f48932aea7385f81f8b30867/patches/menu/menu.patch)
|
||||
- [v0.8](/dwl-patches/raw/branch/main/patches/menu/menu-0.8.patch)
|
||||
- [2025-03-21 v0.7](/dwl/dwl-patches/raw/branch/main/patches/menu/menu-0.7.patch)
|
||||
- [2024-07-13 v0.7](/dwl/dwl-patches/raw/commit/65ea99519bbf7a52f48932aea7385f81f8b30867/patches/menu/menu.patch)
|
||||
|
||||
### Authors
|
||||
- [Nikita Ivanov](https://codeberg.org/nikitaivanov) ([GitHub](https://github.com/NikitaIvanovV))
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
From 4347c2fd720166c526384827ef4f586a84d22040 Mon Sep 17 00:00:00 2001
|
||||
From: Nikita Ivanov <nikita.vyach.ivanov@gmail.com>
|
||||
Date: Fri, 21 Mar 2025 21:48:42 +0100
|
||||
Subject: [PATCH] Add menu command
|
||||
|
||||
---
|
||||
config.def.h | 8 +++
|
||||
dwl.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 164 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 8a6eda0..1de52fa 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -20,6 +20,12 @@ static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You ca
|
||||
/* logging */
|
||||
static int log_level = WLR_ERROR;
|
||||
|
||||
+static const Menu menus[] = {
|
||||
+ /* command feed function action function */
|
||||
+ { "wmenu -i -l 10 -p Windows", menuwinfeed, menuwinaction },
|
||||
+ { "wmenu -i -p Layouts", menulayoutfeed, menulayoutaction },
|
||||
+};
|
||||
+
|
||||
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 */
|
||||
@@ -136,6 +142,8 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
|
||||
{ MODKEY, XKB_KEY_space, setlayout, {0} },
|
||||
+ { MODKEY, XKB_KEY_o, menu, {.v = &menus[0]} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_O, menu, {.v = &menus[1]} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
|
||||
{ MODKEY, XKB_KEY_e, togglefullscreen, {0} },
|
||||
{ MODKEY, XKB_KEY_0, view, {.ui = ~0} },
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 44f3ad9..7e0e7b6 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -239,6 +239,12 @@ typedef struct {
|
||||
struct wl_listener destroy;
|
||||
} SessionLock;
|
||||
|
||||
+typedef struct {
|
||||
+ const char *cmd; /* command to run a menu */
|
||||
+ void (*feed)(FILE *f); /* feed input to menu */
|
||||
+ void (*action)(char *line); /* do action based on menu output */
|
||||
+} Menu;
|
||||
+
|
||||
/* function declarations */
|
||||
static void applybounds(Client *c, struct wlr_box *bbox);
|
||||
static void applyrules(Client *c);
|
||||
@@ -299,6 +305,12 @@ static void killclient(const Arg *arg);
|
||||
static void locksession(struct wl_listener *listener, void *data);
|
||||
static void mapnotify(struct wl_listener *listener, void *data);
|
||||
static void maximizenotify(struct wl_listener *listener, void *data);
|
||||
+static void menu(const Arg *arg);
|
||||
+static int menuread(int fd, uint32_t mask, void *data);
|
||||
+static void menuwinfeed(FILE *f);
|
||||
+static void menuwinaction(char *line);
|
||||
+static void menulayoutfeed(FILE *f);
|
||||
+static void menulayoutaction(char *line);
|
||||
static void monocle(Monitor *m);
|
||||
static void motionabsolute(struct wl_listener *listener, void *data);
|
||||
static void motionnotify(uint32_t time, struct wlr_input_device *device, double sx,
|
||||
@@ -436,6 +448,11 @@ static struct wl_listener request_start_drag = {.notify = requeststartdrag};
|
||||
static struct wl_listener start_drag = {.notify = startdrag};
|
||||
static struct wl_listener new_session_lock = {.notify = locksession};
|
||||
|
||||
+static const Menu *menu_current;
|
||||
+static int menu_fd;
|
||||
+static pid_t menu_pid;
|
||||
+static struct wl_event_source *menu_source;
|
||||
+
|
||||
#ifdef XWAYLAND
|
||||
static void activatex11(struct wl_listener *listener, void *data);
|
||||
static void associatex11(struct wl_listener *listener, void *data);
|
||||
@@ -1820,6 +1837,145 @@ maximizenotify(struct wl_listener *listener, void *data)
|
||||
wlr_xdg_surface_schedule_configure(c->surface.xdg);
|
||||
}
|
||||
|
||||
+void
|
||||
+menu(const Arg *arg)
|
||||
+{
|
||||
+ FILE *f;
|
||||
+ int fd_right[2], fd_left[2];
|
||||
+
|
||||
+ if (menu_current != NULL) {
|
||||
+ wl_event_source_remove(menu_source);
|
||||
+ close(menu_fd);
|
||||
+ kill(menu_pid, SIGTERM);
|
||||
+ menu_current = NULL;
|
||||
+ if (!arg->v)
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (pipe(fd_right) == -1 || pipe(fd_left) == -1)
|
||||
+ return;
|
||||
+ if ((menu_pid = fork()) == -1)
|
||||
+ return;
|
||||
+ if (menu_pid == 0) {
|
||||
+ close(fd_right[1]);
|
||||
+ close(fd_left[0]);
|
||||
+ dup2(fd_right[0], STDIN_FILENO);
|
||||
+ close(fd_right[0]);
|
||||
+ dup2(fd_left[1], STDOUT_FILENO);
|
||||
+ close(fd_left[1]);
|
||||
+ execl("/bin/sh", "/bin/sh", "-c", ((Menu *)(arg->v))->cmd, NULL);
|
||||
+ die("dwl: execl %s failed:", "/bin/sh");
|
||||
+ }
|
||||
+
|
||||
+ close(fd_right[0]);
|
||||
+ close(fd_left[1]);
|
||||
+ menu_fd = fd_left[0];
|
||||
+ if (fd_set_nonblock(menu_fd) == -1)
|
||||
+ return;
|
||||
+ if (!(f = fdopen(fd_right[1], "w")))
|
||||
+ return;
|
||||
+ menu_current = arg->v;
|
||||
+ menu_current->feed(f);
|
||||
+ fclose(f);
|
||||
+ menu_source = wl_event_loop_add_fd(event_loop,
|
||||
+ menu_fd, WL_EVENT_READABLE, menuread, NULL);
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+menuread(int fd, uint32_t mask, void *data)
|
||||
+{
|
||||
+ char *s;
|
||||
+ int n;
|
||||
+ static char line[512];
|
||||
+ static int i = 0;
|
||||
+
|
||||
+ if (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR)) {
|
||||
+ i = 0;
|
||||
+ menu(&(const Arg){ .v = NULL });
|
||||
+ return 0;
|
||||
+ }
|
||||
+ if ((n = read(menu_fd, line + i, LENGTH(line) - 1 - i)) == -1) {
|
||||
+ if (errno != EAGAIN) {
|
||||
+ i = 0;
|
||||
+ menu(&(const Arg){ .v = NULL });
|
||||
+ }
|
||||
+ return 0;
|
||||
+ }
|
||||
+ line[i + n] = '\0';
|
||||
+ if (!(s = strchr(line + i, '\n'))) {
|
||||
+ i += n;
|
||||
+ return 0;
|
||||
+ }
|
||||
+ i = 0;
|
||||
+ *s = '\0';
|
||||
+ menu_current->action(line);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+menuwinfeed(FILE *f)
|
||||
+{
|
||||
+ Client *c;
|
||||
+ const char *title, *appid;
|
||||
+
|
||||
+ wl_list_for_each(c, &fstack, flink) {
|
||||
+ if (!(title = client_get_title(c)))
|
||||
+ continue;
|
||||
+ fprintf(f, "%s", title);
|
||||
+ if ((appid = client_get_appid(c)))
|
||||
+ fprintf(f, " | %s", appid);
|
||||
+ fputc('\n', f);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+menuwinaction(char *line)
|
||||
+{
|
||||
+ Client *c;
|
||||
+ const char *appid, *title;
|
||||
+ static char buf[512];
|
||||
+
|
||||
+ wl_list_for_each(c, &fstack, flink) {
|
||||
+ if (!(title = client_get_title(c)))
|
||||
+ continue;
|
||||
+ appid = client_get_appid(c);
|
||||
+ snprintf(buf, LENGTH(buf) - 1, "%s%s%s",
|
||||
+ title, appid ? " | " : "", appid ? appid : "");
|
||||
+ if (strcmp(line, buf) == 0)
|
||||
+ goto found;
|
||||
+ }
|
||||
+ return;
|
||||
+
|
||||
+found:
|
||||
+ if (!c->mon)
|
||||
+ return;
|
||||
+ wl_list_remove(&c->flink);
|
||||
+ wl_list_insert(&fstack, &c->flink);
|
||||
+ selmon = c->mon;
|
||||
+ view(&(const Arg){ .ui = c->tags });
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+menulayoutfeed(FILE *f)
|
||||
+{
|
||||
+ const Layout *l;
|
||||
+ for (l = layouts; l < END(layouts); l++)
|
||||
+ fprintf(f, "%s\n", l->symbol);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+menulayoutaction(char *line)
|
||||
+{
|
||||
+ const Layout *l;
|
||||
+ for (l = layouts; l < END(layouts); l++)
|
||||
+ if (strcmp(line, l->symbol) == 0)
|
||||
+ goto found;
|
||||
+ return;
|
||||
+
|
||||
+found:
|
||||
+ setlayout(&(const Arg){ .v = l });
|
||||
+}
|
||||
+
|
||||
void
|
||||
monocle(Monitor *m)
|
||||
{
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@@ -63,7 +63,8 @@ index 34397fc..f1b31ea 100644
|
||||
|
||||
### Download
|
||||
|
||||
- [v0.7](/dwl/dwl-patches/raw/branch/main/patches/menurule/menurule.patch)
|
||||
- [0.8](/dwl/dwl-patches/raw/branch/main/patches/menurule/menurule-0.8.patch)
|
||||
- [0.7](/dwl/dwl-patches/raw/branch/main/patches/menurule/menurule-0.7.patch)
|
||||
|
||||
### Authors
|
||||
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
From ffbc9d95316ec42e3f8e08816bfcf7b91a6801b6 Mon Sep 17 00:00:00 2001
|
||||
From: Nikita Ivanov <nikita.vyach.ivanov@gmail.com>
|
||||
Date: Wed, 19 Mar 2025 02:28:46 +0100
|
||||
Subject: [PATCH] Add menurule to tweak rules at runtime
|
||||
|
||||
---
|
||||
config.def.h | 2 +
|
||||
dwl.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 120 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 77a72a5..e7601a4 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -24,6 +24,7 @@ static const Menu menus[] = {
|
||||
/* command feed function action function */
|
||||
{ "wmenu -i -l 10 -p Windows", menuwinfeed, menuwinaction },
|
||||
{ "wmenu -i -p Layouts", menulayoutfeed, menulayoutaction },
|
||||
+ { "wmenu -i -l 10 -p Rules", menurulefeed, menuruleaction },
|
||||
};
|
||||
|
||||
/* Max amount of dynamically added rules */
|
||||
@@ -147,6 +148,7 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_space, setlayout, {0} },
|
||||
{ MODKEY, XKB_KEY_o, menu, {.v = &menus[0]} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_O, menu, {.v = &menus[1]} },
|
||||
+ { MODKEY, XKB_KEY_r, menu, {.v = &menus[2]} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
|
||||
{ MODKEY, XKB_KEY_e, togglefullscreen, {0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_R, setruleisfloating,{0} },
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 3d65e16..49daddb 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -312,6 +312,8 @@ static void menuwinfeed(FILE *f);
|
||||
static void menuwinaction(char *line);
|
||||
static void menulayoutfeed(FILE *f);
|
||||
static void menulayoutaction(char *line);
|
||||
+static void menurulefeed(FILE *f);
|
||||
+static void menuruleaction(char *line);
|
||||
static void monocle(Monitor *m);
|
||||
static void motionabsolute(struct wl_listener *listener, void *data);
|
||||
static void motionnotify(uint32_t time, struct wlr_input_device *device, double sx,
|
||||
@@ -2026,6 +2028,122 @@ found:
|
||||
setlayout(&(const Arg){ .v = l });
|
||||
}
|
||||
|
||||
+void
|
||||
+menurulefeed(FILE *f)
|
||||
+{
|
||||
+ Rule t, *p, *r;
|
||||
+ const char *appid, *title;
|
||||
+ static char buf[515];
|
||||
+ Client *c = focustop(selmon);
|
||||
+ int n, wid = 0, match;
|
||||
+
|
||||
+ t = (Rule){ 0 };
|
||||
+ t.monitor = -1;
|
||||
+ if (c) {
|
||||
+ t.id = appid = client_get_appid(c);
|
||||
+ t.title = title = client_get_title(c);
|
||||
+ if (strcmp(t.id, "broken") == 0)
|
||||
+ t.id = NULL;
|
||||
+ if (strcmp(t.title, "broken") == 0)
|
||||
+ t.title = NULL;
|
||||
+ }
|
||||
+
|
||||
+ for (p = drules; p <= drules + druleslen; p++) {
|
||||
+ r = (p == drules + druleslen) ? &t : p;
|
||||
+ n = 0;
|
||||
+ n += strlen(r->id ? r->id : "NULL");
|
||||
+ n += strlen(r->title ? r->title : "NULL");
|
||||
+ n += 3;
|
||||
+ wid = MAX(wid, n);
|
||||
+ }
|
||||
+ wid = MIN(wid, 40);
|
||||
+
|
||||
+ for (p = drules; p <= drules + druleslen; p++) {
|
||||
+ match = 0;
|
||||
+ /* Check if rule applies to the focused client */
|
||||
+ if (c && p < drules + druleslen) {
|
||||
+ match = (!p->title || strstr(title, p->title))
|
||||
+ && (!p->id || strstr(appid, p->id));
|
||||
+ if (match && p->id)
|
||||
+ t.id = NULL;
|
||||
+ if (match && p->title)
|
||||
+ t.title = NULL;
|
||||
+ }
|
||||
+ r = (p == drules + druleslen) ? &t : p;
|
||||
+ if (r == &t && t.id)
|
||||
+ t.title = NULL;
|
||||
+ /* Do not suggest to add a new empty rule */
|
||||
+ if (r == &t && !(t.id || t.title))
|
||||
+ continue;
|
||||
+ if (r->id && r->title &&
|
||||
+ strcmp(r->id, "removedrule") == 0 && strcmp(r->title, "removedrule") == 0)
|
||||
+ continue;
|
||||
+ snprintf(buf, LENGTH(buf) - 1, "[%s|%s]",
|
||||
+ r->id ? r->id : "NULL", r->title ? r->title : "NULL");
|
||||
+ fprintf(f, "%-*s "
|
||||
+ " tags:%-4"PRIi32
|
||||
+ " isfloating:%-2d"
|
||||
+ " monitor:%-2d"
|
||||
+ "%s\n", wid, buf,
|
||||
+ r->tags,
|
||||
+ r->isfloating,
|
||||
+ r->monitor,
|
||||
+ (r == &t) ? " (NEW)" : match ? " <" : "");
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+menuruleaction(char *line)
|
||||
+{
|
||||
+ Rule r, *f;
|
||||
+ static char appid[256], title[256];
|
||||
+ int del = 0, end;
|
||||
+
|
||||
+ if (line[0] == '-') {
|
||||
+ del = 1;
|
||||
+ line++;
|
||||
+ }
|
||||
+ end = 0;
|
||||
+ sscanf(line, "[%255[^|]|%255[^]]]"
|
||||
+ " tags:%"SCNu32
|
||||
+ " isfloating:%d"
|
||||
+ " monitor:%d"
|
||||
+ "%n", appid, title,
|
||||
+ &r.tags,
|
||||
+ &r.isfloating,
|
||||
+ &r.monitor,
|
||||
+ &end);
|
||||
+
|
||||
+ /* Full line was not parsed, exit */
|
||||
+ if (!end)
|
||||
+ return;
|
||||
+
|
||||
+ r.id = (strcmp(appid, "NULL") != 0) ? appid : NULL;
|
||||
+ r.title = (strcmp(title, "NULL") != 0) ? title : NULL;
|
||||
+
|
||||
+ /* Find which rule we are trying to edit */
|
||||
+ for (f = drules; f < drules + druleslen; f++)
|
||||
+ if (((!r.title && !f->title) || (r.title && f->title && !strcmp(r.title, f->title)))
|
||||
+ && (((!r.id && !f->id) || (r.id && f->id && !strcmp(r.id, f->id)))))
|
||||
+ goto found;
|
||||
+
|
||||
+ if (druleslen >= LENGTH(rules) + RULES_MAX)
|
||||
+ return; /* No free slots left */
|
||||
+
|
||||
+ f = drules + druleslen++;
|
||||
+ f->id = r.id ? strdup(r.id) : NULL;
|
||||
+ f->title = r.title ? strdup(r.title) : NULL;
|
||||
+
|
||||
+found:
|
||||
+ if (del) {
|
||||
+ f->id = f->title = "removedrule";
|
||||
+ return;
|
||||
+ }
|
||||
+ r.id = f->id;
|
||||
+ r.title = f->title;
|
||||
+ *f = r;
|
||||
+}
|
||||
+
|
||||
void
|
||||
monocle(Monitor *m)
|
||||
{
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@@ -7,7 +7,7 @@ To enable Xwayland support, you will need to enable it in the wlroots subproject
|
||||
```sh
|
||||
meson setup -Dwlroots:xwayland=enabled build
|
||||
```
|
||||
It is also reccomended to see the wlroots meson project configuration logs for any
|
||||
It is also recommended to see the wlroots meson project configuration logs for any
|
||||
unusual checks, such as requiring `hwdata` for the DRM backend.
|
||||
|
||||
### Download
|
||||
|
||||
@@ -28,8 +28,10 @@ static const Modekey modekeys[] = {
|
||||
```
|
||||
|
||||
### Download
|
||||
- [v0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/modes/modes.patch)
|
||||
- [git branch](https://codeberg.org/wochap/dwl/src/branch/v0.5/modes)
|
||||
- [v0.5](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/modes/modes.patch)
|
||||
- [v0.5](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/modes/modes-0.5.patch)
|
||||
|
||||
### Authors
|
||||
- [unixchad](https://codeberg.org/unixchad)
|
||||
- [wochap](https://codeberg.org/wochap)
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
From a32b85018ff2cea0fc9f9137789860a4aadc3b3a Mon Sep 17 00:00:00 2001
|
||||
From: wochap <gean.marroquin@gmail.com>
|
||||
Date: Wed, 6 Mar 2024 07:31:17 -0500
|
||||
Subject: [PATCH] implement modes
|
||||
|
||||
like sway/river modes
|
||||
---
|
||||
config.def.h | 20 ++++++++++++++++++++
|
||||
dwl.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 66 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index db0babc..1616136 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -13,6 +13,13 @@ static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||
/* To conform the xdg-protocol, set the alpha to zero to restore the old behavior */
|
||||
static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; /* You can also use glsl colors */
|
||||
|
||||
+enum {
|
||||
+ BROWSER,
|
||||
+};
|
||||
+const char *modes_labels[] = {
|
||||
+ "browser",
|
||||
+};
|
||||
+
|
||||
/* tagging - TAGCOUNT must be no greater than 31 */
|
||||
#define TAGCOUNT (9)
|
||||
|
||||
@@ -152,6 +159,8 @@ static const Key keys[] = {
|
||||
TAGKEYS( XKB_KEY_9, XKB_KEY_parenleft, 8),
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Q, quit, {0} },
|
||||
|
||||
+ { MODKEY, XKB_KEY_b, entermode, {.i = BROWSER} },
|
||||
+
|
||||
/* Ctrl-Alt-Backspace and Ctrl-Alt-Fx used to be handled by X server */
|
||||
{ WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_Terminate_Server, quit, {0} },
|
||||
/* Ctrl-Alt-Fx is used to switch to another VT, if you don't know what a VT is
|
||||
@@ -162,6 +171,17 @@ static const Key keys[] = {
|
||||
CHVT(7), CHVT(8), CHVT(9), CHVT(10), CHVT(11), CHVT(12),
|
||||
};
|
||||
|
||||
+static const Modekey modekeys[] = {
|
||||
+ /* mode modifier key function argument */
|
||||
+ { BROWSER, { 0, XKB_KEY_f, spawn, SHCMD("firefox") } },
|
||||
+ { BROWSER, { 0, XKB_KEY_f, entermode, {.i = NORMAL} } },
|
||||
+ { BROWSER, { 0, XKB_KEY_b, spawn, SHCMD("brave") } },
|
||||
+ { BROWSER, { 0, XKB_KEY_b, entermode, {.i = NORMAL} } },
|
||||
+ { BROWSER, { 0, XKB_KEY_g, spawn, SHCMD("google-chrome-stable") } },
|
||||
+ { BROWSER, { 0, XKB_KEY_g, entermode, {.i = NORMAL} } },
|
||||
+ { BROWSER, { 0, XKB_KEY_Escape, entermode, {.i = NORMAL} } },
|
||||
+};
|
||||
+
|
||||
static const Button buttons[] = {
|
||||
{ MODKEY, BTN_LEFT, moveresize, {.ui = CurMove} },
|
||||
{ MODKEY, BTN_MIDDLE, togglefloating, {0} },
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index ef27a1d..1ada006 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -139,6 +139,11 @@ typedef struct {
|
||||
const Arg arg;
|
||||
} Key;
|
||||
|
||||
+typedef struct {
|
||||
+ int mode_index;
|
||||
+ Key key;
|
||||
+} Modekey;
|
||||
+
|
||||
typedef struct {
|
||||
struct wl_list link;
|
||||
struct wlr_keyboard *wlr_keyboard;
|
||||
@@ -270,6 +275,7 @@ static void handlesig(int signo);
|
||||
static void incnmaster(const Arg *arg);
|
||||
static void inputdevice(struct wl_listener *listener, void *data);
|
||||
static int keybinding(uint32_t mods, xkb_keysym_t sym);
|
||||
+static int modekeybinding(uint32_t mods, xkb_keysym_t sym);
|
||||
static void keypress(struct wl_listener *listener, void *data);
|
||||
static void keypressmod(struct wl_listener *listener, void *data);
|
||||
static int keyrepeat(void *data);
|
||||
@@ -327,6 +333,7 @@ static Monitor *xytomon(double x, double y);
|
||||
static void xytonode(double x, double y, struct wlr_surface **psurface,
|
||||
Client **pc, LayerSurface **pl, double *nx, double *ny);
|
||||
static void zoom(const Arg *arg);
|
||||
+static void entermode(const Arg *arg);
|
||||
|
||||
/* variables */
|
||||
static const char broken[] = "broken";
|
||||
@@ -377,6 +384,9 @@ static struct wlr_box sgeom;
|
||||
static struct wl_list mons;
|
||||
static Monitor *selmon;
|
||||
|
||||
+static const int NORMAL = -1;
|
||||
+static int active_mode_index = NORMAL;
|
||||
+
|
||||
#ifdef XWAYLAND
|
||||
static void activatex11(struct wl_listener *listener, void *data);
|
||||
static void associatex11(struct wl_listener *listener, void *data);
|
||||
@@ -1372,6 +1382,11 @@ keybinding(uint32_t mods, xkb_keysym_t sym)
|
||||
*/
|
||||
int handled = 0;
|
||||
const Key *k;
|
||||
+
|
||||
+ if (active_mode_index >= 0) {
|
||||
+ return modekeybinding(mods, sym);
|
||||
+ }
|
||||
+
|
||||
for (k = keys; k < END(keys); k++) {
|
||||
if (CLEANMASK(mods) == CLEANMASK(k->mod) &&
|
||||
sym == k->keysym && k->func) {
|
||||
@@ -1382,6 +1397,29 @@ keybinding(uint32_t mods, xkb_keysym_t sym)
|
||||
return handled;
|
||||
}
|
||||
|
||||
+int
|
||||
+modekeybinding(uint32_t mods, xkb_keysym_t sym)
|
||||
+{
|
||||
+ int handled = 0;
|
||||
+ const Modekey *mk;
|
||||
+ const Key *k;
|
||||
+
|
||||
+ for (mk = modekeys; mk < END(modekeys); mk++) {
|
||||
+ if (active_mode_index != mk->mode_index) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ k = &mk->key;
|
||||
+ if (CLEANMASK(mods) == CLEANMASK(k->mod) &&
|
||||
+ sym == k->keysym && k->func) {
|
||||
+ k->func(&k->arg);
|
||||
+ handled = 1;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return handled;
|
||||
+}
|
||||
+
|
||||
void
|
||||
keypress(struct wl_listener *listener, void *data)
|
||||
{
|
||||
@@ -1851,6 +1889,7 @@ printstatus(void)
|
||||
printf("%s tags %u %u %u %u\n", m->wlr_output->name, occ, m->tagset[m->seltags],
|
||||
sel, urg);
|
||||
printf("%s layout %s\n", m->wlr_output->name, m->ltsymbol);
|
||||
+ printf("%s mode %s\n", m->wlr_output->name, modes_labels[active_mode_index] ? modes_labels[active_mode_index] : "");
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
@@ -2746,6 +2785,13 @@ zoom(const Arg *arg)
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
+void
|
||||
+entermode(const Arg *arg)
|
||||
+{
|
||||
+ active_mode_index = arg->i;
|
||||
+ printstatus();
|
||||
+}
|
||||
+
|
||||
#ifdef XWAYLAND
|
||||
void
|
||||
activatex11(struct wl_listener *listener, void *data)
|
||||
--
|
||||
2.42.0
|
||||
|
||||
+37
-37
@@ -1,21 +1,20 @@
|
||||
From a32b85018ff2cea0fc9f9137789860a4aadc3b3a Mon Sep 17 00:00:00 2001
|
||||
From: wochap <gean.marroquin@gmail.com>
|
||||
Date: Wed, 6 Mar 2024 07:31:17 -0500
|
||||
Subject: [PATCH] implement modes
|
||||
From 915115151a4429bab38dd8cff2268f34ee23984f Mon Sep 17 00:00:00 2001
|
||||
From: nate zhou <gnuunixchad@outlook.com>
|
||||
Date: Mon, 2 Mar 2026 19:23:59 +0800
|
||||
Subject: [PATCH] Patch: modes-0.8.patch
|
||||
|
||||
like sway/river modes
|
||||
---
|
||||
config.def.h | 20 ++++++++++++++++++++
|
||||
dwl.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 66 insertions(+)
|
||||
dwl.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 67 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index db0babc..1616136 100644
|
||||
index 8a6eda0..bc88ea5 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -13,6 +13,13 @@ static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||
/* To conform the xdg-protocol, set the alpha to zero to restore the old behavior */
|
||||
static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; /* You can also use glsl colors */
|
||||
@@ -14,6 +14,13 @@ static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
||||
static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */
|
||||
|
||||
+enum {
|
||||
+ BROWSER,
|
||||
@@ -27,16 +26,16 @@ index db0babc..1616136 100644
|
||||
/* tagging - TAGCOUNT must be no greater than 31 */
|
||||
#define TAGCOUNT (9)
|
||||
|
||||
@@ -152,6 +159,8 @@ static const Key keys[] = {
|
||||
TAGKEYS( XKB_KEY_9, XKB_KEY_parenleft, 8),
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Q, quit, {0} },
|
||||
@@ -155,6 +162,8 @@ static const Key keys[] = {
|
||||
TAGKEYS( XKB_KEY_9, XKB_KEY_parenleft, 8),
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_q, quit, {0} },
|
||||
|
||||
+ { MODKEY, XKB_KEY_b, entermode, {.i = BROWSER} },
|
||||
+
|
||||
/* Ctrl-Alt-Backspace and Ctrl-Alt-Fx used to be handled by X server */
|
||||
{ WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_Terminate_Server, quit, {0} },
|
||||
/* Ctrl-Alt-Fx is used to switch to another VT, if you don't know what a VT is
|
||||
@@ -162,6 +171,17 @@ static const Key keys[] = {
|
||||
@@ -165,6 +174,17 @@ static const Key keys[] = {
|
||||
CHVT(7), CHVT(8), CHVT(9), CHVT(10), CHVT(11), CHVT(12),
|
||||
};
|
||||
|
||||
@@ -55,10 +54,10 @@ index db0babc..1616136 100644
|
||||
{ MODKEY, BTN_LEFT, moveresize, {.ui = CurMove} },
|
||||
{ MODKEY, BTN_MIDDLE, togglefloating, {0} },
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index ef27a1d..1ada006 100644
|
||||
index 44f3ad9..9247541 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -139,6 +139,11 @@ typedef struct {
|
||||
@@ -148,6 +148,11 @@ typedef struct {
|
||||
const Arg arg;
|
||||
} Key;
|
||||
|
||||
@@ -68,9 +67,9 @@ index ef27a1d..1ada006 100644
|
||||
+} Modekey;
|
||||
+
|
||||
typedef struct {
|
||||
struct wl_list link;
|
||||
struct wlr_keyboard *wlr_keyboard;
|
||||
@@ -270,6 +275,7 @@ static void handlesig(int signo);
|
||||
struct wlr_keyboard_group *wlr_group;
|
||||
|
||||
@@ -292,6 +297,7 @@ static void handlesig(int signo);
|
||||
static void incnmaster(const Arg *arg);
|
||||
static void inputdevice(struct wl_listener *listener, void *data);
|
||||
static int keybinding(uint32_t mods, xkb_keysym_t sym);
|
||||
@@ -78,27 +77,27 @@ index ef27a1d..1ada006 100644
|
||||
static void keypress(struct wl_listener *listener, void *data);
|
||||
static void keypressmod(struct wl_listener *listener, void *data);
|
||||
static int keyrepeat(void *data);
|
||||
@@ -327,6 +333,7 @@ static Monitor *xytomon(double x, double y);
|
||||
@@ -351,6 +357,7 @@ static Monitor *xytomon(double x, double y);
|
||||
static void xytonode(double x, double y, struct wlr_surface **psurface,
|
||||
Client **pc, LayerSurface **pl, double *nx, double *ny);
|
||||
static void zoom(const Arg *arg);
|
||||
+static void entermode(const Arg *arg);
|
||||
|
||||
/* variables */
|
||||
static const char broken[] = "broken";
|
||||
@@ -377,6 +384,9 @@ static struct wlr_box sgeom;
|
||||
static pid_t child_pid = -1;
|
||||
@@ -406,6 +413,9 @@ static struct wlr_box sgeom;
|
||||
static struct wl_list mons;
|
||||
static Monitor *selmon;
|
||||
|
||||
+static const int NORMAL = -1;
|
||||
+static int active_mode_index = NORMAL;
|
||||
+
|
||||
#ifdef XWAYLAND
|
||||
static void activatex11(struct wl_listener *listener, void *data);
|
||||
static void associatex11(struct wl_listener *listener, void *data);
|
||||
@@ -1372,6 +1382,11 @@ keybinding(uint32_t mods, xkb_keysym_t sym)
|
||||
/* global event handlers */
|
||||
static struct wl_listener cursor_axis = {.notify = axisnotify};
|
||||
static struct wl_listener cursor_button = {.notify = buttonpress};
|
||||
@@ -1614,6 +1624,11 @@ keybinding(uint32_t mods, xkb_keysym_t sym)
|
||||
* processing.
|
||||
*/
|
||||
int handled = 0;
|
||||
const Key *k;
|
||||
+
|
||||
+ if (active_mode_index >= 0) {
|
||||
@@ -106,10 +105,10 @@ index ef27a1d..1ada006 100644
|
||||
+ }
|
||||
+
|
||||
for (k = keys; k < END(keys); k++) {
|
||||
if (CLEANMASK(mods) == CLEANMASK(k->mod) &&
|
||||
sym == k->keysym && k->func) {
|
||||
@@ -1382,6 +1397,29 @@ keybinding(uint32_t mods, xkb_keysym_t sym)
|
||||
return handled;
|
||||
if (CLEANMASK(mods) == CLEANMASK(k->mod)
|
||||
&& xkb_keysym_to_lower(sym) == xkb_keysym_to_lower(k->keysym)
|
||||
@@ -1625,6 +1640,30 @@ keybinding(uint32_t mods, xkb_keysym_t sym)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+int
|
||||
@@ -134,19 +133,20 @@ index ef27a1d..1ada006 100644
|
||||
+
|
||||
+ return handled;
|
||||
+}
|
||||
+
|
||||
+
|
||||
void
|
||||
keypress(struct wl_listener *listener, void *data)
|
||||
{
|
||||
@@ -1851,6 +1889,7 @@ printstatus(void)
|
||||
printf("%s tags %u %u %u %u\n", m->wlr_output->name, occ, m->tagset[m->seltags],
|
||||
sel, urg);
|
||||
@@ -2119,6 +2158,7 @@ printstatus(void)
|
||||
printf("%s tags %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32"\n",
|
||||
m->wlr_output->name, occ, m->tagset[m->seltags], sel, urg);
|
||||
printf("%s layout %s\n", m->wlr_output->name, m->ltsymbol);
|
||||
+ printf("%s mode %s\n", m->wlr_output->name, modes_labels[active_mode_index] ? modes_labels[active_mode_index] : "");
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
@@ -2746,6 +2785,13 @@ zoom(const Arg *arg)
|
||||
@@ -3075,6 +3115,13 @@ zoom(const Arg *arg)
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
@@ -161,5 +161,5 @@ index ef27a1d..1ada006 100644
|
||||
void
|
||||
activatex11(struct wl_listener *listener, void *data)
|
||||
--
|
||||
2.42.0
|
||||
2.53.0
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@ Allows more monitor configuration in config.h
|
||||
|
||||
### Download
|
||||
- [git branch](https://codeberg.org/Palanix/dwl/src/branch/monitorconfig)
|
||||
- [2024-02-15](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/monitorconfig/monitorconfig.patch)
|
||||
- [wlroots-next-f4249db](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/monitorconfig/monitorconfig-wlroots-next-f4249db.patch)
|
||||
- [0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/monitorconfig/monitorconfig-0.8.patch)
|
||||
|
||||
### Authors
|
||||
- [Palanix](https://codeberg.org/Palanix)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user