Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7933b5eae0 | ||
|
|
3e4597b89c |
@@ -1,9 +0,0 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
@@ -1,24 +0,0 @@
|
||||
name: Bug
|
||||
description: Report a validated bug -- NOT FOR SUPPORT REQUESTS
|
||||
labels: [bug]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Remember: Omarchy is an open source gift, not a product you bought from a vendor
|
||||
|
||||
- type: input
|
||||
id: system-details
|
||||
attributes:
|
||||
label: System details
|
||||
placeholder: e.g. AMD 9950X, NVIDIA 5090, Omarchy 2.1.0
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: steps
|
||||
attributes:
|
||||
label: What's wrong?
|
||||
description: Describe the issue, include steps to recreate it if possible, and attach the output of `omarchy-debug` if possible
|
||||
validations:
|
||||
required: true
|
||||
@@ -1,8 +0,0 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Suggestion
|
||||
url: https://github.com/basecamp/omarchy/discussions/categories/suggestions
|
||||
about: Suggest a new feature, change to existing feature, or other ideas in Discussions.
|
||||
- name: Support
|
||||
url: https://omarchy.org/discord
|
||||
about: Need help? Join our Discord community for support with any issues. GitHub issues should be used for verified bugs only.
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"workspace": {
|
||||
"library": [
|
||||
"/usr/share/hypr/stubs"
|
||||
],
|
||||
"checkThirdParty": false
|
||||
},
|
||||
"diagnostics": {
|
||||
"globals": ["hl"]
|
||||
}
|
||||
}
|
||||
@@ -1,188 +0,0 @@
|
||||
# Style
|
||||
|
||||
- Two spaces for indentation, no tabs
|
||||
- Use bash 5 conditionals: use `[[ ]]` for string/file tests and `(( ))` for numeric tests
|
||||
- In `[[ ]]`, don't quote variables, but do quote string literals when comparing values (e.g., `[[ $branch == "dev" ]]`)
|
||||
- Prefer `(( ))` over numeric operators inside `[[ ]]` (e.g., `(( count < 50 ))`, not `[[ $count -lt 50 ]]`)
|
||||
- For strings/paths with spaces, quote them instead of escaping spaces with `\ ` (e.g., `"$APP_DIR/Disk Usage.desktop"`, not `$APP_DIR/Disk\ Usage.desktop`)
|
||||
- Shebangs must use `#!/bin/bash` consistently (never `#!/usr/bin/env bash`)
|
||||
- Scripts under `install/` and `migrations/` may be sourced and intentionally omit shebangs
|
||||
|
||||
# Command Naming
|
||||
|
||||
All commands start with `omarchy-`. Prefixes indicate purpose.
|
||||
|
||||
The authoritative command group list lives in `bin/omarchy` in `GROUP_DESCRIPTIONS`. Keep `GROUP_DESCRIPTIONS` updated when adding a new command prefix.
|
||||
|
||||
Common prefixes include:
|
||||
|
||||
- `cmd-` - check if commands exist, misc utility commands
|
||||
- `capture-` - screenshots, screen recordings, and other capture tools
|
||||
- `pkg-` - package management helpers
|
||||
- `hw-` - hardware detection (return exit codes for use in conditionals)
|
||||
- `refresh-` - copy default config to user's `~/.config/`
|
||||
- `restart-` - restart a component
|
||||
- `launch-` - open applications
|
||||
- `install-` - install optional software
|
||||
- `setup-` - interactive setup wizards
|
||||
- `toggle-` - toggle features on/off
|
||||
- `theme-` - theme management
|
||||
- `update-` - update components
|
||||
|
||||
Other current prefixes include:
|
||||
|
||||
- `ac-`, `audio-`, `battery-`, `branch-`, `brightness-`, `channel-`, `config-`, `debug-`, `dev-`, `drive-`, `first-`, `font-`, `haptic-`, `hibernation-`, `hook-`, `hyprland-`, `menu-`, `migrate-`, `notification-`, `npm-`, `plymouth-`, `powerprofiles-`, `reinstall-`, `remove-`, `screensaver-`, `show-`, `snapshot-`, `state-`, `sudo-`, `system-`, `transcode-`, `tui-`, `tz-`, `upload-`, `version-`, `voxtype-`, `webapp-`, `wifi-`, `windows-`
|
||||
|
||||
# Command Metadata
|
||||
|
||||
Commands in `bin/` can declare CLI metadata in comments near the top of the file. `bin/omarchy` scans the first 80 lines, and tests expect command metadata to remain valid.
|
||||
|
||||
Supported metadata keys:
|
||||
|
||||
- `# omarchy:summary=...` - short help text
|
||||
- `# omarchy:args=...` - usage arguments
|
||||
- `# omarchy:examples=...` - examples separated with ` | `
|
||||
- `# omarchy:alias=...` / `# omarchy:aliases=...` - alternate routes
|
||||
- `# omarchy:hidden=true` - hide from default command listings
|
||||
- `# omarchy:requires-sudo=true` - mark commands that require sudo
|
||||
|
||||
Only use `omarchy:examples` where there are args that need explaining.
|
||||
|
||||
Prefer explicit metadata for user-facing commands. Keep routes consistent with the filename unless there is a deliberate alias or compatibility route.
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
# omarchy:summary=Take a screenshot
|
||||
# omarchy:args=[smart|region|windows|fullscreen] [slurp|copy]
|
||||
# omarchy:examples=omarchy screenshot | omarchy capture screenshot region
|
||||
```
|
||||
|
||||
# Runtime Environment
|
||||
|
||||
- `$OMARCHY_PATH` is set at the top level by the uwsm session environment and is always available to Omarchy runtime code.
|
||||
- Commands in `bin/` and Quickshell QML should rely on `$OMARCHY_PATH` / `Quickshell.env("OMARCHY_PATH")`; do not derive fallback paths from `HOME`, `Quickshell.shellDir`, or re-export/default `OMARCHY_PATH` manually.
|
||||
|
||||
# Privileged Commands
|
||||
|
||||
- Whenever you need to trigger a sudo command, use `pkexec` so it results in a user prompt they can approve.
|
||||
|
||||
# Git
|
||||
|
||||
- Commits should be atomic: include only one coherent change or fix, and do not mix unrelated work.
|
||||
- Commit messages should be succinct and describe the change being made.
|
||||
|
||||
# Install Scripts
|
||||
|
||||
Install entry points (`install.sh`, `boot.sh`) use `#!/bin/bash`. Many scripts under `install/` are sourced via `run_logged` and intentionally do not have shebangs.
|
||||
|
||||
Install stage files follow this pattern:
|
||||
|
||||
- `install/*/all.sh` lists scripts in execution order
|
||||
- leaf scripts are sourced by `run_logged $OMARCHY_INSTALL/path/to/script.sh`
|
||||
- avoid `exit` in sourced install scripts unless intentionally aborting the install
|
||||
- use `$OMARCHY_INSTALL` and `$OMARCHY_PATH` instead of hard-coded Omarchy paths
|
||||
- keep hardware-specific logic under `install/config/hardware/`
|
||||
- prefer helper commands for package and command checks where available
|
||||
|
||||
Raw `command -v`, `pacman`, and `pacman-key` are acceptable in bootstrap/preflight/package-helper contexts where the helper commands may not be available yet or where direct package-manager behavior is the point of the script.
|
||||
|
||||
# Helper Commands
|
||||
|
||||
Use these instead of raw shell commands:
|
||||
|
||||
- `omarchy-cmd-missing` / `omarchy-cmd-present` - check for commands
|
||||
- `omarchy-pkg-missing` / `omarchy-pkg-present` - check for packages (don't use these if you can just use `omarchy-pkg-add`/`omarchy-pkg-drop`)
|
||||
- `omarchy-pkg-add` - install packages (handles both pacman and AUR)
|
||||
- `omarchy-pkg-drop` - remove packages; use this instead of raw `pacman -R*`
|
||||
- `omarchy-notification-send` - send desktop notifications; do not call `notify-send` directly
|
||||
- `omarchy-hw-asus-rog` - detect ASUS ROG hardware (and similar `hw-*` commands)
|
||||
|
||||
Exceptions are allowed for bootstrap, preflight, migration, and package-helper scripts where the helper may not be available yet, where the helper itself is being implemented, or where direct package-manager behavior is required.
|
||||
|
||||
# Config Structure
|
||||
|
||||
- `config/` - default configs copied to `~/.config/`
|
||||
- `default/themed/*.tpl` - templates with `{{ variable }}` placeholders for theme colors
|
||||
- `themes/*/colors.toml` - theme color definitions (accent, background, foreground, red/green/yellow/blue/magenta/cyan and bright_* variants)
|
||||
|
||||
# Tests
|
||||
|
||||
Run focused automated tests for the area you changed. Current test entry points:
|
||||
|
||||
- `./test/all` - aggregate runner for CLI and shell tests
|
||||
- `./test/cli` - CLI routing, command metadata, theme helpers, and safe dispatch coverage
|
||||
- `./test/shell` - all Omarchy shell tests under `test/shell.d/`
|
||||
|
||||
New Omarchy shell tests should live in `test/shell.d/*-test.sh` so `./test/shell` picks them up automatically. Source `test/shell.d/base-test.sh` for shared root-path discovery, assertions, and Node test helpers.
|
||||
|
||||
For visual changes, such as omarchy-shell styling, desktop appearance, screenshots, or screen recording flows, verify with the running UI in addition to automated tests. Take and analyze screenshots with `omarchy capture screenshot fullscreen save`. For animation, transitions, capture, or screen recording behavior, make a short recording with `omarchy screenrecord --fullscreen`, stop it with `omarchy screenrecord --stop-recording`, and review the output before finishing.
|
||||
|
||||
For interactive UI work, use `wtype` to simulate keyboard input when available. Example: start the UI in the background, wait briefly for focus, then run `wtype -k Right -k Return` to exercise keyboard selection and confirm the resulting command output or state change. Prefer this over manual-only verification when a UI returns a selected value or changes a symlink/config.
|
||||
|
||||
When testing layer-shell UI, capture the reference and candidate states as separate screenshots, then compare them visually before further edits. If a launched UI would otherwise remain open, keep track of its PID and stop it after the screenshot; avoid broad process kills unless checking with `ps` first.
|
||||
|
||||
# Omarchy shell
|
||||
|
||||
The Quickshell desktop runs as a single long-running process out of
|
||||
`shell/`. Hyprland autostart launches it directly with `quickshell -p`; do
|
||||
not start additional standalone `quickshell -p` instances for individual
|
||||
components.
|
||||
|
||||
Run `omarchy-restart-shell` after making changes to QML files.
|
||||
|
||||
Plugin contract:
|
||||
|
||||
- Each plugin lives in its own directory under
|
||||
`shell/plugins/<id>/` (first-party) or
|
||||
`~/.config/omarchy/plugins/<id>/` (third-party).
|
||||
- Every plugin ships a `manifest.json` declaring `id`, `kinds`,
|
||||
`activation`, and `entryPoints`. The full schema is in
|
||||
[`docs/omarchy-shell.md`](docs/omarchy-shell.md).
|
||||
- Entry-point QML files are `Item`s (not `ShellRoot`), and accept the
|
||||
shell-injected properties `omarchyPath`, `shell`, `manifest`, and
|
||||
`pluginRegistry` / `barWidgetRegistry` as appropriate.
|
||||
- Panel / overlay / menu plugins must expose `open(payloadJson)` and
|
||||
`close()` lifecycle methods for `shell summon` and `shell hide`.
|
||||
|
||||
IPC:
|
||||
|
||||
- `bin/omarchy-shell` is the canonical IPC entry point. It forwards to
|
||||
the running shell and does not start it. Prefer it over re-implementing
|
||||
direct Quickshell socket calls in every CLI.
|
||||
- The `shell` IPC target exposes `ping`, `summon`, `hide`, `toggle`,
|
||||
`rescanPlugins`, `setPluginEnabled`, and `listPlugins`. Individual
|
||||
plugins can register additional IPC targets (the bar registers `bar`,
|
||||
the background switcher registers `image-selector`).
|
||||
|
||||
Widget files in `shell/plugins/bar/widgets/` contain Nerd Font glyphs as raw
|
||||
unicode characters. The `Write` and `Edit` tools strip multi-byte
|
||||
codepoints in some positions — do **not** rewrite widget files wholesale
|
||||
through those tools. For glyph fixes, use the targeted `Edit` tool with
|
||||
the surrounding context, or a Python script that inserts codepoints via
|
||||
`chr(0xXXXXX)`.
|
||||
|
||||
# Refresh Pattern
|
||||
|
||||
To copy a default config to user config with automatic backup:
|
||||
|
||||
```bash
|
||||
omarchy-refresh-config hypr/hyprlock.conf
|
||||
```
|
||||
|
||||
This copies `~/.local/share/omarchy/config/hypr/hyprlock.conf` to `~/.config/hypr/hyprlock.conf`.
|
||||
|
||||
# Migrations
|
||||
|
||||
To create a new migration, run `omarchy-dev-add-migration --no-edit`. This creates a migration file named after the unix timestamp of the last commit.
|
||||
|
||||
New migration format:
|
||||
- File permissions must be `0644` (`-rw-r--r--`); migrations are sourced, not executed directly
|
||||
- No shebang line
|
||||
- Start with an `echo` describing what the migration does
|
||||
- Use `$OMARCHY_PATH` to reference the omarchy directory
|
||||
- Prefer helper commands such as `omarchy-cmd-present`, `omarchy-cmd-missing`, `omarchy-pkg-present`, and `omarchy-pkg-missing`
|
||||
|
||||
Some older migrations predate these rules. Do not copy older migrations that start with shebangs, omit the leading `echo`, or hard-code `~/.local/share/omarchy`.
|
||||
|
||||
Migrations may use raw `pacman`, `command -v`, or direct config edits when needed for historical compatibility or one-off repair work.
|
||||
@@ -1,13 +1,10 @@
|
||||
# Omarchy
|
||||
|
||||
Omarchy is a beautiful, modern & opinionated Linux distribution by DHH.
|
||||
Turn a fresh Arch installation into a fully-configured, beautiful, and modern web development system based on Hyprland by running a single command. That's the one-line pitch for Omarchy (like it was for Omakub). No need to write bespoke configs for every essential tool just to get started or to be up on all the latest command-line tools. Omarchy is an opinionated take on what Linux can be at its best.
|
||||
|
||||
Read more at [omarchy.org](https://omarchy.org).
|
||||
|
||||
## 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).
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
[Desktop Entry]
|
||||
Version=1.0
|
||||
Name=About
|
||||
Comment=System information from Fastfetch
|
||||
Exec=alacritty -o "font.size=9" --class=About --title=About -e bash -c 'fastfetch; read -n 1 -s'
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Icon=Arch
|
||||
Categories=GTK;
|
||||
StartupNotify=false
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
[Desktop Entry]
|
||||
Version=1.0
|
||||
Name=Activity
|
||||
Comment=System activity from btop
|
||||
Exec=alacritty --class=Activity --title=Activity -e btop
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Icon=Activity
|
||||
Categories=GTK;
|
||||
StartupNotify=false
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
[Desktop Entry]
|
||||
Version=1.0
|
||||
Name=Docker
|
||||
Comment=Manage Docker containers with LazyDocker
|
||||
Exec=alacritty --class=Docker --title=Docker -e lazydocker
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Icon=Docker
|
||||
Categories=GTK;
|
||||
StartupNotify=false
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=Battle.net
|
||||
GenericName=Game Launcher
|
||||
Comment=Blizzard game launcher (umu-launcher + GE-Proton)
|
||||
Exec=omarchy-launch-battlenet
|
||||
Icon=Battle.net
|
||||
Terminal=false
|
||||
Categories=Game;
|
||||
StartupNotify=true
|
||||
StartupWMClass=battle.net.exe
|
||||
@@ -0,0 +1,221 @@
|
||||
[Desktop Entry]
|
||||
Version=1.0
|
||||
Name=Chromium
|
||||
# Only KDE 4 seems to use GenericName, so we reuse the KDE strings.
|
||||
# From Ubuntu's language-pack-kde-XX-base packages, version 9.04-20090413.
|
||||
GenericName=Web Browser
|
||||
GenericName[ar]=متصفح الشبكة
|
||||
GenericName[bg]=Уеб браузър
|
||||
GenericName[ca]=Navegador web
|
||||
GenericName[cs]=WWW prohlížeč
|
||||
GenericName[da]=Browser
|
||||
GenericName[de]=Web-Browser
|
||||
GenericName[el]=Περιηγητής ιστού
|
||||
GenericName[en_GB]=Web Browser
|
||||
GenericName[es]=Navegador web
|
||||
GenericName[et]=Veebibrauser
|
||||
GenericName[fi]=WWW-selain
|
||||
GenericName[fr]=Navigateur Web
|
||||
GenericName[gu]=વેબ બ્રાઉઝર
|
||||
GenericName[he]=דפדפן אינטרנט
|
||||
GenericName[hi]=वेब ब्राउज़र
|
||||
GenericName[hu]=Webböngésző
|
||||
GenericName[it]=Browser Web
|
||||
GenericName[ja]=ウェブブラウザ
|
||||
GenericName[kn]=ಜಾಲ ವೀಕ್ಷಕ
|
||||
GenericName[ko]=웹 브라우저
|
||||
GenericName[lt]=Žiniatinklio naršyklė
|
||||
GenericName[lv]=Tīmekļa pārlūks
|
||||
GenericName[ml]=വെബ് ബ്രൌസര്
|
||||
GenericName[mr]=वेब ब्राऊजर
|
||||
GenericName[nb]=Nettleser
|
||||
GenericName[nl]=Webbrowser
|
||||
GenericName[pl]=Przeglądarka WWW
|
||||
GenericName[pt]=Navegador Web
|
||||
GenericName[pt_BR]=Navegador da Internet
|
||||
GenericName[ro]=Navigator de Internet
|
||||
GenericName[ru]=Веб-браузер
|
||||
GenericName[sl]=Spletni brskalnik
|
||||
GenericName[sv]=Webbläsare
|
||||
GenericName[ta]=இணைய உலாவி
|
||||
GenericName[th]=เว็บเบราว์เซอร์
|
||||
GenericName[tr]=Web Tarayıcı
|
||||
GenericName[uk]=Навігатор Тенет
|
||||
GenericName[zh_CN]=网页浏览器
|
||||
GenericName[zh_HK]=網頁瀏覽器
|
||||
GenericName[zh_TW]=網頁瀏覽器
|
||||
# Not translated in KDE, from Epiphany 2.26.1-0ubuntu1.
|
||||
GenericName[bn]=ওয়েব ব্রাউজার
|
||||
GenericName[fil]=Web Browser
|
||||
GenericName[hr]=Web preglednik
|
||||
GenericName[id]=Browser Web
|
||||
GenericName[or]=ଓ୍ବେବ ବ୍ରାଉଜର
|
||||
GenericName[sk]=WWW prehliadač
|
||||
GenericName[sr]=Интернет прегледник
|
||||
GenericName[te]=మహాతల అన్వేషి
|
||||
GenericName[vi]=Bộ duyệt Web
|
||||
# Gnome and KDE 3 uses Comment.
|
||||
Comment=Access the Internet
|
||||
Comment[ar]=الدخول إلى الإنترنت
|
||||
Comment[bg]=Достъп до интернет
|
||||
Comment[bn]=ইন্টারনেটটি অ্যাক্সেস করুন
|
||||
Comment[ca]=Accedeix a Internet
|
||||
Comment[cs]=Přístup k internetu
|
||||
Comment[da]=Få adgang til internettet
|
||||
Comment[de]=Internetzugriff
|
||||
Comment[el]=Πρόσβαση στο Διαδίκτυο
|
||||
Comment[en_GB]=Access the Internet
|
||||
Comment[es]=Accede a Internet.
|
||||
Comment[et]=Pääs Internetti
|
||||
Comment[fi]=Käytä internetiä
|
||||
Comment[fil]=I-access ang Internet
|
||||
Comment[fr]=Accéder à Internet
|
||||
Comment[gu]=ઇંટરનેટ ઍક્સેસ કરો
|
||||
Comment[he]=גישה אל האינטרנט
|
||||
Comment[hi]=इंटरनेट तक पहुंच स्थापित करें
|
||||
Comment[hr]=Pristup Internetu
|
||||
Comment[hu]=Internetelérés
|
||||
Comment[id]=Akses Internet
|
||||
Comment[it]=Accesso a Internet
|
||||
Comment[ja]=インターネットにアクセス
|
||||
Comment[kn]=ಇಂಟರ್ನೆಟ್ ಅನ್ನು ಪ್ರವೇಶಿಸಿ
|
||||
Comment[ko]=인터넷 연결
|
||||
Comment[lt]=Interneto prieiga
|
||||
Comment[lv]=Piekļūt internetam
|
||||
Comment[ml]=ഇന്റര്നെറ്റ് ആക്സസ് ചെയ്യുക
|
||||
Comment[mr]=इंटरनेटमध्ये प्रवेश करा
|
||||
Comment[nb]=Gå til Internett
|
||||
Comment[nl]=Verbinding maken met internet
|
||||
Comment[or]=ଇଣ୍ଟର୍ନେଟ୍ ପ୍ରବେଶ କରନ୍ତୁ
|
||||
Comment[pl]=Skorzystaj z internetu
|
||||
Comment[pt]=Aceder à Internet
|
||||
Comment[pt_BR]=Acessar a internet
|
||||
Comment[ro]=Accesaţi Internetul
|
||||
Comment[ru]=Доступ в Интернет
|
||||
Comment[sk]=Prístup do siete Internet
|
||||
Comment[sl]=Dostop do interneta
|
||||
Comment[sr]=Приступите Интернету
|
||||
Comment[sv]=Gå ut på Internet
|
||||
Comment[ta]=இணையத்தை அணுகுதல்
|
||||
Comment[te]=ఇంటర్నెట్ను ఆక్సెస్ చెయ్యండి
|
||||
Comment[th]=เข้าถึงอินเทอร์เน็ต
|
||||
Comment[tr]=İnternet'e erişin
|
||||
Comment[uk]=Доступ до Інтернету
|
||||
Comment[vi]=Truy cập Internet
|
||||
Comment[zh_CN]=访问互联网
|
||||
Comment[zh_HK]=連線到網際網路
|
||||
Comment[zh_TW]=連線到網際網路
|
||||
Exec=/usr/bin/chromium --ozone-platform=wayland %U
|
||||
StartupNotify=true
|
||||
Terminal=false
|
||||
Icon=chromium
|
||||
Type=Application
|
||||
Categories=Network;WebBrowser;
|
||||
MimeType=application/pdf;application/rdf+xml;application/rss+xml;application/xhtml+xml;application/xhtml_xml;application/xml;image/gif;image/jpeg;image/png;image/webp;text/html;text/xml;x-scheme-handler/http;x-scheme-handler/https;
|
||||
Actions=new-window;new-private-window;
|
||||
|
||||
[Desktop Action new-window]
|
||||
Name=New Window
|
||||
Name[am]=አዲስ መስኮት
|
||||
Name[ar]=نافذة جديدة
|
||||
Name[bg]=Нов прозорец
|
||||
Name[bn]=নতুন উইন্ডো
|
||||
Name[ca]=Finestra nova
|
||||
Name[cs]=Nové okno
|
||||
Name[da]=Nyt vindue
|
||||
Name[de]=Neues Fenster
|
||||
Name[el]=Νέο Παράθυρο
|
||||
Name[en_GB]=New Window
|
||||
Name[es]=Nueva ventana
|
||||
Name[et]=Uus aken
|
||||
Name[fa]=پنجره جدید
|
||||
Name[fi]=Uusi ikkuna
|
||||
Name[fil]=New Window
|
||||
Name[fr]=Nouvelle fenêtre
|
||||
Name[gu]=નવી વિંડો
|
||||
Name[hi]=नई विंडो
|
||||
Name[hr]=Novi prozor
|
||||
Name[hu]=Új ablak
|
||||
Name[id]=Jendela Baru
|
||||
Name[it]=Nuova finestra
|
||||
Name[iw]=חלון חדש
|
||||
Name[ja]=新規ウインドウ
|
||||
Name[kn]=ಹೊಸ ವಿಂಡೊ
|
||||
Name[ko]=새 창
|
||||
Name[lt]=Naujas langas
|
||||
Name[lv]=Jauns logs
|
||||
Name[ml]=പുതിയ വിന്ഡോ
|
||||
Name[mr]=नवीन विंडो
|
||||
Name[nl]=Nieuw venster
|
||||
Name[no]=Nytt vindu
|
||||
Name[pl]=Nowe okno
|
||||
Name[pt]=Nova janela
|
||||
Name[pt_BR]=Nova janela
|
||||
Name[ro]=Fereastră nouă
|
||||
Name[ru]=Новое окно
|
||||
Name[sk]=Nové okno
|
||||
Name[sl]=Novo okno
|
||||
Name[sr]=Нови прозор
|
||||
Name[sv]=Nytt fönster
|
||||
Name[sw]=Dirisha Jipya
|
||||
Name[ta]=புதிய சாளரம்
|
||||
Name[te]=క్రొత్త విండో
|
||||
Name[th]=หน้าต่างใหม่
|
||||
Name[tr]=Yeni Pencere
|
||||
Name[uk]=Нове вікно
|
||||
Name[vi]=Cửa sổ Mới
|
||||
Name[zh_CN]=新建窗口
|
||||
Name[zh_TW]=開新視窗
|
||||
Exec=/usr/bin/chromium --ozone-platform=wayland --new-window
|
||||
|
||||
[Desktop Action new-private-window]
|
||||
Name=New Incognito Window
|
||||
Name[ar]=نافذة جديدة للتصفح المتخفي
|
||||
Name[bg]=Нов прозорец „инкогнито“
|
||||
Name[bn]=নতুন ছদ্মবেশী উইন্ডো
|
||||
Name[ca]=Finestra d'incògnit nova
|
||||
Name[cs]=Nové anonymní okno
|
||||
Name[da]=Nyt inkognitovindue
|
||||
Name[de]=Neues Inkognito-Fenster
|
||||
Name[el]=Νέο παράθυρο για ανώνυμη περιήγηση
|
||||
Name[en_GB]=New Incognito window
|
||||
Name[es]=Nueva ventana de incógnito
|
||||
Name[et]=Uus inkognito aken
|
||||
Name[fa]=پنجره جدید حالت ناشناس
|
||||
Name[fi]=Uusi incognito-ikkuna
|
||||
Name[fil]=Bagong Incognito window
|
||||
Name[fr]=Nouvelle fenêtre de navigation privée
|
||||
Name[gu]=નવી છુપી વિંડો
|
||||
Name[hi]=नई गुप्त विंडो
|
||||
Name[hr]=Novi anoniman prozor
|
||||
Name[hu]=Új Inkognitóablak
|
||||
Name[id]=Jendela Penyamaran baru
|
||||
Name[it]=Nuova finestra di navigazione in incognito
|
||||
Name[iw]=חלון חדש לגלישה בסתר
|
||||
Name[ja]=新しいシークレット ウィンドウ
|
||||
Name[kn]=ಹೊಸ ಅಜ್ಞಾತ ವಿಂಡೋ
|
||||
Name[ko]=새 시크릿 창
|
||||
Name[lt]=Naujas inkognito langas
|
||||
Name[lv]=Jauns inkognito režīma logs
|
||||
Name[ml]=പുതിയ വേഷ പ്രച്ഛന്ന വിന്ഡോ
|
||||
Name[mr]=नवीन गुप्त विंडो
|
||||
Name[nl]=Nieuw incognitovenster
|
||||
Name[no]=Nytt inkognitovindu
|
||||
Name[pl]=Nowe okno incognito
|
||||
Name[pt]=Nova janela de navegação anónima
|
||||
Name[pt_BR]=Nova janela anônima
|
||||
Name[ro]=Fereastră nouă incognito
|
||||
Name[ru]=Новое окно в режиме инкогнито
|
||||
Name[sk]=Nové okno inkognito
|
||||
Name[sl]=Novo okno brez beleženja zgodovine
|
||||
Name[sr]=Нови прозор за прегледање без архивирања
|
||||
Name[sv]=Nytt inkognitofönster
|
||||
Name[ta]=புதிய மறைநிலைச் சாளரம்
|
||||
Name[te]=క్రొత్త అజ్ఞాత విండో
|
||||
Name[th]=หน้าต่างใหม่ที่ไม่ระบุตัวตน
|
||||
Name[tr]=Yeni Gizli pencere
|
||||
Name[uk]=Нове вікно в режимі анонімного перегляду
|
||||
Name[vi]=Cửa sổ ẩn danh mới
|
||||
Name[zh_CN]=新建隐身窗口
|
||||
Name[zh_TW]=新增無痕式視窗
|
||||
Exec=/usr/bin/chromium --ozone-platform=wayland --new-window --incognito
|
||||
@@ -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
|
||||
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 9.8 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 196 KiB |
|
Before Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 75 KiB |
@@ -0,0 +1,12 @@
|
||||
[Desktop Entry]
|
||||
Name=Neovim
|
||||
GenericName=Text Editor
|
||||
Comment=Edit text files
|
||||
Exec=alacritty --class=nvim --title=nvim -e nvim -- %F
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Keywords=Text;editor;
|
||||
Icon=nvim
|
||||
Categories=Utility;TextEditor;
|
||||
StartupNotify=false
|
||||
MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++;
|
||||
@@ -0,0 +1,7 @@
|
||||
[Desktop Entry]
|
||||
Name=Audio Settings
|
||||
Comment=Using Wiremix
|
||||
Exec=alacritty --class=Wiremix --title=Wiremix -e wiremix
|
||||
Icon=audio-headphones
|
||||
Type=Application
|
||||
Terminal=false
|
||||
@@ -0,0 +1,12 @@
|
||||
[Desktop Entry]
|
||||
Name=Zoom
|
||||
Comment=Zoom Video Conference
|
||||
Exec=env QT_SCALE_FACTOR=2 /usr/bin/zoom %U
|
||||
Icon=Zoom
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Encoding=UTF-8
|
||||
Categories=Network;Application;
|
||||
StartupWMClass=zoom
|
||||
MimeType=x-scheme-handler/zoommtg;x-scheme-handler/zoomus;x-scheme-handler/tel;x-scheme-handler/callto;x-scheme-handler/zoomphonecall;x-scheme-handler/zoomphonesms;x-scheme-handler/zoomcontactcentercall;application/x-zoom
|
||||
X-KDE-Protocols=zoommtg;zoomus;tel;callto;zoomphonecall;zoomphonesms;zoomcontactcentercall;
|
||||
@@ -0,0 +1,2 @@
|
||||
[Desktop Entry]
|
||||
Hidden=true
|
||||
@@ -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"
|
||||
@@ -0,0 +1,30 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Designed to be run by systemd timer every 30 seconds and alerts if battery is low
|
||||
|
||||
BATTERY_THRESHOLD=10
|
||||
NOTIFICATION_FLAG="/run/user/$UID/omarchy_battery_notified"
|
||||
|
||||
get_battery_percentage() {
|
||||
upower -i $(upower -e | grep 'BAT') | grep -E "percentage" | grep -o '[0-9]\+%' | sed 's/%//'
|
||||
}
|
||||
|
||||
get_battery_state() {
|
||||
upower -i $(upower -e | grep 'BAT') | grep -E "state" | awk '{print $2}'
|
||||
}
|
||||
|
||||
send_notification() {
|
||||
notify-send -u critical " Time to recharge!" "Battery is down to ${1}%" -i battery-caution -t 30000
|
||||
}
|
||||
|
||||
BATTERY_LEVEL=$(get_battery_percentage)
|
||||
BATTERY_STATE=$(get_battery_state)
|
||||
|
||||
if [[ "$BATTERY_STATE" == "discharging" && "$BATTERY_LEVEL" -le "$BATTERY_THRESHOLD" ]]; then
|
||||
if [[ ! -f "$NOTIFICATION_FLAG" ]]; then
|
||||
send_notification "$BATTERY_LEVEL"
|
||||
touch "$NOTIFICATION_FLAG"
|
||||
fi
|
||||
else
|
||||
rm -f "$NOTIFICATION_FLAG"
|
||||
fi
|
||||
@@ -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 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# omarchy:summary=Returns the battery percentage remaining as an integer.
|
||||
|
||||
upower -i $(upower -e | grep BAT) | awk '/percentage/ {
|
||||
print int($2)
|
||||
exit
|
||||
}'
|
||||
@@ -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,18 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# omarchy:summary=Set the branch for Omarchy's git repository.
|
||||
# omarchy:args=<master|rc|dev>
|
||||
|
||||
if (($# == 0)); then
|
||||
echo "Usage: omarchy-branch-set [master|rc|dev]"
|
||||
exit 1
|
||||
else
|
||||
branch="$1"
|
||||
fi
|
||||
|
||||
if [[ $branch != "master" && $branch != "rc" && $branch != "dev" ]]; then
|
||||
echo "Error: Invalid branch '$branch'. Must be one of: master, rc, dev"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
git -C $OMARCHY_PATH switch $branch
|
||||
@@ -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,22 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# omarchy:summary=Set the Omarchy channel, which dictates what git branch and package repository is used.
|
||||
# omarchy:args=<stable|rc|edge|dev>
|
||||
# omarchy:requires-sudo=true
|
||||
|
||||
if (($# == 0)); then
|
||||
echo "Usage: omarchy-channel-set [stable|rc|edge|dev]"
|
||||
exit 1
|
||||
else
|
||||
channel="$1"
|
||||
fi
|
||||
|
||||
case "$channel" in
|
||||
"stable") omarchy-branch-set "master" && omarchy-refresh-pacman "stable" ;;
|
||||
"rc") omarchy-branch-set "rc" && omarchy-refresh-pacman "rc" ;;
|
||||
"edge") omarchy-branch-set "master" && omarchy-refresh-pacman "edge" ;;
|
||||
"dev") omarchy-branch-set "dev" && omarchy-refresh-pacman "edge" ;;
|
||||
*) echo "Unknown channel: $channel"; exit 1; ;;
|
||||
esac
|
||||
|
||||
omarchy-update -y
|
||||
@@ -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
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [[ $# -eq 0 ]]; then
|
||||
echo "Adjust Apple Display Brightness by passing +5000 or -5000 (or any range from 0-60000)"
|
||||
else
|
||||
sudo asdcontrol $(sudo asdcontrol --detect /dev/usb/hiddev* | grep ^/dev/usb/hiddev | cut -d: -f1) -- "$1"
|
||||
fi
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# omarchy:summary=Check whether any required commands are missing
|
||||
|
||||
for cmd in "$@"; do
|
||||
if ! command -v "$cmd" &>/dev/null; then
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
|
||||
exit 1
|
||||
@@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# omarchy:summary=Check whether all required commands are available
|
||||
|
||||
for cmd in "$@"; do
|
||||
command -v "$cmd" &>/dev/null || exit 1
|
||||
done
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
|
||||
[[ -f ~/.config/user-dirs.dirs ]] && source ~/.config/user-dirs.dirs
|
||||
OUTPUT_DIR="${OMARCHY_SCREENRECORD_DIR:-${XDG_VIDEOS_DIR:-$HOME/Videos}}"
|
||||
|
||||
if [[ ! -d "$OUTPUT_DIR" ]]; then
|
||||
notify-send "Screen recording directory does not exist: $OUTPUT_DIR" -u critical -t 3000
|
||||
exit 1
|
||||
fi
|
||||
|
||||
screenrecording() {
|
||||
filename="$OUTPUT_DIR/screenrecording-$(date +'%Y-%m-%d_%H-%M-%S').mp4"
|
||||
notify-send "Screen recording starting..." -t 1000
|
||||
sleep 1
|
||||
|
||||
if lspci | grep -qi 'nvidia'; then
|
||||
wf-recorder -f "$filename" -c libx264 -p crf=23 -p preset=medium -p movflags=+faststart "$@"
|
||||
else
|
||||
wl-screenrec -f "$filename" --ffmpeg-encoder-options="-c:v libx264 -crf 23 -preset medium -movflags +faststart" "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
if pgrep -x wl-screenrec >/dev/null || pgrep -x wf-recorder >/dev/null; then
|
||||
pkill -x wl-screenrec
|
||||
pkill -x wf-recorder
|
||||
notify-send "Screen recording saved to $OUTPUT_DIR" -t 2000
|
||||
elif [[ "$1" == "output" ]]; then
|
||||
screenrecording
|
||||
else
|
||||
region=$(slurp) || exit 1
|
||||
screenrecording -g "$region"
|
||||
fi
|
||||
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
|
||||
if command -v tte &>/dev/null; then
|
||||
while true; do
|
||||
effect=$(tte 2>&1 | grep -oP '{\K[^}]+' | tr ',' ' ' | tr ' ' '\n' | sed -n '/^beams$/,$p' | sort -u | shuf -n1)
|
||||
tte -i ~/.local/share/omarchy/logo.txt \
|
||||
--frame-rate 240 --canvas-width 0 --canvas-height $(($(tput lines) - 2)) --anchor-canvas c --anchor-text c \
|
||||
"$effect" &
|
||||
|
||||
while pgrep tte >/dev/null; do
|
||||
if read -n 1 -t 0.01; then
|
||||
pkill tte 2>/dev/null
|
||||
pkill -f "alacritty --class Screensaver" 2>/dev/null
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
done
|
||||
else
|
||||
gum spin --title "Can't find tte. Try: pip install terminaltexteffects" -- sleep 2
|
||||
fi
|
||||
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
|
||||
[[ -f ~/.config/user-dirs.dirs ]] && source ~/.config/user-dirs.dirs
|
||||
OUTPUT_DIR="${OMARCHY_SCREENSHOT_DIR:-${XDG_PICTURES_DIR:-$HOME/Pictures}}"
|
||||
|
||||
if [[ ! -d "$OUTPUT_DIR" ]]; then
|
||||
notify-send "Screenshot directory does not exist: $OUTPUT_DIR" -u critical -t 3000
|
||||
exit 1
|
||||
fi
|
||||
|
||||
pkill slurp || hyprshot -m ${1:-region} --raw |
|
||||
satty --filename - \
|
||||
--output-filename "$OUTPUT_DIR/screenshot-$(date +'%Y-%m-%d_%H-%M-%S').png" \
|
||||
--early-exit \
|
||||
--actions-on-enter save-to-clipboard \
|
||||
--save-after-copy \
|
||||
--copy-command 'wl-copy'
|
||||