Compare commits

..
Author SHA1 Message Date
David Heinemeier Hansson dce4f4a74b Merge branch 'dev' into waybar-styling 2026-05-09 08:37:53 +02:00
David Heinemeier Hansson 13b7aaae1d Spike of waybar styling 2026-05-05 14:52:28 +02:00
1362 changed files with 12449 additions and 63357 deletions
-4
View File
@@ -1,4 +0,0 @@
# Python bytecode (orchestrator)
__pycache__/
*.pyc
-11
View File
@@ -1,11 +0,0 @@
{
"workspace": {
"library": [
"/usr/share/hypr/stubs"
],
"checkThirdParty": false
},
"diagnostics": {
"globals": ["hl"]
}
}
+32 -98
View File
@@ -31,7 +31,7 @@ Common prefixes include:
Other current prefixes include:
- `ac-`, `audio-`, `battery-`, `branch-`, `brightness-`, `channel-`, `config-`, `debug-`, `dev-`, `drive-`, `first-`, `font-`, `haptic-`, `hibernation-`, `hook-`, `hyprland-`, `menu-`, `migrate-`, `notification-`, `npm-`, `plymouth-`, `powerprofiles-`, `reinstall-`, `remove-`, `screensaver-`, `show-`, `snapshot-`, `state-`, `sudo-`, `system-`, `transcode-`, `tui-`, `tz-`, `upload-`, `version-`, `voxtype-`, `webapp-`, `wifi-`, `windows-`
- `ac-`, `audio-`, `battery-`, `branch-`, `brightness-`, `channel-`, `config-`, `debug-`, `dev-`, `drive-`, `first-`, `font-`, `haptic-`, `hibernation-`, `hook-`, `hyprland-`, `menu-`, `migrate-`, `notification-`, `npx-`, `plymouth-`, `powerprofiles-`, `reinstall-`, `remove-`, `screensaver-`, `show-`, `snapshot-`, `state-`, `sudo-`, `swayosd-`, `system-`, `transcode-`, `tui-`, `tz-`, `upload-`, `version-`, `voxtype-`, `webapp-`, `wifi-`, `windows-`
# Command Metadata
@@ -40,128 +40,57 @@ Commands in `bin/` can declare CLI metadata in comments near the top of the file
Supported metadata keys:
- `# omarchy:summary=...` - short help text
- `# omarchy:group=...` - command group when it differs from the filename-derived prefix
- `# omarchy:name=...` - command name within the group
- `# omarchy:args=...` - usage arguments
- `# omarchy:examples=...` - examples separated with ` | `
- `# omarchy:alias=...` / `# omarchy:aliases=...` - alternate routes
- `# omarchy:hidden=true` - hide from default command listings
- `# omarchy:requires-sudo=true` - mark commands that require sudo
Only use `omarchy:examples` where there are args that need explaining.
Prefer explicit metadata for user-facing commands. Keep routes consistent with the filename unless there is a deliberate alias or compatibility route.
Example:
```bash
# omarchy:summary=Take a screenshot
# omarchy:group=capture
# omarchy:args=[smart|region|windows|fullscreen] [slurp|copy]
# omarchy:examples=omarchy screenshot | omarchy capture screenshot region
# omarchy:aliases=omarchy screenshot
```
# Runtime Environment
- `$OMARCHY_PATH` is set at the top level by the uwsm session environment and is always available to Omarchy runtime code.
- Commands in `bin/` and Quickshell QML should rely on `$OMARCHY_PATH` / `Quickshell.env("OMARCHY_PATH")`; do not derive fallback paths from `HOME`, `Quickshell.shellDir`, or re-export/default `OMARCHY_PATH` manually.
# Privileged Commands
- Whenever you need to trigger a sudo command, use `pkexec` so it results in a user prompt they can approve.
# Git
- Commits should be atomic: include only one coherent change or fix, and do not mix unrelated work.
- Commit messages should be succinct and describe the change being made.
# Install Scripts
The ISO owns installation orchestration. This repo ships target-side setup commands and reusable setup leaves:
Install entry points (`install.sh`, `boot.sh`) use `#!/bin/bash`. Many scripts under `install/` are sourced via `run_logged` and intentionally do not have shebangs.
- `bin/omarchy-setup-system` runs root-owned system setup during ISO finalization.
- `bin/omarchy-setup-hardware` runs idempotent hardware-specific setup and is called by `omarchy-setup-system`.
- `bin/omarchy-finalize-user` runs the per-user runtime finalization (skill symlinks, xdg-user-dirs, mime defaults, `install/user/all.sh`). Shipped user defaults are seeded by `/etc/skel` from `omarchy-settings`, not by this command. `bin/omarchy-reinstall-configs` is the explicit destructive resync of those defaults into an existing user's `$HOME`.
- leaf scripts under `install/` are sourced by `run_logged $OMARCHY_INSTALL/path/to/script.sh` and intentionally do not have shebangs.
- avoid `exit` in sourced setup scripts unless intentionally aborting setup.
- use `$OMARCHY_INSTALL` and `$OMARCHY_PATH` instead of hard-coded Omarchy paths.
- keep root-scoped hardware setup under `install/hardware/` and orchestrate it through `install/hardware/all.sh`.
- keep every per-user setup leaf under `install/user/` (including `install/user/hardware/` and `install/user/first-run/`) so it is clear what must run for each user.
- prefer helper commands for package and command checks where available.
Install stage files follow this pattern:
Raw `command -v`, `pacman`, and `pacman-key` are acceptable in package-helper contexts where direct package-manager behavior is the point of the script.
- `install/*/all.sh` lists scripts in execution order
- leaf scripts are sourced by `run_logged $OMARCHY_INSTALL/path/to/script.sh`
- avoid `exit` in sourced install scripts unless intentionally aborting the install
- use `$OMARCHY_INSTALL` and `$OMARCHY_PATH` instead of hard-coded Omarchy paths
- keep hardware-specific logic under `install/config/hardware/`
- prefer helper commands for package and command checks where available
Raw `command -v`, `pacman`, and `pacman-key` are acceptable in bootstrap/preflight/package-helper contexts where the helper commands may not be available yet or where direct package-manager behavior is the point of the script.
# Helper Commands
Use these instead of raw shell commands:
- `omarchy-cmd-missing` / `omarchy-cmd-present` - check for commands
- `omarchy-pkg-missing` / `omarchy-pkg-present` - check for packages (don't use these if you can just use `omarchy-pkg-add`/`omarchy-pkg-drop`)
- `omarchy-pkg-missing` / `omarchy-pkg-present` - check for packages
- `omarchy-pkg-add` - install packages (handles both pacman and AUR)
- `omarchy-pkg-drop` - remove packages; use this instead of raw `pacman -R*`
- `omarchy-notification-send` - send desktop notifications; do not call `notify-send` directly
- `omarchy-hw-asus-rog` - detect ASUS ROG hardware (and similar `hw-*` commands)
Exceptions are allowed for migration and package-helper scripts where the helper may not be available yet, where the helper itself is being implemented, or where direct package-manager behavior is required.
Exceptions are allowed for bootstrap, preflight, migration, and package-helper scripts where the helper may not be available yet, where the helper itself is being implemented, or where direct package-manager behavior is required.
# Config Structure
- `config/` - default configs copied to `~/.config/`
- `default/themed/*.tpl` - templates with `{{ variable }}` placeholders for theme colors
- `themes/*/colors.toml` - theme color definitions (accent, bg, fg, red/green/yellow/blue/magenta/cyan and bright_* variants)
# Tests
Run focused automated tests for the area you changed. Current test entry points:
- `./test/all` - aggregate runner for CLI and shell tests
- `./test/cli` - CLI routing, command metadata, theme helpers, and safe dispatch coverage
- `./test/shell` - all Omarchy shell tests under `test/shell.d/`
New Omarchy shell tests should live in `test/shell.d/*-test.sh` so `./test/shell` picks them up automatically. Source `test/shell.d/base-test.sh` for shared root-path discovery, assertions, and Node test helpers.
For visual changes, such as omarchy-shell styling, desktop appearance, screenshots, or screen recording flows, verify with the running UI in addition to automated tests. Take and analyze screenshots with `omarchy capture screenshot fullscreen save`. For animation, transitions, capture, or screen recording behavior, make a short recording with `omarchy screenrecord --fullscreen`, stop it with `omarchy screenrecord --stop-recording`, and review the output before finishing.
For interactive UI work, use `wtype` to simulate keyboard input when available. Example: start the UI in the background, wait briefly for focus, then run `wtype -k Right -k Return` to exercise keyboard selection and confirm the resulting command output or state change. Prefer this over manual-only verification when a UI returns a selected value or changes a symlink/config.
When testing layer-shell UI, capture the reference and candidate states as separate screenshots, then compare them visually before further edits. If a launched UI would otherwise remain open, keep track of its PID and stop it after the screenshot; avoid broad process kills unless checking with `ps` first.
# Omarchy shell
The Quickshell desktop runs as a single long-running process out of
`shell/`. Hyprland autostart launches it directly with `quickshell -p`; do
not start additional standalone `quickshell -p` instances for individual
components.
Run `omarchy-restart-shell` after making changes to QML files.
Plugin contract:
- Each plugin lives in its own directory under
`shell/plugins/<id>/` (first-party) or
`~/.config/omarchy/plugins/<id>/` (third-party).
- Every plugin ships a `manifest.json` declaring `id`, `kinds`,
`activation`, and `entryPoints`. The full schema is in
[`docs/omarchy-shell.md`](docs/omarchy-shell.md).
- Entry-point QML files are `Item`s (not `ShellRoot`), and accept the
shell-injected properties `omarchyPath`, `shell`, `manifest`, and
`pluginRegistry` / `barWidgetRegistry` as appropriate.
- Panel / overlay / menu plugins must expose `open(payloadJson)` and
`close()` lifecycle methods for `shell summon` and `shell hide`.
IPC:
- `bin/omarchy-shell` is the canonical IPC entry point. It forwards to
the running shell and does not start it. Prefer it over re-implementing
direct Quickshell socket calls in every CLI.
- The `shell` IPC target exposes `ping`, `summon`, `hide`, `toggle`,
`rescanPlugins`, `setPluginEnabled`, and `listPlugins`. Individual
plugins can register additional IPC targets (the bar registers `bar`,
the background switcher registers `image-selector`).
Widget files in `shell/plugins/bar/widgets/` contain Nerd Font glyphs as raw
unicode characters. The `Write` and `Edit` tools strip multi-byte
codepoints in some positions — do **not** rewrite widget files wholesale
through those tools. For glyph fixes, use the targeted `Edit` tool with
the surrounding context, or a Python script that inserts codepoints via
`chr(0xXXXXX)`.
- `themes/*/colors.toml` - theme color definitions (accent, background, foreground, color0-15)
# Refresh Pattern
@@ -171,23 +100,28 @@ To copy a default config to user config with automatic backup:
omarchy-refresh-config hypr/hyprlock.conf
```
This copies `/etc/skel/.config/hypr/hyprlock.conf` to `~/.config/hypr/hyprlock.conf`.
This copies `~/.local/share/omarchy/config/hypr/hyprlock.conf` to `~/.config/hypr/hyprlock.conf`.
# Migrations
Read `docs/migrations.md` before creating or changing migrations.
Migrations are per-user and run through `omarchy-migrate` during `omarchy update` or from the migration notification. Put migrations directly under `migrations/<timestamp>.sh`. Pending state is per-user under `~/.local/state/omarchy/migrations/`, so every user gets a chance to run every migration. Migrations run as the user; privileged work should invoke the appropriate helper or privilege prompt, and no-op when another user already applied it.
To create a new migration, run `omarchy-dev-add-migration --no-edit`.
To create a new migration, run `omarchy-dev-add-migration --no-edit`. This creates a migration file named after the unix timestamp of the last commit.
New migration format:
- File permissions must be `0644` (`-rw-r--r--`); migration runners execute them with `bash -euo pipefail`, not through executable bits
- File permissions must be `0644` (`-rw-r--r--`); migrations are sourced, not executed directly
- No shebang line
- Start with an `echo` describing what the migration does
- Use `$OMARCHY_PATH` to reference the omarchy directory
- Prefer helper commands such as `omarchy-cmd-present`, `omarchy-cmd-missing`, `omarchy-pkg-present`, and `omarchy-pkg-missing`
Omarchy 4.0 is upgraded through `bin/omarchy-upgrade-to-4`, not through the normal migration runner. Do not add compatibility migrations for old installer layouts; put pre-4 package-layout transition work in the upgrade command instead.
Some older migrations predate these rules. Do not copy older migrations that start with shebangs, omit the leading `echo`, or hard-code `~/.local/share/omarchy`.
Migrations may use raw `pacman`, `command -v`, or direct config edits when needed for one-off repair work.
Migrations may use raw `pacman`, `command -v`, or direct config edits when needed for historical compatibility or one-off repair work.
Example:
```bash
echo "Disable fingerprint in hyprlock if fingerprint auth is not configured"
if omarchy-cmd-missing fprintd-list || ! fprintd-list "$USER" 2>/dev/null | grep -q "finger"; then
sed -i 's/fingerprint:enabled = .*/fingerprint:enabled = false/' ~/.config/hypr/hyprlock.conf
fi
```
-4
View File
@@ -4,10 +4,6 @@ Omarchy is a beautiful, modern & opinionated Linux distribution by DHH.
Read more at [omarchy.org](https://omarchy.org).
## Docs
- [omarchy-shell](docs/omarchy-shell.md) — shell host, plugin manifest, IPC, `shell.json`, custom bar modules
## License
Omarchy is released under the [MIT License](https://opensource.org/licenses/MIT).
-8
View File
@@ -1,8 +0,0 @@
[Desktop Entry]
Version=1.0
Name=Basecamp
Exec=omarchy-launch-webapp https://launchpad.37signals.com
Terminal=false
Type=Application
Icon=basecamp
StartupNotify=true
-8
View File
@@ -1,8 +0,0 @@
[Desktop Entry]
Version=1.0
Name=ChatGPT
Exec=omarchy-launch-webapp https://chatgpt.com/
Terminal=false
Type=Application
Icon=chatgpt
StartupNotify=true
-8
View File
@@ -1,8 +0,0 @@
[Desktop Entry]
Version=1.0
Name=Discord
Exec=omarchy-launch-webapp https://discord.com/channels/@me
Terminal=false
Type=Application
Icon=omarchy-discord
StartupNotify=true
-8
View File
@@ -1,8 +0,0 @@
[Desktop Entry]
Version=1.0
Name=Disk Usage
Exec=xdg-terminal-exec --app-id=TUI.float -e bash -c "dua i /"
Terminal=false
Type=Application
Icon=disk-usage
StartupNotify=true
-8
View File
@@ -1,8 +0,0 @@
[Desktop Entry]
Version=1.0
Name=Docker
Exec=xdg-terminal-exec --app-id=TUI.tile -e lazydocker
Terminal=false
Type=Application
Icon=docker
StartupNotify=true
-8
View File
@@ -1,8 +0,0 @@
[Desktop Entry]
Version=1.0
Name=Figma
Exec=omarchy-launch-webapp https://figma.com/
Terminal=false
Type=Application
Icon=figma
StartupNotify=true
-8
View File
@@ -1,8 +0,0 @@
[Desktop Entry]
Version=1.0
Name=Fizzy
Exec=omarchy-launch-webapp https://app.fizzy.do/
Terminal=false
Type=Application
Icon=fizzy
StartupNotify=true
-8
View File
@@ -1,8 +0,0 @@
[Desktop Entry]
Version=1.0
Name=GitHub
Exec=omarchy-launch-webapp https://github.com/
Terminal=false
Type=Application
Icon=github
StartupNotify=true
-8
View File
@@ -1,8 +0,0 @@
[Desktop Entry]
Version=1.0
Name=Google Contacts
Exec=omarchy-launch-webapp https://contacts.google.com/
Terminal=false
Type=Application
Icon=google-contacts
StartupNotify=true
-8
View File
@@ -1,8 +0,0 @@
[Desktop Entry]
Version=1.0
Name=Google Maps
Exec=omarchy-launch-webapp https://maps.google.com
Terminal=false
Type=Application
Icon=google-maps
StartupNotify=true
-8
View File
@@ -1,8 +0,0 @@
[Desktop Entry]
Version=1.0
Name=Google Messages
Exec=omarchy-launch-webapp https://messages.google.com/web/conversations
Terminal=false
Type=Application
Icon=google-messages
StartupNotify=true
-8
View File
@@ -1,8 +0,0 @@
[Desktop Entry]
Version=1.0
Name=Google Photos
Exec=omarchy-launch-webapp https://photos.google.com/
Terminal=false
Type=Application
Icon=google-photos
StartupNotify=true
-9
View File
@@ -1,9 +0,0 @@
[Desktop Entry]
Version=1.0
Name=HEY
Exec=omarchy-webapp-handler-hey %u
Terminal=false
Type=Application
Icon=hey
StartupNotify=true
MimeType=x-scheme-handler/mailto
-8
View File
@@ -1,8 +0,0 @@
[Desktop Entry]
Version=1.0
Name=WhatsApp
Exec=omarchy-launch-webapp https://web.whatsapp.com/
Terminal=false
Type=Application
Icon=whatsapp
StartupNotify=true
-8
View File
@@ -1,8 +0,0 @@
[Desktop Entry]
Version=1.0
Name=X
Exec=omarchy-launch-webapp https://x.com/
Terminal=false
Type=Application
Icon=x
StartupNotify=true
-8
View File
@@ -1,8 +0,0 @@
[Desktop Entry]
Version=1.0
Name=YouTube
Exec=omarchy-launch-webapp https://youtube.com/
Terminal=false
Type=Application
Icon=youtube
StartupNotify=true
-9
View File
@@ -1,9 +0,0 @@
[Desktop Entry]
Version=1.0
Name=Zoom
Exec=omarchy-webapp-handler-zoom %u
Terminal=false
Type=Application
Icon=zoom
StartupNotify=true
MimeType=x-scheme-handler/zoommtg;x-scheme-handler/zoomus
-11
View File
@@ -1,11 +0,0 @@
[Desktop Entry]
Type=Application
Name=Battle.net
GenericName=Game Launcher
Comment=Blizzard game launcher (umu-launcher + GE-Proton)
Exec=omarchy-launch-battlenet
Icon=battle-net
Terminal=false
Categories=Game;
StartupNotify=true
StartupWMClass=battle.net.exe
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
+2
View File
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
+2
View File
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
+2
View File
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
+2
View File
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
+2
View File
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
+2
View File
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
+2
View File
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
+2
View File
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
+2
View File
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
+2
View File
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
+2
View File
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
+2
View File
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
+2
View File
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
+2
View File
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
+2
View File
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
+2
View File
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
+2
View File
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
+2
View File
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
+2
View File
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

+3 -14
View File
@@ -27,25 +27,19 @@ declare -A BINARY_TO_KEY
declare -A GROUP_DESCRIPTIONS
GROUP_DESCRIPTIONS[ac]="AC power detection"
GROUP_DESCRIPTIONS[audio]="Audio input and output controls"
GROUP_DESCRIPTIONS[battery]="Battery status helpers"
GROUP_DESCRIPTIONS[bluetooth]="Bluetooth device controls"
GROUP_DESCRIPTIONS[branch]="Omarchy git branch management"
GROUP_DESCRIPTIONS[branding]="About and screensaver branding"
GROUP_DESCRIPTIONS[brightness]="Display and keyboard brightness"
GROUP_DESCRIPTIONS[capture]="Screenshots and screen recording"
GROUP_DESCRIPTIONS[channel]="Omarchy release channel management"
GROUP_DESCRIPTIONS[clipboard]="Clipboard helpers"
GROUP_DESCRIPTIONS[cmd]="Command and shortcut helpers"
GROUP_DESCRIPTIONS[config]="System configuration helpers"
GROUP_DESCRIPTIONS[debug]="Diagnostics and support logs"
GROUP_DESCRIPTIONS[finalize]="Finalize user setup"
GROUP_DESCRIPTIONS[default]="Default application selection"
GROUP_DESCRIPTIONS[dev]="Omarchy development tools"
GROUP_DESCRIPTIONS[dns]="DNS resolver configuration"
GROUP_DESCRIPTIONS[drive]="Drive selection and encryption"
GROUP_DESCRIPTIONS[font]="Font management"
GROUP_DESCRIPTIONS[games]="Game launchers and helpers"
GROUP_DESCRIPTIONS[hibernation]="Hibernation setup and removal"
GROUP_DESCRIPTIONS[hook]="User hook runner"
GROUP_DESCRIPTIONS[hw]="Hardware detection and controls"
@@ -54,13 +48,9 @@ GROUP_DESCRIPTIONS[install]="Optional software installers"
GROUP_DESCRIPTIONS[launch]="Application launchers"
GROUP_DESCRIPTIONS[menu]="Omarchy menu commands"
GROUP_DESCRIPTIONS[migrate]="Migration runner"
GROUP_DESCRIPTIONS[monitor]="Monitor status helpers"
GROUP_DESCRIPTIONS[network]="Network status helpers"
GROUP_DESCRIPTIONS[notification]="Notification helpers"
GROUP_DESCRIPTIONS[mise]="Mise tool wrappers"
GROUP_DESCRIPTIONS[osd]="On-screen display status helpers"
GROUP_DESCRIPTIONS[npx]="NPX package wrappers"
GROUP_DESCRIPTIONS[pkg]="Package management helpers"
GROUP_DESCRIPTIONS[plugin]="Omarchy shell plugin and bar widget management"
GROUP_DESCRIPTIONS[plymouth]="Plymouth boot theme management"
GROUP_DESCRIPTIONS[powerprofiles]="Power profile management"
GROUP_DESCRIPTIONS[refresh]="Reset config to defaults"
@@ -69,12 +59,11 @@ GROUP_DESCRIPTIONS[reminder]="Desktop notification reminders"
GROUP_DESCRIPTIONS[remove]="Removal workflows"
GROUP_DESCRIPTIONS[restart]="Restart Omarchy components"
GROUP_DESCRIPTIONS[setup]="Interactive setup wizards"
GROUP_DESCRIPTIONS[shell]="Omarchy shell IPC helpers"
GROUP_DESCRIPTIONS[screensaver]="Screensaver branding and animation"
GROUP_DESCRIPTIONS[snapshot]="System snapshots"
GROUP_DESCRIPTIONS[style]="Global UI style controls"
GROUP_DESCRIPTIONS[sudo]="Sudo configuration helpers"
GROUP_DESCRIPTIONS[system]="System status, reboot, shutdown, logout, and lock"
GROUP_DESCRIPTIONS[swayosd]="SwayOSD status display helpers"
GROUP_DESCRIPTIONS[system]="Reboot, shutdown, logout, and lock"
GROUP_DESCRIPTIONS[theme]="Theme management"
GROUP_DESCRIPTIONS[toggle]="Toggle Omarchy features"
GROUP_DESCRIPTIONS[transcode]="Image and video transcoding"
+13 -5
View File
@@ -4,10 +4,18 @@
wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle >/dev/null
if wpctl get-volume @DEFAULT_AUDIO_SOURCE@ | grep -q MUTED; then
omarchy-brightness-keyboard-mute on
omarchy-osd -i microphone-muted -m "Microphone muted"
if pactl get-source-mute @DEFAULT_SOURCE@ | rg -q 'yes'; then
led=on
osd_message='Microphone muted'
osd_icon='microphone-sensitivity-muted-symbolic'
else
omarchy-brightness-keyboard-mute off
omarchy-osd -i microphone -m "Microphone on"
led=off
osd_message='Microphone on'
osd_icon='audio-input-microphone-symbolic'
fi
omarchy-brightness-keyboard-mute "$led"
omarchy-swayosd-client \
--custom-message "$osd_message" \
--custom-icon "$osd_icon"
-20
View File
@@ -1,20 +0,0 @@
#!/bin/bash
# omarchy:summary=Set the default audio input and move active streams
# omarchy:args=<node-id> <source-name>
# omarchy:examples=omarchy audio input set default 43 alsa_input.pci-0000_00_1f.3.analog-stereo
node_id=${1:-}
source_name=${2:-}
if [[ -z $node_id || -z $source_name ]]; then
echo "Usage: omarchy-audio-input-set-default <node-id> <source-name>" >&2
exit 1
fi
wpctl set-default "$node_id" 2>/dev/null || true
pactl set-default-source "$source_name" 2>/dev/null || true
pactl list short source-outputs 2>/dev/null | awk '{ print $1 }' | while read -r output; do
[[ -n $output ]] && pactl move-source-output "$output" "$source_name" 2>/dev/null || true
done
-20
View File
@@ -1,20 +0,0 @@
#!/bin/bash
# omarchy:summary=Set the default audio output and move active streams
# omarchy:args=<node-id> <sink-name>
# omarchy:examples=omarchy audio output set default 42 alsa_output.pci-0000_00_1f.3.analog-stereo
node_id=${1:-}
sink_name=${2:-}
if [[ -z $node_id || -z $sink_name ]]; then
echo "Usage: omarchy-audio-output-set-default <node-id> <sink-name>" >&2
exit 1
fi
timeout 2 wpctl set-default "$node_id" 2>/dev/null || true
timeout 2 pactl set-default-sink "$sink_name" 2>/dev/null || true
timeout 2 pactl list short sink-inputs 2>/dev/null | awk '{ print $1 }' | while read -r input; do
[[ -n $input ]] && timeout 2 pactl move-sink-input "$input" "$sink_name" 2>/dev/null || true
done
+34 -14
View File
@@ -1,17 +1,17 @@
#!/bin/bash
# omarchy:summary=Switch between audio outputs while preserving the mute status
# omarchy:summary=Switch between audio outputs while preserving the mute status. By default mapped to Super + Mute.
sinks=$(timeout 2 pactl -f json list sinks | jq '[.[] | select((.ports | length == 0) or ([.ports[]? | .availability != "not available"] | any))]')
sinks_count=$(jq 'length' <<<"$sinks")
sinks=$(pactl -f json list sinks | jq '[.[] | select((.ports | length == 0) or ([.ports[]? | .availability != "not available"] | any))]')
sinks_count=$(echo "$sinks" | jq '. | length')
if (( sinks_count == 0 )); then
omarchy-osd -m "No audio devices found"
omarchy-swayosd-client --custom-message "No audio devices found"
exit 1
fi
current_sink_name=$(timeout 2 pactl get-default-sink)
current_sink_index=$(jq -r --arg name "$current_sink_name" 'map(.name) | index($name)' <<<"$sinks")
current_sink_name=$(pactl get-default-sink)
current_sink_index=$(echo "$sinks" | jq -r --arg name "$current_sink_name" 'map(.name) | index($name)')
if [[ $current_sink_index != "null" ]]; then
next_sink_index=$(((current_sink_index + 1) % sinks_count))
@@ -19,13 +19,28 @@ else
next_sink_index=0
fi
next_sink=$(jq -c ".[$next_sink_index]" <<<"$sinks")
next_sink_name=$(jq -r '.name' <<<"$next_sink")
next_sink_description=$(jq -r '.description // .properties."device.description" // .name' <<<"$next_sink")
next_sink_volume=$(jq -r '.volume | to_entries[0].value.value_percent | sub("%"; "") | tonumber' <<<"$next_sink")
next_sink_is_muted=$(jq -r '.mute' <<<"$next_sink")
next_sink=$(echo "$sinks" | jq -r ".[$next_sink_index]")
next_sink_name=$(echo "$next_sink" | jq -r '.name')
if [[ $next_sink_is_muted == "true" ]] || (( next_sink_volume == 0 )); then
next_sink_description=$(echo "$next_sink" | jq -r '.description')
if [[ $next_sink_description == "(null)" ]] || [[ $next_sink_description == "null" ]] || [[ -z $next_sink_description ]]; then
# For Bluetooth devices, the friendly name is on the Device entry (device.id), not the Sink entry (object.id)
device_id=$(echo "$next_sink" | jq -r '.properties."device.id"')
if [[ $device_id != "null" ]] && [[ -n $device_id ]]; then
next_sink_description=$(wpctl status | grep -E "^\s*│?\s+${device_id}\." | sed -E 's/^.*[0-9]+\.\s+//' | sed -E 's/\s+\[.*$//')
fi
# Fall back to object.id lookup if device.id didn't yield a result
if [[ -z $next_sink_description ]]; then
sink_id=$(echo "$next_sink" | jq -r '.properties."object.id"')
next_sink_description=$(wpctl status | grep -E "\s+\*?\s+${sink_id}\." | sed -E 's/^.*[0-9]+\.\s+//' | sed -E 's/\s+\[.*$//')
fi
fi
next_sink_volume=$(echo "$next_sink" | jq -r \
'.volume | to_entries[0].value.value_percent | sub("%"; "")')
next_sink_is_muted=$(echo "$next_sink" | jq -r '.mute')
if [[ $next_sink_is_muted = "true" ]] || (( next_sink_volume == 0 )); then
icon_state="muted"
elif (( next_sink_volume <= 33 )); then
icon_state="low"
@@ -35,8 +50,13 @@ else
icon_state="high"
fi
next_sink_volume_icon="sink-volume-${icon_state}-symbolic"
if [[ $next_sink_name != $current_sink_name ]]; then
omarchy-audio-output-set-default "$(jq -r '.index' <<<"$next_sink")" "$next_sink_name"
next_sink_wpid=$(echo "$next_sink" | jq -r '.properties."object.id"')
wpctl set-default "$next_sink_wpid"
fi
omarchy-osd -i "volume-${icon_state}" -m "$next_sink_description"
omarchy-swayosd-client \
--custom-message "$next_sink_description" \
--custom-icon "$next_sink_volume_icon"
-67
View File
@@ -1,67 +0,0 @@
#!/bin/bash
# omarchy:summary=Adjust output volume and show the Omarchy OSD
# omarchy:args=<raise|lower|mute-toggle|+N|-N>
# omarchy:examples=omarchy audio output volume raise | omarchy audio output volume lower | omarchy audio output volume mute-toggle | omarchy audio output volume +1
action="${1:-}"
if [[ -z $action ]]; then
echo "Usage: omarchy-audio-output-volume <raise|lower|mute-toggle|+N|-N>"
exit 1
fi
volume_state() {
wpctl get-volume @DEFAULT_AUDIO_SINK@
}
volume_percent() {
volume_state | awk '{ for (i=1; i<=NF; i++) if ($i ~ /^[0-9.]+$/) print int($i * 100) }'
}
volume_muted() {
volume_state | grep -q MUTED
}
unmute_output() {
wpctl set-mute @DEFAULT_AUDIO_SINK@ 0 >/dev/null
}
case "$action" in
raise) action="+5" ;;
lower) action="-5" ;;
esac
if [[ $action == "mute-toggle" ]]; then
runtime_dir="${XDG_RUNTIME_DIR:-/tmp}"
debounce_file="$runtime_dir/omarchy-audio-output-volume-mute-toggle.last"
now=$(date +%s%3N)
last=0
[[ -r $debounce_file ]] && read -r last < "$debounce_file" || true
if (( now - last < 250 )); then
exit 0
fi
printf '%s\n' "$now" > "$debounce_file"
wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle >/dev/null
elif [[ $action == +* ]]; then
step="${action#+}"
unmute_output
wpctl set-volume -l 1.0 @DEFAULT_AUDIO_SINK@ "${step}%+"
elif [[ $action == -* ]]; then
step="${action#-}"
unmute_output
wpctl set-volume @DEFAULT_AUDIO_SINK@ "${step}%-"
else
echo "Unknown volume action: $action"
exit 1
fi
percent=$(volume_percent)
if volume_muted || (( percent == 0 )); then
icon="volume-muted"
else
icon="volume-high"
fi
omarchy-osd -i "$icon" -p "$percent"
-45
View File
@@ -1,45 +0,0 @@
#!/bin/bash
# omarchy:summary=Print PulseAudio sink availability for the shell
# omarchy:group=audio
pactl list sinks 2>/dev/null | awk '
function emit_sink() {
if (name == "") return
print name "\t" ((port_count == 0 || available) ? 1 : 0)
}
/^Sink #/ {
emit_sink()
name = ""
in_ports = 0
port_count = 0
available = 0
next
}
/^[[:space:]]*Name:/ {
name = $2
next
}
/^[[:space:]]*Ports:$/ {
in_ports = 1
next
}
in_ports && /^\tActive Port:/ {
in_ports = 0
next
}
in_ports && /^\t\t/ {
port_count++
if ($0 !~ /not available/) available = 1
next
}
END {
emit_sink()
}
'
-20
View File
@@ -1,20 +0,0 @@
#!/bin/bash
# omarchy:summary=Cycle to the next media source and transfer playback when the current source is playing
# omarchy:args=[next|previous]
# omarchy:examples=omarchy audio source switch | omarchy-audio-source-switch previous
direction="${1:-next}"
case "$direction" in
next)
omarchy-shell media sourceSwitch
;;
previous)
omarchy-shell media sourceSwitchPrevious
;;
*)
echo "Usage: omarchy-audio-source-switch [next|previous]" >&2
exit 1
;;
esac
-17
View File
@@ -1,17 +0,0 @@
#!/bin/bash
# omarchy:summary=Send the low battery warning notification and run battery-low hooks.
# omarchy:args=<percentage>
# omarchy:hidden=true
set -euo pipefail
if (($# != 1)); then
echo "Usage: omarchy-battery-low <percentage>" >&2
exit 1
fi
level=$1
omarchy-notification-send -g 󱐋 -u critical "Time to recharge!" "Battery is down to ${level}%" -i battery-caution -t 30000
omarchy-hook battery-low "$level"
+25
View File
@@ -0,0 +1,25 @@
#!/bin/bash
# omarchy:summary=Designed to be run by systemd timer every 30 seconds and alerts if battery is low
# omarchy:hidden=true
BATTERY_THRESHOLD=10
NOTIFICATION_FLAG="/run/user/$UID/omarchy_battery_notified"
BATTERY_LEVEL=$(omarchy-battery-remaining)
BATTERY_STATE=$(upower -i $(upower -e | grep 'BAT') | grep -E "state" | awk '{print $2}')
send_notification() {
notify-send -u critical "󱐋 Time to recharge!" "Battery is down to ${1}%" -i battery-caution -t 30000
omarchy-hook battery-low "$1"
}
if [[ -n $BATTERY_LEVEL && $BATTERY_LEVEL =~ ^[0-9]+$ ]]; then
if [[ $BATTERY_STATE == "discharging" ]] && (( BATTERY_LEVEL <= BATTERY_THRESHOLD )); then
if [[ ! -f $NOTIFICATION_FLAG ]]; then
send_notification $BATTERY_LEVEL
touch $NOTIFICATION_FLAG
fi
else
rm -f $NOTIFICATION_FLAG
fi
fi
+17 -98
View File
@@ -1,108 +1,27 @@
#!/bin/bash
# omarchy:summary=Returns a formatted battery status string with percentage and power draw/charge.
# omarchy:args=[--shell]
shell_output=false
battery_info=$(upower -i $(upower -e | grep BAT))
case "${1:-}" in
"")
;;
--shell)
shell_output=true
;;
*)
echo "Usage: omarchy-battery-status [--shell]" >&2
exit 2
;;
esac
percentage=$(echo "$battery_info" | awk '/percentage/ {
print int($2)
exit
}')
battery=$(upower -e 2>/dev/null | grep BAT | head -n 1)
[[ -z $battery ]] && exit 0
power_rate=$(echo "$battery_info" | awk '/energy-rate/ {
rounded = sprintf("%.1f", $2)
sub(/\.0$/, "", rounded)
print rounded
exit
}')
battery_info=$(upower -i "$battery")
state=$(echo "$battery_info" | awk '/state/ { print $2; exit }')
time_remaining=$(omarchy-battery-remaining-time)
capacity=$(omarchy-battery-capacity)
percentage=$(awk '/percentage/ { print int($2); exit }' <<<"$battery_info")
power_rate_raw=$(awk '/energy-rate/ { print $2; exit }' <<<"$battery_info")
power_rate=$(awk '/energy-rate/ {
rounded = sprintf("%.1f", $2)
sub(/\.0$/, "", rounded)
print rounded
exit
}' <<<"$battery_info")
state=$(awk '/state/ { print $2; exit }' <<<"$battery_info")
time_remaining=$(omarchy-battery-remaining-time 2>/dev/null)
capacity=$(omarchy-battery-capacity 2>/dev/null)
threshold_start=$(awk '/charge-start-threshold:/ { gsub(/%/, "", $2); print int($2); exit }' <<<"$battery_info")
threshold_end=$(awk '/charge-end-threshold:/ { gsub(/%/, "", $2); print int($2); exit }' <<<"$battery_info")
[[ -z $threshold_end ]] && threshold_end=$(cat /sys/class/power_supply/BAT*/charge_control_end_threshold 2>/dev/null | head -1)
[[ -z $threshold_start ]] && threshold_start=$(cat /sys/class/power_supply/BAT*/charge_control_start_threshold 2>/dev/null | head -1)
ac_online=false
for supply in /sys/class/power_supply/*; do
[[ -r $supply/type ]] || continue
[[ $(<"$supply/type") == "Mains" ]] || continue
[[ -r $supply/online ]] || continue
if [[ $(<"$supply/online") == "1" ]]; then
ac_online=true
break
fi
done
charge_idle=false
if awk -v rate="${power_rate_raw:-0}" 'BEGIN { exit !(rate <= 0.2) }'; then
charge_idle=true
fi
charge_holding=false
if [[ $ac_online == "true" && -n $threshold_end ]]; then
if [[ $state == "pending-charge" ]]; then
charge_holding=true
elif [[ $state == "fully-charged" ]] && (( percentage < 99 )); then
charge_holding=true
elif [[ $state == "charging" && $charge_idle == "true" ]] && (( threshold_end < 99 && percentage >= threshold_end )); then
charge_holding=true
fi
fi
if [[ $shell_output == "true" ]]; then
printf 'percentage\t%s\n' "${percentage}%"
if [[ $charge_holding == "true" ]]; then
printf 'state\tholding\n'
else
printf 'state\t%s\n' "$state"
fi
printf 'rate\t%s\n' "${power_rate}W"
printf 'size\t%s\n' "${capacity}Wh"
printf 'time\t%s\n' "$time_remaining"
cycles=$(cat /sys/class/power_supply/BAT*/cycle_count 2>/dev/null | head -1)
[[ -n $cycles ]] && printf 'cycles\t%s\n' "$cycles"
if [[ -n $threshold_end ]]; then
if [[ -n $threshold_start && $threshold_start != $threshold_end ]]; then
printf 'threshold\t%s-%s%%\n' "$threshold_start" "$threshold_end"
else
printf 'threshold\t%s%%\n' "$threshold_end"
fi
fi
exit 0
fi
if [[ $charge_holding == "true" ]]; then
if [[ -n $threshold_start && $threshold_start != $threshold_end ]]; then
threshold_label="${threshold_start}-${threshold_end}%"
else
threshold_label="${threshold_end}%"
fi
echo "Battery ${percentage}% · Holding at ${threshold_label} · ${power_rate}W / ${capacity}Wh"
elif [[ $state == "charging" ]]; then
echo "Battery ${percentage}% · ${time_remaining} to full ·  ${power_rate}W / ${capacity}Wh"
if [[ $state == "charging" ]]; then
echo "󰁹 Battery ${percentage}% · ${time_remaining} to full ·  ${power_rate}W / ${capacity}Wh"
else
echo "Battery ${percentage}% · ${time_remaining} left ·  ${power_rate}W / ${capacity}Wh"
echo "󰁹 Battery ${percentage}% · ${time_remaining} left ·  ${power_rate}W / ${capacity}Wh"
fi
-50
View File
@@ -1,50 +0,0 @@
#!/bin/bash
# omarchy:summary=Control a Bluetooth device
# omarchy:group=bluetooth
# omarchy:args=[pair|connect|disconnect|forget] <address>
# omarchy:examples=omarchy bluetooth device connect 00:11:22:33:44:55
set -e
usage() {
echo "Usage: omarchy-bluetooth-device [pair|connect|disconnect|forget] <address>" >&2
exit 1
}
action=${1:-}
address=${2:-}
[[ $action == "pair" || $action == "connect" || $action == "disconnect" || $action == "forget" ]] || usage
[[ $address =~ ^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$ ]] || usage
power_on() {
bluetoothctl power on >/dev/null 2>&1 || true
sleep 0.5
}
trust_device() {
bluetoothctl trust "$address" >/dev/null 2>&1 || true
}
case "$action" in
pair)
power_on
timeout 20s bluetoothctl pair "$address" >/dev/null 2>&1 || true
trust_device
timeout 20s bluetoothctl connect "$address" >/dev/null 2>&1 || true
;;
connect)
power_on
trust_device
timeout 20s bluetoothctl connect "$address" >/dev/null 2>&1 || true
;;
disconnect)
timeout 10s bluetoothctl disconnect "$address" >/dev/null 2>&1 || true
;;
forget)
power_on
timeout 10s bluetoothctl disconnect "$address" >/dev/null 2>&1 || true
timeout 10s bluetoothctl remove "$address" >/dev/null 2>&1 || true
;;
esac
+18
View File
@@ -0,0 +1,18 @@
#!/bin/bash
# omarchy:summary=Set the branch for Omarchy's git repository.
# omarchy:args=<master|rc|dev>
if (($# == 0)); then
echo "Usage: omarchy-branch-set [master|rc|dev]"
exit 1
else
branch="$1"
fi
if [[ $branch != "master" && $branch != "rc" && $branch != "dev" ]]; then
echo "Error: Invalid branch '$branch'. Must be one of: master, rc, dev"
exit 1
fi
git -C $OMARCHY_PATH switch $branch
+2 -4
View File
@@ -8,12 +8,10 @@
set -euo pipefail
SOURCE_DIR="${XDG_PICTURES_DIR:-$HOME/Pictures}"
case "${1:-}" in
image)
image=$(omarchy-menu-file "Pick png/svg from $SOURCE_DIR" "${SOURCE_DIR}" "svg png")
if [[ -n $image ]] && omarchy-transcode-ascii "$image" ~/.config/omarchy/branding/about.txt --width 54 --height 26; then
image=$(omarchy-menu-file "Logo image" "$HOME" "svg png")
if [[ -n $image ]] && omarchy-transcode-ascii "$image" ~/.config/omarchy/branding/about.txt --width 54 --height 26 --mode block; then
omarchy-launch-about >/dev/null 2>&1
fi
;;
+1 -3
View File
@@ -8,11 +8,9 @@
set -euo pipefail
SOURCE_DIR="${XDG_PICTURES_DIR:-$HOME/Pictures}"
case "${1:-}" in
image)
image=$(omarchy-menu-file "Pick png/svg from $SOURCE_DIR" "${SOURCE_DIR}" "svg png")
image=$(omarchy-menu-file "Logo image" "$HOME" "svg png")
if [[ -n $image ]] && omarchy-transcode-ascii "$image" ~/.config/omarchy/branding/screensaver.txt; then
omarchy-launch-screensaver force >/dev/null 2>&1
fi
+17 -49
View File
@@ -1,67 +1,35 @@
#!/bin/bash
# omarchy:summary=Show or adjust brightness on the most likely display device.
# omarchy:args=[--no-osd] [+N%|N%-|N%|off|on]
# omarchy:examples=omarchy brightness display | omarchy brightness display +5% | omarchy brightness display --no-osd 50% | omarchy brightness display off | omarchy brightness display on
# omarchy:summary=Adjust brightness on the most likely display device.
# omarchy:args=<+N%|N%-|N%|off|on>
# omarchy:examples=omarchy brightness display +5% | omarchy brightness display 5%- | omarchy brightness display 50% | omarchy brightness display off | omarchy brightness display on
no_osd=0
args=()
step="${1:-+5%}"
for arg in "$@"; do
if [[ $arg == "--no-osd" ]]; then
no_osd=1
else
args+=("$arg")
# Start with the first possible output, then refine to the most likely given an order heuristic.
device="$(ls -1 /sys/class/backlight 2>/dev/null | head -n1)"
for candidate in amdgpu_bl* intel_backlight acpi_video*; do
if [[ -e /sys/class/backlight/$candidate ]]; then
device="$candidate"
break
fi
done
set -- "${args[@]}"
# Get the brightness of the passed display
display_brightness() {
brightnessctl -d "$1" -m 2>/dev/null | awk -F, '{ gsub("%", "", $4); print $4; found=1 } END{ exit !found }'
}
if (( $# == 0 )); then
if omarchy-hyprland-monitor-focused-apple; then
omarchy-brightness-display-apple
exit
fi
device="$(omarchy-hw-display)" || exit 1
display_brightness "$device"
exit
fi
step="$1"
if [[ $step == "off" ]]; then
hyprctl dispatch 'hl.dsp.dpms({ action = "disable" })' >/dev/null 2>&1
hyprctl dispatch dpms off >/dev/null 2>&1
exit 0
elif [[ $step == "on" ]]; then
hyprctl dispatch 'hl.dsp.dpms({ action = "enable" })' >/dev/null 2>&1
hyprctl dispatch dpms on >/dev/null 2>&1
exit 0
fi
# Drop overlapping brightness key events so concurrent invocations do not race.
# Hardware key repeat present on some devices can otherwise glitch OSD rendering.
exec {lock_fd}>"${XDG_RUNTIME_DIR:-/tmp}/omarchy-brightness-display.lock"
flock -n "$lock_fd" || exit 0
if omarchy-hyprland-monitor-focused-apple; then
if (( no_osd )); then
omarchy-brightness-display-apple --no-osd "$step"
else
omarchy-brightness-display-apple "$step"
fi
omarchy-brightness-display-apple "$step"
exit
fi
# Current device highlighted
device="$(omarchy-hw-display)" || exit 1
# Current brightness percentage
current=$(display_brightness "$device") || exit 1
current=$(brightnessctl -d "$device" -m | cut -d',' -f4 | tr -d '%')
# Apply non-uniform step size: 1% steps if at or below 5%, otherwise set an
# absolute target percentage to avoid raw backlight rounding causing uneven OSD steps.
@@ -85,8 +53,8 @@ elif [[ $step == "5%-" ]]; then
step="$target%"
fi
# Set brightness of the display device.
# Set the actual brightness of the display device.
brightnessctl -d "$device" set "$step" >/dev/null
# Show the new brightness in OSD
(( no_osd )) || omarchy-osd -i brightness -p "$(display_brightness "$device")"
# Use SwayOSD to display the new brightness setting.
omarchy-swayosd-brightness "$(brightnessctl -d "$device" -m | cut -d',' -f4 | tr -d '%')"
+18 -85
View File
@@ -1,101 +1,34 @@
#!/bin/bash
# omarchy:summary=Show or adjust Apple Studio Display and Apple XDR Display brightness using asdcontrol.
# omarchy:args=[--no-osd] [+N%|N%-|N%]
# omarchy:examples=omarchy brightness display apple | omarchy brightness display apple +5% | omarchy brightness display apple --no-osd 50%
# omarchy:summary=Adjust the brightness on Apple Studio Displays and Apple XDR Displays using asdcontrol.
# omarchy:args=<+N%|N%-|N%>
# omarchy:examples=omarchy brightness display apple +5% | omarchy brightness display apple 5%- | omarchy brightness display apple 50%
device_cache="${XDG_RUNTIME_DIR:-/tmp}/omarchy-brightness-display-apple.device"
no_osd=0
args=()
for arg in "$@"; do
if [[ $arg == "--no-osd" ]]; then
no_osd=1
else
args+=("$arg")
if (( $# == 0 )); then
echo "Adjust Apple Display brightness by passing +5%, 5%-, or 100%"
else
step="$1"
if [[ $step =~ ^([0-9]+)%-$ ]]; then
step="-${BASH_REMATCH[1]}%"
fi
done
set -- "${args[@]}"
detect_apple_display_device() {
local devices=()
local path=""
devices=()
for path in /dev/usb/hiddev* /dev/hiddev*; do
[[ -e $path ]] && devices+=("$path")
done
(( ${#devices[@]} > 0 )) || return 1
sudo asdcontrol --detect "${devices[@]}" 2>/dev/null | awk -F: '/^\/dev\/(usb\/)?hiddev/{ print $1; exit }'
}
find_apple_display_device() {
local cached=""
local device=""
if [[ -r $device_cache ]]; then
read -r cached <"$device_cache" || true
if [[ -n $cached && -e $cached ]]; then
printf '%s\n' "$cached"
return 0
fi
fi
device="$(detect_apple_display_device)" || return 1
[[ -n $device ]] || return 1
printf '%s\n' "$device" >"$device_cache"
printf '%s\n' "$device"
}
current_brightness() {
local device="$1"
sudo asdcontrol "$device" 2>/dev/null | awk -F= '
/BRIGHTNESS=/ {
print int($2 * 100 / 60000)
found = 1
}
END { exit !found }
'
}
retry_with_fresh_device() {
rm -f "$device_cache"
device="$(find_apple_display_device || true)"
if [[ -z $device ]]; then
echo "No Apple Display HID device found" >&2
if (( ${#devices[@]} == 0 )); then
echo "No Apple Display HID device found"
exit 1
fi
}
device="$(find_apple_display_device || true)"
if [[ -z $device ]]; then
echo "No Apple Display HID device found" >&2
exit 1
fi
if (( $# == 0 )); then
if current_brightness "$device"; then
exit
else
retry_with_fresh_device
current_brightness "$device"
exit
device="$(sudo asdcontrol --detect "${devices[@]}" | grep -E '^/dev/(usb/)?hiddev' | cut -d: -f1 | head -n1)"
if [[ -z $device ]]; then
echo "No Apple Display HID device found"
exit 1
fi
fi
step="$1"
if [[ $step =~ ^([0-9]+)%-$ ]]; then
step="-${BASH_REMATCH[1]}%"
fi
if ! sudo asdcontrol "$device" -- "$step" >/dev/null; then
retry_with_fresh_device
sudo asdcontrol "$device" -- "$step" >/dev/null
value="$(sudo asdcontrol "$device" | awk -F= '/BRIGHTNESS=/{print $2+0}')"
omarchy-swayosd-brightness "$(( value * 100 / 60000 ))"
fi
(( no_osd )) || omarchy-osd -i brightness -p "$(current_brightness "$device")"
+5 -15
View File
@@ -1,20 +1,7 @@
#!/bin/bash
# omarchy:summary=Adjust keyboard backlight brightness using available steps.
# omarchy:args=[--no-osd] <up|down|cycle|off|restore>
no_osd=0
args=()
for arg in "$@"; do
if [[ $arg == "--no-osd" ]]; then
no_osd=1
else
args+=("$arg")
fi
done
set -- "${args[@]}"
# omarchy:args=<up|down|cycle|off|restore>
direction="${1:-up}"
@@ -62,4 +49,7 @@ fi
# Set the new brightness.
brightnessctl -d "$device" set "$new_brightness" >/dev/null
(( no_osd )) || omarchy-osd -i keyboard -p "$(( new_brightness * 100 / max_brightness ))"
# Use SwayOSD to display the new brightness setting.
percent=$((new_brightness * 100 / max_brightness))
omarchy-swayosd-kbd-brightness "$percent"
+5 -12
View File
@@ -2,7 +2,7 @@
# omarchy:summary=Start or stop screen recording
# omarchy:group=capture
# omarchy:args=[--fullscreen] [--with-desktop-audio] [--with-microphone-audio] [--with-webcam] [--webcam-device=<device>] [--resolution=<size>] [--stop-recording]
# omarchy:args=[--with-desktop-audio] [--with-microphone-audio] [--with-webcam] [--webcam-device=<device>] [--resolution=<size>] [--stop-recording]
# omarchy:examples=omarchy screenrecord | omarchy capture screenrecord --with-desktop-audio
# omarchy:aliases=omarchy screenrecord
#
@@ -31,7 +31,6 @@ MICROPHONE_AUDIO="false"
WEBCAM="false"
WEBCAM_DEVICE=""
RESOLUTION=""
FULLSCREEN="false"
STOP_RECORDING="false"
RECORDING_FILE="/tmp/omarchy-screenrecord-filename"
LOG_FILE=$([[ ${OMARCHY_SCREENRECORD_DEBUG:-false} == "true" ]] && echo "/tmp/omarchy-screenrecord.log" || echo "/dev/null")
@@ -43,7 +42,6 @@ for arg in "$@"; do
--with-webcam) WEBCAM="true" ;;
--webcam-device=*) WEBCAM_DEVICE="${arg#*=}" ;;
--resolution=*) RESOLUTION="${arg#*=}" ;;
--fullscreen) FULLSCREEN="true" ;;
--stop-recording) STOP_RECORDING="true" ;;
esac
done
@@ -169,10 +167,7 @@ start_screenrecording() {
# the portal backend supports and the kms backend doesn't). Default flow uses
# slurp + the kms backend, which avoids the EGL DMA-BUF modifier import
# failures the portal path can hit on some configurations.
if [[ $FULLSCREEN == "true" ]]; then
target="monitor:$(omarchy-hyprland-monitor-focused)"
capture_args=(-w "${target#monitor:}" -s "${RESOLUTION:-$(default_resolution)}")
elif [[ ${OMARCHY_SCREENRECORD_USE_PORTAL:-false} == "true" ]]; then
if [[ ${OMARCHY_SCREENRECORD_USE_PORTAL:-false} == "true" ]]; then
target="portal"
capture_args=(-w portal -s "${RESOLUTION:-$(default_resolution)}")
else
@@ -238,16 +233,14 @@ stop_screenrecording() {
else
finalize_recording
local filename=$(cat "$RECORDING_FILE" 2>/dev/null)
echo "$filename"
local preview="${filename%.mp4}-preview.png"
# Generate a preview thumbnail from the first frame
ffmpeg -y -i "$filename" -ss 00:00:00.1 -vframes 1 -q:v 2 "$preview" -loglevel quiet 2>/dev/null
(
if [[ -n $(omarchy-notification-send "Screen recording saved" "Open with Super + Alt + , (or click this)" -t 10000 --image "${preview:-$filename}" -a) ]]; then
mpv "$filename"
fi
ACTION=$(notify-send "Screen recording saved" "Open with Super + Alt + , (or click this)" -t 10000 -i "${preview:-$filename}" -A "default=open")
[[ $ACTION == "default" ]] && mpv "$filename"
rm -f "$preview"
) &
fi
@@ -256,7 +249,7 @@ stop_screenrecording() {
}
toggle_screenrecording_indicator() {
omarchy-shell -q Indicators refresh
pkill -RTMIN+8 waybar
}
screenrecording_active() {
@@ -1,35 +0,0 @@
#!/bin/bash
# omarchy:summary=Pick a webcam and start a screen recording with it
# omarchy:examples=omarchy capture screenrecording-with-webcam
set -o pipefail
webcam_list() {
v4l2-ctl --list-devices 2>/dev/null | while IFS= read -r line; do
if [[ $line != $'\t'* && -n $line ]]; then
local name="$line"
local device
IFS= read -r device || break
device=$(tr -d '\t' <<<"$device" | head -1)
[[ -n $device ]] && echo "$device $name"
fi
done
}
mapfile -t devices < <(webcam_list)
if (( ${#devices[@]} == 0 )); then
omarchy-notification-send "No webcam devices found" -u critical -t 3000
exit 1
fi
if (( ${#devices[@]} == 1 )); then
device="${devices[0]%%[[:space:]]*}"
else
selection=$(omarchy-menu-select "Select Webcam" "${devices[@]}" -- --width 520 --maxheight 520) || exit 1
device="${selection%%[[:space:]]*}"
fi
exec omarchy-capture-screenrecording \
--with-desktop-audio --with-microphone-audio \
--with-webcam --webcam-device="$device"
+22 -23
View File
@@ -2,7 +2,7 @@
# omarchy:summary=Take a screenshot
# omarchy:group=capture
# omarchy:args=[smart|region|windows|fullscreen] [slurp|copy|save] [--editor=<name>]
# omarchy:args=[smart|region|windows|fullscreen] [slurp|copy] [--editor=<name>]
# omarchy:examples=omarchy screenshot | omarchy capture screenshot region
# omarchy:aliases=omarchy screenshot
@@ -11,12 +11,12 @@ OUTPUT_DIR="${OMARCHY_SCREENSHOT_DIR:-${XDG_PICTURES_DIR:-$HOME/Pictures}}"
if [[ ! -d $OUTPUT_DIR ]]; then
mkdir -p "$OUTPUT_DIR"
omarchy-notification-send "Created screenshot directory: $OUTPUT_DIR" -t 2000
notify-send "Created screenshot directory: $OUTPUT_DIR" -u normal -t 2000
fi
pkill slurp && exit 0
SCREENSHOT_EDITOR="${OMARCHY_SCREENSHOT_EDITOR:-tensaku-edit}"
SCREENSHOT_EDITOR="${OMARCHY_SCREENSHOT_EDITOR:-satty}"
# Parse --editor flag from any position
ARGS=()
@@ -31,7 +31,15 @@ set -- "${ARGS[@]}"
open_editor() {
local filepath="$1"
"$SCREENSHOT_EDITOR" "$filepath"
if [[ $SCREENSHOT_EDITOR == "satty" ]]; then
satty --filename "$filepath" \
--output-filename "$filepath" \
--actions-on-enter save-to-clipboard \
--save-after-copy \
--copy-command 'wl-copy'
else
$SCREENSHOT_EDITOR "$filepath"
fi
}
MODE="${1:-smart}"
@@ -118,23 +126,14 @@ esac
FILENAME="screenshot-$(date +'%Y-%m-%d_%H-%M-%S').png"
FILEPATH="$OUTPUT_DIR/$FILENAME"
case "$PROCESSING" in
slurp)
grim -g "$SELECTION" "$FILEPATH" || exit 1
echo "$FILEPATH"
wl-copy --type image/png <"$FILEPATH"
if [[ $PROCESSING == "slurp" ]]; then
grim -g "$SELECTION" "$FILEPATH" || exit 1
wl-copy <"$FILEPATH"
(
if [[ -n $(omarchy-notification-send "Screenshot saved to clipboard and file" "Edit with Super + Alt + , (or click this)" -t 10000 --image "$FILEPATH" -a) ]]; then
open_editor "$FILEPATH"
fi
) >/dev/null 2>&1 &
;;
copy)
grim -g "$SELECTION" - | wl-copy --type image/png
;;
save)
grim -g "$SELECTION" "$FILEPATH" || exit 1
echo "$FILEPATH"
;;
esac
(
ACTION=$(notify-send "Screenshot saved to clipboard and file" "Edit with Super + Alt + , (or click this)" -t 10000 -i "$FILEPATH" -A "default=edit")
[[ $ACTION == "default" ]] && open_editor "$FILEPATH"
) &
else
grim -g "$SELECTION" - | wl-copy
fi
+1 -1
View File
@@ -23,4 +23,4 @@ TEXT=$(grim -g "$SELECTION" - | tesseract stdin stdout --oem 1 --psm 6 -l "${OMA
[[ -z $TEXT ]] && exit 1
printf "%s" "$TEXT" | wl-copy
omarchy-notification-send -g 󰴑 "Copied text from selection to clipboard"
notify-send "󰴑 Copied text from selection to clipboard"
-33
View File
@@ -1,33 +0,0 @@
#!/bin/bash
# omarchy:summary=Print the active Omarchy package channel
set -euo pipefail
conf=${OMARCHY_CONFIG_FILE:-/etc/omarchy.conf}
omarchy_path=${OMARCHY_PATH:-/usr/share/omarchy}
if [[ -r $conf ]]; then
configured_path=$(bash -c 'source "$1"; printf "%s\n" "${OMARCHY_PATH:-}"' bash "$conf" 2>/dev/null || true)
[[ -n $configured_path ]] && omarchy_path="$configured_path"
fi
channel=$(omarchy-version-channel 2>/dev/null | awk '{ print $1 }')
if pacman -Q omarchy-dev omarchy-settings-dev >/dev/null 2>&1; then
case "$channel" in
rc) echo rc ;;
edge)
if [[ $omarchy_path == "/usr/share/omarchy" ]]; then
echo dev
else
echo edge
fi
;;
*) echo unknown ;;
esac
elif pacman -Q omarchy omarchy-settings >/dev/null 2>&1 && [[ $channel == "stable" ]]; then
echo stable
else
echo unknown
fi
+13 -114
View File
@@ -1,123 +1,22 @@
#!/bin/bash
# omarchy:summary=Set the Omarchy package channel.
# omarchy:args=<stable|rc|dev|edge>
# omarchy:summary=Set the Omarchy channel, which dictates what git branch and package repository is used.
# omarchy:args=<stable|rc|edge|dev>
# omarchy:requires-sudo=true
set -euo pipefail
usage() { echo "Usage: omarchy-channel-set [stable|rc|dev|edge]"; }
fail() { echo "Error: $*" >&2; exit 1; }
confirm_edge() {
cat <<'WARNING'
Edge links Omarchy directly to a mutable source checkout.
This disables package-based protections for the Omarchy code path, including
normal package updates and package-backed snapshot restores. You'll be
responsible for pulling, fixing, and restoring that checkout yourself.
WARNING
if omarchy-cmd-present gum; then
gum confirm --default=false "Enable Edge anyway?"
else
local answer=""
read -r -p "Enable Edge anyway? [y/N] " answer
[[ $answer == "y" || $answer == "Y" || $answer == "yes" || $answer == "YES" ]]
fi
}
choose_edge_checkout() {
local default_path="$HOME/Work/omarchy"
local path="${OMARCHY_EDGE_PATH:-}"
if [[ -z $path ]]; then
if omarchy-cmd-present gum; then
path=$(gum input --value "$default_path" --placeholder "$default_path" --header "Where should Edge checkout live? Existing non-checkout paths will not be overwritten.") || exit 1
else
read -r -p "Edge checkout path [$default_path]: " path
fi
fi
path="${path:-$default_path}"
case "$path" in
"~") path="$HOME" ;;
"~/"*) path="$HOME/${path#~/}" ;;
/*) ;;
*) path="$PWD/$path" ;;
esac
if [[ -e $path && ! -d $path/.git ]]; then
fail "$path already exists and is not a git checkout. Choose an empty path or an existing Omarchy checkout."
fi
if [[ -d $path/.git && ( ! -d $path/bin || ! -d $path/default || ! -d $path/shell ) ]]; then
fail "$path is a git checkout, but it does not look like Omarchy."
fi
printf '%s\n' "$path"
}
sync_edge_checkout() {
local checkout="$1"
if [[ -d $checkout/.git ]]; then
echo "Updating Edge checkout at $checkout"
git -C "$checkout" fetch origin quattro
git -C "$checkout" checkout quattro 2>/dev/null || git -C "$checkout" checkout --track origin/quattro
git -C "$checkout" pull --ff-only origin quattro
else
mkdir -p "$(dirname -- "$checkout")"
git clone --branch quattro --single-branch https://github.com/basecamp/omarchy.git "$checkout"
fi
omarchy-dev-link "$checkout"
}
(( $# > 0 )) || { usage; exit 1; }
edge_checkout=""
channel="$1"
if (($# == 0)); then
echo "Usage: omarchy-channel-set [stable|rc|edge|dev]"
exit 1
else
channel="$1"
fi
case "$channel" in
stable)
pacman_channel=stable
packages=(omarchy omarchy-settings)
;;
rc)
pacman_channel=rc
packages=(omarchy-dev omarchy-settings-dev)
;;
dev)
pacman_channel=edge
packages=(omarchy-dev omarchy-settings-dev)
;;
edge|source)
confirm_edge || { echo "Cancelled."; exit 0; }
edge_checkout=$(choose_edge_checkout)
pacman_channel=edge
packages=(omarchy-dev omarchy-settings-dev)
;;
*)
echo "Unknown channel: $channel" >&2
usage >&2
exit 1
;;
"stable") omarchy-branch-set "master" && omarchy-refresh-pacman "stable" ;;
"rc") omarchy-branch-set "rc" && omarchy-refresh-pacman "rc" ;;
"edge") omarchy-branch-set "master" && omarchy-refresh-pacman "edge" ;;
"dev") omarchy-branch-set "dev" && omarchy-refresh-pacman "edge" ;;
*) echo "Unknown channel: $channel"; exit 1; ;;
esac
omarchy-refresh-pacman "$pacman_channel"
# --ask 4 accepts omarchy <-> omarchy-dev replacement prompts without file overwrites.
sudo env OMARCHY_UPDATE_PACMAN=1 pacman -S --needed --noconfirm --ask 4 "${packages[@]}"
if [[ -z $edge_checkout ]] && omarchy-cmd-present omarchy-dev-unlink; then
omarchy-dev-unlink
export OMARCHY_PATH=/usr/share/omarchy
fi
omarchy-update -y
if [[ -n $edge_checkout ]]; then
sync_edge_checkout "$edge_checkout"
fi
-136
View File
@@ -1,136 +0,0 @@
#!/bin/bash
# omarchy:summary=Native messaging host: download the URL sent by the yt-dlp Chromium extension
# omarchy:hidden=true
set -euo pipefail
SCRIPT_PATH="${BASH_SOURCE[0]}"
# The browser launches us without Omarchy's environment, so locate the repo from
# our own path when OMARCHY_PATH isn't already set. Export it — omarchy-shell (used
# by omarchy-osd) needs it to find the running shell, and silently no-ops without it.
export OMARCHY_PATH="${OMARCHY_PATH:-$(cd -- "$(dirname -- "$SCRIPT_PATH")/.." && pwd)}"
# Make sure the Omarchy bin and yt-dlp are reachable when launched by the browser.
export PATH="$OMARCHY_PATH/bin:/usr/local/bin:/usr/bin:$PATH"
DOWNLOAD_DIR="${OMARCHY_YTDLP_DIR:-$HOME/Videos}"
parse_url() {
jq -r '.url // empty' 2>/dev/null <<<"$1" || true
}
valid_url() {
[[ $1 =~ ^https?:// ]]
}
# Drive the Quickshell OSD — a single overlay that updates in place (like the
# volume/brightness bar), so download progress never stacks like notifications.
osd_progress() {
omarchy-osd -i 󰇚 -p "$1" -d 8000 >/dev/null 2>&1 || true
}
osd_close() {
omarchy-shell -q osd close >/dev/null 2>&1 || true
}
download_url() {
local url="$1"
mkdir -p "$DOWNLOAD_DIR"
# Don't show anything until yt-dlp confirms there's actually a video to grab.
if ! yt-dlp --no-playlist --simulate --quiet --no-warnings "$url" >/dev/null 2>&1; then
omarchy-notification-send -u critical -g 󰅖 "No video found for download" "$url"
exit 0
fi
osd_progress 0
# Stream the download: OMARCHY_PROG carries the percent (drives the OSD),
# OMARCHY_FILE (printed only after a successful move) carries title + path.
local line rest pct intpct last="" er nowms lastms=0 title="" filepath=""
while IFS= read -r line; do
case $line in
OMARCHY_PROG*)
pct=${line#OMARCHY_PROG$'\t'}
intpct=${pct%%.*}
intpct=${intpct//[^0-9]/}
[[ -n $intpct && $intpct != "$last" ]] || continue # skip no-op repeats
# Throttle to ~4 redraws/sec so fast downloads don't spawn a flurry of processes.
er=$EPOCHREALTIME
nowms=$((${er%[.,]*} * 1000 + 10#${er##*[.,]} / 1000))
((nowms - lastms >= 250)) || continue
last=$intpct
lastms=$nowms
osd_progress "$intpct"
;;
OMARCHY_FILE*)
rest=${line#OMARCHY_FILE$'\t'}
title=${rest%%$'\t'*}
filepath=${rest#*$'\t'}
;;
esac
done < <(PYTHONUNBUFFERED=1 yt-dlp --no-playlist --restrict-filenames --no-simulate \
--quiet --no-warnings --progress --newline \
--progress-template $'download:OMARCHY_PROG\t%(progress._percent_str)s' \
--paths "$DOWNLOAD_DIR" -o '%(title)s [%(id)s].%(ext)s' \
--print $'after_move:OMARCHY_FILE\t%(title)s\t%(filepath)s' \
"$url" 2>&1)
osd_close
# after_move only prints on a successful download+move, so a captured path == success.
if [[ -n $filepath ]]; then
((${#title} > 50)) && title="${title:0:50}…" # keep the toast compact
# Square, center-cropped thumbnail so the notification preview isn't stretched.
local preview
preview="$(mktemp --suffix=.jpg)"
ffmpeg -y -i "$filepath" -ss 00:00:00.1 -vframes 1 \
-vf "crop='min(iw,ih)':'min(iw,ih)',scale=256:256" -q:v 2 \
"$preview" -loglevel quiet 2>/dev/null || true
# Clicking the toast opens the video in mpv (-a blocks until clicked or timed out).
(
if [[ -n $(omarchy-notification-send -g 󰄬 "Download complete" "$title" -t 10000 --image "${preview:-$filepath}" -a) ]]; then
mpv "$filepath"
fi
rm -f "$preview"
) &
else
omarchy-notification-send -u critical -g 󰅖 "Download failed" "$url"
fi
exit 0
}
main() {
local length payload url
# Detached worker: this is what actually runs yt-dlp and fires notifications.
if [[ "${1:-}" == "--download" ]]; then
download_url "$2"
fi
# Native messaging frame: 4-byte little-endian length prefix, then UTF-8 JSON.
length=$(head -c4 | od -An -v -tu4 --endian=little | tr -d ' ')
[[ -n ${length:-} ]] && ((length > 0)) || exit 0
payload=$(head -c "$length")
# Ack with an empty message so the extension's sendNativeMessage callback resolves cleanly.
printf '\x02\x00\x00\x00{}'
url=$(parse_url "$payload")
[[ -n $url ]] || exit 0
valid_url "$url" || exit 0
# Detach the download so this host exits promptly and frees the browser's port.
setsid -f "$SCRIPT_PATH" --download "$url" </dev/null >/dev/null 2>&1
}
if [[ ${BASH_SOURCE[0]} == "$0" ]]; then
main "$@"
fi
-69
View File
@@ -1,69 +0,0 @@
#!/bin/bash
# omarchy:summary=Open a clipboard history entry
# omarchy:group=clipboard
# omarchy:args=--history-index <index>
history_index=""
history_path="$HOME/.local/state/omarchy/clipboard-history.json"
while [[ $# -gt 0 ]]; do
case "$1" in
--history-index)
history_index="${2:-}"
shift 2
;;
*)
echo "Usage: omarchy-clipboard-open --history-index <index>" >&2
exit 1
;;
esac
done
[[ $history_index =~ ^[0-9]+$ ]] || exit 1
[[ -r $history_path ]] || exit 1
entry_type=$(jq -er --argjson index "$history_index" '.[$index].type' "$history_path") || exit 1
open_image() {
local path="$1"
[[ -r $path ]] || exit 1
exec tensaku-edit "$path"
}
open_text() {
local text="$1"
local url=""
local open_dir=""
local open_file=""
url=$(grep -Eom1 'https?://[^[:space:]"'\''<>]+' <<<"$text" || true)
if [[ -z $url && $text =~ ^[[:space:]]*([[:alnum:]][[:alnum:].-]+\.[[:alpha:]]{2,})(/[^[:space:]]*)?[[:space:]]*$ ]]; then
url="https://${BASH_REMATCH[1]}${BASH_REMATCH[2]}"
fi
if [[ -n $url ]]; then
exec omarchy-launch-browser "$url"
fi
open_dir="${XDG_STATE_HOME:-$HOME/.local/state}/omarchy/clipboard-open"
mkdir -p "$open_dir"
open_file=$(mktemp --tmpdir="$open_dir" clipboard.XXXXXX.txt) || exit 1
printf '%s' "$text" >"$open_file"
exec omarchy-launch-editor "$open_file"
}
case "$entry_type" in
image)
path=$(jq -er --argjson index "$history_index" '.[$index].path' "$history_path") || exit 1
open_image "$path"
;;
text)
text=$(jq -er --argjson index "$history_index" '.[$index].text' "$history_path") || exit 1
open_text "$text"
;;
*)
exit 1
;;
esac
-32
View File
@@ -1,32 +0,0 @@
#!/bin/bash
# omarchy:summary=Copy a file to the clipboard and paste it
# omarchy:group=clipboard
# omarchy:args=[--copy-only] <mime-type> <path>
# omarchy:examples=omarchy clipboard paste file image/png /tmp/screenshot.png
copy_only=false
if [[ ${1:-} == "--copy-only" ]]; then
copy_only=true
shift
fi
mime=${1:-}
path=${2:-}
if [[ -z $mime || -z $path ]]; then
echo "Usage: omarchy-clipboard-paste-file [--copy-only] <mime-type> <path>" >&2
exit 1
fi
[[ -r $path ]] || exit 1
wl-copy --type "$mime" < "$path"
if [[ $copy_only == "true" ]]; then
exit
fi
sleep 0.15
wtype -M shift -k Insert -m shift 2>/dev/null || true
-62
View File
@@ -1,62 +0,0 @@
#!/bin/bash
# omarchy:summary=Copy text to the clipboard and type or paste it
# omarchy:group=clipboard
# omarchy:args=[--shift-insert] [--copy-only] [--history-index <index>|<text>]
# omarchy:examples=omarchy clipboard paste text "hello" | omarchy clipboard paste text --shift-insert "hello"
use_shift_insert=false
copy_only=false
history_index=""
text=""
while [[ $# -gt 0 ]]; do
case "$1" in
--shift-insert)
use_shift_insert=true
shift
;;
--copy-only)
copy_only=true
shift
;;
--history-index)
history_index="${2:-}"
shift 2
;;
*)
break
;;
esac
done
copy_history_entry() {
local history_path="$HOME/.local/state/omarchy/clipboard-history.json"
[[ $history_index =~ ^[0-9]+$ ]] || exit
jq -e --argjson index "$history_index" '.[$index].type == "text" and (.[$index].text | type == "string")' "$history_path" >/dev/null || exit
jq -j --argjson index "$history_index" '.[$index].text' "$history_path" | wl-copy
}
if [[ -n $history_index ]]; then
copy_history_entry
if [[ $copy_only != "true" ]]; then
use_shift_insert=true
fi
else
text=${1:-}
[[ -n $text ]] || exit
printf '%s' "$text" | wl-copy
fi
if [[ $copy_only == "true" ]]; then
exit
fi
sleep 0.15
if [[ $use_shift_insert == "true" ]]; then
wtype -M shift -k Insert -m shift 2>/dev/null || true
else
wtype "$text" 2>/dev/null || true
fi
-615
View File
@@ -1,615 +0,0 @@
#!/bin/bash
# omarchy:summary=Mutate the user shell.json bar layout and active bar option
# omarchy:args=show | options [--json] | use <plugin> | reset | list [--json] [--all] | add [plugin] [left|center|right] | remove [plugin] | drop [plugin] | position <top|bottom|left|right> | transparent <true|false>
# omarchy:examples=omarchy config shell bar show | omarchy config shell bar options | omarchy config shell bar use local.neon-bar | omarchy config shell bar reset | omarchy config shell bar list | omarchy config shell bar add omarchy.tailscale | omarchy config shell bar position top | omarchy config shell bar transparent true
set -euo pipefail
CONFIG_FILE="$HOME/.config/omarchy/shell.json"
OMARCHY_ROOT="${OMARCHY_PATH:-}"
DEFAULTS_FILE="$OMARCHY_ROOT/config/omarchy/shell.json"
usage() {
echo "Usage: omarchy-config-shell-bar show | options [--json] | use <plugin> | reset | list [--json] [--all] | add [plugin] [left|center|right] | remove [plugin] | drop [plugin] | position <top|bottom|left|right> | transparent <true|false>" >&2
}
fail() {
echo "omarchy-config-shell-bar: $*" >&2
exit 1
}
refresh_shell_config() {
if ! omarchy-shell shell reloadConfig >/dev/null 2>&1; then
omarchy-shell -q shell rescanPlugins >/dev/null 2>&1 || true
fi
}
source_file() {
local source="$CONFIG_FILE"
if [[ ! -s $source ]]; then
[[ -n $OMARCHY_ROOT ]] || fail "OMARCHY_PATH is not set"
source="$DEFAULTS_FILE"
fi
[[ -s $source ]] || fail "could not find shell config or defaults"
printf '%s\n' "$source"
}
bar_widget_manifest_paths() {
{
if [[ -n $OMARCHY_ROOT && -d $OMARCHY_ROOT/shell/plugins ]]; then
find "$OMARCHY_ROOT/shell/plugins" -mindepth 2 -maxdepth 4 -type f \( -name manifest.json -o -name '*.manifest.json' \) 2>/dev/null
fi
if [[ -d $HOME/.config/omarchy/plugins ]]; then
find -L "$HOME/.config/omarchy/plugins" -mindepth 2 -maxdepth 2 -type f -name manifest.json 2>/dev/null
fi
} | sort -u
}
bar_option_manifest_paths() {
{
if [[ -n $OMARCHY_ROOT && -d $OMARCHY_ROOT/shell/plugins ]]; then
find "$OMARCHY_ROOT/shell/plugins" -mindepth 2 -maxdepth 4 -type f \( -name manifest.json -o -name '*.manifest.json' \) 2>/dev/null
fi
if [[ -d $HOME/.config/omarchy/plugins ]]; then
find -L "$HOME/.config/omarchy/plugins" -mindepth 2 -maxdepth 2 -type f -name manifest.json 2>/dev/null
fi
} | sort -u
}
current_bar_option_id() {
jq -r '(.bar.id // "omarchy.bar") | tostring' "$(source_file)"
}
available_bar_options_json() {
local current_id
local manifest_paths=()
current_id=$(current_bar_option_id)
mapfile -t manifest_paths < <(bar_option_manifest_paths)
if (( ${#manifest_paths[@]} == 0 )); then
printf '[]\n'
return
fi
jq -s --arg currentId "$current_id" '
map(
select(((.kinds // []) | index("bar")) and ((.entryPoints.bar // "") != "")) |
{
id: (.id // ""),
name: (.name // .id // ""),
description: (.description // ""),
firstParty: ((.id // "") | startswith("omarchy.")),
active: ((.id // "") == $currentId)
} |
select(.id != "")
) |
unique_by(.id) |
sort_by((if .id == "omarchy.bar" then 0 else 1 end), .name, .id)
' "${manifest_paths[@]}"
}
print_bar_options() {
local json="false"
while (( $# > 0 )); do
case "$1" in
--json)
json="true"
;;
-h|--help)
usage
exit 0
;;
*)
fail "unknown options option: $1"
;;
esac
shift
done
if [[ $json == "true" ]]; then
available_bar_options_json
return
fi
available_bar_options_json | jq -r '
.[] |
[
.id,
(if .active then "active" else "available" end),
(if .firstParty then "built-in" else "plugin" end),
.name,
.description
] | @tsv
' | awk -F '\t' '
BEGIN { printf "%-32s %-10s %-8s %-22s %s\n", "ID", "STATUS", "SOURCE", "NAME", "DESCRIPTION" }
{ printf "%-32s %-10s %-8s %-22s %s\n", $1, $2, $3, $4, $5 }
'
}
bar_option_exists() {
local id="$1"
available_bar_options_json | jq -e --arg id "$id" 'any(.[]; .id == $id)' >/dev/null
}
current_bar_ids_json() {
jq -c '
def array_or_empty: if type == "array" then . else [] end;
def entry_id: if type == "object" then (.id // "" | tostring) else tostring end;
["left", "center", "right"] as $sections |
[ $sections[] as $section |
((.bar.layout[$section] // []) | array_or_empty)[] |
entry_id |
select(length > 0)
]
' "$(source_file)"
}
current_bar_entries_json() {
jq -c '
def array_or_empty: if type == "array" then . else [] end;
def entry_id($entry): if ($entry | type) == "object" then ($entry.id // "" | tostring) else ($entry | tostring) end;
["left", "center", "right"] as $sections |
[ $sections[] as $section |
((.bar.layout[$section] // []) | array_or_empty | to_entries[]) |
{ section: $section, index: .key, id: entry_id(.value) } |
select(.id | length > 0)
]
' "$(source_file)"
}
available_widgets_json() {
local include_all="$1"
local current_ids
local manifest_paths=()
current_ids=$(current_bar_ids_json)
mapfile -t manifest_paths < <(bar_widget_manifest_paths)
if (( ${#manifest_paths[@]} == 0 )); then
printf '[]\n'
return
fi
jq -s --argjson currentIds "$current_ids" --argjson includeAll "$include_all" '
map(
select(((.kinds // []) | index("bar-widget")) and ((.entryPoints.barWidget // "") != "")) |
{
id: (.id // ""),
name: (.barWidget.displayName // .name // .id // ""),
description: (.barWidget.description // .description // ""),
category: (.barWidget.category // "Plugin"),
allowMultiple: (.barWidget.allowMultiple == true)
} |
select(.id != "")
) |
unique_by(.id) |
map(. as $widget |
$widget + {
inBar: (($currentIds | index($widget.id)) != null),
addable: ($widget.allowMultiple or (($currentIds | index($widget.id)) == null))
}
) |
map(select($includeAll or .addable)) |
sort_by(.category, .name, .id)
' "${manifest_paths[@]}"
}
print_available_widgets() {
local include_all="false"
local json="false"
while (( $# > 0 )); do
case "$1" in
--all)
include_all="true"
;;
--json)
json="true"
;;
-h|--help)
usage
exit 0
;;
*)
fail "unknown list option: $1"
;;
esac
shift
done
if [[ $json == "true" ]]; then
available_widgets_json "$include_all"
return
fi
available_widgets_json "$include_all" | jq -r '
.[] |
[
.id,
(if .inBar and .allowMultiple then "addable*" elif .inBar then "in-bar" else "addable" end),
.category,
.name,
.description
] | @tsv
' | awk -F '\t' '
BEGIN { printf "%-28s %-10s %-14s %-22s %s\n", "ID", "STATUS", "CATEGORY", "NAME", "DESCRIPTION" }
{ printf "%-28s %-10s %-14s %-22s %s\n", $1, $2, $3, $4, $5 }
'
}
choose_widget() {
local widgets
local options=()
local selected=""
widgets=$(available_widgets_json false)
if ! jq -e 'length > 0' <<<"$widgets" >/dev/null; then
fail "no addable bar widgets found"
fi
mapfile -t options < <(jq -r '
.[] |
[.id, .name, .category, .description] | @tsv
' <<<"$widgets" | awk -F '\t' '{ printf "%-28s %-22s [%s] %s\n", $1, $2, $3, $4 }')
if [[ -t 0 || -t 2 ]]; then
if omarchy-cmd-present gum; then
selected=$(printf '%s\n' "${options[@]}" | gum filter --header "Add bar widget" --placeholder "Search addable widgets..." --limit 1 --height 14) || return 1
elif omarchy-cmd-present fzf; then
selected=$(printf '%s\n' "${options[@]}" | fzf --prompt "Add bar widget > " --height 40% --layout reverse --border) || return 1
else
print_available_widgets >&2
fail "gum or fzf is required for interactive widget selection"
fi
else
print_available_widgets >&2
fail "widget id is required; use list to see addable widgets"
fi
selected="${selected%%[[:space:]]*}"
[[ -n $selected ]] || return 1
printf '%s\n' "$selected"
}
choose_removal() {
local entries
local widgets
local options=()
local selected=""
local location=""
local section=""
local index=""
entries=$(current_bar_entries_json)
widgets=$(available_widgets_json true)
if ! jq -e 'length > 0' <<<"$entries" >/dev/null; then
fail "no bar widgets are currently configured"
fi
mapfile -t options < <(jq -r --argjson widgets "$widgets" '
def widget_meta($id): first($widgets[]? | select(.id == $id)) // {};
.[] as $entry |
(widget_meta($entry.id)) as $meta |
[
"\($entry.section)[\($entry.index)]",
$entry.id,
($meta.name // $entry.id),
($meta.category // "")
] | @tsv
' <<<"$entries" | awk -F '\t' '{ printf "%-10s %-28s %-22s %s\n", $1, $2, $3, $4 }')
if [[ -t 0 || -t 2 ]]; then
if omarchy-cmd-present gum; then
selected=$(printf '%s\n' "${options[@]}" | gum filter --header "Remove bar widget" --placeholder "Search current widgets..." --limit 1 --height 14) || return 1
elif omarchy-cmd-present fzf; then
selected=$(printf '%s\n' "${options[@]}" | fzf --prompt "Remove bar widget > " --height 40% --layout reverse --border) || return 1
else
jq -r '.[] | "\(.section)[\(.index)]\t\(.id)"' <<<"$entries" >&2
fail "gum or fzf is required for interactive widget selection"
fi
else
jq -r '.[] | "\(.section)[\(.index)]\t\(.id)"' <<<"$entries" >&2
fail "widget id is required; use show to see current widgets"
fi
location="${selected%%[[:space:]]*}"
section="${location%%[*}"
index="${location#*[}"
index="${index%]}"
[[ $section =~ ^(left|center|right)$ ]] || return 1
[[ $index =~ ^[0-9]+$ ]] || return 1
printf '%s\t%s\n' "$section" "$index"
}
command="${1:-}"
case "$command" in
show|current)
if (( $# != 1 )); then
usage
exit 1
fi
jq '.bar // {}' "$(source_file)"
;;
selected|active)
if (( $# != 1 )); then
usage
exit 1
fi
current_bar_option_id
;;
options|option)
shift
print_bar_options "$@"
;;
use)
if (( $# != 2 )); then
usage
exit 1
fi
plugin="${2:-}"
[[ -n $plugin ]] || fail "bar option id is required"
if [[ $plugin == "default" || $plugin == "built-in" ]]; then
plugin="omarchy.bar"
fi
bar_option_exists "$plugin" || fail "$plugin is not a known bar option; run 'omarchy config shell bar options'"
mkdir -p "$(dirname "$CONFIG_FILE")"
source="$(source_file)"
tmp=$(mktemp)
trap 'rm -f "$tmp"' EXIT
if [[ $plugin == "omarchy.bar" ]]; then
jq '
def object_or_empty: if type == "object" then . else {} end;
object_or_empty
| .version = 1
| .bar = (.bar | object_or_empty)
| del(.bar.id)
' "$source" >"$tmp"
else
jq --arg plugin "$plugin" '
def object_or_empty: if type == "object" then . else {} end;
object_or_empty
| .version = 1
| .bar = (.bar | object_or_empty)
| .bar.id = $plugin
' "$source" >"$tmp"
fi
mv "$tmp" "$CONFIG_FILE"
trap - EXIT
omarchy-shell -q shell rescanPlugins >/dev/null 2>&1 || true
refresh_shell_config
;;
reset)
if (( $# != 1 )); then
usage
exit 1
fi
mkdir -p "$(dirname "$CONFIG_FILE")"
source="$(source_file)"
tmp=$(mktemp)
trap 'rm -f "$tmp"' EXIT
jq '
def object_or_empty: if type == "object" then . else {} end;
object_or_empty
| .version = 1
| .bar = (.bar | object_or_empty)
| del(.bar.id)
' "$source" >"$tmp"
mv "$tmp" "$CONFIG_FILE"
trap - EXIT
refresh_shell_config
;;
list|available|widgets)
shift
print_available_widgets "$@"
;;
add)
if (( $# > 3 )); then
usage
exit 1
fi
if (( $# == 1 )); then
plugin=$(choose_widget) || exit 1
else
plugin="${2:-}"
fi
section="${3:-right}"
[[ -n $plugin ]] || fail "plugin is required"
[[ $section =~ ^(left|center|right)$ ]] || fail "section must be left, center, or right"
mkdir -p "$(dirname "$CONFIG_FILE")"
source="$(source_file)"
tmp=$(mktemp)
trap 'rm -f "$tmp"' EXIT
jq --arg section "$section" --arg plugin "$plugin" '
def object_or_empty: if type == "object" then . else {} end;
def array_or_empty: if type == "array" then . else [] end;
def entry_id: if type == "object" then (.id // "" | tostring) else tostring end;
def append_anchor($section):
{
left: "omarchy.workspaces",
center: "omarchy.weather",
right: "omarchy.tray"
}[$section];
def insert_after_anchor($entries; $entry; $anchor):
($entries | map(entry_id) | index($anchor)) as $index
| if $index == null then
$entries + [$entry]
else
$entries[0:$index + 1] + [$entry] + $entries[$index + 1:]
end;
object_or_empty
| .version = 1
| .bar = (.bar | object_or_empty)
| .bar.layout = (.bar.layout | object_or_empty)
| .bar.layout.left = (.bar.layout.left | array_or_empty | map(select(entry_id != $plugin)))
| .bar.layout.center = (.bar.layout.center | array_or_empty | map(select(entry_id != $plugin)))
| .bar.layout.right = (.bar.layout.right | array_or_empty | map(select(entry_id != $plugin)))
| .plugins = (.plugins | array_or_empty)
| .bar.layout[$section] = insert_after_anchor(.bar.layout[$section]; { id: $plugin }; append_anchor($section))
' "$source" >"$tmp"
mv "$tmp" "$CONFIG_FILE"
trap - EXIT
refresh_shell_config
;;
position)
if (( $# != 2 )); then
usage
exit 1
fi
position="${2:-}"
[[ $position =~ ^(top|bottom|left|right)$ ]] || fail "position must be top, bottom, left, or right"
mkdir -p "$(dirname "$CONFIG_FILE")"
source="$(source_file)"
tmp=$(mktemp)
trap 'rm -f "$tmp"' EXIT
jq --arg position "$position" '
def object_or_empty: if type == "object" then . else {} end;
object_or_empty
| .version = 1
| .bar = (.bar | object_or_empty)
| .bar.position = $position
' "$source" >"$tmp"
mv "$tmp" "$CONFIG_FILE"
trap - EXIT
refresh_shell_config
;;
transparent)
if (( $# != 2 )); then
usage
exit 1
fi
transparent="${2:-}"
[[ $transparent =~ ^(true|false)$ ]] || fail "transparent must be true or false"
mkdir -p "$(dirname "$CONFIG_FILE")"
source="$(source_file)"
tmp=$(mktemp)
trap 'rm -f "$tmp"' EXIT
jq --argjson transparent "$transparent" '
def object_or_empty: if type == "object" then . else {} end;
object_or_empty
| .version = 1
| .bar = (.bar | object_or_empty)
| .bar.transparent = $transparent
' "$source" >"$tmp"
mv "$tmp" "$CONFIG_FILE"
trap - EXIT
refresh_shell_config
;;
drop|remove|rm)
if (( $# > 2 )); then
usage
exit 1
fi
plugin=""
target_section=""
target_index=""
if (( $# == 1 )); then
removal=$(choose_removal) || exit 1
target_section="${removal%%$'\t'*}"
target_index="${removal#*$'\t'}"
else
plugin="${2:-}"
[[ -n $plugin ]] || fail "plugin is required"
fi
mkdir -p "$(dirname "$CONFIG_FILE")"
source="$(source_file)"
tmp=$(mktemp)
trap 'rm -f "$tmp"' EXIT
if [[ -n $target_section ]]; then
jq --arg section "$target_section" --argjson index "$target_index" '
def object_or_empty: if type == "object" then . else {} end;
def array_or_empty: if type == "array" then . else [] end;
object_or_empty
| .version = 1
| .bar = (.bar | object_or_empty)
| .bar.layout = (.bar.layout | object_or_empty)
| .bar.layout.left = (.bar.layout.left | array_or_empty)
| .bar.layout.center = (.bar.layout.center | array_or_empty)
| .bar.layout.right = (.bar.layout.right | array_or_empty)
| if (.bar.layout[$section] | length) <= $index then
error("no widget at " + $section + "[" + ($index | tostring) + "]")
else
.bar.layout[$section] = (.bar.layout[$section][0:$index] + .bar.layout[$section][($index + 1):])
end
| .plugins = (.plugins | array_or_empty)
' "$source" >"$tmp"
else
jq --arg plugin "$plugin" '
def object_or_empty: if type == "object" then . else {} end;
def array_or_empty: if type == "array" then . else [] end;
def entry_id: if type == "object" then (.id // "" | tostring) else tostring end;
object_or_empty
| .version = 1
| .bar = (.bar | object_or_empty)
| .bar.layout = (.bar.layout | object_or_empty)
| .bar.layout.left = (.bar.layout.left | array_or_empty | map(select(entry_id != $plugin)))
| .bar.layout.center = (.bar.layout.center | array_or_empty | map(select(entry_id != $plugin)))
| .bar.layout.right = (.bar.layout.right | array_or_empty | map(select(entry_id != $plugin)))
| .plugins = (.plugins | array_or_empty)
' "$source" >"$tmp"
fi
mv "$tmp" "$CONFIG_FILE"
trap - EXIT
refresh_shell_config
;;
*)
usage
exit 1
;;
esac
+5 -3
View File
@@ -37,7 +37,7 @@ fi
cat > "$LOG_FILE" <<EOF
Date: $(date)
Hostname: $(hostname)
Omarchy Package: $(pacman -Q omarchy 2>/dev/null || echo "unknown")
Omarchy Branch: $(git -C "$OMARCHY_PATH" branch --show-current 2>/dev/null || echo "unknown")
=========================================
SYSTEM INFORMATION
@@ -74,13 +74,15 @@ ACTION=$(gum choose "${OPTIONS[@]}")
case "$ACTION" in
"Upload log")
echo "Uploading debug log to logs.omarchy.org..."
URL=$(curl -sf -F "file=@$LOG_FILE" -Fexpires=24 https://logs.omarchy.org/)
echo "Uploading debug log to 0x0.st..."
URL=$(curl -sF "file=@$LOG_FILE" -Fexpires=24 https://0x0.st)
if (( $? == 0 )) && [[ -n $URL ]]; then
echo "✓ Log uploaded successfully!"
echo "Share this URL:"
echo ""
echo " $URL"
echo ""
echo "This link will expire in 24 hours."
else
echo "Error: Failed to upload log file"
exit 1
-58
View File
@@ -1,58 +0,0 @@
#!/bin/bash
# omarchy:summary=Show idle, screensaver, and lock diagnostics
# omarchy:group=debug
# omarchy:args=[log-lines]
# omarchy:examples=omarchy debug idle | omarchy-debug-idle 400
lines=${1:-200}
if [[ ! $lines =~ ^[0-9]+$ ]]; then
lines=200
fi
section() {
printf '\n== %s ==\n' "$1"
}
section "Time"
date -Is
section "Idle IPC status"
omarchy-shell idle status 2>&1 | jq . 2>/dev/null || omarchy-shell idle status 2>&1 || true
section "Quickshell instances"
quickshell list -p "$OMARCHY_PATH/shell" --any-display 2>&1 || true
section "Recent idle logs"
quickshell --no-color log -p "$OMARCHY_PATH/shell" --any-display --tail "$lines" --log-times -r 'quickshell.wayland.idle_notify=true' 2>&1 \
| grep -Ei 'omarchy idle|idle_notify|screensaver|lock|error|warn|failed' || true
section "Relevant processes"
ps -eo pid=,args= \
| grep -E 'quickshell -n -p|omarchy-system-sleep-monitor|systemd-inhibit.*Lock screen before suspend|org\.omarchy\.screensaver|omarchy-screensaver|(^|/| )tte( |$)' \
| grep -v grep || true
section "Sleep lock service"
systemctl --user status omarchy-sleep-lock.service --no-pager 2>/dev/null || true
section "Hyprland screensaver clients"
hyprctl clients -j 2>/dev/null \
| jq -r '.[] | select(.class == "org.omarchy.screensaver" or .initialClass == "org.omarchy.screensaver") | [.pid,.class,.initialClass,.title,.focusHistoryID] | @tsv' || true
section "Idle inhibitors"
hyprctl clients -j 2>/dev/null \
| jq -r '.[] | select(.inhibitingIdle == true or ((.tags // []) | index("noidle"))) | [.pid,.class,.title,((.tags // []) | join(",")),.inhibitingIdle] | @tsv' || true
section "Screensaver detector"
if hyprctl clients -j 2>/dev/null | jq -e '.[] | select(.class == "org.omarchy.screensaver" or .initialClass == "org.omarchy.screensaver")' >/dev/null; then
echo "running-window"
elif pgrep -f '[o]rg.omarchy.screensaver' >/dev/null; then
echo "running-process"
elif omarchy-toggle-enabled screensaver-off; then
echo "disabled"
else
echo "stopped"
fi
section "Lock detector"
omarchy-shell lock status 2>&1 | jq . 2>/dev/null || omarchy-shell lock status 2>&1 || true
-32
View File
@@ -1,32 +0,0 @@
#!/bin/bash
# omarchy:summary=Set the default AI harness used by omarchy-launch-ai
# omarchy:args=[pi|claude|codex|opencode]
# omarchy:examples=omarchy default ai | omarchy default ai pi | omarchy default ai claude
ai_file="$HOME/.local/state/omarchy/defaults/ai"
if (( $# == 0 )); then
if [[ -f $ai_file ]]; then
read -r harness <"$ai_file"
fi
[[ -n ${harness:-} ]] && echo "$harness" || echo "pi"
exit 0
fi
case "$1" in
pi) harness="pi"; name="Pi"; glyph=󰚩 ;;
claude) harness="claude"; name="Claude Code"; glyph=󰚩 ;;
codex) harness="codex"; name="Codex"; glyph=󰚩 ;;
opencode) harness="opencode"; name="OpenCode"; glyph=󰚩 ;;
*)
echo "Usage: omarchy-default-ai <pi|claude|codex|opencode>" >&2
exit 1
;;
esac
mkdir -p "$(dirname "$ai_file")"
printf '%s\n' "$harness" >"$ai_file"
omarchy-notification-send -g "$glyph" "$name is now the default AI harness"
+8 -8
View File
@@ -19,13 +19,13 @@ if (($# == 0)); then
fi
case "$1" in
chromium) desktop_id="chromium.desktop"; name="Chromium"; glyph= ;;
chrome) desktop_id="google-chrome.desktop"; name="Chrome"; glyph=󰊯 ;;
brave) desktop_id="brave-browser.desktop"; name="Brave"; glyph=󰖟 ;;
brave-origin) desktop_id="brave-origin-beta.desktop"; name="Brave Origin"; glyph=󰖟 ;;
edge) desktop_id="microsoft-edge.desktop"; name="Edge"; glyph=󰇩 ;;
firefox) desktop_id="firefox.desktop"; name="Firefox"; glyph=󰈹 ;;
zen) desktop_id="zen.desktop"; name="Zen"; glyph=󰖟 ;;
chromium) desktop_id="chromium.desktop"; name="Chromium"; glyph="" ;;
chrome) desktop_id="google-chrome.desktop"; name="Chrome"; glyph="󰊯" ;;
brave) desktop_id="brave-browser.desktop"; name="Brave"; glyph="󰖟" ;;
brave-origin) desktop_id="brave-origin-beta.desktop"; name="Brave Origin"; glyph="󰖟" ;;
edge) desktop_id="microsoft-edge.desktop"; name="Edge"; glyph="󰇩" ;;
firefox) desktop_id="firefox.desktop"; name="Firefox"; glyph="󰈹" ;;
zen) desktop_id="zen.desktop"; name="Zen"; glyph="󰰷" ;;
*)
echo "Usage: omarchy-default-browser <chromium|chrome|brave|brave-origin|edge|firefox|zen>"
exit 1
@@ -37,4 +37,4 @@ xdg-mime default "$desktop_id" x-scheme-handler/http
xdg-mime default "$desktop_id" x-scheme-handler/https
xdg-mime default "$desktop_id" text/html
omarchy-notification-send -g $glyph "$name is now the default browser"
notify-send -u low "$glyph $name is now the default browser"
+13 -19
View File
@@ -1,36 +1,30 @@
#!/bin/bash
# omarchy:summary=Set the default editor used by omarchy-launch-editor
# omarchy:summary=Set the default editor for $EDITOR
# omarchy:args=[code|cursor|zed|sublime_text|helix|vim|emacs|nvim]
# omarchy:examples=omarchy default editor | omarchy default editor code | omarchy default editor helix
editor_file="$HOME/.local/state/omarchy/defaults/editor"
if (($# == 0)); then
if [[ -f $editor_file ]]; then
read -r editor <"$editor_file"
fi
[[ -n $editor ]] && echo "$editor" || echo "nvim"
sed -n 's/^export EDITOR=//p' ~/.config/uwsm/default | head -n 1
exit 0
fi
case "$1" in
code) editor="code"; name="VSCode"; glyph= ;;
cursor) editor="cursor"; name="Cursor"; glyph= ;;
zed | zeditor) editor="zeditor"; name="Zed"; glyph= ;;
sublime_text) editor="sublime_text"; name="Sublime Text"; glyph= ;;
helix) editor="helix"; name="Helix"; glyph= ;;
vim) editor="vim"; name="Vim"; glyph= ;;
emacs) editor="emacs"; name="Emacs"; glyph= ;;
nvim) editor="nvim"; name="Neovim"; glyph= ;;
code) editor="code"; name="VSCode"; glyph="" ;;
cursor) editor="cursor"; name="Cursor"; glyph="" ;;
zed | zeditor) editor="zeditor"; name="Zed"; glyph="" ;;
sublime_text) editor="sublime_text"; name="Sublime Text"; glyph="" ;;
helix) editor="helix"; name="Helix"; glyph="" ;;
vim) editor="vim"; name="Vim"; glyph="" ;;
emacs) editor="emacs"; name="Emacs"; glyph="" ;;
nvim) editor="nvim"; name="Neovim"; glyph="" ;;
*)
echo "Usage: omarchy-default-editor <code|cursor|zed|sublime_text|helix|vim|emacs|nvim>"
exit 1
;;
esac
mkdir -p "$(dirname "$editor_file")"
printf '%s\n' "$editor" >"$editor_file"
sed -i "s/^export EDITOR=.*/export EDITOR=$editor/" ~/.config/uwsm/default
omarchy-notification-send -g $glyph "$name is now the default editor"
export EDITOR="$editor"
notify-send -u low "$glyph $name is now the default editor" " Effective after logging out"
+6 -7
View File
@@ -5,8 +5,7 @@
# omarchy:examples=omarchy default terminal ghostty | omarchy default terminal kitty
if (($# == 0)); then
desktop_id=$(xdg-terminal-exec --print-id 2>/dev/null || true)
desktop_id=${desktop_id%%:*}
desktop_id=$(grep -vE '^($|#)' ~/.config/xdg-terminals.list 2>/dev/null | head -n 1)
case "$desktop_id" in
Alacritty.desktop) echo "alacritty" ;;
foot.desktop) echo "foot" ;;
@@ -18,10 +17,10 @@ if (($# == 0)); then
fi
case "$1" in
alacritty) desktop_id="Alacritty.desktop"; name="Alacritty"; glyph= ;;
foot) desktop_id="foot.desktop"; name="Foot"; glyph= ;;
ghostty) desktop_id="com.mitchellh.ghostty.desktop"; name="Ghostty"; glyph= ;;
kitty) desktop_id="kitty.desktop"; name="Kitty"; glyph= ;;
alacritty) desktop_id="Alacritty.desktop"; name="Alacritty"; glyph="" ;;
foot) desktop_id="foot.desktop"; name="Foot"; glyph="" ;;
ghostty) desktop_id="com.mitchellh.ghostty.desktop"; name="Ghostty"; glyph="" ;;
kitty) desktop_id="kitty.desktop"; name="Kitty"; glyph="" ;;
*)
echo "Usage: omarchy-default-terminal <alacritty|foot|ghostty|kitty>"
exit 1
@@ -34,4 +33,4 @@ cat >~/.config/xdg-terminals.list <<EOF
$desktop_id
EOF
omarchy-notification-send -g $glyph "$name is now the default terminal"
notify-send -u low "$glyph $name is now the default terminal"
+7 -35
View File
@@ -1,41 +1,13 @@
#!/bin/bash
# omarchy:summary=Create a new Omarchy migration in the current source tree.
# omarchy:args=[--no-edit]
# omarchy:summary=Creates a new Omarchy migration named after the unix timestamp of the last commit.
set -euo pipefail
cd ~/.local/share/omarchy
migration_file="$HOME/.local/share/omarchy/migrations/$(git log -1 --format=%cd --date=unix).sh"
touch $migration_file
no_edit=0
while (($#)); do
case "$1" in
--no-edit)
no_edit=1
shift
;;
system|user)
echo "omarchy-dev-add-migration: migration scopes are no longer used; creating a regular migration." >&2
shift
;;
-h|--help)
echo "Usage: omarchy-dev-add-migration [--no-edit]"
exit 0
;;
*)
echo "Unknown option: $1" >&2
echo "Usage: omarchy-dev-add-migration [--no-edit]" >&2
exit 1
;;
esac
done
cd "${OMARCHY_PATH:-$(pwd)}"
mkdir -p migrations
migration_file="migrations/$(git log -1 --format=%cd --date=unix).sh"
touch "$migration_file"
if (( ! no_edit )); then
nvim "$migration_file"
if [[ $1 != "--no-edit" ]]; then
nvim $migration_file
fi
printf '%s\n' "$PWD/$migration_file"
echo $migration_file
-160
View File
@@ -1,160 +0,0 @@
#!/bin/bash
# omarchy:summary=Measure theme switcher cache and selector prep times
# omarchy:args=[--repeat=<count>] [--keep-cache]
# omarchy:examples=omarchy dev benchmark theme switcher | omarchy dev benchmark theme-switcher --repeat=10
# omarchy:aliases=omarchy dev benchmark theme-switcher
set -euo pipefail
OMARCHY_BIN_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
REPEAT=5
KEEP_CACHE=false
show_help() {
cat <<'EOF'
Usage:
omarchy dev benchmark theme switcher [--repeat=<count>] [--keep-cache]
Measure the non-interactive parts of the theme switcher:
- theme preview index build (omarchy-theme-switcher before UI handoff)
- lazy selector row prep used by the interactive theme switcher
- full thumbnail cache warmup cost (omarchy-menu-images --cache-only)
Options:
--repeat=<count> Number of warm runs to measure for each case (default: 5)
--keep-cache Keep the temporary benchmark cache and print its path
EOF
}
now_us() {
local now="${EPOCHREALTIME/./}"
printf '%s' "$now"
}
format_ms() {
local us="$1"
printf '%d.%03d' "$(( us / 1000 ))" "$(( us % 1000 ))"
}
measure_once() {
local start_us end_us
start_us=$(now_us)
"$@" >/dev/null
end_us=$(now_us)
printf '%s' "$(( end_us - start_us ))"
}
run_case() {
local label="$1"
shift
local total_us=0
local min_us=0
local max_us=0
local elapsed_us=0
for (( i = 1; i <= REPEAT; i++ )); do
elapsed_us=$(measure_once "$@")
total_us=$(( total_us + elapsed_us ))
if (( i == 1 || elapsed_us < min_us )); then
min_us=$elapsed_us
fi
if (( elapsed_us > max_us )); then
max_us=$elapsed_us
fi
done
printf '%-34s avg %8s ms min %8s ms max %8s ms\n' \
"$label" \
"$(format_ms "$(( total_us / REPEAT ))")" \
"$(format_ms "$min_us")" \
"$(format_ms "$max_us")"
}
while (( $# > 0 )); do
case "$1" in
--repeat=*)
REPEAT="${1#*=}"
;;
--keep-cache)
KEEP_CACHE=true
;;
--help | -h)
show_help
exit 0
;;
*)
echo "Unknown option: $1" >&2
show_help >&2
exit 2
;;
esac
shift
done
if [[ ! $REPEAT =~ ^[0-9]+$ ]] || (( REPEAT < 1 )); then
echo "--repeat must be a positive integer" >&2
exit 2
fi
benchmark_cache=$(mktemp -d)
thumbnail_cache=$(mktemp -d)
stub_bin=$(mktemp -d)
cleanup() {
rm -rf "$stub_bin"
if [[ $KEEP_CACHE == "true" ]]; then
printf 'Benchmark cache: %s\n' "$benchmark_cache"
printf 'Thumbnail cache: %s\n' "$thumbnail_cache"
else
rm -rf "$benchmark_cache" "$thumbnail_cache"
fi
}
trap cleanup EXIT
cat >"$stub_bin/omarchy-menu-images" <<'EOF'
#!/bin/bash
exit 0
EOF
chmod +x "$stub_bin/omarchy-menu-images"
benchmark_env=(
env
"XDG_CACHE_HOME=$benchmark_cache"
"PATH=$stub_bin:$OMARCHY_BIN_DIR:$PATH"
)
thumbnail_env=(
env
"XDG_CACHE_HOME=$thumbnail_cache"
"PATH=$stub_bin:$OMARCHY_BIN_DIR:$PATH"
)
preview_dir="$benchmark_cache/omarchy/theme-selector/previews"
thumbnail_preview_dir="$thumbnail_cache/omarchy/theme-selector/previews"
build_theme_index() {
"${benchmark_env[@]}" "$OMARCHY_BIN_DIR/omarchy-theme-switcher"
}
prepare_selector_lazy() {
"${benchmark_env[@]}" "$OMARCHY_BIN_DIR/omarchy-menu-images" --prepare-only --lazy-thumbnails --show-labels --filterable "$preview_dir"
}
prepare_image_cache() {
"${thumbnail_env[@]}" "$OMARCHY_BIN_DIR/omarchy-menu-images" --cache-only "$thumbnail_preview_dir"
}
printf 'Theme switcher benchmark (%d warm runs each)\n\n' "$REPEAT"
printf '%-34s %s ms\n' "theme index cold" "$(format_ms "$(measure_once build_theme_index)")"
run_case "theme index warm" build_theme_index
printf '%-34s %s ms\n' "selector prep cold (lazy)" "$(format_ms "$(measure_once prepare_selector_lazy)")"
run_case "selector prep warm (lazy)" prepare_selector_lazy
"${thumbnail_env[@]}" "$OMARCHY_BIN_DIR/omarchy-theme-switcher" >/dev/null
printf '%-34s %s ms\n' "thumbnail cache cold" "$(format_ms "$(measure_once prepare_image_cache)")"
run_case "thumbnail cache warm" prepare_image_cache
printf '\nTheme previews: %d\n' "$(find -L "$preview_dir" -maxdepth 1 -type f 2>/dev/null | wc -l)"
+1 -1
View File
@@ -61,7 +61,7 @@ Do not define:
false flags or empty args
Examples:
# omarchy:summary=Restart the shell
# omarchy:summary=Restart Walker and related user services
# omarchy:summary=Take a screenshot
# omarchy:group=capture
-50
View File
@@ -1,50 +0,0 @@
#!/bin/bash
# omarchy:summary=Install and enable ydotool mouse automation for Omarchy development
# omarchy:requires-sudo=true
set -euo pipefail
RULE_FILE="/etc/udev/rules.d/80-uinput.rules"
if ! getent group input >/dev/null; then
echo "omarchy-dev-install-ydoo: input group does not exist" >&2
exit 1
fi
if ! id -nG "$USER" | tr ' ' '\n' | grep -qx input; then
echo "Adding $USER to the input group. You may need to log out and back in before this applies."
pkexec usermod -aG input "$USER"
fi
if omarchy-cmd-missing ydotool || omarchy-pkg-missing ydotool; then
omarchy-pkg-add ydotool
fi
pkexec /bin/bash -c '
set -euo pipefail
cat >"'"$RULE_FILE"'" <<'"'"'EOF'"'"'
KERNEL=="uinput", GROUP="input", MODE="0660", OPTIONS+="static_node=uinput"
EOF
modprobe uinput
udevadm control --reload-rules
udevadm trigger /dev/uinput 2>/dev/null || true
if [[ -e /dev/uinput ]]; then
chgrp input /dev/uinput
chmod 0660 /dev/uinput
fi
'
systemctl --user reset-failed ydotool.service >/dev/null 2>&1 || true
systemctl --user start ydotool.service
if ! systemctl --user is-active --quiet ydotool.service; then
echo "omarchy-dev-install-ydoo: ydotool.service did not start" >&2
systemctl --user status ydotool.service --no-pager >&2 || true
exit 1
fi
echo "ydotool is ready."

Some files were not shown because too many files have changed in this diff Show More