This commit is contained in:
2026-07-12 08:16:17 +03:30
commit 72be1234e1
2027 changed files with 221388 additions and 0 deletions
+46
View File
@@ -0,0 +1,46 @@
### Description
This patch adds an ability to add or change client rules at runtime.
Sometimes it happens that some client rule I've set is not relevant in the
current circumstance and adds major disturbance and annoyance to my work
(e.g., `isfloating` is set or unset and I want the opposite). Changing the rule
is not an option because it will require recompilation and restarting dwl, which
is even worse. Having an option of always being able to change a rule solves
this issue.
The patch only adds one keybinding (`Alt+Shift+R`) to toggle `isfloating`
option. Upon pressing it, dwl will try to find a matching rule for the focused
client and change its `isfloating` setting. If there's no such a rule, a new
rule will be added. The new rule will inherit an appid of the focused client.
It's very easy to add support for more rule options from other patches as well.
You just need to define a new function similar to `setruleisfloating` and add a
new keybinding to `config.h`. For example, this is a function I created for my
build to toggle `noswallow` option from the [swallow][swallow] patch:
```c
void
setrulenoswallow(const Arg *arg)
{
Rule *r = getrule(focustop(selmon));
if (!r)
return;
r->noswallow = !r->noswallow;
}
```
You can also try [menurule][menurule] patch if you want to be able to edit rules
with dmenu.
[swallow]: /dwl/dwl-patches/src/branch/main/patches/swallow
[menurule]: /dwl/dwl-patches/src/branch/main/patches/menurule
### Download
- [v0.7](/dwl/dwl-patches/raw/branch/main/patches/setrule/setrule.patch)
- [2025-02-14 v0.7](https://codeberg.org/dwl/dwl-patches/raw/commit/268bee3cee239e5bd52cceed88a52bfc21143cc3/patches/setrule/setrule.patch)
### Authors
- [Nikita Ivanov](https://codeberg.org/nikitaivanov) ([GitHub](https://github.com/NikitaIvanovV))
+155
View File
@@ -0,0 +1,155 @@
From 3c78308f0d74ac6ef112804333f82c098e33bb40 Mon Sep 17 00:00:00 2001
From: Nikita Ivanov <nikita.vyach.ivanov@gmail.com>
Date: Fri, 21 Mar 2025 22:20:54 +0100
Subject: [PATCH] setrule: add/change rules at runtime
---
config.def.h | 4 ++++
dwl.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 70 insertions(+), 1 deletion(-)
diff --git a/config.def.h b/config.def.h
index 22d2171..5b05e52 100644
--- a/config.def.h
+++ b/config.def.h
@@ -20,6 +20,9 @@ static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You ca
/* logging */
static int log_level = WLR_ERROR;
+/* Max amount of dynamically added rules */
+#define RULES_MAX 100
+
/* 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 */
@@ -142,6 +145,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_R, setruleisfloating,{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 def2562..8beac1f 100644
--- a/dwl.c
+++ b/dwl.c
@@ -290,6 +290,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 Rule *getrule(Client *c);
static void gpureset(struct wl_listener *listener, void *data);
static void handlesig(int signo);
static void incnmaster(const Arg *arg);
@@ -331,6 +332,7 @@ static void setlayout(const Arg *arg);
static void setmfact(const Arg *arg);
static void setmon(Client *c, Monitor *m, uint32_t newtags);
static void setpsel(struct wl_listener *listener, void *data);
+static void setruleisfloating(const Arg *arg);
static void setsel(struct wl_listener *listener, void *data);
static void setup(void);
static void spawn(const Arg *arg);
@@ -413,6 +415,9 @@ static struct wlr_box sgeom;
static struct wl_list mons;
static Monitor *selmon;
+static Rule *drules;
+static size_t druleslen;
+
#ifdef XWAYLAND
static void activatex11(struct wl_listener *listener, void *data);
static void associatex11(struct wl_listener *listener, void *data);
@@ -466,7 +471,7 @@ applyrules(Client *c)
if (!(title = client_get_title(c)))
title = broken;
- for (r = rules; r < END(rules); r++) {
+ for (r = drules; r < drules + druleslen; r++) {
if ((!r->title || strstr(title, r->title))
&& (!r->id || strstr(appid, r->id))) {
c->isfloating = r->isfloating;
@@ -1472,6 +1477,53 @@ fullscreennotify(struct wl_listener *listener, void *data)
setfullscreen(c, client_wants_fullscreen(c));
}
+Rule *
+getrule(Client *c)
+{
+ Rule *r;
+ const Rule *e;
+ const char *appid, *title;
+
+ if (!c)
+ return NULL;
+
+ if (!(appid = client_get_appid(c)))
+ appid = broken;
+ if (!(title = client_get_title(c)))
+ title = broken;
+
+ for (r = drules + druleslen - 1; r >= drules; r--)
+ if ((!r->title || strstr(title, r->title))
+ && (!r->id || strstr(appid, r->id)))
+ goto found;
+
+ if (druleslen >= LENGTH(rules) + RULES_MAX)
+ return NULL; /* No free slots left */
+
+ r = drules + druleslen++;
+
+ /* Use [NULL,NULL] as the default rule if exists */
+ for (e = rules; e < END(rules); e++)
+ if (!e->title && !e->id) {
+ *r = *e;
+ break;
+ }
+
+ /* No default rule found, set reasoble defaults */
+ if (e >= END(rules)) {
+ r->monitor = -1;
+ }
+
+ /* Only set title if appid is unset */
+ if (appid == broken)
+ r->title = strdup(title);
+ else
+ r->id = strdup(appid);
+
+found:
+ return r;
+}
+
void
gpureset(struct wl_listener *listener, void *data)
{
@@ -2417,6 +2469,15 @@ setpsel(struct wl_listener *listener, void *data)
wlr_seat_set_primary_selection(seat, event->source, event->serial);
}
+void
+setruleisfloating(const Arg *arg)
+{
+ Rule *r = getrule(focustop(selmon));
+ if (!r)
+ return;
+ r->isfloating = !r->isfloating;
+}
+
void
setsel(struct wl_listener *listener, void *data)
{
@@ -2645,6 +2706,10 @@ setup(void)
fprintf(stderr, "failed to setup XWayland X server, continuing without it\n");
}
#endif
+
+ drules = ecalloc(LENGTH(rules) + RULES_MAX, sizeof(Rule));
+ memcpy(drules, rules, sizeof(rules));
+ druleslen = LENGTH(rules);
}
void
--
2.49.0