Commit Graph
281 Commits
Author SHA1 Message Date
David Heinemeier HanssonandClaude Opus 5 6d4fa7acaf Make the open-panel mark find and fit its module
A center-anchored module is mounted twice: the copy that is drawn, and a
zero-size placeholder holding its place in the flow beside the anchor.
findPanelWidget returned whichever registered first, and that order is
not stable across a live bar reconfiguration, so a panel could open
anchored to the invisible copy -- mispositioned, with the drawn slot
never lighting up and switchPanelFrom unable to find it again.

The mark was also always 55% of the slot, which fits an icon but
underlines only a fraction of a text label, and runs the full height of a
multi-line module on a vertical bar. Modules can now say how long the
mark should be along the bar; anything that does not answer keeps the old
proportion.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 19:10:06 -07:00
David Heinemeier HanssonandClaude Opus 5 d4c835afb5 Fix the default center layout assertion
The center layout was reordered when the indicators moved next to the
clock, but the assertion kept the old order, so this has been failing on
quattro since.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 19:10:06 -07:00
David Heinemeier HanssonandClaude Opus 5 187c2ecf7f Size zram the way Fedora does
zram-size = min(ram, 8192) is Fedora's default since F34, where
zram-fraction=1.0 with max-zram-size=8192 has run on desktops for five
years. The previous min(ram / 2, 8192) halved that on every machine
below 16G with nothing behind the fraction; at 16G and above the two
already agree.

A changed size only reaches a running device on the next boot, so the
migration resizes an empty device now and asks for a reboot otherwise.
It asks the generator what the config evaluates to rather than
repeating the expression here, and does neither when the device already
matches.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 12:58:02 -07:00
David Heinemeier HanssonandClaude Opus 5 2e04f093c1 Ship zram tuning as a vendor drop-in
pacman checks file conflicts during transaction prepare, so the --overwrite
entry added alongside /etc/systemd/zram-generator.conf never got to run: the
copy of omarchy-update-system-pkgs driving the upgrade is the one already on
disk. Every machine carrying archinstall's copy aborted the transaction.

zram-generator.conf(5) reserves /etc for the local admin and has vendors ship
snippets under /usr/lib/systemd/zram-generator.conf.d/, where drop-ins outrank
the main config file. Nothing collides, and the tuning wins whether or not
archinstall's file is still around.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LjeyQZsNBxqyYy9z8KaKm7
2026-07-25 14:01:38 -07:00
David Heinemeier HanssonandClaude Opus 5 9ddcec272d Lock the screen before suspend instead of racing logind for it
Closing the lid could suspend the machine with the session still exposed.
omarchy-sleep-lock held a delay inhibitor and waited for Quickshell to report
the session secure, but a delay inhibitor is a timer rather than a promise:
logind suspends once InhibitDelayMaxSec expires, locked or not. The default is
five seconds, and closing the lid also reconfigures displays -- exactly when
the lock service is waiting for the screen set to settle before it can secure.

The race is now off the critical path. switch:on:Lid Switch runs
omarchy-system-lid-close, which requests the lock the moment the lid closes,
before logind has decided to suspend at all, so the inhibitor window usually
finds the session already secure. A docked lid close does not suspend
(HandleLidSwitchDocked defaults to ignore) and must not lock either, since that
is clamshell mode still in use on the external display, so the handler gates on
the same closed-and-undocked pair logind itself keys on.

Suspends that never touch the lid -- idle timeout, the system menu, low battery
-- still arrive through the inhibitor, so that path gets room to work too. The
shipped drop-in raises InhibitDelayMaxSec to 15s, and the helper derives its
budget from logind's live InhibitDelayMaxUSec rather than assuming the drop-in
landed: a machine that has not reloaded logind yet, or that carries its own
override, gets a budget that fits what logind will actually allow. It leaves
logind a fifth of its own window and caps at 12s, so a hand-raised window
cannot strand a closed laptop awake in a bag.

The wait itself had three defects. Its deadline arithmetic read EPOCHREALTIME
assuming a period, so under any comma-decimal locale the subtraction parsed as
bash's comma operator and silently voided the deadline, leaving only the
attempt counter to stop it. The lock request shared the status polls' timeout
and exited on first failure, so a shell 300ms slow meant suspending unlocked;
it now has its own budget and is simply retried, since asking again is
idempotent. And a refusal the shell reports on stdout with a zero exit --
missing-pam -- read as success, burning the whole window on a lock that could
never happen.

Every call is bounded by what is left of the budget rather than by an estimate
of what the step should cost, so the deadline holds on hardware slower than
anything the constants were fitted to.

Failure is still possible and it used to be silent. It now writes to the
journal and raises a critical notification, which lands on the screen the user
unlocks into.

Incidentally, monitor-recovery-test asserted lid probing against
omarchy-hw-clamshell after that logic moved to omarchy-hw-laptop-closed. It
aborted the file under set -e, skipping the nine assertions behind it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 12:35:17 -07:00
David Heinemeier Hansson 57923f0378 Support positional section when moving bar widgets 2026-07-25 11:14:04 -07:00
David Heinemeier HanssonandClaude Opus 5 195df4f5c7 Repair Neovim theme symlinks the earlier relink missed
1781158082.sh matched an explicit list of three legacy spellings for
~/.config/nvim/lua/plugins/theme.lua. At least one more exists in the
wild -- "../../../../.config/omarchy/current/theme/neovim.lua" -- so
those installs fell through the case, kept a dangling link, and Neovim
loaded no colorscheme spec at all. The failure looks theme-specific
because it only surfaces when you next switch themes.

Editing that migration would not help anyone, since it is already marked
applied. Add a new one that matches the shared suffix instead of an
enumerated list, so every spelling of the pre-state-dir path is caught.
It exits early when the link already points at the state directory and
ignores targets outside omarchy/current, leaving custom links alone.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LjeyQZsNBxqyYy9z8KaKm7
2026-07-25 11:04:55 -07:00
David Heinemeier Hansson fc4caf3c60 Extract notification center bar widget 2026-07-25 10:59:09 -07:00
David Heinemeier HanssonandClaude Opus 5 e880cf77cc Alert on tmux output while its terminal is unfocused
tmux only raises an activity flag for windows that are not currently
selected, so a long-running command in the window you left selected --
the common case, since you switch away by moving your Hyprland focus
elsewhere rather than by selecting another tmux window -- finished
silently and the indicator never lit.

Windows now also count as waiting when they are selected in an attached
client, every client showing them is unfocused, and their window_activity
is newer than an @omarchy_unfocused_activity watermark. The watermark is
stamped by a new `track` subcommand wired to client-focus-in/out and the
existing select-window hooks, so it records where attention last was.
The hooks pass #{window_id} and #{window_activity} as arguments, which
tmux expands when the hook fires; run-shell -b would otherwise let output
arriving during the handoff be swallowed by the new watermark. The focus
hooks take index 100 to leave a user's own bindings alone.

That state has no hook of its own, so it needs polling to be noticed.
The probe therefore moves out of the indicator and into a service plugin,
alongside nightlight and battery. A bar surface exists per monitor and
each one instantiates every indicator twice, once per block, so a timer
on the indicator meant a shell-out per instance per tick -- four probe
processes every three seconds on a two-monitor machine, forever. One
service polls for the whole shell instead.

Sharing the state also fixes what per-instance polling would have papered
over: each indicator used to own its own count, so a timer-driven update
only refreshed the bar it ran on and left the other monitors stale.
Refreshes still arrive over the existing indicator broadcast, which now
coalesces into a single run no matter how many bars relay it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018CC9kSQv8ZEogaxDoeKBzL
2026-07-25 07:19:02 -07:00
David Heinemeier HanssonandClaude Opus 5 ec1553d720 Let tmux alerts actually reach the bar
The tmux alert hooks fire omarchy-shell through run-shell, and run-shell
builds its own environment rather than passing the server's along, so the
hook ran without WAYLAND_DISPLAY. qs matches instances by display, so every
refresh from a bell died at "omarchy-shell is not running", which -q then
swallowed by design.

That left the indicator with no way to turn itself on. Its five second poll
only runs while the indicator is already active, so an alert raised after
startup was invisible until the shell happened to restart with the window
still flagged. The icon appeared roughly never.

Recovering the display from the socket in XDG_RUNTIME_DIR fixes it in the
one place that needs it, and covers any other caller reaching the shell from
a stripped environment rather than just the tmux hooks.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 07:03:58 -07:00
David Heinemeier HanssonandClaude Opus 5 c6ad61448f Stop the launcher from listing an app more than once
The apps list rebuilt its rows by writing into the maps held by the menu's
items and itemOrder var properties. Writing into an object owned by a QML var
property is not reliable: the same row object written into a plain JS object
always lands, but written through the property it occasionally arrives with the
key created and the value undefined. One write per rescan was lost, on a
different app each time.

A lost write left an id in itemOrder with no item behind it. The old purge only
deleted app rows it could find in items, so the orphan survived the next merge,
the add loop appended a second row for the same app, and the list grew by one --
permanently, and again on every later rescan. Touching a single desktop file
fires around a dozen merges, because the entry model emits valuesChanged per
insert and removal while it reconciles, so duplicates piled up quickly: nine
YouTube rows on the reporting machine, and Alacritty doubled before that.

The bookkeeping moves into MenuModel as two pure functions that build fresh maps
for the caller to assign in one shot, so the fragile write disappears. They also
make the merge self-healing rather than merely correct-when-nothing-is-lost: an
id with no item is dropped instead of carried forward, and an id is listed once
even when two desktop entries claim it -- so no single dropped write can compound
into a duplicate row again. The bash-backed providers behind the font and power
profile lists had the same latent bug and get the same treatment.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TJQJfHXXApUk6En8EZisHg
2026-07-24 19:42:07 -07:00
David Heinemeier Hansson be781574d1 Let the invitation terminals actually open
Clicking the Voxtype or fingerprint invitation did nothing. The launcher
execs setsid, which forks because the transient unit's main process is
already a process group leader, so the unit exits within milliseconds and
systemd's default control-group kill took the still-starting terminal down
with it. Run those units with KillMode=process instead.

The invitation tests had also drifted from the two-unit design and were
failing; teach the systemd-run mock to run the command it is given.
2026-07-24 18:57:51 -07:00
David Heinemeier HanssonandClaude Opus 5 248659de5a Give every OSD card exact padding on all four sides
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LfqzqpU1T6pQRsmpbGxBs5
2026-07-24 16:48:14 -07:00
David Heinemeier HanssonandClaude Opus 5 528a4343a9 Add omarchy-hyprland-monitor-laptop for internal display lookup
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-24 12:28:55 -07:00
David Heinemeier HanssonandGitHub 1d4077287b Merge pull request #6353 from zainsyedz/fix-clamshell-internal-monitor-config
Respect internal monitor config in clamshell recovery
2026-07-24 10:31:00 -07:00
David Heinemeier HanssonandGitHub a62e95d2e1 Merge pull request #6367 from khpark43/fix-bar-plugin-json-values
Fix bar plugin JSON value validation
2026-07-24 10:24:34 -07:00
Kyunghyun Park 876d6bcd23 Fix bar plugin JSON value validation 2026-07-25 01:33:30 +09:00
David Heinemeier Hansson 5a046035d5 Fix shell restart across dev path changes 2026-07-24 09:31:09 -07:00
David Heinemeier HanssonandClaude Fable 5 2c8639ffbd Persist workspace layout toggles across Hyprland reloads
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 21:03:43 -07:00
David Heinemeier Hansson 202296324a Keep display scaling options consistent 2026-07-23 20:37:25 -07:00
David Heinemeier HanssonandClaude Fable 5 00eae9a5ef Invite fingerprint setup after the first system update
The setup installs packages (libfprint-git, fprintd, usbutils), which
isn't reliable on a fresh install before the databases have been
synced. Defer the invitation with a post-update hook, like Voxtype.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 19:25:06 -07:00
David Heinemeier Hansson 86f616cfb3 Add emoji picker to Trigger menu 2026-07-23 19:23:50 -07:00
David Heinemeier Hansson 9b09a3c142 Clear update inhibitors before reboot prompt 2026-07-23 18:58:55 -07:00
David Heinemeier HanssonandClaude Fable 5 a0e6d65ba8 Keep universal clipboard shortcuts working in terminals
Sending the shortcut through wtype's virtual keyboard let the physically
held SUPER merge into the injected chord, so terminals saw
SUPER+CTRL+Insert instead of CTRL+Insert, and injected CTRL+V could even
trigger the SUPER+CTRL+V clipboard manager bind. Send via send_key_state
with no window target instead: explicit mods go straight to the focused
surface, layer-shell panels included.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XnMDbwJXQA3fvW8o8Pwr97
2026-07-23 18:08:31 -07:00
David Heinemeier Hansson 63955e787f Hide unavailable display scale options 2026-07-23 18:06:19 -07:00
David Heinemeier Hansson 58ec29f20a Move direct boot command to setup 2026-07-23 17:43:36 -07:00
David Heinemeier HanssonandClaude Fable 5 5b130c1063 Make tmux alert parsing and focus more robust
Session names can contain pipes but never colons, so split fields on
colons instead. Remember refreshes that arrive while the indicator is
already polling, and jump to the most recently used tmux client rather
than an arbitrary one.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 17:40:47 -07:00
David Heinemeier HanssonandClaude Opus 4.8 a382be2645 Indicate and jump to tmux panes waiting for attention
Show a bar indicator whenever tmux has flagged a window, the same state
that highlights the tab, and jump to it on click or with Super + Ctrl + J.
Tmux hooks push the state to the shell, so nothing polls while no pane is
waiting.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 17:40:47 -07:00
David Heinemeier Hansson 6d7268eb65 Support clipboard shortcuts in shell panels 2026-07-23 17:12:39 -07:00
David Heinemeier Hansson c844277749 Activate dev checkout before updates 2026-07-23 17:05:29 -07:00
David Heinemeier Hansson ed9e68957f Match display scale highlights to clean scales 2026-07-23 16:48:29 -07:00
David Heinemeier Hansson 2d3d1e2a3c Only offer webcam recording when available 2026-07-23 16:33:12 -07:00
David Heinemeier Hansson 7798ed34b1 Keep apps menu alphabetically sorted 2026-07-23 16:32:31 -07:00
David Heinemeier Hansson 8e549c27d0 Update active dev checkout with system 2026-07-23 15:28:32 -07:00
David Heinemeier Hansson 7a9947a732 Combine the Omarchy menu and the launcher
Now that we can deep search, they don't need to be different
2026-07-23 15:04:22 -07:00
David Heinemeier Hansson 347997871e Defer channel switch reboot until after update 2026-07-23 14:19:24 -07:00
David Heinemeier Hansson f911851319 Link dev channel to home checkout 2026-07-23 14:01:36 -07:00
David Heinemeier HanssonandClaude Opus 4.8 540e411edf Show fingerprint on lock screen and polkit, gated by lid state
Bring the fingerprint affordance to the Quickshell lock screen and polkit
dialog, matching what hyprlock did on master.

Lock screen: render the md-fingerprint glyph inside the password field's
right edge when a sensor is enrolled, reserving space so long passwords
never run under it.

Polkit dialog: show one method at a time. When a sensor is enrolled and
the reader is reachable, the dialog is just the centered fingerprint icon
(square card); the moment PAM asks for a password it switches to the
password field. Detects pam_fprintd anywhere in the auth stack now that a
gate can precede it.

Lid awareness: a closed lid means the reader is unreachable, so both
surfaces fall back to the password. polkit gets a pam_exec clamshell gate
(auth [success=1 default=ignore] before pam_fprintd) so a shut lid drops
straight to the password prompt instead of blocking on the reader for the
pam_fprintd timeout; the lock screen hides the icon and skips scanning.

The gate points at the fixed /usr/bin path the package always provides so
it survives switching between package installs and dev-link. A migration
adds the gate for existing fingerprint setups.

New helper omarchy-hw-laptop-closed (pure lid state); omarchy-hw-clamshell
now composes it with the external-monitor check.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 13:51:07 -07:00
39ca9135c4 Fix headless bar widget test skip (#6338)
Co-authored-by: almondsun <maramirezes@outlook.com>
2026-07-23 07:53:57 -07:00
Zain Syed e7fc47a44a Respect internal monitor config in clamshell recovery 2026-07-23 13:53:49 +05:30
David Heinemeier Hansson 1b6ab15331 Fix command detection in Hyprland Lua 2026-07-22 21:48:30 -07:00
David Heinemeier Hansson fc6168af86 Load Voxtype hotkeys when installed 2026-07-22 21:39:15 -07:00
David Heinemeier Hansson c544440469 Rename CLI benchmark command 2026-07-22 17:32:01 -07:00
David Heinemeier Hansson 1de4c89030 Expand graphical acceptance coverage 2026-07-22 17:31:14 -07:00
David Heinemeier Hansson 7361b48461 Refresh shell test fixtures 2026-07-22 17:31:14 -07:00
David Heinemeier Hansson 43e95217f2 Reload weather location when opening panel 2026-07-22 17:31:14 -07:00
David Heinemeier Hansson 475211a5d4 Make Copy URL use native clipboard host 2026-07-22 17:25:28 -07:00
David Heinemeier Hansson 60a550a646 Add --fit OSD option and use it for system shutdown/reboot/logout 2026-07-22 16:33:54 -07:00
David Heinemeier Hansson 36329cee7a Launch 1Password installer when missing 2026-07-22 16:10:45 -07:00
David Heinemeier Hansson 1e928d58db Remove menu keywords feature 2026-07-22 16:06:55 -07:00