* Anchor the webcam overlay to the recorded region, not the monitor
Recording a single window on an ultrawide put the camera outside the frame.
The overlay is placed twice, and neither placement knows what is being
captured: the window rules in default/hypr/apps/webcam-overlay.lua position it
from monitor_w/monitor_h, and omarchy-capture-webcam-resize recomputes the same
corner from hyprctl monitors. Both resolve to the monitor's bottom-right, so a
window anywhere but the far right of the display records without the camera in
it, and dragging it into frame by hand is undone by the next resize.
The geometry is already known. select_capture_target resolves the picked window
to a region rectangle before start_webcam_overlay runs, and a bare click in
smart mode snaps that rectangle to the window's own bounds. gpu-screen-recorder
takes the region in the compositor's logical coordinate space, which is the
same space window moves take, so the value needs no conversion to be reused as
an anchor.
Publish it for the resize helper, which becomes the single place that positions
the overlay. It anchors to the region when one is recorded and falls back to
the monitor otherwise, so full-monitor captures, the portal backend, and manual
resizes outside a recording all keep their current behaviour. A malformed or
empty file falls back the same way.
Presets scale from the anchor's height rather than the monitor's, so the camera
keeps its proportion of the frame instead of covering a small capture outright.
A tall, narrow region cannot fit a preset derived from its height, so widths are
capped to the space available and heights follow at the same 8:9 aspect.
Placement happens inside start_webcam_overlay rather than after it returns.
Correcting the position once that function had returned left the move adjacent
to gpu-screen-recorder starting, and the camera was recorded sliding the last
stretch into its corner over the opening frames. The overlay is waited for
explicitly instead, positioned, and only then does capture start.
Waiting for the map is what the blind second was partly guessing at, so the
remainder is trimmed to hold the delay before capture where it was. Starting
later is not free: it eats the opening words of whatever is being narrated.
* Keep the webcam size ladder usable in a narrow region
Capping each preset's width to the region separately collapsed small,
medium and large onto the same width, so Super + Alt + [ and ] had
nothing to step between, and integer division left small taller than
medium. Cap the height the presets scale from instead, which shrinks
the ladder as a whole and keeps the three sizes ordered and distinct.
Cover the anchoring in the test suite: a region the camera follows, the
fallback for an unreadable one, and the narrow-region ladder. Point
XDG_RUNTIME_DIR at the test's own directory while doing so — the resize
helper now reads a region file from there, and the existing geometry
assertions would pick up a real one from a live recording.
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 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>
Both capture scripts carried the same pipeline: workspace rectangles
from hyprctl, a hyprpicker freeze, slurp, and the bare-click snap loop.
The copies had already diverged once (rotated-display handling), so the
pipeline now lives in one hidden helper, omarchy-capture-region-pick,
which prints the picked geometry in slurp format.
The two callers differ only in what they layer on top. The screenshot
needs the freeze to outlive the pick so grim captures frozen content:
--keep-freeze leaves hyprpicker running and prints its PID first, with
the caller owning the kill. The recording prefers native full-monitor
capture: --match-monitor prints monitor:NAME when the geometry exactly
matches a display.
One deliberate fix along the way: the screenshot snap regex rejected
negative coordinates, so bare clicks on monitors positioned left of or
above the origin never snapped. The helper uses the recording variant,
which handles them.
Verified with an 11-case shim harness (snap precedence, rotated-monitor
match, freeze ownership, cancellation, negative coordinates) and the
live end-to-end screenshot sanity test.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The screenshot picker swaps monitor dimensions for transform 1/3
displays; the recording copy had drifted and did not, so portrait
monitors got landscape rectangles in the picker. The full-monitor
match had the same blind spot, silently downgrading rotated-monitor
selections to region capture instead of native -w capture.
Both now share the screenshot script's format_geo jq helper, which
also lets the monitor match compare one geometry string instead of
four fields.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
omarchy-shell's bar plugin replaces waybar on every default path, so the
waybar package, configs, indicator scripts, and toggle/restart/refresh
binaries all go away in this commit.
The four small helper scripts that Bar.qml shells out to (weather.sh and
indicators/*.sh) move with the shell rather than disappear \u2014 they live
at default/quickshell/omarchy-shell/scripts/ now, alongside the rest of
the shell code.
Companion script changes:
- omarchy-shell-ipc gains --if-running so fire-and-forget refresh
callers (toggle-idle, toggle-notification-silencing,
update-available-reset, capture-screenrecording) don't accidentally
spawn the shell when it isn't already up.
- omarchy-theme-set, omarchy-tz-select, omarchy-voxtype-{install,model},
omarchy-toggle-nightlight, omarchy-voxtype-config drop their waybar
branches and comments.
- omarchy-voxtype-status's summary stops claiming it's a Waybar helper.
- omarchy-base.packages drops waybar; install/packaging/fonts.sh's
comment points at the new bar consumer.
- SKILL.md / AGENTS.md / omarchy-menu.jsonc lose their waybar entries.
- test/omarchy-cli-test.sh substitutes a remaining toggle command.
Adds first-party omarchy.notifications service plugin that hosts a
freedesktop notification server and renders popups + a history popup
inside the shell. Uninstalls mako and retargets every helper, keybind,
indicator, and migration entry to the new daemon.
Plugin (default/quickshell/omarchy-shell/plugins/notifications/):
- Service.qml: NotificationServer, popupModel + pendingModel + pastModel
(two-tier history, see below), DND via PersistentProperties +
cache-file backstop, image cache for /tmp screenshots, IpcHandler with
toggleDnd/setDnd/isDnd/showHistory/clear/clearPending/markAllSeen/
dismissAll/dismissOne/invokeLast/dismiss, per-theme override file
~/.config/omarchy/current/theme/notifications.json honoring
borderColor/backgroundColor/textColor/countdownColor.
- components/NotificationCard.qml: theme-driven card (Color.foreground/
background/border tokens from Commons/Color.qml), 32x32 icon slot,
Nerd Font glyph fallback via omarchy-glyph hint, hero image strip
for screenshot/image-path notifications, hover-pause progress bar,
uses bar.fontFamily so all surfaces share one font.
Filtering and DND:
- transient hint and CLI-style senders (app_name in notify-send /
omarchy-action) bypass history but still pop.
- DND only allows omarchy-action toasts and notify-send -u critical
through; real-app urgency=critical (Discord, Slack, Vesktop) is
silenced and lands in pending instead.
- Pending vs past split surfaced via tabs in the bar widget popup;
past tab is auto-pruned at the 15-minute mark.
- Click-to-jump: notifications without a libnotify default action focus
the matching Hyprland window via class lookup.
Shell host:
- shell.qml: generic first-party service loader (mirrors the existing
noctalia-compat path) and an alias for the bar so plugins can read
barSize / barHidden / position for anchoring.
- Commons/Color.qml: parses the theme's hyprland.conf for
$activeBorderColor so notifications match Hyprland window borders;
picks the explicit accent= key over the color4= alias.
Bar widget rebase (plugins/bar/widgets/notificationCenter.qml):
- Drops the chunk-1 stub server, binds count/dnd state to the service,
hosts the history popup via PopupCard so it drops down from the
notification glyph the same way Quick Settings does.
- Pending/Past tabs, dismiss-individual close X, mark-all-as-seen and
clear-recent action buttons, theme-driven palette.
Quick Settings rework (plugins/bar/widgets/controlCenter.qml):
- DND tile binds directly to service.doNotDisturb for instant feedback.
- Drops the volume slider (already in audioPanel) and the no-op Theme
tile; adds a Bluetooth toggle bound to Quickshell.Bluetooth.
- Bigger 44x44 wallet was scaled back to 32x32 for tighter rows.
Notification scripts (bin/omarchy-*):
- omarchy-notification-send: passes glyph as a custom hint instead of
prepending to the summary; adds -a omarchy-action and -u urgency
automatically; supports -e/--transient passthrough.
- User-action toasts in the capture / toggle / hyprland / default-*
scripts and bindings/utilities.lua now tag themselves
-a omarchy-action so DND treats them as intent-based bypass.
- omarchy-toggle-notification-silencing, omarchy-notification-dismiss,
default/waybar/indicators/notification-silencing.sh, and the Hyprland
comma-keybinds all route through omarchy-shell-ipc notifications.
- omarchy-capture-screenshot / -screenrecording set the image-path
hint properly so the hero-image rendering kicks in.
Mako removal (migrations/1778743515.sh):
- pkill -x mako, systemctl --user stop mako.service, pacman -Rns mako
(uninstalling deletes /usr/lib/systemd/user/mako.service so D-Bus
activation can't respawn it). Removes ~/.config/mako/ and the legacy
toggle file. Restarts quickshell so it claims the bus name.
- Drops mako from install/omarchy-base.packages, autostart.lua,
install/config/theme.sh + toggles.sh, default/themed/mako.ini.tpl,
default/mako/, the omarchy-menu Mako restart row, bin/omarchy
GROUP_DESCRIPTIONS, the settings panel catalogue, and the
default/omarchy-skill paths table.
- Removed scripts: bin/omarchy-restart-mako,
bin/omarchy-style-corners-mako.
- bin/omarchy-style-corners summary updated; corner radius for the
notification card reads ~/.local/state/omarchy/toggles/quickshell-menu.json
alongside the rest of the shell.