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:
co-authored by
David Heinemeier Hansson
parent
354c2f0060
commit
7633d8dee4
@@ -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"
|
||||
@@ -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'))
|
||||
|
||||
Reference in New Issue
Block a user