Skip to content

Quattro#6231

Draft
dhh wants to merge 1168 commits into
masterfrom
quattro
Draft

Quattro#6231
dhh wants to merge 1168 commits into
masterfrom
quattro

Conversation

@dhh

@dhh dhh commented Jul 17, 2026

Copy link
Copy Markdown
Member

Quattro Alpha

Omarchy 4 aka Quattro is the biggest release since the project started. The entire desktop shell has been reimagined in Quickshell: the bar, launcher, menus, notifications, on-screen displays, control panels, lock screen, and polkit agent now all live inside a single long-running shell process with a plugin architecture. That means Waybar, Walker, Mako, SwayOSD, hyprlock, hypridle, swaybg, and polkit-gnome are all gone, replaced by one coherent, fully-themed, IPC-scriptable shell.

You can upgrade an existing Omarchy installation to Quattro with the following command:

curl -fsSL https://omarchy.org/upgrade-to-quattro-dev | bash

This will put you on the alpha development version. So not something that's recommended for production systems. Ensure you have a good backup first!

Headline Features

  • Reimagine the entire desktop shell in Quickshell.
  • Move Omarchy internals from git to system packages.
  • Offer dual-boot installation when free space is available.
  • Shrink both the ISO (-1.2GB!) and memory footprint.
  • Convert all Hyprland configs to lua for full 0.55+ compatibility.
  • Expand theme coloring from base 8 to 24.
  • Use networkmanager for new network panel for greater compatibility.
  • Add nested search to Omarchy menu.
  • Add menu bar repositioning (top/bottom/left/right) and transparency.
  • Add menu bar panels for Tailscale + Dropbox.
  • Add weather panel with configurable location.
  • Add multiple users on a single installation.
  • Add Omawrite and Omacut as default applications.
  • Add Solitude and Last Horizon as new themes.
  • Add window position saving per workspace for quick layout restoring.
  • Add much-improve clamshell operations for laptops used with external monitors.

The Shell

  • Rewrite the entire desktop shell in Quickshell — bar, launcher, menus, notifications, OSDs, panels, lock screen, and polkit agent as plugins in one process by @dhh and @ryanrhughes
  • Add a new modular bar with interactive widgets: workspaces, active window, clock (click for ISO week format), weather, media (MPRIS), system tray, battery, keyboard layout, microphone, update indicator, and manual-state indicators (DND, night light, stay awake, screen recording, dictation, reminders)
  • Move the bar by dragging it to any screen edge — a ghost slab previews the target edge while you drag — and double-click empty bar space to toggle transparency (SUPER + SHIFT + CTRL + arrows works too)
  • Add a bar plugin system: third-party widgets and even whole replacement bars installed straight from git with omarchy plugin add <git-url> (landing disabled for code review first) by @ryanrhughes
  • Add a native launcher with fuzzy/acronym matching, live app icon indexing, and hidden-entry management (SUPER + SPACE)
  • Add a native notification daemon with popups, a history center with pending/past tabs (SUPER + SHIFT + ALT + ,), do-not-disturb, deduping, and replay of recent history after restarts
  • Add a native clipboard manager with image previews and sensitive-content exclusion (SUPER + CTRL + V)
  • Add a native emoji picker (SUPER + CTRL + E) and native volume/brightness/media OSDs
  • Add control panels for Audio (SUPER + CTRL + A), Bluetooth (SUPER + CTRL + B), Network (SUPER + CTRL + W), Display (SUPER + CTRL + D), and Power (SUPER + CTRL + P)
  • Add optional service widgets with full panels for Tailscale (connection control, exit-node picker with Mullvad nodes grouped by country) and Dropbox (login, storage, recent files) by @ryanrhughes and @dhh
  • Add a model-usage bar widget showing Claude Code/Codex usage stats, optionally synced across machines by @ryanrhughes
  • Add a Google Meet picture-in-picture widget by @ryanrhughes
  • Replace hyprlock with shell-powered password and fingerprint PAM flows.
  • Move the Omarchy menu into the shell as a filterable, nested command palette defined in JSONC (extensible via ~/.config/omarchy/extensions/omarchy-menu.jsonc)

Theming & Aesthetics

  • Add a visual theme switcher: a filterable carousel of live theme previews (SUPER + SHIFT + CTRL + SPACE)
  • Add a visual background switcher in the same style (SUPER + CTRL + SPACE)
  • Add Last Horizon and Solitude themes by @HANCORE-linux
  • Add a Pi theme based on the system theme by @ryanrhughes
  • Add a semantic theme color system with normalized color names by @bjarneo
  • Add integrated corner controls (rounded/sharp) applied across Hyprland, notifications, lock screen, and menus
  • Add themed Hyprland gradient borders in the new shell by @ryanrhughes
  • Add a generated VS Code theme extension by @ryanrhughes
  • Add Tab/Shift+Tab navigation in the theme and background switchers by @bjarneo

Apps & Defaults

  • Add Omawrite, a dead-simple Markdown writing app, as the default writing tool replacing Typora (SUPER + SHIFT + W)
  • Add Omacut, a dead-simple video length trimmer built on ffmpeg
  • Switch the default terminal to Foot
  • Add a yt-dlp-powered "Download Video" Chromium extension
  • Add Sunshine game streaming (with autostart toggle) and the Moonlight client
  • Add automounting of removable drives via udiskie by @ryanrhughes
  • Add mpv MPRIS support so media keys control mpv by @berenddeboer
  • Use dua for disk usage by @crmne and @dhh
  • Move Signal, Spotify, and 1Password to on-demand installs and remove Figma + GitHub from the defaults.
  • Switch to the lighter basic JetBrains Mono Nerd font

Capture

  • Add relatively sized preview to the live webcam overlay on screen recordings (and offer further tweaks via SUPER + ALT + [ / ].
  • Add full-screen capture with RETURN while the region picker is open.
  • Add optional rsync of screenshots to a remote host (handy for forwarding to remote AI runners) via rsw/lsw/dsw commands.
  • Handle rotated monitors in the recording region picker.
  • Trash imv deletions and add Ctrl+E to edit in Satty by @jondkinney

Controls

  • Convert the Hyprland configuration to Lua: bindings, monitors, and toggles are now expressive Lua (o.bind("SUPER + SHIFT + W", "Omawrite", { launch = "omawrite" })) by @ryanrhughes
  • Add save/restore of window widths per app and workspace on SUPER + ALT + HOME / SUPER + HOME
  • Add fine (±25px) and coarse (±300px) window resizing tiers by @zaborowskimichal and @dhh
  • Add alternative media next/previous bindings for keyboards with only a play button by @dhh
  • Add a tmux keybindings viewer (SUPER + ALT + K) and new-pane/split bindings for tmux, kitty, ghostty, and alacritty by @ryanrhughes, @vtmx, @heymaikol, and @dhh
  • Add laptop clamshell handling with idempotent scale recovery, internal-display toggle, and display mirroring by @dhh

Networking/Connections

  • Add ping, live up/down stats, speed test, and DNS provider selection to the network panel by @dhh
  • Add per-device Bluetooth pairing, connection state, and forget/disconnect flows by @dhh
  • Add audio output/source switching that preserves playback, with recovery when audio services get stuck by @dhh
  • Switch Wi-Fi management to NetworkManager, replacing iwd/impala/bluetui/wiremix with the shell panels by @dhh

System & Upgrade

  • Re-architect Omarchy into proper Arch packages with system files shipped via /etc, so updates flow through pacman by @ryanrhughes
  • Add an ALPM guard that routes system updates through omarchy update (bypassable via OMARCHY_ALLOW_DIRECT_PACMAN=1) by @ryanrhughes
  • Switch privilege escalation to pkexec/polkit with a themed prompt that shows exactly what's being authorized by @dhh
  • Switch lazy-loaded tools (Claude Code, GitHub CLI) from npm to mise, and add a 5-day lag on new npm package installs to dodge zero-day supply-chain exploits (but offer mup alias to get instant updates) by @dhh
  • Add pre-refresh-pacman.d hooks for custom repository support by @tyvsmith
  • Persist Bluetooth power state across reboots by @heymaikol
  • Enable Docker multi-arch builds by default by @axelfontaine
  • Add weather locations that can be pinned to a chosen place instead of following IP geolocation by @dhh
  • Add SSHD setup and removal under Setup/Remove > Security by @dhh
  • Remember explicit power profile choices per power source (AC/battery) across reboots by @dhh
  • Pin Chromium-based browsers to the gnome-libsecret password store, so backend autodetection can't silently log you out of everything by @nt1998

Fixes

  • Fix fontconfig monospace binding overriding app-specific fonts by @Ninso112
  • Fix power profile race on plug/unplug events by @aikazu
  • Fix brightness indicator glitches from hardware key auto-repeat by @mateuszkowalczyk
  • Fix brightness OSD width jitter across percentages by @Pegorim
  • Fix transparent-bar flicker and systray action handling by @kevinmcconnell
  • Fix phantom display scaling by reading the configured scale in clamshell recovery
  • Fix notification expire timeouts being treated as seconds instead of milliseconds
  • Fix new windows — including browser windows and portal file dialogs — opening on the wrong workspace by @scottjones and @dhh
  • Fix the LUKS passphrase prompt ignoring the configured keyboard layout by bundling vconsole.conf in the initramfs (Latin layouts) by @Zeus-Deus
  • Prevent empty disk encryption passwords in the installer by @heymaikol
  • Fix power-profile udev rule wakeup failures from a fixed unit name by @DiegoMirner
  • Prevent the migration notifier from rate-limiting itself into silence by @Pegorim
  • Align snapshot pruning with Snapper's retention (off-by-one) by @Pegorim
  • Wake the internal display only when actually leaving clamshell by @monorkin
  • Force software cursors on nouveau by @stephentaylor-com
  • Install sof-firmware on all Intel SOF audio platforms so more laptops get working sound out of the box
  • Fix monitor scale-down getting stuck at 3x due to floating point drift
  • Keep software-composited cursors out of screenshots
  • Fix new terminals not opening in the current directory on Kitty
  • Fix fip and friends misparsing under zsh by @pkwagner
  • Clear the launcher/menu filter with CTRL + BACKSPACE by @RushiChaganti
  • Only bind F9 to Voxtype when it's installed by @r3quie

Feature presentations

The theme switcher

Switching themes is now a more visual affair: a filterable carousel of live previews for every installed theme, opened with SUPER + SHIFT + CTRL + SPACE or via Style > Theme. You can see the new bar riding on top too.

theme-switcher

The background switcher

Backgrounds get the same treatment on SUPER + CTRL + SPACE: flip through the current theme's backgrounds (plus any you've added) and see exactly what you're picking.

bg-switcher

The launcher

Walker has been replaced by a native launcher with fuzzy and acronym matching, live icon indexing (freshly-installed apps show up with their icons immediately), and the ability to hide entries you never use. Still on SUPER + SPACE.

launcher

The Omarchy menu

The menu is now a native, filterable command palette living inside the shell. Same SUPER + ALT + SPACE muscle memory, instant response, and extensible through a JSONC file if you want to add your own entries.

menu

Control panels

The bar widgets now open real control panels. Audio (SUPER + CTRL + A) has output/input device switching and volume control:

audio-panel

Network (SUPER + CTRL + W) shows live throughput, ping, packet loss, a one-click speed test, DNS provider selection, and nearby networks:

network-panel

And weather now has a proper forecast panel, which can be pinned to a chosen location instead of following your IP around:

weather-panel

A bar you can grab

There's no settings panel for the bar — you just grab it. Click and hold any empty stretch of bar and drag it toward a screen edge, and a ghost slab previews where it will dock. Drop it on the left or right and it turns into a vertical bar. Double-click empty bar space to toggle transparency. Widgets are added, removed, and rearranged with omarchy bar plugin, and third-party widgets install straight from git.

bar-left

Privilege escalation with context

Omarchy now uses pkexec/polkit for privileged operations, with a themed prompt that tells you exactly what command you're authorizing before you type your password.

polkit

Omawrite

Typora is out, and Omawrite is in. A dead-simple Markdown writing app that opens in a blink, autosaves as you type, and stays out of the way. Bound to SUPER + SHIFT + W. Free software.

omawrite

Omacut

A dead-simple video trimmer to go with it. Drop in a clip — like the screen recordings Omarchy takes — drag the handles on the filmstrip, and export the cut with ffmpeg doing the heavy lifting.

omacut

ryanrhughes and others added 30 commits June 12, 2026 02:16
And stick with the same gaps setup as all other themes
The launcher resolves each entry's icon through Quickshell.iconPath(),
which bottoms out in Qt's QIconLoader / QIcon::fromTheme. That engine
caches the theme's directory listing — and null results — for the life
of the process, and only re-scans when the icon theme or search paths
change. Nothing in Quickshell 0.3 exposes a way to invalidate it, and a
QML reload doesn't reset it either (QIconLoader is a QtGui process
global, not tied to the QML engine).

So when a user installs a new app while the shell is running, its
.desktop file is picked up live (DesktopEntries is file-watched and the
name appears immediately), but its icon resolves to the cached miss and
renders blank until the whole shell is restarted. That's a poor "I just
installed this" experience.

Fix it without a restart by keeping our own on-disk icon index as a
fallback. When themed lookup returns empty, iconSource() consults a
name->path map built by scanning the XDG icon dirs and /usr/share/
pixmaps (SVGs first, so scalable wins). The scan runs on startup and on
a debounced DesktopEntries change — the same signal that already makes
names appear — and swapping the iconIndex property re-evaluates every
iconSource() binding, so freshly installed icons show up live. Icons Qt
can already resolve are untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Run internal monitor toggle recovery before the sleep lock path and retry recovery after Hyprland monitor removal events. This gives dock/lid-close races time to settle before suspend or external-display reconnects leave the session without a safe internal display fallback.
It's using a staggering 250mb RAM
The May 17 picker performance change made activated thumbnail loads asynchronous, which undid the earlier anti-flicker fix and let carousel movement flash blank thumbnails. Keep lazy activation, but load activated thumbnails synchronously so theme/background picker navigation remains stable. Add regression coverage for the thumbnail loading mode.
dhh and others added 14 commits July 19, 2026 19:07
The colorset is the Monokai Pro Ristretto palette, so the generated
themes keep all the accent colors. Brightened muted to Monokai Pro's
actual comment color, since comments sit on that key.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The lock service arms a 5s blank timer whenever the screen locks, and
input at the lock screen re-arms it. Closing the lid sprays pointer
noise over the lock surface, so the timer was routinely armed right
before suspend, froze mid-countdown, and fired moments after resume --
blanking the freshly woken unlock screen under the user.

Guard the timer with a wall-clock check: if far more time elapsed than
the interval, the countdown slept through a suspend, so take a fresh
run-up instead of blanking. This also blanks the lock screen 5s after
an untouched resume.

Two accomplices made the flash worse and hid the real bug:

- The clamshell watcher's 2s poll fired an unconditional global DPMS
  enable whenever no external monitor was active, relighting any blank
  within 2 seconds (lock-screen blanking never stuck on undocked
  laptops) and racing the resume modeset. Recovery now only wakes
  displays when it actually re-enables one.

- Every keystroke at the lock screen dispatched a redundant DPMS
  enable via omarchy-system-wake, forcing extra modesets in the
  fragile just-resumed DRM state. Brightness "on" now skips the
  dispatch when every active display is already lit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fixing to screenrecording instead screenrecord that works only when
using the alias
Adds shift:both_capslock alongside compose:caps so pressing both Shift
keys together toggles real Caps Lock. Caps Lock alone remains the
Compose key, and single-Shift behavior is unchanged. Provides an escape
hatch when Caps Lock gets stuck on (e.g. after an fcitx5 desync).

Closes #5981

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The tree is wholly package-owned, but files can land there unowned
(in-place extension work, script-written files), and pacman then aborts
the entire upgrade on the file conflict — as happened when copy-url's
service worker was renamed to background-2.js. The conflict check runs
before any hooks or scriptlets, so the package itself can't recover;
the update command has to allow the overwrite.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
omarchy-update-user-notify.path used PathExistsGlob= on the packaged
migrations directory. That directive is level-triggered: systemd re-checks
it every time the triggered unit deactivates and fires again while the glob
still matches. Since applied migrations stay on disk forever (state lives in
~/.local/state/omarchy/migrations), the glob always matches, so the oneshot
notifier re-triggered itself in a tight loop (~26-66 starts/sec) — burning
about a core and flooding the journal for the whole session.

The loop existed since the unit was introduced, but the default start-rate
limit killed it after 5 iterations, taking the .path unit down with
'unit-start-limit-hit'. That symptom was reported as #6174 and fixed
yesterday by setting StartLimitIntervalSec=0 — which removed the only brake
and turned the capped hiccup into an unbounded busy-loop.

Fix the actual cause instead:

* Drop PathExistsGlob= from the .path unit, keeping the edge-triggered
  PathModified= watch for updates that land mid-session.
* Revert the StartLimitIntervalSec=0 override; with the level trigger gone
  there is no self-re-fire to trip the limit, and the default limit is a
  useful backstop again.
* Preserve the once-per-login pending check the glob used to provide by
  giving the service its own WantedBy=graphical-session.target, enabled at
  first-run alongside the other user units.
* Add a migration that daemon-reloads, revives a rate-limit-killed .path,
  restarts the watcher, and enables the login-time notifier on existing
  installs.

Verified with transient path/service units: the old config runs the service
200 times in 3 seconds; the new config runs it zero times while idle and
exactly once when a new migration file lands.

Thanks to @HANCORE-linux for finding and diagnosing the problem.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The background plugin ran a 100ms Timer that spawned a readlink
subprocess ~10x/sec for the life of the shell, purely to notice
wallpaper changes. Wallpaper updates already arrive over IPC
(omarchy-theme-bg-set calls `background set`, omarchy-theme-set calls
`background themeTransition`), and the initial wallpaper is read once
in Component.onCompleted, so the poll was redundant.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The indicators widget broadcast a refresh every 2s, fanning out to four
status subprocesses (nightlight, idle, reminder, screen-recording), and
NightLight/StayAwake each ran an additional 5s poll. On an idle desktop
this was the dominant source of process churn (~33 of ~53 forks/sec in a
VM). The state-changing commands already push `omarchy.indicators
refresh` over IPC, so the polling was redundant.

Drop the 2s broadcast and the two 5s timers; indicators now refresh at
startup and on the IPC push. Also fix three callers that pushed to the
wrong target `Indicators` instead of `omarchy.indicators` (screen
recording, notification silencing, and the omarchy-shell help example) —
those pushes silently failed and only appeared to work because the poll
masked them.

Idle fork rate drops ~53/s to ~20/s.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The monitor panel polled `omarchy-monitor-state` every 5s (26 forks per
call) and the network panel polled `omarchy-network-status` every 3s,
both with `running: true` rather than gating like the sibling panels.

Monitor: gate the poll on `opened` (brightness/scale are only shown in
the open panel, which already refreshes on open) and drive the bar glyph
from Quickshell.screens instead of the polled display list, so monitor
count stays correct without polling.

Network: the bar pill needs live-ish state, so keep polling but at 10s
instead of 3s. (Deriving the pill from the native Networking service
would remove the poll entirely; left as a follow-up since it needs Wi-Fi
state testing.)

Idle fork rate drops ~20/s to ~14/s.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Each `bash -lc` starts a login shell that re-sources the profile
(mise activation, /etc/profile.d) on every invocation — ~16 forks per
call versus ~2 for `bash -c` — which taxes every menu/panel/launcher
action the shell shells out for. The session already exports PATH and
env to the shell, so omarchy commands resolve fine under `bash -c`.

Switch the internal/omarchy-owned spawns (theme+background switches,
brightness, monitor scaling, DNS, lock/fingerprint, keyboard-layout
probe, voxtype status, and the `:`/printf state-file writes) to
`bash -c`. Leave `bash -lc` on the sites that run user-configurable
commands (custom bar-widget exec, menu provider/guard scripts,
launcher scan commands, configurable idle/screensaver command), where
a user's command may rely on their login environment.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jheuing

jheuing commented Jul 20, 2026

Copy link
Copy Markdown

Great work!!!

SUPER + ALT + [ / ]

Can we have a different key to / as in german / swiss keyboards, this is available via shift. So it would be SUPER+ALT+SHIFT+7. Usually having / and \ are not working keyboard shortcuts and need manual fixing.

@jheuing

jheuing commented Jul 20, 2026

Copy link
Copy Markdown

BTW: I can suggest alternatives and provide an MR if we're open to this change incl. past shortcuts...

husamemadH and others added 14 commits July 20, 2026 07:41
The pill was populated by polling omarchy-network-status (previously
every 3s, then 10s). Derive kind/signalStrength directly from the
Quickshell.Networking service instead: wired-connected → ethernet
(preferred, matching the default-route device), else a connected Wi-Fi
network → wifi with its signal, else disconnected. The service's
properties are change-notified, so the pill updates on connect/
disconnect and signal changes with no polling and no subprocess.

Removes the last periodic poll from the bar; the label/frequency pill
fields were write-only and are dropped.

Verified live: pill tracks ethernet → disconnected → ethernet in real
time as the wired device goes down and up.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
omarchy-hyprland-monitor-watch ran poll_clamshell_state() every 2s for
the whole session, and each pass forks omarchy-hyprland-monitor-clamshell
plus its hyprctl/jq/monitor-* children. Clamshell (lid) handling can only
ever apply to a machine with a lid, so on desktops and VMs this was pure
churn — the single largest remaining source of idle process wakeups
(~3 forks/sec on an otherwise idle desktop).

Gate the poll behind a new omarchy-hw-laptop helper (lid button, or a
laptop DMI chassis type as a fallback). The event-driven socat watch on
Hyprland monitor add/remove is unchanged, so monitor hotplug still
reconciles everywhere; only the periodic lid poll is now laptop-only.

Verified on a desktop: steady-state omarchy-hyprland-* forks drop from
~3/sec to zero, socat watch still present.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The reconciliation poll (added in "Fix clamshell display recovery") is a
backstop for lid transitions the Hyprland switch binds can miss across
suspend/resume. But the internal panel is only ever disabled while the
laptop is docked — lid shut with an external monitor active — so the poll
has nothing to reconcile when undocked. Running it 24/7 on every laptop
wakes the CPU every 2s for no reason, which is exactly the case where
battery matters most.

Start the poll when an external monitor is present and stop it when the
last one goes away (driven by the socat monitor-add/remove watch), gated
on omarchy-hw-laptop. Undocked laptops and desktops now never poll; a
docked laptop keeps the 2s recovery poll. Switch the event reader from a
pipe to process substitution so it runs in the main shell and can manage
the poll's lifetime.

Desktop verified: no poll runs even with external monitors attached. The
docked-laptop start/stop path needs a check on real laptop hardware.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The media service ran a 500ms repeat timer calling syncPlayingOrder() for
the whole session — two CPU wakeups a second even with nothing playing.
syncPlayingOrder only depends on the set of MPRIS players and each
player's isPlaying state, both of which the Mpris service already signals.

Replace the timer with onPlayersChanged (players appearing/disappearing)
plus an Instantiator that connects isPlayingChanged for each live player,
and a Component.onCompleted for the initial sync.

Verified with a test MPRIS player: play/pause and player add/remove all
update the active player with no periodic timer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Guards the dock-gating in omarchy-hyprland-monitor-watch: the poll runs
only when omarchy-hw-laptop and an external monitor are both present, via
sync_poll_state, with the event loop fed by process substitution so it
can start/stop the poll. Behaviourally simulated (stubbed hw checks +
synthetic monitor events): the poll runs only while docked and stops on
undock; a desktop or undocked laptop never polls.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
system-config-printer ships /etc/xdg/autostart/print-applet.desktop, so
installing it for the printer GUI also starts a ~24 MiB Python tray applet
in every session whose only job is print-job notifications. Override it
with a Hidden=true entry in config/autostart (same mechanism already used
for fcitx5 and limine-snapper-notify), so the applet no longer autostarts.
Printing and the system-config-printer GUI are unaffected.

Verified: with the override in place, systemd's xdg-autostart generator no
longer produces app-print\x2dapplet@autostart.service.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
gum_env.lua is fed into the compositor environment via hl.env at login,
but that environment is captured once and is not refreshed on a theme
switch. Terminals launched through uwsm-app inherit the caller's
environment (scopes don't read systemctl --user set-environment), so a
floating terminal would show the login-time theme's gum colors.

Extract the export logic into a sourced omarchy-restart-gum helper and
source it from the presentation terminal launcher so gum widgets match
the active theme.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
graphical.target was gated on network-online.target: cups-browsed orders
itself After=network-online.target and sits in multi-user.target, so the
session waited for NetworkManager-wait-online (DHCP/Wi-Fi association)
before coming up. On the bench VM that was ~140ms, but it's the classic
multi-second boot stall on real Wi-Fi.

Mask NetworkManager-wait-online.service so network-online.target is
reached immediately and nothing in the boot waits for connectivity;
NetworkManager still comes up and cups-browsed browses once the link is
live. Mirrors the existing systemd-networkd-wait-online mask. Enabled at
install (enable-services.sh) and masked on existing installs via
migration.

Verified on a fresh boot: the graphical.target critical chain no longer
passes through network-online.target / NetworkManager-wait-online.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Copy URL shortcut repair checked the outer script's yes variable,
which never reached the user-transition heredoc's bash process, so the
upgrade died with "yes: unbound variable" under set -u whenever a
browser was running with the old extension id in its Preferences.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The user-transition script is fed to bash on stdin, so the browser-close
gum confirm read the script itself: it auto-declined and swallowed the
remaining script text, leaving bash to fail on a mid-construct syntax
error. The outer confirm and reboot prompts had the same exposure when
the script runs via curl | bash. Read all three from /dev/tty.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Extract run_as_user_omarchy and run_as_user_wayland_session helpers to
  replace ten hand-rolled run_as_user env blocks
- Declare the retired user-unit list once instead of three times
- Use git ls-files --others to find user-added theme backgrounds instead
  of diffing against the tracked list by hand
- Stop rewriting the SDDM 10-theme/10-wayland confs the omarchy package
  already installs, and drop the duplicate [Theme] section from
  99-omarchy-login.conf
- Drop the legacy-path rewrite in the theme hyprland.conf shim; the user
  transition already rewrote those references
- Remove dead code: the unreachable channel re-validation, the declare -F
  guard in cleanup_on_exit, and the unset block at the end of the
  user-transition script

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Suppression was enabled only after cleanup_legacy_user_paths had already
moved ~/.local/share/omarchy aside, so the live session could auto-reload
during the swap window and pop "source= globbing error: found no match"
for every legacy hyprland.conf source line. Enable suppression as the
first step of the upgrade sequence instead; the EXIT trap still restores
it if the upgrade dies early.

Co-Authored-By: Claude Fable 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.