Keep the bar mapped while hidden so revealing it is instant (#6677)

* Keep the bar mapped while hidden so revealing it is instant

Hiding the bar set the panel invisible, which unmaps the layer surface and
releases the scene graph with it. Every reveal then had to rebuild all of
it: a new layer surface, a configure roundtrip, re-shaped glyphs and
re-uploaded textures, and a first frame before anything appeared.

Measured on a 2560x1440 screen, showing took 155-175ms against 20ms to
hide, and 400-595ms on the first reveal after a cold start. Splitting the
cost showed the exclusive-zone reflow was not to blame: show latency was
the same on an empty workspace as on a tiled one, and windows finished
moving ~15ms after the bar was already on screen.

Park the bar one bar-width past its anchored edge instead, and drop its
exclusion zone while hidden. The surface stays alive, so showing is only
a margin change: 10-14ms in both directions, at every bar position.

Since a hidden bar is now mapped, layer_present no longer proves the bar
is visible; the session acceptance test asserts on-screen geometry.

* Fix layer visibility checks on offset monitors

* Handle rotated outputs in layer visibility checks

* Cover hidden bar behavior in acceptance tests

---------

Co-authored-by: David Heinemeier Hansson <david@hey.com>
This commit is contained in:
Vivek
2026-08-10 14:10:31 +02:00
committed by GitHub
co-authored by David Heinemeier Hansson
parent 354c2f0060
commit 7633d8dee4
5 changed files with 134 additions and 5 deletions
+16 -3
View File
@@ -27,8 +27,8 @@ Item {
// diagnostics; the built-in bar does not otherwise need it.
property var manifest: null
// Mirrors the on-disk `bar-off` flag so the user can hide the bar without
// killing the entire shell. Wired to BarPanel.visible below; updated by the
// FileView watcher further down.
// killing the entire shell. Hidden panels stay mapped but park off-screen
// without an exclusion zone; updated by the FileView watcher further down.
property bool barHidden: false
property string home: Quickshell.env("HOME")
property string stateHome: home + "/.local/state"
@@ -956,13 +956,26 @@ Item {
component BarPanel: PanelWindow {
id: barWindow
visible: !root.barHidden && !remapGuard.remapping
// Hiding parks the bar just past its screen edge instead of unmapping it.
// Unmapping frees the layer surface and the whole scene graph, so every
// reveal has to rebuild them — new surface, re-shaped glyphs, re-uploaded
// textures — which measures ~150ms against ~20ms to tear down. Parking
// keeps the surface alive, so showing is only a margin change.
visible: !remapGuard.remapping
exclusionMode: root.barHidden ? ExclusionMode.Ignore : ExclusionMode.Auto
ScreenMoveRemap {
id: remapGuard
window: barWindow
}
margins {
top: root.barHidden && root.position === "top" ? -root.barSize : 0
bottom: root.barHidden && root.position === "bottom" ? -root.barSize : 0
left: root.barHidden && root.position === "left" ? -root.barSize : 0
right: root.barHidden && root.position === "right" ? -root.barSize : 0
}
anchors {
top: root.position === "top" || root.vertical
bottom: root.position === "bottom" || root.vertical
+28
View File
@@ -79,6 +79,34 @@ layer_absent() {
! layer_present "$1"
}
# A layer can be mapped but parked off the monitor: the bar hides that way so
# revealing it does not have to rebuild the surface. Assert on geometry when
# what matters is that the user can actually see it. Layer boxes are local to
# their monitor and in logical coordinates, so compare them with local bounds
# derived from the monitor's scaled pixel size.
layer_on_screen() {
local monitors
monitors=$(hyprctl -j monitors) || return 1
hyprctl -j layers | jq -e --arg ns "$1" --argjson monitors "$monitors" '
to_entries[]
| .key as $name
| .value as $levels
| ($monitors[] | select(.name == $name)) as $m
| (if ($m.transform // 0) % 2 == 1 then $m.height else $m.width end) / $m.scale | round as $width
| (if ($m.transform // 0) % 2 == 1 then $m.width else $m.height end) / $m.scale | round as $height
| [$levels | .. | objects | select(.namespace? == $ns)][]
| select(
.x + .w > 0 and .x < $width and
.y + .h > 0 and .y < $height
)
' >/dev/null
}
layer_off_screen() {
! layer_on_screen "$1"
}
# Close every window matching a class regex, by address so multi-window apps
# are fully closed. Tries the quattro Lua dispatcher first, then classic.
close_windows() {
+19 -2
View File
@@ -24,8 +24,25 @@ for plugin in \
done
# The bar and background are actually on screen
wait_until "bar layer is on screen" 30 layer_present "omarchy-bar"
wait_until "background layer is on screen" 30 layer_present "omarchy-background"
wait_until "bar layer is on screen" 30 layer_on_screen "omarchy-bar"
wait_until "background layer is on screen" 30 layer_on_screen "omarchy-background"
# Hiding parks the bar off-screen without unmapping its layer surface, and
# revealing brings that same surface back on-screen.
restore_bar_visibility() {
omarchy-toggle-bar off >/dev/null 2>&1 || true
}
trap restore_bar_visibility EXIT
omarchy-toggle-bar on
wait_until "hidden bar layer stays mapped" 15 layer_present "omarchy-bar"
wait_until "hidden bar layer parks off screen" 15 layer_off_screen "omarchy-bar"
screenshot "success-bar-hidden"
omarchy-toggle-bar off
wait_until "revealed bar layer returns on screen" 15 layer_on_screen "omarchy-bar"
screenshot "success-bar-revealed"
trap - EXIT
# Audio stack is up
wait_until "pipewire is running" 30 wpctl status
+53
View File
@@ -0,0 +1,53 @@
#!/bin/bash
source "$(dirname "$0")/base-test.sh"
source "$ROOT/test/acceptance.d/base-test.sh"
monitor_json='[
{"name":"DP-1","x":1920,"y":0,"width":3840,"height":2160,"scale":2},
{"name":"DP-2","x":-2560,"y":-1440,"width":2560,"height":1440,"scale":1},
{"name":"DP-3","x":0,"y":1080,"width":1920,"height":1080,"scale":1,"transform":1}
]'
layer_json='{
"DP-1":{"levels":{"2":[
{"x":0,"y":0,"w":1920,"h":26,"namespace":"visible-positive-offset"},
{"x":1920,"y":0,"w":26,"h":1080,"namespace":"parked-positive-offset"}
]}},
"DP-2":{"levels":{"2":[
{"x":0,"y":0,"w":2560,"h":26,"namespace":"visible-negative-offset"},
{"x":-26,"y":0,"w":26,"h":1440,"namespace":"parked-negative-offset"}
]}},
"DP-3":{"levels":{"2":[
{"x":0,"y":1500,"w":26,"h":26,"namespace":"visible-rotated"},
{"x":1080,"y":0,"w":26,"h":1920,"namespace":"parked-rotated"}
]}}
}'
hyprctl() {
if [[ $2 == "monitors" ]]; then
printf '%s\n' "$monitor_json"
elif [[ $2 == "layers" ]]; then
printf '%s\n' "$layer_json"
else
return 1
fi
}
assert_layer_on_screen() {
local namespace="$1" description="$2"
layer_on_screen "$namespace" && pass "$description" || fail "$description"
}
assert_layer_off_screen() {
local namespace="$1" description="$2"
layer_off_screen "$namespace" && pass "$description" || fail "$description"
}
assert_layer_on_screen "visible-positive-offset" "visible layer is found on a positively offset monitor"
assert_layer_off_screen "parked-positive-offset" "right-parked layer stays off a positively offset monitor"
assert_layer_on_screen "visible-negative-offset" "visible layer is found on a negatively offset monitor"
assert_layer_off_screen "parked-negative-offset" "left-parked layer stays off a negatively offset monitor"
assert_layer_on_screen "visible-rotated" "visible layer uses the transformed monitor height"
assert_layer_off_screen "parked-rotated" "parked layer uses the transformed monitor width"
+18
View File
@@ -22,6 +22,24 @@ const shellSource = fs.readFileSync(root + '/shell/shell.qml', 'utf8')
assert(/function toggleBarTransparency\(\): string \{[\s\S]*?shell\.bar\.toggleTransparency\(\)/.test(shellSource), 'shell exposes the bar transparency toggle over IPC')
// Hiding must not unmap the bar. An unmapped layer surface has to be rebuilt on
// every reveal, which measured ~150ms against ~20ms to tear it down; parking it
// past the screen edge keeps show and hide symmetric at ~12ms.
assert(
/visible: !remapGuard\.remapping/.test(barSource),
'bar stays mapped while hidden so revealing it does not rebuild the surface'
)
assert(
/exclusionMode: root\.barHidden \? ExclusionMode\.Ignore : ExclusionMode\.Auto/.test(barSource),
'a hidden bar reserves no space for itself'
)
for (const edge of ['top', 'bottom', 'left', 'right']) {
assert(
new RegExp(`${edge}: root\\.barHidden && root\\.position === "${edge}" \\? -root\\.barSize : 0`).test(barSource),
`a hidden bar parks past the ${edge} edge`
)
}
// The center section declares two arrangements and shows one; the hidden one
// must not build its modules or every center widget exists twice.
const moduleList = barSource.slice(barSource.indexOf('component ModuleList'), barSource.indexOf('component ModuleSlot'))