Proof Portal
Omarchy
ProbeLabs65 findings · 95 requirementsA proof layer — requirements, tests and verified fixes — for two of Omarchy's subsystems: the application menu (launcher scripts, QML model, JSONC config, search and selection) and the lock screen (lock scripts, QML, PAM authentication). Scope is deliberately limited to those components of omacom/omarchy; the rest of the distribution is not covered.
KeyboardPanel dismissal recreates N-1 full-screen layer-shell surfaces on every open — laggy on many-monitor setups
Reported by jacobtminson · filed Sep 8, 2026 · open at source
At a glance
- 1 · What is claimed?
- Only the report text below — no validator has restated it as checkable claims yet.
- 2 · What does it affect?
- AreaOutside the audited area· Decided by agents · verified
- 3 · Is it reproducible?
- No validation has been run yet.
- 4 · What remains unclear?
- Not validated yet: no claims, no reproducer.
- 5 · What happens next?
- Decided by agents and verified by a second, independent agent — see the decision.
Original report
System details
Intel i9-14900HX / NVIDIA RTX 4070 Max-Q (mobile, hybrid), Omarchy 4.0.2-1, 5 monitors
What's wrong?
Opening any bar panel that uses Ui/KeyboardPanel.qml (weather, network, bluetooth, audio, monitor, power, tailscale, agents, and any bar-widget plugin built on it — basically everything except the couple built on PopupCard.qml) takes a perceptible moment on a many-monitor setup, every single time, not just on first open.
Cause: KeyboardPanel.qml's outside-click dismissal for other outputs is implemented as:
Variants {
model: root.open ? Quickshell.screens : []
delegate: Component {
PanelWindow { ... WlrLayershell.namespace: "omarchy-keyboard-panel-dismiss" ... }
}
}This creates N-1 full-screen transparent layer-shell surfaces (one per other monitor) on every single panel open, and destroys them again on close. That's a real Wayland surface map/unmap round-trip per surface, per open, scaling linearly with monitor count. On a 5-monitor setup this is 4 extra surface creations on every panel open — confirmed via hyprctl layers showing the omarchy-keyboard-panel-dismiss layers appear/disappear in lockstep with each open/close.
Existing lighter pattern in the same codebase: Ui/PopupCard.qml dismisses outside clicks via Hyprland's HyprlandFocusGrab instead, which needs no extra surfaces at all.
A fix we tried and do NOT recommend: keeping the Variants model always Quickshell.screens and relying only on the delegate's visible: root.open && ... binding to hide it when not needed. This does eliminate the per-open lag, but visible: false on this PanelWindow does not actually unmap the underlying wlr-layer-shell surface — it stayed mapped and kept accepting pointer input on every monitor, all the time, including while every panel was closed. Result: a full-screen invisible click-blocker on every screen, mouse completely unusable (keyboard still worked), until reverted. Do not ship this exact change.
Suggested direction instead: follow Ui/PopupCard.qml's existing pattern — HyprlandFocusGrab for outside-click dismissal needs no extra per-monitor surfaces at all, so it sidesteps this whole class of cost rather than trying to cache it.
One real wrinkle for whoever attempts that: KeyboardPanel.qml's own header comment notes that WlrKeyboardFocus.Exclusive "makes Hyprland route every pointer event to the exclusive surface no matter which output the cursor is over" — i.e. this component's existing Exclusive→OnDemand focus-prime dance exists specifically because compositor-wide (not per-output) pointer routing bit it once already. PopupCard.qml (a PopupWindow/xdg-popup) has no such priming logic to interact with. Whether HyprlandFocusGrab on a layer-shell PanelWindow that also toggles WlrLayershell.keyboardFocus between Exclusive/OnDemand/None plays nicely together is untested — we did not attempt it live given the blast radius (a bad interaction here reproduces the exact all-monitor input lockout above, not just a cosmetic bug), and would want it verified in a proper dev/test setup rather than on a live multi-monitor desktop.
Repro:
1. Have 3+ monitors active.
2. Open any KeyboardPanel-based bar panel (e.g. weather).
3. hyprctl layers while it's open — note omarchy-keyboard-panel-dismiss on every other monitor.
4. Close it, reopen it — same lag every time, not just first open.
View raw text
### System details
Intel i9-14900HX / NVIDIA RTX 4070 Max-Q (mobile, hybrid), Omarchy 4.0.2-1, 5 monitors
### What's wrong?
Opening any bar panel that uses `Ui/KeyboardPanel.qml` (weather, network, bluetooth, audio, monitor, power, tailscale, agents, and any bar-widget plugin built on it — basically everything except the couple built on `PopupCard.qml`) takes a perceptible moment on a many-monitor setup, every single time, not just on first open.
**Cause:** `KeyboardPanel.qml`'s outside-click dismissal for other outputs is implemented as:
```qml
Variants {
model: root.open ? Quickshell.screens : []
delegate: Component {
PanelWindow { ... WlrLayershell.namespace: "omarchy-keyboard-panel-dismiss" ... }
}
}
```
This creates N-1 full-screen transparent layer-shell surfaces (one per other monitor) on every single panel open, and destroys them again on close. That's a real Wayland surface map/unmap round-trip per surface, per open, scaling linearly with monitor count. On a 5-monitor setup this is 4 extra surface creations on every panel open — confirmed via `hyprctl layers` showing the `omarchy-keyboard-panel-dismiss` layers appear/disappear in lockstep with each open/close.
**Existing lighter pattern in the same codebase:** `Ui/PopupCard.qml` dismisses outside clicks via Hyprland's `HyprlandFocusGrab` instead, which needs no extra surfaces at all.
**A fix we tried and do NOT recommend:** keeping the `Variants` model always `Quickshell.screens` and relying only on the delegate's `visible: root.open && ...` binding to hide it when not needed. This does eliminate the per-open lag, but `visible: false` on this `PanelWindow` does **not** actually unmap the underlying wlr-layer-shell surface — it stayed mapped and kept accepting pointer input on every monitor, all the time, including while every panel was closed. Result: a full-screen invisible click-blocker on every screen, mouse completely unusable (keyboard still worked), until reverted. Do not ship this exact change.
**Suggested direction instead:** follow `Ui/PopupCard.qml`'s existing pattern — `HyprlandFocusGrab` for outside-click dismissal needs no extra per-monitor surfaces at all, so it sidesteps this whole class of cost rather than trying to cache it.
**One real wrinkle for whoever attempts that:** `KeyboardPanel.qml`'s own header comment notes that `WlrKeyboardFocus.Exclusive` "makes Hyprland route *every* pointer event to the exclusive surface no matter which output the cursor is over" — i.e. this component's existing Exclusive→OnDemand focus-prime dance exists specifically because compositor-wide (not per-output) pointer routing bit it once already. `PopupCard.qml` (a `PopupWindow`/xdg-popup) has no such priming logic to interact with. Whether `HyprlandFocusGrab` on a layer-shell `PanelWindow` that also toggles `WlrLayershell.keyboardFocus` between Exclusive/OnDemand/None plays nicely together is untested — we did not attempt it live given the blast radius (a bad interaction here reproduces the exact all-monitor input lockout above, not just a cosmetic bug), and would want it verified in a proper dev/test setup rather than on a live multi-monitor desktop.
**Repro:**
1. Have 3+ monitors active.
2. Open any KeyboardPanel-based bar panel (e.g. weather).
3. `hyprctl layers` while it's open — note `omarchy-keyboard-panel-dismiss` on every other monitor.
4. Close it, reopen it — same lag every time, not just first open.Validation
Not checked yet. A validator will restate this report as checkable claims, map it to the project's requirements and write a reproducer that the proof engine runs.
Linked
Not linked to any known issue, other report or change yet.
Decision
Decisions are recorded by our staff — or, where this project allows it, by agents: checked by a second, independent agent, or by a single agent where the project's policy says so. Any decision reached so far is shown below.
- Out of scopeDecided by agents · verified · 2026-10-09 11:14 UTC