diff --git a/patches/swapfocus/README.md b/patches/swapfocus/README.md new file mode 100644 index 0000000..3cf9e34 --- /dev/null +++ b/patches/swapfocus/README.md @@ -0,0 +1,8 @@ +### Description +Swapfocus adds a new function on dwl: a shortcut to change the focus to the last focused window. If the last focused window is in another tag, then the focus will change to that tag. + +### Download +- [v0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/swapfocus/swapfocus.patch) + +### Authors +- [André Desgualdo Pereira](https://codeberg.org/Kana) diff --git a/patches/swapfocus/swapfocus.patch b/patches/swapfocus/swapfocus.patch new file mode 100644 index 0000000..bd262e9 --- /dev/null +++ b/patches/swapfocus/swapfocus.patch @@ -0,0 +1,109 @@ +From 34c613a77683ab0e2beac36276315d037ba222a5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Andr=C3=A9=20Desgualdo=20Pereira?= +Date: Thu, 30 Apr 2026 13:36:03 -0300 +Subject: [PATCH] add swapfocus patch + +--- + config.def.h | 1 + + dwl.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 46 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..dac34a6 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,42 @@ spawn(const Arg *arg) + } + } + ++void ++swapfocus(const Arg *arg) ++{ ++ Client *c; ++ int found = 0; ++ ++ if (!prevclient) ++ return; ++ ++ /* Verify the client still exists in the list of managed windows */ ++ 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); ++ } else { ++ /* Tag IS visible: Just swap focus within the same view */ ++ focusclient(prevclient, 1); ++ } ++ } ++} ++ + void + startdrag(struct wl_listener *listener, void *data) + { +-- +2.53.0 +