A machine without a GPU, like most VMs, renders through llvmpipe on the
CPU, where every animated frame and every translucent window costs. In a
VM, opening and closing a terminal took ~5s of CPU; a panel ~3.4s.
omarchy toggle animations (also under Toggle > Animations) places a Hyprland
flag that turns off animations, blur and shadows and makes windows opaque.
The shell follows Hyprland's animations:enabled, rereading it on every
config reload: its one-shot animations run for Style.duration(ms), which
is then 0, and its spinners, pulses and title marquee hold still. A new
install in a VM starts with the flag in place.
Measured in the ISO test VM (llvmpipe), CPU per interaction:
terminal open+close 5000ms -> 481ms, workspace switch 1670ms -> 409ms,
audio panel 3446ms -> 796ms, volume OSD 2324ms -> 584ms, menu 2028ms ->
1241ms.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Answer omarchy-shell calls over the shell's own socket
Every omarchy-shell call started a qs ipc client, ~45ms of startup for one
IPC call: a theme switch makes two, and every script-driven OSD, toggle
refresh and lock query paid it too.
The shell now serves a socket in XDG_RUNTIME_DIR, named from its config
path and Wayland display as qs ipc selects its instance, and omarchy-shell
tries it first through socat, which starts in ~5ms. First-party handlers
register as ShellIpc, an IpcHandler that qs ipc still reaches, and the
socket calls only the functions a handler declares with their exact
argument count, allowed by name so QObject methods such as destroy() stay
out of reach.
When the shell ran nothing it answers SKIP, and omarchy-shell asks qs ipc
for its exact answer, so errors, third-party plugins and an unreachable
socket behave as before. A call that may have run is never retried: a
timeout or a connection closed without an answer reports the shell as not
responding.
omarchy-shell shell ping takes ~13-18ms instead of ~61ms, and omarchy-osd
reaches the screen in ~36ms instead of ~77ms. Output and exit status match
the qs ipc path across 26 calls, errors and quiet mode included.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Only accept whole socket replies and retry only unmade connections
A reply cut off after its OK prefix passed for the whole answer, and an
empty reply with socat failing was retried through qs ipc although the
request might already have been delivered.
An answer now counts only once its record separator arrived. socat's own
errors join the reply, so only its connect error, a socket nothing
listens on, falls back to qs ipc beside an explicit SKIP; anything else
is reported as not responding rather than retried.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The menu, emoji picker, clipboard, OSD, reminder flow and Wi-Fi QR code
mapped a fresh surface on every open. Qt drew its first frames before
Hyprland sent the surface's fractional scale: the pixel ratio stepped
2, 1, then 1.6, so on a 1.6 display each overlay showed blurry for
~350ms before going sharp.
A new OverlayWindow keeps the surface. Hidden, it parks as a 1x1,
input-less layer below windows, off the overlay layer so it never
blocks direct scanout. Showing only resizes and raises it, so the scale
is already settled. Content stays hidden until the surface has grown,
so no 1x1 frame is stretched across the screen, and the window follows
the focused monitor each time it is shown. The image picker's own
fullscreen parking moves onto it too.
Each parked overlay keeps a Qt window alive: at rest the shell holds
~40 MiB more RSS and ~20 MiB more GPU memory.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Show OSD and sync touchpad steps when scrolling bar widgets
Scrolling the volume or brightness icon in the bar changed the value
directly without ever calling omarchy-osd, so only the keyboard media
keys showed the popup. On top of that, a touchpad's stream of many
small wheel events per finger-drag wasn't matched to a mouse's single
±120 notch per click, so touchpad scrolling felt uncoordinated and
uneven next to the keyboard/mouse behavior.
- shell/plugins/panels/audio/Panel.qml: accumulate raw wheel delta and
only apply a step once it crosses a full mouse-notch's worth, so
touchpad and mouse move the volume in identical 5% increments, and
ping the OSD each time a step actually lands.
- shell/plugins/panels/monitor/Panel.qml: same accumulator for
brightness, with a 5% floor so scrolling down can never blank the
screen.
- shell/plugins/osd/Osd.qml: animate the progress bar's width instead
of snapping, so successive steps glide smoothly.
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Fix bar wheel OSD behavior
* Normalize scaled wheel events
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: David Heinemeier Hansson <david@hey.com>
Adds named reboot and shutdown OSD icons, and gives the touchscreen
toggle a proper gesture-tap glyph instead of the restart arrow it
was accidentally using.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
OSD reimplemented clamp() inline when Util already has one.
PanelSlider's knob-scale binding read `mouseArea.containsMouse` directly
instead of going through a `_hot` like the other interactive controls
(TextField, NumberField, Dropdown). Mirror them so future style work
has a single property to override.
Themes now drive typography the same way they drive colors: one [font]
base-size in shell.toml is the rem root, and every Style.font.<token>
(caption, bodySmall, body, subtitle, title, heading, display,
displayLarge, iconSmall, icon, iconLarge) derives from it via a fixed
multiplier. Themes can also pin individual tokens for stylistic
emphasis. base-size is clamped 11..13 until row-height tokens exist.
Bar dimensions move to the same singleton: [bar] size-horizontal /
size-vertical replace the hardcoded 26/28 in Bar.qml, exposed as
Style.bar.sizeHorizontal / sizeVertical.
Style.qml also resolves the fontconfig 'monospace' alias via fc-match
and exposes Style.font.resolvedFamily so panels can display the
concrete family. Watches ~/.config/fontconfig/fonts.conf so it tracks
'omarchy font set <name>'.
The qs.Ui kit (PillButton, Dropdown, Toggle, TextField, etc.) and
every first-party plugin (bar widgets, settings, menu, clipboard,
emoji, polkit, notifications, osd, image-picker, dev-gallery) now
bind to Style.font.* instead of pixel literals. Only three deliberate
display-scale outliers remain: the notification empty-state glyph and
the weather flyout's hero temperature pair, all commented.
Background plugin's applyTheme IPC fast-path also pushes shell.toml to
Style so theme swaps update typography and bar size without waiting
for inotify debounce.
Dev gallery (omarchy dev ui-preview) now ships a Typography section
that renders the full scale and theme tokens live, and its summon
command is fixed (omarchy-shell-ipc -> omarchy-shell).