Compare commits

..
1669 changed files with 6339 additions and 70509 deletions
-9
View File
@@ -1,9 +0,0 @@
root = true
[*]
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
end_of_line = lf
charset = utf-8
-24
View File
@@ -1,24 +0,0 @@
name: Bug
description: Report a validated bug -- NOT FOR SUPPORT REQUESTS
labels: [bug]
body:
- type: markdown
attributes:
value: |
Remember: Omarchy is an open source gift, not a product you bought from a vendor
- type: input
id: system-details
attributes:
label: System details
placeholder: e.g. AMD 9950X, NVIDIA 5090, Omarchy 2.1.0
validations:
required: true
- type: textarea
id: steps
attributes:
label: What's wrong?
description: Describe the issue, include steps to recreate it if possible, and attach the output of `omarchy-debug` if possible
validations:
required: true
-8
View File
@@ -1,8 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Suggestion
url: https://github.com/basecamp/omarchy/discussions/categories/suggestions
about: Suggest a new feature, change to existing feature, or other ideas in Discussions.
- name: Support
url: https://omarchy.org/discord
about: Need help? Join our Discord community for support with any issues. GitHub issues should be used for verified bugs only.
-11
View File
@@ -1,11 +0,0 @@
{
"workspace": {
"library": [
"/usr/share/hypr/stubs"
],
"checkThirdParty": false
},
"diagnostics": {
"globals": ["hl"]
}
}
-188
View File
@@ -1,188 +0,0 @@
# Style
- Two spaces for indentation, no tabs
- Use bash 5 conditionals: use `[[ ]]` for string/file tests and `(( ))` for numeric tests
- In `[[ ]]`, don't quote variables, but do quote string literals when comparing values (e.g., `[[ $branch == "dev" ]]`)
- Prefer `(( ))` over numeric operators inside `[[ ]]` (e.g., `(( count < 50 ))`, not `[[ $count -lt 50 ]]`)
- For strings/paths with spaces, quote them instead of escaping spaces with `\ ` (e.g., `"$APP_DIR/Disk Usage.desktop"`, not `$APP_DIR/Disk\ Usage.desktop`)
- Shebangs must use `#!/bin/bash` consistently (never `#!/usr/bin/env bash`)
- Scripts under `install/` and `migrations/` may be sourced and intentionally omit shebangs
# Command Naming
All commands start with `omarchy-`. Prefixes indicate purpose.
The authoritative command group list lives in `bin/omarchy` in `GROUP_DESCRIPTIONS`. Keep `GROUP_DESCRIPTIONS` updated when adding a new command prefix.
Common prefixes include:
- `cmd-` - check if commands exist, misc utility commands
- `capture-` - screenshots, screen recordings, and other capture tools
- `pkg-` - package management helpers
- `hw-` - hardware detection (return exit codes for use in conditionals)
- `refresh-` - copy default config to user's `~/.config/`
- `restart-` - restart a component
- `launch-` - open applications
- `install-` - install optional software
- `setup-` - interactive setup wizards
- `toggle-` - toggle features on/off
- `theme-` - theme management
- `update-` - update components
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-`
# Command Metadata
Commands in `bin/` can declare CLI metadata in comments near the top of the file. `bin/omarchy` scans the first 80 lines, and tests expect command metadata to remain valid.
Supported metadata keys:
- `# omarchy:summary=...` - short help text
- `# 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:args=[smart|region|windows|fullscreen] [slurp|copy]
# omarchy:examples=omarchy screenshot | omarchy capture screenshot region
```
# 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
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.
Install stage files follow this pattern:
- `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-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 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, background, foreground, 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)`.
# Refresh Pattern
To copy a default config to user config with automatic backup:
```bash
omarchy-refresh-config hypr/hyprlock.conf
```
This copies `~/.local/share/omarchy/config/hypr/hyprlock.conf` to `~/.config/hypr/hyprlock.conf`.
# Migrations
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--`); 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`
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 historical compatibility or one-off repair work.
+2 -5
View File
@@ -1,13 +1,10 @@
# Omarchy # Omarchy
Omarchy is a beautiful, modern & opinionated Linux distribution by DHH. Turn a fresh Arch installation into a fully-configured, beautiful, and modern web development system based on Hyprland by running a single command. That's the one-line pitch for Omarchy (like it was for Omakub). No need to write bespoke configs for every essential tool just to get started or to be up on all the latest command-line tools. Omarchy is an opinionated take on what Linux can be at its best.
Read more at [omarchy.org](https://omarchy.org). 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 ## License
Omarchy is released under the [MIT License](https://opensource.org/licenses/MIT). Omarchy is released under the [MIT License](https://opensource.org/licenses/MIT).
-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
-21
View File
@@ -1,21 +0,0 @@
[Desktop Entry]
Type=Application
TryExec=foot
Exec=foot
Icon=foot
Terminal=false
Categories=System;TerminalEmulator;
Name=Foot
GenericName=Terminal
Comment=A fast, lightweight and minimalistic Wayland terminal emulator
StartupNotify=true
StartupWMClass=foot
Actions=New;
X-TerminalArgExec=-e
X-TerminalArgAppId=--app-id=
X-TerminalArgTitle=--title=
X-TerminalArgDir=--working-directory=
[Desktop Action New]
Name=New Terminal
Exec=foot
+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
@@ -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
@@ -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: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

+12
View File
@@ -0,0 +1,12 @@
[Desktop Entry]
Name=Neovim
GenericName=Text Editor
Comment=Edit text files
Exec=alacritty --class=nvim --title=nvim -e nvim -- %F
Terminal=false
Type=Application
Keywords=Text;editor;
Icon=nvim
Categories=Utility;TextEditor;
StartupNotify=false
MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++;
+7
View File
@@ -0,0 +1,7 @@
[Desktop Entry]
Name=Audio Settings
Comment=Using Wiremix
Exec=alacritty --class=Wiremix --title=Wiremix -e wiremix
Icon=audio-headphones
Type=Application
Terminal=false
+12
View File
@@ -0,0 +1,12 @@
[Desktop Entry]
Name=Zoom
Comment=Zoom Video Conference
Exec=env QT_SCALE_FACTOR=2 /usr/bin/zoom %U
Icon=Zoom
Terminal=false
Type=Application
Encoding=UTF-8
Categories=Network;Application;
StartupWMClass=zoom
MimeType=x-scheme-handler/zoommtg;x-scheme-handler/zoomus;x-scheme-handler/tel;x-scheme-handler/callto;x-scheme-handler/zoomphonecall;x-scheme-handler/zoomphonesms;x-scheme-handler/zoomcontactcentercall;application/x-zoom
X-KDE-Protocols=zoommtg;zoomus;tel;callto;zoomphonecall;zoomphonesms;zoomcontactcentercall;
+2
View File
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
-1073
View File
File diff suppressed because it is too large Load Diff
-9
View File
@@ -1,9 +0,0 @@
#!/bin/bash
# omarchy:summary=Returns true if AC power is connected.
for ac in /sys/class/power_supply/AC* /sys/class/power_supply/ADP*; do
[[ -r $ac/online && $(cat "$ac/online") == "1" ]] && exit 0
done
exit 1
-13
View File
@@ -1,13 +0,0 @@
#!/bin/bash
# omarchy:summary=Toggle microphone mute. Drives the hardware mic-mute LED on laptops that expose one.
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"
else
omarchy-brightness-keyboard-mute off
omarchy-osd -i microphone -m "Microphone on"
fi
-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
-42
View File
@@ -1,42 +0,0 @@
#!/bin/bash
# omarchy:summary=Switch between audio outputs while preserving the mute status
sinks=$(timeout 2 pactl -f json list sinks | jq '[.[] | select((.ports | length == 0) or ([.ports[]? | .availability != "not available"] | any))]')
sinks_count=$(jq 'length' <<<"$sinks")
if (( sinks_count == 0 )); then
omarchy-osd -m "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")
if [[ $current_sink_index != "null" ]]; then
next_sink_index=$(((current_sink_index + 1) % sinks_count))
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")
if [[ $next_sink_is_muted == "true" ]] || (( next_sink_volume == 0 )); then
icon_state="muted"
elif (( next_sink_volume <= 33 )); then
icon_state="low"
elif (( next_sink_volume <= 66 )); then
icon_state="medium"
else
icon_state="high"
fi
if [[ $next_sink_name != $current_sink_name ]]; then
omarchy-audio-output-set-default "$(jq -r '.index' <<<"$next_sink")" "$next_sink_name"
fi
omarchy-osd -i "volume-${icon_state}" -m "$next_sink_description"
-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
-10
View File
@@ -1,10 +0,0 @@
#!/bin/bash
# omarchy:summary=Returns the battery full capacity in Wh (rounded to whole number).
battery_info=$(upower -i $(upower -e | grep BAT))
echo "$battery_info" | awk '/energy-full:/ {
printf "%d", $2
exit
}'
-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"
+30
View File
@@ -0,0 +1,30 @@
#!/bin/bash
# Designed to be run by systemd timer every 30 seconds and alerts if battery is low
BATTERY_THRESHOLD=10
NOTIFICATION_FLAG="/run/user/$UID/omarchy_battery_notified"
get_battery_percentage() {
upower -i $(upower -e | grep 'BAT') | grep -E "percentage" | grep -o '[0-9]\+%' | sed 's/%//'
}
get_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
}
BATTERY_LEVEL=$(get_battery_percentage)
BATTERY_STATE=$(get_battery_state)
if [[ "$BATTERY_STATE" == "discharging" && "$BATTERY_LEVEL" -le "$BATTERY_THRESHOLD" ]]; then
if [[ ! -f "$NOTIFICATION_FLAG" ]]; then
send_notification "$BATTERY_LEVEL"
touch "$NOTIFICATION_FLAG"
fi
else
rm -f "$NOTIFICATION_FLAG"
fi
-12
View File
@@ -1,12 +0,0 @@
#!/bin/bash
# omarchy:summary=Returns true if a battery is present on the system.
for bat in /sys/class/power_supply/BAT*; do
[[ -r $bat/present ]] &&
[[ $(cat $bat/present) == "1" ]] &&
[[ $(cat $bat/type) == "Battery" ]] &&
exit 0
done
exit 1
-8
View File
@@ -1,8 +0,0 @@
#!/bin/bash
# omarchy:summary=Returns the battery percentage remaining as an integer.
upower -i $(upower -e | grep BAT) | awk '/percentage/ {
print int($2)
exit
}'
-22
View File
@@ -1,22 +0,0 @@
#!/bin/bash
# omarchy:summary=Returns the battery time remaining (to empty or full) in a compact format.
battery_info=$(upower -i $(upower -e | grep BAT))
echo "$battery_info" | awk '/time to (empty|full)/ {
value = $4
unit = $5
if (unit ~ /^minute/) {
printf "%dm", int(value)
} else {
hours = int(value)
minutes = int((value - hours) * 60)
if (minutes > 0) {
printf "%dh %dm", hours, minutes
} else {
printf "%dh", hours
}
}
exit
}'
-108
View File
@@ -1,108 +0,0 @@
#!/bin/bash
# omarchy:summary=Returns a formatted battery status string with percentage and power draw/charge.
# omarchy:args=[--shell]
shell_output=false
case "${1:-}" in
"")
;;
--shell)
shell_output=true
;;
*)
echo "Usage: omarchy-battery-status [--shell]" >&2
exit 2
;;
esac
battery=$(upower -e 2>/dev/null | grep BAT | head -n 1)
[[ -z $battery ]] && exit 0
battery_info=$(upower -i "$battery")
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"
else
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
@@ -1,18 +0,0 @@
#!/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
-30
View File
@@ -1,30 +0,0 @@
#!/bin/bash
# omarchy:summary=Edit, set, or reset About branding
# omarchy:group=branding
# omarchy:name=about
# omarchy:args=<image|text|reset>
# omarchy:examples=omarchy branding about image | omarchy branding about text | omarchy branding about reset
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
omarchy-launch-about >/dev/null 2>&1
fi
;;
text)
omarchy-launch-editor ~/.config/omarchy/branding/about.txt >/dev/null 2>&1 && omarchy-launch-about >/dev/null 2>&1
;;
reset)
cp "$OMARCHY_PATH/icon.txt" ~/.config/omarchy/branding/about.txt && omarchy-launch-about >/dev/null 2>&1
;;
*)
echo "Usage: omarchy-branding-about <image|text|reset>" >&2
exit 1
;;
esac
-30
View File
@@ -1,30 +0,0 @@
#!/bin/bash
# omarchy:summary=Edit, set, or reset screensaver branding
# omarchy:group=branding
# omarchy:name=screensaver
# omarchy:args=<image|text|reset>
# omarchy:examples=omarchy branding screensaver image | omarchy branding screensaver text | omarchy branding screensaver reset
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/screensaver.txt; then
omarchy-launch-screensaver force >/dev/null 2>&1
fi
;;
text)
omarchy-launch-editor ~/.config/omarchy/branding/screensaver.txt >/dev/null 2>&1 && omarchy-launch-screensaver force >/dev/null 2>&1
;;
reset)
cp "$OMARCHY_PATH/logo.txt" ~/.config/omarchy/branding/screensaver.txt && omarchy-launch-screensaver force >/dev/null 2>&1
;;
*)
echo "Usage: omarchy-branding-screensaver <image|text|reset>" >&2
exit 1
;;
esac
-92
View File
@@ -1,92 +0,0 @@
#!/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
no_osd=0
args=()
for arg in "$@"; do
if [[ $arg == "--no-osd" ]]; then
no_osd=1
else
args+=("$arg")
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
exit 0
elif [[ $step == "on" ]]; then
hyprctl dispatch 'hl.dsp.dpms({ action = "enable" })' >/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
exit
fi
# Current device highlighted
device="$(omarchy-hw-display)" || exit 1
# Current brightness percentage
current=$(display_brightness "$device") || exit 1
# 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.
if [[ $step == "+5%" ]]; then
if (( current < 5 )); then
(( target = current + 1 ))
else
(( target = current + 5 ))
fi
(( target > 100 )) && target=100
step="$target%"
elif [[ $step == "5%-" ]]; then
if (( current <= 5 )); then
(( target = current - 1 ))
else
(( target = current - 5 ))
fi
(( target < 1 )) && target=1
step="$target%"
fi
# Set 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")"
-101
View File
@@ -1,101 +0,0 @@
#!/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%
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")
fi
done
set -- "${args[@]}"
detect_apple_display_device() {
local devices=()
local path=""
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
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
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
fi
(( no_osd )) || omarchy-osd -i brightness -p "$(current_brightness "$device")"
-65
View File
@@ -1,65 +0,0 @@
#!/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[@]}"
direction="${1:-up}"
# Find keyboard backlight device (look for *kbd_backlight* pattern in leds class).
device=""
for candidate in /sys/class/leds/*kbd_backlight*; do
if [[ -e $candidate ]]; then
device="$(basename "$candidate")"
break
fi
done
if [[ -z $device ]]; then
echo "No keyboard backlight device found" >&2
exit 1
fi
if [[ $direction == "off" ]]; then
brightnessctl -sd "$device" set 0 >/dev/null
exit 0
elif [[ $direction == "restore" ]]; then
brightnessctl -rd "$device" >/dev/null
exit 0
fi
# Get current and max brightness to determine step size.
max_brightness="$(brightnessctl -d "$device" max)"
current_brightness="$(brightnessctl -d "$device" get)"
# Calculate step as 10% of max brightness. Keyboards with many levels (e.g. 512)
# need larger steps; keyboards with few levels (e.g. 3) fall back to step=1.
step=$(( max_brightness / 10 ))
(( step < 1 )) && step=1
if [[ $direction == "cycle" ]]; then
new_brightness=$(( current_brightness + step ))
(( new_brightness > max_brightness )) && new_brightness=0
elif [[ $direction == "up" ]]; then
new_brightness=$(( current_brightness + step ))
(( new_brightness > max_brightness )) && new_brightness=$max_brightness
else
new_brightness=$(( current_brightness - step ))
(( new_brightness < 0 )) && new_brightness=0
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 ))"
-14
View File
@@ -1,14 +0,0 @@
#!/bin/bash
# omarchy:summary=Set the mic-mute indicator LED on laptops that expose a platform::micmute LED node.
# omarchy:args=<on|off>
if [[ -e /sys/class/leds/platform::micmute/brightness ]]; then
case "$1" in
on) value=1 ;;
off) value=0 ;;
*) echo "Usage: $(basename "$0") <on|off>" >&2; exit 1 ;;
esac
brightnessctl --device="platform::micmute" set "$value" >/dev/null 2>&1 || true
fi
-301
View File
@@ -1,301 +0,0 @@
#!/bin/bash
# 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:examples=omarchy screenrecord | omarchy capture screenrecord --with-desktop-audio
# omarchy:aliases=omarchy screenrecord
#
# Env: OMARCHY_SCREENRECORD_USE_PORTAL=true skips the built-in slurp picker and
# uses gpu-screen-recorder's xdg-desktop-portal capture backend instead. The
# portal backend was originally added (PR #3401) for HDR-aware capture, support
# for monitors driven by external GPUs, and window capture — enable it if any
# of those matter to you. Off by default because the portal path can fail EGL
# DMA-BUF modifier import on some configurations, leaving recording unable to
# start.
#
# Env: OMARCHY_SCREENRECORD_DEBUG=true appends gpu-screen-recorder's stderr (and
# the picker target it was launched with) to /tmp/omarchy-screenrecord.log so
# users can attach a log when reporting capture failures.
[[ -f ~/.config/user-dirs.dirs ]] && source ~/.config/user-dirs.dirs
OUTPUT_DIR="${OMARCHY_SCREENRECORD_DIR:-${XDG_VIDEOS_DIR:-$HOME/Videos}}"
if [[ ! -d $OUTPUT_DIR ]]; then
notify-send "Screen recording directory does not exist: $OUTPUT_DIR" -u critical -t 3000
exit 1
fi
DESKTOP_AUDIO="false"
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")
for arg in "$@"; do
case "$arg" in
--with-desktop-audio) DESKTOP_AUDIO="true" ;;
--with-microphone-audio) MICROPHONE_AUDIO="true" ;;
--with-webcam) WEBCAM="true" ;;
--webcam-device=*) WEBCAM_DEVICE="${arg#*=}" ;;
--resolution=*) RESOLUTION="${arg#*=}" ;;
--fullscreen) FULLSCREEN="true" ;;
--stop-recording) STOP_RECORDING="true" ;;
esac
done
start_webcam_overlay() {
cleanup_webcam
# Auto-detect first available webcam if none specified
if [[ -z $WEBCAM_DEVICE ]]; then
WEBCAM_DEVICE=$(v4l2-ctl --list-devices 2>/dev/null | grep -m1 "^[[:space:]]*/dev/video" | tr -d '\t')
if [[ -z $WEBCAM_DEVICE ]]; then
notify-send "No webcam devices found" -u critical -t 3000
return 1
fi
fi
# Get monitor scale
local scale=$(hyprctl monitors -j | jq -r '.[] | select(.focused == true) | .scale')
# Target width (base 360px, scaled to monitor)
local target_width=$(awk "BEGIN {printf \"%.0f\", 360 * $scale}")
# Try preferred 16:9 resolutions in order, use first available
local preferred_resolutions=("640x360" "1280x720" "1920x1080")
local video_size_arg=""
local available_formats=$(v4l2-ctl --list-formats-ext -d "$WEBCAM_DEVICE" 2>/dev/null)
for resolution in "${preferred_resolutions[@]}"; do
if echo "$available_formats" | grep -q "$resolution"; then
video_size_arg="-video_size $resolution"
break
fi
done
ffplay -f v4l2 $video_size_arg -framerate 30 "$WEBCAM_DEVICE" \
-vf "crop=iw/2:ih,scale=${target_width}:-1" \
-window_title "WebcamOverlay" \
-noborder \
-fflags nobuffer -flags low_delay \
-probesize 32 -analyzeduration 0 \
-loglevel quiet &
sleep 1
}
cleanup_webcam() {
pkill -f "WebcamOverlay" 2>/dev/null
}
default_resolution() {
local width height
read -r width height < <(hyprctl monitors -j | jq -r '.[] | select(.focused == true) | "\(.width) \(.height)"')
if ((width > 3840 || height > 2160)); then
echo "3840x2160"
else
echo "0x0"
fi
}
# Monitor + window rectangles on the focused workspace, in slurp's "X,Y WxH" format.
# Mirrors omarchy-capture-screenshot so the picker UX is identical.
get_rectangles() {
local active_workspace=$(hyprctl monitors -j | jq -r '.[] | select(.focused == true) | .activeWorkspace.id')
hyprctl monitors -j | jq -r --arg ws "$active_workspace" '
.[] | select(.activeWorkspace.id == ($ws | tonumber)) |
"\(.x),\(.y) \(.width / .scale | floor)x\(.height / .scale | floor)"'
hyprctl clients -j | jq -r --arg ws "$active_workspace" '
.[] | select(.workspace.id == ($ws | tonumber)) |
"\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"'
}
# Echoes "monitor:NAME" when the selection matches an entire monitor, otherwise
# "region:WxH+X+Y" with physical-pixel coordinates ready for gpu-screen-recorder.
# Returns non-zero if the user cancelled the picker.
select_capture_target() {
local rects=$(get_rectangles)
hyprpicker -r -z >/dev/null 2>&1 &
local picker_pid=$!
sleep .1
local selection=$(echo "$rects" | slurp 2>/dev/null)
kill $picker_pid 2>/dev/null
# X and Y can be negative (Hyprland monitor positions in multi-display layouts);
# widths and heights are always positive.
[[ $selection =~ ^(-?[0-9]+),(-?[0-9]+)[[:space:]]([0-9]+)x([0-9]+)$ ]] || return 1
local sx=${BASH_REMATCH[1]} sy=${BASH_REMATCH[2]}
local sw=${BASH_REMATCH[3]} sh=${BASH_REMATCH[4]}
# A bare click (area < 20px²) snaps to whichever rectangle the click landed
# inside, so users don't end up with accidental 2px recordings.
if ((sw * sh < 20)); then
while IFS= read -r rect; do
[[ $rect =~ ^(-?[0-9]+),(-?[0-9]+)[[:space:]]([0-9]+)x([0-9]+)$ ]] || continue
local rx=${BASH_REMATCH[1]} ry=${BASH_REMATCH[2]}
local rw=${BASH_REMATCH[3]} rh=${BASH_REMATCH[4]}
if ((sx >= rx && sx < rx + rw && sy >= ry && sy < ry + rh)); then
sx=$rx sy=$ry sw=$rw sh=$rh
break
fi
done <<<"$rects"
fi
# When the selection exactly matches a monitor, prefer -w <monitor> over a
# region capture — same kms backend, but no scaling math and full native res.
local monitor=$(hyprctl monitors -j | jq -r --argjson x "$sx" --argjson y "$sy" --argjson w "$sw" --argjson h "$sh" '
.[] | select(.x == $x and .y == $y and (.width / .scale | floor) == $w and (.height / .scale | floor) == $h) | .name' | head -1)
if [[ -n $monitor ]]; then
echo "monitor:$monitor"
return
fi
# gpu-screen-recorder wants region geometry in the compositor's logical
# coordinate space — same space slurp returns — so pass the values through
# untouched. (gsr scales to physical pixels itself based on the monitor.)
echo "region:${sw}x${sh}+${sx}+${sy}"
}
start_screenrecording() {
local capture_args=()
local target
# Opt-in path for HDR, external-GPU monitors, and window capture (all things
# 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
target="portal"
capture_args=(-w portal -s "${RESOLUTION:-$(default_resolution)}")
else
target=$(select_capture_target) || return 1
case $target in
monitor:*)
capture_args=(-w "${target#monitor:}" -s "${RESOLUTION:-$(default_resolution)}")
;;
region:*)
capture_args=(-w "${target#region:}")
[[ -n $RESOLUTION ]] && capture_args+=(-s "$RESOLUTION")
;;
esac
fi
[[ $WEBCAM == "true" ]] && start_webcam_overlay
local filename="$OUTPUT_DIR/screenrecording-$(date +'%Y-%m-%d_%H-%M-%S').mp4"
local audio_devices=""
local audio_args=()
[[ $DESKTOP_AUDIO == "true" ]] && audio_devices+="default_output"
if [[ $MICROPHONE_AUDIO == "true" ]]; then
# Merge audio tracks into one - separate tracks only play one at a time in most players
[[ -n $audio_devices ]] && audio_devices+="|"
audio_devices+="default_input"
fi
[[ -n $audio_devices ]] && audio_args+=(-a "$audio_devices" -ac aac)
echo "===== $(date '+%F %T') args: $* target: $target =====" >>"$LOG_FILE"
gpu-screen-recorder "${capture_args[@]}" -k auto -f 60 -fm cfr -fallback-cpu-encoding yes -o "$filename" "${audio_args[@]}" 2>>"$LOG_FILE" &
local pid=$!
while kill -0 $pid 2>/dev/null && [[ ! -f $filename ]]; do
sleep 0.2
done
if kill -0 $pid 2>/dev/null; then
echo "$filename" >"$RECORDING_FILE"
toggle_screenrecording_indicator
fi
}
stop_screenrecording() {
pkill -SIGINT -f "^gpu-screen-recorder" # SIGINT required to save video properly
# Wait a maximum of 5 seconds to finish before hard killing
local count=0
while pgrep -f "^gpu-screen-recorder" >/dev/null && ((count < 50)); do
sleep 0.1
count=$((count + 1))
done
toggle_screenrecording_indicator
cleanup_webcam
if pgrep -f "^gpu-screen-recorder" >/dev/null; then
pkill -9 -f "^gpu-screen-recorder"
notify-send "Screen recording error" "Recording process had to be force-killed. Video may be corrupted." -u critical -t 5000
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
rm -f "$preview"
) &
fi
rm -f "$RECORDING_FILE"
}
toggle_screenrecording_indicator() {
omarchy-shell -q Indicators refresh
}
screenrecording_active() {
pgrep -f "^gpu-screen-recorder" >/dev/null
}
finalize_recording() {
local latest
latest=$(cat "$RECORDING_FILE" 2>/dev/null)
[[ -f $latest ]] || return
# Re-encode only when the first GOP contains discardable warmup packets — stream copy can't
# trim those (it rewinds to the keyframe). Clean recordings stay on the fast stream-copy path.
local video_codec=(-c:v copy)
if ffprobe -v error -select_streams v:0 -read_intervals %+0.2 -show_entries packet=flags -of csv=p=0 "$latest" 2>/dev/null | grep -q D; then
video_codec=(-c:v libx264 -preset veryfast -crf 20)
fi
# Trim the first frame, and normalize audio to -14 LUFS if present, in a single pass
local args=(-y -ss 0.1 -i "$latest" "${video_codec[@]}")
if ffprobe -v error -select_streams a -show_entries stream=codec_type -of csv=p=0 "$latest" 2>/dev/null | grep -q audio; then
# Hard-mute the first 400ms to drop the PipeWire capture-open pop (a near-clipping
# transient around 130-200ms that a gentle fade-in can't attenuate enough), then a
# 50ms fade avoids a click at the boundary before loudnorm normalizes the rest.
args+=(-af "volume=enable='lt(t,0.4)':volume=0,afade=t=in:st=0.4:d=0.05,loudnorm=I=-14:TP=-1.5:LRA=11")
fi
local processed="${latest%.mp4}-processed.mp4"
if ffmpeg "${args[@]}" "$processed" -loglevel quiet 2>/dev/null; then
mv "$processed" "$latest"
else
rm -f "$processed"
fi
}
if screenrecording_active; then
stop_screenrecording
elif [[ $STOP_RECORDING == "true" ]]; then
exit 1
else
start_screenrecording || cleanup_webcam
fi
@@ -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"
-148
View File
@@ -1,148 +0,0 @@
#!/bin/bash
# omarchy:summary=Take a screenshot
# omarchy:group=capture
# omarchy:args=[smart|region|windows|fullscreen] [slurp|copy|save] [--editor=<name>]
# omarchy:examples=omarchy screenshot | omarchy capture screenshot region
# omarchy:aliases=omarchy screenshot
[[ -f ~/.config/user-dirs.dirs ]] && source ~/.config/user-dirs.dirs
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
fi
pkill slurp && exit 0
SCREENSHOT_EDITOR="${OMARCHY_SCREENSHOT_EDITOR:-satty}"
# Parse --editor flag from any position
ARGS=()
for arg in "$@"; do
if [[ $arg == --editor=* ]]; then
SCREENSHOT_EDITOR="${arg#--editor=}"
else
ARGS+=("$arg")
fi
done
set -- "${ARGS[@]}"
open_editor() {
local filepath="$1"
if [[ $SCREENSHOT_EDITOR == "satty" ]]; then
satty --filename "$filepath" \
--output-filename "$filepath" \
--actions-on-enter save-to-clipboard \
--save-after-copy \
--copy-command 'wl-copy --type image/png'
else
$SCREENSHOT_EDITOR "$filepath"
fi
}
MODE="${1:-smart}"
PROCESSING="${2:-slurp}"
# accounting for portrait/transformed displays
JQ_MONITOR_GEO='
def format_geo:
.x as $x | .y as $y |
(.width / .scale | floor) as $w |
(.height / .scale | floor) as $h |
.transform as $t |
if $t == 1 or $t == 3 then
"\($x),\($y) \($h)x\($w)"
else
"\($x),\($y) \($w)x\($h)"
end;
'
get_rectangles() {
local active_workspace=$(hyprctl monitors -j | jq -r '.[] | select(.focused == true) | .activeWorkspace.id')
hyprctl monitors -j | jq -r --arg ws "$active_workspace" "${JQ_MONITOR_GEO} .[] | select(.activeWorkspace.id == (\$ws | tonumber)) | format_geo"
hyprctl clients -j | jq -r --arg ws "$active_workspace" '.[] | select(.workspace.id == ($ws | tonumber)) | "\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"'
}
# Keep hyprpicker alive until after grim captures so the screenshot sees the
# frozen overlay rather than live content shifting during teardown.
cleanup_freeze() {
[[ -n $PID ]] && kill $PID 2>/dev/null
}
trap cleanup_freeze EXIT
# Select based on mode
case "$MODE" in
region)
hyprpicker -r -z >/dev/null 2>&1 &
PID=$!
sleep .1
SELECTION=$(slurp 2>/dev/null)
;;
windows)
hyprpicker -r -z >/dev/null 2>&1 &
PID=$!
sleep .1
SELECTION=$(get_rectangles | slurp -r 2>/dev/null)
;;
fullscreen)
SELECTION=$(hyprctl monitors -j | jq -r "${JQ_MONITOR_GEO} .[] | select(.focused == true) | format_geo")
;;
smart | *)
RECTS=$(get_rectangles)
hyprpicker -r -z >/dev/null 2>&1 &
PID=$!
sleep .1
SELECTION=$(echo "$RECTS" | slurp 2>/dev/null)
# If the selection area is L * W < 20, we'll assume you were trying to select whichever
# window or output it was inside of to prevent accidental 2px snapshots
if [[ $SELECTION =~ ^([0-9]+),([0-9]+)[[:space:]]([0-9]+)x([0-9]+)$ ]]; then
if ((${BASH_REMATCH[3]} * ${BASH_REMATCH[4]} < 20)); then
click_x="${BASH_REMATCH[1]}"
click_y="${BASH_REMATCH[2]}"
while IFS= read -r rect; do
if [[ $rect =~ ^([0-9]+),([0-9]+)[[:space:]]([0-9]+)x([0-9]+) ]]; then
rect_x="${BASH_REMATCH[1]}"
rect_y="${BASH_REMATCH[2]}"
rect_width="${BASH_REMATCH[3]}"
rect_height="${BASH_REMATCH[4]}"
if ((click_x >= rect_x && click_x < rect_x + rect_width && click_y >= rect_y && click_y < rect_y + rect_height)); then
SELECTION="${rect_x},${rect_y} ${rect_width}x${rect_height}"
break
fi
fi
done <<<"$RECTS"
fi
fi
;;
esac
[[ -z $SELECTION ]] && exit 0
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 [[ -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
-26
View File
@@ -1,26 +0,0 @@
#!/bin/bash
# omarchy:summary=Extract text from a screenshot region with OCR
# omarchy:group=capture
# omarchy:examples=omarchy capture ocr
# Keep hyprpicker alive until after grim captures so the screenshot sees the
# frozen overlay rather than live content shifting during teardown.
cleanup_freeze() {
[[ -n $PID ]] && kill $PID 2>/dev/null
}
trap cleanup_freeze EXIT
hyprpicker -r -z >/dev/null 2>&1 &
PID=$!
sleep .1
SELECTION=$(slurp 2>/dev/null)
[[ -z $SELECTION ]] && exit 0
TEXT=$(grim -g "$SELECTION" - | tesseract stdin stdout --oem 1 --psm 6 -l "${OMARCHY_OCR_LANGS:-eng}" --dpi 300 -c preserve_interword_spaces=1 2>/dev/null) || exit 1
[[ -z $TEXT ]] && exit 1
printf "%s" "$TEXT" | wl-copy
omarchy-notification-send -g 󰴑 "Copied text from selection to clipboard"
-22
View File
@@ -1,22 +0,0 @@
#!/bin/bash
# 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
if (($# == 0)); then
echo "Usage: omarchy-channel-set [stable|rc|edge|dev]"
exit 1
else
channel="$1"
fi
case "$channel" in
"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-update -y
-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 satty --filename "$path" --output-filename "$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
+7
View File
@@ -0,0 +1,7 @@
#!/bin/bash
if [[ $# -eq 0 ]]; then
echo "Adjust Apple Display Brightness by passing +5000 or -5000 (or any range from 0-60000)"
else
sudo asdcontrol $(sudo asdcontrol --detect /dev/usb/hiddev* | grep ^/dev/usb/hiddev | cut -d: -f1) -- "$1"
fi
+19
View File
@@ -0,0 +1,19 @@
#!/bin/bash
# Find all the audio sinks but exit if there are none
sinks=($(wpctl status | sed -n '/Sinks:/,/Sources:/p' | grep -E '^\s*│\s+\*?\s*[0-9]+\.' | sed -E 's/^[^0-9]*([0-9]+)\..*/\1/'))
[ ${#sinks[@]} -eq 0 ] && exit 1
# Find current audio sink
current=$(wpctl status | sed -n '/Sinks:/,/Sources:/p' | grep '^\s*│\s*\*' | sed -E 's/^[^0-9]*([0-9]+)\..*/\1/')
# Find the next sink (looping around in the list)
for i in "${!sinks[@]}"; do
[ "${sinks[$i]}" = "$current" ] && next=${sinks[$(((i + 1) % ${#sinks[@]}))]}
done
next=${next:-${sinks[0]}}
# Set the next sink and ensure it's not muted
wpctl set-default "$next"
wpctl set-mute "$next" 0
+9
View File
@@ -0,0 +1,9 @@
#!/bin/bash
# Close all open windows
hyprctl clients -j | \
jq -r ".[].address" | \
xargs -I{} hyprctl dispatch closewindow address:{}
# Move to first workspace
hyprctl dispatch workspace 1
-11
View File
@@ -1,11 +0,0 @@
#!/bin/bash
# omarchy:summary=Check whether any required commands are missing
for cmd in "$@"; do
if ! command -v "$cmd" &>/dev/null; then
exit 0
fi
done
exit 1
-9
View File
@@ -1,9 +0,0 @@
#!/bin/bash
# omarchy:summary=Check whether all required commands are available
for cmd in "$@"; do
command -v "$cmd" &>/dev/null || exit 1
done
exit 0
+32
View File
@@ -0,0 +1,32 @@
#!/bin/bash
[[ -f ~/.config/user-dirs.dirs ]] && source ~/.config/user-dirs.dirs
OUTPUT_DIR="${OMARCHY_SCREENRECORD_DIR:-${XDG_VIDEOS_DIR:-$HOME/Videos}}"
if [[ ! -d "$OUTPUT_DIR" ]]; then
notify-send "Screen recording directory does not exist: $OUTPUT_DIR" -u critical -t 3000
exit 1
fi
screenrecording() {
filename="$OUTPUT_DIR/screenrecording-$(date +'%Y-%m-%d_%H-%M-%S').mp4"
notify-send "Screen recording starting..." -t 1000
sleep 1
if lspci | grep -Eqi 'nvidia|intel.*graphics'; then
wf-recorder -f "$filename" -c libx264 -p crf=23 -p preset=medium -p movflags=+faststart "$@"
else
wl-screenrec -f "$filename" --ffmpeg-encoder-options="-c:v libx264 -crf 23 -preset medium -movflags +faststart" "$@"
fi
}
if pgrep -x wl-screenrec >/dev/null || pgrep -x wf-recorder >/dev/null; then
pkill -x wl-screenrec
pkill -x wf-recorder
notify-send "Screen recording saved to $OUTPUT_DIR" -t 2000
elif [[ "$1" == "output" ]]; then
screenrecording
else
region=$(slurp) || exit 1
screenrecording -g "$region"
fi
+7
View File
@@ -0,0 +1,7 @@
#!/bin/bash
if pgrep -x wl-screenrec >/dev/null || pgrep -x wf-recorder >/dev/null; then
pkill -x wl-screenrec
pkill -x wf-recorder
notify-send "Screen recording stopped" -t 2000
fi
+20
View File
@@ -0,0 +1,20 @@
#!/bin/bash
if command -v tte &>/dev/null; then
while true; do
effect=$(tte 2>&1 | grep -oP '{\K[^}]+' | tr ',' ' ' | tr ' ' '\n' | sed -n '/^beams$/,$p' | sort -u | shuf -n1)
tte -i ~/.config/omarchy/branding/screensaver.txt \
--frame-rate 240 --canvas-width 0 --canvas-height $(($(tput lines) - 2)) --anchor-canvas c --anchor-text c \
"$effect" &
while pgrep -x tte >/dev/null; do
if read -n 1 -t 0.01; then
pkill -x tte 2>/dev/null
pkill -f "alacritty --class Screensaver" 2>/dev/null
exit 0
fi
done
done
else
gum spin --title "Can't find tte. Try: pip install terminaltexteffects" -- sleep 2
fi
+17
View File
@@ -0,0 +1,17 @@
#!/bin/bash
[[ -f ~/.config/user-dirs.dirs ]] && source ~/.config/user-dirs.dirs
OUTPUT_DIR="${OMARCHY_SCREENSHOT_DIR:-${XDG_PICTURES_DIR:-$HOME/Pictures}}"
if [[ ! -d "$OUTPUT_DIR" ]]; then
notify-send "Screenshot directory does not exist: $OUTPUT_DIR" -u critical -t 3000
exit 1
fi
pkill slurp || hyprshot -m ${1:-region} --raw |
satty --filename - \
--output-filename "$OUTPUT_DIR/screenshot-$(date +'%Y-%m-%d_%H-%M-%S').png" \
--early-exit \
--actions-on-enter save-to-clipboard \
--save-after-copy \
--copy-command 'wl-copy'
+3 -13
View File
@@ -1,21 +1,11 @@
#!/bin/bash #!/bin/bash
# omarchy:summary=Print the current working directory of the active terminal window # Go from current active terminal to its child shell process and run cwd there
# omarchy:hidden=true
terminal_pid=$(hyprctl activewindow | awk '/pid:/ {print $2}') terminal_pid=$(hyprctl activewindow | awk '/pid:/ {print $2}')
shell_pid=$(pgrep -P "$terminal_pid" | tail -n1) shell_pid=$(pgrep -P "$terminal_pid" | head -n1)
if [[ -n $shell_pid ]]; then if [[ -n $shell_pid ]]; then
cwd=$(readlink -f "/proc/$shell_pid/cwd" 2>/dev/null) readlink -f "/proc/$shell_pid/cwd" 2>/dev/null
shell=$(readlink -f "/proc/$shell_pid/exe" 2>/dev/null)
# Check if $shell is a valid shell and $cwd is a directory.
if grep -qs "$shell" /etc/shells && [[ -d $cwd ]]; then
echo "$cwd"
else
echo "$HOME"
fi
else else
echo "$HOME" echo "$HOME"
fi fi
+6
View File
@@ -0,0 +1,6 @@
#!/bin/bash
sudo tzupdate
new_timezone=$(timedatectl show -p Timezone --value)
omarchy-restart-waybar
notify-send "Timezone has been set to $new_timezone"
-58
View File
@@ -1,58 +0,0 @@
#!/bin/bash
# omarchy:summary=Add or remove an EFI boot entry for the Omarchy UKI, allowing the system to boot directly
# omarchy:requires-sudo=true
if [[ ! -d /sys/firmware/efi ]]; then
echo "Error: System is not booted in UEFI mode" >&2
exit 1
fi
if ! efibootmgr &>/dev/null; then
echo "Error: efibootmgr is not available or not functional" >&2
exit 1
fi
if cat /sys/class/dmi/id/bios_vendor 2>/dev/null | grep -qi "American Megatrends"; then
echo "Error: American Megatrends firmware may not safely support custom EFI entries" >&2
exit 1
fi
if cat /sys/class/dmi/id/bios_vendor 2>/dev/null | grep -qi "Apple"; then
echo "Error: Apple firmware uses its own boot manager" >&2
exit 1
fi
existing_entry=$(efibootmgr | grep -E "^Boot[0-9A-Fa-f]+\*? Omarchy([[:space:]]|$)" | head -1)
if [[ -n $existing_entry ]]; then
boot_num=$(echo "$existing_entry" | sed -n 's/^Boot\([0-9A-Fa-f]\+\).*/\1/p')
if gum confirm "Disable direct boot (remove Omarchy EFI entry)?"; then
echo "Removing EFI boot entry $boot_num"
sudo efibootmgr --bootnum "$boot_num" --delete-bootnum >/dev/null
fi
exit 0
else
uki_file=$(find /boot/EFI/Linux/ -name "omarchy*.efi" -printf "%f\n" 2>/dev/null | head -1)
if [[ -z $uki_file ]]; then
echo "Error: No Omarchy UKI found in /boot/EFI/Linux/" >&2
exit 1
fi
boot_source=$(findmnt -n -o SOURCE /boot)
disk=$(echo "$boot_source" | sed 's/p\?[0-9]*$//')
part=$(echo "$boot_source" | grep -o 'p\?[0-9]*$' | sed 's/^p//')
if gum confirm "Setup direct boot (so snapshot booting must be done via bios)?"; then
echo "Creating EFI boot entry for $uki_file"
sudo efibootmgr --create \
--disk "$disk" \
--part "$part" \
--label "Omarchy" \
--loader "\\EFI\\Linux\\$uki_file"
fi
fi

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