detached 99fdfdf

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 VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · 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
9191 | `close-window` | Close the focused window |
9292 | `toggle-fullscreen` | Fullscreen the focused window |
9393 | `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 |
9595 | `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 |
9696 | `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 |
9797 | `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) {
128128 }
129129 }
130130
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.
133133 func TestToggleFloatingVisibleFocusAndFullscreen(t *testing.T) {
134134 w := workspace()
135135 w.Overflow = OverflowFixed
@@ -137,9 +137,16 @@ func TestToggleFloatingVisibleFocusAndFullscreen(t *testing.T) {
137137 w.AddFloating(2, 20, 10)
138138 w.FocusID(1)
139139 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)
140145 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)
143150 }
144151 w.FocusID(2)
145152 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 float131+// 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 = OverflowFixed135 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 {
139139 Floats []Float
140140 floatFocus bool
141141 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.
145144 hiddenFullscreen WindowID
146145 // home is the monitor (key or connector) the workspace belongs to; ""
147146 // 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) {
336335 w.hiddenFullscreen = 0
337336 }
338337 if len(w.Floats) == 0 {
339- w.floatFocus, w.floatsHidden, w.hiddenFocus = false, false, false
338+ w.floatFocus, w.floatsHidden = false, false
340339 }
341340 return
342341 }
@@ -1013,24 +1012,25 @@ func (w *Workspace) ToggleWindowFloating() {
10131012 w.Floats[len(w.Floats)-1].back = back
10141013 }
10151014
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.
10171017 func (w *Workspace) ToggleFloatingVisible() {
1018- if len(w.Floats) == 0 {
1018+ if len(w.Floats) == 0 || !w.floatsHidden && !w.floatFocus {
10191019 return
10201020 }
10211021 w.floatsHidden = !w.floatsHidden
10221022 if w.floatsHidden {
10231023 // A hidden fullscreen float would still hide the columns.
1024- w.hiddenFocus, w.floatFocus = w.floatFocus, false
1024+ w.floatFocus = false
10251025 w.hiddenFullscreen = 0
10261026 if w.floatIndex(w.fullscreen) >= 0 {
10271027 w.hiddenFullscreen, w.fullscreen = w.fullscreen, 0
10281028 }
10291029 return
10301030 }
1031- w.floatFocus = w.hiddenFocus
1031+ w.floatFocus = true
10321032 if w.fullscreen == 0 && w.floatIndex(w.hiddenFullscreen) >= 0 {
10331033 w.fullscreen = w.hiddenFullscreen
10341034 }
1035- w.hiddenFocus, w.hiddenFullscreen = false, 0
1035+ w.hiddenFullscreen = 0
10361036 }
@@ -139,9 +139,8 @@ type Workspace struct {
139 Floats []Float139 Floats []Float
140 floatFocus bool140 floatFocus bool
141 floatsHidden bool141 floatsHidden bool
142- // hiddenFocus and hiddenFullscreen hold the float focus and a float's142+ // 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 WindowID144 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 is146 // 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 = 0335 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, false338+ w.floatFocus, w.floatsHidden = false, false
340 }339 }
341 return340 return
342 }341 }
@@ -1013,24 +1012,25 @@ func (w *Workspace) ToggleWindowFloating() {
1013 w.Floats[len(w.Floats)-1].back = back1012 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 return1019 return
1020 }1020 }
1021 w.floatsHidden = !w.floatsHidden1021 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, false1024+ w.floatFocus = false
1025 w.hiddenFullscreen = 01025 w.hiddenFullscreen = 0
1026 if w.floatIndex(w.fullscreen) >= 0 {1026 if w.floatIndex(w.fullscreen) >= 0 {
1027 w.hiddenFullscreen, w.fullscreen = w.fullscreen, 01027 w.hiddenFullscreen, w.fullscreen = w.fullscreen, 0
1028 }1028 }
1029 return1029 return
1030 }1030 }
1031- w.floatFocus = w.hiddenFocus1031+ 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.hiddenFullscreen1033 w.fullscreen = w.hiddenFullscreen
1034 }1034 }
1035- w.hiddenFocus, w.hiddenFullscreen = false, 01035+ w.hiddenFullscreen = 0
1036 }1036 }

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 25

Tags 10

↑↓ moveenter openesc close