Files
omarchy/test/shell.d/overlay-window-test.sh
T
David Heinemeier HanssonandClaude Opus 5.5 5c7cef1e78 Keep Hyprland from sliding the OSD in from the corner (#13436)
The OSD, the reminder flow and the Wi-Fi QR code now keep a surface that
parks as a 1x1 in the corner and grows when shown. They were missing from
the layer rule that turns Hyprland's layer animation off for the shell's
overlays, so Hyprland animated that growth: the OSD flew in from the left.

Add them to the rule, and test that every OverlayWindow's namespace is in
it.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 21:07:27 +02:00

82 lines
3.5 KiB
Bash

#!/bin/bash
set -euo pipefail
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
run_node_test <<'JS'
const fs = require('fs')
const read = (file) => fs.readFileSync(path.join(root, file), 'utf8')
const overlay = read('shell/Ui/OverlayWindow.qml')
// Closed, the surface parks 1x1, input-less and without keyboard below
// windows: off the overlay layer, so it never blocks direct scanout.
assert(
overlay.includes('visible: true') &&
overlay.includes('anchors { top: true; left: true; bottom: shown; right: shown }') &&
overlay.includes('implicitWidth: 1') &&
overlay.includes('implicitHeight: 1') &&
overlay.includes('mask: shown ? null : emptyRegion') &&
overlay.includes('WlrLayershell.layer: shown ? shownLayer : WlrLayer.Bottom') &&
overlay.includes('WlrLayershell.keyboardFocus: shown ? shownKeyboardFocus : WlrKeyboardFocus.None'),
'overlay window parks a 1x1 input-less surface below windows while hidden'
)
// Content stays hidden until the surface has grown, so no frame drawn at 1x1
// is stretched across the screen.
assert(
/target: window\.contentItem\s*property: "visible"\s*value: window\.shown && window\.width > 1 && window\.height > 1/.test(overlay),
'overlay window draws nothing until the surface has grown'
)
assert(
/onShownChanged: if \(shown\) targetScreen = focusedScreen\(\) \|\| targetScreen/.test(overlay) &&
overlay.includes('screen: targetScreen'),
'overlay window follows the focused monitor each time it is shown'
)
const overlays = {
'shell/plugins/menu/Menu.qml': 'shown: root.opened && root.rowsLoaded',
'shell/plugins/emojis/Emojis.qml': 'shown: root.opened',
'shell/plugins/clipboard/Clipboard.qml': 'shown: root.opened',
'shell/plugins/osd/Osd.qml': 'shown: root.opened',
'shell/plugins/reminders/ReminderFlow.qml': 'shown: root.opened',
'shell/plugins/panels/wifiqr/Panel.qml': 'shown: root.opened',
'shell/plugins/image-picker/ImagePicker.qml': 'shown: root.opened',
}
for (const [file, shown] of Object.entries(overlays)) {
const qml = read(file)
assert(
qml.includes('OverlayWindow {') && qml.includes(shown) && !/PanelWindow \{\s*(id: panel\s*)?visible: root\.opened/.test(qml),
`${file} keeps its surface through OverlayWindow`
)
}
// Window visibility never changes now, so close-time resets key off shown.
const menuQml = read('shell/plugins/menu/Menu.qml')
assert(
menuQml.includes('onShownChanged: if (!shown) { cardTop = -1; maxRowsHeight = -1 }') &&
menuQml.includes('if (shown && cardTop < 0) {') &&
!/onVisibleChanged: if \(!visible\) \{ cardTop/.test(menuQml),
'the menu unfreezes its layout when the overlay hides'
)
// A kept surface grows from its parked 1x1 when shown, which Hyprland animates
// as a slide in from the corner unless its layer rule turns animation off.
const shellRules = read('default/hypr/apps/omarchy-shell.lua')
const noAnim = /namespace = "\^\(([^)]*)\)\$" \}, no_anim = true/.exec(shellRules)
assert(noAnim, 'the shell overlays share one no-animation layer rule')
const unanimated = noAnim ? noAnim[1].split('|') : []
for (const file of Object.keys(overlays)) {
const namespace = /WlrLayershell\.namespace: "([^"]+)"/.exec(read(file))
assert(namespace && unanimated.includes(namespace[1]), `${file} is exempt from Hyprland's layer animation`)
}
// The OSD never takes the keyboard or input, shown or not.
const osd = read('shell/plugins/osd/Osd.qml')
assert(
osd.includes('shownKeyboardFocus: WlrKeyboardFocus.None') && osd.includes('mask: Region {}'),
'the OSD stays click-through and keyboard-free while shown'
)
JS