Conversation
| function isMullvadPeer(peer) { | ||
| var hostName = String((peer && peer.HostName) || "").toLowerCase() | ||
| var dnsName = cleanDnsName((peer && peer.DNSName) || "").toLowerCase() | ||
| return dnsName.indexOf(".mullvad.ts.net") !== -1 || hostName.indexOf(".mullvad.ts.net") !== -1 |
| function isMullvadPeer(peer) { | ||
| var hostName = String((peer && peer.HostName) || "").toLowerCase() | ||
| var dnsName = cleanDnsName((peer && peer.DNSName) || "").toLowerCase() | ||
| return dnsName.indexOf(".mullvad.ts.net") !== -1 || hostName.indexOf(".mullvad.ts.net") !== -1 |
| var country = sliceTableColumn(line, countryStart, cityStart) | ||
| var city = sliceTableColumn(line, cityStart, statusStart) | ||
| var status = sliceTableColumn(line, statusStart, -1) | ||
| if (host.indexOf(".mullvad.ts.net") === -1) continue |
|
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. |
|
BTW: I can suggest alternatives and provide an MR if we're open to this change incl. past shortcuts... |
|
I just YOLO'd my 3.8... Workin like a boss. Nothing but what was expecting and a few pleasant surprises. Much appreciation to all of ya'll who made this happen! |
|
Running Quattro as my daily driver (upgraded an existing install, large 4K display (LG 48GQ900-B 48” OLED) at scale 1). The unified text-size knob is a great idea, but it hard-links three surfaces that don't always want to move together, and there's no way to express "just the shell" for example. Concrete case: I wanted the shell components (bar, menus, notifications) larger. Moving the display-panel slider did that, but it also:
There's also a small legibility trap in the mapping: because of the 12px→9pt anchor, the number you pick is never the number that lands in your terminal — e.g. the slider stop labeled "16" writes 12pt into terminal configs. The three legs are already independently settable underneath ([font] base-size in ~/.config/omarchy/shell.toml, gsettings, terminal configs), so I got what I wanted manually. But that means the knob is unusable for anyone tuning per-surface, one touch of the slider re-links everything. Proposal: scope flags on omarchy-display-text-size, something like --shell, --gtk, --terminals, defaulting to all three so the one-knob behavior is unchanged. The panel slider keeps calling it with no flags. Happy to submit this as a follow-up PR if there's interest. |
Quattro (Omarchy 4) breaks every hook this repo has into Omarchy: the git checkout at ~/.local/share/omarchy becomes a pacman-owned symlink, Hyprland config converts from .conf to Lua, Waybar is replaced by a Quickshell shell configured through shell.json, and generated theme state moves from ~/.config/omarchy/current to ~/.local/state/omarchy/current. This patch rewrites the overlays quattro-native. The theme-set and update-perform script overrides shrink to two hooks (zellij retint on theme-set, rustup/cargo on post-update) because user themed templates, helix restarts, cwd-aware terminal launches, mise updates, and persistent workspaces 1-5 are now stock. The hypr .conf files become Lua unbind/rebind overrides, waybar becomes a shell.json carrying only the clock format and Berkeley Mono, and the theme symlinks plus alacritty/ghostty imports re-point at the new state dir. My themed/*.tpl files survive untouched since upstream kept legacy colorN aliases. Do NOT merge or apply this on a machine still running Omarchy 3.x; it deletes the .conf and waybar files the live session reads. Upgrade day: run omarchy-upgrade-to-quattro, reboot, merge this bookmark, then chezmoi apply (accepting the .chezmoiremove deletions), re-run omarchy-theme-set, and reload Hyprland. Quattro is still alpha, so re-verify the hook names and shell.json schema against upstream first. Tested: chezmoi execute-template renders input/monitors for every dpi/mousedpi branch and luac -p passes on all of them plus bindings.lua and looknfeel.lua; shell.json validates; chezmoi status shows the expected adds/deletes. NOT TESTED on a real Quattro install. The monitor-relative floating window size in looknfeel.lua needs checking against hl.window_rule serialization on a live system. Ref: basecamp/omarchy#6231 Assisted-by: Claude:claude-fable-5
Quattro (Omarchy 4) breaks every hook this repo has into Omarchy: the git checkout at ~/.local/share/omarchy becomes a pacman-owned symlink, Hyprland config converts from .conf to Lua, Waybar is replaced by a Quickshell shell, and generated theme state moves from ~/.config/omarchy/current to ~/.local/state/omarchy/current. This patch rewrites the overlays quattro-native. The theme-set and update-perform script overrides shrink to two hooks (zellij retint on theme-set, rustup/cargo on post-update) because user themed templates, helix restarts, cwd-aware terminal launches, mise updates, and persistent workspaces 1-5 are now stock. The hypr .conf files become Lua unbind/rebind overrides, and the theme symlinks plus alacritty/ghostty imports re-point at the new state dir. My themed/*.tpl files survive untouched since upstream kept legacy colorN aliases. The Quickshell bar carries no user config. shell.json's clock keys are gone (upstream's stock layout and ISO-week clock are fine), and its fontFamily key never fed the bar anyway: the bar binds font.family to the "monospace" alias, so Berkeley Mono now lives in ~/.config/fontconfig/fonts.conf, the file `omarchy font set` owns and the shell, Qt apps, and everything resolving "monospace" read. Berkeley Mono has no Nerd glyphs, so fonts.conf adds a Nerd Font to the monospace fallback to keep bar and TUI icons rendering; upstream needs no such entry because its monospace alias is itself a Nerd Font. Do NOT merge or apply this on a machine still running Omarchy 3.x; it deletes the .conf and waybar files the live session reads. Upgrade day: run the quattro upgrade, reboot, merge this bookmark, then chezmoi apply (accepting the .chezmoiremove deletions), re-run omarchy-theme-set, and reload Hyprland. Quattro is still alpha, so re-verify the hook names against upstream first. Tested: chezmoi execute-template plus luac -p pass on bindings.lua, looknfeel.lua, and input.lua/monitors.lua rendered across every mousedpi (high/mid/low) and dpi (retina/mid/low) branch. xmllint validates fonts.conf, and fc-match against the rendered fonts.conf resolves monospace to Berkeley Mono Variable and falls back to an installed Nerd Font (JetBrainsMono/Caskaydia) for glyphs Berkeley lacks. chezmoi status shows the expected fontconfig modify plus the hypr .conf->.lua swaps. NOT TESTED on a real Quattro install. The monitor-relative floating window size in looknfeel.lua still needs checking against hl.window_rule serialization on a live system. Ref: basecamp/omarchy#6231 Assisted-by: Claude:claude-opus-4.8
Quattro (Omarchy 4) breaks every hook this repo has into Omarchy: the git checkout at ~/.local/share/omarchy becomes a pacman-owned symlink, Hyprland config converts from .conf to Lua, Waybar is replaced by a Quickshell shell, and generated theme state moves from ~/.config/omarchy/current to ~/.local/state/omarchy/current. This patch rewrites the overlays quattro-native. The theme-set and update-perform script overrides shrink to two hooks (zellij retint on theme-set, rustup/cargo on post-update) because user themed templates, helix restarts, cwd-aware terminal launches, mise updates, and persistent workspaces 1-5 are now stock. The hypr .conf files become Lua unbind/rebind overrides, and the theme symlinks plus alacritty/ghostty imports re-point at the new state dir. My themed/*.tpl files survive untouched since upstream kept legacy colorN aliases. The Quickshell bar carries no user config. shell.json's clock keys are gone (upstream's stock layout and ISO-week clock are fine), and its fontFamily key never fed the bar anyway: the bar binds font.family to the "monospace" fontconfig alias. Berkeley Mono is installed out of band (it's paid, so unlike my other fonts it isn't committed here), and the alias is set with `omarchy font set "Berkeley Mono Variable"`, which rewrites ~/.config/fontconfig/fonts.conf from the current package default. I don't manage that file in chezmoi for the same reason I dropped shell.json: omarchy owns and rewrites it, so a committed copy would both fork an upstream file that still gains fixes (the recent Arabic Naskh fallback) and fight the next `omarchy font set`. Do NOT merge or apply this on a machine still running Omarchy 3.x; it deletes the .conf and waybar files the live session reads. Upgrade day: run the quattro upgrade, reboot, merge this bookmark, then chezmoi apply (accepting the .chezmoiremove deletions), re-run omarchy-theme-set, run `omarchy font set "Berkeley Mono Variable"` to point the monospace alias (and thus the bar) at Berkeley Mono, and reload Hyprland. Quattro is still alpha, so re-verify the hook names against upstream first. Tested: chezmoi execute-template plus luac -p pass on bindings.lua, looknfeel.lua, and input.lua/monitors.lua rendered across every mousedpi (high/mid/low) and dpi (retina/mid/low) branch. Confirmed against upstream Style.qml that the bar's font.family binds to the "monospace" alias (so shell.json's fontFamily was dead) and that `omarchy font set` is what writes fonts.conf. chezmoi status shows only the expected hypr .conf->.lua swaps. NOT TESTED on a real Quattro install. The monitor-relative floating window size in looknfeel.lua still needs checking against hl.window_rule serialization on a live system. Ref: basecamp/omarchy#6231 Assisted-by: Claude:claude-opus-4.8
Quattro (Omarchy 4) breaks every hook this repo has into Omarchy: the git checkout at ~/.local/share/omarchy becomes a pacman-owned symlink, Hyprland config converts from .conf to Lua, Waybar is replaced by a Quickshell shell, and generated theme state moves from ~/.config/omarchy/current to ~/.local/state/omarchy/current. This patch rewrites the overlays quattro-native. The theme-set and update-perform script overrides shrink to two hooks (zellij retint on theme-set, rustup/cargo on post-update) because user themed templates, helix restarts, cwd-aware terminal launches, mise updates, and persistent workspaces 1-5 are now stock. The hypr .conf files become Lua unbind/rebind overrides, and the theme symlinks plus alacritty/ghostty imports re-point at the new state dir. My themed/*.tpl files survive untouched since upstream kept legacy colorN aliases. The Quickshell bar carries no user config. shell.json's clock keys are gone (upstream's stock layout and ISO-week clock are fine), and its fontFamily key never fed the bar anyway: the bar binds font.family to the "monospace" fontconfig alias. Berkeley Mono is installed out of band (it's paid, so unlike my other fonts it isn't committed here), and the alias is set with `omarchy font set "Berkeley Mono Variable"`, which rewrites ~/.config/fontconfig/fonts.conf from the current package default. I don't manage that file in chezmoi for the same reason I dropped shell.json: omarchy owns and rewrites it, so a committed copy would both fork an upstream file that still gains fixes (the recent Arabic Naskh fallback) and fight the next `omarchy font set`. Do NOT merge or apply this on a machine still running Omarchy 3.x; it deletes the .conf and waybar files the live session reads. Upgrade day: run the quattro upgrade, reboot, merge this bookmark, then chezmoi apply (accepting the .chezmoiremove deletions), re-run omarchy-theme-set, run `omarchy font set "Berkeley Mono Variable"` to point the monospace alias (and thus the bar) at Berkeley Mono, and reload Hyprland. Quattro is still alpha, so re-verify the hook names against upstream first. Tested: chezmoi execute-template plus luac -p pass on bindings.lua, looknfeel.lua, and input.lua/monitors.lua rendered across every mousedpi (high/mid/low) and dpi (retina/mid/low) branch. Confirmed against upstream Style.qml that the bar's font.family binds to the "monospace" alias (so shell.json's fontFamily was dead) and that `omarchy font set` is what writes fonts.conf. chezmoi status shows only the expected hypr .conf->.lua swaps. NOT TESTED on a real Quattro install. The monitor-relative floating window size in looknfeel.lua still needs checking against hl.window_rule serialization on a live system. Ref: basecamp/omarchy#6231 Assisted-by: Claude:claude-opus-4.8
Quattro (Omarchy 4) breaks every hook this repo has into Omarchy: the git checkout at ~/.local/share/omarchy becomes a pacman-owned symlink, Hyprland config converts from .conf to Lua, Waybar is replaced by a Quickshell shell, and generated theme state moves from ~/.config/omarchy/current to ~/.local/state/omarchy/current. This patch rewrites the overlays quattro-native. The theme-set and update-perform script overrides shrink to two hooks (zellij retint on theme-set, rustup/cargo on post-update) because user themed templates, helix restarts, cwd-aware terminal launches, mise updates, and persistent workspaces 1-5 are now stock. The hypr .conf files become Lua unbind/rebind overrides, and the theme symlinks plus alacritty/ghostty imports re-point at the new state dir. My themed/*.tpl files survive untouched since upstream kept legacy colorN aliases. The Quickshell bar carries no user config. shell.json's clock keys are gone (upstream's stock layout and ISO-week clock are fine), and its fontFamily key never fed the bar anyway: the bar binds font.family to the "monospace" fontconfig alias. Berkeley Mono is installed out of band (it's paid, so unlike my other fonts it isn't committed here), and the alias is set with `omarchy font set "Berkeley Mono Variable"`, which rewrites ~/.config/fontconfig/fonts.conf from the current package default. I don't manage that file in chezmoi for the same reason I dropped shell.json: omarchy owns and rewrites it, so a committed copy would both fork an upstream file that still gains fixes (the recent Arabic Naskh fallback) and fight the next `omarchy font set`. Do NOT merge or apply this on a machine still running Omarchy 3.x; it deletes the .conf and waybar files the live session reads. Upgrade day: run the quattro upgrade, reboot, merge this bookmark, then chezmoi apply (accepting the .chezmoiremove deletions), re-run omarchy-theme-set, run `omarchy font set "Berkeley Mono Variable"` to point the monospace alias (and thus the bar) at Berkeley Mono, and reload Hyprland. Quattro is still alpha, so re-verify the hook names against upstream first. Tested: chezmoi execute-template plus luac -p pass on bindings.lua, looknfeel.lua, and input.lua/monitors.lua rendered across every mousedpi (high/mid/low) and dpi (retina/mid/low) branch. Confirmed against upstream Style.qml that the bar's font.family binds to the "monospace" alias (so shell.json's fontFamily was dead) and that `omarchy font set` is what writes fonts.conf. chezmoi status shows only the expected hypr .conf->.lua swaps. NOT TESTED on a real Quattro install. The monitor-relative floating window size in looknfeel.lua still needs checking against hl.window_rule serialization on a live system. Re-checked the overlay against upstream quattro at f4e8470c3a1b: the theme-set and post-update hook dirs, the themed template renderer's legacy colorN aliases, the `o.bind` dispatcher tables, `o.window`, and the floating-window tag all still behave as this patch assumes, and the state dir the symlinks point at is unchanged. The uwsm/default override survives too: quattro moved the file into the package, but /usr/share/uwsm/env.d/10-omarchy still sources ~/.config/uwsm/default, and the upgrade keeps hash-mismatched user copies active, so EDITOR stays helix. Worth knowing for upgrade day: the upgrade's always-copy list rewrites all four hypr .lua files with quattro skeletons, which is why chezmoi apply has to run after the upgrade rather than before. Ref: basecamp/omarchy#6231 Assisted-by: Claude:claude-opus-4.8 Assisted-by: Claude:claude-opus-5
Quattro (Omarchy 4) breaks every hook this repo has into Omarchy: the git checkout at ~/.local/share/omarchy becomes a pacman-owned symlink, Hyprland config converts from .conf to Lua, Waybar is replaced by a Quickshell shell, and generated theme state moves from ~/.config/omarchy/current to ~/.local/state/omarchy/current. This patch rewrites the overlays quattro-native. The theme-set and update-perform script overrides shrink to two hooks (zellij retint on theme-set, rustup/cargo on post-update) because user themed templates, helix restarts, cwd-aware terminal launches, mise updates, and persistent workspaces 1-5 are now stock. The hypr .conf files become Lua unbind/rebind overrides, and the theme symlinks plus alacritty/ghostty imports re-point at the new state dir. My themed/*.tpl files survive untouched since upstream kept legacy colorN aliases. The Quickshell bar carries no user config. shell.json's clock keys are gone (upstream's stock layout and ISO-week clock are fine), and its fontFamily key never fed the bar anyway: the bar binds font.family to the "monospace" fontconfig alias. Berkeley Mono is installed out of band (it's paid, so unlike my other fonts it isn't committed here), and the alias is set with `omarchy font set "Berkeley Mono Variable"`, which rewrites ~/.config/fontconfig/fonts.conf from the current package default. I don't manage that file in chezmoi for the same reason I dropped shell.json: omarchy owns and rewrites it, so a committed copy would both fork an upstream file that still gains fixes (the recent Arabic Naskh fallback) and fight the next `omarchy font set`. Do NOT merge or apply this on a machine still running Omarchy 3.x; it deletes the .conf and waybar files the live session reads. Upgrade day: run the quattro upgrade, reboot, merge this bookmark, then chezmoi apply (accepting the .chezmoiremove deletions), re-run omarchy-theme-set, run `omarchy font set "Berkeley Mono Variable"` to point the monospace alias (and thus the bar) at Berkeley Mono, and reload Hyprland. Quattro is still alpha, so re-verify the hook names against upstream first. Tested: chezmoi execute-template plus luac -p pass on bindings.lua, looknfeel.lua, and input.lua/monitors.lua rendered across every mousedpi (high/mid/low) and dpi (retina/mid/low) branch. Confirmed against upstream Style.qml that the bar's font.family binds to the "monospace" alias (so shell.json's fontFamily was dead) and that `omarchy font set` is what writes fonts.conf. chezmoi status shows only the expected hypr .conf->.lua swaps. NOT TESTED on a real Quattro install. The monitor-relative floating size in looknfeel.lua is now verified on Hyprland 0.56.0: a probe window took 1654x1016 on a 3008x1692 logical monitor, so monitor_w/monitor_h resolve against logical and not physical pixels, which is what makes 55%/60% right on a retina display. The percentage form (size 55% 60%) is not a substitute: hyprctl accepts it and then silently ignores it, leaving the app's own default. What remains unproven is only the Lua table to rule-string serialization, and upstream ships that same shape in webcam-overlay.lua. Re-checked the overlay against upstream quattro at f4e8470c3a1b: the theme-set and post-update hook dirs, the themed template renderer's legacy colorN aliases, the `o.bind` dispatcher tables, `o.window`, and the floating-window tag all still behave as this patch assumes, and the state dir the symlinks point at is unchanged. The uwsm/default override survives too: quattro moved the file into the package, but /usr/share/uwsm/env.d/10-omarchy still sources ~/.config/uwsm/default, and the upgrade keeps hash-mismatched user copies active, so EDITOR stays helix. Worth knowing for upgrade day: the upgrade's always-copy list rewrites all four hypr .lua files with quattro skeletons, which is why chezmoi apply has to run after the upgrade rather than before. Ref: basecamp/omarchy#6231 Assisted-by: Claude:claude-opus-4.8 Assisted-by: Claude:claude-opus-5
Quattro (Omarchy 4) breaks every hook this repo has into Omarchy: the git checkout at ~/.local/share/omarchy becomes a pacman-owned symlink, Hyprland config converts from .conf to Lua, Waybar is replaced by a Quickshell shell, and generated theme state moves from ~/.config/omarchy/current to ~/.local/state/omarchy/current. This patch rewrites the overlays quattro-native. The theme-set and update-perform script overrides shrink to two hooks (zellij retint on theme-set, rustup/cargo on post-update) because user themed templates, helix restarts, cwd-aware terminal launches, mise updates, and persistent workspaces 1-5 are now stock. The hypr .conf files become Lua unbind/rebind overrides, and the theme symlinks plus alacritty/ghostty imports re-point at the new state dir. My themed/*.tpl files survive untouched since upstream kept legacy colorN aliases. The Quickshell bar carries no user config. shell.json's clock keys are gone (upstream's stock layout and ISO-week clock are fine), and its fontFamily key never fed the bar anyway: the bar binds font.family to the "monospace" fontconfig alias. Berkeley Mono is installed out of band (it's paid, so unlike my other fonts it isn't committed here), and the alias is set with `omarchy font set "Berkeley Mono Variable"`, which rewrites ~/.config/fontconfig/fonts.conf from the current package default. I don't manage that file in chezmoi for the same reason I dropped shell.json: omarchy owns and rewrites it, so a committed copy would both fork an upstream file that still gains fixes (the recent Arabic Naskh fallback) and fight the next `omarchy font set`. Do NOT merge or apply this on a machine still running Omarchy 3.x; it deletes the .conf and waybar files the live session reads. Upgrade day: run the quattro upgrade, reboot, merge this bookmark, then chezmoi apply (accepting the .chezmoiremove deletions), re-run omarchy-theme-set, run `omarchy font set "Berkeley Mono Variable"` to point the monospace alias (and thus the bar) at Berkeley Mono, and reload Hyprland. Quattro is still alpha, so re-verify the hook names against upstream first. Tested: chezmoi execute-template plus luac -p pass on bindings.lua, looknfeel.lua, and input.lua/monitors.lua rendered across every mousedpi (high/mid/low) and dpi (retina/mid/low) branch. Confirmed against upstream Style.qml that the bar's font.family binds to the "monospace" alias (so shell.json's fontFamily was dead) and that `omarchy font set` is what writes fonts.conf. chezmoi status shows only the expected hypr .conf->.lua swaps. NOT TESTED on a real Quattro install. The monitor-relative floating size in looknfeel.lua is now verified on Hyprland 0.56.0: a probe window took 1654x1016 on a 3008x1692 logical monitor, so monitor_w/monitor_h resolve against logical and not physical pixels, which is what makes 55%/60% right on a retina display. The percentage form (size 55% 60%) is not a substitute: hyprctl accepts it and then silently ignores it, leaving the app's own default. What remains unproven is only the Lua table to rule-string serialization, and upstream ships that same shape in webcam-overlay.lua. Re-checked the overlay against upstream quattro at f4e8470c3a1b: the theme-set and post-update hook dirs, the themed template renderer's legacy colorN aliases, the `o.bind` dispatcher tables, `o.window`, and the floating-window tag all still behave as this patch assumes, and the state dir the symlinks point at is unchanged. The uwsm/default override survives too: quattro moved the file into the package, but /usr/share/uwsm/env.d/10-omarchy still sources ~/.config/uwsm/default, and the upgrade keeps hash-mismatched user copies active, so EDITOR stays helix. Worth knowing for upgrade day: the upgrade's always-copy list rewrites all four hypr .lua files with quattro skeletons, which is why chezmoi apply has to run after the upgrade rather than before. Ref: basecamp/omarchy#6231 Assisted-by: Claude:claude-opus-5
Every install row that leaves a durable artifact now carries a `when` that mirrors its remove counterpart, negated. Packages check `omarchy-pkg-present`, Ollama checks the command since the action picks between three packages, and the rest check whatever the installer actually leaves behind: Games/battlenet, the Xbox Cloud and Windows VM desktop files, the flatpak, the mise install dirs, ~/.rustup, ~/.opam, the composer laravel binary, the phx_new archive. Chromium Account now shows only when chromium-flags.conf exists and lacks the oauth client id. It was a visible no-op both before Chromium was installed and after the flags had been added. The pickers stay unguarded: Package, AUR, Web App, TUI, Style, Docker DB, and the RetroArch Game Launcher, which builds one launcher per game. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Stop stranding the Launching… OSD when a second app is launched
* Add Tailscale header on/off toggle * Address Tailscale toggle review feedback * Hide Tailscale tooltip while busy * Keep Tailscale labels clear of header toggle * Extract the switch from Toggle into a reusable ToggleSwitch Toggle rendered its own track and knob inline, so anything else wanting a switch had to copy the geometry. Pull it into Ui/ToggleSwitch.qml and let Toggle compose it, and give PanelHero a trailingControl slot so a hero can pin a control to its trailing edge without the caller doing the layout. The switch draws its cursor as a ring outside the track: themes give normal chrome a stronger border than hover-cursor, which is right for controls that are borderless at rest but would make a bordered track go fainter under the cursor. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Keep the panel cursor on the virtual header section clampCursor resets focusSection whenever it is not in visibleSections, but "header" is virtual and never appears there. Any refresh of the underlying model therefore threw the cursor off the hero toggle: muting republishes the PipeWire snapshot, and toggling the Bluetooth adapter empties and refills the device lists. moveCursor already special-cases "header"; clampCursor now does too. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Toggle panel heroes with a switch instead of the status icon The hero icon doubled as the on/off control, which was invisible as an affordance and made the icon carry two jobs at once. Give Tailscale, Dropbox, Bluetooth, Audio, and Network a ToggleSwitch on the trailing edge of the hero and leave the icon to report status. The switch is the header's only cursor target, so the keyboard reaches it the same way the mouse does. Dropping the icon's focus ring also drops heroRingPad, which lets each hero line up with the rows beneath it. Network's link detail moves inline after the name -- "Ethernet (2.5gbit)" -- since the pill crowded the switch. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Make the network hero switch honestly a Wi-Fi switch The switch reads and writes Networking.wifiEnabled, but its tooltip claimed to turn "network" on and off whenever Ethernet was the active connection. A click asserted nothing; a switch asserts state, so on a wired machine with the radio off it sat there reading "off" beside a perfectly live Ethernet connection. Say Wi-Fi, and only offer the switch when there is a radio to switch. headerActionCount follows the same condition so the keyboard cannot reach a control that is not there. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Stop the header cursor claiming an absent switch The switch hides when the thing it toggles is unavailable -- no Tailscale CLI, no Dropbox CLI, no Wi-Fi radio -- but "header" stayed reachable, so the cursor could sit on a target that never rendered. The old clickable icon was always on screen, so there was always something to highlight. "header" stays navigable and Enter still no-ops safely; the cursor just stops claiming a spot that is not there. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Wrap the gallery's switch caption The caption sat unbounded inside the switch row. The gallery has a 560px minimum width, horizontal scrolling off, and clipping on, so at that size the end of the line was simply unreachable. Move it below the row and wrap it, the way every other description in the gallery already does. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: David Heinemeier Hansson <david@hey.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sliders only ever accepted the left button. Audio wants right-click as a secondary action on the track, so emit rightClicked() for it and keep dragging left-button-only: press and release both ignore anything else, so a right-click can neither start a drag nor move the value. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The hero switch is the panel's on/off, so it now carries output and input together rather than output alone. It reads as on while anything is still audible, which keeps muting a single channel from flipping the master switch. Right-clicking a volume bar mutes just that channel -- output, input, or one app's stream -- matching what the `m` key already does for the focused row. Only channels that exist get a vote: a machine with no default source would otherwise report its input unmuted forever, leaving the switch able to mute but never to unmute. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Clipboard history is fed by two wl-paste --watch processes started once when the shell loads. When one dies, nothing notices: copying still works, the picker still opens, and the old entries are all still there, so history just silently stops recording until the next shell reload. Respawn them on exit instead. The one-shot timer both coalesces the case where both watchers die together and keeps a wl-paste that cannot start at all from spinning as fast as fork allows. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The shell starts before DHCP finishes, so Claude's first probe of the OAuth usage endpoint came back as a transport failure and pinned "Claude limits unavailable" for a full refresh interval. Opening the panel could not clear it either: the open path refreshed unforced and hit the same throttle it was trying to escape. A transport failure now arms a short retry that goes straight to the probe, since a retry answering to the throttle never gets off the ground. Any real answer disarms it — a server that replied, 429 included, is one to stop pestering. Probes are single-flight, a fresh token skips the throttle its predecessor set, and opening the panel asks for the wire without re-walking every transcript on disk. The module also earns its place in the bar now instead of sitting there dimmed with nothing to say: it collapses out entirely until a provider has actually recorded usage, here or on a synced machine. That made both presence probes redundant, so they are gone. Selection follows the provider rather than its slot, so one appearing while the panel is open no longer swaps out what you were reading. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The edge channel installs omarchy-dev, but omarchy-version only queried omarchy, so it exited 1 there. omarchy-snapshot runs under set -e, so the failed lookup aborted the whole update over a snapshot label. It only worked at all because omarchy-dev declares provides=(omarchy) from the installer repo. Builds without it fail, so check both packages here instead of relying on a declaration from another tree. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…der-corners Fix asymmetric rounded shell borders
Opening the cheatsheet outright put a menu in front of someone who had not asked for one, and it blocked first run until they dismissed it. Go back to a toast that opens the same menu when clicked. The body carries real newlines now. It was written with a literal \n, which the card renders as the two characters rather than a line break. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Previously, right-clicking the audio icon muted only the output. Whereas the switch at the top of the panel mutes all audio (inputs and outputs). Pairing the right-click to the switch seems a bit less confusing, and also matches the behaviour with other panels (e.g. Bluetooth, Tailscale, etc).
* Fix unclickable tray submenus by drilling down inside the popup Clicking a tray menu entry that has children was a silent no-op: the row called QsMenuEntry.display(), which renders a *platform* menu, and Quickshell refuses that unless the shell root sets `//@ pragma UseQApplication` -- shell.qml does not. The log shows "Cannot display PlatformMenuEntry as quickshell was not started in QApplication mode" and nothing opens. Apps whose whole menu is submenus, like radiotray-ng's station list, were unusable. Adding the pragma would be the wrong fix: it switches the entire shell from QGuiApplication to QApplication, dragging QtWidgets into the process and changing application-class behavior for the sake of one popup -- which would then render as an unstyled platform menu beside omarchy's own popup styling anyway. Instead, submenus drill down inside the existing popup. A child QsMenuEntry inherits QsMenuHandle, so it can feed a nested QsMenuOpener and render through the same row delegate. Each level keeps its own live opener on a stack -- a child entry is owned by its parent opener's model, so collapsing to a single reassigned opener would destroy the very entry being displayed. A back header row walks out one level; at the root the menu renders exactly as before, and items without a DBusMenu still use the platform fallback. * Destroy submenu openers deepest-first and reset before switching items resetTrayMenu() destroyed openers front-to-back and only cleared submenuStack afterward. A deeper opener's menu entry is owned by its parent's children model, so destroying the parent first could invalidate an entry a still-live child opener referenced. Clear the stack before tearing anything down, then destroy deepest-first so a child is always gone before the parent whose model owns its entry. openTrayMenu() reassigned activeTrayItem before calling resetTrayMenu(). trayMenuOpener.menu binds to activeTrayItem.menu, so that reassignment immediately swaps what the root opener's children expose -- invalidating entries any live submenu opener still referenced, before resetTrayMenu() got a chance to tear them down. Reset first, then switch items. Thanks @Copilot for catching both. * Defer submenu reset until the popup's fade-out actually finishes onTrayMenuOpenChanged reset the submenu stack the instant trayMenuOpen went false, but the popup stays visible for the whole 140ms opacity fade (PopupCard's own visible: open || card.opacity > 0) -- dismissing from a submenu flashed the root menu mid-fade, and could resize or reposition the fading popup if the two have different geometry. Moved the reset to trayMenuPopup's own onVisibleChanged, which only fires once the fade has genuinely completed. Switching to a different tray item is unaffected: openTrayMenu() already resets explicitly before assigning the new item, independent of whether the popup ever dips to invisible (rapid reopen mid-fade never does). Thanks @Copilot for catching this. * Ignore tray menu clicks for a beat after changing submenu level Changing level swaps the Repeater's model, which rebuilds the row delegates synchronously -- a fresh row lands under a cursor that hasn't moved. Submenu clicks used to be silent no-ops, which trained users to click them twice, so that second click now fires whatever entry took the spot. On radiotray-ng that means an accidental station switch. Gate row and back-header clicks for 250ms after each level change. A deliberate follow-up click is slower than that; a double-click is not. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Pin the submenu back header above the scrolling menu rows The back header lived inside the Flickable's Column, so in a submenu taller than the 420px cap -- exactly the long station list this drill-down exists for -- scrolling down pushed the only way back off screen, with no Escape or right-click alternative. Move it into a pinned Column above the Flickable and account for its height in the popup's contentHeight. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Reset the tray menu scroll offset when the drill-down is torn down Flickable keeps its contentY across a model swap whenever the new content is still tall enough to hold it. A menu dismissed while scrolled therefore reopened part-way down with its first entries off screen: reproducible on any tray app whose root menu outgrows the 420px cap, and now reachable on every app once a long submenu has been scrolled. Zero the offset in resetTrayMenu(), which runs both on teardown and before switching items. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Toni Nowak <t.nowak@ai-flow.no> Co-authored-by: David Heinemeier Hansson <david@hey.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Coding agents refuse to persist trust for $HOME, so the keybinding and menu launches -- which inherit the session's ~ cwd -- re-asked on every single session. ~/Work is already the work root Omarchy creates, and trust there sticks. Only applies when the cwd is exactly $HOME, so the inline alias still starts in whatever project directory it was run from. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(monitor): prevent mirror toggle deletion during recovery and fix UI state * Assert the external monitor helper counts mirrors as active The helper now asks `hyprctl monitors all -j`, so the test that pinned it to plain `monitors` failed. A mirrored external is absent from plain `monitors`, which reads as a disconnect and hands the mirror toggle to recovery. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Keep the mirror state line when nothing is mirrored Piping the first mirroring monitor into the branch fed jq's test() a null whenever no output mirrored, and jq aborts there rather than falling back to "". The panel reads this output by line, so the missing line shifted the focused monitor, the scale, and the display list up one, and left mirroring reading as on whenever the external display had focus. Select first and branch inside the pipeline, so the branch only ever sees a monitor and the empty case falls to "" as the lines around it do. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Cover the monitor panel state the shell reads by line Nothing exercised omarchy-monitor-state, so both the mirror direction it reported and the jq that reported it went unguarded. The panel reads the output by line index, where a helper dying mid-script costs a line and shifts every field below it into the wrong property without failing. Assert the line count alongside the fields, over extended, mirrored both directions, and clamshelled displays. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: David Heinemeier Hansson <david@hey.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
lspci reads PCI config space, and the kernel resumes a runtime-suspended device to serve that read. On a hybrid laptop the discrete GPU idles in D3cold, so the first lspci of a Hyprland config load spends over a second waking it — longer than the 1.5s budget Hyprland gives the whole load. The reload then fails at whichever line runs next, which is why the error pointed at default/hypr/apps/1password.lua rather than at nvidia.lua. Read the vendor, class, and device IDs from sysfs instead. Those are served from cached fields and never touch config space, so nothing wakes up. Classify by device ID while we're here: Turing is both the first generation with GSP firmware and the first at 0x1e00 or above, and Maxwell opens at 0x1340, one ID past the last Kepler part. Bounding the older detector at both ends keeps pre-Maxwell cards off the 580xx driver that cannot drive them, and picks up the Maxwell and Pascal parts the lspci name regex used to miss. omarchy-hw-nvidia was also checked in without its executable bit, which it needs now that nvidia.lua runs it. Fixes #6660 Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Looks cool, LGTM! 🚀 |
Herdr ships its own annotated keybindings menu, same as Tmux, but nothing in the menu pointed at it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The row list was capped at 60% of screen height so a card could never read as a page. On a laptop-height display that folds the starting menu one row early, hiding About behind the peek for no gain. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Every other pointer at the community lives in an error path or a doc, so there was no way to reach it from the menu. Prefer the Discord app when it is installed, and fall back to the invite in a browser when it is not. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Repair theme symlinks the state-move migration left dangling 1781043107.sh re-linked legacy theme symlinks whose targets were stored with a literal "~/.config/omarchy/current/..." string. The replacement used the same literal tilde, which the filesystem never expands inside a symlink target, so btop, Helix, and VS Code/Cursor lost their theme and the migration reported success anyway. Fix the source migration to relink through the already-defined $current_state_dir variable, and add a follow-up migration that repairs the links the applied version left dangling — matching the existing 1785002349.sh pattern, so it is idempotent and leaves custom links alone. Co-Authored-By: Claude <noreply@anthropic.com> * Only repair theme symlinks that could never have worked The repair matched any target containing omarchy/current, so a working link into a user's own dotfiles was rewritten to the state directory and their setup was lost. Claim a link only when its target starts with a literal "~/", which the filesystem never expands, and names this exact theme file: that is what 1781043107.sh wrote, and no working link can look like it. A dangling target is not enough on its own, since a dotfiles repo may just be unmounted. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Clean up every scratch directory the CLI suite creates Five of the eight mktemp directories were never registered with the exit trap, so each run left them behind in /tmp. Route them all through a helper that records them for cleanup. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Drop the theme symlink migration tests A migration runs once on each machine and is then inert, but a test for it sits in the suite forever. Now that the repair behaves correctly, keep the migration and let it go untested rather than grow the suite permanently. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: David Heinemeier Hansson <david@hey.com>
…#6716) * Accept either name for the lock authentication command omarchy-setup-lock was renamed to omarchy-apply-lock in 536fcd5, but the upgrade calls into whatever the channel just installed, and every released package still ships the old name. The rename only moves in lockstep for the ISO, which installs the runtime from the mirror it ships with; the upgrade has no such guarantee, so it aborted every run with "omarchy-apply-lock is unavailable" right before the point of no return. Prefer the new name and fall back to the old one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Leave the Omarchy 3 session alone until the reboot The upgrade tried to start Quickshell in the live session, and only stopped waybar/walker/elephant if that worked. Every branch of it could fail, so it needed a warning for each, and those warnings were the first thing users read at the end of an upgrade that had otherwise succeeded. The reboot is the cutover. Swapping the UI out underneath a running session buys nothing, so drop the attempt and both functions with it. The Omarchy 3 bar, launcher, and notifications keep working until the reboot, which is what happened anyway whenever the start failed. Also warn up front when the live Hyprland session cannot be reached, and drop the package_mode label that was set on both branches of the dev-package check and never read. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Shim the legacy Hyprland defaults from the backup, not from GitHub populate_legacy_hypr_defaults tried a sparse git clone of master, then a curl of the master tarball, and only if both failed the backup taken a few lines earlier. That backup is the checkout the running session is sourcing right now: it is the correct content, it is already on disk, and it needs no network in the middle of an upgrade. master is a guess that is wrong for any machine not on master. Try the backup first and drop the git clone, which fetched the same thing as the tarball by a longer route. The network path stays for the case that has no backup, where the legacy root was already a symlink. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Clear the Hyprland error bar the upgrade leaves behind The two settings were applied through both the keyword and the Lua API, in four calls on the way out and three on the way in, split differently each time. Fold that into one helper that takes the value. The error bar needed more than suppression. An explicit hyprctl reload re-reads the config from disk, which resets both keywords before it reports what it found, so suppression cannot survive one; anything that reloaded during the swap left the bar on screen. Hyprland then keeps it up until a later clean reload, which this script deliberately never performs, so it was still there when the upgrade finished. Clear the overlay on the way out, once the shims have made the legacy config resolve again. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Run the packaged firewall config instead of a copy of it configure_snapper_policy and configure_lock_authentication already call into the installed tree; apply_firewall_defaults reimplemented install/config/firewall.sh inline instead, and had already drifted from it. The packaged script also installs the ufw-docker rules, so upgraded machines came up without the Docker firewall protections a fresh install gets. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Stop the Voxtype toggle migration reloading a mid-swap session This is the reload behind the "source= globbing error" bar users see during a Quattro upgrade. The upgrade runs the packaged migrations against a still-running Omarchy 3 session, and this one ends with hyprctl reload. That re-parses a legacy config whose theme source= has nothing to resolve to yet, so Hyprland paints an error bar and keeps it up until a later clean reload the upgrade deliberately never performs. It was still on screen when the upgrade finished. The upgrade already exports OMARCHY_UPGRADE_TO_QUATTRO_LIVE for exactly this, and 1782002156 honors it. Do the same here. Nothing in that session reads the toggle being removed; the reboot applies it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Assert the retired session entry points stay gone The ordering check would still pass if either came back, while the comment above it claims they cannot. Name them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Upgrade onto the channel the machine is already on The upgrade always defaulted to stable, so an rc machine taking it landed on production packages from the stable repo. rc callers worked around that by passing --channel rc, which then forced every caller onto rc, stable machines included. Read the channel off the mirrorlist the way omarchy-version-channel does and follow it: stable machines get omarchy and omarchy-settings from stable, and rc or edge machines get omarchy-dev and omarchy-settings-dev from edge, which is what --dev already selects. An explicit --channel or --dev still wins, and an unrecognized mirrorlist still falls back to stable. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Keep rc machines on the rc mirror when taking dev packages --dev forced the edge channel, so an rc machine following its own channel was moved onto the edge Arch mirror as well. The constraint is narrower than that: the dev packages are only published to the edge package repo, which the rc and edge channels both already point at. Only stable is incompatible. Reject --dev only for stable, and default to edge just when no channel was chosen. rc machines now upgrade against rc-mirror with the dev packages out of the edge repo, which is where Quattro lives until it ships. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
omarchy-monitor-state stopped shelling out to omarchy-hyprland-monitor-focused when it started deriving the focused name from its own hyprctl snapshot, so the stub the test installed was never called and the assertion could never pass. Expect the focused monitor from the fixture instead, and drop the dead stub. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The sleep inhibitor deliberately outlives the start that spawns it, but script tears its pty down as soon as the command returns, and the SIGHUP that follows could kill the inhibitor before it managed to exec. The sudo stub then never logged and the test failed about half the time. Hold the session open from inside until the inhibitor has started. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The stub polled for the lock with its own flock, competing with the holder it had just started. The holder took the lock non-blockingly and never retried, so a lost race killed it and left the lock free. The notifier then saw no update in progress and sent the toast the test asserts it withholds. Wait on the holder's own signal instead. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1784917531 gated its UKI rebuild on initramfs_async=0 being present in the Limine config, but omarchy-settings ships omarchy-defaults.conf with that parameter already in it. Any machine that installed the package and ran the migration in the same update matched the config the package had just written, skipped the rebuild, and kept booting an image baked before the config existed — without initramfs_async=0, so encrypted boots still fell back to an unthemed text LUKS prompt. Compare the booted command line against the configured one and rebuild when they disagree. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every supported agent spells it differently, so map each one to its own bypass flag instead of leaving the launcher at each agent's default. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
History was a pair of in-memory lists mirrored into notifications.json, split into "pending" and "past" by a seen/unseen distinction no surface exposed, capped at 100, deduped by an id that repeats across server generations, and pruned by a 15-minute TTL. Replaying it showed five rows drawn from whichever list happened to hold them. Every toast already writes a file under ~/.local/state/omarchy/notifications so it can survive a shell restart. That file is now the history record: when the popup leaves the screen it moves into notifications/history instead of being deleted, the newest ten are kept, and showHistory replays exactly what is in there, including the toasts still on screen when it is asked for. A notification DND silenced is written straight into the same directory, since a toast that never showed is the one worth looking back at. That leaves the models, notifications.json history payload, past pruning, and the /tmp image cache that existed to keep century-old history thumbnails alive with nothing to do, so they go. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…laced A client that updates a notification through replaces_id does not produce a second onNotification: Quickshell writes the new content onto the Notification object the shell is already holding. The card draws a snapshot copied out of that object — deliberately, since a live QObject in a ListModel role becomes a dangling pointer the moment the server destroys it — so the toast kept showing the superseded text, and archived it to history when it left the screen. A Slack thread that updates in place read as stuck. Every property the card draws is now watched on the notification we hold, and a change rewrites both the model row and the file the popup was persisted under. The file name is that popup's identity, so the rewrite lands in place: a shell restart restores the version last shown, and so does the copy that reaches history. The countdown starts over when the content changes. New text arriving a second before the toast was due to expire deserves a full look, not the remainder of the clock the text it replaced had nearly run through. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The pacman cache grows without bound across updates, and nothing in the update flow ever reclaimed it. On a machine that has been updating for a while it reaches several gigabytes of superseded versions that nothing will ever install again. Prune it with paccache -rk2 as the first step of an update. Both halves of that placement are load-bearing. Keeping two versions rather than one preserves the rollback path. The cache is Arch's only offline downgrade: when an update breaks a single package, reinstalling its predecessor from here is the surgical fix, where a snapshot rollback would revert every other package too. Pruning before the packages update means the installed version is still the newest cached, so it survives along with a spare. Retention is by version order and never consults what is installed, so that holds while the installed version is among the two newest cached; a deliberate downgrade or repeated failed transactions can stack newer archives on top of it. Running before the snapshot is what actually frees the space. The cache sits on the snapshotted root subvolume, so a prune taken afterwards leaves the fresh snapshot holding those extents and reclaims nothing until it ages out of the number cleanup. A failed prune warns and continues. Cache housekeeping should not trip the update's ERR trap and tell the user their update went wrong. This runs after omarchy-update-requires-free-space, so it reclaims space during healthy updates but does not rescue a machine already under the 10 GiB gate. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Replay the history a dismissal or a clear was still being written into The popup files a replay reads are written by a serialized queue of shell jobs, and the read ran as its own process alongside it. A dismissal issued a moment earlier could still be queued when the directory was read, leaving the notification out of the replay it was the newest entry of, and a clear issued a moment earlier could still be queued too, replaying entries it was about to remove. The read now waits for the queue to go idle, so the replay shows the history as of the moment it was asked for rather than whichever jobs happened to have landed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Catch up on an update that arrived before its popup had a row Watching a notification for in-place updates starts the moment it is handed over, but the row those updates write to is inserted a tick later, deferred to keep a mid-incubation Repeater from being mutated underneath. A client fast enough to update inside that window found no row to write to, and a property that has already changed does not change again — so the toast and its file sat on the superseded content until something else moved. The row is now refreshed from the live notification once it exists. That reads the same object the signals would have, so an update that beat the insert is picked up and one that did not costs nothing: a refresh whose content matches the row it would write is dropped, which also collapses the several signals a single multi-property update emits into one rewrite. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Hold queued file work behind the replay's read, not just ahead of it The read waited for everything queued before it, but nothing stopped the queue from running on while it worked. A clear or an archive issued during the read could delete or move files out from under awk mid-glob, so a replay could still show a partial history — some of what a clear was in the middle of emptying. The read is a barrier in both directions now: the queue holds until it exits, and it releases on exit rather than on output, so a read that comes back empty or fails cannot park the queue behind it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Queue the replay's read instead of waiting for the queue to empty Waiting for the queue to go idle before starting the read still let work overtake it. A clear or an archive enqueued after the replay was asked for, while the current job was running, was dequeued the moment that job exited — the read only starts once nothing is left — so the replay showed the state after those jobs, which is the race this was meant to close. Unbroken file traffic could postpone the read indefinitely for the same reason. The read is now an entry in that queue rather than a process running beside it. It takes its place in line behind the work queued before the request and ahead of everything queued after, so no later job can overtake it and no amount of traffic can push it back. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
The widget polled hyprctl every 10 seconds per monitor, including on the single-layout install where it never shows. Keep the poll only where its answer can change - a seat with more than one keyboard, where Hyprland moves the main flag with no event to announce it - and stop it entirely once a one-keyboard seat has been read. Also coalesce a refresh that arrives mid-query instead of dropping it, time out a query that never returns rather than letting it hold the guard shut for good, and re-read the layout on configreloaded. Co-Authored-By: markbus-ai <markbus-ai@users.noreply.github.com>
* Restore FPC fingerprint detection
* Anchor the FPC product match to a prefix
*fpc* is an unanchored three-letter token on the one branch that is
trusted outright, with none of the kernel-driver checking the vendor
guess gets. Every FPC reader on record leads with it — "FPC Sensor
Controller", "FPC Sensor Controller L:0002 FW:25.26.23.14", and this
branch's "FPC L:0000 FW:1425046" — so requiring the prefix costs no
coverage while keeping three letters from matching mid-string, where
FPC abbreviates unrelated things like flexible printed circuit.
Also restore the note about why Elan is kept out of the vendor list, so
the two signatures read as the same deliberate exception.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Write no product descriptor for a two-field device spec
${remainder#*:} returns the string unchanged when there is no second
colon, so a spec meant to describe a device with no product descriptor
wrote the product id out as its product string instead. Every call site
happened to pass a trailing colon, so the suite was right by accident.
Guard the split and drop the trailing colons, so the two vendor-match
cases exercise the path they were written for.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Bind a named driver in the kernel-driver fixture
Touching a bare `driver` file asserts that any driver at all disqualifies
a vendor guess, which is more than the detector should promise: libusb
claims an interface through a synthetic `usbfs` driver, so a reader in
active use looks bound by that rule.
Link the interface at a named driver directory instead, the way sysfs
does. The case still covers what it was written for — a Synaptics bridge
or a camera on a fingerprint vendor ID — without fixing the shape of the
answer for drivers it was never about.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: David Heinemeier Hansson <david@hey.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
The vendor-ID guess rejects any device with a driver bound, on the reasoning that libfprint drives readers from userspace so a real one sits there unbound. But libusb claims interfaces through a synthetic usbfs driver, so the reader binds one for as long as fprintd holds the claim — which is exactly while it is being enrolled or verified against. Readers that name themselves take the product-string branch and never reach this, so the exposure is the ones that don't: Goodix 27c6:6594 reports "Goodix USB2.0 MISC", matches on vendor ID alone, and drops out of detection mid-authentication. The menu entry disappears and the first-run invitation stops firing while the reader is in use. Ignore a driver link that resolves to usbfs, and keep rejecting the real ones — usbio-bridge, usbhid, uvcvideo — including on a device that has both. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Drops the ChatGPT web app from the default set at the same time, so installing the openai-codex-desktop package can't leave two identical-looking ChatGPT entries in the launcher. Super + Shift + A still opens the web version, which is the only place it was really used. The bundled ChatGPT icon stays: the package's own chatgpt.desktop asks for Icon=chatgpt and ships no hicolor icon of its own. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Quattro Beta
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 | bashThis will put you on the beta development version. So not something that's recommended for production systems. Ensure you have a good backup first!
Better yet, install it on a secondary machine using the ISO: https://iso.omarchy.org/omarchy-quattro-beta3.iso
Headline Features
Super + Space).The Shell
Setup > Menu Barin the Omarchy menu)omarchy plugin add <git-url>, and managed fromSetup > Plugins(add, clone, enable, disable, remove) by @ryanrhughes and @dhhSUPER + SPACEsearches apps and commands from one surfaceSUPER + ALT + SPACESUPER + SHIFT + ALT + ,), do-not-disturb, and deduping — popups on screen survive shell restarts (like the one every update performs), so critical alerts always make it acrossSUPER + CTRL + V)SUPER + CTRL + E) replacing Walker picker.SUPER + CTRL + A), Bluetooth (SUPER + CTRL + B), Network (SUPER + CTRL + W), Display (SUPER + CTRL + D), and Power (SUPER + CTRL + P) replacing bluetui, impala.~/.config/omarchy/extensions/omarchy-menu.jsonc)SUPER + CTRL + 1through9, counted left to right — rearranging the section or adding a widget renumbers them with no binding to rewrite by @dhhTheming & Aesthetics
SUPER + SHIFT + CTRL + SPACE) by @dhhSUPER + CTRL + SPACE) by @dhh~/.config/omarchy/shell.tomlas a machine-level override merged over the active theme, so a personal font, spacing, or bar tweak survives theme switching — and it's watched, so edits re-flow the shell liveomarchy display text size: one knob, 9–20px, that moves the shell font, GTK's text-scaling-factor, and the terminal point size in lockstep, with a notched slider in the display panelhyprctl bindsoutput to survive its broken JSON by @dhhApps & Defaults
SUPER + SHIFT + W) by @dhhSUPER + CTRL + Q) by @dhhSetup > Defaults > Agent, then launch it withSUPER + SHIFT + CTRL + Aor theaterminal alias — lazy-installed on first use by @dhhAlt + Shift + Dby @dhhCapture
SUPER + ALT + [ / ]by @dhh (on request from @jasonfried)RETURNcaptures the highlighted window,CTRL + RETURNthe whole display, andTABand the arrow keys move the selection through the workspace's windows by @jzimdars and @dhhotpauth://setup code on screen no longer needs a phone. The decoded value never touches disk and is marked sensitive, so clipboard history skips it by @dhh and @WondertanControls
o.bind("SUPER + SHIFT + W", "Omawrite", { launch = "omawrite" })) by @ryanrhughesSUPER + ALT + HOME/SUPER + HOMEby @dhhSUPER + ALT + K) and new-pane/split bindings for tmux, kitty, ghostty, and alacritty by @ryanrhughes, @vtmx, @heymaikol, and @dhhSUPER + CTRL + Jjumps straight to it. Tmux hooks push the state, so nothing polls while nothing is waiting by @dhhhdl/hds/hdlm/hsldevelopment-layout helpers by @dhhSUPER + CTRL + RETURNand its keybindings viewer withSUPER + CTRL + K, mirroring the tmux pair — plus tmux's tab moves, zoom flag, hostname in the window title, and hidden outer pane frame carried over by @dhhNetworking/Connections
System & Upgrade
/etc, so updates flow through pacman by @ryanrhughesomarchy update(bypassable viaOMARCHY_ALLOW_DIRECT_PACMAN=1) by @ryanrhughesomarchy updateon current releases instead of waiting out the release cooldown by @dhhpre-refresh-pacman.dhooks for custom repository support by @tyvsmithTrigger > Speed Test, sharing the live dial interface with the network test by @dhhSetup > Reset Computer: swap the running root for a fresh clone of the@factorysnapshot the ISO takes at install time, scrub machine identity, accounts, and fingerprint enrollments, and hand the machine back in that untouched first-boot state. A machine with no factory snapshot is turned away with an explanation rather than given a partial wipe by @dhhFixes
fipand friends misparsing under zsh by @pkwagnerCTRL + BACKSPACEby @RushiChagantiSUPER + C/Vclipboard shortcuts work there toopipefail, rerun the T2 defaults migration they skipped, and choose the gmux display backlight instead of the Touch Bar on T2 MacsBROWSERoverride to interactive shells/booton encrypted installs, fixing direct-boot setup and stale-UKI cleanupeflag, an unescaped VS Code theme name, unvalidated keyboard RGB), and drop the unconstrained tzupdate sudoers grant that let any wheel user write a root-owned symlink anywhere by @KazeTachinuuomarchy_monitor_scalehaving the variable name itself read as the scale, dropping clamshell recovery to a hardcoded 2x by @s-gatoomarchy bar putplace a widget on a bar it does not recognize, instead of refusing and taking the whole migration chain down with it by @dhhorg.codeberg.dnkl.footapp-id as a terminal so universal copy stops sendingCTRL + Cinto it by @dhh\uescapes instead of characters by @dhhFeature 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 + SPACEor via Style > Theme. You can see the new bar riding on top too.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.The launcher and the menu, together
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.And the Omarchy menu is now the same surface. Once the menu could search its own nested entries, there was no reason to keep two palettes with two shortcuts around — so
SUPER + SPACEnow finds your apps and every Omarchy command from one box. It's a native, filterable command palette living inside the shell: instant response, and extensible through a JSONC file if you want to add your own entries. (Prefer apps only?SUPER + ALT + SPACEopens the menu scoped to just them.)Control panels
The bar widgets now open real control panels. Audio (
SUPER + CTRL + A) has output/input device switching and volume control:Network (
SUPER + CTRL + W) shows live throughput, ping, packet loss, a one-click speed test, DNS provider selection, Wi-Fi QR sharing, and nearby networks:And weather now has a proper forecast panel, which can be pinned to a chosen location instead of following your IP around:
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.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.
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.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.
This PR description is up to date as of
27d1b6be; next time, review commits after this one.