This commit is contained in:
2026-07-12 08:16:17 +03:30
commit 72be1234e1
2027 changed files with 221388 additions and 0 deletions
+9
View File
@@ -0,0 +1,9 @@
### Description
Port of dwm's accessnthmon. Adds functions to tag and focus monitor by index.
### Download
- [git branch](https://codeberg.org/Rutherther/dwl/src/branch/patch/accessnthmonitor)
- [2024-05-10](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/accessnthmon/accessnthmon.patch)
### Authors
- [Rutherther](https://codeberg.org/Rutherther)
- [Palanix](https://codeberg.org/Palanix)
+122
View File
@@ -0,0 +1,122 @@
From 5f531bfb1387ded7b8817faf7df760d3b998742b Mon Sep 17 00:00:00 2001
From: Rutherther <rutherther@proton.me>
Date: Sat, 27 Apr 2024 21:25:16 +0200
Subject: [PATCH] feat: access nth monitor
---
config.def.h | 4 +++-
dwl.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 49 insertions(+), 1 deletion(-)
diff --git a/config.def.h b/config.def.h
index 8847e58..4709c5d 100644
--- a/config.def.h
+++ b/config.def.h
@@ -108,7 +108,9 @@ static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TA
{ MODKEY, KEY, view, {.ui = 1 << TAG} }, \
{ MODKEY|WLR_MODIFIER_CTRL, KEY, toggleview, {.ui = 1 << TAG} }, \
{ MODKEY|WLR_MODIFIER_SHIFT, SKEY, tag, {.ui = 1 << TAG} }, \
- { MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT,SKEY,toggletag, {.ui = 1 << TAG} }
+ { MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT,SKEY,toggletag, {.ui = 1 << TAG} }, \
+ { WLR_MODIFIER_ALT, KEY, focusnthmon, {.ui = TAG} }, \
+ { WLR_MODIFIER_ALT|WLR_MODIFIER_SHIFT, SKEY, tagnthmon, {.ui = TAG} }
/* helper for spawning shell commands in the pre dwm-5.0 fashion */
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
diff --git a/dwl.c b/dwl.c
index bf763df..1d42caf 100644
--- a/dwl.c
+++ b/dwl.c
@@ -11,6 +11,7 @@
#include <time.h>
#include <unistd.h>
#include <wayland-server-core.h>
+#include <wayland-util.h>
#include <wlr/backend.h>
#include <wlr/backend/libinput.h>
#include <wlr/render/allocator.h>
@@ -278,8 +279,10 @@ static void destroypointerconstraint(struct wl_listener *listener, void *data);
static void destroysessionlock(struct wl_listener *listener, void *data);
static void destroysessionmgr(struct wl_listener *listener, void *data);
static Monitor *dirtomon(enum wlr_direction dir);
+static Monitor *numtomon(int num);
static void focusclient(Client *c, int lift);
static void focusmon(const Arg *arg);
+static void focusnthmon(const Arg *arg);
static void focusstack(const Arg *arg);
static Client *focustop(Monitor *m);
static void fullscreennotify(struct wl_listener *listener, void *data);
@@ -329,6 +332,7 @@ static void spawn(const Arg *arg);
static void startdrag(struct wl_listener *listener, void *data);
static void tag(const Arg *arg);
static void tagmon(const Arg *arg);
+static void tagnthmon(const Arg *arg);
static void tile(Monitor *m);
static void togglefloating(const Arg *arg);
static void togglefullscreen(const Arg *arg);
@@ -1233,6 +1237,25 @@ dirtomon(enum wlr_direction dir)
return selmon;
}
+Monitor *
+numtomon(int num)
+{
+ Monitor *m = NULL;
+ int found = 0;
+ int i = 0;
+
+ wl_list_for_each(m, &mons, link) {
+ if (!m->wlr_output->enabled)
+ i--;
+ else if (i == num) {
+ found = true;
+ break;
+ }
+ i++;
+ }
+ return found ? m : NULL;
+}
+
void
focusclient(Client *c, int lift)
{
@@ -1320,6 +1343,16 @@ focusmon(const Arg *arg)
focusclient(focustop(selmon), 1);
}
+void
+focusnthmon(const Arg *arg)
+{
+ Monitor *m = numtomon(arg->i);
+ if (!m || m == selmon)
+ return;
+ selmon = m;
+ focusclient(focustop(selmon), 1);
+}
+
void
focusstack(const Arg *arg)
{
@@ -2569,6 +2602,19 @@ tagmon(const Arg *arg)
setmon(sel, dirtomon(arg->i), 0);
}
+void
+tagnthmon(const Arg *arg)
+{
+ Client *sel = focustop(selmon);
+ Monitor *m = numtomon(arg->i);
+ if (!m || !sel)
+ return;
+ setmon(sel, m, 0);
+
+ arrange(selmon);
+ arrange(m);
+}
+
void
tile(Monitor *m)
{
--
2.44.0
+9
View File
@@ -0,0 +1,9 @@
### Description
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)
### Authors
- [Guido Cella](https://codeberg.org/guidocella)
+39
View File
@@ -0,0 +1,39 @@
From f43a49324c2ddd21100d6308d1adde9d894746e2 Mon Sep 17 00:00:00 2001
From: Guido Cella <guido@guidocella.xyz>
Date: Wed, 5 Jun 2024 12:05:16 +0200
Subject: [PATCH] center floating windows
---
dwl.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/dwl.c b/dwl.c
index 12f441e..c377c67 100644
--- a/dwl.c
+++ b/dwl.c
@@ -499,6 +499,11 @@ applyrules(Client *c)
}
}
+ 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
+10
View File
@@ -0,0 +1,10 @@
### Description
Newly created windows are placed at the bottom of the client tile stack.
### Download
- [git branch](https://codeberg.org/bencc/dwl/src/branch/attachbottom)
- [2024-05-16](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/attachbottom/attachbottom.patch)
### Authors
- [Ben Collerson](https://codeberg.org/bencc)
- [Aurel Weinhold](https://github.com/AurelWeinhold)
+29
View File
@@ -0,0 +1,29 @@
From 0dda3ed8634154fd3887b71133b451d66a11b61d Mon Sep 17 00:00:00 2001
From: Ben Collerson <benc@benc.cc>
Date: Thu, 4 Jan 2024 23:31:41 +1000
Subject: [PATCH] attachbottom
---
dwl.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/dwl.c b/dwl.c
index bf763dfc..12e08e2b 100644
--- a/dwl.c
+++ b/dwl.c
@@ -1605,7 +1605,11 @@ mapnotify(struct wl_listener *listener, void *data)
c->geom.height += 2 * c->bw;
/* Insert this client into client lists. */
- wl_list_insert(&clients, &c->link);
+ if (clients.prev)
+ // tile at the bottom
+ wl_list_insert(clients.prev, &c->link);
+ else
+ wl_list_insert(&clients, &c->link);
wl_list_insert(&fstack, &c->flink);
/* Set initial monitor, tags, floating status, and focus:
--
2.43.0
+11
View File
@@ -0,0 +1,11 @@
### Description
Makes windows attach below the currently active window.
KNOWN ISSUES: Upon closing the last client when using multiple monitors, the last client will briefly flash on all
monitors before closing.
### Download
- [0.7](/dwl/dwl-patches/raw/branch/main/patches/attachfocused/attachfocused.patch)
### Authors
- [MayOrMayNotBeACat](https://codeberg.org/MayOrMayNotBeACat)
+29
View File
@@ -0,0 +1,29 @@
From d03851c14073874f5b3d19a095e184dc24d219cd Mon Sep 17 00:00:00 2001
From: MayOrMayNotBeACat <maybeacat804@gmail.com>
Date: Sun, 11 May 2025 20:24:51 -0400
Subject: [PATCH] Make new windows attach to active client
---
dwl.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/dwl.c b/dwl.c
index cf3ef70..1907c5f 100644
--- a/dwl.c
+++ b/dwl.c
@@ -1726,7 +1726,11 @@ mapnotify(struct wl_listener *listener, void *data)
c->geom.height += 2 * c->bw;
/* Insert this client into client lists. */
- wl_list_insert(&clients, &c->link);
+ Client* focused = focustop(selmon);
+ if (focused)
+ wl_list_insert(&focused->link, &c->link);
+ else
+ wl_list_insert(&clients, &c->link);
wl_list_insert(&fstack, &c->flink);
/* Set initial monitor, tags, floating status, and focus:
--
2.49.0
+13
View File
@@ -0,0 +1,13 @@
### Description
This is a port of attachtop patch for dwm: https://dwm.suckless.org/patches/attachtop
New client attaches below the last master/on top of the stack.
Behavior feels very intuitive as it doesn't disrupt existing masters no matter the amount of them, it only pushes the clients in stack down.
### Download
- [git branch](https://codeberg.org/nikitaivanov/dwl/src/branch/attachtop)
- [2025-06-16](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/attachtop/attachtop.patch)
### Authors
- [Nikita Ivanov](https://codeberg.org/nikitaivanov)
+36
View File
@@ -0,0 +1,36 @@
From 29e6a4bef02c473cc5bd04804fe508bda265077d Mon Sep 17 00:00:00 2001
From: Nikita Ivanov <nikita.vyach.ivanov@gmail.com>
Date: Sun, 7 Apr 2024 21:10:17 +0200
Subject: [PATCH] New client are attached on top of the stack
---
dwl.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/dwl.c b/dwl.c
index bf763df..02e3d07 100644
--- a/dwl.c
+++ b/dwl.c
@@ -1605,7 +1605,18 @@ mapnotify(struct wl_listener *listener, void *data)
c->geom.height += 2 * c->bw;
/* Insert this client into client lists. */
- wl_list_insert(&clients, &c->link);
+ i = 0;
+ wl_list_for_each(w, &clients, link) {
+ if (!VISIBLEON(w, selmon) || w->isfloating)
+ continue;
+ p = w;
+ if (++i >= selmon->nmaster)
+ break;
+ }
+ if (i > 0)
+ wl_list_insert(&p->link, &c->link);
+ else
+ wl_list_insert(&clients, &c->link);
wl_list_insert(&fstack, &c->flink);
/* Set initial monitor, tags, floating status, and focus:
--
2.49.0
+14
View File
@@ -0,0 +1,14 @@
### Description
Allow dwl to execute commands from autostart array in your config.h file. And when you exit dwl all processes from autostart array will be killed.
Note: Commands from array are executed using execvp(). So if you need to execute shell command you need to prefix it with "sh", "-c" (change sh to any shell you like).
### 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)
### Authors
- [sevz](https://codeberg.org/sevz)
- [Rayan Nakib](https://nakibrayan2.pages.dev/)
- [NFVblog](https://github.com/nf02)
+154
View File
@@ -0,0 +1,154 @@
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
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(-)
diff --git a/config.def.h b/config.def.h
index 22d2171..8dc6502 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
/* logging */
static int log_level = WLR_ERROR;
+/* Autostart */
+static const char *const autostart[] = {
+ "wbg", "/path/to/your/image", NULL,
+ 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 */
diff --git a/dwl.c b/dwl.c
index 5bf995e..e8b8727 100644
--- a/dwl.c
+++ b/dwl.c
@@ -249,6 +249,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);
+static void autostartexec(void);
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"
+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)
}
}
+void
+autostartexec(void) {
+ const char *const *p;
+ size_t i = 0;
+
+ /* count entries */
+ for (p = autostart; *p; autostart_len++, p++)
+ while (*++p);
+
+ autostart_pids = calloc(autostart_len, sizeof(pid_t));
+ for (p = autostart; *p; i++, p++) {
+ if ((autostart_pids[i] = fork()) == 0) {
+ setsid();
+ execvp(*p, (char *const *)p);
+ die("dwl: execvp %s:", *p);
+ }
+ /* skip arguments */
+ while (*++p);
+ }
+}
+
void
axisnotify(struct wl_listener *listener, void *data)
{
@@ -676,11 +701,21 @@ checkidleinhibitor(struct wlr_surface *exclude)
void
cleanup(void)
{
+ size_t i;
#ifdef XWAYLAND
wlr_xwayland_destroy(xwayland);
xwayland = NULL;
#endif
wl_display_destroy_clients(dpy);
+
+ /* kill child processes */
+ for (i = 0; i < autostart_len; i++) {
+ if (0 < autostart_pids[i]) {
+ kill(autostart_pids[i], SIGTERM);
+ waitpid(autostart_pids[i], NULL, 0);
+ }
+ }
+
if (child_pid > 0) {
kill(-child_pid, SIGTERM);
waitpid(child_pid, NULL, 0);
@@ -1497,18 +1532,31 @@ 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
- 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)
+ child_pid = -1;
+ if (!(p = autostart_pids))
+ continue;
+ lim = &p[autostart_len];
+
+ for (; p < lim; p++) {
+ if (*p == in.si_pid) {
+ *p = -1;
+ break;
+ }
+ }
+ }
} else if (signo == SIGINT || signo == SIGTERM) {
quit(NULL);
}
@@ -2224,6 +2272,7 @@ run(char *startup_cmd)
die("startup: backend_start");
/* Now that the socket exists and the backend is started, run the startup command */
+ autostartexec();
if (startup_cmd) {
int piperw[2];
if (pipe(piperw) < 0)
--
2.45.2
+148
View File
@@ -0,0 +1,148 @@
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
https://dwm.suckless.org/patches/cool_autostart/
Signed-off-by: Leonardo Hernández Hernández <leohdz172@proton.me>
---
config.def.h | 7 +++++++
dwl.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 62 insertions(+), 3 deletions(-)
diff --git a/config.def.h b/config.def.h
index 22d2171d..8dc6502c 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
/* logging */
static int log_level = WLR_ERROR;
+/* Autostart */
+static const char *const autostart[] = {
+ "wbg", "/path/to/your/image", NULL,
+ 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 */
diff --git a/dwl.c b/dwl.c
index ad21e1ba..3118e07f 100644
--- a/dwl.c
+++ b/dwl.c
@@ -246,6 +246,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);
+static void autostartexec(void);
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"
+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)
}
}
+void
+autostartexec(void) {
+ const char *const *p;
+ size_t i = 0;
+
+ /* count entries */
+ for (p = autostart; *p; autostart_len++, p++)
+ while (*++p);
+
+ autostart_pids = calloc(autostart_len, sizeof(pid_t));
+ for (p = autostart; *p; i++, p++) {
+ if ((autostart_pids[i] = fork()) == 0) {
+ setsid();
+ execvp(*p, (char *const *)p);
+ die("dwl: execvp %s:", *p);
+ }
+ /* skip arguments */
+ while (*++p);
+ }
+}
+
void
axisnotify(struct wl_listener *listener, void *data)
{
@@ -695,12 +720,23 @@ checkidleinhibitor(struct wlr_surface *exclude)
void
cleanup(void)
{
+ size_t i;
+
cleanuplisteners();
#ifdef XWAYLAND
wlr_xwayland_destroy(xwayland);
xwayland = NULL;
#endif
wl_display_destroy_clients(dpy);
+
+ /* kill child processes */
+ for (i = 0; i < autostart_len; i++) {
+ if (0 < autostart_pids[i]) {
+ kill(autostart_pids[i], SIGTERM);
+ waitpid(autostart_pids[i], NULL, 0);
+ }
+ }
+
if (child_pid > 0) {
kill(-child_pid, SIGTERM);
waitpid(child_pid, NULL, 0);
@@ -1551,10 +1587,25 @@ gpureset(struct wl_listener *listener, void *data)
void
handlesig(int signo)
{
- if (signo == SIGCHLD)
- while (waitpid(-1, NULL, WNOHANG) > 0);
- 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 == pid) {
+ *p = -1;
+ break;
+ }
+ }
+ }
+ } else if (signo == SIGINT || signo == SIGTERM) {
quit(NULL);
+ }
}
void
@@ -2241,6 +2292,7 @@ run(char *startup_cmd)
die("startup: backend_start");
/* Now that the socket exists and the backend is started, run the startup command */
+ autostartexec();
if (startup_cmd) {
int piperw[2];
if (pipe(piperw) < 0)
--
2.48.0
+19
View File
@@ -0,0 +1,19 @@
### Description
Add a system tray to the [bar](/dwl/dwl-patches/src/branch/main/patches/bar).
To keep dependencies to minimum, icon(svg) loading from the filesystem is not
supported. Applications that expect this will show the initial letter of the
program name, instead of a real icon.
Menus for the icons are handled by a dmenu-like program of the user's choice.
### Dependencies
- [bar.patch](/dwl/dwl-patches/src/branch/main/patches/bar)
- [libdbus](https://gitlab.freedesktop.org/dbus/dbus)
### Download
- [git branch](/janetski/dwl/src/branch/0.7-bar-systray)
- [0.7](/dwl/dwl-patches/raw/branch/main/patches/bar-systray/bar-systray-0.7.patch)
### Authors
- [janetski](https://codeberg.org/janetski) ([.vetu](https://discordapp.com/users/355488216469471242) on discord)
File diff suppressed because it is too large Load Diff
+34
View File
@@ -0,0 +1,34 @@
### Description
Add a bar identical to dwm's bar.
To use a status-bar, you can pass in status text via stdin:
```
slstatus -s | dwl
```
### Dependencies
* tllist (build dependency, required & pulled automatically by fcft)
* fcft
* pixman
### Download
- [main 2025-07-29](/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)
It is required to remove, regenerate or update `config.h` after applying the patch,
since it makes changes to the configuration structure.
For example, in the `pertag` patch, `TAGCOUNT` must be replaced with `LENGTH(tags)`.
Below is a preview of the patch.
![bar patch preview](bar.png)
### Authors
- [sewn](https://codeberg.org/sewn)
### Credits
- [MadcowOG](https://github.com/MadcowOG)
- [kolumni](https://github.com/kolunmi/dwlb)
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1266
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

+10
View File
@@ -0,0 +1,10 @@
### Description
Add a border around the [bar](/dwl/dwl-patches/wiki/bar) similar to how a client is given a border.
### Download
- [0.7](/dwl/dwl-patches/raw/branch/main/patches/barborder/barborder.patch)
### Authors
- [sewn](https://codeberg.org/sewn)
+136
View File
@@ -0,0 +1,136 @@
From 7d95ce0fba8f172748bbd71b4c03ce12acd54eea Mon Sep 17 00:00:00 2001
From: sewn <sewn@disroot.org>
Date: Fri, 23 Aug 2024 14:11:37 +0300
Subject: [PATCH] add border to bar
---
config.def.h | 3 ++-
dwl.c | 32 +++++++++++++++++++-------------
2 files changed, 21 insertions(+), 14 deletions(-)
diff --git a/config.def.h b/config.def.h
index 5d1dc2b..4763482 100644
--- a/config.def.h
+++ b/config.def.h
@@ -6,7 +6,7 @@
/* 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 unsigned int borderpx = 1; /* border pixel of windows & 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"};
@@ -18,6 +18,7 @@ static uint32_t colors[][3] = {
[SchemeNorm] = { 0xbbbbbbff, 0x222222ff, 0x444444ff },
[SchemeSel] = { 0xeeeeeeff, 0x005577ff, 0x005577ff },
[SchemeUrg] = { 0, 0, 0x770000ff },
+ [SchemeBar] = { 0, 0, 0x557700ff },
};
/* tagging - TAGCOUNT must be no greater than 31 */
diff --git a/dwl.c b/dwl.c
index ece537a..c637da4 100644
--- a/dwl.c
+++ b/dwl.c
@@ -85,7 +85,7 @@
#define TEXTW(mon, text) (drwl_font_getwidth(mon->drw, text) + mon->lrpad)
/* enums */
-enum { SchemeNorm, SchemeSel, SchemeUrg }; /* color schemes */
+enum { SchemeNorm, SchemeSel, SchemeUrg, SchemeBar }; /* color schemes */
enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */
enum { XDGShell, LayerShell, X11 }; /* client types */
enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrTop, LyrFS, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */
@@ -750,7 +750,7 @@ buttonpress(struct wl_listener *listener, void *data)
if (!c && !exclusive_focus &&
(node = wlr_scene_node_at(&layers[LyrBottom]->node, cursor->x, cursor->y, NULL, NULL)) &&
(buffer = wlr_scene_buffer_from_node(node)) && buffer == selmon->scene_buffer) {
- cx = (cursor->x - selmon->m.x) * selmon->wlr_output->scale;
+ cx = (cursor->x - selmon->m.x - borderpx) * selmon->wlr_output->scale;
do
x += TEXTW(selmon, tags[i]);
while (cx >= x && ++i < LENGTH(tags));
@@ -1506,10 +1506,12 @@ dirtomon(enum wlr_direction dir)
void
drawbar(Monitor *m)
{
- int x, w, tw = 0;
+ int x, y = borderpx, w, tw = 0;
+ int mh = m->b.height - borderpx * 2, mw = m->b.width - borderpx * 2;
int boxs = m->drw->font->height / 9;
int boxw = m->drw->font->height / 6 + 2;
uint32_t i, occ = 0, urg = 0;
+ uint32_t borderscm[] = { colors[SchemeBar][ColBorder] };
Client *c;
Buffer *buf;
@@ -1518,11 +1520,15 @@ drawbar(Monitor *m)
if (!(buf = bufmon(m)))
return;
+ drwl_setscheme(m->drw, borderscm);
+ drwl_rect(m->drw, 0, 0, m->b.width, m->b.height, 1, 0);
+ drwl_setscheme(m->drw, colors[SchemeNorm]);
+
/* 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);
+ drwl_text(m->drw, borderpx + mw - tw, y, tw, mh, 0, stext, 0);
}
wl_list_for_each(c, &clients, link) {
@@ -1532,31 +1538,31 @@ drawbar(Monitor *m)
if (c->isurgent)
urg |= c->tags;
}
- x = 0;
+ x = borderpx;
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);
+ drwl_text(m->drw, x, y, w, mh, m->lrpad / 2, tags[i], urg & 1 << i);
if (occ & 1 << i)
- drwl_rect(m->drw, x + boxs, boxs, boxw, boxw,
+ drwl_rect(m->drw, x + boxs, y + 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);
+ x = drwl_text(m->drw, x, y, w, mh, m->lrpad / 2, m->ltsymbol, 0);
- if ((w = m->b.width - tw - x) > m->b.height) {
+ if ((w = mw - tw - x + borderpx) > mh) {
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);
+ drwl_text(m->drw, x, y, w, mh, m->lrpad / 2, client_get_title(c), 0);
if (c && c->isfloating)
- drwl_rect(m->drw, x + boxs, boxs, boxw, boxw, 0, 0);
+ drwl_rect(m->drw, x + boxs, y + boxs, boxw, boxw, 0, 0);
} else {
drwl_setscheme(m->drw, colors[SchemeNorm]);
- drwl_rect(m->drw, x, 0, w, m->b.height, 1, 1);
+ drwl_rect(m->drw, x, y, w, mh, 1, 1);
}
}
@@ -3183,7 +3189,7 @@ updatebar(Monitor *m)
m->b.scale = m->wlr_output->scale;
m->lrpad = m->drw->font->height;
- m->b.height = m->drw->font->height + 2;
+ m->b.height = m->drw->font->height + 2 + borderpx * 2;
m->b.real_height = (int)((float)m->b.height / m->wlr_output->scale);
}
--
2.46.0
+9
View File
@@ -0,0 +1,9 @@
### Description
Add support for colored status text to the [bar](/dwl/dwl-patches/src/branch/main/patches/bar). Text can be colored in the same manner as with dwlb, namely by wrapping it between `^fg(color)` and `^fg()` or `^bg(color)` and `^bg()`, where `color` is a 6-digit hexadecimal value.
### Download
- [git branch](/kerberoge/dwl/src/branch/barcolors)
- [0.7](/dwl/dwl-patches/raw/branch/main/patches/barcolors/barcolors.patch)
### Authors
- [kerberoge](https://codeberg.org/kerberoge)
+144
View File
@@ -0,0 +1,144 @@
From d2b529d9ebee6b2e625afd5c89c2ede5bb0ca91b Mon Sep 17 00:00:00 2001
From: Kerberoge <sjoerdenjh@gmail.com>
Date: Sun, 25 Aug 2024 22:41:55 +0200
Subject: [PATCH 1/1] updated barcolors
---
dwl.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 87 insertions(+), 6 deletions(-)
diff --git a/dwl.c b/dwl.c
index ece537a..6663399 100644
--- a/dwl.c
+++ b/dwl.c
@@ -83,6 +83,7 @@
#define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L)))
#define LISTEN_STATIC(E, H) do { static struct wl_listener _l = {.notify = (H)}; wl_signal_add((E), &_l); } while (0)
#define TEXTW(mon, text) (drwl_font_getwidth(mon->drw, text) + mon->lrpad)
+#define PREFIX(str, prefix) !strncmp(str, prefix, strlen(prefix))
/* enums */
enum { SchemeNorm, SchemeSel, SchemeUrg }; /* color schemes */
@@ -318,6 +319,7 @@ static void destroykeyboardgroup(struct wl_listener *listener, void *data);
static Monitor *dirtomon(enum wlr_direction dir);
static void drawbar(Monitor *m);
static void drawbars(void);
+static int drawstatus(Monitor *m);
static void focusclient(Client *c, int lift);
static void focusmon(const Arg *arg);
static void focusstack(const Arg *arg);
@@ -448,7 +450,7 @@ static struct wlr_box sgeom;
static struct wl_list mons;
static Monitor *selmon;
-static char stext[256];
+static char stext[512];
static struct wl_event_source *status_event_source;
static const struct wlr_buffer_impl buffer_impl = {
@@ -1519,11 +1521,8 @@ drawbar(Monitor *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 (m == selmon) /* status is only drawn on selected monitor */
+ tw = drawstatus(m);
wl_list_for_each(c, &clients, link) {
if (c->mon != m)
@@ -1577,6 +1576,88 @@ drawbars(void)
drawbar(m);
}
+int
+drawstatus(Monitor *m)
+{
+ int x, tw, iw;
+ char rstext[512] = "";
+ char *p, *argstart, *argend, *itext;
+ uint32_t scheme[3], *color;
+
+ /* calculate real width of stext */
+ for (p = stext; *p; p++) {
+ if (PREFIX(p, "^^")) {
+ strncat(rstext, p, 2);
+ p++;
+ } else if (PREFIX(p, "^fg(") || PREFIX(p, "^bg(")) {
+ argend = strchr(p, ')');
+ if (!argend) { /* ignore this command */
+ argstart = strchr(p, '(') + 1;
+ strncat(rstext, p, argstart - p);
+ p = argstart - 1;
+ } else {
+ p = argend;
+ }
+ } else {
+ strncat(rstext, p, 1);
+ }
+ }
+ tw = TEXTW(m, rstext) - m->lrpad;
+
+ x = m->b.width - tw;
+ itext = stext;
+ scheme[0] = colors[SchemeNorm][0];
+ scheme[1] = colors[SchemeNorm][1];
+ drwl_setscheme(m->drw, scheme);
+ for (p = stext; *p; p++) {
+ if (PREFIX(p, "^^")) {
+ p++;
+ } else if (PREFIX(p, "^fg(") || PREFIX(p, "^bg(")) {
+ argstart = strchr(p, '(') + 1;
+ argend = strchr(argstart, ')');
+ if (!argend) { /* ignore this command */
+ p = argstart - 1;
+ continue;
+ }
+
+ *p = '\0';
+ iw = TEXTW(m, itext) - m->lrpad;
+ if (*itext) /* only draw text if there is something to draw */
+ x = drwl_text(m->drw, x, 0, iw, m->b.height, 0, itext, 0);
+ *p = '^';
+
+ if (PREFIX(p, "^fg("))
+ color = &scheme[0];
+ else
+ color = &scheme[1];
+
+ if (argend != argstart) {
+ *argend = '\0';
+ *color = strtoul(argstart, NULL, 16);
+ *color = *color << 8 | 0xff; /* add alpha channel */
+ *argend = ')';
+ } else {
+ *color = 0; /* reset */
+ }
+
+ /* reset color back to normal if none was provided */
+ if (!scheme[0])
+ scheme[0] = colors[SchemeNorm][0];
+ if (!scheme[1])
+ scheme[1] = colors[SchemeNorm][1];
+
+ itext = argend + 1;
+ drwl_setscheme(m->drw, scheme);
+ p = argend;
+ }
+ }
+ iw = TEXTW(m, itext) - m->lrpad;
+ if (*itext)
+ drwl_text(m->drw, x, 0, iw, m->b.height, 0, itext, 0);
+
+ return tw;
+}
+
void
focusclient(Client *c, int lift)
{
--
2.48.1
+10
View File
@@ -0,0 +1,10 @@
### Description
Add vertical and horizontal space between the [bar](/dwl/dwl-patches/wiki/bar) and the edge of the screen.
### Download
- [0.7](/dwl/dwl-patches/raw/branch/main/patches/barpadding/barpadding.patch)
### Authors
- [sewn](https://codeberg.org/sewn)
+73
View File
@@ -0,0 +1,73 @@
From f01cea73042155e856b2f41452724fe5c895eee4 Mon Sep 17 00:00:00 2001
From: sewn <sewn@disroot.org>
Date: Fri, 23 Aug 2024 09:59:03 +0300
Subject: [PATCH] add vertical and horizontal spacing to bar
https://dwm.suckless.org/patches/barpadding/
---
config.def.h | 2 ++
dwl.c | 14 +++++++-------
2 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/config.def.h b/config.def.h
index 5d1dc2b..756b1ae 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 vertpad = 10; /* vertical padding of bar */
+static const int sidepad = 10; /* horizontal padding of bar */
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 ece537a..380549a 100644
--- a/dwl.c
+++ b/dwl.c
@@ -598,8 +598,8 @@ arrangelayers(Monitor *m)
return;
if (m->scene_buffer->node.enabled) {
- usable_area.height -= m->b.real_height;
- usable_area.y += topbar ? m->b.real_height : 0;
+ usable_area.height -= m->b.real_height + vertpad;
+ usable_area.y += topbar ? m->b.real_height + vertpad : 0;
}
/* Arrange exclusive surfaces from top->bottom */
@@ -750,7 +750,7 @@ buttonpress(struct wl_listener *listener, void *data)
if (!c && !exclusive_focus &&
(node = wlr_scene_node_at(&layers[LyrBottom]->node, cursor->x, cursor->y, NULL, NULL)) &&
(buffer = wlr_scene_buffer_from_node(node)) && buffer == selmon->scene_buffer) {
- cx = (cursor->x - selmon->m.x) * selmon->wlr_output->scale;
+ cx = (cursor->x - selmon->m.x - sidepad) * selmon->wlr_output->scale;
do
x += TEXTW(selmon, tags[i]);
while (cx >= x && ++i < LENGTH(tags));
@@ -1562,8 +1562,8 @@ drawbar(Monitor *m)
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,
- m->m.y + (topbar ? 0 : m->m.height - m->b.real_height));
+ wlr_scene_node_set_position(&m->scene_buffer->node, m->m.x + sidepad,
+ m->m.y + (topbar ? vertpad : m->m.height - m->b.real_height - vertpad));
wlr_scene_buffer_set_buffer(m->scene_buffer, &buf->base);
wlr_buffer_unlock(&buf->base);
}
@@ -3162,8 +3162,8 @@ updatebar(Monitor *m)
char fontattrs[12];
wlr_output_transformed_resolution(m->wlr_output, &rw, &rh);
- m->b.width = rw;
- m->b.real_width = (int)((float)m->b.width / m->wlr_output->scale);
+ m->b.width = rw - (2 * sidepad);
+ m->b.real_width = (int)((float)rw / m->wlr_output->scale) - (2 * sidepad);
wlr_scene_node_set_enabled(&m->scene_buffer->node, m->wlr_output->enabled ? showbar : 0);
--
2.46.0
+11
View File
@@ -0,0 +1,11 @@
### Description
A homegrown port of dwm's _truecenteredtitle_ patch, with the addition of a config option to toggle its effects.<br>Requires [the bar patch](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/bar) to be applied beforehand.
![](centeredtitle.webp)
### Download
- [v0.7/v0.6](/dwl/dwl-patches/raw/branch/main/patches/bartruecenteredtitle/bartruecenteredtitle.patch)<br>Works on both v0.7 and v0.6.
### Author
- [moonsabre](https://codeberg.org/moonsabre)
- [sewn](https://codeberg.org/sewn)
@@ -0,0 +1,46 @@
From 17501c9f28226b1f332d6842be0d7f50ba618a29 Mon Sep 17 00:00:00 2001
From: moonsabre <moonsabre@tuta.io>
Date: Fri, 14 Mar 2025 16:04:25 -0700
Subject: [PATCH] Bar title centering parameter.
---
config.def.h | 1 +
dwl.c | 9 +++++++--
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/config.def.h b/config.def.h
index 5d1dc2b..8ac3a8b 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 int centeredtitle = 1; /* 1 means centered title */
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 ece537a..9eb816b 100644
--- a/dwl.c
+++ b/dwl.c
@@ -1551,9 +1551,14 @@ drawbar(Monitor *m)
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);
+ tw = TEXTW(selmon, client_get_title(c));
+ drwl_text(m->drw, x, 0, w, m->b.height,
+ !centeredtitle || tw > w ? m->lrpad / 2 : (w - tw) / 2,
+ client_get_title(c), 0);
if (c && c->isfloating)
- drwl_rect(m->drw, x + boxs, boxs, boxw, boxw, 0, 0);
+ drwl_rect(m->drw,
+ !centeredtitle || tw > w ? x + boxs : x + ((w - tw) / 2 - boxs * 8),
+ boxs, boxw, boxw, 0, 0);
} else {
drwl_setscheme(m->drw, colors[SchemeNorm]);
drwl_rect(m->drw, x, 0, w, m->b.height, 1, 1);
--
2.48.1
Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

+48
View File
@@ -0,0 +1,48 @@
### Description
This patch allows you to configure window resizing more flexibly.
It introduces three options with the following possible values:
- warp_cursor:
```
0 - the mouse cursor remains in its original position at the start of the resize.
1 - the cursor is automatically warped to the selected corner before resizing begins.
```
- lock_cursor:
```
0 - the cursor can move freely during the resize.
1 - the cursor position is completely frozen for the entire duration of the resize.
```
- resize_corner:
```
0: top-left
1: top-right
2: bottom-left
3: bottom-right
4: selects the corner based on the current mouse quadrant
```
### Demos
All demos below use resize_corner = 4:
| no warp + no lock | warp + lock |
|-|-|
| ![demo-nowarp-nolock](https://github.com/mmistika/dwl-better-resize/blob/main/demo/demo-nowarp-nolock.gif?raw=true) | ![demo-warp-lock](https://github.com/mmistika/dwl-better-resize/blob/main/demo/demo-warp-lock.gif?raw=true) |
| no warp + lock | warp + no lock |
|-|-|
| ![demo-nowarp-lock](https://github.com/mmistika/dwl-better-resize/blob/main/demo/demo-nowarp-lock.gif?raw=true) | ![demo-warp-nolock](https://github.com/mmistika/dwl-better-resize/blob/main/demo/demo-warp-nolock.gif?raw=true) |
### Known Issues (warp + lock)
The combination of warp_cursor and lock_cursor is not recommended without outer gaps.
If the selected resize corner aligns exactly with a screen corner, the cursor gets locked there and cannot be moved outward, so resizing only works inward.
To resize outward, you must restart the resize operation with the cursor positioned somewhere away from the screen corner.
This happens because the locked cursor cannot move past the screen edge, and therefore cannot generate a non-zero delta to resize outward.
On multihead setups, if the resize corner is near another screen, the window may switch monitors upon completion of the resize.
### Download
- [0.7](/dwl/dwl-patches/raw/branch/main/patches/better-resize/better-resize-0.7.patch)
### Authors
- [mmistika](https://codeberg.org/mmistika)
@@ -0,0 +1,107 @@
From f109808140cd6323b3a100663a10e048ae32e3a0 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
Signed-off-by: mmistika <mistikasoft@gmail.com>
---
config.def.h | 12 ++++++++++++
dwl.c | 45 +++++++++++++++++++++++++++++++++++++--------
2 files changed, 49 insertions(+), 8 deletions(-)
diff --git a/config.def.h b/config.def.h
index 22d2171..e404549 100644
--- a/config.def.h
+++ b/config.def.h
@@ -20,6 +20,18 @@ static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You ca
/* logging */
static int log_level = WLR_ERROR;
+/* window resizing */
+/* resize_corner:
+ * 0: top-left
+ * 1: top-right
+ * 2: bottom-left
+ * 3: bottom-right
+ * 4: closest to the cursor
+ */
+static const int resize_corner = 4;
+static const int warp_cursor = 1; /* 1: warp to corner, 0: dont warp */
+static const int lock_cursor = 0; /* 1: lock cursor, 0: don't lock */
+
/* 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 */
diff --git a/dwl.c b/dwl.c
index c717c1d..aacd074 100644
--- a/dwl.c
+++ b/dwl.c
@@ -407,6 +407,7 @@ static KeyboardGroup *kb_group;
static unsigned int cursor_mode;
static Client *grabc;
static int grabcx, grabcy; /* client-relative */
+static int rzcorner;
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
.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);
+ int cdx = (int)round(cursor->x) - grabcx;
+ int cdy = (int)round(cursor->y) - grabcy;
+
+ const struct wlr_box box = {
+ .x = grabc->geom.x + (rzcorner & 1 ? 0 : cdx),
+ .y = grabc->geom.y + (rzcorner & 2 ? 0 : cdy),
+ .width = grabc->geom.width + (rzcorner & 1 ? cdx : -cdx),
+ .height = grabc->geom.height + (rzcorner & 2 ? cdy : -cdy)
+ };
+ resize(grabc, box, 1);
+
+ if (!lock_cursor) {
+ grabcx += cdx;
+ grabcy += cdy;
+ } else {
+ wlr_cursor_warp_closest(cursor, NULL, grabcx, grabcy);
+ }
+
return;
}
@@ -1920,12 +1937,24 @@ moveresize(const Arg *arg)
wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur");
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");
+ const char *cursors[] = { "nw-resize", "ne-resize", "sw-resize", "se-resize" };
+
+ rzcorner = resize_corner;
+ grabcx = (int)round(cursor->x);
+ grabcy = (int)round(cursor->y);
+
+ if (rzcorner == 4)
+ /* identify the closest corner index */
+ rzcorner = (grabcx - grabc->geom.x < grabc->geom.x + grabc->geom.width - grabcx ? 0 : 1)
+ + (grabcy - grabc->geom.y < grabc->geom.y + grabc->geom.height - grabcy ? 0 : 2);
+
+ if (warp_cursor) {
+ grabcx = rzcorner & 1 ? grabc->geom.x + grabc->geom.width : grabc->geom.x;
+ grabcy = rzcorner & 2 ? grabc->geom.y + grabc->geom.height : grabc->geom.y;
+ wlr_cursor_warp_closest(cursor, NULL, grabcx, grabcy);
+ }
+
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, cursors[rzcorner]);
break;
}
}
--
2.50.1
+37
View File
@@ -0,0 +1,37 @@
### Description
Adds 2 more borders to each side (top, bottom, left, right) of every window.
<details>
<summary>Preview</summary>
<pre>
With the following config:
```c
static const unsigned int borderpx = 9; /* border pixel of windows */
static const unsigned int borderspx = 3; /* width of the border that start from outside the windows */
static const unsigned int borderepx = 3; /* width of the border that start from inside the windows */
```
and `border_color_type` set to `BrdOriginal`:
<img src="https://i.imgur.com/msead2K.png"/>
and `border_color_type` set to `BrdStart`:
<img src="https://i.imgur.com/ssgPG36.png"/>
and `border_color_type` set to `BrdEnd`:
<img src="https://i.imgur.com/i2Xtjy6.png"/>
and `border_color_type` set to `BrdStartEnd`:
<img src="https://i.imgur.com/fnkitdR.png"/>
</pre>
</details>
### Download
- [git branch](https://codeberg.org/wochap/dwl/src/branch/v0.5/borders)
- [2024-06-04](https://codeberg.org/dwl/dwl-patches/raw/commit/1a6825f2b8cd23044312c8040d0bf63ee7f85bc5/patches/borders/borders.patch)
- [v0.5](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/borders/borders.patch)
### Authors
- [wochap](https://codeberg.org/wochap)
+213
View File
@@ -0,0 +1,213 @@
From b12cfff672f0705d8259cf26b3a574faa5ca43ae Mon Sep 17 00:00:00 2001
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
change the size of the client
---
client.h | 16 +++++++++++++---
config.def.h | 8 ++++++++
dwl.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++----
3 files changed, 70 insertions(+), 7 deletions(-)
diff --git a/client.h b/client.h
index 800b867..33fd579 100644
--- a/client.h
+++ b/client.h
@@ -325,11 +325,21 @@ client_send_close(Client *c)
}
static inline void
-client_set_border_color(Client *c, const float color[static 4])
+client_set_border_color(Client *c, const float color[static 4], const float colors[static 4], const float colore[static 4])
{
int i;
- for (i = 0; i < 4; i++)
- wlr_scene_rect_set_color(c->border[i], color);
+ for (i = 0; i < 4; i++) {
+ if (border_color_type == BrdOriginal) {
+ wlr_scene_rect_set_color(c->border[i], color);
+ } else if (border_color_type == BrdStart) {
+ wlr_scene_rect_set_color(c->borders[i], colors);
+ } else if (border_color_type == BrdEnd) {
+ wlr_scene_rect_set_color(c->bordere[i], colore);
+ } else if (border_color_type == BrdStartEnd) {
+ wlr_scene_rect_set_color(c->borders[i], colors);
+ wlr_scene_rect_set_color(c->bordere[i], colore);
+ }
+ }
}
static inline void
diff --git a/config.def.h b/config.def.h
index 8847e58..2d6bbe5 100644
--- a/config.def.h
+++ b/config.def.h
@@ -7,8 +7,16 @@
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 unsigned int borderspx = 0; /* width of the border that start from outside the windows */
+static const unsigned int borderepx = 0; /* width of the border that start from inside the windows */
+static const unsigned int borderspx_offset = 0; /* offset of the border that start from outside the windows */
+static const unsigned int borderepx_negative_offset = 0; /* offset of the border that start from inside the windows */
static const float rootcolor[] = COLOR(0x222222ff);
static const float bordercolor[] = COLOR(0x444444ff);
+static const float borderscolor[] = COLOR(0x444444ff); /* color of the border that start from outside the windows */
+static const float borderecolor[] = COLOR(0x444444ff); /* color of the border that start from inside the windows */
+static const int border_color_type = BrdOriginal; /* borders to be colored (focuscolor, urgentcolor) */
+static const int borders_only_floating = 0;
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 */
diff --git a/dwl.c b/dwl.c
index bf763df..303832a 100644
--- a/dwl.c
+++ b/dwl.c
@@ -86,6 +86,7 @@ enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrTop, LyrFS, LyrOverlay, LyrBlock,
enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar,
NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */
#endif
+enum { BrdOriginal, BrdStart, BrdEnd, BrdStartEnd };
typedef union {
int i;
@@ -109,6 +110,8 @@ typedef struct {
Monitor *mon;
struct wlr_scene_tree *scene;
struct wlr_scene_rect *border[4]; /* top, bottom, left, right */
+ struct wlr_scene_rect *borders[4]; /* top, bottom, left, right */
+ struct wlr_scene_rect *bordere[4]; /* top, bottom, left, right */
struct wlr_scene_tree *scene_surface;
struct wl_list link;
struct wl_list flink;
@@ -136,6 +139,8 @@ typedef struct {
struct wl_listener set_hints;
#endif
unsigned int bw;
+ unsigned int bws;
+ unsigned int bwe;
uint32_t tags;
int isfloating, isurgent, isfullscreen;
uint32_t resize; /* configure serial of a pending resize */
@@ -973,6 +978,8 @@ createnotify(struct wl_listener *listener, void *data)
c = xdg_surface->data = ecalloc(1, sizeof(*c));
c->surface.xdg = xdg_surface;
c->bw = borderpx;
+ c->bws = borders_only_floating ? 0 : borderspx;
+ c->bwe = borders_only_floating ? 0 : borderepx;
wlr_xdg_toplevel_set_wm_capabilities(xdg_surface->toplevel,
WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN);
@@ -1268,7 +1275,7 @@ 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)
- client_set_border_color(c, focuscolor);
+ client_set_border_color(c, focuscolor, focuscolor, focuscolor);
}
/* Deactivate old client if focus is changing */
@@ -1285,7 +1292,7 @@ focusclient(Client *c, int lift)
/* Don't deactivate old client if the new one wants focus, as this causes issues with winecfg
* 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_border_color(old_c, bordercolor, borderscolor, borderecolor);
client_activate_surface(old, 0);
}
@@ -1597,6 +1604,12 @@ mapnotify(struct wl_listener *listener, void *data)
c->border[i] = wlr_scene_rect_create(c->scene, 0, 0,
c->isurgent ? urgentcolor : bordercolor);
c->border[i]->node.data = c;
+
+ c->borders[i] = wlr_scene_rect_create(c->scene, 0, 0, borderscolor);
+ c->borders[i]->node.data = c;
+
+ c->bordere[i] = wlr_scene_rect_create(c->scene, 0, 0, borderecolor);
+ c->bordere[i]->node.data = c;
}
/* Initialize client geometry with room for border */
@@ -1618,6 +1631,12 @@ mapnotify(struct wl_listener *listener, void *data)
} else {
applyrules(c);
}
+
+ if (borders_only_floating) {
+ c->bws = c->isfloating ? borderspx : 0;
+ c->bwe = c->isfloating ? borderepx : 0;
+ }
+
printstatus();
unset_fullscreen:
@@ -2051,6 +2070,24 @@ resize(Client *c, struct wlr_box geo, int interact)
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->borders[0], c->geom.width - 2 * borderspx_offset, c->bws);
+ wlr_scene_rect_set_size(c->borders[1], c->geom.width - 2 * borderspx_offset, c->bws);
+ wlr_scene_rect_set_size(c->borders[2], c->bws, c->geom.height - 2 * c->bws - 2 * borderspx_offset);
+ wlr_scene_rect_set_size(c->borders[3], c->bws, c->geom.height - 2 * c->bws - 2 * borderspx_offset);
+ wlr_scene_node_set_position(&c->borders[0]->node, borderspx_offset, borderspx_offset);
+ wlr_scene_node_set_position(&c->borders[1]->node, borderspx_offset, c->geom.height - c->bws - borderspx_offset);
+ wlr_scene_node_set_position(&c->borders[2]->node, borderspx_offset, c->bws + borderspx_offset);
+ wlr_scene_node_set_position(&c->borders[3]->node, c->geom.width - c->bws - borderspx_offset, c->bws + borderspx_offset);
+
+ wlr_scene_rect_set_size(c->bordere[0], c->geom.width - (c->bw - c->bwe) * 2 + borderepx_negative_offset * 2, c->bwe);
+ wlr_scene_rect_set_size(c->bordere[1], c->geom.width - (c->bw - c->bwe) * 2 + borderepx_negative_offset * 2, c->bwe);
+ wlr_scene_rect_set_size(c->bordere[2], c->bwe, c->geom.height - 2 * c->bw + 2 * borderepx_negative_offset);
+ wlr_scene_rect_set_size(c->bordere[3], c->bwe, c->geom.height - 2 * c->bw + 2 * borderepx_negative_offset);
+ wlr_scene_node_set_position(&c->bordere[0]->node, c->bw - c->bwe - borderepx_negative_offset, c->bw - c->bwe - borderepx_negative_offset);
+ wlr_scene_node_set_position(&c->bordere[1]->node, c->bw - c->bwe - borderepx_negative_offset, c->geom.height - c->bw + borderepx_negative_offset);
+ wlr_scene_node_set_position(&c->bordere[2]->node, c->bw - c->bwe - borderepx_negative_offset, c->bw - borderepx_negative_offset);
+ wlr_scene_node_set_position(&c->bordere[3]->node, c->geom.width - c->bw + borderepx_negative_offset, c->bw - borderepx_negative_offset);
+
/* this is a no-op if size hasn't changed */
c->resize = client_set_size(c, c->geom.width - 2 * c->bw,
c->geom.height - 2 * c->bw);
@@ -2151,6 +2188,12 @@ setfloating(Client *c, int floating)
c->isfloating = floating;
if (!c->mon)
return;
+
+ if (borders_only_floating) {
+ c->bws = c->isfloating ? borderspx : 0;
+ c->bwe = c->isfloating ? borderepx : 0;
+ }
+
wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen ||
(p && p->isfullscreen) ? LyrFS
: c->isfloating ? LyrFloat : LyrTile]);
@@ -2165,6 +2208,8 @@ setfullscreen(Client *c, int fullscreen)
if (!c->mon)
return;
c->bw = fullscreen ? 0 : borderpx;
+ c->bws = fullscreen ? 0 : borderspx;
+ c->bwe = fullscreen ? 0 : borderepx;
client_set_fullscreen(c, fullscreen);
wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen
? LyrFS : c->isfloating ? LyrFloat : LyrTile]);
@@ -2819,7 +2864,7 @@ urgent(struct wl_listener *listener, void *data)
printstatus();
if (client_surface(c)->mapped)
- client_set_border_color(c, urgentcolor);
+ client_set_border_color(c, urgentcolor, urgentcolor, urgentcolor);
}
void
@@ -3023,7 +3068,7 @@ sethints(struct wl_listener *listener, void *data)
printstatus();
if (c->isurgent && surface && surface->mapped)
- client_set_border_color(c, urgentcolor);
+ client_set_border_color(c, urgentcolor, urgentcolor, urgentcolor);
}
void
--
2.44.1
+27
View File
@@ -0,0 +1,27 @@
### Description
bstack and bstackhoriz are two stack layouts for dwl.
### Scheme
```
bstack (TTT) bstackhoriz (===)
+-----------------+ +-----------------+
| | | |
| | | |
| | | |
+-----+-----+-----+ +-----------------+
| | | | +-----------------+
| | | | +-----------------+
+-----+-----+-----+ +-----------------+
```
### Download
- [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
- [wochap](https://codeberg.org/wochap)
- [DanielMowitz](https://github.com/DanielMowitz)
- [Abanoub8](https://github.com/Abanoub8)
+140
View File
@@ -0,0 +1,140 @@
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
---
config.def.h | 4 +++
dwl.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 88 insertions(+)
diff --git a/config.def.h b/config.def.h
index 22d2171..5aac3e9 100644
--- a/config.def.h
+++ b/config.def.h
@@ -34,6 +34,8 @@ static const Layout layouts[] = {
{ "[]=", tile },
{ "><>", NULL }, /* no layout function means floating behavior */
{ "[M]", monocle },
+ { "TTT", bstack },
+ { "===", bstackhoriz },
};
/* 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} },
diff --git a/dwl.c b/dwl.c
index dc0437e..5648d5f 100644
--- a/dwl.c
+++ b/dwl.c
@@ -57,6 +57,7 @@
#include <wlr/types/wlr_xdg_decoration_v1.h>
#include <wlr/types/wlr_xdg_output_v1.h>
#include <wlr/types/wlr_xdg_shell.h>
+#include <wlr/util/box.h>
#include <wlr/util/log.h>
#include <wlr/util/region.h>
#include <xkbcommon/xkbcommon.h>
@@ -351,6 +352,8 @@ 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 bstack(Monitor *m);
+static void bstackhoriz(Monitor *m);
/* variables */
static const char broken[] = "broken";
@@ -3160,3 +3163,84 @@ main(int argc, char *argv[])
usage:
die("Usage: %s [-v] [-d] [-s startup command]", argv[0]);
}
+
+static void
+bstack(Monitor *m)
+{
+ int w, h, mh, mx, tx, ty, tw;
+ int i, n = 0;
+ Client *c;
+
+ wl_list_for_each(c, &clients, link)
+ if (VISIBLEON(c, m) && !c->isfloating)
+ n++;
+ if (n == 0)
+ return;
+
+ if (n > m->nmaster) {
+ mh = (int)round(m->nmaster ? m->mfact * m->w.height : 0);
+ tw = m->w.width / (n - m->nmaster);
+ ty = m->w.y + mh;
+ } else {
+ mh = m->w.height;
+ tw = m->w.width;
+ ty = m->w.y;
+ }
+
+ i = mx = 0;
+ tx = m-> w.x;
+ wl_list_for_each(c, &clients, link) {
+ if (!VISIBLEON(c, m) || c->isfloating)
+ continue;
+ if (i < m->nmaster) {
+ w = (m->w.width - mx) / (MIN(n, m->nmaster) - i);
+ resize(c, (struct wlr_box) { .x = m->w.x + mx, .y = m->w.y, .width = w, .height = mh }, 0);
+ mx += c->geom.width;
+ } else {
+ h = m->w.height - mh;
+ resize(c, (struct wlr_box) { .x = tx, .y = ty, .width = tw, .height = h }, 0);
+ if (tw != m->w.width)
+ tx += c->geom.width;
+ }
+ i++;
+ }
+}
+
+static void
+bstackhoriz(Monitor *m) {
+ int w, mh, mx, tx, ty, th;
+ int i, n = 0;
+ Client *c;
+
+ wl_list_for_each(c, &clients, link)
+ if (VISIBLEON(c, m) && !c->isfloating)
+ n ++;
+ if (n == 0)
+ return;
+
+ if (n > m->nmaster) {
+ mh = (int)round(m->nmaster ? m->mfact * m->w.height : 0);
+ th = (m->w.height - mh) / (n - m->nmaster);
+ ty = m->w.y + mh;
+ } else {
+ th = mh = m->w.height;
+ ty = m->w.y;
+ }
+
+ i = mx = 0;
+ tx = m-> w.x;
+ wl_list_for_each(c, &clients, link) {
+ if (!VISIBLEON(c,m) || c->isfloating)
+ continue;
+ if (i < m->nmaster) {
+ w = (m->w.width - mx) / (MIN(n, m->nmaster) - i);
+ resize(c, (struct wlr_box) { .x = m->w.x + mx, .y = m->w.y, .width = w, .height = mh }, 0);
+ mx += c->geom.width;
+ } else {
+ resize(c, (struct wlr_box) { .x = tx, .y = ty, .width = m->w.width, .height = th }, 0);
+ if (th != m->w.height)
+ ty += c->geom.height;
+ }
+ i++;
+ }
+}
--
2.45.1
+103
View File
@@ -0,0 +1,103 @@
### Description
# btrtile — A Focus-Driven Tiling Layout
It provides a focus-driven, mouse- and keyboard-friendly tiling layout that grants you granular control over how clients are placed and resized.
![btrtile in action](https://github.com/julmajustus/dwl-patches/blob/main/demos/btrtiledemo.gif?raw=true)
---
# Why btrtile
While dwls patches folder is full of different layouts, I couldn't find suitable layout that would work well with my workflow and single ultrawide monitor setup. btrtile aims to solve that by introducing a layout strategy that splits clients according to user focus and pointer position.
---
# Features
- **Combined Tiling and Management**
Combines tiling layout and management of clients under one patchset.
- **Focus-Driven Splits**
When you add a new client, btrtile checks where your pointer is relative to the focused clients geometry.
- If the pointer is on the left half (for a horizontally large client), the new client spawns on the left side, and vice versa.
- By default, new splits are 50/50.
- **Adaptive Splitting**
- If the area to be split is wider than its height, btrtile does a vertical split.
- Otherwise, it does a horizontal split.
- **Keyboard and Mouse Driven**
- Supports keyboard-based commands for quick ratio adjustments and client swapping.
- Mouse-based resizing and moving are integrated for more intuitive manipulation.
---
# How It Works
btrtile organizes clients using a binary tree data structure that represents splits either vertically or horizontally.
When a new client appears:
1. **Focused Client Detection**
btrtile checks your pointer location to find which client (if any) youre interacting with.
2. **Split Creation**
- If theres a focused client, btrtile creates a split node around it, placing the new client on the side where your pointer is.
3. **Ratio Management**
Each split node has a `split_ratio` (defaulting to 0.5). This ratio defines how much space is allocated to each child node. You can adjust this ratio using keyboard or mouse actions.
---
# What It Doesnt Handle
- **Suckless philosophy**
- Yea, it's a bloat. I tried to hide the suck inside a single file as much I could. While this approach is not ideal, it's how it's at least for now.
---
# Configuring btrtile
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.
Defaults to 0.0002f.
2. **resize_interval_ms**
- A time based resize call limiter. Depends on framerate and screen refresh rate.
Defaults to 16ms. (~60 resize updates per second)
Fine tune these values to find the best values for your setup, smoother resizing can significally increase cpu overhead.
If mouse resizing feels sluggish, you can try compiling dwl with more aggressive optimization flags like -O2/-O3.
---
# Patch recommendations
1. **Patches that I use with my btrtile**
- [focusdir](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/focusdir)
Great patch to move focus between clients.
- [rotatetags](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/rotatetags)
Good patch to rotate the view or shift clients between tags.
- [warpcursor](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/warpcursor)
Moves cursor location to focused client.
- [pertag](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/pertag)
Allows each tag to have individual layout setups.
- [gaps](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/gaps)
Add gaps between clients.
---
### 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)
### Authors
- [julmajustus](https://codeberg.org/julmajustus)
+922
View File
@@ -0,0 +1,922 @@
From 858ef20d36c2d5e6a23a69b3b5909a80fab05f97 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
---
btrtile.c | 582 +++++++++++++++++++++++++++++++++++++++++++++++++++
config.def.h | 12 ++
dwl.c | 152 +++++++++++---
3 files changed, 717 insertions(+), 29 deletions(-)
create mode 100644 btrtile.c
diff --git a/btrtile.c b/btrtile.c
new file mode 100644
index 0000000..650cab5
--- /dev/null
+++ b/btrtile.c
@@ -0,0 +1,582 @@
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* 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 */
+/* */
+/* ************************************************************************** */
+
+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(LayoutNode *start, unsigned int need_vert);
+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 int resizing_from_mouse = 0;
+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;
+ 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 were 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 || !m->root)
+ 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(LayoutNode *start_node, unsigned int need_vertical)
+{
+ LayoutNode *n = start_node;
+ /* if we started from a client node, jump to its parent: */
+ if (n && n->is_client_node)
+ 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;
+ 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;
+}
+
+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);
+}
+
+void
+setratio_h(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, 1);
+ 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);
+ }
+}
+
+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);
+ }
+}
+
+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 its a split node. */
+ return visible_count(node->left, m) + visible_count(node->right, m);
+}
+
+Client *
+xytoclient(double x, double 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 &&
+ 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, selmon) && !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 = sqrt(dx * dx + dy * dy);
+ if (dist < mindist) {
+ mindist = dist;
+ closest = c;
+ }
+ }
+ }
+ return closest;
+}
diff --git a/config.def.h b/config.def.h
index 22d2171..92f3ad6 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 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)
@@ -31,6 +34,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 },
@@ -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),
diff --git a/dwl.c b/dwl.c
index a2711f6..e49a061 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>
@@ -103,6 +104,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 {
#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 {
@@ -208,6 +211,7 @@ struct Monitor {
int nmaster;
char ltsymbol[16];
int asleep;
+ LayoutNode *root;
};
typedef struct {
@@ -250,6 +254,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);
@@ -333,6 +338,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);
@@ -431,6 +439,7 @@ static xcb_atom_t netatom[NetLast];
/* attempt to encapsulate suck into one file */
#include "client.h"
+#include "btrtile.c"
/* function implementations */
void
@@ -601,7 +610,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);
@@ -622,7 +631,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;
}
@@ -632,15 +641,36 @@ 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);
+ arrange(selmon);
+
+ } else if (cursor_mode == CurResize && !c->isfloating) {
+ resizing_from_mouse = 0;
+ }
+ } else {
+ if (cursor_mode == CurResize && resizing_from_mouse)
+ resizing_from_mouse = 0;
+ }
+ /* Default behaviour */
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)
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);
@@ -1024,6 +1055,7 @@ createmon(struct wl_listener *listener, void *data)
wl_list_insert(&mons, &m->link);
printstatus();
+ init_tree(m);
/* The xdg-protocol specifies:
*
@@ -1263,6 +1295,10 @@ destroynotify(struct wl_listener *listener, void *data)
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);
#ifdef XWAYLAND
if (c->type != XDGShell) {
wl_list_remove(&c->activate.link);
@@ -1809,7 +1845,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;
@@ -1863,18 +1900,56 @@ 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)
+ 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 && resizing_from_mouse) {
+ 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);
+ }
+ arrange(selmon);
+
+ 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. */
@@ -1908,22 +1983,41 @@ 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, "fleur");
- 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;
+ resizing_from_mouse = 1;
+ 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;
+ }
}
}
--
2.45.3
+903
View File
@@ -0,0 +1,903 @@
From b9789420f166c20579f29ecd171a8956c681848d 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
---
btrtile.c | 563 +++++++++++++++++++++++++++++++++++++++++++++++++++
config.def.h | 12 ++
dwl.c | 152 +++++++++++---
3 files changed, 698 insertions(+), 29 deletions(-)
create mode 100644 btrtile.c
diff --git a/btrtile.c b/btrtile.c
new file mode 100644
index 0000000..03f4680
--- /dev/null
+++ b/btrtile.c
@@ -0,0 +1,563 @@
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* 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 */
+/* */
+/* ************************************************************************** */
+
+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(LayoutNode *start, unsigned int need_vert);
+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 int resizing_from_mouse = 0;
+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;
+ 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 were 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 || !m->root)
+ 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(LayoutNode *start_node, unsigned int need_vertical)
+{
+ LayoutNode *n = start_node;
+ /* if we started from a client node, jump to its parent: */
+ if (n && n->is_client_node)
+ 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;
+ 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;
+}
+
+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);
+}
+
+void
+setratio_h(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, 1);
+ 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);
+ }
+}
+
+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);
+ }
+}
+
+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 its a split node. */
+ return visible_count(node->left, m) + visible_count(node->right, m);
+}
+
+Client *
+xytoclient(double x, double 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 &&
+ 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, selmon) && !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 = sqrt(dx * dx + dy * dy);
+ if (dist < mindist) {
+ mindist = dist;
+ closest = c;
+ }
+ }
+ }
+ return closest;
+}
diff --git a/config.def.h b/config.def.h
index 22d2171..92f3ad6 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 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)
@@ -31,6 +34,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 },
@@ -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),
diff --git a/dwl.c b/dwl.c
index a2711f6..e49a061 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>
@@ -103,6 +104,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 {
#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 {
@@ -208,6 +211,7 @@ struct Monitor {
int nmaster;
char ltsymbol[16];
int asleep;
+ LayoutNode *root;
};
typedef struct {
@@ -250,6 +254,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);
@@ -333,6 +338,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);
@@ -431,6 +439,7 @@ static xcb_atom_t netatom[NetLast];
/* attempt to encapsulate suck into one file */
#include "client.h"
+#include "btrtile.c"
/* function implementations */
void
@@ -601,7 +610,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);
@@ -622,7 +631,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;
}
@@ -632,15 +641,36 @@ 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);
+ arrange(selmon);
+
+ } else if (cursor_mode == CurResize && !c->isfloating) {
+ resizing_from_mouse = 0;
+ }
+ } else {
+ if (cursor_mode == CurResize && resizing_from_mouse)
+ resizing_from_mouse = 0;
+ }
+ /* Default behaviour */
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)
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);
@@ -1024,6 +1055,7 @@ createmon(struct wl_listener *listener, void *data)
wl_list_insert(&mons, &m->link);
printstatus();
+ init_tree(m);
/* The xdg-protocol specifies:
*
@@ -1263,6 +1295,10 @@ destroynotify(struct wl_listener *listener, void *data)
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);
#ifdef XWAYLAND
if (c->type != XDGShell) {
wl_list_remove(&c->activate.link);
@@ -1809,7 +1845,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;
@@ -1863,18 +1900,56 @@ 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)
+ 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 && resizing_from_mouse) {
+ 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);
+ }
+ arrange(selmon);
+
+ 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. */
@@ -1908,22 +1983,41 @@ 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, "fleur");
- 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;
+ resizing_from_mouse = 1;
+ 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;
+ }
}
}
--
2.45.3
+10
View File
@@ -0,0 +1,10 @@
### Description
Adds "state" (`enum wlr_button_state`) to configure a button action on either press or release.
This basically enables release to be used for button actions.
### Download
- [git branch](https://codeberg.org/nullsystem/dwl/src/branch/main_buttonbystate)
- [2024-04-06](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/buttonbystate/buttonbystate.patch)
### Authors
- [nullsystem](https://codeberg.org/nullsystem)
+78
View File
@@ -0,0 +1,78 @@
From 4141aa9455e4b4a5b4a235475c70e8c100ec663e Mon Sep 17 00:00:00 2001
From: nullsystem <nullsystem.aongp@slmail.me>
Date: Sat, 6 Apr 2024 02:03:49 +0100
Subject: [PATCH] buttonbystate - allow config for release (and press)
- Adds "state" (enum wlr_button_state) to configure a button action on
either press or release. This basically enables release to be used
for button actions.
---
config.def.h | 6 +++---
dwl.c | 22 ++++++++++++----------
2 files changed, 15 insertions(+), 13 deletions(-)
diff --git a/config.def.h b/config.def.h
index 8847e58..cc989cf 100644
--- a/config.def.h
+++ b/config.def.h
@@ -165,7 +165,7 @@ static const Key keys[] = {
};
static const Button buttons[] = {
- { MODKEY, BTN_LEFT, moveresize, {.ui = CurMove} },
- { MODKEY, BTN_MIDDLE, togglefloating, {0} },
- { MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize} },
+ { MODKEY, BTN_LEFT, moveresize, {.ui = CurMove}, WLR_BUTTON_PRESSED },
+ { MODKEY, BTN_MIDDLE, togglefloating, {0}, WLR_BUTTON_PRESSED },
+ { MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize}, WLR_BUTTON_PRESSED },
};
diff --git a/dwl.c b/dwl.c
index bf763df..6b60ccf 100644
--- a/dwl.c
+++ b/dwl.c
@@ -99,6 +99,7 @@ typedef struct {
unsigned int button;
void (*func)(const Arg *);
const Arg arg;
+ enum wlr_button_state state;
} Button;
typedef struct Monitor Monitor;
@@ -595,16 +596,6 @@ buttonpress(struct wl_listener *listener, void *data)
xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL);
if (c && (!client_is_unmanaged(c) || client_wants_focus(c)))
focusclient(c, 1);
-
- keyboard = wlr_seat_get_keyboard(seat);
- 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) {
- b->func(&b->arg);
- return;
- }
- }
break;
case WLR_BUTTON_RELEASED:
held_grab = NULL;
@@ -622,6 +613,17 @@ buttonpress(struct wl_listener *listener, void *data)
}
break;
}
+
+ keyboard = wlr_seat_get_keyboard(seat);
+ mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
+ for (b = buttons; b < END(buttons); b++) {
+ if (b->state == event->state && CLEANMASK(mods) == CLEANMASK(b->mod) &&
+ event->button == b->button && b->func) {
+ b->func(&b->arg);
+ return;
+ }
+ }
+
/* If the event wasn't handled by the compositor, notify the client with
* pointer focus that a button press has occurred */
wlr_seat_pointer_notify_button(seat,
--
2.44.0
+13
View File
@@ -0,0 +1,13 @@
### Description
Add a keybinding that toggles centering the terminally horizontally when
it's the only window, while still tiling multiple windows.
This limits the width of long text making it easier to read, and avoids
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)
### Authors
- [Guido Cella](https://codeberg.org/guidocella)
@@ -0,0 +1,103 @@
From 340cc5ef90dfcc495bdad045f3f76ae07405cffd Mon Sep 17 00:00:00 2001
From: Guido Cella <guido@guidocella.xyz>
Date: Tue, 6 Feb 2024 09:20:48 +0100
Subject: [PATCH] add a keybinding to center the terminal
Add a keybinding that toggles centering the terminally horizontally when
it's the only window, while still tiling multiple windows.
This limits the width of long text making it easier to read, and avoids
covering the wallpaper more than necessary.
---
config.def.h | 1 +
dwl.c | 20 ++++++++++++++++++++
2 files changed, 21 insertions(+)
diff --git a/config.def.h b/config.def.h
index 22d2171..8229fcc 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} },
diff --git a/dwl.c b/dwl.c
index 12f441e..3b15748 100644
--- a/dwl.c
+++ b/dwl.c
@@ -8,6 +8,7 @@
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
+#include <strings.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
@@ -138,6 +139,7 @@ typedef struct {
unsigned int bw;
uint32_t tags;
int isfloating, isurgent, isfullscreen;
+ bool centered;
uint32_t resize; /* configure serial of a pending resize */
} Client;
@@ -334,6 +336,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 togglecenter(const Arg *arg);
static void togglefloating(const Arg *arg);
static void togglefullscreen(const Arg *arg);
static void toggletag(const Arg *arg);
@@ -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 bool center;
+
#ifdef XWAYLAND
static void activatex11(struct wl_listener *listener, void *data);
static void associatex11(struct wl_listener *listener, void *data);
@@ -499,6 +504,9 @@ applyrules(Client *c)
}
}
+ if (!strcasecmp(appid, termcmd[0]))
+ c->centered = true;
+
c->isfloating |= client_is_float_type(c);
setmon(c, mon, newtags);
}
@@ -2730,6 +2738,11 @@ tile(Monitor *m)
if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
continue;
if (i < m->nmaster) {
+ if (n == 1 && center && c->centered) {
+ resize(c, (struct wlr_box){.x = m->w.width / 4, .y = m->w.y,
+ .width = m->w.width / 2, .height = m->w.height - 2 * c->bw}, 0);
+ return;
+ }
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)
}
}
+void
+togglecenter(const Arg *arg)
+{
+ center = !center;
+ tile(selmon);
+}
+
void
togglefloating(const Arg *arg)
{
--
2.49.0
+33
View File
@@ -0,0 +1,33 @@
### Description
This is a port of centeredmaster patch for dwm: <https://dwm.suckless.org/patches/centeredmaster>
centeredmaster centers the nmaster area on screen, using mfact * monitor
width & height, with the stacked windows distributed to the left and
right. It can be selected with `Alt+c`.
With one and two clients in master respectively this results in:
```
+------------------------------+ +------------------------------+
|+--------++--------++--------+| |+--------++--------++--------+|
|| || || || || || || ||
|| || || || || || M1 || ||
|| || || || || || || ||
|| S2 || M || S1 || || |+--------+| ||
|| || || || || |+--------+| ||
|| || || || || || || ||
|| || || || || || M2 || ||
|| || || || || || || ||
|+--------++--------++--------+| |+--------++--------++--------+|
+------------------------------+ +------------------------------+
```
### Download
- [0.7](/dwl/dwl-patches/raw/branch/main/patches/centeredmaster/centeredmaster.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)
+135
View File
@@ -0,0 +1,135 @@
From b1ca46930756b59c1ebba0b8c7871b85ff84f62f Mon Sep 17 00:00:00 2001
From: Nikita Ivanov <nikita.vyach.ivanov@gmail.com>
Date: Sat, 8 Feb 2025 16:10:25 +0100
Subject: [PATCH] Add centeredmaster layout
This is a port of centeredmaster patch for dwm:
https://dwm.suckless.org/patches/centeredmaster
centeredmaster centers the nmaster area on screen, using mfact * monitor
width & height, with the stacked windows distributed to the left and
right. It can be selected with [Alt]+[c].
With one and two clients in master respectively this results in:
+------------------------------+ +------------------------------+
|+--------++--------++--------+| |+--------++--------++--------+|
|| || || || || || || ||
|| || || || || || M1 || ||
|| || || || || || || ||
|| S2 || M || S1 || || |+--------+| ||
|| || || || || |+--------+| ||
|| || || || || || || ||
|| || || || || || M2 || ||
|| || || || || || || ||
|+--------++--------++--------+| |+--------++--------++--------+|
+------------------------------+ +------------------------------+
---
config.def.h | 2 ++
dwl.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 65 insertions(+)
diff --git a/config.def.h b/config.def.h
index 22d2171..9a3b0c5 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 },
+ { "|M|", centeredmaster },
};
/* 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_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 def2562..c2456dd 100644
--- a/dwl.c
+++ b/dwl.c
@@ -251,6 +251,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);
@@ -649,6 +650,68 @@ 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 */
+ 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 */
+ 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.48.1
+13
View File
@@ -0,0 +1,13 @@
### Description
This patch implements [cfact][cfact] for [snail][snail] layout.
This patch must be applied on top of cfact and snail patches.
[cfact]: /dwl/dwl-patches/src/branch/main/patches/cfact
[snail]: /dwl/dwl-patches/src/branch/main/patches/snail
### Download
- [v0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/cfact-snail/cfact-snail.patch)
### Authors
- [Nikita Ivanov](https://codeberg.org/nikitaivanov) ([GitHub](https://github.com/NikitaIvanovV))
+68
View File
@@ -0,0 +1,68 @@
From 9f8109182a7d173d2a2cb30c089a7e7b9ffe0a5e Mon Sep 17 00:00:00 2001
From: Nikita Ivanov <nikita.vyach.ivanov@gmail.com>
Date: Tue, 25 Mar 2025 02:24:32 +0100
Subject: [PATCH] cfact patch for snail layout
---
dwl.c | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/dwl.c b/dwl.c
index 4f8c493..37aa935 100644
--- a/dwl.c
+++ b/dwl.c
@@ -2699,10 +2699,10 @@ snail(Monitor *m)
* Split the previous horizontally and put the current window on the right
*/
} else if (dir == WLR_DIRECTION_RIGHT) {
- c->geom = (struct wlr_box){.x = prev->geom.x + prev->geom.width / 2, .y = prev->geom.y,
- .width = prev->geom.width / 2, .height = prev->geom.height};
+ c->geom = (struct wlr_box){.x = prev->geom.x + (int)(prev->cweight / (prev->cweight + c->cweight) * prev->geom.width), .y = prev->geom.y,
+ .width = (int)(c->cweight / (c->cweight + prev->cweight) * prev->geom.width), .height = prev->geom.height};
prev->geom = (struct wlr_box){.x = prev->geom.x, .y = prev->geom.y,
- .width = prev->geom.width / 2, .height = prev->geom.height};
+ .width = (int)(prev->cweight / (prev->cweight + c->cweight) * prev->geom.width), .height = prev->geom.height};
/*
* If it's a stack window or the first narrow window in the master
* area, put the next one below it
@@ -2713,28 +2713,28 @@ snail(Monitor *m)
* Split the previous vertically and put the current window below it
*/
} else if (dir == WLR_DIRECTION_DOWN) {
- c->geom = (struct wlr_box){.x = prev->geom.x, .y = prev->geom.y + prev->geom.height / 2,
- .width = prev->geom.width, .height = prev->geom.height / 2};
+ c->geom = (struct wlr_box){.x = prev->geom.x, .y = prev->geom.y + (int)(prev->cweight / (prev->cweight + c->cweight) * prev->geom.height),
+ .width = prev->geom.width, .height = (int)(c->cweight / (c->cweight + prev->cweight) * prev->geom.height)};
prev->geom = (struct wlr_box){.x = prev->geom.x, .y = prev->geom.y,
- .width = prev->geom.width, .height = prev->geom.height / 2};
+ .width = prev->geom.width, .height = (int)(prev->cweight / (prev->cweight + c->cweight) * prev->geom.height)};
dir = WLR_DIRECTION_LEFT;
/*
* Split the previous horizontally and put the current window on the left
*/
} else if (dir == WLR_DIRECTION_LEFT) {
c->geom = (struct wlr_box){.x = prev->geom.x, .y = prev->geom.y,
- .width = prev->geom.width / 2, .height = prev->geom.height};
- prev->geom = (struct wlr_box){.x = prev->geom.x + prev->geom.width / 2, .y = prev->geom.y,
- .width = prev->geom.width / 2, .height = prev->geom.height};
+ .width = (int)(c->cweight / (c->cweight + prev->cweight) * prev->geom.width), .height = prev->geom.height};
+ prev->geom = (struct wlr_box){.x = prev->geom.x + (int)(c->cweight / (c->cweight + prev->cweight) * prev->geom.width), .y = prev->geom.y,
+ .width = (int)(prev->cweight / (prev->cweight + c->cweight) * prev->geom.width), .height = prev->geom.height};
dir = WLR_DIRECTION_UP;
/*
* Split the previous vertically and put the current window above it
*/
} else {
c->geom = (struct wlr_box){.x = prev->geom.x, .y = prev->geom.y,
- .width = prev->geom.width, .height = prev->geom.height / 2};
- prev->geom = (struct wlr_box){.x = prev->geom.x, .y = prev->geom.y + prev->geom.height / 2,
- .width = prev->geom.width, .height = prev->geom.height / 2};
+ .width = prev->geom.width, .height = (int)(c->cweight / (c->cweight + prev->cweight) * prev->geom.height)};
+ prev->geom = (struct wlr_box){.x = prev->geom.x, .y = prev->geom.y + (int)(c->cweight / (c->cweight + prev->cweight) * prev->geom.height),
+ .width = prev->geom.width, .height = (int)(prev->cweight / (prev->cweight + c->cweight) * prev->geom.height)};
dir = WLR_DIRECTION_RIGHT;
}
i++;
--
2.49.0
+25
View File
@@ -0,0 +1,25 @@
### Description
A port of the [dwm cfacts patch](https://dwm.suckless.org/patches/cfacts/) (with the limits removed)
Clients with higher weight are allocated more space!
```
+---------------------+
| | 0.5 |
| 1.0 +----------+
+----------+ |
| | 1.0 |
| +----------+
| 2.0 | |
| | 1.0 |
+----------+----------+`
```
### Download
- [git branch](https://codeberg.org/Palanix/dwl/src/branch/cfact)
- [v0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/cfact/cfact-v0.7.patch)
- [v0.7-gaps](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/cfact/cfact-v0.7-gaps.patch)
- [v0.6](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/cfact/cfact-v0.6.patch)
- [2024-02-15](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/cfact/cfact.patch)
### Authors
- [dev-gm](https://codeberg.org/dev-gm)
- [Palanix](https://codeberg.org/Palanix)
+121
View File
@@ -0,0 +1,121 @@
From 52d8ed5ece7c96ea02441faaa4da2b0f51c8ebc4 Mon Sep 17 00:00:00 2001
From: Palanix <palanixyt@gmail.com>
Date: Fri, 24 Nov 2023 21:16:56 +0100
Subject: [PATCH] cweights to allow different size clients in normal layouts
---
config.def.h | 3 +++
dwl.c | 32 ++++++++++++++++++++++++++++++--
2 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/config.def.h b/config.def.h
index 22d2171..d1bc596 100644
--- a/config.def.h
+++ b/config.def.h
@@ -133,6 +133,9 @@ 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_SHIFT, XKB_KEY_H, setcfact, {.f = +0.25f} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_L, setcfact, {.f = -0.25f} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_K, setcfact, {.f = 0.0f} },
{ 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 145fd01..68e35d2 100644
--- a/dwl.c
+++ b/dwl.c
@@ -140,6 +140,7 @@ typedef struct {
uint32_t tags;
int isfloating, isurgent, isfullscreen;
uint32_t resize; /* configure serial of a pending resize */
+ float cweight;
} Client;
typedef struct {
@@ -318,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 setcfact(const Arg *arg);
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);
@@ -1041,6 +1043,7 @@ createnotify(struct wl_listener *listener, void *data)
c = xdg_surface->data = ecalloc(1, sizeof(*c));
c->surface.xdg = xdg_surface;
c->bw = borderpx;
+ c->cweight = 1.0;
wlr_xdg_toplevel_set_wm_capabilities(xdg_surface->toplevel,
WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN);
@@ -2218,6 +2221,19 @@ run(char *startup_cmd)
wl_display_run(dpy);
}
+void
+setcfact(const Arg *arg)
+{
+ Client *sel = focustop(selmon);
+
+ if(!arg || !sel || !selmon->lt[selmon->sellt]->arrange)
+ return;
+ sel->cweight = (float) (arg->f ? sel->cweight + arg->f : 1.0);
+ if (sel->cweight < 0)
+ sel->cweight = 0;
+ arrange(selmon);
+}
+
void
setcursor(struct wl_listener *listener, void *data)
{
@@ -2637,6 +2653,7 @@ tile(Monitor *m)
{
unsigned int mw, my, ty;
int i, n = 0;
+ float mweight = 0, tweight = 0;
Client *c;
wl_list_for_each(c, &clients, link)
@@ -2649,17 +2666,27 @@ tile(Monitor *m)
mw = m->nmaster ? (int)roundf(m->w.width * m->mfact) : 0;
else
mw = m->w.width;
+ i = 0;
+ wl_list_for_each(c, &clients, link){
+ if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
+ continue;
+ if (i < m->nmaster)
+ mweight += c->cweight;
+ else
+ tweight += c->cweight;
+ i++;
+ }
i = my = ty = 0;
wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
continue;
if (i < m->nmaster) {
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);
+ .height = (int) ((c->cweight / mweight) * m->w.height)}, 0);
my += c->geom.height;
} else {
resize(c, (struct wlr_box){.x = m->w.x + mw, .y = m->w.y + ty,
- .width = m->w.width - mw, .height = (m->w.height - ty) / (n - i)}, 0);
+ .width = m->w.width - mw, .height = (int) ((c->cweight / tweight) * m->w.height) }, 0);
ty += c->geom.height;
}
i++;
@@ -3047,6 +3074,7 @@ createnotifyx11(struct wl_listener *listener, void *data)
c->surface.xwayland = xsurface;
c->type = X11;
c->bw = client_is_unmanaged(c) ? 0 : borderpx;
+ c->cweight = 1.0;
/* Listen to the various events it can emit */
LISTEN(&xsurface->events.associate, &c->associate, associatex11);
--
2.45.2
+155
View File
@@ -0,0 +1,155 @@
From 31d0ceb3f7dea83282e61e556d71d06b7f43d753 Mon Sep 17 00:00:00 2001
From: Gavin M <git@gavinm.us>
Date: Sat, 16 Nov 2024 08:47:02 -0500
Subject: [PATCH] Add cfact to gaps
---
config.def.h | 3 +++
dwl.c | 63 +++++++++++++++++++++++++++++++++++++++++-----------
2 files changed, 53 insertions(+), 13 deletions(-)
diff --git a/config.def.h b/config.def.h
index b388b4e..a871364 100644
--- a/config.def.h
+++ b/config.def.h
@@ -136,6 +136,9 @@ 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_SHIFT, XKB_KEY_H, setcfact, {.f = +0.25f} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_L, setcfact, {.f = -0.25f} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_K, setcfact, {.f = 0.0f} },
{ MODKEY, XKB_KEY_Return, zoom, {0} },
{ MODKEY, XKB_KEY_Tab, view, {0} },
{ MODKEY, XKB_KEY_g, togglegaps, {0} },
diff --git a/dwl.c b/dwl.c
index dc851df..b5313c1 100644
--- a/dwl.c
+++ b/dwl.c
@@ -140,6 +140,7 @@ typedef struct {
uint32_t tags;
int isfloating, isurgent, isfullscreen;
uint32_t resize; /* configure serial of a pending resize */
+ float cweight;
} Client;
typedef struct {
@@ -319,6 +320,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 setcfact(const Arg *arg);
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);
@@ -1045,6 +1047,7 @@ createnotify(struct wl_listener *listener, void *data)
c = xdg_surface->data = ecalloc(1, sizeof(*c));
c->surface.xdg = xdg_surface;
c->bw = borderpx;
+ c->cweight = 1.0;
wlr_xdg_toplevel_set_wm_capabilities(xdg_surface->toplevel,
WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN);
@@ -2223,6 +2226,19 @@ run(char *startup_cmd)
wl_display_run(dpy);
}
+void
+setcfact(const Arg *arg)
+{
+ Client *sel = focustop(selmon);
+
+ if(!arg || !sel || !selmon->lt[selmon->sellt]->arrange)
+ return;
+ sel->cweight = (float) (arg->f ? sel->cweight + arg->f : 1.0);
+ if (sel->cweight < 0)
+ sel->cweight = 0;
+ arrange(selmon);
+}
+
void
setcursor(struct wl_listener *listener, void *data)
{
@@ -2642,38 +2658,58 @@ tagmon(const Arg *arg)
void
tile(Monitor *m)
{
- unsigned int h, r, e = m->gaps, mw, my, ty;
+ unsigned int e = m->gaps, mw, my, ty;
int i, n = 0;
- Client *c;
+ float mweight = 0, tweight = 0;
+ Client *c, *sel = NULL;
+
+ wl_list_for_each(c, &fstack, flink) {
+ if (VISIBLEON(c, m) && !c->isfullscreen) {
+ if (!sel)
+ sel = c;
+ if (!c->isfloating)
+ n++;
+ }
+ }
- wl_list_for_each(c, &clients, link)
- if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen)
- n++;
if (n == 0)
return;
+
if (smartgaps == n)
e = 0;
if (n > m->nmaster)
mw = m->nmaster ? (int)roundf((m->w.width + gappx*e) * m->mfact) : 0;
else
- mw = m->w.width;
+ mw = m->w.width - gappx*e;
+
+ i = 0;
+ wl_list_for_each(c, &clients, link){
+ if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
+ continue;
+ if (i < m->nmaster)
+ mweight += c->cweight;
+ else
+ tweight += c->cweight;
+ i++;
+ }
+
i = 0;
my = ty = gappx*e;
wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
continue;
if (i < m->nmaster) {
- r = MIN(n, m->nmaster) - i;
- h = (m->w.height - my - gappx*e - gappx*e * (r - 1)) / r;
resize(c, (struct wlr_box){.x = m->w.x + gappx*e, .y = m->w.y + my,
- .width = mw - 2*gappx*e, .height = h}, 0);
+ .width = mw - gappx*e,
+ .height = (int)((c->cweight / mweight) * (float)(m->w.height - gappx*e)) - gappx*e
+ }, 0);
my += c->geom.height + gappx*e;
} else {
- r = n - i;
- h = (m->w.height - ty - gappx*e - gappx*e * (r - 1)) / r;
- resize(c, (struct wlr_box){.x = m->w.x + mw, .y = m->w.y + ty,
- .width = m->w.width - mw - gappx*e, .height = h}, 0);
+ resize(c, (struct wlr_box){.x = m->w.x + mw + gappx*e, .y = m->w.y + ty,
+ .width = m->w.width - mw - 2*gappx*e,
+ .height = (int)((c->cweight / tweight) * (float)(m->w.height - gappx*e)) - gappx*e
+ }, 0);
ty += c->geom.height + gappx*e;
}
i++;
@@ -3068,6 +3104,7 @@ createnotifyx11(struct wl_listener *listener, void *data)
c->surface.xwayland = xsurface;
c->type = X11;
c->bw = client_is_unmanaged(c) ? 0 : borderpx;
+ c->cweight = 1.0;
/* Listen to the various events it can emit */
LISTEN(&xsurface->events.associate, &c->associate, associatex11);
--
2.47.0
+121
View File
@@ -0,0 +1,121 @@
From e82e15860c36a70539625b8fe7b4bd54d0721705 Mon Sep 17 00:00:00 2001
From: Palanix <palanixyt@gmail.com>
Date: Fri, 24 Nov 2023 21:16:56 +0100
Subject: [PATCH] cweights to allow different size clients in normal layouts
---
config.def.h | 3 +++
dwl.c | 32 ++++++++++++++++++++++++++++++--
2 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/config.def.h b/config.def.h
index 22d2171..d1bc596 100644
--- a/config.def.h
+++ b/config.def.h
@@ -133,6 +133,9 @@ 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_SHIFT, XKB_KEY_H, setcfact, {.f = +0.25f} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_L, setcfact, {.f = -0.25f} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_K, setcfact, {.f = 0.0f} },
{ 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 5bf995e..5a17343 100644
--- a/dwl.c
+++ b/dwl.c
@@ -141,6 +141,7 @@ typedef struct {
uint32_t tags;
int isfloating, isurgent, isfullscreen;
uint32_t resize; /* configure serial of a pending resize */
+ float cweight;
} Client;
typedef struct {
@@ -322,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 setcfact(const Arg *arg);
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);
@@ -1060,6 +1062,7 @@ createnotify(struct wl_listener *listener, void *data)
c = toplevel->base->data = ecalloc(1, sizeof(*c));
c->surface.xdg = toplevel->base;
c->bw = borderpx;
+ c->cweight = 1.0;
LISTEN(&toplevel->base->surface->events.commit, &c->commit, commitnotify);
LISTEN(&toplevel->base->surface->events.map, &c->map, mapnotify);
@@ -2268,6 +2271,19 @@ run(char *startup_cmd)
wl_display_run(dpy);
}
+void
+setcfact(const Arg *arg)
+{
+ Client *sel = focustop(selmon);
+
+ if(!arg || !sel || !selmon->lt[selmon->sellt]->arrange)
+ return;
+ sel->cweight = (float) (arg->f ? sel->cweight + arg->f : 1.0);
+ if (sel->cweight < 0)
+ sel->cweight = 0;
+ arrange(selmon);
+}
+
void
setcursor(struct wl_listener *listener, void *data)
{
@@ -2692,6 +2708,7 @@ tile(Monitor *m)
{
unsigned int mw, my, ty;
int i, n = 0;
+ float mweight = 0, tweight = 0;
Client *c;
wl_list_for_each(c, &clients, link)
@@ -2704,17 +2721,27 @@ tile(Monitor *m)
mw = m->nmaster ? (int)roundf(m->w.width * m->mfact) : 0;
else
mw = m->w.width;
+ i = 0;
+ wl_list_for_each(c, &clients, link){
+ if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
+ continue;
+ if (i < m->nmaster)
+ mweight += c->cweight;
+ else
+ tweight += c->cweight;
+ i++;
+ }
i = my = ty = 0;
wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
continue;
if (i < m->nmaster) {
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);
+ .height = (int) ((c->cweight / mweight) * m->w.height)}, 0);
my += c->geom.height;
} else {
resize(c, (struct wlr_box){.x = m->w.x + mw, .y = m->w.y + ty,
- .width = m->w.width - mw, .height = (m->w.height - ty) / (n - i)}, 0);
+ .width = m->w.width - mw, .height = (int) ((c->cweight / tweight) * m->w.height) }, 0);
ty += c->geom.height;
}
i++;
@@ -3102,6 +3129,7 @@ createnotifyx11(struct wl_listener *listener, void *data)
c->surface.xwayland = xsurface;
c->type = X11;
c->bw = client_is_unmanaged(c) ? 0 : borderpx;
+ c->cweight = 1.0;
/* Listen to the various events it can emit */
LISTEN(&xsurface->events.associate, &c->associate, associatex11);
--
2.45.2
+121
View File
@@ -0,0 +1,121 @@
From 98fe302cd240b519c28c886250273854844ab2c7 Mon Sep 17 00:00:00 2001
From: Palanix <palanixyt@gmail.com>
Date: Fri, 24 Nov 2023 21:16:56 +0100
Subject: [PATCH] cweights to allow different size clients in normal layouts
---
config.def.h | 3 +++
dwl.c | 32 ++++++++++++++++++++++++++++++--
2 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/config.def.h b/config.def.h
index 9009517..27ff521 100644
--- a/config.def.h
+++ b/config.def.h
@@ -128,6 +128,9 @@ 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_SHIFT, XKB_KEY_H, setcfact, {.f = +0.25f} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_L, setcfact, {.f = -0.25f} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_K, setcfact, {.f = 0.0f} },
{ 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 fa76db2..9bdb438 100644
--- a/dwl.c
+++ b/dwl.c
@@ -136,6 +136,7 @@ typedef struct {
uint32_t tags;
int isfloating, isurgent, isfullscreen;
uint32_t resize; /* configure serial of a pending resize */
+ float cweight;
} Client;
typedef struct {
@@ -301,6 +302,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 setcfact(const Arg *arg);
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);
@@ -956,6 +958,7 @@ createnotify(struct wl_listener *listener, void *data)
c = xdg_surface->data = ecalloc(1, sizeof(*c));
c->surface.xdg = xdg_surface;
c->bw = borderpx;
+ c->cweight = 1.0;
wlr_xdg_toplevel_set_wm_capabilities(xdg_surface->toplevel,
WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN);
@@ -2009,6 +2012,19 @@ run(char *startup_cmd)
wl_display_run(dpy);
}
+void
+setcfact(const Arg *arg)
+{
+ Client *sel = focustop(selmon);
+
+ if(!arg || !sel || !selmon->lt[selmon->sellt]->arrange)
+ return;
+ sel->cweight = (float) (arg->f ? sel->cweight + arg->f : 1.0);
+ if (sel->cweight < 0)
+ sel->cweight = 0;
+ arrange(selmon);
+}
+
void
setcursor(struct wl_listener *listener, void *data)
{
@@ -2468,6 +2484,7 @@ tile(Monitor *m)
{
unsigned int mw, my, ty;
int i, n = 0;
+ float mweight = 0, tweight = 0;
Client *c;
wl_list_for_each(c, &clients, link)
@@ -2480,17 +2497,27 @@ tile(Monitor *m)
mw = m->nmaster ? ROUND(m->w.width * m->mfact) : 0;
else
mw = m->w.width;
+ i = 0;
+ wl_list_for_each(c, &clients, link){
+ if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
+ continue;
+ if (i < m->nmaster)
+ mweight += c->cweight;
+ else
+ tweight += c->cweight;
+ i++;
+ }
i = my = ty = 0;
wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
continue;
if (i < m->nmaster) {
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);
+ .height = (int) ((c->cweight / mweight) * m->w.height)}, 0);
my += c->geom.height;
} else {
resize(c, (struct wlr_box){.x = m->w.x + mw, .y = m->w.y + ty,
- .width = m->w.width - mw, .height = (m->w.height - ty) / (n - i)}, 0);
+ .width = m->w.width - mw, .height = (int) ((c->cweight / tweight) * m->w.height) }, 0);
ty += c->geom.height;
}
i++;
@@ -2872,6 +2899,7 @@ createnotifyx11(struct wl_listener *listener, void *data)
c->surface.xwayland = xsurface;
c->type = X11;
c->bw = borderpx;
+ c->cweight = 1.0;
/* Listen to the various events it can emit */
LISTEN(&xsurface->events.associate, &c->associate, associatex11);
--
2.43.1
+15
View File
@@ -0,0 +1,15 @@
### Description
Implements chained keybindings (like the dwm
[keychain](https://dwm.suckless.org/patches/keychain/) patch).
Bindings can share a leading chain key. This chain key will be triggered when
Mod+chain is pressed. A subsequent keypress will be matched against bindings
for that chain key. If it is configured the action will be triggered, otherwise
the keypress will be ignored.
### Download
- [git branch](https://codeberg.org/bencc/dwl/src/branch/chainkeys)
- [2024-05-20](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/chainkeys/chainkeys.patch)
### Authors
- [Ben Collerson](https://codeberg.org/bencc)
+157
View File
@@ -0,0 +1,157 @@
From 226e204ec7fb6d6840a984ef8e8ec1d2514e985f Mon Sep 17 00:00:00 2001
From: Ben Collerson <benc@benc.cc>
Date: Tue, 2 Jan 2024 10:33:59 +1000
Subject: [PATCH] chainkeys
---
config.def.h | 62 ++++++++++++++++++++++++++--------------------------
dwl.c | 23 ++++++++++++++++++-
2 files changed, 53 insertions(+), 32 deletions(-)
diff --git a/config.def.h b/config.def.h
index 8f498d2f..1c182547 100644
--- a/config.def.h
+++ b/config.def.h
@@ -105,10 +105,10 @@ static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TA
#define MODKEY WLR_MODIFIER_ALT
#define TAGKEYS(KEY,SKEY,TAG) \
- { MODKEY, KEY, view, {.ui = 1 << TAG} }, \
- { MODKEY|WLR_MODIFIER_CTRL, KEY, toggleview, {.ui = 1 << TAG} }, \
- { MODKEY|WLR_MODIFIER_SHIFT, SKEY, tag, {.ui = 1 << TAG} }, \
- { MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT,SKEY,toggletag, {.ui = 1 << TAG} }
+ { MODKEY, -1, KEY, view, {.ui = 1 << TAG} }, \
+ { MODKEY|WLR_MODIFIER_CTRL, -1, KEY, toggleview, {.ui = 1 << TAG} }, \
+ { MODKEY|WLR_MODIFIER_SHIFT, -1, SKEY, tag, {.ui = 1 << TAG} }, \
+ { MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT,-1,SKEY,toggletag, {.ui = 1 << TAG} }
/* helper for spawning shell commands in the pre dwm-5.0 fashion */
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
@@ -119,30 +119,30 @@ static const char *menucmd[] = { "wmenu-run", NULL };
static const Key keys[] = {
/* Note that Shift changes certain key codes: c -> C, 2 -> at, etc. */
- /* modifier key function argument */
- { MODKEY, XKB_KEY_p, spawn, {.v = menucmd} },
- { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
- { MODKEY, XKB_KEY_j, focusstack, {.i = +1} },
- { MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
- { MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
- { MODKEY, XKB_KEY_d, incnmaster, {.i = -1} },
- { MODKEY, XKB_KEY_h, setmfact, {.f = -0.05f} },
- { MODKEY, XKB_KEY_l, setmfact, {.f = +0.05f} },
- { MODKEY, XKB_KEY_Return, zoom, {0} },
- { MODKEY, XKB_KEY_Tab, view, {0} },
- { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_C, killclient, {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]} },
- { MODKEY, XKB_KEY_space, setlayout, {0} },
- { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {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} },
- { 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} },
+ /* modifier chain, key function argument */
+ { MODKEY, -1, XKB_KEY_p, spawn, {.v = menucmd} },
+ { MODKEY|WLR_MODIFIER_SHIFT, -1, XKB_KEY_Return, spawn, {.v = termcmd} },
+ { MODKEY, -1, XKB_KEY_j, focusstack, {.i = +1} },
+ { MODKEY, -1, XKB_KEY_k, focusstack, {.i = -1} },
+ { MODKEY, -1, XKB_KEY_i, incnmaster, {.i = +1} },
+ { MODKEY, -1, XKB_KEY_d, incnmaster, {.i = -1} },
+ { MODKEY, -1, XKB_KEY_h, setmfact, {.f = -0.05f} },
+ { MODKEY, -1, XKB_KEY_l, setmfact, {.f = +0.05f} },
+ { MODKEY, -1, XKB_KEY_Return, zoom, {0} },
+ { MODKEY, -1, XKB_KEY_Tab, view, {0} },
+ { MODKEY|WLR_MODIFIER_SHIFT, -1, XKB_KEY_C, killclient, {0} },
+ { MODKEY, -1, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
+ { MODKEY, -1, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
+ { MODKEY, -1, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
+ { MODKEY, -1, XKB_KEY_space, setlayout, {0} },
+ { MODKEY|WLR_MODIFIER_SHIFT, -1, XKB_KEY_space, togglefloating, {0} },
+ { MODKEY, -1, XKB_KEY_e, togglefullscreen, {0} },
+ { MODKEY, -1, XKB_KEY_0, view, {.ui = ~0} },
+ { MODKEY|WLR_MODIFIER_SHIFT, -1, XKB_KEY_parenright, tag, {.ui = ~0} },
+ { MODKEY, -1, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} },
+ { MODKEY, -1, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} },
+ { MODKEY|WLR_MODIFIER_SHIFT, -1, XKB_KEY_less, tagmon, {.i = WLR_DIRECTION_LEFT} },
+ { MODKEY|WLR_MODIFIER_SHIFT, -1, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} },
TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0),
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
@@ -152,14 +152,14 @@ static const Key keys[] = {
TAGKEYS( XKB_KEY_7, XKB_KEY_ampersand, 6),
TAGKEYS( XKB_KEY_8, XKB_KEY_asterisk, 7),
TAGKEYS( XKB_KEY_9, XKB_KEY_parenleft, 8),
- { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Q, quit, {0} },
+ { MODKEY|WLR_MODIFIER_SHIFT, -1, XKB_KEY_Q, quit, {0} },
/* Ctrl-Alt-Backspace and Ctrl-Alt-Fx used to be handled by X server */
- { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_Terminate_Server, quit, {0} },
+ { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,-1,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
* do not remove them.
*/
-#define CHVT(n) { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_XF86Switch_VT_##n, chvt, {.ui = (n)} }
+#define CHVT(n) { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,-1,XKB_KEY_XF86Switch_VT_##n, chvt, {.ui = (n)} }
CHVT(1), CHVT(2), CHVT(3), CHVT(4), CHVT(5), CHVT(6),
CHVT(7), CHVT(8), CHVT(9), CHVT(10), CHVT(11), CHVT(12),
};
diff --git a/dwl.c b/dwl.c
index bf763dfc..05e667f8 100644
--- a/dwl.c
+++ b/dwl.c
@@ -143,6 +143,7 @@ typedef struct {
typedef struct {
uint32_t mod;
+ int chain;
xkb_keysym_t keysym;
void (*func)(const Arg *);
const Arg arg;
@@ -353,6 +354,7 @@ static const char broken[] = "broken";
static pid_t child_pid = -1;
static int locked;
static void *exclusive_focus;
+static int chainkey = -1;
static struct wl_display *dpy;
static struct wlr_backend *backend;
static struct wlr_scene *scene;
@@ -1438,11 +1440,30 @@ keybinding(uint32_t mods, xkb_keysym_t sym)
const Key *k;
for (k = keys; k < END(keys); k++) {
if (CLEANMASK(mods) == CLEANMASK(k->mod)
- && sym == k->keysym && k->func) {
+ && sym == k->keysym
+ && chainkey == -1
+ && k->chain == -1
+ && k->func) {
k->func(&k->arg);
return 1;
}
+ else if (sym == k->keysym
+ && chainkey != -1
+ && k->chain == chainkey
+ && k->func) {
+ k->func(&k->arg);
+ chainkey = -1;
+ return 1;
+ }
+ else if (CLEANMASK(mods) == CLEANMASK(k->mod)
+ && k->chain == (int)sym
+ && chainkey == -1
+ && k->func) {
+ chainkey = sym;
+ return 1;
+ }
}
+ chainkey = -1;
return 0;
}
--
2.43.0
+18
View File
@@ -0,0 +1,18 @@
### Description
This patch adds default transparency parameters to config.h which specify the starting transparencies of all windows.
It also adds opacities to the ruleset, enabling override of the opacities on a per client basis.
Additionally, it adds some shortcuts:
```
[MODKEY]+[o] -> increase focus opacity of currently focused window
[MODKEY]+[Shift]+[o] -> decrease focus opacity of currently focused window
```
### Download
- [git branch](https://codeberg.org/sevz/dwl/src/branch/client-opacity)
- [2025-01-20](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/client-opacity/client-opacity.patch)
### Authors
- [sevz](https://codeberg.org/sevz)
+181
View File
@@ -0,0 +1,181 @@
From ba3172875d379ff4f2db69753f50067cecfc8293 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?=
<leohdz172@proton.me>
Date: Tue, 25 Jul 2023 12:48:22 -0600
Subject: [PATCH] add default transparency for windows and rules for override
the transparency
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>
---
config.def.h | 9 ++++++---
dwl.c | 39 +++++++++++++++++++++++++++++++++++++++
2 files changed, 45 insertions(+), 3 deletions(-)
diff --git a/config.def.h b/config.def.h
index 22d2171d..0eb86874 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 default_opacity = 0.75;
/* 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 alpha 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, default_opacity, -1 }, /* Start on currently visible tags floating, not tiled */
+ { "firefox_EXAMPLE", NULL, 1 << 8, 0, 1.0, -1 }, /* Start on ONLY tag "9" */
};
/* layout(s) */
@@ -133,6 +134,8 @@ 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, XKB_KEY_o, setopacity, {.f = +0.1f} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_O, setopacity, {.f = -0.1f} },
{ 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 ad21e1ba..0554fcdf 100644
--- a/dwl.c
+++ b/dwl.c
@@ -138,6 +138,7 @@ typedef struct {
unsigned int bw;
uint32_t tags;
int isfloating, isurgent, isfullscreen;
+ float opacity;
uint32_t resize; /* configure serial of a pending resize */
} Client;
@@ -227,6 +228,7 @@ typedef struct {
const char *title;
uint32_t tags;
int isfloating;
+ float opacity;
int monitor;
} Rule;
@@ -319,6 +321,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 +329,7 @@ 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 setopacity(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);
@@ -491,6 +495,7 @@ applyrules(Client *c)
if ((!r->title || strstr(title, r->title))
&& (!r->id || strstr(appid, r->id))) {
c->isfloating = r->isfloating;
+ c->opacity = r->opacity;
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)
c = toplevel->base->data = ecalloc(1, sizeof(*c));
c->surface.xdg = toplevel->base;
c->bw = borderpx;
+ c->opacity = default_opacity;
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)
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)
{
@@ -2353,6 +2373,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();
}
@@ -2409,6 +2430,23 @@ setmon(Client *c, Monitor *m, uint32_t newtags)
focusclient(focustop(selmon), 1);
}
+void
+setopacity(const Arg *arg)
+{
+ Client *sel = focustop(selmon);
+ if (!sel)
+ return;
+
+ sel->opacity += arg->f;
+ if (sel->opacity > 1.0)
+ sel->opacity = 1.0f;
+
+ if (sel->opacity < 0.1)
+ sel->opacity = 0.1f;
+
+ wlr_scene_node_for_each_buffer(&sel->scene_surface->node, scenebuffersetopacity, sel);
+}
+
void
setpsel(struct wl_listener *listener, void *data)
{
@@ -3120,6 +3158,7 @@ createnotifyx11(struct wl_listener *listener, void *data)
c->surface.xwayland = xsurface;
c->type = X11;
c->bw = client_is_unmanaged(c) ? 0 : borderpx;
+ c->opacity = default_opacity;
/* Listen to the various events it can emit */
LISTEN(&xsurface->events.associate, &c->associate, associatex11);
--
2.48.0
+9
View File
@@ -0,0 +1,9 @@
### Description
A column layout patch. This patch just puts the visible clients into equal-width columns on the screen.
### Download
- [git branch](https://codeberg.org/bencc/dwl/src/branch/column)
- [2024-01-02](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/column/column.patch)
### Authors
- [Ben Collerson](https://codeberg.org/bencc)
+79
View File
@@ -0,0 +1,79 @@
From d1eb2061c619d0bbd7a0ecda0fe77409f3a6c399 Mon Sep 17 00:00:00 2001
From: Ben Collerson <benc@benc.cc>
Date: Fri, 29 Dec 2023 19:02:11 +1000
Subject: [PATCH] column layout
---
config.def.h | 2 ++
dwl.c | 28 ++++++++++++++++++++++++++++
2 files changed, 30 insertions(+)
diff --git a/config.def.h b/config.def.h
index a8ed61d9..edb30cae 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 },
+ { "||", col },
};
/* monitors */
@@ -134,6 +135,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 4d19357f..63d80da7 100644
--- a/dwl.c
+++ b/dwl.c
@@ -243,6 +243,7 @@ static void checkidleinhibitor(struct wlr_surface *exclude);
static void cleanup(void);
static void cleanupmon(struct wl_listener *listener, void *data);
static void closemon(Monitor *m);
+static void col(Monitor *m);
static void commitlayersurfacenotify(struct wl_listener *listener, void *data);
static void commitnotify(struct wl_listener *listener, void *data);
static void createdecoration(struct wl_listener *listener, void *data);
@@ -704,6 +705,33 @@ closemon(Monitor *m)
printstatus();
}
+void
+col(Monitor *m)
+{
+ Client *c;
+ unsigned int n = 0, i = 0;
+
+ wl_list_for_each(c, &clients, link)
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen)
+ n++;
+
+ wl_list_for_each(c, &clients, link) {
+ if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
+ continue;
+ resize(
+ c,
+ (struct wlr_box){
+ .x = m->w.x + i * m->w.width / n,
+ .y = m->w.y,
+ .width = m->w.width / n,
+ .height = m->w.height
+ },
+ 0
+ );
+ i++;
+ }
+}
+
void
commitlayersurfacenotify(struct wl_listener *listener, void *data)
{
--
2.43.0
+11
View File
@@ -0,0 +1,11 @@
### Description
Generate a coredump if dwl exited abnormally (to be more usefull you need to
compile dwl and wlroots with debug symbols)
### Download
- [git branch](https://codeberg.org/sevz/dwl/src/branch/coredump)
- [main 2025-01-20](/dwl/dwl-patches/raw/branch/main/patches/coredump/coredump.patch)
- [coredump-0.7.patch](/dwl/dwl-patches/raw/branch/main/patches/coredump/coredump-0.7.patch)
### Authors
- [sevz](https://codeberg.org/sevz)
+65
View File
@@ -0,0 +1,65 @@
From 2abde87f9159ec3318a0489ac0ed512f166ef8c8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?=
<leohdz172@proton.me>
Date: Wed, 5 Oct 2022 23:07:13 -0500
Subject: [PATCH] increase RLIMIT_CORE (generate a coredump)
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>
---
dwl.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/dwl.c b/dwl.c
index a2711f67..cfbb0bb8 100644
--- a/dwl.c
+++ b/dwl.c
@@ -8,6 +8,7 @@
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
+#include <sys/resource.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
@@ -358,6 +359,8 @@ static void zoom(const Arg *arg);
/* variables */
static const char broken[] = "broken";
+static struct rlimit oldrlimit;
+static struct rlimit newrlimit;
static pid_t child_pid = -1;
static int locked;
static void *exclusive_focus;
@@ -2232,6 +2235,7 @@ run(char *startup_cmd)
if ((child_pid = fork()) < 0)
die("startup: fork:");
if (child_pid == 0) {
+ setrlimit(RLIMIT_CORE, &oldrlimit);
setsid();
dup2(piperw[0], STDIN_FILENO);
close(piperw[0]);
@@ -2649,6 +2653,7 @@ void
spawn(const Arg *arg)
{
if (fork() == 0) {
+ setrlimit(RLIMIT_CORE, &oldrlimit);
dup2(STDERR_FILENO, STDOUT_FILENO);
setsid();
execvp(((char **)arg->v)[0], (char **)arg->v);
@@ -3189,6 +3194,10 @@ main(int argc, char *argv[])
char *startup_cmd = NULL;
int c;
+ getrlimit(RLIMIT_CORE, &oldrlimit);
+ newrlimit.rlim_cur = newrlimit.rlim_max = oldrlimit.rlim_max;
+ setrlimit(RLIMIT_CORE, &newrlimit);
+
while ((c = getopt(argc, argv, "s:hdv")) != -1) {
if (c == 's')
startup_cmd = optarg;
--
2.46.0
+65
View File
@@ -0,0 +1,65 @@
From 6d5017888891957615160fe7c015adf7a6f0fd45 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?=
<leohdz172@proton.me>
Date: Wed, 5 Oct 2022 23:07:13 -0500
Subject: [PATCH] increase RLIMIT_CORE (generate a coredump)
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>
---
dwl.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/dwl.c b/dwl.c
index ad21e1ba..940fbeff 100644
--- a/dwl.c
+++ b/dwl.c
@@ -8,6 +8,7 @@
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
+#include <sys/resource.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
@@ -353,6 +354,8 @@ static void xytonode(double x, double y, struct wlr_surface **psurface,
static void zoom(const Arg *arg);
/* variables */
+static struct rlimit oldrlimit;
+static struct rlimit newrlimit;
static pid_t child_pid = -1;
static int locked;
static void *exclusive_focus;
@@ -2248,6 +2251,7 @@ run(char *startup_cmd)
if ((child_pid = fork()) < 0)
die("startup: fork:");
if (child_pid == 0) {
+ setrlimit(RLIMIT_CORE, &oldrlimit);
setsid();
dup2(piperw[0], STDIN_FILENO);
close(piperw[0]);
@@ -2659,6 +2663,7 @@ void
spawn(const Arg *arg)
{
if (fork() == 0) {
+ setrlimit(RLIMIT_CORE, &oldrlimit);
dup2(STDERR_FILENO, STDOUT_FILENO);
setsid();
execvp(((char **)arg->v)[0], (char **)arg->v);
@@ -3178,6 +3183,10 @@ main(int argc, char *argv[])
char *startup_cmd = NULL;
int c;
+ getrlimit(RLIMIT_CORE, &oldrlimit);
+ newrlimit.rlim_cur = newrlimit.rlim_max = oldrlimit.rlim_max;
+ setrlimit(RLIMIT_CORE, &newrlimit);
+
while ((c = getopt(argc, argv, "s:hdv")) != -1) {
if (c == 's')
startup_cmd = optarg;
--
2.48.0
+17
View File
@@ -0,0 +1,17 @@
### Description
Adds ability to change cursor's theme and size.
```c
static const char *cursor_theme = NULL;
static const char cursor_size[] = "24"; /* Make sure it's a valid integer, otherwise things will break */
```
### Download
- [git branch](https://codeberg.org/wochap/dwl/src/branch/v0.5/cursortheme)
- [2024-07-09](https://codeberg.org/dwl/dwl-patches/raw/commit/13d96b51b54500dd24544cf3a73c61b7a1414bc6/patches/cursortheme/cursortheme.patch)
- [2024-04-11](https://codeberg.org/dwl/dwl-patches/raw/commit/b828e21717fa584affeb3245359c3ab615759fa4/cursortheme/cursortheme.patch)
- [v0.5](https://codeberg.org/dwl/dwl-patches/raw/commit/c676de59d51e613bd52ac46c77a24b1cac9a61a1/cursortheme/cursortheme.patch)
### Authors
- [wochap](https://codeberg.org/wochap)
- [egorguslyan](https://github.com/egorguslyan)
+46
View File
@@ -0,0 +1,46 @@
From f08376a2a04929a3907612e6c1f980ad3cdf939f Mon Sep 17 00:00:00 2001
From: wochap <gean.marroquin@gmail.com>
Date: Fri, 5 Jul 2024 11:10:39 -0500
Subject: [PATCH] implement cursortheme
---
config.def.h | 2 ++
dwl.c | 8 ++++++--
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/config.def.h b/config.def.h
index 22d2171..1f9ff56 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.1f, 0.1f, 0.1f, 1.0f}; /* You can also use glsl colors */
+static const char *cursor_theme = NULL;
+static const char cursor_size[] = "24"; /* Make sure it's a valid integer, otherwise things will break */
/* tagging - TAGCOUNT must be no greater than 31 */
#define TAGCOUNT (9)
diff --git a/dwl.c b/dwl.c
index dc0437e..a91d42b 100644
--- a/dwl.c
+++ b/dwl.c
@@ -2522,8 +2522,12 @@ setup(void)
* Xcursor themes to source cursor images from and makes sure that cursor
* images are available at all scale factors on the screen (necessary for
* HiDPI support). Scaled cursors will be loaded with each output. */
- cursor_mgr = wlr_xcursor_manager_create(NULL, 24);
- setenv("XCURSOR_SIZE", "24", 1);
+ cursor_mgr = wlr_xcursor_manager_create(cursor_theme, atoi(cursor_size));
+ setenv("XCURSOR_SIZE", cursor_size, 1);
+ if (cursor_theme)
+ setenv("XCURSOR_THEME", cursor_theme, 1);
+ else
+ unsetenv("XCURSOR_THEME");
/*
* wlr_cursor *only* displays an image on screen. It does not move around
--
2.45.1
+24
View File
@@ -0,0 +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)
+93
View File
@@ -0,0 +1,93 @@
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
+19
View File
@@ -0,0 +1,19 @@
### Description
Implements dimming of clients which are unfocused.
The code also allows any color dimming. There is also an additional option in `Rule`, which allows you to keep the client `neverdim`, that is, as if it is focused.
There are also two functions that can be bound to a `Key` or `Button`,
1. `toggledimming`: Which toggles dimming for all windows (except for `Rule`s)
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)
- [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)
- [2024-04-16](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/dim-unfocused/dim-unfocused-20240416.patch)
- [git branch](https://codeberg.org/dhruva_sambrani/dwl/src/branch/dim-unfocused)
### Authors
- [Dhruva Sambrani](https://codeberg.org/dhruva_sambrani)
@@ -0,0 +1,213 @@
From cd3b5580dbf38f54b54d5bfb6039e0039cbd6b21 Mon Sep 17 00:00:00 2001
From: Dhruva Sambrani <44899822+DhruvaSambrani@users.noreply.github.com>
Date: Thu, 16 May 2024 12:26:05 +0200
Subject: [PATCH] clean git history
---
client.h | 6 ++++++
config.def.h | 13 ++++++++-----
dwl.c | 40 +++++++++++++++++++++++++++++++++++-----
3 files changed, 49 insertions(+), 10 deletions(-)
diff --git a/client.h b/client.h
index 800b867..4d83248 100644
--- a/client.h
+++ b/client.h
@@ -332,6 +332,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 8f498d2..d3950f9 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 */
@@ -21,10 +22,11 @@ static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You ca
static int log_level = WLR_ERROR;
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) */
@@ -135,8 +137,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} },
diff --git a/dwl.c b/dwl.c
index bf763df..ca88ad0 100644
--- a/dwl.c
+++ b/dwl.c
@@ -109,6 +109,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;
@@ -137,7 +138,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;
@@ -227,6 +228,7 @@ typedef struct {
const char *title;
uint32_t tags;
int isfloating;
+ int neverdim;
int monitor;
} Rule;
@@ -330,6 +332,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 toggledimming(const Arg *arg);
static void togglefloating(const Arg *arg);
static void togglefullscreen(const Arg *arg);
static void toggletag(const Arg *arg);
@@ -404,6 +407,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);
@@ -462,6 +466,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) {
@@ -1267,8 +1272,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 */
@@ -1286,7 +1293,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);
}
}
@@ -1566,7 +1573,7 @@ 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 *w, *d, *c = wl_container_of(listener, c, map);
Monitor *m;
int i;
@@ -1599,6 +1606,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;
@@ -1617,6 +1628,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();
@@ -2040,7 +2055,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);
@@ -2050,6 +2065,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, c-> geom.height);
+ wlr_scene_node_set_position(&c->dimmer->node, 0, 0);
/* this is a no-op if size hasn't changed */
c->resize = client_set_size(c, c->geom.width - 2 * c->bw,
@@ -2603,6 +2620,19 @@ 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
togglefloating(const Arg *arg)
{
--
2.45.1
@@ -0,0 +1,177 @@
diff --git a/client.h b/client.h
index 800b867..4d83248 100644
--- a/client.h
+++ b/client.h
@@ -332,6 +332,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 8847e58..36ac2a1 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 */
@@ -21,10 +22,11 @@ static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You ca
static int log_level = WLR_ERROR;
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) */
@@ -135,8 +137,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} },
diff --git a/dwl.c b/dwl.c
index bf763df..abd7112 100644
--- a/dwl.c
+++ b/dwl.c
@@ -109,6 +109,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;
@@ -137,7 +138,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;
@@ -227,6 +228,7 @@ typedef struct {
const char *title;
uint32_t tags;
int isfloating;
+ int neverdim;
int monitor;
} Rule;
@@ -330,6 +332,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 toggledimming(const Arg *arg);
static void togglefloating(const Arg *arg);
static void togglefullscreen(const Arg *arg);
static void toggletag(const Arg *arg);
@@ -404,6 +407,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);
@@ -462,6 +466,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) {
@@ -1267,8 +1272,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 */
@@ -1286,7 +1293,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);
}
}
@@ -1599,6 +1606,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;
@@ -2040,7 +2051,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);
@@ -2050,6 +2061,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, c-> geom.height);
+ wlr_scene_node_set_position(&c->dimmer->node, 0, 0);
/* this is a no-op if size hasn't changed */
c->resize = client_set_size(c, c->geom.width - 2 * c->bw,
@@ -2603,6 +2616,17 @@ 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);
+ }
+ client_set_dimmer_state(focustop(selmon), 0);
+}
+
void
togglefloating(const Arg *arg)
{
@@ -0,0 +1,199 @@
diff --git a/client.h b/client.h
index f0e5445..04b8d31 100644
--- a/client.h
+++ b/client.h
@@ -320,6 +320,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..e1b2bf0 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} },
diff --git a/dwl.c b/dwl.c
index 145fd01..6c65860 100644
--- a/dwl.c
+++ b/dwl.c
@@ -110,6 +110,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;
@@ -138,7 +139,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;
@@ -229,6 +230,7 @@ typedef struct {
const char *title;
uint32_t tags;
int isfloating;
+ int neverdim;
int monitor;
} Rule;
@@ -334,6 +336,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 toggledimming(const Arg *arg);
static void togglefloating(const Arg *arg);
static void togglefullscreen(const Arg *arg);
static void toggletag(const Arg *arg);
@@ -407,6 +410,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);
@@ -465,6 +469,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) {
@@ -1346,8 +1351,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 */
@@ -1365,7 +1372,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);
}
}
@@ -1638,7 +1645,7 @@ void
mapnotify(struct wl_listener *listener, void *data)
{
/* Called when the surface is mapped, or ready to display on-screen. */
- Client *p, *w, *c = wl_container_of(listener, c, map);
+ Client *p, *w, *d, *c = wl_container_of(listener, c, map);
Monitor *m;
int i;
@@ -1670,6 +1677,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;
@@ -1688,6 +1699,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();
@@ -2141,7 +2156,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);
@@ -2151,6 +2166,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,
@@ -2666,6 +2683,19 @@ 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
togglefloating(const Arg *arg)
{
@@ -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 9021e44..e1f32e9 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) {
@@ -1366,8 +1372,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 */
@@ -1385,7 +1393,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);
}
}
@@ -1682,8 +1690,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;
@@ -1717,6 +1724,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;
@@ -1735,6 +1746,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();
@@ -2161,7 +2176,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);
@@ -2171,6 +2186,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,
@@ -2682,6 +2699,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)
{
+216
View File
@@ -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)
{
@@ -0,0 +1,11 @@
### Description
This patch changes the default behavior of the [disable-keybindings-on-fullscreen](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/disable-keybindings-on-fullscreen) patch by only taking effect when you explicitly toggle the functionality.
You must apply that patch prior to applying this one.
### Download
- [git branch](https://github.com/Shringe/dwl/tree/disable-keybindings-on-fullscreen-toggle)
- [0.7](/dwl/dwl-patches/raw/branch/main/patches/disable-keybindings-on-fullscreen-toggle/disable-keybindings-on-fullscreen-toggle-0.7.patch)
### Authors
- [Shringe](https://codeberg.org/Shringe)
- shringe_ at [dwl Discord](https://discord.gg/jJxZnrGPWN)
@@ -0,0 +1,71 @@
From 71809cee0e27f1b3620773e1745afed8023f71c9 Mon Sep 17 00:00:00 2001
From: Shringe <dashingkoso@gmail.com>
Date: Mon, 23 Jun 2025 18:50:40 -0500
Subject: [PATCH] Implemented functionality for patch
---
config.def.h | 1 +
dwl.c | 14 ++++++++++++--
2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/config.def.h b/config.def.h
index 22d2171..dda4ad0 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|WLR_MODIFIER_SHIFT, XKB_KEY_G, togglefullscreenkeyinhibit, {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 f11de4b..5deb9c7 100644
--- a/dwl.c
+++ b/dwl.c
@@ -341,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 togglefullscreenkeyinhibit(const Arg *arg);
static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
static void unlocksession(struct wl_listener *listener, void *data);
@@ -414,6 +415,8 @@ static struct wlr_box sgeom;
static struct wl_list mons;
static Monitor *selmon;
+static int fullscreen_key_inhibit_enabled = 0;
+
#ifdef XWAYLAND
static void activatex11(struct wl_listener *listener, void *data);
static void associatex11(struct wl_listener *listener, void *data);
@@ -1583,8 +1586,9 @@ keybinding(uint32_t mods, xkb_keysym_t sym)
for (k = keys; k < END(keys); k++) {
if (CLEANMASK(mods) == CLEANMASK(k->mod)
&& sym == k->keysym && k->func) {
- if (c && c->isfullscreen) {
- if (k->func == togglefullscreen) {
+ if (fullscreen_key_inhibit_enabled
+ && c && c->isfullscreen) {
+ if (k->func == togglefullscreenkeyinhibit) {
k->func(&k->arg);
return 1;
}
@@ -2763,6 +2767,12 @@ togglefullscreen(const Arg *arg)
setfullscreen(sel, !sel->isfullscreen);
}
+void
+togglefullscreenkeyinhibit(const Arg *arg)
+{
+ fullscreen_key_inhibit_enabled = !fullscreen_key_inhibit_enabled;
+}
+
void
toggletag(const Arg *arg)
{
--
2.49.0
@@ -0,0 +1,9 @@
### Description
This patch disables all keybindings except `togglefullscreen` when the focused window is fullscreen.
Might help prevent fat-fingering.
### Download
- [git branch](https://codeberg.org/korei999/dwl/src/branch/disable-keybindings-on-fullscreen)
- [2025-02-09](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/disable-keybindings-on-fullscreen/disable-keybindings-on-fullscreen.patch)
### Authors
- [korei999](https://codeberg.org/korei999)
@@ -0,0 +1,82 @@
From 2d6b845701091d3238774747c718df7fef135986 Mon Sep 17 00:00:00 2001
From: korei999 <ju7t1xe@gmail.com>
Date: Sun, 9 Feb 2025 14:59:33 +0200
Subject: [PATCH] disable keybindings on fullscreen
---
dwl.c | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/dwl.c b/dwl.c
index ec4ca86..8c771e8 100644
--- a/dwl.c
+++ b/dwl.c
@@ -282,6 +282,7 @@ 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 Client *firstfocused(void);
static void focusclient(Client *c, int lift);
static void focusmon(const Arg *arg);
static void focusstack(const Arg *arg);
@@ -620,11 +621,15 @@ 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, *focused;
const Button *b;
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
+ focused = firstfocused();
+ if (focused && focused->isfullscreen)
+ goto skip_click;
+
switch (event->state) {
case WL_POINTER_BUTTON_STATE_PRESSED:
cursor_mode = CurPressed;
@@ -664,6 +669,7 @@ buttonpress(struct wl_listener *listener, void *data)
}
/* If the event wasn't handled by the compositor, notify the client with
* pointer focus that a button press has occurred */
+skip_click:
wlr_seat_pointer_notify_button(seat,
event->time_msec, event->button, event->state);
}
@@ -1393,6 +1399,13 @@ dirtomon(enum wlr_direction dir)
return selmon;
}
+Client *
+firstfocused(void)
+{
+ Client *c = wl_container_of(fstack.next, c, flink);
+ return c;
+}
+
void
focusclient(Client *c, int lift)
{
@@ -1607,10 +1620,18 @@ keybinding(uint32_t mods, xkb_keysym_t sym)
* processing keys, rather than passing them on to the client for its own
* processing.
*/
+ Client *c = firstfocused();
const Key *k;
for (k = keys; k < END(keys); k++) {
if (CLEANMASK(mods) == CLEANMASK(k->mod)
&& sym == k->keysym && k->func) {
+ if (c && c->isfullscreen) {
+ if (k->func == togglefullscreen) {
+ k->func(&k->arg);
+ return 1;
+ }
+ return 0;
+ }
k->func(&k->arg);
return 1;
}
--
2.48.1
+11
View File
@@ -0,0 +1,11 @@
### Description
Change mfact by dragging the mouse.
### Download
- [git branch](https://codeberg.org/Palanix/dwl/src/branch/dragmfact)
- [v0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/dragmfact/dragmfact-v0.7.patch)
- [v0.6](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/dragmfact/dragmfact-v0.6.patch)
- [2024-02-16](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/dragmfact/dragmfact.patch)
### Authors
- [Palanix](https://codeberg.org/Palanix)
+59
View File
@@ -0,0 +1,59 @@
From aeee958aec3e0774f3ea8baefe028e1a8cc2d2ce Mon Sep 17 00:00:00 2001
From: Palanix <palanixyt@gmail.com>
Date: Fri, 25 Mar 2022 23:45:10 +0100
Subject: [PATCH] Change mfact using Middle mouse
---
config.def.h | 2 +-
dwl.c | 9 ++++++++-
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/config.def.h b/config.def.h
index 22d2171..c9071a5 100644
--- a/config.def.h
+++ b/config.def.h
@@ -171,6 +171,6 @@ static const Key keys[] = {
static const Button buttons[] = {
{ MODKEY, BTN_LEFT, moveresize, {.ui = CurMove} },
- { MODKEY, BTN_MIDDLE, togglefloating, {0} },
+ { MODKEY, BTN_MIDDLE, moveresize, {.ui = Curmfact} },
{ MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize} },
};
diff --git a/dwl.c b/dwl.c
index 145fd01..0a3d140 100644
--- a/dwl.c
+++ b/dwl.c
@@ -80,7 +80,7 @@
#define LISTEN_STATIC(E, H) do { static struct wl_listener _l = {.notify = (H)}; wl_signal_add((E), &_l); } while (0)
/* enums */
-enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */
+enum { CurNormal, CurPressed, CurMove, CurResize, Curmfact }; /* cursor */
enum { XDGShell, LayerShell, X11 }; /* client types */
enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrTop, LyrFS, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */
#ifdef XWAYLAND
@@ -1823,6 +1823,9 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
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;
+ } else if (cursor_mode == Curmfact && time) {
+ selmon->mfact = (float) (cursor->x / selmon->m.width);
+ arrange(selmon);
}
/* If there's no client surface under the cursor, set the cursor image to a
@@ -1874,6 +1877,10 @@ moveresize(const Arg *arg)
grabc->geom.y + grabc->geom.height);
wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
break;
+ case Curmfact:
+ setfloating(grabc, 0);
+ selmon->mfact = (float) (cursor->x / selmon->m.width);
+ arrange(selmon);
}
}
--
2.45.2
+59
View File
@@ -0,0 +1,59 @@
From ae44bfc181fc1532d2f0c4deb20e20634050a661 Mon Sep 17 00:00:00 2001
From: Palanix <palanixyt@gmail.com>
Date: Fri, 25 Mar 2022 23:45:10 +0100
Subject: [PATCH] Change mfact using Middle mouse
---
config.def.h | 2 +-
dwl.c | 9 ++++++++-
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/config.def.h b/config.def.h
index 22d2171..c9071a5 100644
--- a/config.def.h
+++ b/config.def.h
@@ -171,6 +171,6 @@ static const Key keys[] = {
static const Button buttons[] = {
{ MODKEY, BTN_LEFT, moveresize, {.ui = CurMove} },
- { MODKEY, BTN_MIDDLE, togglefloating, {0} },
+ { MODKEY, BTN_MIDDLE, moveresize, {.ui = Curmfact} },
{ MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize} },
};
diff --git a/dwl.c b/dwl.c
index 5bf995e..dfb0754 100644
--- a/dwl.c
+++ b/dwl.c
@@ -81,7 +81,7 @@
#define LISTEN_STATIC(E, H) do { static struct wl_listener _l = {.notify = (H)}; wl_signal_add((E), &_l); } while (0)
/* enums */
-enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */
+enum { CurNormal, CurPressed, CurMove, CurResize, Curmfact }; /* cursor */
enum { XDGShell, LayerShell, X11 }; /* client types */
enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrTop, LyrFS, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */
#ifdef XWAYLAND
@@ -1872,6 +1872,9 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
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;
+ } else if (cursor_mode == Curmfact && time) {
+ selmon->mfact = (float) (cursor->x / selmon->m.width);
+ arrange(selmon);
}
/* If there's no client surface under the cursor, set the cursor image to a
@@ -1923,6 +1926,10 @@ moveresize(const Arg *arg)
grabc->geom.y + grabc->geom.height);
wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
break;
+ case Curmfact:
+ setfloating(grabc, 0);
+ selmon->mfact = (float) (cursor->x / selmon->m.width);
+ arrange(selmon);
}
}
--
2.45.2
+59
View File
@@ -0,0 +1,59 @@
From 435cdf673e5a8080123109dbf874aac2ccef1498 Mon Sep 17 00:00:00 2001
From: Palanix <palanixyt@gmail.com>
Date: Fri, 25 Mar 2022 23:45:10 +0100
Subject: [PATCH] Change mfact using Middle mouse
---
config.def.h | 2 +-
dwl.c | 9 ++++++++-
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/config.def.h b/config.def.h
index 9009517..3c26522 100644
--- a/config.def.h
+++ b/config.def.h
@@ -166,6 +166,6 @@ static const Key keys[] = {
static const Button buttons[] = {
{ MODKEY, BTN_LEFT, moveresize, {.ui = CurMove} },
- { MODKEY, BTN_MIDDLE, togglefloating, {0} },
+ { MODKEY, BTN_MIDDLE, moveresize, {.ui = Curmfact} },
{ MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize} },
};
diff --git a/dwl.c b/dwl.c
index fa76db2..528e102 100644
--- a/dwl.c
+++ b/dwl.c
@@ -76,7 +76,7 @@
#define LISTEN_STATIC(E, H) do { static struct wl_listener _l = {.notify = (H)}; wl_signal_add((E), &_l); } while (0)
/* enums */
-enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */
+enum { CurNormal, CurPressed, CurMove, CurResize, Curmfact }; /* cursor */
enum { XDGShell, LayerShell, X11 }; /* client types */
enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrFS, LyrTop, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */
#ifdef XWAYLAND
@@ -1639,6 +1639,9 @@ motionnotify(uint32_t time)
resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y,
.width = ROUND(cursor->x) - grabc->geom.x, .height = ROUND(cursor->y) - grabc->geom.y}, 1);
return;
+ } else if (cursor_mode == Curmfact && time) {
+ selmon->mfact = (float) (cursor->x / selmon->m.width);
+ arrange(selmon);
}
/* Find the client under the pointer and send the event along. */
@@ -1701,6 +1704,10 @@ moveresize(const Arg *arg)
grabc->geom.y + grabc->geom.height);
wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
break;
+ case Curmfact:
+ setfloating(grabc, 0);
+ selmon->mfact = (float) (cursor->x / selmon->m.width);
+ arrange(selmon);
}
}
--
2.43.2
+12
View File
@@ -0,0 +1,12 @@
### Description
implement rio-like window resizing
select window to resize (mod+middleclick by default) then drag out an area for it to occupy
### Download
- [git branch](https://codeberg.org/notchoc/dwl/src/branch/dragresize)
- [2024-07-10](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/dragresize/dragresize.patch)
- [2024-06-19](https://codeberg.org/dwl/dwl-patches/raw/commit/8c75e6dbc1728bf70d42547222464f496d9ea613/patches/dragresize/dragresize.patch)
### Authors
- [notchoc](https://codeberg.org/notchoc)
+210
View File
@@ -0,0 +1,210 @@
From 83ae7d4816a49f46063ab16ffecd32b2e7e61784 Mon Sep 17 00:00:00 2001
From: choc <notchoc@proton.me>
Date: Fri, 15 Sep 2023 11:45:16 +0800
Subject: [PATCH] dragresize: implement rio-like window resizing
select window to resize then drag out an area for it to occupy
---
dwl.c | 132 +++++++++++++++++++++++++++++++++++++++++++---------------
1 file changed, 98 insertions(+), 34 deletions(-)
diff --git a/dwl.c b/dwl.c
index dc0437e..843aa7a 100644
--- a/dwl.c
+++ b/dwl.c
@@ -80,7 +80,7 @@
#define LISTEN_STATIC(E, H) do { static struct wl_listener _l = {.notify = (H)}; wl_signal_add((E), &_l); } while (0)
/* enums */
-enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */
+enum { CurNormal, CurPressed, CurSelect, CurMove, CurResize, CurBind }; /* cursor */
enum { XDGShell, LayerShell, X11 }; /* client types */
enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrTop, LyrFS, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */
#ifdef XWAYLAND
@@ -603,15 +603,21 @@ buttonpress(struct wl_listener *listener, void *data)
switch (event->state) {
case WLR_BUTTON_PRESSED:
- cursor_mode = CurPressed;
selmon = xytomon(cursor->x, cursor->y);
- if (locked)
+ if (locked) {
+ cursor_mode = CurPressed;
break;
+ }
- /* Change focus if the button was _pressed_ over a client */
- xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL);
- if (c && (!client_is_unmanaged(c) || client_wants_focus(c)))
- focusclient(c, 1);
+ if (cursor_mode == CurNormal)
+ cursor_mode = CurPressed;
+
+ if (cursor_mode != CurResize) {
+ /* Change focus if the button was _pressed_ over a client */
+ xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL);
+ if (c && (!client_is_unmanaged(c) || client_wants_focus(c)))
+ focusclient(c, 1);
+ }
keyboard = wlr_seat_get_keyboard(seat);
mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
@@ -624,17 +630,42 @@ buttonpress(struct wl_listener *listener, void *data)
}
break;
case WLR_BUTTON_RELEASED:
+ if (locked) {
+ cursor_mode = CurNormal;
+ break;
+ }
/* 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) {
- wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
+ switch (cursor_mode) {
+ case CurPressed:
cursor_mode = CurNormal;
- /* Drop the window off on its new monitor */
- selmon = xytomon(cursor->x, cursor->y);
- setmon(grabc, selmon, 0);
+ case CurNormal:
+ break;
+ case CurSelect:
return;
- } else {
+ case CurResize:
+ /* a label can only be part of a statement - Wpedantic */
+ {
+ int nw = abs((int) cursor->x - grabcx);
+ int nh = abs((int) cursor->y - grabcy);
+ if (nw > 1 && nh > 1) {
+ setfloating(grabc, 1);
+ resize(grabc, (struct wlr_box){.x = MIN(ROUND(cursor->x), grabcx),
+ .y = MIN(ROUND(cursor->y), grabcy),
+ .width = nw, .height = nh}, 1);
+ }
+ }
+ /* fallthrough */
+ default:
+ /* TODO should reset to the pointer focus's current setcursor */
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
+ /* Drop the window off on its new monitor */
+ if (grabc && cursor_mode != CurBind) {
+ selmon = xytomon(cursor->x, cursor->y);
+ setmon(grabc, selmon, 0);
+ grabc = NULL;
+ }
cursor_mode = CurNormal;
+ return;
}
break;
}
@@ -1815,15 +1846,33 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y));
/* If we are currently grabbing the mouse, handle and return */
- if (cursor_mode == CurMove) {
+ switch (cursor_mode) {
+ case CurSelect:
+ return;
+ case 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;
- } 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;
+ case CurResize:
+ {
+ int w, h, x, y;
+ if (!grabc)
+ return;
+ w = abs(grabcx - (int)round(cursor->x));
+ h = abs(grabcy - (int)round(cursor->y));
+ x = MIN(grabcx, (int)round(cursor->x)) - grabc->geom.x;
+ y = MIN(grabcy, (int)round(cursor->y)) - grabc->geom.y;
+ wlr_scene_rect_set_size(grabc->border[0], w, grabc->bw);
+ wlr_scene_rect_set_size(grabc->border[1], w, grabc->bw);
+ wlr_scene_rect_set_size(grabc->border[2], grabc->bw, h - 2 * grabc->bw);
+ wlr_scene_rect_set_size(grabc->border[3], grabc->bw, h - 2 * grabc->bw);
+ wlr_scene_node_set_position(&grabc->border[0]->node, x, y);
+ wlr_scene_node_set_position(&grabc->border[1]->node, x, y + h - grabc->bw);
+ wlr_scene_node_set_position(&grabc->border[2]->node, x, y + grabc->bw);
+ wlr_scene_node_set_position(&grabc->border[3]->node, x + w - grabc->bw, y + grabc->bw);
+ return;
+ }
}
/* If there's no client surface under the cursor, set the cursor image to a
@@ -1853,29 +1902,43 @@ motionrelative(struct wl_listener *listener, void *data)
void
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)
+ /* Consider global select bool instead of this + CurSelect enum */
+ bool selected = (cursor_mode == CurSelect);
+ if (!selected) {
+ 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) {
+ grabc = NULL;
+ cursor_mode = CurNormal;
return;
+ }
- /* Float the window and tell motionnotify to grab it */
- setfloating(grabc, 1);
+ /* TODO: factor out selected bool */
switch (cursor_mode = arg->ui) {
+ case CurResize:
+ if (!selected) break;
+ grabcx = ROUND(cursor->x);
+ grabcy = ROUND(cursor->y);
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "tcross");
+ return;
case CurMove:
grabcx = (int)round(cursor->x) - grabc->geom.x;
grabcy = (int)round(cursor->y) - grabc->geom.y;
+ setfloating(grabc, 1);
wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur");
- 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;
+ return;
+ default:
+ grabc = NULL;
+ cursor_mode = CurNormal;
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
+ return;
}
+
+ cursor_mode = CurSelect;
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "crosshair");
}
void
@@ -2149,6 +2212,7 @@ resize(Client *c, struct wlr_box geo, int interact)
wlr_scene_rect_set_size(c->border[1], c->geom.width, c->bw);
wlr_scene_rect_set_size(c->border[2], c->bw, c->geom.height - 2 * c->bw);
wlr_scene_rect_set_size(c->border[3], c->bw, c->geom.height - 2 * c->bw);
+ wlr_scene_node_set_position(&c->border[0]->node, 0, 0);
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);
--
2.43.0
+11
View File
@@ -0,0 +1,11 @@
### Description
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)
### Authors
- [ForzCross](https://codeberg.org/ForzCross)
- [Nikita Ivanov](https://codeberg.org/nikitaivanov) ([GitHub](https://github.com/NikitaIvanovV))
- [dimkr](https://codeberg.org/dimkr) (<dima@dimakrasner.com>)
+73
View File
@@ -0,0 +1,73 @@
From cd61fac9cb6e9d0172e2f7a01e6a514d676ba5f0 Mon Sep 17 00:00:00 2001
From: Nikita Ivanov <nikita.vyach.ivanov@gmail.com>
Date: Tue, 4 Feb 2025 23:53:11 +0100
Subject: [PATCH] Always use the English keymap to get keycodes
---
dwl.c | 23 +++++++++++++++++++----
1 file changed, 19 insertions(+), 4 deletions(-)
diff --git a/dwl.c b/dwl.c
index def2562..c299365 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_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);
@@ -694,6 +699,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);
@@ -1582,16 +1590,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);
@@ -2607,6 +2618,10 @@ 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_keymap = xkb_keymap_new_from_names(en_context, &en_rules,
+ XKB_KEYMAP_COMPILE_NO_FLAGS);
+ en_state = xkb_state_new(en_keymap);
LISTEN_STATIC(&backend->events.new_input, inputdevice);
virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy);
LISTEN_STATIC(&virtual_keyboard_mgr->events.new_virtual_keyboard, virtualkeyboard);
--
2.48.1
+8
View File
@@ -0,0 +1,8 @@
### Description
Input device configuration (click method, tap-and-drag, acceleration, etc), border size and colors via environment variables.
### Download
- [2024-02-11](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/envcfg/envcfg.patch)
### Authors
- [Dima Krasner](https://codeberg.org/dimkr) (<dima@dimakrasner.com>)
+302
View File
@@ -0,0 +1,302 @@
From 3c3ea42cd50bfa5111be69b3c1f71afa0443bb53 Mon Sep 17 00:00:00 2001
From: Dima Krasner <dima@dimakrasner.com>
Date: Sat, 30 Dec 2023 10:49:48 +0200
Subject: [PATCH] allow environment variables to override config.h
---
Makefile | 1 +
config.def.h | 10 +--
dwl.c | 5 ++
env.c | 217 +++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 228 insertions(+), 5 deletions(-)
create mode 100644 env.c
diff --git a/Makefile b/Makefile
index 9308656..c66d376 100644
--- a/Makefile
+++ b/Makefile
@@ -22,6 +22,7 @@ dwl: dwl.o util.o
dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h \
pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h \
wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h
+dwl.o: env.c
util.o: util.c util.h
# wayland-scanner is a tool which generates C headers and rigging for Wayland
diff --git a/config.def.h b/config.def.h
index a784eb4..e0f10de 100644
--- a/config.def.h
+++ b/config.def.h
@@ -6,11 +6,11 @@
/* 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 float rootcolor[] = COLOR(0x222222ff);
-static const float bordercolor[] = COLOR(0x444444ff);
-static const float focuscolor[] = COLOR(0x005577ff);
-static const float urgentcolor[] = COLOR(0xff0000ff);
+static unsigned int borderpx = 1; /* border pixel of windows */
+static float rootcolor[] = COLOR(0x222222ff);
+static float bordercolor[] = COLOR(0x444444ff);
+static float focuscolor[] = COLOR(0x005577ff);
+static 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 */
diff --git a/dwl.c b/dwl.c
index d48bf40..de33dfe 100644
--- a/dwl.c
+++ b/dwl.c
@@ -429,6 +429,8 @@ static xcb_atom_t netatom[NetLast];
/* attempt to encapsulate suck into one file */
#include "client.h"
+#include "env.c"
+
/* function implementations */
void
applybounds(Client *c, struct wlr_box *bbox)
@@ -1082,6 +1084,8 @@ createpointer(struct wlr_pointer *pointer)
libinput_device_config_accel_set_profile(device, accel_profile);
libinput_device_config_accel_set_speed(device, accel_speed);
}
+
+ inputconfig(device);
}
wlr_cursor_attach_input_device(cursor, &pointer->base);
@@ -3141,6 +3145,7 @@ main(int argc, char *argv[])
/* Wayland requires XDG_RUNTIME_DIR for creating its communications socket */
if (!getenv("XDG_RUNTIME_DIR"))
die("XDG_RUNTIME_DIR must be set");
+ loadtheme();
setup();
run(startup_cmd);
cleanup();
diff --git a/env.c b/env.c
new file mode 100644
index 0000000..618f81e
--- /dev/null
+++ b/env.c
@@ -0,0 +1,217 @@
+static int
+isenabled(const char *val, int def)
+{
+ return ((def && (!val || !val[0] || (val[0] != '0'))) || (!def && (val && val[0] && (val[0] != '0'))));
+}
+
+static void
+setclickmethod(struct libinput_device *libinput_device)
+{
+ const char *val;
+ long l;
+ char *end = NULL;
+
+ val = getenv("LIBINPUT_DEFAULT_CLICK_METHOD");
+ if (!val || !val[0])
+ return;
+
+ errno = 0;
+ l = strtol(val, &end, 10);
+ if (errno || (end && *end))
+ return;
+
+ libinput_device_config_click_set_method(libinput_device,
+ (enum libinput_config_click_method)l);
+}
+
+static void
+settap(struct libinput_device *libinput_device)
+{
+ const char *val;
+
+ val = getenv("LIBINPUT_DEFAULT_TAP");
+ if (val) {
+ if (!val[0])
+ return;
+
+ libinput_device_config_tap_set_enabled(libinput_device,
+ isenabled(val, 1) ? LIBINPUT_CONFIG_TAP_ENABLED :
+ LIBINPUT_CONFIG_TAP_DISABLED);
+ } else if (tap_to_click && libinput_device_config_tap_get_finger_count(libinput_device))
+ libinput_device_config_tap_set_enabled(libinput_device,
+ LIBINPUT_CONFIG_TAP_ENABLED);
+}
+
+static void
+settapanddrag(struct libinput_device *libinput_device)
+{
+ const char *val;
+
+ val = getenv("LIBINPUT_DEFAULT_DRAG");
+ if (val && val[0])
+ libinput_device_config_tap_set_drag_enabled(libinput_device,
+ isenabled(val, 1) ? LIBINPUT_CONFIG_DRAG_ENABLED :
+ LIBINPUT_CONFIG_DRAG_DISABLED);
+}
+
+static void
+setnaturalscroll(struct libinput_device *libinput_device)
+{
+ const char *val;
+
+ val = getenv("LIBINPUT_DEFAULT_NATURAL_SCROLL");
+ if (val && val[0])
+ libinput_device_config_scroll_set_natural_scroll_enabled(
+ libinput_device, isenabled(val, 0));
+ else if (!val && libinput_device_config_scroll_has_natural_scroll(libinput_device))
+ libinput_device_config_scroll_set_natural_scroll_enabled(
+ libinput_device, natural_scrolling);
+}
+
+static void
+setaccelprofile(struct libinput_device *libinput_device)
+{
+ const char *val;
+ double profile;
+ char *end = NULL;
+
+ val = getenv("LIBINPUT_DEFAULT_ACCELERATION_PROFILE");
+ if (!val || !val[0])
+ return;
+
+ errno = 0;
+ profile = strtod(val, &end);
+ if (errno || (end && *end))
+ return;
+
+ libinput_device_config_accel_set_profile(libinput_device,
+ (enum libinput_config_accel_profile)profile);
+}
+
+static void
+setaccelspeed(struct libinput_device *libinput_device)
+{
+ const char *val;
+ double accel = 0;
+ char *end = NULL;
+
+ val = getenv("LIBINPUT_DEFAULT_ACCELERATION");
+ if (!val || !val[0])
+ return;
+
+ errno = 0;
+ accel = strtod(val, &end);
+ if (errno || (end && *end) || (accel < -1) || (accel > 1))
+ return;
+
+ libinput_device_config_accel_set_speed(libinput_device, accel);
+}
+
+static void
+setscrollmethod(struct libinput_device *libinput_device)
+{
+ const char *val;
+ long l;
+ char *end = NULL;
+
+ val = getenv("LIBINPUT_DEFAULT_SCROLL_METHOD");
+ if (!val || !val[0])
+ return;
+
+ errno = 0;
+ l = strtol(val, &end, 10);
+ if (errno || (end && *end))
+ return;
+
+ libinput_device_config_scroll_set_method(libinput_device,
+ (enum libinput_config_scroll_method)l);
+}
+
+static void
+setdwt(struct libinput_device *libinput_device)
+{
+ const char *val;
+
+ val = getenv("LIBINPUT_DEFAULT_DISABLE_WHILE_TYPING");
+ if (val && val[0])
+ libinput_device_config_dwt_set_enabled(libinput_device,
+ isenabled(val, false) ? LIBINPUT_CONFIG_DWT_ENABLED :
+ LIBINPUT_CONFIG_DWT_DISABLED);
+}
+
+static void
+setmiddleemul(struct libinput_device *libinput_device)
+{
+ const char *val;
+
+ val = getenv("LIBINPUT_DEFAULT_MIDDLE_EMULATION");
+ if (val && val[0])
+ libinput_device_config_middle_emulation_set_enabled(libinput_device,
+ isenabled(val, false) ? LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED :
+ LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED);
+}
+
+static void
+setlefthanded(struct libinput_device *libinput_device)
+{
+ const char *val;
+
+ val = getenv("LIBINPUT_DEFAULT_LEFT_HANDED");
+ if (val && val[0])
+ libinput_device_config_left_handed_set(libinput_device,
+ isenabled(val, 0));
+}
+
+static void
+inputconfig(struct libinput_device *libinput_device)
+{
+ setclickmethod(libinput_device);
+ settap(libinput_device);
+ settapanddrag(libinput_device);
+ setnaturalscroll(libinput_device);
+ setaccelprofile(libinput_device);
+ setaccelspeed(libinput_device);
+ setscrollmethod(libinput_device);
+ setdwt(libinput_device);
+ setmiddleemul(libinput_device);
+ setlefthanded(libinput_device);
+}
+
+static void
+parsecolor(const char *val, float color[4])
+{
+ uint8_t r, g, b;
+ if (sscanf(val, "#%02hhx%02hhx%02hhx", &r, &g, &b) == 3) {
+ color[0] = (float)r / 0xFF;
+ color[1] = (float)g / 0xFF;
+ color[2] = (float)b / 0xFF;
+ color[3] = 1.0;
+ }
+}
+
+static void
+loadtheme(void)
+{
+ const char *val;
+ unsigned int tmp;
+
+ val = getenv("DWL_ROOT_COLOR");
+ if (val)
+ parsecolor(val, rootcolor);
+
+ val = getenv("DWL_BORDER_COLOR");
+ if (val)
+ parsecolor(val, bordercolor);
+
+ val = getenv("DWL_FOCUS_COLOR");
+ if (val)
+ parsecolor(val, focuscolor);
+
+ val = getenv("DWL_URGENT_COLOR");
+ if (val)
+ parsecolor(val, urgentcolor);
+
+ val = getenv("DWL_BORDER");
+ if (val && sscanf(val, "%u", &tmp) == 1)
+ borderpx = tmp;
+}
--
2.43.0
+8
View File
@@ -0,0 +1,8 @@
### Description
Allow setting fake fullscreen per client
### Download
- [git branch](https://codeberg.org/notchoc/dwl/src/branch/fakefullscreenclient)
- [2024-03-29](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/fakefullscreenclient/fakefullscreenclient.patch)
### Authors
- [notchoc](https://codeberg.org/notchoc)
@@ -0,0 +1,87 @@
From 2ec6d0c668b4daee601337f8da45ccfa3a7d5fc6 Mon Sep 17 00:00:00 2001
From: choc <notchoc@proton.me>
Date: Fri, 29 Mar 2024 22:50:00 +0800
Subject: [PATCH] implement fakefullscreenclient
---
config.def.h | 1 +
dwl.c | 23 ++++++++++++++++++++++-
2 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/config.def.h b/config.def.h
index 9009517..8c220eb 100644
--- a/config.def.h
+++ b/config.def.h
@@ -137,6 +137,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|WLR_MODIFIER_SHIFT, XKB_KEY_E, togglefakefullscreen, {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 5867b0c..1e78491 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, isfullscreen, isfakefullscreen;
uint32_t resize; /* configure serial of a pending resize */
} Client;
@@ -318,6 +318,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 setfakefullscreen(Client *c, int fullscreen);
static void setgamma(struct wl_listener *listener, void *data);
static void setlayout(const Arg *arg);
static void setmfact(const Arg *arg);
@@ -332,6 +333,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 togglefakefullscreen(const Arg *arg);
static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
static void unlocksession(struct wl_listener *listener, void *data);
@@ -2181,6 +2183,17 @@ setfullscreen(Client *c, int fullscreen)
printstatus();
}
+void
+setfakefullscreen(Client *c, int fullscreen)
+{
+ c->isfakefullscreen = fullscreen;
+ if (!c->mon)
+ return;
+ if (c->isfullscreen)
+ setfullscreen(c, 0);
+ client_set_fullscreen(c, fullscreen);
+}
+
void
setgamma(struct wl_listener *listener, void *data)
{
@@ -2620,6 +2633,14 @@ togglefullscreen(const Arg *arg)
setfullscreen(sel, !sel->isfullscreen);
}
+void
+togglefakefullscreen(const Arg *arg)
+{
+ Client *sel = focustop(selmon);
+ if (sel)
+ setfakefullscreen(sel, !sel->isfakefullscreen);
+}
+
void
toggletag(const Arg *arg)
{
--
2.44.0
+8
View File
@@ -0,0 +1,8 @@
### Description
Tries a different display mode if the preferred mode doesn't work.
### Download
- [2024-02-11](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/fallback/fallback.patch)
### Authors
- [Dima Krasner](https://codeberg.org/dimkr) (<dima@dimakrasner.com>)
+44
View File
@@ -0,0 +1,44 @@
From a94c52af879027e654f67c36621a8c9b2f338f56 Mon Sep 17 00:00:00 2001
From: Dima Krasner <dima@dimakrasner.com>
Date: Sat, 2 Dec 2023 10:36:35 +0200
Subject: [PATCH] fall back to a lower output mode if needed
(swaywm/sway@4cdc4ac)
---
dwl.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/dwl.c b/dwl.c
index d48bf40..7719f7e 100644
--- a/dwl.c
+++ b/dwl.c
@@ -920,6 +920,7 @@ createmon(struct wl_listener *listener, void *data)
/* This event is raised by the backend when a new output (aka a display or
* monitor) becomes available. */
struct wlr_output *wlr_output = data;
+ struct wlr_output_mode *preferred_mode, *mode;
const MonitorRule *r;
size_t i;
struct wlr_output_state state;
@@ -956,7 +957,17 @@ createmon(struct wl_listener *listener, void *data)
* monitor supports only a specific set of modes. We just pick the
* monitor's preferred mode; a more sophisticated compositor would let
* the user configure it. */
- wlr_output_state_set_mode(&state, wlr_output_preferred_mode(wlr_output));
+ preferred_mode = wlr_output_preferred_mode(wlr_output);
+ wlr_output_state_set_mode(&state, preferred_mode);
+ if (!wlr_output_test_state(wlr_output, &state) && !wl_list_empty(&wlr_output->modes)) {
+ wl_list_for_each(mode, &wlr_output->modes, link) {
+ if (mode != preferred_mode) {
+ wlr_output_state_set_mode(&state, mode);
+ if (wlr_output_test_state(wlr_output, &state))
+ break;
+ }
+ }
+ }
/* Set up event listeners */
LISTEN(&wlr_output->events.frame, &m->frame, rendermon);
--
2.43.0
+9
View File
@@ -0,0 +1,9 @@
### Description
Focus the window to the left, right, above or below the current focused window
### Download
- [git branch](https://codeberg.org/ldev105/dwl/src/branch/focusdir)
- [2023-01-22](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/focusdir/focusdir.patch)
### Authors
- [ldev105](https://codeberg.org/ldev105)
+98
View File
@@ -0,0 +1,98 @@
From a0e71a687b7fcaebdaf1da80c09bf5563bff46b1 Mon Sep 17 00:00:00 2001
From: ldev <ldev@ldev.eu.org>
Date: Mon, 12 Feb 2024 21:50:24 +0100
Subject: [PATCH] focusdir
---
config.def.h | 4 ++++
dwl.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 49 insertions(+)
diff --git a/config.def.h b/config.def.h
index 9009517..2a1a82e 100644
--- a/config.def.h
+++ b/config.def.h
@@ -124,6 +124,10 @@ static const Key keys[] = {
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
{ MODKEY, XKB_KEY_j, focusstack, {.i = +1} },
{ MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_h, focusdir, {.ui = 0} },
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_l, focusdir, {.ui = 1} },
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_k, focusdir, {.ui = 2} },
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_j, focusdir, {.ui = 3} },
{ MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
{ MODKEY, XKB_KEY_d, incnmaster, {.i = -1} },
{ MODKEY, XKB_KEY_h, setmfact, {.f = -0.05f} },
diff --git a/dwl.c b/dwl.c
index bf02a6d..64d5de7 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>
@@ -268,6 +269,7 @@ static Monitor *dirtomon(enum wlr_direction dir);
static void focusclient(Client *c, int lift);
static void focusmon(const Arg *arg);
static void focusstack(const Arg *arg);
+static void focusdir(const Arg *arg);
static Client *focustop(Monitor *m);
static void fullscreennotify(struct wl_listener *listener, void *data);
static void handlesig(int signo);
@@ -1271,6 +1273,49 @@ focusstack(const Arg *arg)
focusclient(c, 1);
}
+void focusdir(const Arg *arg)
+{
+ /* Focus the left, right, up, down client relative to the current focused client on selmon */
+ Client *c, *sel = focustop(selmon);
+ if (!sel || sel->isfullscreen)
+ return;
+
+ int dist=INT_MAX;
+ Client *newsel = NULL;
+ int newdist=INT_MAX;
+ wl_list_for_each(c, &clients, link) {
+ if (!VISIBLEON(c, selmon))
+ continue; /* skip non visible windows */
+
+ if (arg->ui == 0 && sel->geom.x <= c->geom.x) {
+ /* Client isn't on our left */
+ continue;
+ }
+ if (arg->ui == 1 && sel->geom.x >= c->geom.x) {
+ /* Client isn't on our right */
+ continue;
+ }
+ if (arg->ui == 2 && sel->geom.y <= c->geom.y) {
+ /* Client isn't above us */
+ continue;
+ }
+ if (arg->ui == 3 && sel->geom.y >= c->geom.y) {
+ /* Client isn't below us */
+ continue;
+ }
+
+ dist=abs(sel->geom.x-c->geom.x)+abs(sel->geom.y-c->geom.y);
+ if (dist < newdist){
+ newdist = dist;
+ newsel=c;
+ }
+ }
+ if (newsel != NULL){
+ focusclient(newsel, 1);
+ }
+}
+
+
/* We probably should change the name of this, it sounds like
* will focus the topmost client of this mon, when actually will
* only return that client */
--
2.43.0
+10
View File
@@ -0,0 +1,10 @@
### Description
An extremely simple patch that adds the option to change DWL's window sending behavior; when active, sent windows will be followed, i.e. when a window is sent to another tag, the view changes to that tag.<br>No dependencies.
![](follow.webp)
### Download
- [v0.7](/dwl/dwl-patches/raw/branch/main/patches/follow/follow.patch)<br>Targets tag v0.7, but also works on git master and v0.6.
### Author
- [moonsabre](https://codeberg.org/moonsabre)
+38
View File
@@ -0,0 +1,38 @@
From c4de366aa5e2a465f5e2963f4ffed7adde77929a Mon Sep 17 00:00:00 2001
From: moonsabre <moonsabre@tuta.io>
Date: Thu, 13 Mar 2025 14:36:49 -0700
Subject: [PATCH] Add parameter for following sent windows.
---
config.def.h | 1 +
dwl.c | 2 ++
2 files changed, 3 insertions(+)
diff --git a/config.def.h b/config.def.h
index 22d2171..cdbdc72 100644
--- a/config.def.h
+++ b/config.def.h
@@ -6,6 +6,7 @@
/* 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 int follow = 1; /* 1 means follow windows when sent to another tag */
static const unsigned int borderpx = 1; /* border pixel of windows */
static const float rootcolor[] = COLOR(0x222222ff);
static const float bordercolor[] = COLOR(0x444444ff);
diff --git a/dwl.c b/dwl.c
index a2711f6..d2cf8ba 100644
--- a/dwl.c
+++ b/dwl.c
@@ -2677,6 +2677,8 @@ tag(const Arg *arg)
sel->tags = arg->ui & TAGMASK;
focusclient(focustop(selmon), 1);
arrange(selmon);
+ if (follow == 1)
+ view(arg);
printstatus();
}
--
2.48.1
Binary file not shown.

After

Width:  |  Height:  |  Size: 607 KiB

@@ -0,0 +1,9 @@
### Description
Implement `foreign-toplevel-management`, it add handlers for activate, close, fullscreen and destroy request events, it's missing minimize and maximize request handlers.
### Download
- [git branch](https://codeberg.org/wochap/dwl/src/branch/v0.6-a/foreign-toplevel-management)
- [2024-05-02](https://codeberg.org/dwl/dwl-patches/raw/commit/e58c3ec41a39df934d2998161d7187ac965ea77a/foreign-toplevel-management/foreign-toplevel-management.patch)
### Authors
- [wochap](https://codeberg.org/wochap)
@@ -0,0 +1,507 @@
From dc63d64cd69f515013464b3feb8acb411f5a348f Mon Sep 17 00:00:00 2001
From: wochap <gean.marroquin@gmail.com>
Date: Thu, 2 May 2024 17:25:45 -0500
Subject: [PATCH] implement foreign toplevel management
---
Makefile | 5 +-
dwl.c | 93 +++++-
...oreign-toplevel-management-unstable-v1.xml | 270 ++++++++++++++++++
3 files changed, 366 insertions(+), 2 deletions(-)
create mode 100644 protocols/wlr-foreign-toplevel-management-unstable-v1.xml
diff --git a/Makefile b/Makefile
index a67fdd3..e0e1260 100644
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@ LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(LIBS)
all: dwl
dwl: dwl.o util.o
$(CC) dwl.o util.o $(LDLIBS) $(LDFLAGS) $(DWLCFLAGS) -o $@
-dwl.o: dwl.c config.mk config.h client.h cursor-shape-v1-protocol.h pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h xdg-shell-protocol.h
+dwl.o: dwl.c config.mk config.h client.h cursor-shape-v1-protocol.h pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h xdg-shell-protocol.h wlr-foreign-toplevel-management-unstable-v1-protocol.h
util.o: util.c util.h
# wayland-scanner is a tool which generates C headers and rigging for Wayland
@@ -37,6 +37,9 @@ wlr-layer-shell-unstable-v1-protocol.h:
xdg-shell-protocol.h:
$(WAYLAND_SCANNER) server-header \
$(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@
+wlr-foreign-toplevel-management-unstable-v1-protocol.h:
+ $(WAYLAND_SCANNER) server-header \
+ protocols/wlr-foreign-toplevel-management-unstable-v1.xml $@
config.h:
cp config.def.h $@
diff --git a/dwl.c b/dwl.c
index bf763df..648616d 100644
--- a/dwl.c
+++ b/dwl.c
@@ -22,6 +22,7 @@
#include <wlr/types/wlr_data_device.h>
#include <wlr/types/wlr_drm.h>
#include <wlr/types/wlr_export_dmabuf_v1.h>
+#include <wlr/types/wlr_foreign_toplevel_management_v1.h>
#include <wlr/types/wlr_fractional_scale_v1.h>
#include <wlr/types/wlr_gamma_control_v1.h>
#include <wlr/types/wlr_idle_inhibit_v1.h>
@@ -126,6 +127,11 @@ typedef struct {
struct wl_listener fullscreen;
struct wl_listener set_decoration_mode;
struct wl_listener destroy_decoration;
+ struct wlr_foreign_toplevel_handle_v1 *foreign_toplevel;
+ struct wl_listener factivate;
+ struct wl_listener fclose;
+ struct wl_listener ffullscreen;
+ struct wl_listener fdestroy;
struct wlr_box prev; /* layout-relative, includes border */
struct wlr_box bounds;
#ifdef XWAYLAND
@@ -347,6 +353,11 @@ 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 createforeigntoplevel(Client *c);
+static void factivatenotify(struct wl_listener *listener, void *data);
+static void fclosenotify(struct wl_listener *listener, void *data);
+static void fdestroynotify(struct wl_listener *listener, void *data);
+static void ffullscreennotify(struct wl_listener *listener, void *data);
/* variables */
static const char broken[] = "broken";
@@ -392,6 +403,8 @@ static struct wlr_scene_rect *locked_bg;
static struct wlr_session_lock_v1 *cur_lock;
static struct wl_listener lock_listener = {.notify = locksession};
+static struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_mgr;
+
static struct wlr_seat *seat;
static KeyboardGroup kb_group = {0};
static KeyboardGroup vkb_group = {0};
@@ -458,6 +471,11 @@ applyrules(Client *c)
if (!(title = client_get_title(c)))
title = broken;
+ if (c->foreign_toplevel) {
+ wlr_foreign_toplevel_handle_v1_set_app_id(c->foreign_toplevel, appid);
+ wlr_foreign_toplevel_handle_v1_set_title(c->foreign_toplevel, title);
+ }
+
for (r = rules; r < END(rules); r++) {
if ((!r->title || strstr(title, r->title))
&& (!r->id || strstr(appid, r->id))) {
@@ -1288,6 +1306,8 @@ focusclient(Client *c, int lift)
client_set_border_color(old_c, bordercolor);
client_activate_surface(old, 0);
+ if (old_c->foreign_toplevel)
+ wlr_foreign_toplevel_handle_v1_set_activated(old_c->foreign_toplevel, 0);
}
}
printstatus();
@@ -1306,6 +1326,8 @@ focusclient(Client *c, int lift)
/* Activate the new client */
client_activate_surface(client_surface(c), 1);
+ if (c->foreign_toplevel)
+ wlr_foreign_toplevel_handle_v1_set_activated(c->foreign_toplevel, 1);
}
void
@@ -1599,6 +1621,8 @@ mapnotify(struct wl_listener *listener, void *data)
c->border[i]->node.data = c;
}
+ createforeigntoplevel(c);
+
/* 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;
@@ -2232,12 +2256,17 @@ setmon(Client *c, Monitor *m, uint32_t newtags)
c->prev = c->geom;
/* Scene graph sends surface leave/enter events on move and resize */
- if (oldmon)
+ if (oldmon) {
+ if (c->foreign_toplevel)
+ wlr_foreign_toplevel_handle_v1_output_leave(c->foreign_toplevel, oldmon->wlr_output);
arrange(oldmon);
+ }
if (m) {
/* 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 */
+ if (c->foreign_toplevel)
+ wlr_foreign_toplevel_handle_v1_output_enter(c->foreign_toplevel, m->wlr_output);
setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */
setfloating(c, c->isfloating);
}
@@ -2351,6 +2380,9 @@ setup(void)
gamma_control_mgr = wlr_gamma_control_manager_v1_create(dpy);
LISTEN_STATIC(&gamma_control_mgr->events.set_gamma, setgamma);
+ /* Initializes foreign toplevel management */
+ foreign_toplevel_mgr = wlr_foreign_toplevel_manager_v1_create(dpy);
+
/* Creates an output layout, which a wlroots utility for working with an
* arrangement of screens in a physical layout. */
output_layout = wlr_output_layout_create();
@@ -2691,6 +2723,11 @@ unmapnotify(struct wl_listener *listener, void *data)
wl_list_remove(&c->flink);
}
+ if (c->foreign_toplevel) {
+ wlr_foreign_toplevel_handle_v1_destroy(c->foreign_toplevel);
+ c->foreign_toplevel = NULL;
+ }
+
wlr_scene_node_destroy(&c->scene->node);
printstatus();
motionnotify(0, NULL, 0, 0, 0, 0);
@@ -2802,6 +2839,12 @@ void
updatetitle(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, set_title);
+ if (c->foreign_toplevel) {
+ const char *title;
+ if (!(title = client_get_title(c)))
+ title = broken;
+ wlr_foreign_toplevel_handle_v1_set_title(c->foreign_toplevel, title);
+ }
if (c == focustop(c->mon))
printstatus();
}
@@ -2929,6 +2972,54 @@ zoom(const Arg *arg)
arrange(selmon);
}
+void
+createforeigntoplevel(Client *c)
+{
+ c->foreign_toplevel = wlr_foreign_toplevel_handle_v1_create(foreign_toplevel_mgr);
+
+ LISTEN(&c->foreign_toplevel->events.request_activate, &c->factivate, factivatenotify);
+ LISTEN(&c->foreign_toplevel->events.request_close, &c->fclose, fclosenotify);
+ LISTEN(&c->foreign_toplevel->events.request_fullscreen, &c->ffullscreen, ffullscreennotify);
+ LISTEN(&c->foreign_toplevel->events.destroy, &c->fdestroy, fdestroynotify);
+}
+
+void
+factivatenotify(struct wl_listener *listener, void *data)
+{
+ Client *c = wl_container_of(listener, c, factivate);
+ if (c->mon == selmon) {
+ c->tags = c->mon->tagset[c->mon->seltags];
+ } else {
+ setmon(c, selmon, 0);
+ }
+ focusclient(c, 1);
+ arrange(c->mon);
+}
+
+void
+fclosenotify(struct wl_listener *listener, void *data)
+{
+ Client *c = wl_container_of(listener, c, fclose);
+ client_send_close(c);
+}
+
+void
+ffullscreennotify(struct wl_listener *listener, void *data) {
+ Client *c = wl_container_of(listener, c, ffullscreen);
+ struct wlr_foreign_toplevel_handle_v1_fullscreen_event *event = data;
+ setfullscreen(c, event->fullscreen);
+}
+
+void
+fdestroynotify(struct wl_listener *listener, void *data)
+{
+ Client *c = wl_container_of(listener, c, fdestroy);
+ wl_list_remove(&c->factivate.link);
+ wl_list_remove(&c->fclose.link);
+ wl_list_remove(&c->ffullscreen.link);
+ wl_list_remove(&c->fdestroy.link);
+}
+
#ifdef XWAYLAND
void
activatex11(struct wl_listener *listener, void *data)
diff --git a/protocols/wlr-foreign-toplevel-management-unstable-v1.xml b/protocols/wlr-foreign-toplevel-management-unstable-v1.xml
new file mode 100644
index 0000000..44505bb
--- /dev/null
+++ b/protocols/wlr-foreign-toplevel-management-unstable-v1.xml
@@ -0,0 +1,270 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="wlr_foreign_toplevel_management_unstable_v1">
+ <copyright>
+ Copyright © 2018 Ilia Bozhinov
+
+ Permission to use, copy, modify, distribute, and sell this
+ software and its documentation for any purpose is hereby granted
+ without fee, provided that the above copyright notice appear in
+ all copies and that both that copyright notice and this permission
+ notice appear in supporting documentation, and that the name of
+ the copyright holders not be used in advertising or publicity
+ pertaining to distribution of the software without specific,
+ written prior permission. The copyright holders make no
+ representations about the suitability of this software for any
+ purpose. It is provided "as is" without express or implied
+ warranty.
+
+ THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ THIS SOFTWARE.
+ </copyright>
+
+ <interface name="zwlr_foreign_toplevel_manager_v1" version="3">
+ <description summary="list and control opened apps">
+ The purpose of this protocol is to enable the creation of taskbars
+ and docks by providing them with a list of opened applications and
+ letting them request certain actions on them, like maximizing, etc.
+
+ After a client binds the zwlr_foreign_toplevel_manager_v1, each opened
+ toplevel window will be sent via the toplevel event
+ </description>
+
+ <event name="toplevel">
+ <description summary="a toplevel has been created">
+ This event is emitted whenever a new toplevel window is created. It
+ is emitted for all toplevels, regardless of the app that has created
+ them.
+
+ All initial details of the toplevel(title, app_id, states, etc.) will
+ be sent immediately after this event via the corresponding events in
+ zwlr_foreign_toplevel_handle_v1.
+ </description>
+ <arg name="toplevel" type="new_id" interface="zwlr_foreign_toplevel_handle_v1"/>
+ </event>
+
+ <request name="stop">
+ <description summary="stop sending events">
+ Indicates the client no longer wishes to receive events for new toplevels.
+ However the compositor may emit further toplevel_created events, until
+ the finished event is emitted.
+
+ The client must not send any more requests after this one.
+ </description>
+ </request>
+
+ <event name="finished" type="destructor">
+ <description summary="the compositor has finished with the toplevel manager">
+ This event indicates that the compositor is done sending events to the
+ zwlr_foreign_toplevel_manager_v1. The server will destroy the object
+ immediately after sending this request, so it will become invalid and
+ the client should free any resources associated with it.
+ </description>
+ </event>
+ </interface>
+
+ <interface name="zwlr_foreign_toplevel_handle_v1" version="3">
+ <description summary="an opened toplevel">
+ A zwlr_foreign_toplevel_handle_v1 object represents an opened toplevel
+ window. Each app may have multiple opened toplevels.
+
+ Each toplevel has a list of outputs it is visible on, conveyed to the
+ client with the output_enter and output_leave events.
+ </description>
+
+ <event name="title">
+ <description summary="title change">
+ This event is emitted whenever the title of the toplevel changes.
+ </description>
+ <arg name="title" type="string"/>
+ </event>
+
+ <event name="app_id">
+ <description summary="app-id change">
+ This event is emitted whenever the app-id of the toplevel changes.
+ </description>
+ <arg name="app_id" type="string"/>
+ </event>
+
+ <event name="output_enter">
+ <description summary="toplevel entered an output">
+ This event is emitted whenever the toplevel becomes visible on
+ the given output. A toplevel may be visible on multiple outputs.
+ </description>
+ <arg name="output" type="object" interface="wl_output"/>
+ </event>
+
+ <event name="output_leave">
+ <description summary="toplevel left an output">
+ This event is emitted whenever the toplevel stops being visible on
+ the given output. It is guaranteed that an entered-output event
+ with the same output has been emitted before this event.
+ </description>
+ <arg name="output" type="object" interface="wl_output"/>
+ </event>
+
+ <request name="set_maximized">
+ <description summary="requests that the toplevel be maximized">
+ Requests that the toplevel be maximized. If the maximized state actually
+ changes, this will be indicated by the state event.
+ </description>
+ </request>
+
+ <request name="unset_maximized">
+ <description summary="requests that the toplevel be unmaximized">
+ Requests that the toplevel be unmaximized. If the maximized state actually
+ changes, this will be indicated by the state event.
+ </description>
+ </request>
+
+ <request name="set_minimized">
+ <description summary="requests that the toplevel be minimized">
+ Requests that the toplevel be minimized. If the minimized state actually
+ changes, this will be indicated by the state event.
+ </description>
+ </request>
+
+ <request name="unset_minimized">
+ <description summary="requests that the toplevel be unminimized">
+ Requests that the toplevel be unminimized. If the minimized state actually
+ changes, this will be indicated by the state event.
+ </description>
+ </request>
+
+ <request name="activate">
+ <description summary="activate the toplevel">
+ Request that this toplevel be activated on the given seat.
+ There is no guarantee the toplevel will be actually activated.
+ </description>
+ <arg name="seat" type="object" interface="wl_seat"/>
+ </request>
+
+ <enum name="state">
+ <description summary="types of states on the toplevel">
+ The different states that a toplevel can have. These have the same meaning
+ as the states with the same names defined in xdg-toplevel
+ </description>
+
+ <entry name="maximized" value="0" summary="the toplevel is maximized"/>
+ <entry name="minimized" value="1" summary="the toplevel is minimized"/>
+ <entry name="activated" value="2" summary="the toplevel is active"/>
+ <entry name="fullscreen" value="3" summary="the toplevel is fullscreen" since="2"/>
+ </enum>
+
+ <event name="state">
+ <description summary="the toplevel state changed">
+ This event is emitted immediately after the zlw_foreign_toplevel_handle_v1
+ is created and each time the toplevel state changes, either because of a
+ compositor action or because of a request in this protocol.
+ </description>
+
+ <arg name="state" type="array"/>
+ </event>
+
+ <event name="done">
+ <description summary="all information about the toplevel has been sent">
+ This event is sent after all changes in the toplevel state have been
+ sent.
+
+ This allows changes to the zwlr_foreign_toplevel_handle_v1 properties
+ to be seen as atomic, even if they happen via multiple events.
+ </description>
+ </event>
+
+ <request name="close">
+ <description summary="request that the toplevel be closed">
+ Send a request to the toplevel to close itself. The compositor would
+ typically use a shell-specific method to carry out this request, for
+ example by sending the xdg_toplevel.close event. However, this gives
+ no guarantees the toplevel will actually be destroyed. If and when
+ this happens, the zwlr_foreign_toplevel_handle_v1.closed event will
+ be emitted.
+ </description>
+ </request>
+
+ <request name="set_rectangle">
+ <description summary="the rectangle which represents the toplevel">
+ The rectangle of the surface specified in this request corresponds to
+ the place where the app using this protocol represents the given toplevel.
+ It can be used by the compositor as a hint for some operations, e.g
+ minimizing. The client is however not required to set this, in which
+ case the compositor is free to decide some default value.
+
+ If the client specifies more than one rectangle, only the last one is
+ considered.
+
+ The dimensions are given in surface-local coordinates.
+ Setting width=height=0 removes the already-set rectangle.
+ </description>
+
+ <arg name="surface" type="object" interface="wl_surface"/>
+ <arg name="x" type="int"/>
+ <arg name="y" type="int"/>
+ <arg name="width" type="int"/>
+ <arg name="height" type="int"/>
+ </request>
+
+ <enum name="error">
+ <entry name="invalid_rectangle" value="0"
+ summary="the provided rectangle is invalid"/>
+ </enum>
+
+ <event name="closed">
+ <description summary="this toplevel has been destroyed">
+ This event means the toplevel has been destroyed. It is guaranteed there
+ won't be any more events for this zwlr_foreign_toplevel_handle_v1. The
+ toplevel itself becomes inert so any requests will be ignored except the
+ destroy request.
+ </description>
+ </event>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the zwlr_foreign_toplevel_handle_v1 object">
+ Destroys the zwlr_foreign_toplevel_handle_v1 object.
+
+ This request should be called either when the client does not want to
+ use the toplevel anymore or after the closed event to finalize the
+ destruction of the object.
+ </description>
+ </request>
+
+ <!-- Version 2 additions -->
+
+ <request name="set_fullscreen" since="2">
+ <description summary="request that the toplevel be fullscreened">
+ Requests that the toplevel be fullscreened on the given output. If the
+ fullscreen state and/or the outputs the toplevel is visible on actually
+ change, this will be indicated by the state and output_enter/leave
+ events.
+
+ The output parameter is only a hint to the compositor. Also, if output
+ is NULL, the compositor should decide which output the toplevel will be
+ fullscreened on, if at all.
+ </description>
+ <arg name="output" type="object" interface="wl_output" allow-null="true"/>
+ </request>
+
+ <request name="unset_fullscreen" since="2">
+ <description summary="request that the toplevel be unfullscreened">
+ Requests that the toplevel be unfullscreened. If the fullscreen state
+ actually changes, this will be indicated by the state event.
+ </description>
+ </request>
+
+ <!-- Version 3 additions -->
+
+ <event name="parent" since="3">
+ <description summary="parent change">
+ This event is emitted whenever the parent of the toplevel changes.
+
+ No event is emitted when the parent handle is destroyed by the client.
+ </description>
+ <arg name="parent" type="object" interface="zwlr_foreign_toplevel_handle_v1" allow-null="true"/>
+ </event>
+ </interface>
+</protocol>
--
2.43.2
+29
View File
@@ -0,0 +1,29 @@
### Description
# fullscreenadaptivesync — Enables adaptive sync/VRR when a client is fullscreen.
Adds a function that automatically enables adaptive sync/VRR when a fullscreen client is detected, and disables it once the client exits fullscreen.
---
1. **Why**
- Some VRR implementations can introduce distracting flickering when the displays refresh rate is synced with the applications framerate. While VRR is useful for some applications (especially fullscreen games), this patch automates the toggling of VRR whenever a client enters or exits fullscreen.
2. **Requirements**
- A FreeSync/G-Sync capable monitor
- GPU/driver support for adaptive sync
3. **How it works**
- When a client enters fullscreen, adaptive sync is automatically enabled.
- When the client exits fullscreen, adaptive sync is disabled again.
4. **togglefullscreenadaptivesync**
- Adds a switch to enable or disable the fullscreenadaptivesync behavior.
- 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)
### Authors
- [julmajustus](https://codeberg.org/julmajustus)
@@ -0,0 +1,122 @@
From c003f450c197a0c960bbb355511f8dca7a35e3c3 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
---
config.def.h | 1 +
dwl.c | 40 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 41 insertions(+)
diff --git a/config.def.h b/config.def.h
index 22d2171..886f1ab 100644
--- a/config.def.h
+++ b/config.def.h
@@ -142,6 +142,7 @@ static const Key keys[] = {
{ MODKEY, XKB_KEY_space, setlayout, {0} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
{ MODKEY, XKB_KEY_e, togglefullscreen, {0} },
+ { MODKEY, XKB_KEY_F5, togglefullscreenadaptivesync, {0} },
{ MODKEY, XKB_KEY_0, view, {.ui = ~0} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} },
{ MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} },
diff --git a/dwl.c b/dwl.c
index a2711f6..7be05ef 100644
--- a/dwl.c
+++ b/dwl.c
@@ -322,6 +322,7 @@ static void requeststartdrag(struct wl_listener *listener, void *data);
static void requestmonstate(struct wl_listener *listener, void *data);
static void resize(Client *c, struct wlr_box geo, int interact);
static void run(char *startup_cmd);
+static void set_adaptive_sync(Monitor *m, int enabled);
static void setcursor(struct wl_listener *listener, void *data);
static void setcursorshape(struct wl_listener *listener, void *data);
static void setfloating(Client *c, int floating);
@@ -340,6 +341,7 @@ static void tagmon(const Arg *arg);
static void tile(Monitor *m);
static void togglefloating(const Arg *arg);
static void togglefullscreen(const Arg *arg);
+static void togglefullscreenadaptivesync(const Arg *arg);
static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
static void unlocksession(struct wl_listener *listener, void *data);
@@ -413,6 +415,8 @@ static struct wlr_box sgeom;
static struct wl_list mons;
static Monitor *selmon;
+static int fullscreen_adaptive_sync_enabled = 1;
+
#ifdef XWAYLAND
static void activatex11(struct wl_listener *listener, void *data);
static void associatex11(struct wl_listener *listener, void *data);
@@ -2269,6 +2273,31 @@ run(char *startup_cmd)
wl_display_run(dpy);
}
+void
+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;
+
+ 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);
+
+ /* Broadcast the adaptive sync state change to output_mgr */
+ config_head->state.adaptive_sync_enabled = enable;
+ wlr_output_manager_v1_set_configuration(output_mgr, config);
+}
+
void
setcursor(struct wl_listener *listener, void *data)
{
@@ -2332,10 +2361,12 @@ setfullscreen(Client *c, int fullscreen)
if (fullscreen) {
c->prev = c->geom;
resize(c, c->mon->m, 0);
+ set_adaptive_sync(c->mon, 1);
} else {
/* restore previous size instead of arrange for floating windows since
* client positions are set by the user and cannot be recalculated */
resize(c, c->prev, 0);
+ set_adaptive_sync(c->mon, 0);
}
arrange(c->mon);
printstatus();
@@ -2739,6 +2770,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)
{
@@ -2809,6 +2846,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);
wlr_scene_node_destroy(&c->scene->node);
printstatus();
--
2.45.2
+19
View File
@@ -0,0 +1,19 @@
### Description
Arranges windows in a grid. Except it adjusts the number of windows in the first few columns to avoid empty cells.
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)
- [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)
## 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
- [Sneethe](https://github.com/Sneethe/)
- [Vladislav Nepogodin](https://github.com/vnepogodin)
- [Dhruva Sambrani](https://codeberg.org/dhruva_sambrani/) (Revived to codeberg)
@@ -0,0 +1,97 @@
From 958cf2c2415927e2f7b471da9ada7c6e7d169a63 Mon Sep 17 00:00:00 2001
From: Dhruva Sambrani <44899822+DhruvaSambrani@users.noreply.github.com>
Date: Mon, 8 Jan 2024 16:11:30 +0100
Subject: [PATCH] revive gaplessgrid
---
config.def.h | 2 ++
dwl.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 48 insertions(+)
diff --git a/config.def.h b/config.def.h
index a8ed61d..7400b7f 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 */
@@ -134,6 +135,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 632dabf..4d810f7 100644
--- a/dwl.c
+++ b/dwl.c
@@ -268,6 +268,7 @@ static void focusclient(Client *c, int lift);
static void focusmon(const Arg *arg);
static void focusstack(const Arg *arg);
static Client *focustop(Monitor *m);
+static void gaplessgrid(Monitor *m);
static void fullscreennotify(struct wl_listener *listener, void *data);
static void handlesig(int signo);
static void incnmaster(const Arg *arg);
@@ -1311,6 +1312,51 @@ 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;
+ 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.43.0
@@ -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 145fd01..dae1d1a 100644
--- a/dwl.c
+++ b/dwl.c
@@ -287,6 +287,7 @@ static void focusmon(const Arg *arg);
static void focusstack(const Arg *arg);
static Client *focustop(Monitor *m);
static void fullscreennotify(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);
@@ -1467,6 +1468,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)
{

Some files were not shown because too many files have changed in this diff Show More