fix(core): hide floats with cmd+shift+v only when a float has focus
- commit
- 99fdfdfa975bf16041b3c4d330c6d543114c1e2c
- author
- brice · · 2026-09-28 13:12 UTC
- committer
- brice · · 2026-09-28 14:44 UTC
- parent
- 0db93ca
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
3 files · +21 -14
M docs/config.md +1 -1
| @@ -91,7 +91,7 @@ HDR requires DRM HDR connector properties, suitable KMS planes, and Vulkan fp16 | |||
| 91 | 91 | | `close-window` | Close the focused window | | |
| 92 | 92 | | `toggle-fullscreen` | Fullscreen the focused window | | |
| 93 | 93 | | `toggle-window-floating` | Float a tiled window at 80% of usable area; toggle back to its former column, width and maximized or expanded state when possible. A native dialog becomes a new tiled column | | |
| 94 | - | | `toggle-floating-visible` | Hide or show all floats on this workspace; a new float shows them again | | |
| 94 | + | | `toggle-floating-visible` | Hide all floats on this workspace when a float has the focus, or show hidden ones again; a new float shows them too | | |
| 95 | 95 | | `maximize-column` | Toggle full usable width for the focused column, preserving gaps and its saved width; in fixed overflow, other columns are hidden until focus moves or it is toggled off. On a window that made itself fullscreen (e.g. a Wine app at monitor size), it first returns the window to its column | | |
| 96 | 96 | | `cycle-column-width` | Step through `layout.presets`. In fixed overflow, toggle the focused column to `max-columns - 1` cells in place; the other columns stack on each side in the last cell. One column is expanded at a time | | |
| 97 | 97 | | `focus-column-left/right` | Focus the neighbor column; at the edge, the neighbor monitor. In fixed overflow, the neighbor on screen | | |
| @@ -91,7 +91,7 @@ HDR requires DRM HDR connector properties, suitable KMS planes, and Vulkan fp16 | |||||
| 91 | | `close-window` | Close the focused window | | 91 | | `close-window` | Close the focused window | | ||
| 92 | | `toggle-fullscreen` | Fullscreen the focused window | | 92 | | `toggle-fullscreen` | Fullscreen the focused window | | ||
| 93 | | `toggle-window-floating` | Float a tiled window at 80% of usable area; toggle back to its former column, width and maximized or expanded state when possible. A native dialog becomes a new tiled column | | 93 | | `toggle-window-floating` | Float a tiled window at 80% of usable area; toggle back to its former column, width and maximized or expanded state when possible. A native dialog becomes a new tiled column | | ||
| 94 | - | | `toggle-floating-visible` | Hide or show all floats on this workspace; a new float shows them again | | 94 | + | | `toggle-floating-visible` | Hide all floats on this workspace when a float has the focus, or show hidden ones again; a new float shows them too | |
| 95 | | `maximize-column` | Toggle full usable width for the focused column, preserving gaps and its saved width; in fixed overflow, other columns are hidden until focus moves or it is toggled off. On a window that made itself fullscreen (e.g. a Wine app at monitor size), it first returns the window to its column | | 95 | | `maximize-column` | Toggle full usable width for the focused column, preserving gaps and its saved width; in fixed overflow, other columns are hidden until focus moves or it is toggled off. On a window that made itself fullscreen (e.g. a Wine app at monitor size), it first returns the window to its column | | ||
| 96 | | `cycle-column-width` | Step through `layout.presets`. In fixed overflow, toggle the focused column to `max-columns - 1` cells in place; the other columns stack on each side in the last cell. One column is expanded at a time | | 96 | | `cycle-column-width` | Step through `layout.presets`. In fixed overflow, toggle the focused column to `max-columns - 1` cells in place; the other columns stack on each side in the last cell. One column is expanded at a time | | ||
| 97 | | `focus-column-left/right` | Focus the neighbor column; at the edge, the neighbor monitor. In fixed overflow, the neighbor on screen | | 97 | | `focus-column-left/right` | Focus the neighbor column; at the edge, the neighbor monitor. In fixed overflow, the neighbor on screen | | ||
M internal/core/floating_test.go +11 -4
| @@ -128,8 +128,8 @@ func TestHiddenFloatFullscreenRequest(t *testing.T) { | |||
| 128 | 128 | } | |
| 129 | 129 | } | |
| 130 | 130 | ||
| 131 | - | // Hiding floats keeps the columns' focus, and a hidden fullscreen float | |
| 132 | - | // no longer hides the columns. | |
| 131 | + | // Only a focused float hides the floats; a hidden fullscreen float no | |
| 132 | + | // longer hides the columns. | |
| 133 | 133 | func TestToggleFloatingVisibleFocusAndFullscreen(t *testing.T) { | |
| 134 | 134 | w := workspace() | |
| 135 | 135 | w.Overflow = OverflowFixed | |
| @@ -137,9 +137,16 @@ func TestToggleFloatingVisibleFocusAndFullscreen(t *testing.T) { | |||
| 137 | 137 | w.AddFloating(2, 20, 10) | |
| 138 | 138 | w.FocusID(1) | |
| 139 | 139 | w.Apply(ActionToggleFloatingVisible) | |
| 140 | + | if id, _ := w.Focused(); id != 1 || w.floatsHidden { | |
| 141 | + | t.Fatalf("column window hid floats: focused %d hidden %v", id, w.floatsHidden) | |
| 142 | + | } | |
| 143 | + | // Shown again from a column window, the top float takes the focus. | |
| 144 | + | w.FocusID(2) | |
| 140 | 145 | w.Apply(ActionToggleFloatingVisible) | |
| 141 | - | if id, _ := w.Focused(); id != 1 { | |
| 142 | - | t.Fatalf("column focus lost: %d", id) | |
| 146 | + | w.FocusID(1) | |
| 147 | + | w.Apply(ActionToggleFloatingVisible) | |
| 148 | + | if id, _ := w.Focused(); id != 2 || w.floatsHidden { | |
| 149 | + | t.Fatalf("show from column: focused %d hidden %v", id, w.floatsHidden) | |
| 143 | 150 | } | |
| 144 | 151 | w.FocusID(2) | |
| 145 | 152 | w.SetFullscreen(2, true) | |
| @@ -128,8 +128,8 @@ func TestHiddenFloatFullscreenRequest(t *testing.T) { | |||||
| 128 | } | 128 | } | ||
| 129 | } | 129 | } | ||
| 130 | 130 | ||||
| 131 | - | // Hiding floats keeps the columns' focus, and a hidden fullscreen float | 131 | + | // Only a focused float hides the floats; a hidden fullscreen float no |
| 132 | - | // no longer hides the columns. | 132 | + | // longer hides the columns. |
| 133 | func TestToggleFloatingVisibleFocusAndFullscreen(t *testing.T) { | 133 | func TestToggleFloatingVisibleFocusAndFullscreen(t *testing.T) { | ||
| 134 | w := workspace() | 134 | w := workspace() | ||
| 135 | w.Overflow = OverflowFixed | 135 | w.Overflow = OverflowFixed | ||
| @@ -137,9 +137,16 @@ func TestToggleFloatingVisibleFocusAndFullscreen(t *testing.T) { | |||||
| 137 | w.AddFloating(2, 20, 10) | 137 | w.AddFloating(2, 20, 10) | ||
| 138 | w.FocusID(1) | 138 | w.FocusID(1) | ||
| 139 | w.Apply(ActionToggleFloatingVisible) | 139 | w.Apply(ActionToggleFloatingVisible) | ||
| 140 | + | if id, _ := w.Focused(); id != 1 || w.floatsHidden { | |||
| 141 | + | t.Fatalf("column window hid floats: focused %d hidden %v", id, w.floatsHidden) | |||
| 142 | + | } | |||
| 143 | + | // Shown again from a column window, the top float takes the focus. | |||
| 144 | + | w.FocusID(2) | |||
| 140 | w.Apply(ActionToggleFloatingVisible) | 145 | w.Apply(ActionToggleFloatingVisible) | ||
| 141 | - | if id, _ := w.Focused(); id != 1 { | 146 | + | w.FocusID(1) |
| 142 | - | t.Fatalf("column focus lost: %d", id) | 147 | + | w.Apply(ActionToggleFloatingVisible) |
| 148 | + | if id, _ := w.Focused(); id != 2 || w.floatsHidden { | |||
| 149 | + | t.Fatalf("show from column: focused %d hidden %v", id, w.floatsHidden) | |||
| 143 | } | 150 | } | ||
| 144 | w.FocusID(2) | 151 | w.FocusID(2) | ||
| 145 | w.SetFullscreen(2, true) | 152 | w.SetFullscreen(2, true) | ||
M internal/core/layout.go +9 -9
| @@ -139,9 +139,8 @@ type Workspace struct { | |||
| 139 | 139 | Floats []Float | |
| 140 | 140 | floatFocus bool | |
| 141 | 141 | floatsHidden bool | |
| 142 | - | // hiddenFocus and hiddenFullscreen hold the float focus and a float's | |
| 143 | - | // fullscreen while the floats are hidden, restored when shown. | |
| 144 | - | hiddenFocus bool | |
| 142 | + | // hiddenFullscreen holds a float's fullscreen while the floats are | |
| 143 | + | // hidden, restored when shown. | |
| 145 | 144 | hiddenFullscreen WindowID | |
| 146 | 145 | // home is the monitor (key or connector) the workspace belongs to; "" | |
| 147 | 146 | // means the one it is on. On another monitor it is a guest; homePos is | |
| @@ -336,7 +335,7 @@ func (w *Workspace) RemoveWindow(id WindowID) { | |||
| 336 | 335 | w.hiddenFullscreen = 0 | |
| 337 | 336 | } | |
| 338 | 337 | if len(w.Floats) == 0 { | |
| 339 | - | w.floatFocus, w.floatsHidden, w.hiddenFocus = false, false, false | |
| 338 | + | w.floatFocus, w.floatsHidden = false, false | |
| 340 | 339 | } | |
| 341 | 340 | return | |
| 342 | 341 | } | |
| @@ -1013,24 +1012,25 @@ func (w *Workspace) ToggleWindowFloating() { | |||
| 1013 | 1012 | w.Floats[len(w.Floats)-1].back = back | |
| 1014 | 1013 | } | |
| 1015 | 1014 | ||
| 1016 | - | // ToggleFloatingVisible hides every float without changing its placement. | |
| 1015 | + | // ToggleFloatingVisible hides every float without changing its placement | |
| 1016 | + | // when a float has the focus, and shows them again from any window. | |
| 1017 | 1017 | func (w *Workspace) ToggleFloatingVisible() { | |
| 1018 | - | if len(w.Floats) == 0 { | |
| 1018 | + | if len(w.Floats) == 0 || !w.floatsHidden && !w.floatFocus { | |
| 1019 | 1019 | return | |
| 1020 | 1020 | } | |
| 1021 | 1021 | w.floatsHidden = !w.floatsHidden | |
| 1022 | 1022 | if w.floatsHidden { | |
| 1023 | 1023 | // A hidden fullscreen float would still hide the columns. | |
| 1024 | - | w.hiddenFocus, w.floatFocus = w.floatFocus, false | |
| 1024 | + | w.floatFocus = false | |
| 1025 | 1025 | w.hiddenFullscreen = 0 | |
| 1026 | 1026 | if w.floatIndex(w.fullscreen) >= 0 { | |
| 1027 | 1027 | w.hiddenFullscreen, w.fullscreen = w.fullscreen, 0 | |
| 1028 | 1028 | } | |
| 1029 | 1029 | return | |
| 1030 | 1030 | } | |
| 1031 | - | w.floatFocus = w.hiddenFocus | |
| 1031 | + | w.floatFocus = true | |
| 1032 | 1032 | if w.fullscreen == 0 && w.floatIndex(w.hiddenFullscreen) >= 0 { | |
| 1033 | 1033 | w.fullscreen = w.hiddenFullscreen | |
| 1034 | 1034 | } | |
| 1035 | - | w.hiddenFocus, w.hiddenFullscreen = false, 0 | |
| 1035 | + | w.hiddenFullscreen = 0 | |
| 1036 | 1036 | } | |
| @@ -139,9 +139,8 @@ type Workspace struct { | |||||
| 139 | Floats []Float | 139 | Floats []Float | ||
| 140 | floatFocus bool | 140 | floatFocus bool | ||
| 141 | floatsHidden bool | 141 | floatsHidden bool | ||
| 142 | - | // hiddenFocus and hiddenFullscreen hold the float focus and a float's | 142 | + | // hiddenFullscreen holds a float's fullscreen while the floats are |
| 143 | - | // fullscreen while the floats are hidden, restored when shown. | 143 | + | // hidden, restored when shown. |
| 144 | - | hiddenFocus bool | |||
| 145 | hiddenFullscreen WindowID | 144 | hiddenFullscreen WindowID | ||
| 146 | // home is the monitor (key or connector) the workspace belongs to; "" | 145 | // home is the monitor (key or connector) the workspace belongs to; "" | ||
| 147 | // means the one it is on. On another monitor it is a guest; homePos is | 146 | // means the one it is on. On another monitor it is a guest; homePos is | ||
| @@ -336,7 +335,7 @@ func (w *Workspace) RemoveWindow(id WindowID) { | |||||
| 336 | w.hiddenFullscreen = 0 | 335 | w.hiddenFullscreen = 0 | ||
| 337 | } | 336 | } | ||
| 338 | if len(w.Floats) == 0 { | 337 | if len(w.Floats) == 0 { | ||
| 339 | - | w.floatFocus, w.floatsHidden, w.hiddenFocus = false, false, false | 338 | + | w.floatFocus, w.floatsHidden = false, false |
| 340 | } | 339 | } | ||
| 341 | return | 340 | return | ||
| 342 | } | 341 | } | ||
| @@ -1013,24 +1012,25 @@ func (w *Workspace) ToggleWindowFloating() { | |||||
| 1013 | w.Floats[len(w.Floats)-1].back = back | 1012 | w.Floats[len(w.Floats)-1].back = back | ||
| 1014 | } | 1013 | } | ||
| 1015 | 1014 | ||||
| 1016 | - | // ToggleFloatingVisible hides every float without changing its placement. | 1015 | + | // ToggleFloatingVisible hides every float without changing its placement |
| 1016 | + | // when a float has the focus, and shows them again from any window. | |||
| 1017 | func (w *Workspace) ToggleFloatingVisible() { | 1017 | func (w *Workspace) ToggleFloatingVisible() { | ||
| 1018 | - | if len(w.Floats) == 0 { | 1018 | + | if len(w.Floats) == 0 || !w.floatsHidden && !w.floatFocus { |
| 1019 | return | 1019 | return | ||
| 1020 | } | 1020 | } | ||
| 1021 | w.floatsHidden = !w.floatsHidden | 1021 | w.floatsHidden = !w.floatsHidden | ||
| 1022 | if w.floatsHidden { | 1022 | if w.floatsHidden { | ||
| 1023 | // A hidden fullscreen float would still hide the columns. | 1023 | // A hidden fullscreen float would still hide the columns. | ||
| 1024 | - | w.hiddenFocus, w.floatFocus = w.floatFocus, false | 1024 | + | w.floatFocus = false |
| 1025 | w.hiddenFullscreen = 0 | 1025 | w.hiddenFullscreen = 0 | ||
| 1026 | if w.floatIndex(w.fullscreen) >= 0 { | 1026 | if w.floatIndex(w.fullscreen) >= 0 { | ||
| 1027 | w.hiddenFullscreen, w.fullscreen = w.fullscreen, 0 | 1027 | w.hiddenFullscreen, w.fullscreen = w.fullscreen, 0 | ||
| 1028 | } | 1028 | } | ||
| 1029 | return | 1029 | return | ||
| 1030 | } | 1030 | } | ||
| 1031 | - | w.floatFocus = w.hiddenFocus | 1031 | + | w.floatFocus = true |
| 1032 | if w.fullscreen == 0 && w.floatIndex(w.hiddenFullscreen) >= 0 { | 1032 | if w.fullscreen == 0 && w.floatIndex(w.hiddenFullscreen) >= 0 { | ||
| 1033 | w.fullscreen = w.hiddenFullscreen | 1033 | w.fullscreen = w.hiddenFullscreen | ||
| 1034 | } | 1034 | } | ||
| 1035 | - | w.hiddenFocus, w.hiddenFullscreen = false, 0 | 1035 | + | w.hiddenFullscreen = 0 |
| 1036 | } | 1036 | } | ||