From 310edeada8647bd1df1f2d625f8fe8888ac04a75 Mon Sep 17 00:00:00 2001 From: Yocraft-2000 <304616174+Yocraft-2000@users.noreply.github.com> Date: Sat, 22 Aug 2026 22:45:22 +0200 Subject: [PATCH 1/4] feat: add window-focus-toggle-floating-tiling bind --- src/config/keybind_parse.cpp | 1 + src/config/keybind_parse.h | 1 + src/scene/cheatsheet_rows.cpp | 1 + src/server/actions.cpp | 26 ++++++++++++++++++++++++++ 4 files changed, 29 insertions(+) diff --git a/src/config/keybind_parse.cpp b/src/config/keybind_parse.cpp index 5051313d..cf3626c0 100644 --- a/src/config/keybind_parse.cpp +++ b/src/config/keybind_parse.cpp @@ -184,6 +184,7 @@ namespace umbriel { {"window-focus-next", "", KeybindAction::WindowFocusNext}, {"window-focus-right", "", KeybindAction::WindowFocusRight}, {"window-focus-up", "", KeybindAction::WindowFocusUp}, + {"window-focus-toggle-floating-tiling", "", KeybindAction::WindowFocusFloatingOrTiling}, {"window-modify-width", "", KeybindAction::WindowModifyWidth, ActionArgKind::WidthDelta}, {"window-move-down", "", KeybindAction::WindowMoveDown}, {"window-move-to-output-down", "", KeybindAction::WindowMoveToOutputDown}, diff --git a/src/config/keybind_parse.h b/src/config/keybind_parse.h index 727f8e12..3f76a09d 100644 --- a/src/config/keybind_parse.h +++ b/src/config/keybind_parse.h @@ -31,6 +31,7 @@ namespace umbriel { WindowFocusRight, WindowFocusUp, WindowFocusDown, + WindowFocusFloatingOrTiling, ColumnMoveLeft, ColumnMoveRight, WindowMoveUp, diff --git a/src/scene/cheatsheet_rows.cpp b/src/scene/cheatsheet_rows.cpp index 7e081bea..0df9933b 100644 --- a/src/scene/cheatsheet_rows.cpp +++ b/src/scene/cheatsheet_rows.cpp @@ -272,6 +272,7 @@ namespace { case A::WindowFocusDown: case A::WindowFocusNext: case A::WindowFocusId: + case A::WindowFocusFloatingOrTiling: return Group::Focus; case A::ColumnMoveLeft: case A::ColumnMoveRight: diff --git a/src/server/actions.cpp b/src/server/actions.cpp index 17148c85..9c4c510e 100644 --- a/src/server/actions.cpp +++ b/src/server/actions.cpp @@ -508,6 +508,31 @@ namespace umbriel { return true; } + bool actionFocusFloatingOrTiling(Server& server, const Keybind& /*bind*/, std::string* /*error*/) { + Workspace* workspace = activeWorkspace(server); + if (workspace == nullptr) { + return true; + } + View* focused = workspace->focusedView(); + const bool seekFloating = focused == nullptr || !focused->floating(); + View* target = nullptr; + for (const auto& entry : server.registry().all()) { + View* view = entry.get(); + if (view == focused || !view->mapped() || view->workspace() != workspace) { + continue; + } + if (view->floating() != seekFloating) { + continue; + } + target = view; + break; + } + if (target != nullptr && target != focused) { + server.focusView(target, FocusReason::Directional); + } + return true; + } + // Workspaces bool actionWorkspace(Server& server, const Keybind& bind, std::string* error) { const std::expected target = resolveWorkspaceSelector(server, bind); @@ -839,6 +864,7 @@ namespace umbriel { &actionFocusAdjacent<1>, &actionFocusVertical<-1>, &actionFocusVertical<1>, + &actionFocusFloatingOrTiling, &actionMoveColumn<-1>, &actionMoveColumn<1>, &actionMoveVertical<-1>, From 056ec8829a1d850e3c721a67fd26c534621ed90b Mon Sep 17 00:00:00 2001 From: Yocraft-2000 <304616174+Yocraft-2000@users.noreply.github.com> Date: Sat, 22 Aug 2026 22:47:59 +0200 Subject: [PATCH 2/4] fix: keep alphabetical order in keybind_parse.cpp --- src/config/keybind_parse.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/keybind_parse.cpp b/src/config/keybind_parse.cpp index cf3626c0..0b584001 100644 --- a/src/config/keybind_parse.cpp +++ b/src/config/keybind_parse.cpp @@ -183,8 +183,8 @@ namespace umbriel { {"window-focus-left", "", KeybindAction::WindowFocusLeft}, {"window-focus-next", "", KeybindAction::WindowFocusNext}, {"window-focus-right", "", KeybindAction::WindowFocusRight}, - {"window-focus-up", "", KeybindAction::WindowFocusUp}, {"window-focus-toggle-floating-tiling", "", KeybindAction::WindowFocusFloatingOrTiling}, + {"window-focus-up", "", KeybindAction::WindowFocusUp}, {"window-modify-width", "", KeybindAction::WindowModifyWidth, ActionArgKind::WidthDelta}, {"window-move-down", "", KeybindAction::WindowMoveDown}, {"window-move-to-output-down", "", KeybindAction::WindowMoveToOutputDown}, From 76469b8ff0be41919534d3b40a77c40e07b23d79 Mon Sep 17 00:00:00 2001 From: Yocraft-2000 <304616174+Yocraft-2000@users.noreply.github.com> Date: Sat, 22 Aug 2026 22:51:17 +0200 Subject: [PATCH 3/4] docs: document window-focus-toggle-floating-tiling bind and config example --- docs/user/keybinds.md | 2 ++ examples/config.toml | 1 + 2 files changed, 3 insertions(+) diff --git a/docs/user/keybinds.md b/docs/user/keybinds.md index 98d5f5a4..48b168a0 100644 --- a/docs/user/keybinds.md +++ b/docs/user/keybinds.md @@ -114,6 +114,8 @@ These take no argument. The first time a window floats, Umbriel places it slightly below and to the right of its tiled position while keeping it on-screen. +`window-focus-toggle-floating-tiling` switches focus between floating and tiling windows. + `window-toggle-pinned` makes the focused window float and keeps it above fullscreen windows on its output. Pinned windows remain visible when you switch workspaces. You cannot pin a fullscreen window, and making a pinned diff --git a/examples/config.toml b/examples/config.toml index 15159185..54215500 100644 --- a/examples/config.toml +++ b/examples/config.toml @@ -187,6 +187,7 @@ follows_mouse = false [keybinds] "Mod+Return" = "spawn:kitty" "Mod+T" = "window-toggle-floating" +"Mod+Shift+T" = "window-focus-toggle-floating-tiling" "Mod+P" = "window-toggle-pinned" "Mod+M" = "window-toggle-maximize-to-edges" "Mod+Shift+Q" = "window-close" From da1068b98c1912f209a8dbd0bd78d50f928b99b6 Mon Sep 17 00:00:00 2001 From: Lemmy Date: Tue, 25 Aug 2026 22:28:59 -0400 Subject: [PATCH 4/4] fix(keybinds): rename floating focus switch action --- docs/user/keybinds.md | 3 ++- examples/config.toml | 2 +- src/config/keybind_parse.cpp | 2 +- src/config/keybind_parse.h | 2 +- src/scene/cheatsheet_rows.cpp | 2 +- src/server/actions.cpp | 4 ++-- tests/keybind_parse.cpp | 4 ++++ 7 files changed, 12 insertions(+), 7 deletions(-) diff --git a/docs/user/keybinds.md b/docs/user/keybinds.md index 48b168a0..65116f7c 100644 --- a/docs/user/keybinds.md +++ b/docs/user/keybinds.md @@ -114,7 +114,8 @@ These take no argument. The first time a window floats, Umbriel places it slightly below and to the right of its tiled position while keeping it on-screen. -`window-focus-toggle-floating-tiling` switches focus between floating and tiling windows. +`window-focus-switch-floating` switches focus to the most recently focused +window with the opposite floating state. `window-toggle-pinned` makes the focused window float and keeps it above fullscreen windows on its output. Pinned windows remain visible when you diff --git a/examples/config.toml b/examples/config.toml index 54215500..68268077 100644 --- a/examples/config.toml +++ b/examples/config.toml @@ -187,7 +187,7 @@ follows_mouse = false [keybinds] "Mod+Return" = "spawn:kitty" "Mod+T" = "window-toggle-floating" -"Mod+Shift+T" = "window-focus-toggle-floating-tiling" +"Mod+Shift+T" = "window-focus-switch-floating" "Mod+P" = "window-toggle-pinned" "Mod+M" = "window-toggle-maximize-to-edges" "Mod+Shift+Q" = "window-close" diff --git a/src/config/keybind_parse.cpp b/src/config/keybind_parse.cpp index 0b584001..f4111d53 100644 --- a/src/config/keybind_parse.cpp +++ b/src/config/keybind_parse.cpp @@ -183,7 +183,7 @@ namespace umbriel { {"window-focus-left", "", KeybindAction::WindowFocusLeft}, {"window-focus-next", "", KeybindAction::WindowFocusNext}, {"window-focus-right", "", KeybindAction::WindowFocusRight}, - {"window-focus-toggle-floating-tiling", "", KeybindAction::WindowFocusFloatingOrTiling}, + {"window-focus-switch-floating", "", KeybindAction::WindowFocusSwitchFloating}, {"window-focus-up", "", KeybindAction::WindowFocusUp}, {"window-modify-width", "", KeybindAction::WindowModifyWidth, ActionArgKind::WidthDelta}, {"window-move-down", "", KeybindAction::WindowMoveDown}, diff --git a/src/config/keybind_parse.h b/src/config/keybind_parse.h index 3f76a09d..11153f86 100644 --- a/src/config/keybind_parse.h +++ b/src/config/keybind_parse.h @@ -31,7 +31,7 @@ namespace umbriel { WindowFocusRight, WindowFocusUp, WindowFocusDown, - WindowFocusFloatingOrTiling, + WindowFocusSwitchFloating, ColumnMoveLeft, ColumnMoveRight, WindowMoveUp, diff --git a/src/scene/cheatsheet_rows.cpp b/src/scene/cheatsheet_rows.cpp index 0df9933b..909c4e59 100644 --- a/src/scene/cheatsheet_rows.cpp +++ b/src/scene/cheatsheet_rows.cpp @@ -272,7 +272,7 @@ namespace { case A::WindowFocusDown: case A::WindowFocusNext: case A::WindowFocusId: - case A::WindowFocusFloatingOrTiling: + case A::WindowFocusSwitchFloating: return Group::Focus; case A::ColumnMoveLeft: case A::ColumnMoveRight: diff --git a/src/server/actions.cpp b/src/server/actions.cpp index 9c4c510e..adce3319 100644 --- a/src/server/actions.cpp +++ b/src/server/actions.cpp @@ -508,7 +508,7 @@ namespace umbriel { return true; } - bool actionFocusFloatingOrTiling(Server& server, const Keybind& /*bind*/, std::string* /*error*/) { + bool actionFocusSwitchFloating(Server& server, const Keybind& /*bind*/, std::string* /*error*/) { Workspace* workspace = activeWorkspace(server); if (workspace == nullptr) { return true; @@ -864,7 +864,7 @@ namespace umbriel { &actionFocusAdjacent<1>, &actionFocusVertical<-1>, &actionFocusVertical<1>, - &actionFocusFloatingOrTiling, + &actionFocusSwitchFloating, &actionMoveColumn<-1>, &actionMoveColumn<1>, &actionMoveVertical<-1>, diff --git a/tests/keybind_parse.cpp b/tests/keybind_parse.cpp index 872a9fae..a8fcb113 100644 --- a/tests/keybind_parse.cpp +++ b/tests/keybind_parse.cpp @@ -179,6 +179,10 @@ UMBRIEL_TEST(parsesSimpleActions) { CHECK(parseAction("window-close", bind)); CHECK(bind.action == KeybindAction::WindowClose); + CHECK(parseAction("window-focus-switch-floating", bind)); + CHECK(bind.action == KeybindAction::WindowFocusSwitchFloating); + CHECK(!parseAction("window-focus-toggle-floating-tiling", bind)); + CHECK(parseAction("session-quit", bind)); CHECK(bind.action == KeybindAction::SessionQuit); }