Proof Portal

Project overview

Omarchy

ProbeLabs65 findings · 95 requirements

A 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.

Inbox
ReportR-1850GitHub issuePublicDecided· Out of scope

Screensaver opens as a small floating window and self-terminates after 1s when a bar panel is open

Reported by echelonzero · filed Aug 15, 2026 · open at source

Decided: Out of scope — decided by agents · verified 4 days ago.

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

Screensaver opens as a small floating window and self-terminates after 1s when a bar panel is openrevision 1 · captured 2026-09-28 21:29 UTC via poll

Screensaver opens as a small floating window and self-terminates after 1s when a bar panel is open

Summary

When any bar widget panel (e.g. the power/battery dropdown) is open at the moment the idle
timer fires, the screensaver misbehaves in two ways at once:

  1. It does not go fullscreen — it appears as a small floating terminal window in the

middle of the screen, at foot's default 700x500.
2. It kills itself after ~1.05 seconds, without any user input.

The visible result is a small box that pops up, animates briefly, and disappears on its own.
The idle service logs this as screensaver-dismissed and cancels the pending lock, so **the
session also fails to lock** on that cycle.

Both symptoms trace to the panel holding layer-shell keyboard focus.

Environment

Omarchy4.0.0-1
Hyprlandv0.56.2
Quickshell0.3.0 (28771c7c, AUR quickshell-git)
foot1.27.0
ttfx0.3.1
Kernel6.19.8-arch1-3-surface
CPUIntel i7-1185G7 (Tiger Lake)
GPUIntel Iris Xe (TigerLake-LP GT2)
Displaysingle eDP-1, 2880x1920, scale = 2
Terminalfoot (xdg-terminal-exec --print-id → foot.desktop)

idle.screensaver = 150, idle.lock = 300 in ~/.config/omarchy/shell.json.

Steps to reproduce

Deterministic, no waiting for the idle timer:

# 1. Open any bar panel built on KeyboardPanel
omarchy-shell omarchy.power open

# 2. Launch the screensaver the same way the idle service does
omarchy-launch-screensaver force

Result: a small floating terminal appears centered, runs the ttfx animation, and exits by
itself after about one second.

Control — the identical command with the panel closed produces a correct fullscreen
screensaver that persists:

omarchy-shell omarchy.power close
omarchy-launch-screensaver force

In normal use this happens whenever you leave the battery/power dropdown open and walk away.

Expected vs actual

Expected: the screensaver covers the screen and stays up until real user input, then the
lock fires at idle.lock.

Actual: a small floating box appears for ~1s and self-terminates. The idle service reads
the window closing as a user dismissal, cancels the cycle, and the machine never locks.

Evidence

Window state sampled every 100ms via hyprctl clients -j, same command, only the panel state
differs:

panel closed (control)panel open
fullscreen2`0`
size[1440, 960] (full screen)`[700, 500]` (foot default)
floatingtruetrue
lifetimepersisted past 2.6s1.08s, exited on its own

Focus sampled every 50ms across a naturally-occurring failure (window opened 22:40:34.937):

34.944 NOTFOCUS  class=foot   <- 7ms after map; screensaver never got focus
...    (167/167 samples NOTFOCUS class=foot)
35.982 idle-cycle-cancel: screensaver-dismissed

Lifetime 34.937 → 35.982 = 1.045s.

Across five separate naturally-occurring failures, window-open → dismissal was
1.046, 1.044, 1.228, 1.235, 1.235s — each one exactly 1.000s (the read -n1 -t 1
timeout) plus a short wait_for_terminal_resize prefix. No human input was involved.

Root cause

Bar panels are built on KeyboardPanel, which takes layer-shell keyboard focus while open
(shell/Ui/KeyboardPanel.qml:98; the power panel instantiates it at
shell/plugins/panels/power/Panel.qml:292):

WlrLayershell.keyboardFocus: open
  ? (focusPrimed ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.Exclusive)
  : WlrKeyboardFocus.None

That single condition breaks the screensaver twice.

1. The fullscreen window rule never applies

With the panel holding focus, the newly mapped screensaver window does not become the active
toplevel, so fullscreen = true (default/hypr/apps/system.lua:35) does not take effect. The
adjacent float = true (line 36) does, leaving a floating window at foot's default 700x500 —
the small centered box.

2. The watchdog mistakes "never had focus" for "user dismissed me"

bin/omarchy-screensaver:5:

screensaver_in_focus() {
  hyprctl activewindow -j | jq -e '.class == "org.omarchy.screensaver"' >/dev/null 2>&1
}

hyprctl activewindow only reports toplevel windows — layer surfaces are invisible to it.
With the panel focused it returns the last focused toplevel (here foot), so the check returns
false even though nothing the user did caused it.

At the first tick of the watch loop (bin/omarchy-screensaver:44):

if read -n1 -t 1 || ! screensaver_in_focus; then
  exit_screensaver
fi

read times out at 1.000s, screensaver_in_focus is false, and the screensaver pkills
itself (bin/omarchy-screensaver:12). The idle service then observes closewindow, treats it
as screensaver-dismissed, and cancels the pending lock.

The check has no way to distinguish lost focus from never acquired focus, and no awareness
of layer-shell focus.

Suggested fixes

Any one of these addresses it; the first two are the smallest:

  • Close open bar panels before launching the screensaver, or skip the launch while a

keyboard-focus panel is open (the idle service already shells out, so this is one more call).
- Don't run the focus check until the screensaver has been focused at least once. Latch a
"was focused" flag and only treat focus loss as dismissal after that, which also removes the
fixed 1s window where a slow-mapping window can be killed.
- Make the focus check layer-aware, e.g. treat "no active toplevel / a layer surface holds
focus" as not-a-dismissal rather than as a dismissal.
- Consider making the screensaver a layer-shell overlay rather than a toplevel terminal window,
which sidesteps both the fullscreen-rule race and the focus check entirely.

Additional note

exit_screensaver uses pkill -f '[o]rg.omarchy.screensaver' (bin/omarchy-screensaver:12).
The [o] guard only protects against matching the pgrep/pkill process itself — it still
matches any process whose command line contains that string. Scripts or tooling that mention
the class by name (including diagnostics for this very bug) get killed as collateral. Matching
on PID or window address would be safer.

View raw text
# Screensaver opens as a small floating window and self-terminates after 1s when a bar panel is open

## Summary

When any bar widget panel (e.g. the power/battery dropdown) is open at the moment the idle
timer fires, the screensaver misbehaves in two ways at once:

1. It does **not** go fullscreen — it appears as a small floating terminal window in the
   middle of the screen, at foot's default 700x500.
2. It **kills itself after ~1.05 seconds**, without any user input.

The visible result is a small box that pops up, animates briefly, and disappears on its own.
The idle service logs this as `screensaver-dismissed` and cancels the pending lock, so **the
session also fails to lock** on that cycle.

Both symptoms trace to the panel holding layer-shell keyboard focus.

## Environment

| | |
|---|---|
| Omarchy | 4.0.0-1 |
| Hyprland | v0.56.2 |
| Quickshell | 0.3.0 (`28771c7c`, AUR `quickshell-git`) |
| foot | 1.27.0 |
| ttfx | 0.3.1 |
| Kernel | 6.19.8-arch1-3-surface |
| CPU | Intel i7-1185G7 (Tiger Lake) |
| GPU | Intel Iris Xe (TigerLake-LP GT2) |
| Display | single eDP-1, 2880x1920, `scale = 2` |
| Terminal | foot (`xdg-terminal-exec --print-id` → `foot.desktop`) |

`idle.screensaver = 150`, `idle.lock = 300` in `~/.config/omarchy/shell.json`.

## Steps to reproduce

Deterministic, no waiting for the idle timer:

```bash
# 1. Open any bar panel built on KeyboardPanel
omarchy-shell omarchy.power open

# 2. Launch the screensaver the same way the idle service does
omarchy-launch-screensaver force
```

**Result:** a small floating terminal appears centered, runs the ttfx animation, and exits by
itself after about one second.

**Control** — the identical command with the panel closed produces a correct fullscreen
screensaver that persists:

```bash
omarchy-shell omarchy.power close
omarchy-launch-screensaver force
```

In normal use this happens whenever you leave the battery/power dropdown open and walk away.

## Expected vs actual

**Expected:** the screensaver covers the screen and stays up until real user input, then the
lock fires at `idle.lock`.

**Actual:** a small floating box appears for ~1s and self-terminates. The idle service reads
the window closing as a user dismissal, cancels the cycle, and the machine never locks.

## Evidence

Window state sampled every 100ms via `hyprctl clients -j`, same command, only the panel state
differs:

| | panel closed (control) | panel open |
|---|---|---|
| `fullscreen` | `2` | **`0`** |
| `size` | `[1440, 960]` (full screen) | **`[700, 500]`** (foot default) |
| `floating` | `true` | `true` |
| lifetime | persisted past 2.6s | **1.08s**, exited on its own |

Focus sampled every 50ms across a naturally-occurring failure (window opened 22:40:34.937):

```
34.944 NOTFOCUS  class=foot   <- 7ms after map; screensaver never got focus
...    (167/167 samples NOTFOCUS class=foot)
35.982 idle-cycle-cancel: screensaver-dismissed
```

Lifetime 34.937 → 35.982 = **1.045s**.

Across five separate naturally-occurring failures, window-open → dismissal was
**1.046, 1.044, 1.228, 1.235, 1.235s** — each one exactly 1.000s (the `read -n1 -t 1`
timeout) plus a short `wait_for_terminal_resize` prefix. No human input was involved.

## Root cause

Bar panels are built on `KeyboardPanel`, which takes layer-shell keyboard focus while open
(`shell/Ui/KeyboardPanel.qml:98`; the power panel instantiates it at
`shell/plugins/panels/power/Panel.qml:292`):

```qml
WlrLayershell.keyboardFocus: open
  ? (focusPrimed ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.Exclusive)
  : WlrKeyboardFocus.None
```

That single condition breaks the screensaver twice.

### 1. The fullscreen window rule never applies

With the panel holding focus, the newly mapped screensaver window does not become the active
toplevel, so `fullscreen = true` (`default/hypr/apps/system.lua:35`) does not take effect. The
adjacent `float = true` (line 36) *does*, leaving a floating window at foot's default 700x500 —
the small centered box.

### 2. The watchdog mistakes "never had focus" for "user dismissed me"

`bin/omarchy-screensaver:5`:

```bash
screensaver_in_focus() {
  hyprctl activewindow -j | jq -e '.class == "org.omarchy.screensaver"' >/dev/null 2>&1
}
```

`hyprctl activewindow` only reports **toplevel** windows — layer surfaces are invisible to it.
With the panel focused it returns the last focused toplevel (here `foot`), so the check returns
false even though nothing the user did caused it.

At the first tick of the watch loop (`bin/omarchy-screensaver:44`):

```bash
if read -n1 -t 1 || ! screensaver_in_focus; then
  exit_screensaver
fi
```

`read` times out at 1.000s, `screensaver_in_focus` is false, and the screensaver `pkill`s
itself (`bin/omarchy-screensaver:12`). The idle service then observes `closewindow`, treats it
as `screensaver-dismissed`, and cancels the pending lock.

The check has no way to distinguish *lost* focus from *never acquired* focus, and no awareness
of layer-shell focus.

## Suggested fixes

Any one of these addresses it; the first two are the smallest:

- **Close open bar panels before launching the screensaver**, or skip the launch while a
  keyboard-focus panel is open (the idle service already shells out, so this is one more call).
- **Don't run the focus check until the screensaver has been focused at least once.** Latch a
  "was focused" flag and only treat focus loss as dismissal after that, which also removes the
  fixed 1s window where a slow-mapping window can be killed.
- **Make the focus check layer-aware**, e.g. treat "no active toplevel / a layer surface holds
  focus" as not-a-dismissal rather than as a dismissal.
- Consider making the screensaver a layer-shell overlay rather than a toplevel terminal window,
  which sidesteps both the fullscreen-rule race and the focus check entirely.

## Additional note

`exit_screensaver` uses `pkill -f '[o]rg.omarchy.screensaver'` (`bin/omarchy-screensaver:12`).
The `[o]` guard only protects against matching the `pgrep`/`pkill` process itself — it still
matches *any* process whose command line contains that string. Scripts or tooling that mention
the class by name (including diagnostics for this very bug) get killed as collateral. Matching
on PID or window address would be safer.

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 02:26 UTC