From ae0fe9e21266269c15c2fd5ddd552b73afb684f9 Mon Sep 17 00:00:00 2001 From: iglt Date: Sun, 25 Oct 2026 12:32:30 +0100 Subject: [PATCH] swapfocus: minor update --- patches/swapfocus/README.md | 3 +- patches/swapfocus/swapfocus-0.8.patch | 154 ++++++++++++++++++++++++++ patches/swapfocus/swapfocus.patch | 31 ++---- 3 files changed, 165 insertions(+), 23 deletions(-) create mode 100644 patches/swapfocus/swapfocus-0.8.patch diff --git a/patches/swapfocus/README.md b/patches/swapfocus/README.md index 22e1939..b4e4fbb 100644 --- a/patches/swapfocus/README.md +++ b/patches/swapfocus/README.md @@ -4,7 +4,8 @@ Swapfocus adds a new function on dwl: a shortcut to change the focus to the last - Alternatively: edit the patch and uncomment and comment out the lines instructed to keep the swapfocus shortcut from changing to another tag. ### Download -- [v0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/swapfocus/swapfocus.patch) +- [2026-10-25]((https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/swapfocus/swapfocus.patch) +- [v0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/swapfocus/swapfocus-0.8..patch) ### Authors - [André Desgualdo Pereira](https://codeberg.org/Kana) diff --git a/patches/swapfocus/swapfocus-0.8.patch b/patches/swapfocus/swapfocus-0.8.patch new file mode 100644 index 0000000..10bbc2a --- /dev/null +++ b/patches/swapfocus/swapfocus-0.8.patch @@ -0,0 +1,154 @@ +From 364b9f20b830886b9c0e6539ddba2cc206a286eb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Andr=C3=A9=20Desgualdo=20Pereira?= +Date: Thu, 21 May 2026 09:50:03 -0300 +Subject: [PATCH] swapfocus patch + +--- + config.def.h | 1 + + dwl.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 91 insertions(+) + +diff --git a/config.def.h b/config.def.h +index 8a6eda0..23e502d 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -132,6 +132,7 @@ static const Key keys[] = { + { MODKEY, XKB_KEY_Return, zoom, {0} }, + { MODKEY, XKB_KEY_Tab, view, {0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_c, killclient, {0} }, ++ { MODKEY, XKB_KEY_s, swapfocus, {0} }, + { MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} }, + { MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} }, +diff --git a/dwl.c b/dwl.c +index 101a45f..c512323 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -332,6 +332,7 @@ static void setsel(struct wl_listener *listener, void *data); + static void setup(void); + static void spawn(const Arg *arg); + static void startdrag(struct wl_listener *listener, void *data); ++static void swapfocus(const Arg *arg); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); + static void tile(Monitor *m); +@@ -375,6 +376,7 @@ static struct wlr_xdg_activation_v1 *activation; + static struct wlr_xdg_decoration_manager_v1 *xdg_decoration_mgr; + static struct wl_list clients; /* tiling order */ + static struct wl_list fstack; /* focus order */ ++static Client *prevclient = NULL; + static struct wlr_idle_notifier_v1 *idle_notifier; + static struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr; + static struct wlr_layer_shell_v1 *layer_shell; +@@ -1330,6 +1332,8 @@ destroynotify(struct wl_listener *listener, void *data) + { + /* Called when the xdg_toplevel is destroyed. */ + Client *c = wl_container_of(listener, c, destroy); ++ if (c == prevclient) ++ prevclient = NULL; + wl_list_remove(&c->destroy.link); + wl_list_remove(&c->set_title.link); + wl_list_remove(&c->fullscreen.link); +@@ -1424,6 +1428,11 @@ focusclient(Client *c, int lift) + wlr_xdg_popup_destroy(popup); + } + ++ /* Capture the client losing focus as the previous client */ ++ if (old_c && !client_is_unmanaged(old_c) && old_c != c) { ++ prevclient = old_c; ++ } ++ + /* Put the new client atop the focus stack and select its monitor */ + if (c && !client_is_unmanaged(c)) { + wl_list_remove(&c->flink); +@@ -2679,6 +2688,87 @@ spawn(const Arg *arg) + } + } + ++void ++swapfocus(const Arg *arg) ++{ ++ Client *c; ++ int found = 0; ++ ++ /* Verify the client still exists in the list of managed windows */ ++ if (prevclient) { ++ wl_list_for_each(c, &clients, link) { ++ if (c == prevclient) { ++ found = 1; ++ break; ++ } ++ } ++ } ++ ++ if (found && !client_is_unmanaged(prevclient)) { ++ /* Get the bitmask of currently visible tags on the prevclient's monitor */ ++ unsigned int visible_tags = prevclient->mon->tagset[prevclient->mon->seltags]; ++ ++ /* Check if the client's tags are currently visible */ ++ if (!(prevclient->tags & visible_tags)) { ++ /* Tag is NOT visible: Switch tags and monitor only. ++ * dwl's view() calls arrange(), which automatically focuses the ++ * top-most window in the focus stack for that tag. */ ++ Arg a = {.ui = prevclient->tags}; ++ selmon = prevclient->mon; ++ view(&a); ++ ++ /* Comment out the 3 lines above and ++ * uncommment the following lines ++ * if changing tags isn't desired */ ++ ++// int current_tag_clients = 0; ++// Client *tmp; ++// wl_list_for_each(tmp, &clients, link) { ++// /* Make sure it's on the current monitor, visible on the current tag, and mapped */ ++// if (tmp->mon == selmon && (tmp->tags & selmon->tagset[selmon->seltags]) && !client_is_unmanaged(tmp)) { ++// current_tag_clients++; ++// } ++// } ++// ++// /* If there's more than 1 window here, mimic Mod+k instead of switching tags */ ++// if (current_tag_clients > 1) { ++// Arg arg_focus = {.i = -1}; ++// focusstack(&arg_focus); ++// } ++ ++ /* End of not changing tags logic */ ++ } else { ++ /* Tag IS visible: Just swap focus within the same view */ ++ focusclient(prevclient, 1); ++ } ++ } else { ++ Arg a = {.ui = 0}; ++ selmon = prevclient->mon; ++ view(&a); ++ ++ /* Comment out the 3 lines above and ++ * uncommment the following lines ++ * if changing tags isn't desired */ ++ ++ /* use the following if changing tags isn't desired */ ++// int current_tag_clients = 0; ++// Client *tmp; ++// wl_list_for_each(tmp, &clients, link) { ++// /* Make sure it's on the current monitor, visible on the current tag, and mapped */ ++// if (tmp->mon == selmon && (tmp->tags & selmon->tagset[selmon->seltags]) && !client_is_unmanaged(tmp)) { ++// current_tag_clients++; ++// } ++// } ++// ++// /* If there's more than 1 window here, mimic Mod+k instead of switching tags */ ++// if (current_tag_clients > 1) { ++// Arg arg_focus = {.i = -1}; ++// focusstack(&arg_focus); ++// } ++ /* end of not changing tags logic */ ++ } ++} ++ + void + startdrag(struct wl_listener *listener, void *data) + { +-- +2.53.0 + diff --git a/patches/swapfocus/swapfocus.patch b/patches/swapfocus/swapfocus.patch index 10bbc2a..1320b08 100644 --- a/patches/swapfocus/swapfocus.patch +++ b/patches/swapfocus/swapfocus.patch @@ -1,15 +1,5 @@ -From 364b9f20b830886b9c0e6539ddba2cc206a286eb Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Andr=C3=A9=20Desgualdo=20Pereira?= -Date: Thu, 21 May 2026 09:50:03 -0300 -Subject: [PATCH] swapfocus patch - ---- - config.def.h | 1 + - dwl.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 91 insertions(+) - diff --git a/config.def.h b/config.def.h -index 8a6eda0..23e502d 100644 +index a4019d3..02ee21c 100644 --- a/config.def.h +++ b/config.def.h @@ -132,6 +132,7 @@ static const Key keys[] = { @@ -21,18 +11,18 @@ index 8a6eda0..23e502d 100644 { MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} }, { MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} }, diff --git a/dwl.c b/dwl.c -index 101a45f..c512323 100644 +index d5f2f98..5e65cfa 100644 --- a/dwl.c +++ b/dwl.c -@@ -332,6 +332,7 @@ static void setsel(struct wl_listener *listener, void *data); - static void setup(void); +@@ -362,6 +362,7 @@ static struct wlr_scene_node *snapshot(struct wlr_scene_node *node, + struct wlr_scene_tree *parent, void *data); static void spawn(const Arg *arg); static void startdrag(struct wl_listener *listener, void *data); +static void swapfocus(const Arg *arg); static void tag(const Arg *arg); static void tagmon(const Arg *arg); static void tile(Monitor *m); -@@ -375,6 +376,7 @@ static struct wlr_xdg_activation_v1 *activation; +@@ -410,6 +411,7 @@ static struct wlr_xdg_activation_v1 *activation; static struct wlr_xdg_decoration_manager_v1 *xdg_decoration_mgr; static struct wl_list clients; /* tiling order */ static struct wl_list fstack; /* focus order */ @@ -40,7 +30,7 @@ index 101a45f..c512323 100644 static struct wlr_idle_notifier_v1 *idle_notifier; static struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr; static struct wlr_layer_shell_v1 *layer_shell; -@@ -1330,6 +1332,8 @@ destroynotify(struct wl_listener *listener, void *data) +@@ -1500,6 +1502,8 @@ destroynotify(struct wl_listener *listener, void *data) { /* Called when the xdg_toplevel is destroyed. */ Client *c = wl_container_of(listener, c, destroy); @@ -49,7 +39,7 @@ index 101a45f..c512323 100644 wl_list_remove(&c->destroy.link); wl_list_remove(&c->set_title.link); wl_list_remove(&c->fullscreen.link); -@@ -1424,6 +1428,11 @@ focusclient(Client *c, int lift) +@@ -1600,6 +1604,11 @@ focusclient(Client *c, LayerSurface *l, int lift) wlr_xdg_popup_destroy(popup); } @@ -61,7 +51,7 @@ index 101a45f..c512323 100644 /* Put the new client atop the focus stack and select its monitor */ if (c && !client_is_unmanaged(c)) { wl_list_remove(&c->flink); -@@ -2679,6 +2688,87 @@ spawn(const Arg *arg) +@@ -3015,6 +3024,87 @@ spawn(const Arg *arg) } } @@ -116,7 +106,7 @@ index 101a45f..c512323 100644 + /* End of not changing tags logic */ + } else { + /* Tag IS visible: Just swap focus within the same view */ -+ focusclient(prevclient, 1); ++ focusclient(prevclient, NULL, 1); + } + } else { + Arg a = {.ui = 0}; @@ -149,6 +139,3 @@ index 101a45f..c512323 100644 void startdrag(struct wl_listener *listener, void *data) { --- -2.53.0 -