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