mirror of
https://github.com/arthur-pbty/arthur-os.git
synced 2026-08-02 12:47:49 +02:00
Compare commits
60
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51c48de1ba | ||
|
|
34dbfc0d7c | ||
|
|
c7203b6714 | ||
|
|
5552be964b | ||
|
|
78bc4d34c5 | ||
|
|
27dfc23139 | ||
|
|
234f670310 | ||
|
|
080d287d74 | ||
|
|
286e6378e7 | ||
|
|
ffb080d80d | ||
|
|
6eb6c79831 | ||
|
|
98db372bce | ||
|
|
a1ed2cf37f | ||
|
|
06ee173aca | ||
|
|
a966fbbc33 | ||
|
|
b3755d423a | ||
|
|
723ea545b5 | ||
|
|
4078102b80 | ||
|
|
507062f077 | ||
|
|
49e65067d5 | ||
|
|
81687e4f34 | ||
|
|
75c0e965a0 | ||
|
|
378497c8a2 | ||
|
|
fe19eee32b | ||
|
|
14696c315e | ||
|
|
4178547bbf | ||
|
|
8984affcbe | ||
|
|
4e15165155 | ||
|
|
6fd95b3e37 | ||
|
|
42fed06d9f | ||
|
|
8963c0dd2d | ||
|
|
dc17299a69 | ||
|
|
132e42a45f | ||
|
|
36b7bc7342 | ||
|
|
b9654a9372 | ||
|
|
e4e7fae5ef | ||
|
|
46db57acc5 | ||
|
|
89c5cc2d74 | ||
|
|
7c2402ff5b | ||
|
|
b609519c83 | ||
|
|
6d583028d5 | ||
|
|
0a8bcbe40a | ||
|
|
448cf86ff3 | ||
|
|
2ac65b5273 | ||
|
|
d0af0f998b | ||
|
|
76894b9c74 | ||
|
|
b7ccb64082 | ||
|
|
de4819bd17 | ||
|
|
6f73a52510 | ||
|
|
b64046fd5e | ||
|
|
433346353e | ||
|
|
11bb11814b | ||
|
|
df3310a453 | ||
|
|
087545e17e | ||
|
|
442cd5917a | ||
|
|
21ac298e88 | ||
|
|
5ae7bad9b5 | ||
|
|
35c21d7bea | ||
|
|
29041f7a56 | ||
|
|
42bfa3582b |
@@ -1,4 +0,0 @@
|
||||
|
||||
# Python bytecode (orchestrator)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"workspace": {
|
||||
"library": [
|
||||
"/usr/share/hypr/stubs"
|
||||
],
|
||||
"checkThirdParty": false
|
||||
},
|
||||
"diagnostics": {
|
||||
"globals": ["hl"]
|
||||
}
|
||||
}
|
||||
@@ -1,196 +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
|
||||
|
||||
The ISO owns installation orchestration. This repo ships target-side setup commands and reusable setup leaves:
|
||||
|
||||
- `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.
|
||||
|
||||
Raw `command -v`, `pacman`, and `pacman-key` are acceptable in package-helper contexts 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 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 `/etc/skel/.config/hypr/hyprlock.conf` to `~/.config/hypr/hyprlock.conf`.
|
||||
|
||||
# Migrations
|
||||
|
||||
Read `docs/migrations.md` before creating or changing migrations.
|
||||
|
||||
Migrations are split by execution scope:
|
||||
|
||||
- `migrations/system/<timestamp>.sh` — root, noninteractive, safe to run from pacman via `omarchy-migrate-system` (`omarchy` `post_upgrade` calls it). Use for `/etc`, `/usr`, `/boot`, services, hardware quirks, and other system state. Do not prompt.
|
||||
- `migrations/user/<timestamp>.sh` — current user/session, may touch `~/.config`, `~/.local`, user systemd, browser prefs, DBus/session state, and may prompt if necessary. Runs through `omarchy-migrate` / `omarchy-migrate-user`; pending state is per-user based on missing files under `~/.local/state/omarchy/migrations/user/`.
|
||||
|
||||
To create a new migration, run `omarchy-dev-add-migration system --no-edit` or `omarchy-dev-add-migration user --no-edit` based on scope.
|
||||
|
||||
New migration format:
|
||||
- File permissions must be `0644` (`-rw-r--r--`); migration runners execute them with `bash -euo pipefail`, not through executable bits
|
||||
- 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.
|
||||
|
||||
Migrations may use raw `pacman`, `command -v`, or direct config edits when needed for one-off repair work.
|
||||
@@ -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).
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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=discord
|
||||
StartupNotify=true
|
||||
@@ -1,8 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Version=1.0
|
||||
Name=Disk Usage
|
||||
Exec=xdg-terminal-exec --app-id=TUI.float -e bash -c "dust -r; read -n 1 -s"
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Icon=disk-usage
|
||||
StartupNotify=true
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 9.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 53 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 21 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 63 KiB |
-1074
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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()
|
||||
}
|
||||
'
|
||||
@@ -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
|
||||
@@ -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
|
||||
}'
|
||||
@@ -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"
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
#!/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"
|
||||
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
|
||||
}
|
||||
|
||||
if [[ -n "$BATTERY_LEVEL" && "$BATTERY_LEVEL" =~ ^[0-9]+$ ]]; then
|
||||
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
|
||||
fi
|
||||
@@ -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
|
||||
@@ -1,8 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
# omarchy:summary=Returns the battery percentage remaining as an integer.
|
||||
# Returns the battery percentage remaining as an integer.
|
||||
|
||||
upower -i $(upower -e | grep BAT) | awk '/percentage/ {
|
||||
print int($2)
|
||||
upower -i $(upower -e | grep BAT) \
|
||||
| awk -F: '/percentage/ {
|
||||
gsub(/[%[:space:]]/, "", $2);
|
||||
val=$2;
|
||||
printf("%d\n", (val+0.5))
|
||||
exit
|
||||
}'
|
||||
}'
|
||||
|
||||
@@ -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
|
||||
}'
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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")"
|
||||
@@ -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")"
|
||||
@@ -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 ))"
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# omarchy:summary=Set the Omarchy package channel.
|
||||
# omarchy:args=<stable|rc|edge|dev>
|
||||
# omarchy:requires-sudo=true
|
||||
|
||||
set -e
|
||||
|
||||
if (($# == 0)); then
|
||||
echo "Usage: omarchy-channel-set [stable|rc|edge|dev]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
channel="$1"
|
||||
case "$channel" in
|
||||
stable|rc|edge) omarchy-refresh-pacman "$channel" ;;
|
||||
dev) omarchy-refresh-pacman edge ;;
|
||||
*) echo "Unknown channel: $channel"; exit 1 ;;
|
||||
esac
|
||||
|
||||
omarchy-update -y
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [[ $# -eq 0 ]]; then
|
||||
echo "Adjust Apple Display Brightness by passing +5000 or -5000 (or any range from 0-60000)"
|
||||
else
|
||||
DEVICE="$(sudo asdcontrol --detect /dev/usb/hiddev* | grep ^/dev/usb/hiddev | cut -d: -f1)"
|
||||
sudo asdcontrol "$DEVICE" -- "$1" >/dev/null
|
||||
VALUE="$(sudo asdcontrol "$DEVICE" | awk -F= '/BRIGHTNESS=/{print $2+0}')"
|
||||
swayosd-client \
|
||||
--monitor "$(hyprctl monitors -j | jq -r '.[]|select(.focused==true).name')" \
|
||||
--custom-icon display-brightness \
|
||||
--custom-progress "$(awk -v v="$VALUE" 'BEGIN{printf "%.2f", v/60000}')" \
|
||||
--custom-progress-text "$(( VALUE * 100 / 60000 ))%"
|
||||
fi
|
||||
Executable
+56
@@ -0,0 +1,56 @@
|
||||
#!/bin/bash
|
||||
|
||||
focused_monitor="$(hyprctl monitors -j | jq -r '.[] | select(.focused == true).name')"
|
||||
|
||||
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" -eq 0 ]; then
|
||||
swayosd-client \
|
||||
--monitor "$focused_monitor" \
|
||||
--custom-message "No audio devices found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
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))
|
||||
else
|
||||
next_sink_index=0
|
||||
fi
|
||||
|
||||
next_sink=$(echo "$sinks" | jq -r ".[$next_sink_index]")
|
||||
next_sink_name=$(echo "$next_sink" | jq -r '.name')
|
||||
|
||||
next_sink_description=$(echo "$next_sink" | jq -r '.description')
|
||||
if [ "$next_sink_description" = "(null)" ] || [ "$next_sink_description" = "null" ] || [ -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
|
||||
|
||||
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" -eq 0 ]; then
|
||||
icon_state="muted"
|
||||
elif [ "$next_sink_volume" -le 33 ]; then
|
||||
icon_state="low"
|
||||
elif [ "$next_sink_volume" -le 66 ]; then
|
||||
icon_state="medium"
|
||||
else
|
||||
icon_state="high"
|
||||
fi
|
||||
|
||||
next_sink_volume_icon="sink-volume-${icon_state}-symbolic"
|
||||
|
||||
if [ "$next_sink_name" != "$current_sink_name" ]; then
|
||||
pactl set-default-sink "$next_sink_name"
|
||||
fi
|
||||
|
||||
swayosd-client \
|
||||
--monitor "$focused_monitor" \
|
||||
--custom-message "$next_sink_description" \
|
||||
--custom-icon "$next_sink_volume_icon"
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
FIRST_RUN_MODE=~/.local/state/omarchy/first-run.mode
|
||||
|
||||
if [[ -f "$FIRST_RUN_MODE" ]]; then
|
||||
rm -f "$FIRST_RUN_MODE"
|
||||
|
||||
bash "$OMARCHY_PATH/install/first-run/battery-monitor.sh"
|
||||
bash "$OMARCHY_PATH/install/first-run/cleanup-reboot-sudoers.sh"
|
||||
bash "$OMARCHY_PATH/install/first-run/firewall.sh"
|
||||
bash "$OMARCHY_PATH/install/first-run/dns-resolver.sh"
|
||||
bash "$OMARCHY_PATH/install/first-run/gnome-theme.sh"
|
||||
sudo rm -f /etc/sudoers.d/first-run
|
||||
|
||||
bash "$OMARCHY_PATH/install/first-run/welcome.sh"
|
||||
bash "$OMARCHY_PATH/install/first-run/wifi.sh"
|
||||
fi
|
||||
@@ -1,7 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
# omarchy:summary=Check whether any required commands are missing
|
||||
|
||||
for cmd in "$@"; do
|
||||
if ! command -v "$cmd" &>/dev/null; then
|
||||
exit 0
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
# omarchy:summary=Check whether all required commands are available
|
||||
|
||||
for cmd in "$@"; do
|
||||
command -v "$cmd" &>/dev/null || exit 1
|
||||
done
|
||||
|
||||
Executable
+142
@@ -0,0 +1,142 @@
|
||||
#!/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
|
||||
|
||||
SCOPE=""
|
||||
AUDIO="false"
|
||||
WEBCAM="false"
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--with-audio) AUDIO="true" ;;
|
||||
--with-webcam) WEBCAM="true" ;;
|
||||
output|region) SCOPE="$arg" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
cleanup_webcam() {
|
||||
pkill -f "WebcamOverlay" 2>/dev/null
|
||||
}
|
||||
|
||||
start_webcam_overlay() {
|
||||
cleanup_webcam
|
||||
|
||||
# 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 /dev/video0 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 /dev/video0 \
|
||||
-vf "scale=${target_width}:-1" \
|
||||
-window_title "WebcamOverlay" \
|
||||
-noborder \
|
||||
-fflags nobuffer -flags low_delay \
|
||||
-probesize 32 -analyzeduration 0 \
|
||||
-loglevel quiet &
|
||||
sleep 1
|
||||
}
|
||||
|
||||
start_screenrecording() {
|
||||
local filename="$OUTPUT_DIR/screenrecording-$(date +'%Y-%m-%d_%H-%M-%S').mp4"
|
||||
local audio_args=""
|
||||
|
||||
# Merge audio tracks into one - separate tracks only play one at a time in most players
|
||||
[[ "$AUDIO" == "true" ]] && audio_args="-a default_output|default_input"
|
||||
|
||||
gpu-screen-recorder -w "$@" -f 60 -c mp4 -o "$filename" $audio_args &
|
||||
toggle_screenrecording_indicator
|
||||
}
|
||||
|
||||
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 -lt 50 ]; do
|
||||
sleep 0.1
|
||||
count=$((count + 1))
|
||||
done
|
||||
|
||||
if pgrep -f "gpu-screen-recorder" >/dev/null; then
|
||||
pkill -9 -f "gpu-screen-recorder"
|
||||
cleanup_webcam
|
||||
notify-send "Screen recording error" "Recording process had to be force-killed. Video may be corrupted." -u critical -t 5000
|
||||
else
|
||||
cleanup_webcam
|
||||
notify-send "Screen recording saved to $OUTPUT_DIR" -t 2000
|
||||
fi
|
||||
toggle_screenrecording_indicator
|
||||
}
|
||||
|
||||
toggle_screenrecording_indicator() {
|
||||
pkill -RTMIN+8 waybar
|
||||
}
|
||||
|
||||
screenrecording_active() {
|
||||
pgrep -f "gpu-screen-recorder" >/dev/null || pgrep -x slurp >/dev/null || pgrep -f "WebcamOverlay" >/dev/null
|
||||
}
|
||||
|
||||
if screenrecording_active; then
|
||||
if pgrep -x slurp >/dev/null; then
|
||||
pkill -x slurp 2>/dev/null
|
||||
elif pgrep -f "WebcamOverlay" >/dev/null && ! pgrep -f "gpu-screen-recorder" >/dev/null; then
|
||||
cleanup_webcam
|
||||
else
|
||||
stop_screenrecording
|
||||
fi
|
||||
elif [[ "$SCOPE" == "output" ]]; then
|
||||
[[ "$WEBCAM" == "true" ]] && start_webcam_overlay
|
||||
|
||||
if ! output=$(slurp -o -f "%o"); then
|
||||
[[ "$WEBCAM" == "true" ]] && cleanup_webcam
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$output" ]]; then
|
||||
notify-send "Error" "Could not detect monitor" -u critical
|
||||
[[ "$WEBCAM" == "true" ]] && cleanup_webcam
|
||||
exit 1
|
||||
fi
|
||||
|
||||
start_screenrecording "$output"
|
||||
else
|
||||
[[ "$WEBCAM" == "true" ]] && start_webcam_overlay
|
||||
|
||||
scale=$(hyprctl monitors -j | jq -r '.[] | select(.focused == true) | .scale')
|
||||
|
||||
if ! region=$(slurp -f "%wx%h+%x+%y"); then
|
||||
[[ "$WEBCAM" == "true" ]] && cleanup_webcam
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$region" =~ ^([0-9]+)x([0-9]+)\+([0-9]+)\+([0-9]+)$ ]]; then
|
||||
w=$(awk "BEGIN {printf \"%.0f\", ${BASH_REMATCH[1]} * $scale}")
|
||||
h=$(awk "BEGIN {printf \"%.0f\", ${BASH_REMATCH[2]} * $scale}")
|
||||
x=$(awk "BEGIN {printf \"%.0f\", ${BASH_REMATCH[3]} * $scale}")
|
||||
y=$(awk "BEGIN {printf \"%.0f\", ${BASH_REMATCH[4]} * $scale}")
|
||||
scaled_region="${w}x${h}+${x}+${y}"
|
||||
else
|
||||
scaled_region="$region"
|
||||
fi
|
||||
|
||||
start_screenrecording region -region "$scaled_region"
|
||||
fi
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
|
||||
screensaver_in_focus() {
|
||||
hyprctl activewindow -j | jq -e '.class == "Screensaver"' >/dev/null 2>&1
|
||||
}
|
||||
|
||||
exit_screensaver() {
|
||||
hyprctl keyword cursor:invisible false
|
||||
pkill -x tte 2>/dev/null
|
||||
pkill -f "alacritty --class Screensaver" 2>/dev/null
|
||||
exit 0
|
||||
}
|
||||
|
||||
trap exit_screensaver SIGINT SIGTERM SIGHUP SIGQUIT
|
||||
|
||||
hyprctl keyword cursor:invisible true &>/dev/null
|
||||
|
||||
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 3 || ! screensaver_in_focus; then
|
||||
exit_screensaver
|
||||
fi
|
||||
done
|
||||
done
|
||||
Executable
+83
@@ -0,0 +1,83 @@
|
||||
#!/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 && exit 0
|
||||
|
||||
MODE="${1:-smart}"
|
||||
PROCESSING="${2:-slurp}"
|
||||
|
||||
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])"'
|
||||
}
|
||||
|
||||
# Select based on mode
|
||||
case "$MODE" in
|
||||
region)
|
||||
wayfreeze & PID=$!
|
||||
sleep .1
|
||||
SELECTION=$(slurp 2>/dev/null)
|
||||
kill $PID 2>/dev/null
|
||||
;;
|
||||
windows)
|
||||
wayfreeze & PID=$!
|
||||
sleep .1
|
||||
SELECTION=$(get_rectangles | slurp -r 2>/dev/null)
|
||||
kill $PID 2>/dev/null
|
||||
;;
|
||||
fullscreen)
|
||||
SELECTION=$(hyprctl monitors -j | jq -r '.[] | select(.focused == true) | "\(.x),\(.y) \((.width / .scale) | floor)x\((.height / .scale) | floor)"')
|
||||
;;
|
||||
smart|*)
|
||||
RECTS=$(get_rectangles)
|
||||
wayfreeze & PID=$!
|
||||
sleep .1
|
||||
SELECTION=$(echo "$RECTS" | slurp 2>/dev/null)
|
||||
kill $PID 2>/dev/null
|
||||
|
||||
# If the selction 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
|
||||
|
||||
if [[ $PROCESSING == "slurp" ]]; then
|
||||
grim -g "$SELECTION" - |
|
||||
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'
|
||||
else
|
||||
grim -g "$SELECTION" - | wl-copy
|
||||
fi
|
||||
@@ -1,13 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# omarchy:summary=Share clipboard, files, or folders with LocalSend
|
||||
# omarchy:group=share
|
||||
# omarchy:name=
|
||||
# omarchy:args=<clipboard|file|folder> [path...]
|
||||
# omarchy:examples=omarchy share clipboard | omarchy share file ~/Downloads/example.txt
|
||||
|
||||
if (($# == 0)); then
|
||||
echo "Usage: omarchy-menu-share [clipboard|file|folder]"
|
||||
echo "Usage: omarchy-cmd-share [clipboard|file|folder]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -29,7 +23,7 @@ else
|
||||
# Pick one or more files from home directory
|
||||
FILES=$(find "$HOME" -type f 2>/dev/null | fzf --multi)
|
||||
fi
|
||||
[[ -z $FILES ]] && exit 0
|
||||
[ -z "$FILES" ] && exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
# omarchy:summary=Print the current working directory of the active terminal window
|
||||
# omarchy:hidden=true
|
||||
|
||||
# Go from current active terminal to its child shell process and run cwd there
|
||||
terminal_pid=$(hyprctl activewindow | awk '/pid:/ {print $2}')
|
||||
shell_pid=$(pgrep -P "$terminal_pid" | tail -n1)
|
||||
|
||||
if [[ -n $shell_pid ]]; then
|
||||
cwd=$(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
|
||||
if [[ -d $cwd ]]; then
|
||||
echo "$cwd"
|
||||
else
|
||||
echo "$HOME"
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user