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.
Bar: pointing-hand cursor never appears until the slot's first click (stale mouseX/mouseY in modulePointer cursorShape binding)
Reported by JeronimoColon · filed Aug 30, 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
What happened
In the Omarchy shell bar, hovering a clickable bar widget does not show the pointing-hand cursor on first hover — the cursor stays an arrow. After the first click anywhere in that bar slot, the hand appears and then sticks for the rest of the session (frozen at the press point, so it even shows over the slot's non-clickable padding). Each slot needs its own first click. Widgets whose internal MouseAreas set PointingHandCursor (e.g. Ui/WidgetButton.qml) are shadowed by the slot layer and never show it on their own.
Expected
Pointing-hand cursor on first hover over any clickable widget, arrow over padding, no click required.
Root cause
shell/plugins/bar/Bar.qml:1667, in the per-slot modulePointer MouseArea (component ModuleSlot):
cursorShape: root.moduleClickTargetAt(slot, mouseX, mouseY) ? Qt.PointingHandCursor : Qt.ArrowCursormodulePointer never sets hoverEnabled (defaults to false), so per Qt semantics mouseX/mouseY are only updated by button presses — they initialize to (0,0). The binding therefore always evaluates moduleClickTargetAt(slot, 0, 0):
- Pre-click: slot-local (0,0) is padding on virtually every widget → always
ArrowCursor, regardless of where the pointer hovers. - Why the arrow shadows widget-internal hand cursors:
modulePointeris the topmost item in every slot, and cursor resolution picks the topmost item with a cursor set.QQuickMouseArea'shasCursorlatches permanently once the binding ever produces a non-default value — which happens transiently during bar startup, when click-target registration runs before the positioner spreads the slots and every slot's (0,0) probe momentarily hits an overlapping full-slot target. After that, the latched Arrow overrides the widgets' ownPointingHandCursorbeneath. - Why a click "fixes" it: the press finally writes real coordinates into
mouseX/mouseY(and they then freeze there), so the binding flips to the hand and stays.
Verified against the installed stack (Qt 6.11.2, quickshell 0.3.1, Hyprland 0.56.2) with offscreen QML test cases reproducing the stale-coordinate behavior, the startup latch, and the click "fix". Wayland cursor-shape protocol, Hyprland, and quickshell's window proxying were investigated and ruled out — the compositor and toolkit behave per spec; the binding just runs on coordinates that never update.
Proposed one-line fix
Not hoverEnabled: true on modulePointer — tested; a hover-enabled MouseArea on top blocks hover from reaching widget-internal MouseAreas, killing tooltips (WidgetButton onEntered → bar.showTooltip), containsMouse styling, and indicator hover-reveal. Presumably why it was left off.
The slot already has HoverHandler { id: moduleHover } (Bar.qml:1577, currently only feeding slot.hovered). HoverHandlers observe hover without blocking items below, and moduleHover.point.position is live and slot-local — the exact coordinate space moduleClickTargetAt expects. Replace line 1667 with:
cursorShape: root.moduleClickTargetAt(slot,
moduleHover.point.position.x, moduleHover.point.position.y)
? Qt.PointingHandCursor : undefinedThe undefined branch resets the cursor property (unsetCursor), so modulePointer stops claiming the cursor when not over a click target — this both defuses the startup latch and un-shadows widgets that set their own cursor internally. Verified offscreen (Qt 6.11.2): hand on first hover with no click, arrow over padding, hover still reaches inner MouseAreas (tooltips intact), click/drag logic unaffected (onPositionChanged already guards on mouse.buttons). Cost is an event-driven binding evaluation per hover move — no polling, no animation.
System
- Omarchy 4.0.1-1
- Qt 6.11.2 · quickshell 0.3.1 · Hyprland 0.56.2
- Dell Latitude 5420 (Intel TigerLake, Iris Xe), 1920×1080 @ 1.5 scale
Steps to reproduce
- Fresh login (or
omarchy restart shell); do not click anything in the bar. - Hover any clickable bar widget (clock, workspaces, etc.) → cursor stays an arrow.
- Click once anywhere in that widget's slot → hand cursor appears and persists for that slot, including over its padding.
View raw text
### What happened
In the Omarchy shell bar, hovering a clickable bar widget does not show the pointing-hand cursor on first hover — the cursor stays an arrow. After the first click anywhere in that bar slot, the hand appears and then sticks for the rest of the session (frozen at the press point, so it even shows over the slot's non-clickable padding). Each slot needs its own first click. Widgets whose internal MouseAreas set `PointingHandCursor` (e.g. `Ui/WidgetButton.qml`) are shadowed by the slot layer and never show it on their own.
### Expected
Pointing-hand cursor on first hover over any clickable widget, arrow over padding, no click required.
### Root cause
`shell/plugins/bar/Bar.qml:1667`, in the per-slot `modulePointer` MouseArea (`component ModuleSlot`):
```qml
cursorShape: root.moduleClickTargetAt(slot, mouseX, mouseY) ? Qt.PointingHandCursor : Qt.ArrowCursor
```
`modulePointer` never sets `hoverEnabled` (defaults to false), so per Qt semantics `mouseX/mouseY` are only updated by button presses — they initialize to (0,0). The binding therefore always evaluates `moduleClickTargetAt(slot, 0, 0)`:
1. **Pre-click**: slot-local (0,0) is padding on virtually every widget → always `ArrowCursor`, regardless of where the pointer hovers.
2. **Why the arrow shadows widget-internal hand cursors**: `modulePointer` is the topmost item in every slot, and cursor resolution picks the topmost item with a cursor set. `QQuickMouseArea`'s `hasCursor` latches permanently once the binding ever produces a non-default value — which happens transiently during bar startup, when click-target registration runs before the positioner spreads the slots and every slot's (0,0) probe momentarily hits an overlapping full-slot target. After that, the latched Arrow overrides the widgets' own `PointingHandCursor` beneath.
3. **Why a click "fixes" it**: the press finally writes real coordinates into `mouseX/mouseY` (and they then freeze there), so the binding flips to the hand and stays.
Verified against the installed stack (Qt 6.11.2, quickshell 0.3.1, Hyprland 0.56.2) with offscreen QML test cases reproducing the stale-coordinate behavior, the startup latch, and the click "fix". Wayland cursor-shape protocol, Hyprland, and quickshell's window proxying were investigated and ruled out — the compositor and toolkit behave per spec; the binding just runs on coordinates that never update.
### Proposed one-line fix
**Not** `hoverEnabled: true` on `modulePointer` — tested; a hover-enabled MouseArea on top blocks hover from reaching widget-internal MouseAreas, killing tooltips (`WidgetButton` `onEntered → bar.showTooltip`), `containsMouse` styling, and indicator hover-reveal. Presumably why it was left off.
The slot already has `HoverHandler { id: moduleHover }` (Bar.qml:1577, currently only feeding `slot.hovered`). HoverHandlers observe hover without blocking items below, and `moduleHover.point.position` is live and slot-local — the exact coordinate space `moduleClickTargetAt` expects. Replace line 1667 with:
```qml
cursorShape: root.moduleClickTargetAt(slot,
moduleHover.point.position.x, moduleHover.point.position.y)
? Qt.PointingHandCursor : undefined
```
The `undefined` branch resets the cursor property (`unsetCursor`), so `modulePointer` stops claiming the cursor when not over a click target — this both defuses the startup latch and un-shadows widgets that set their own cursor internally. Verified offscreen (Qt 6.11.2): hand on first hover with no click, arrow over padding, hover still reaches inner MouseAreas (tooltips intact), click/drag logic unaffected (`onPositionChanged` already guards on `mouse.buttons`). Cost is an event-driven binding evaluation per hover move — no polling, no animation.
### System
- Omarchy 4.0.1-1
- Qt 6.11.2 · quickshell 0.3.1 · Hyprland 0.56.2
- Dell Latitude 5420 (Intel TigerLake, Iris Xe), 1920×1080 @ 1.5 scale
### Steps to reproduce
1. Fresh login (or `omarchy restart shell`); do not click anything in the bar.
2. Hover any clickable bar widget (clock, workspaces, etc.) → cursor stays an arrow.
3. Click once anywhere in that widget's slot → hand cursor appears and persists for that slot, including over its padding.
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 10:02 UTC