diff --git a/docs/user/keybinds.md b/docs/user/keybinds.md index 98d5f5a..48b168a 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 1515918..5421550 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" diff --git a/src/config/keybind_parse.cpp b/src/config/keybind_parse.cpp index 5051313..0b58400 100644 --- a/src/config/keybind_parse.cpp +++ b/src/config/keybind_parse.cpp @@ -183,6 +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-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 727f8e1..3f76a09 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 7e081be..0df9933 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 17148c8..9c4c510 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>,