Skip to content

Add a refresh-rate picker to the display panel - #10195

Open
kidskript3 wants to merge 2 commits into
omacom:quattrofrom
kidskript3:add-monitor-refresh-picker
Open

Add a refresh-rate picker to the display panel#10195
kidskript3 wants to merge 2 commits into
omacom:quattrofrom
kidskript3:add-monitor-refresh-picker

Conversation

@kidskript3

@kidskript3 kidskript3 commented Sep 4, 2026

Copy link
Copy Markdown

Builds on #10194 — that branch is the base, so the diff here is only the refresh work once #10194 lands.

Why

Low refresh rates are not only a smoothness preference. For people who get cyber sickness or simulator sickness, a panel running at 60Hz when the hardware can do 144 or 240 means nausea and headaches within minutes of use. It is the same mechanism that makes a VR headset or a shaky camera unpleasant, and it does not go away by getting used to it.

A monitor comes up at whatever rate it reports as preferred, and on plenty of high-refresh panels that is 60Hz. Raising it today means opening ~/.config/hypr/monitors.lua, knowing that mode takes a WIDTHxHEIGHT@RATE string, and knowing which rates the monitor actually offers. That is a barrier in front of exactly the people who most need the setting.

So this puts the rate one click away, next to the scale control that already lives there.

The panel with the new REFRESH row — this laptop's built-in display supports 240 Hz and was running at 60.

omarchy-display-panel-refresh

What it adds

A REFRESH section in the display panel, below SCALE and built the same way: the rates the focused monitor offers at its current resolution, highest first, with the active one marked. It appears only when there is more than one rate to choose from, so single-rate displays see no change. Keyboard navigation matches SCALE — h/l walks the row, Enter applies.

omarchy hyprland monitor refresh, a companion to omarchy-hyprland-monitor-scaling and shaped like it:

omarchy hyprland monitor refresh          # 144
omarchy hyprland monitor refresh --list   # 144 100 85 72
omarchy hyprland monitor refresh 100

The panel defers to the CLI the way setScale already defers to the scaling command, so applying and persisting live in one place.

Notes on the details

  • Rates are filtered by the current resolution. A 5120x1440 ultrawide also lists 3840x1080 and 1920x1080 modes; offering their rates would silently change resolution.
  • Rounded to whole numbers. Hyprland reports 143.979 where the mode string says 144; the spec sheet and the user both say 144.
  • The apply keeps the monitor in place. The resolution is not changing, so there is nothing for position = "auto" to re-derive and no reason to make the other displays jump.
  • Persistence does not take the config away from the user. An output that already has a rule of its own only gets its mode rewritten, so a hand-written position or transform survives. An output with no rule gets one appended that inherits omarchy_monitor_scale where the file still defines it — otherwise a later omarchy hyprland monitor scaling would stop reaching that output. Setting a second rate rewrites that rule instead of stacking another one, and commented example lines are left alone.
  • State plumbing. omarchy-monitor-state carries refreshRate and availableModes per display, so the panel needs no second hyprctl process. Filtering and rounding are pure functions in Model.js.

Tests

  • test/shell.d/monitor-refresh-test.sh (new, modelled on monitor-scaling-test.sh) — reporting, listing, refusing a rate the resolution has no mode for, applying in place, appending a rule, rewriting it instead of stacking, leaving commented examples alone, and preserving a user-written rule's other fields.
  • test/shell.d/monitor-test.shavailableRates and activeRate, including duplicate rates that round to the same number and a display with no mode list.
  • test/shell.d/monitor-state-test.sh — fixtures and expectations extended.
  • Full test/shell: the only failures are the ones that fail identically on an unmodified checkout on this host (bar-icon-geometry, config, snapper, unowned-system-paths, and runtime-smoke whenever two displays are attached).

Verified on hardware

Alienware m15 R7 with an external 5120x1440 ultrawide on DP-1 at scale 1.25, Hyprland 0.56.2:

before   DP-1 5120x1440@143.979 scale 1.25 at 0x0
set 100  DP-1 5120x1440@99.996  scale 1.25 at 0x0
set 144  DP-1 5120x1440@143.979 scale 1.25 at 0x0

Scale and position survive the change, hyprctl configerrors stays empty, and the persisted rule was rewritten rather than duplicated on the second call. In the panel the four pills (144 / 100 / 85 / 72) fit the section width without clipping, and the active one is marked.

Also

manual/33-monitors.md gains a short "Refresh rate" section, including the motion-sickness note — it is the part users are least likely to guess on their own.

🤖 Generated with Claude Code

kidskript3 and others added 2 commits September 4, 2026 17:40
The rows called `hyprctl keyword monitor <name>,disable`, which the
non-legacy Lua parser refuses ("keyword can't work with non-legacy
parsers. Use eval.") while hyprctl still exits 0, so nothing surfaced and
the display never toggled.

Switch the toggle to `hyprctl eval` and spell out `disabled = false` when
an output comes back; restating a mode alone returns ok and leaves an
already-disabled output off.

Coming back on also has to land where it was. Scale and position can only
be read dependably while an output is on, and "auto" for both re-places
the display and drops a scaled one to 1, so `omarchy-monitor-state` now
carries each display's scale and position and the panel remembers the last
values it saw while an output was on.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A monitor comes up at the rate it reports as preferred, which on plenty of
high-refresh panels is 60Hz. Raising it meant hand-editing monitors.lua and
knowing the mode syntax — a barrier for the people who need it most, since
low refresh rates make some viewers motion sick.

Add a REFRESH section below SCALE listing the rates the focused monitor
offers at its current resolution, and a companion CLI shaped like
omarchy-hyprland-monitor-scaling. The panel defers to the CLI the way it
already does for scaling, so the rate is applied and persisted in one place.

Persisting keeps the output's own rule if it has one, rewriting only its
mode; otherwise it appends a rule that inherits omarchy_monitor_scale, so
monitor scaling keeps reaching that output afterwards.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant