Compare commits
90
Commits
No files matched your search
@@ -104,7 +104,7 @@ Use these instead of raw shell commands:
|
|||||||
|
|
||||||
- `omarchy-cmd-missing` / `omarchy-cmd-present` - check for commands
|
- `omarchy-cmd-missing` / `omarchy-cmd-present` - check for commands
|
||||||
- `omarchy-pkg-missing` / `omarchy-pkg-present` - check for packages (don't use these if you can just use `omarchy-pkg-add`/`omarchy-pkg-drop`)
|
- `omarchy-pkg-missing` / `omarchy-pkg-present` - check for packages (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-add` - install packages from the configured pacman repos, Omarchy's included; use `omarchy-pkg-aur-add` for AUR packages
|
||||||
- `omarchy-pkg-drop` - remove packages; use this instead of raw `pacman -R*`
|
- `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-notification-send` - send desktop notifications; do not call `notify-send` directly
|
||||||
- `omarchy-hw-asus-rog` - detect ASUS ROG hardware (and similar `hw-*` commands)
|
- `omarchy-hw-asus-rog` - detect ASUS ROG hardware (and similar `hw-*` commands)
|
||||||
@@ -113,6 +113,10 @@ Commands installed by Omarchy's default package set are runtime invariants. Invo
|
|||||||
|
|
||||||
Exceptions are allowed for migration and package-helper scripts where the helper may not be available yet, where the helper itself is being implemented, or where direct package-manager behavior is required.
|
Exceptions are allowed for 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.
|
||||||
|
|
||||||
|
# Background Work
|
||||||
|
|
||||||
|
- Long-running code (the shell, daemons, watchers) reacts to events instead of polling with a timer. Polling is the last resort, for state with no change signal; [`agents/skills/shell-dev.md`](agents/skills/shell-dev.md) lists the event sources and the push-refresh pattern.
|
||||||
|
|
||||||
# Menu
|
# Menu
|
||||||
|
|
||||||
- The menu definition lives in `default/omarchy/omarchy-menu.jsonc`;
|
- The menu definition lives in `default/omarchy/omarchy-menu.jsonc`;
|
||||||
@@ -120,6 +124,19 @@ Exceptions are allowed for migration and package-helper scripts where the helper
|
|||||||
- Do not add `aliases` to new menu entries. Aliases are reserved for
|
- Do not add `aliases` to new menu entries. Aliases are reserved for
|
||||||
established alternate names users already type, kept for compatibility.
|
established alternate names users already type, kept for compatibility.
|
||||||
|
|
||||||
|
# Language
|
||||||
|
|
||||||
|
- `omarchy-language en|zh` (Setup > Language) owns `LANG` in `/etc/locale.conf`; the installer sets it from its first screen. Nothing in `omarchy update` or migrations may change `/etc/locale.conf`.
|
||||||
|
- Chinese menu labels live in `default/omarchy/omarchy-menu.zh-cn.jsonc`, merged when `LANG` starts with `zh_CN`; give a new menu row with translatable words a label there.
|
||||||
|
- Shell text goes through `I18n.tr("English %1", arg)` from `qs.Commons`, with its Chinese in `shell/Commons/I18nZh.js` keyed by the English. Notifications and OSD messages are worded by their sender with `omarchy-text "English %1" "$arg"` (Python: `text()`, QML: `I18n.tr`), which reads the same table; the shell shows them as given, so user text is never translated. `test/shell.d/shell-i18n-test.sh` fails on a missing entry.
|
||||||
|
|
||||||
|
# Region
|
||||||
|
|
||||||
|
- `/etc/omarchy/region` holds the region the installer derived from the timezone (`cn`); no file means Global. The profile lives in `default/regions/cn/`, its contract in `docs/regions.md`.
|
||||||
|
- `install/config/region.sh` links the `cn` developer mirrors into `/etc` and `/.cargo` and refuses to replace a regular file it did not create. It serves both the install (the marker) and `omarchy region cn|global` (`OMARCHY_REGION`), which also records or removes the marker; Global removes only the links it made.
|
||||||
|
- `omarchy-region` prints the region (`Global` or `China`) and switches it. Nothing in `omarchy update` or migrations may change the region.
|
||||||
|
- China-only menu rows carry `"when":"[[ \"$(omarchy-region)\" == \"China\" ]]"` on every row, not only the submenu, because search checks each row's own guard. User-facing docs: `manual/52-china.md`.
|
||||||
|
|
||||||
# Config Structure
|
# Config Structure
|
||||||
|
|
||||||
- `config/` - default configs copied to `~/.config/`
|
- `config/` - default configs copied to `~/.config/`
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ The manual lives in [`manual/`](manual/), which is its authoritative source.
|
|||||||
- [Omarchy on...](manual/49-omarchy-on.md)
|
- [Omarchy on...](manual/49-omarchy-on.md)
|
||||||
- [Dual Boot Install](manual/50-dual-boot-install.md)
|
- [Dual Boot Install](manual/50-dual-boot-install.md)
|
||||||
- [Unattended Installs](manual/51-unattended-installs.md)
|
- [Unattended Installs](manual/51-unattended-installs.md)
|
||||||
|
- [China](manual/52-china.md)
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,10 @@ Run `omarchy-restart-shell` after making changes to QML files.
|
|||||||
- Panel / overlay / menu plugins must expose `open(payloadJson)` and
|
- Panel / overlay / menu plugins must expose `open(payloadJson)` and
|
||||||
`close()` lifecycle methods for `shell summon` and `shell hide`.
|
`close()` lifecycle methods for `shell summon` and `shell hide`.
|
||||||
|
|
||||||
|
## Text
|
||||||
|
|
||||||
|
Wrap every user-visible string in `I18n.tr()` (`import qs.Commons`) and add its Chinese to `shell/Commons/I18nZh.js`; plain JS models that Node tests load stay English, and their text is wrapped where QML shows it.
|
||||||
|
|
||||||
## IPC
|
## IPC
|
||||||
|
|
||||||
- `bin/omarchy-shell` is the canonical IPC entry point. It forwards to
|
- `bin/omarchy-shell` is the canonical IPC entry point. It forwards to
|
||||||
@@ -38,6 +42,17 @@ Run `omarchy-restart-shell` after making changes to QML files.
|
|||||||
bar widgets register one target each — `omarchy.indicators`,
|
bar widgets register one target each — `omarchy.indicators`,
|
||||||
`omarchy.system-update`, `omarchy.clock`. There is no `bar` target.
|
`omarchy.system-update`, `omarchy.clock`. There is no `bar` target.
|
||||||
|
|
||||||
|
## Keeping state current without polling
|
||||||
|
|
||||||
|
The shell runs all day on battery, and a widget is built once per monitor, so a `Timer` that starts a `Process` costs that process times the number of monitors, every tick, forever. Don't poll for state that only changes through known events. Pick the first of these that fits:
|
||||||
|
|
||||||
|
- A native Quickshell service that signals on change: `UPower` and `PowerProfiles` (`Quickshell.Services.UPower`), `Hyprland` and each workspace's `lastIpcObject`, `Pipewire`, `Mpris`, `SystemTray`, `Notifications`.
|
||||||
|
- An event stream the shell already runs, such as the Hyprland IPC events or the long-running `pactl subscribe` in `Commons/UntypedInput.qml`. Extend it rather than starting a second one.
|
||||||
|
- A file watch: `FileView` with `watchChanges`, or the directory watch in `plugins/bar/Bar.qml`, when the state lives in a file the user can read.
|
||||||
|
- A push from the command that changes the state. If only Omarchy commands change it, have them call `omarchy-shell -q <target> refresh` after the change, the way `omarchy-reminder` and `omarchy-sudo-passwordless` do. When the change happens later, without a command running (an expiry, say), schedule the refresh with a transient `systemd-run --user --on-active=…` timer. A root-owned timer cannot reach the user's shell.
|
||||||
|
|
||||||
|
Polling is the last resort, kept for state with no change signal at all (a remote API, say). Then gate the timer on the panel being open where you can, pick the longest interval the UI can tolerate, and put the poll in one shared service rather than in a per-monitor widget. Never poll a privileged probe: every `sudo -n` can write to the auth log.
|
||||||
|
|
||||||
## Editing widget files with glyphs
|
## Editing widget files with glyphs
|
||||||
|
|
||||||
Widget files in `shell/plugins/bar/widgets/` contain Nerd Font glyphs as raw
|
Widget files in `shell/plugins/bar/widgets/` contain Nerd Font glyphs as raw
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
Version=1.0
|
Version=1.0
|
||||||
Name=Basecamp
|
Name=Basecamp
|
||||||
Exec=omarchy-launch-webapp https://launchpad.37signals.com
|
Exec=omarchy-launch-webapp https://launchpad.37signals.com
|
||||||
|
StartupWMClass=chrome-launchpad.37signals.com__-Default
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Type=Application
|
Type=Application
|
||||||
Icon=basecamp
|
Icon=basecamp
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
Version=1.0
|
Version=1.0
|
||||||
Name=Discord
|
Name=Discord
|
||||||
Exec=omarchy-launch-webapp https://discord.com/channels/@me
|
Exec=omarchy-launch-webapp https://discord.com/channels/@me
|
||||||
|
StartupWMClass=chrome-discord.com__channels_@me-Default
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Type=Application
|
Type=Application
|
||||||
Icon=omarchy-discord
|
Icon=omarchy-discord
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
Version=1.0
|
Version=1.0
|
||||||
Name=Google Contacts
|
Name=Google Contacts
|
||||||
Exec=omarchy-launch-webapp https://contacts.google.com/
|
Exec=omarchy-launch-webapp https://contacts.google.com/
|
||||||
|
StartupWMClass=chrome-contacts.google.com__-Default
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Type=Application
|
Type=Application
|
||||||
Icon=google-contacts
|
Icon=google-contacts
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
Version=1.0
|
Version=1.0
|
||||||
Name=Google Maps
|
Name=Google Maps
|
||||||
Exec=omarchy-launch-webapp https://maps.google.com
|
Exec=omarchy-launch-webapp https://maps.google.com
|
||||||
|
StartupWMClass=chrome-maps.google.com__-Default
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Type=Application
|
Type=Application
|
||||||
Icon=google-maps
|
Icon=google-maps
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
Version=1.0
|
Version=1.0
|
||||||
Name=Google Messages
|
Name=Google Messages
|
||||||
Exec=omarchy-launch-webapp https://messages.google.com/web/conversations
|
Exec=omarchy-launch-webapp https://messages.google.com/web/conversations
|
||||||
|
StartupWMClass=chrome-messages.google.com__web_conversations-Default
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Type=Application
|
Type=Application
|
||||||
Icon=google-messages
|
Icon=google-messages
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
Version=1.0
|
Version=1.0
|
||||||
Name=Google Photos
|
Name=Google Photos
|
||||||
Exec=omarchy-launch-webapp https://photos.google.com/
|
Exec=omarchy-launch-webapp https://photos.google.com/
|
||||||
|
StartupWMClass=chrome-photos.google.com__-Default
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Type=Application
|
Type=Application
|
||||||
Icon=google-photos
|
Icon=google-photos
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
Version=1.0
|
Version=1.0
|
||||||
Name=WhatsApp
|
Name=WhatsApp
|
||||||
Exec=omarchy-launch-webapp https://web.whatsapp.com/
|
Exec=omarchy-launch-webapp https://web.whatsapp.com/
|
||||||
|
StartupWMClass=chrome-web.whatsapp.com__-Default
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Type=Application
|
Type=Application
|
||||||
Icon=whatsapp
|
Icon=whatsapp
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
Version=1.0
|
Version=1.0
|
||||||
Name=X
|
Name=X
|
||||||
Exec=omarchy-launch-webapp https://x.com/
|
Exec=omarchy-launch-webapp https://x.com/
|
||||||
|
StartupWMClass=chrome-x.com__-Default
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Type=Application
|
Type=Application
|
||||||
Icon=x
|
Icon=x
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
Version=1.0
|
Version=1.0
|
||||||
Name=YouTube
|
Name=YouTube
|
||||||
Exec=omarchy-launch-webapp https://youtube.com/
|
Exec=omarchy-launch-webapp https://youtube.com/
|
||||||
|
StartupWMClass=chrome-youtube.com__-Default
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Type=Application
|
Type=Application
|
||||||
Icon=youtube
|
Icon=youtube
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ GROUP_DESCRIPTIONS[hw]="Hardware detection and controls"
|
|||||||
GROUP_DESCRIPTIONS[hyprland]="Hyprland window, monitor, and toggle controls"
|
GROUP_DESCRIPTIONS[hyprland]="Hyprland window, monitor, and toggle controls"
|
||||||
GROUP_DESCRIPTIONS[install]="Optional software installers"
|
GROUP_DESCRIPTIONS[install]="Optional software installers"
|
||||||
GROUP_DESCRIPTIONS[installed]="Installed optional service checks"
|
GROUP_DESCRIPTIONS[installed]="Installed optional service checks"
|
||||||
|
GROUP_DESCRIPTIONS[language]="System language"
|
||||||
GROUP_DESCRIPTIONS[launch]="Application launchers"
|
GROUP_DESCRIPTIONS[launch]="Application launchers"
|
||||||
GROUP_DESCRIPTIONS[menu]="Omarchy menu commands"
|
GROUP_DESCRIPTIONS[menu]="Omarchy menu commands"
|
||||||
GROUP_DESCRIPTIONS[migrate]="Migration runner"
|
GROUP_DESCRIPTIONS[migrate]="Migration runner"
|
||||||
@@ -74,6 +75,7 @@ GROUP_DESCRIPTIONS[plymouth]="Plymouth boot theme management"
|
|||||||
GROUP_DESCRIPTIONS[power]="Power supply detection"
|
GROUP_DESCRIPTIONS[power]="Power supply detection"
|
||||||
GROUP_DESCRIPTIONS[powerprofiles]="Power profile management"
|
GROUP_DESCRIPTIONS[powerprofiles]="Power profile management"
|
||||||
GROUP_DESCRIPTIONS[refresh]="Reset config to defaults"
|
GROUP_DESCRIPTIONS[refresh]="Reset config to defaults"
|
||||||
|
GROUP_DESCRIPTIONS[region]="Region-specific package sources and setup"
|
||||||
GROUP_DESCRIPTIONS[reinstall]="Reinstall and reset workflows"
|
GROUP_DESCRIPTIONS[reinstall]="Reinstall and reset workflows"
|
||||||
GROUP_DESCRIPTIONS[reminder]="Desktop notification reminders"
|
GROUP_DESCRIPTIONS[reminder]="Desktop notification reminders"
|
||||||
GROUP_DESCRIPTIONS[remove]="Removal workflows"
|
GROUP_DESCRIPTIONS[remove]="Removal workflows"
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ finish() {
|
|||||||
fail() {
|
fail() {
|
||||||
if [[ $events == "true" ]]; then
|
if [[ $events == "true" ]]; then
|
||||||
printf '@@omarchy error %s\n' "$1"
|
printf '@@omarchy error %s\n' "$1"
|
||||||
omarchy-notification-send -g -u critical "Couldn't add the $name account" "$1"
|
omarchy-notification-send -g -u critical "$(omarchy-text "Couldn't add the %1 account" "$name")" "$1"
|
||||||
else
|
else
|
||||||
echo "$1" >&2
|
echo "$1" >&2
|
||||||
fi
|
fi
|
||||||
@@ -113,9 +113,9 @@ interruptible() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if omarchy-cmd-missing "$provider"; then
|
if omarchy-cmd-missing "$provider"; then
|
||||||
say "Installing the $name CLI…"
|
say "$(omarchy-text "Installing the %1 CLI…" "$name")"
|
||||||
if [[ $events == "true" ]]; then
|
if [[ $events == "true" ]]; then
|
||||||
mise use -g "$package" >/dev/null 2>&1 || fail "Installing the $name CLI didn't finish."
|
mise use -g "$package" >/dev/null 2>&1 || fail "$(omarchy-text "Installing the %1 CLI didn't finish." "$name")"
|
||||||
else
|
else
|
||||||
mise use -g "$package" || exit 1
|
mise use -g "$package" || exit 1
|
||||||
fi
|
fi
|
||||||
@@ -150,26 +150,26 @@ if [[ -n $reauth ]]; then
|
|||||||
else
|
else
|
||||||
account_home=$(omarchy-agent-account-state homes "$provider" | awk -F'\t' -v id="$reauth" '$1 == id { print $2 }')
|
account_home=$(omarchy-agent-account-state homes "$provider" | awk -F'\t' -v id="$reauth" '$1 == id { print $2 }')
|
||||||
fi
|
fi
|
||||||
[[ -n $account_home ]] || fail "No $name account named $reauth."
|
[[ -n $account_home ]] || fail "$(omarchy-text "No %1 account named %2." "$name" "$reauth")"
|
||||||
|
|
||||||
if [[ $account_home == "$HOME/.$provider" ]]; then
|
if [[ $account_home == "$HOME/.$provider" ]]; then
|
||||||
say "Sign in to $name again in the browser window that opens."
|
say "$(omarchy-text "Sign in to %1 again in the browser window that opens." "$name")"
|
||||||
login || fail "The $name sign-in didn't finish."
|
login || fail "$(omarchy-text "The %1 sign-in didn't finish." "$name")"
|
||||||
else
|
else
|
||||||
say "Sign in again as this account in the private window that opens."
|
say "$(omarchy-text "Sign in again as this account in the private window that opens.")"
|
||||||
private_browser
|
private_browser
|
||||||
interruptible env BROWSER="$browser" "$home_env=$account_home" "${login_command[@]}" || fail "The $name sign-in didn't finish."
|
interruptible env BROWSER="$browser" "$home_env=$account_home" "${login_command[@]}" || fail "$(omarchy-text "The %1 sign-in didn't finish." "$name")"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
omarchy-agent-usage-update --force "$provider" >/dev/null 2>&1 &
|
omarchy-agent-usage-update --force "$provider" >/dev/null 2>&1 &
|
||||||
finish "Signed in to $name again."
|
finish "$(omarchy-text "Signed in to %1 again." "$name")"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# The first subscription signs in where the CLI always looks, through your
|
# The first subscription signs in where the CLI always looks, through your
|
||||||
# normal browser: nothing is signed in there yet that it could be mistaken for.
|
# normal browser: nothing is signed in there yet that it could be mistaken for.
|
||||||
if ! primary_signed_in "$provider"; then
|
if ! primary_signed_in "$provider"; then
|
||||||
say "Sign in to $name in the browser window that opens."
|
say "$(omarchy-text "Sign in to %1 in the browser window that opens." "$name")"
|
||||||
if login && primary_signed_in "$provider"; then
|
if login && primary_signed_in "$provider"; then
|
||||||
# The first agent signed in on a machine with none chosen becomes the
|
# The first agent signed in on a machine with none chosen becomes the
|
||||||
# default, so `omarchy agent` and the panel's starter prompts have one to
|
# default, so `omarchy agent` and the panel's starter prompts have one to
|
||||||
@@ -179,9 +179,9 @@ if ! primary_signed_in "$provider"; then
|
|||||||
printf '%s\n' "$provider" >"$HOME/.config/omarchy/defaults/agent"
|
printf '%s\n' "$provider" >"$HOME/.config/omarchy/defaults/agent"
|
||||||
fi
|
fi
|
||||||
omarchy-agent-usage-update --force "$provider" >/dev/null 2>&1 &
|
omarchy-agent-usage-update --force "$provider" >/dev/null 2>&1 &
|
||||||
finish "Signed in to $name."
|
finish "$(omarchy-text "Signed in to %1." "$name")"
|
||||||
else
|
else
|
||||||
fail "The $name sign-in didn't finish."
|
fail "$(omarchy-text "The %1 sign-in didn't finish." "$name")"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
if [[ -z $label && $events == "false" && -t 0 ]]; then
|
if [[ -z $label && $events == "false" && -t 0 ]]; then
|
||||||
@@ -189,7 +189,7 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $events == "true" ]]; then
|
if [[ $events == "true" ]]; then
|
||||||
say "Sign in as the account you're adding in the private window that opens."
|
say "$(omarchy-text "Sign in as the account you're adding in the private window that opens.")"
|
||||||
else
|
else
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
|
|
||||||
@@ -201,7 +201,7 @@ Don't log out of the $name CLI to do this: logging out revokes the saved sign-in
|
|||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
home=$(omarchy-agent-account-state begin "$provider") || fail "Couldn't set up a home for the new account."
|
home=$(omarchy-agent-account-state begin "$provider") || fail "$(omarchy-text "Couldn't set up a home for the new account.")"
|
||||||
|
|
||||||
private_browser
|
private_browser
|
||||||
interruptible env BROWSER="$browser" "$home_env=$home" "${login_command[@]}"
|
interruptible env BROWSER="$browser" "$home_env=$home" "${login_command[@]}"
|
||||||
@@ -211,9 +211,9 @@ EOF
|
|||||||
added=$(jq -r '.label + (if .email != "" then " (" + .email + ")" else "" end)' <<<"$account")
|
added=$(jq -r '.label + (if .email != "" then " (" + .email + ")" else "" end)' <<<"$account")
|
||||||
omarchy-agent-usage-update --force "$provider" >/dev/null 2>&1 &
|
omarchy-agent-usage-update --force "$provider" >/dev/null 2>&1 &
|
||||||
if [[ $events == "true" ]]; then
|
if [[ $events == "true" ]]; then
|
||||||
finish "Added $added."
|
finish "$(omarchy-text "Added %1." "$added")"
|
||||||
else
|
else
|
||||||
finish "Added $added."
|
finish "$(omarchy-text "Added %1." "$added")"
|
||||||
echo "Switch to it with: omarchy agent account use $provider $(jq -r .id <<<"$account")"
|
echo "Switch to it with: omarchy agent account use $provider $(jq -r .id <<<"$account")"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -73,6 +73,11 @@ class AccountError(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def text(english: str, *args: object) -> str:
|
||||||
|
"""English with %1.. filled, in the session's language, from the shell's table."""
|
||||||
|
return subprocess.run(["omarchy-text", english, *map(str, args)], capture_output=True, text=True, check=True).stdout.rstrip("\n")
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------- paths
|
# ------------------------------------------------------------------- paths
|
||||||
|
|
||||||
|
|
||||||
@@ -335,12 +340,12 @@ def begin(provider: str) -> Path:
|
|||||||
def register(provider: str, label: str, pending: Path) -> dict[str, Any]:
|
def register(provider: str, label: str, pending: Path) -> dict[str, Any]:
|
||||||
pending = pending.resolve()
|
pending = pending.resolve()
|
||||||
if pending.parent != (accounts_root() / provider / ".pending").resolve():
|
if pending.parent != (accounts_root() / provider / ".pending").resolve():
|
||||||
raise AccountError(f"{pending} is not a pending {PROVIDERS[provider]['name']} login")
|
raise AccountError(text("%1 is not a pending %2 login", pending, PROVIDERS[provider]['name']))
|
||||||
|
|
||||||
found = identity(provider, pending)
|
found = identity(provider, pending)
|
||||||
if not found["accountId"]:
|
if not found["accountId"]:
|
||||||
shutil.rmtree(pending, ignore_errors=True)
|
shutil.rmtree(pending, ignore_errors=True)
|
||||||
raise AccountError("The login didn't finish, so no account was added.")
|
raise AccountError(text("The login didn't finish, so no account was added."))
|
||||||
|
|
||||||
with Locked(provider) as registry:
|
with Locked(provider) as registry:
|
||||||
# Each home is asked who it is now, not trusted from when it was added: a
|
# Each home is asked who it is now, not trusted from when it was added: a
|
||||||
@@ -350,10 +355,10 @@ def register(provider: str, label: str, pending: Path) -> dict[str, Any]:
|
|||||||
for account in registry["accounts"]:
|
for account in registry["accounts"]:
|
||||||
if account.get("accountId") == found["accountId"]:
|
if account.get("accountId") == found["accountId"]:
|
||||||
shutil.rmtree(pending, ignore_errors=True)
|
shutil.rmtree(pending, ignore_errors=True)
|
||||||
raise AccountError(
|
raise AccountError(text(
|
||||||
f"That's {account['label']} ({found['email'] or 'already added'}). "
|
"That's %1 (%2). Try again, and sign in as the other account in the private window.",
|
||||||
"Try again, and sign in as the other account in the private window."
|
account["label"], found["email"] or text("already added"),
|
||||||
)
|
))
|
||||||
|
|
||||||
label = label.strip() or found["email"].split("@")[0] or "Account"
|
label = label.strip() or found["email"].split("@")[0] or "Account"
|
||||||
account_id = unique_id(provider, registry, label)
|
account_id = unique_id(provider, registry, label)
|
||||||
@@ -395,11 +400,11 @@ def unique_id(provider: str, registry: dict[str, Any], label: str, keep: dict[st
|
|||||||
def rename(provider: str, target: str, label: str) -> dict[str, Any]:
|
def rename(provider: str, target: str, label: str) -> dict[str, Any]:
|
||||||
label = label.strip()
|
label = label.strip()
|
||||||
if not label:
|
if not label:
|
||||||
raise AccountError("Give the account a name")
|
raise AccountError(text("Give the account a name"))
|
||||||
with Locked(provider) as registry:
|
with Locked(provider) as registry:
|
||||||
account = find(registry, target)
|
account = find(registry, target)
|
||||||
if not account:
|
if not account:
|
||||||
raise AccountError(f"No {PROVIDERS[provider]['name']} account named {target}")
|
raise AccountError(text("No %1 account named %2", PROVIDERS[provider]['name'], target))
|
||||||
new_id = unique_id(provider, registry, label, keep=account)
|
new_id = unique_id(provider, registry, label, keep=account)
|
||||||
if not account.get("primary") and not account.get("home"):
|
if not account.get("primary") and not account.get("home"):
|
||||||
account["home"] = str(account_home(provider, account))
|
account["home"] = str(account_home(provider, account))
|
||||||
@@ -428,7 +433,7 @@ def use(provider: str, target: str) -> tuple[dict[str, Any], dict[str, Any]]:
|
|||||||
target = ids[(ids.index(previous["id"]) + 1) % len(ids)]
|
target = ids[(ids.index(previous["id"]) + 1) % len(ids)]
|
||||||
account = find(registry, target)
|
account = find(registry, target)
|
||||||
if not account:
|
if not account:
|
||||||
raise AccountError(f"No {PROVIDERS[provider]['name']} account named {target}")
|
raise AccountError(text("No %1 account named %2", PROVIDERS[provider]['name'], target))
|
||||||
registry["active"] = account["id"]
|
registry["active"] = account["id"]
|
||||||
registry["alert"] = ""
|
registry["alert"] = ""
|
||||||
if not account.get("primary"):
|
if not account.get("primary"):
|
||||||
@@ -456,12 +461,12 @@ def remove(provider: str, target: str) -> dict[str, Any]:
|
|||||||
with Locked(provider) as registry:
|
with Locked(provider) as registry:
|
||||||
account = find(registry, target)
|
account = find(registry, target)
|
||||||
if not account:
|
if not account:
|
||||||
raise AccountError(f"No {PROVIDERS[provider]['name']} account named {target}")
|
raise AccountError(text("No %1 account named %2", PROVIDERS[provider]['name'], target))
|
||||||
if account.get("primary"):
|
if account.get("primary"):
|
||||||
raise AccountError(f"{account['label']} is the login in {primary_home(provider)}; it can't be removed here.")
|
raise AccountError(text("%1 is the login in %2; it can't be removed here.", account["label"], primary_home(provider)))
|
||||||
home = account_home(provider, account)
|
home = account_home(provider, account)
|
||||||
if home_in_use(provider, home):
|
if home_in_use(provider, home):
|
||||||
raise AccountError(f"A running {PROVIDERS[provider]['name']} session uses {account['label']}. Quit it first, then remove the account.")
|
raise AccountError(text("A running %1 session uses %2. Quit it first, then remove the account.", PROVIDERS[provider]['name'], account["label"]))
|
||||||
# Only the account's own directory goes. Its links point into the primary
|
# Only the account's own directory goes. Its links point into the primary
|
||||||
# home, and rmtree removes a link without following it.
|
# home, and rmtree removes a link without following it.
|
||||||
if home.resolve().parent == (accounts_root() / provider).resolve():
|
if home.resolve().parent == (accounts_root() / provider).resolve():
|
||||||
@@ -474,14 +479,14 @@ def remove(provider: str, target: str) -> dict[str, Any]:
|
|||||||
|
|
||||||
def set_mode(provider: str, mode: str, threshold: str | None) -> dict[str, Any]:
|
def set_mode(provider: str, mode: str, threshold: str | None) -> dict[str, Any]:
|
||||||
if mode not in SWITCH_MODES:
|
if mode not in SWITCH_MODES:
|
||||||
raise AccountError("Switch mode is manual or auto")
|
raise AccountError(text("Switch mode is manual or auto"))
|
||||||
with Locked(provider) as registry:
|
with Locked(provider) as registry:
|
||||||
registry["switch"] = mode
|
registry["switch"] = mode
|
||||||
if threshold is not None:
|
if threshold is not None:
|
||||||
try:
|
try:
|
||||||
registry["threshold"] = max(50, min(100, int(threshold)))
|
registry["threshold"] = max(50, min(100, int(threshold)))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise AccountError("The threshold is a percentage between 50 and 100")
|
raise AccountError(text("The threshold is a percentage between 50 and 100"))
|
||||||
registry["alert"] = ""
|
registry["alert"] = ""
|
||||||
return dict(registry)
|
return dict(registry)
|
||||||
|
|
||||||
@@ -556,10 +561,10 @@ def duration(delta: dt.timedelta) -> str:
|
|||||||
hours, minutes = divmod(minutes, 60)
|
hours, minutes = divmod(minutes, 60)
|
||||||
days, hours = divmod(hours, 24)
|
days, hours = divmod(hours, 24)
|
||||||
if days:
|
if days:
|
||||||
return f"{days}d {hours}h"
|
return text("%1d %2h", days, hours)
|
||||||
if hours:
|
if hours:
|
||||||
return f"{hours}h {minutes}m"
|
return text("%1h %2m", hours, minutes)
|
||||||
return f"{minutes}m"
|
return text("%1m", minutes)
|
||||||
|
|
||||||
|
|
||||||
# The whole switching policy, with no I/O: given the registry and the per
|
# The whole switching policy, with no I/O: given the registry and the per
|
||||||
@@ -659,21 +664,23 @@ def autoswitch(provider: str, now: dt.datetime | None = None) -> bool:
|
|||||||
threshold = registry["threshold"]
|
threshold = registry["threshold"]
|
||||||
if decision["action"] == "exhausted":
|
if decision["action"] == "exhausted":
|
||||||
soonest = decision["soonest"]
|
soonest = decision["soonest"]
|
||||||
when = f" {soonest[1]['label']} resets in {duration(soonest[0] - now)}." if soonest else ""
|
staying = text("Staying on %1.", source["label"])
|
||||||
notify(f"All {name} accounts are over {threshold}%", f"Staying on {source['label']}.{when}")
|
if soonest:
|
||||||
|
staying = text("Staying on %1. %2 resets in %3.", source["label"], soonest[1]["label"], duration(soonest[0] - now))
|
||||||
|
notify(text("All %1 accounts are over %2%", name, threshold), staying)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
target = decision["to"]
|
target = decision["to"]
|
||||||
headline = f"{source['label']} is at {round(decision['fromPeak'])}% of a {name} limit"
|
headline = text("%1 is at %2% of a %3 limit", source["label"], round(decision["fromPeak"]), name)
|
||||||
if decision["action"] == "switch":
|
if decision["action"] == "switch":
|
||||||
registry["active"] = target["id"]
|
registry["active"] = target["id"]
|
||||||
if not target.get("primary"):
|
if not target.get("primary"):
|
||||||
link_shared(provider, account_home(provider, target))
|
link_shared(provider, account_home(provider, target))
|
||||||
notify(headline, f"New {name} sessions now use {target['label']} ({round(decision['toPeak'])}%). Running sessions stay on {source['label']}.")
|
notify(headline, text("New %1 sessions now use %2 (%3%). Running sessions stay on %4.", name, target["label"], round(decision["toPeak"]), source["label"]))
|
||||||
return True
|
return True
|
||||||
notify(
|
notify(
|
||||||
headline,
|
headline,
|
||||||
f"{target['label']} is at {round(decision['toPeak'])}%. Click to switch new sessions to it.",
|
text("%1 is at %2%. Click to switch new sessions to it.", target["label"], round(decision["toPeak"])),
|
||||||
["omarchy-agent-account-use", provider, target["id"]],
|
["omarchy-agent-account-use", provider, target["id"]],
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ active=$(jq -r '.active.label + (if (.active.plan // "") != "" then " (" + .acti
|
|||||||
if [[ $(jq -r .previous.id <<<"$result") == "$(jq -r .active.id <<<"$result")" ]]; then
|
if [[ $(jq -r .previous.id <<<"$result") == "$(jq -r .active.id <<<"$result")" ]]; then
|
||||||
echo "New $name sessions already use $active."
|
echo "New $name sessions already use $active."
|
||||||
else
|
else
|
||||||
message="Running sessions stay on $previous."
|
message=$(omarchy-text "Running sessions stay on %1." "$previous")
|
||||||
echo "New $name sessions now use $active. $message"
|
echo "New $name sessions now use $active. $message"
|
||||||
omarchy-notification-send -g "New $name sessions now use $active" "$message"
|
omarchy-notification-send -g "$(omarchy-text "New %1 sessions now use %2" "$name" "$active")" "$message"
|
||||||
# The usage record's own limits describe the active account.
|
# The usage record's own limits describe the active account.
|
||||||
omarchy-agent-usage-update --limits-only "$1" >/dev/null 2>&1 &
|
omarchy-agent-usage-update --limits-only "$1" >/dev/null 2>&1 &
|
||||||
fi
|
fi
|
||||||
@@ -22,6 +22,7 @@ import json
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import time
|
import time
|
||||||
@@ -32,6 +33,11 @@ from typing import Any
|
|||||||
|
|
||||||
AGENT_ID = "claude"
|
AGENT_ID = "claude"
|
||||||
AGENT_NAME = "Claude Code"
|
AGENT_NAME = "Claude Code"
|
||||||
|
def text(english, *args):
|
||||||
|
"""English with %1.. filled, in the session's language, from the shell's table."""
|
||||||
|
return subprocess.run(["omarchy-text", english, *map(str, args)], capture_output=True, text=True, check=True).stdout.rstrip("\n")
|
||||||
|
|
||||||
|
|
||||||
AUTH_HELP = "Run `claude auth login` to restore authoritative usage."
|
AUTH_HELP = "Run `claude auth login` to restore authoritative usage."
|
||||||
USAGE_ENDPOINT = "https://api.anthropic.com/api/oauth/usage"
|
USAGE_ENDPOINT = "https://api.anthropic.com/api/oauth/usage"
|
||||||
PROBE_MIN_INTERVAL_SECONDS = 15
|
PROBE_MIN_INTERVAL_SECONDS = 15
|
||||||
@@ -989,11 +995,12 @@ def probe_limits(access_token: str) -> dict[str, Any]:
|
|||||||
except urllib.error.HTTPError as error:
|
except urllib.error.HTTPError as error:
|
||||||
retry_after = error.headers.get("retry-after", "") if error.headers else ""
|
retry_after = error.headers.get("retry-after", "") if error.headers else ""
|
||||||
if error.code == 429:
|
if error.code == 429:
|
||||||
help_text = "Anthropic's usage endpoint is rate limiting checks right now" + (
|
if retry_after:
|
||||||
f" (retry after {retry_after}s)" if retry_after else ""
|
help_text = text("Anthropic's usage endpoint is rate limiting checks right now (retry after %1s). Local Claude Code stats are still shown.", retry_after)
|
||||||
) + ". Local Claude Code stats are still shown."
|
else:
|
||||||
|
help_text = text("Anthropic's usage endpoint is rate limiting checks right now. Local Claude Code stats are still shown.")
|
||||||
else:
|
else:
|
||||||
help_text = f"Anthropic's usage endpoint returned status {error.code}. Local Claude Code stats are still shown."
|
help_text = text("Anthropic's usage endpoint returned status %1. Local Claude Code stats are still shown.", error.code)
|
||||||
return {"ok": False, "helpText": help_text}
|
return {"ok": False, "helpText": help_text}
|
||||||
except Exception:
|
except Exception:
|
||||||
# A transport failure reached no server at all — no route, no DNS. Any
|
# A transport failure reached no server at all — no route, no DNS. Any
|
||||||
|
|||||||
Executable
+77
@@ -0,0 +1,77 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# omarchy:summary=Restore channel and regional pacman defaults in an installed target
|
||||||
|
# omarchy:args=<stable|rc|edge> [target-root] | --render <stable|rc|edge> <output-dir> [target-root]
|
||||||
|
# omarchy:requires-sudo=true
|
||||||
|
# omarchy:hidden=true
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "Usage: omarchy-apply-pacman <stable|rc|edge> [target-root]" >&2
|
||||||
|
echo " omarchy-apply-pacman --render <stable|rc|edge> <output-dir> [target-root]" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# --render only builds the two files, so an unprivileged caller can hand root
|
||||||
|
# nothing but plain copies of the finished result.
|
||||||
|
render_dir=""
|
||||||
|
if [[ ${1:-} == "--render" ]]; then
|
||||||
|
(( $# == 3 || $# == 4 )) || usage
|
||||||
|
channel="$2"
|
||||||
|
render_dir="$3"
|
||||||
|
[[ -d $render_dir ]] || { echo "Render directory not found: $render_dir" >&2; exit 1; }
|
||||||
|
etc="${4:-/}/etc"
|
||||||
|
else
|
||||||
|
(( $# >= 1 && $# <= 2 )) || usage
|
||||||
|
channel="$1"
|
||||||
|
etc="${2:-/}/etc"
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$channel" in
|
||||||
|
stable|rc|edge) ;;
|
||||||
|
*) echo "Invalid pacman channel: $channel" >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# The ISO writes this plain-text marker before target finalization. Missing
|
||||||
|
# markers keep existing installations global; never source it as shell code.
|
||||||
|
region=global
|
||||||
|
if [[ -e $etc/omarchy/region ]]; then
|
||||||
|
region=$(<"$etc/omarchy/region")
|
||||||
|
fi
|
||||||
|
case "$region" in
|
||||||
|
global|cn) ;;
|
||||||
|
*) echo "Unsupported region: $region (expected global or cn)" >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Build both files before replacing either. Explicit refreshes retain backups;
|
||||||
|
# ordinary updates do not call this command or enforce regional defaults.
|
||||||
|
if [[ -n $render_dir ]]; then
|
||||||
|
staging="$render_dir"
|
||||||
|
else
|
||||||
|
staging=$(mktemp -d)
|
||||||
|
trap 'rm -rf "$staging"' EXIT
|
||||||
|
fi
|
||||||
|
cp "$OMARCHY_PATH/default/pacman/pacman-$channel.conf" "$staging/pacman.conf"
|
||||||
|
if [[ $region == "global" ]]; then
|
||||||
|
cp "$OMARCHY_PATH/default/pacman/mirrorlist-$channel" "$staging/mirrorlist"
|
||||||
|
else
|
||||||
|
profile="$OMARCHY_PATH/default/regions/$region/pacman"
|
||||||
|
printf '\n' >> "$staging/pacman.conf"
|
||||||
|
cat "$profile/pacman.conf.append" >> "$staging/pacman.conf"
|
||||||
|
# pacman tries servers in order, so the regional mirror leads and the
|
||||||
|
# channel's own mirror stays as the fallback.
|
||||||
|
cat "$profile/mirrorlist-$channel.prepend" "$OMARCHY_PATH/default/pacman/mirrorlist-$channel" > "$staging/mirrorlist"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z $render_dir ]]; then
|
||||||
|
mkdir -p "$etc/pacman.d"
|
||||||
|
for file in pacman.conf pacman.d/mirrorlist; do
|
||||||
|
if [[ -e $etc/$file ]]; then
|
||||||
|
cp -f "$etc/$file" "$etc/$file.bak"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
# Copying over an existing file keeps its owner and mode, as refresh always has.
|
||||||
|
cp -f "$staging/pacman.conf" "$etc/pacman.conf"
|
||||||
|
cp -f "$staging/mirrorlist" "$etc/pacman.d/mirrorlist"
|
||||||
|
fi
|
||||||
@@ -6,8 +6,8 @@ wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle >/dev/null
|
|||||||
|
|
||||||
if wpctl get-volume @DEFAULT_AUDIO_SOURCE@ | grep -q MUTED; then
|
if wpctl get-volume @DEFAULT_AUDIO_SOURCE@ | grep -q MUTED; then
|
||||||
omarchy-brightness-keyboard-mute on
|
omarchy-brightness-keyboard-mute on
|
||||||
omarchy-osd -i microphone-muted -m "Microphone muted"
|
omarchy-osd -i microphone-muted -m "$(omarchy-text "Microphone muted")"
|
||||||
else
|
else
|
||||||
omarchy-brightness-keyboard-mute off
|
omarchy-brightness-keyboard-mute off
|
||||||
omarchy-osd -i microphone -m "Microphone on"
|
omarchy-osd -i microphone -m "$(omarchy-text "Microphone on")"
|
||||||
fi
|
fi
|
||||||
@@ -13,7 +13,7 @@ sinks=$(timeout 2 pactl -f json list sinks |
|
|||||||
sinks_count=$(jq 'length' <<<"$sinks")
|
sinks_count=$(jq 'length' <<<"$sinks")
|
||||||
|
|
||||||
if (( sinks_count == 0 )); then
|
if (( sinks_count == 0 )); then
|
||||||
omarchy-osd -m "No audio devices found"
|
omarchy-osd -m "$(omarchy-text "No audio devices found")"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
+104
-10
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# omarchy:summary=Configure the bar and its widget layout
|
# omarchy:summary=Configure the bar and its widget layout
|
||||||
# omarchy:group=bar
|
# omarchy:group=bar
|
||||||
# omarchy:args=use <id> | reset | defaults | position <top|bottom|left|right> | transparent <true|false|toggle> | put <id> [placement] | move <id> [placement] | set <id> <key> <value> [--json] [placement]
|
# omarchy:args=use <id> | reset | defaults | position [top|bottom|left|right] | background [opaque|glassy|none|cycle] | put <id> [placement] | move <id> [placement] | set <id> <key> <value> [--json] [placement] | get <id> <key>
|
||||||
# omarchy:examples=omarchy bar use local.neon-bar | omarchy bar put omarchy.keyboard-layout --after omarchy.clock | omarchy bar move omarchy.clock --section center --index 0 | omarchy bar set omarchy.clock format HH:mm
|
# omarchy:examples=omarchy bar use local.neon-bar | omarchy bar put omarchy.keyboard-layout --after omarchy.clock | omarchy bar move omarchy.clock --section center --index 0 | omarchy bar set omarchy.clock format HH:mm
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
@@ -16,13 +16,19 @@ Usage: omarchy bar <command> [args...]
|
|||||||
use <id> Use a bar option as the active bar
|
use <id> Use a bar option as the active bar
|
||||||
reset Return to the built-in Omarchy bar
|
reset Return to the built-in Omarchy bar
|
||||||
defaults Restore the default bar and service widgets
|
defaults Restore the default bar and service widgets
|
||||||
position <top|bottom|left|right> Bar position
|
position [top|bottom|left|right] Bar position; prints the current one
|
||||||
transparent <true|false|toggle> Bar transparency
|
when given none
|
||||||
|
background [opaque|glassy|none|cycle]
|
||||||
|
Bar background: glassy shows what is
|
||||||
|
behind the bar blurred, cycle steps
|
||||||
|
none, glassy, opaque; prints the
|
||||||
|
current one when given none
|
||||||
put <id> [placement] Put a widget on the bar, leaving one
|
put <id> [placement] Put a widget on the bar, leaving one
|
||||||
that is already there where it is
|
that is already there where it is
|
||||||
move <id> [placement] Move a widget within or between sections
|
move <id> [placement] Move a widget within or between sections
|
||||||
set <id> <key> <value> [--json] [placement]
|
set <id> <key> <value> [--json] [placement]
|
||||||
Set a per-widget option
|
Set a per-widget option
|
||||||
|
get <id> <key> Print a per-widget option
|
||||||
|
|
||||||
Placement:
|
Placement:
|
||||||
--section <left|center|right> Target section
|
--section <left|center|right> Target section
|
||||||
@@ -192,30 +198,92 @@ cmd_defaults() {
|
|||||||
" \
|
" \
|
||||||
--slurpfile defaults "$DEFAULTS_FILE" \
|
--slurpfile defaults "$DEFAULTS_FILE" \
|
||||||
--argjson widgets "$optional_widgets"
|
--argjson widgets "$optional_widgets"
|
||||||
|
sync_glass || fail "could not change the blur behind the bar"
|
||||||
echo "Restored the default Omarchy bar"
|
echo "Restored the default Omarchy bar"
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd_position() {
|
cmd_position() {
|
||||||
local position="${1:-}"
|
if (( $# == 0 )); then
|
||||||
[[ -n $position ]] || fail "position is required"
|
jq -r '.bar.position // "top"' "$(source_file)"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local position="$1"
|
||||||
(( $# == 1 )) || fail "position takes a single value"
|
(( $# == 1 )) || fail "position takes a single value"
|
||||||
[[ $position =~ ^(top|bottom|left|right)$ ]] || fail "position must be top, bottom, left, or right"
|
[[ $position =~ ^(top|bottom|left|right)$ ]] || fail "position must be top, bottom, left, or right"
|
||||||
commit "$NORMALIZE | .bar.position = \$position" --arg position "$position"
|
commit "$NORMALIZE | .bar.position = \$position" --arg position "$position"
|
||||||
echo "Bar position set to $position"
|
echo "Bar position set to $position"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# The bar background is opaque, glassy, or none. A shell.json from before it
|
||||||
|
# had one says transparent instead, which is none, and setting a background
|
||||||
|
# drops it.
|
||||||
|
current_background() {
|
||||||
|
jq -r '.bar.background // (if .bar.transparent == true then "none" else "opaque" end)' "$(source_file)"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_background() {
|
||||||
|
if (( $# == 0 )); then
|
||||||
|
current_background
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local background="$1"
|
||||||
|
(( $# == 1 )) || fail "background takes a single value"
|
||||||
|
[[ $background =~ ^(opaque|glassy|none|cycle)$ ]] || fail "background must be opaque, glassy, none, or cycle"
|
||||||
|
|
||||||
|
if [[ $background == "cycle" ]]; then
|
||||||
|
# Each step changes the bar by one degree: clear, then glassy, then opaque.
|
||||||
|
case $(current_background) in
|
||||||
|
none) background="glassy" ;;
|
||||||
|
glassy) background="opaque" ;;
|
||||||
|
*) background="none" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
local previous
|
||||||
|
previous=$(current_background)
|
||||||
|
commit "$NORMALIZE | .bar.background = \$background | del(.bar.transparent)" --arg background "$background"
|
||||||
|
if ! sync_glass; then
|
||||||
|
commit "$NORMALIZE | .bar.background = \$background | del(.bar.transparent)" --arg background "$previous"
|
||||||
|
fail "could not change the blur behind the bar"
|
||||||
|
fi
|
||||||
|
echo "Bar background set to $background"
|
||||||
|
}
|
||||||
|
|
||||||
|
# The older on/off form of the background, kept for scripts and dotfiles:
|
||||||
|
# transparent is none, and not transparent is opaque.
|
||||||
cmd_transparent() {
|
cmd_transparent() {
|
||||||
local transparent="${1:-}"
|
local transparent="${1:-}"
|
||||||
[[ -n $transparent ]] || fail "transparent is required"
|
[[ -n $transparent ]] || fail "transparent is required"
|
||||||
(( $# == 1 )) || fail "transparent takes a single value"
|
(( $# == 1 )) || fail "transparent takes a single value"
|
||||||
[[ $transparent =~ ^(true|false|toggle)$ ]] || fail "transparent must be true, false, or toggle"
|
[[ $transparent =~ ^(true|false|toggle)$ ]] || fail "transparent must be true, false, or toggle"
|
||||||
if [[ $transparent == "toggle" ]]; then
|
if [[ $transparent == "toggle" ]]; then
|
||||||
commit "$NORMALIZE | .bar.transparent = (.bar.transparent != true)"
|
[[ $(current_background) == "none" ]] && transparent="false" || transparent="true"
|
||||||
echo "Bar transparency toggled"
|
|
||||||
else
|
|
||||||
commit "$NORMALIZE | .bar.transparent = \$transparent" --argjson transparent "$transparent"
|
|
||||||
echo "Bar transparency set to $transparent"
|
|
||||||
fi
|
fi
|
||||||
|
if [[ $transparent == "true" ]]; then
|
||||||
|
cmd_background none
|
||||||
|
else
|
||||||
|
cmd_background opaque
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Hyprland blurs behind the bar only while the bar-glassy toggle is on, so it
|
||||||
|
# follows the bar background, reloading Hyprland only when it changes. The
|
||||||
|
# toggle sits where Hyprland reads it, under XDG_STATE_HOME.
|
||||||
|
sync_glass() {
|
||||||
|
local dir="${XDG_STATE_HOME:-$HOME/.local/state}/omarchy/toggles/hypr"
|
||||||
|
local flag="$dir/bar-glassy.lua"
|
||||||
|
|
||||||
|
if [[ $(current_background) == "glassy" ]]; then
|
||||||
|
[[ ! -f $flag ]] || return 0
|
||||||
|
mkdir -p "$dir" && cp "$OMARCHY_PATH/default/hypr/toggles/bar-glassy.lua" "$flag" || return 1
|
||||||
|
else
|
||||||
|
[[ -f $flag ]] || return 0
|
||||||
|
rm -f "$flag" || return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
hyprctl reload >/dev/null 2>&1 || true
|
||||||
}
|
}
|
||||||
|
|
||||||
bar_widget_default_section() {
|
bar_widget_default_section() {
|
||||||
@@ -363,6 +431,21 @@ cmd_set() {
|
|||||||
echo "Set $key on $id"
|
echo "Set $key on $id"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Prints the option from the first instance of the widget on the bar, raw for a
|
||||||
|
# string and as JSON otherwise, and fails when no instance sets it.
|
||||||
|
cmd_get() {
|
||||||
|
local id="${1:-}"
|
||||||
|
local key="${2:-}"
|
||||||
|
[[ -n $id ]] || fail "get requires a widget id"
|
||||||
|
[[ -n $key ]] || fail "get requires a setting key"
|
||||||
|
(( $# == 2 )) || fail "get takes a widget id and a setting key"
|
||||||
|
|
||||||
|
jq -e -r --arg id "$id" --arg key "$key" '
|
||||||
|
first(.bar.layout[]?[]? | select(.id == $id) | .[$key] | select(. != null))
|
||||||
|
| if type == "string" then . else tojson end
|
||||||
|
' "$(source_file)" 2>/dev/null || exit 1
|
||||||
|
}
|
||||||
|
|
||||||
# --------------------------------------------------------------------- dispatch
|
# --------------------------------------------------------------------- dispatch
|
||||||
|
|
||||||
command="${1:-}"
|
command="${1:-}"
|
||||||
@@ -385,6 +468,14 @@ case "$command" in
|
|||||||
transparent)
|
transparent)
|
||||||
cmd_transparent "$@"
|
cmd_transparent "$@"
|
||||||
;;
|
;;
|
||||||
|
background)
|
||||||
|
cmd_background "$@"
|
||||||
|
;;
|
||||||
|
# Internal: the shell runs this when it loads a bar background, so one set
|
||||||
|
# by editing shell.json gets its blur too.
|
||||||
|
sync-glass)
|
||||||
|
sync_glass || fail "could not change the blur behind the bar"
|
||||||
|
;;
|
||||||
put)
|
put)
|
||||||
cmd_put "$@"
|
cmd_put "$@"
|
||||||
;;
|
;;
|
||||||
@@ -394,6 +485,9 @@ case "$command" in
|
|||||||
set)
|
set)
|
||||||
cmd_set "$@"
|
cmd_set "$@"
|
||||||
;;
|
;;
|
||||||
|
get)
|
||||||
|
cmd_get "$@"
|
||||||
|
;;
|
||||||
-h | --help | help | "")
|
-h | --help | help | "")
|
||||||
usage
|
usage
|
||||||
;;
|
;;
|
||||||
|
|||||||
@@ -13,5 +13,5 @@ fi
|
|||||||
|
|
||||||
level=$1
|
level=$1
|
||||||
|
|
||||||
omarchy-notification-send -g -u critical "Time to recharge!" "Battery is down to ${level}%" -i battery-caution -t 30000
|
omarchy-notification-send -g -u critical "$(omarchy-text "Time to recharge!")" "$(omarchy-text "Battery is down to %1%" "$level")" -i battery-caution -t 30000
|
||||||
omarchy-hook battery-low "$level"
|
omarchy-hook battery-low "$level"
|
||||||
@@ -150,9 +150,9 @@ if [[ $charge_holding == "true" ]]; then
|
|||||||
threshold_label="${threshold_end}%"
|
threshold_label="${threshold_end}%"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Battery ${percentage}% · Holding at ${threshold_label} · ${power_rate}W / ${capacity}Wh"
|
omarchy-text "Battery %1% · Holding at %2 · %3W / %4Wh" "$percentage" "$threshold_label" "$power_rate" "$capacity"
|
||||||
elif [[ $state == "charging" ]]; then
|
elif [[ $state == "charging" ]]; then
|
||||||
echo "Battery ${percentage}% · ${time_remaining} to full · ${power_rate}W / ${capacity}Wh"
|
omarchy-text "Battery %1% · %2 to full · %3W / %4Wh" "$percentage" "$time_remaining" "$power_rate" "$capacity"
|
||||||
else
|
else
|
||||||
echo "Battery ${percentage}% · ${time_remaining} left · ${power_rate}W / ${capacity}Wh"
|
omarchy-text "Battery %1% · %2 left · %3W / %4Wh" "$percentage" "$time_remaining" "$power_rate" "$capacity"
|
||||||
fi
|
fi
|
||||||
@@ -23,7 +23,7 @@ SELECTION=$(slurp 2>/dev/null)
|
|||||||
RESULT=$(grim -g "$SELECTION" - | zbarimg -q --raw -Sdisable -Sqrcode.enable - 2>/dev/null)
|
RESULT=$(grim -g "$SELECTION" - | zbarimg -q --raw -Sdisable -Sqrcode.enable - 2>/dev/null)
|
||||||
|
|
||||||
if [[ -z $RESULT ]]; then
|
if [[ -z $RESULT ]]; then
|
||||||
omarchy-notification-send -g -u critical "No QR code found" "Select a region containing a QR code"
|
omarchy-notification-send -g -u critical "$(omarchy-text "No QR code found")" "$(omarchy-text "Select a region containing a QR code")"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -33,4 +33,4 @@ fi
|
|||||||
# the notification history, and an unmarked copy would be retained by clipboard
|
# the notification history, and an unmarked copy would be retained by clipboard
|
||||||
# history. Pasting still works; only the recorded copy is given up.
|
# history. Pasting still works; only the recorded copy is given up.
|
||||||
printf '%s' "$RESULT" | wl-copy --sensitive
|
printf '%s' "$RESULT" | wl-copy --sensitive
|
||||||
omarchy-notification-send -g "QR code copied to clipboard"
|
omarchy-notification-send -g "$(omarchy-text "QR code copied to clipboard")"
|
||||||
@@ -86,7 +86,7 @@ esac
|
|||||||
# --status only answers whether our recording runs, for the bar and the menu, so
|
# --status only answers whether our recording runs, for the bar and the menu, so
|
||||||
# it needs no recordings directory and never notifies.
|
# it needs no recordings directory and never notifies.
|
||||||
if [[ $STATUS != "true" && ! -d $OUTPUT_DIR ]]; then
|
if [[ $STATUS != "true" && ! -d $OUTPUT_DIR ]]; then
|
||||||
omarchy-notification-send -u critical -t 3000 "Screen recording directory does not exist: $OUTPUT_DIR"
|
omarchy-notification-send -u critical -t 3000 "$(omarchy-text "Screen recording directory does not exist: %1" "$OUTPUT_DIR")"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ start_webcam_overlay() {
|
|||||||
if [[ -z $WEBCAM_DEVICE ]]; then
|
if [[ -z $WEBCAM_DEVICE ]]; then
|
||||||
WEBCAM_DEVICE=$(omarchy-capture-webcam-list | sed -n '1s/[[:space:]].*//p')
|
WEBCAM_DEVICE=$(omarchy-capture-webcam-list | sed -n '1s/[[:space:]].*//p')
|
||||||
if [[ -z $WEBCAM_DEVICE ]]; then
|
if [[ -z $WEBCAM_DEVICE ]]; then
|
||||||
omarchy-notification-send -u critical -t 3000 "No webcam devices found"
|
omarchy-notification-send -u critical -t 3000 "$(omarchy-text "No webcam devices found")"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -235,7 +235,9 @@ wf_audio_device() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
wf_audio_unavailable() {
|
wf_audio_unavailable() {
|
||||||
omarchy-notification-send -u critical -t 5000 "Recording without $1 audio" "The $1 audio could not be added to this recording." >/dev/null 2>&1
|
local audio
|
||||||
|
audio=$(omarchy-text "$1")
|
||||||
|
omarchy-notification-send -u critical -t 5000 "$(omarchy-text "Recording without %1 audio" "$audio")" "$(omarchy-text "The %1 audio could not be added to this recording." "$audio")" >/dev/null 2>&1
|
||||||
}
|
}
|
||||||
|
|
||||||
wf_audio_cleanup() {
|
wf_audio_cleanup() {
|
||||||
@@ -424,7 +426,7 @@ stop_screenrecording() {
|
|||||||
|
|
||||||
if omarchy-capture-screenrecording-process "${RECORDER[@]}"; then
|
if omarchy-capture-screenrecording-process "${RECORDER[@]}"; then
|
||||||
omarchy-capture-screenrecording-process "${RECORDER[@]}" --signal KILL
|
omarchy-capture-screenrecording-process "${RECORDER[@]}" --signal KILL
|
||||||
omarchy-notification-send -u critical -t 5000 "Screen recording error" "Recording process had to be force-killed. Video may be corrupted."
|
omarchy-notification-send -u critical -t 5000 "$(omarchy-text "Screen recording error")" "$(omarchy-text "Recording process had to be force-killed. Video may be corrupted.")"
|
||||||
else
|
else
|
||||||
finalize_recording
|
finalize_recording
|
||||||
local filename=$(cat "$RECORDING_FILE" 2>/dev/null)
|
local filename=$(cat "$RECORDING_FILE" 2>/dev/null)
|
||||||
@@ -434,7 +436,7 @@ stop_screenrecording() {
|
|||||||
# Generate a preview thumbnail from the first frame
|
# 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
|
ffmpeg -y -i "$filename" -ss 00:00:00.1 -vframes 1 -q:v 2 "$preview" -loglevel quiet 2>/dev/null
|
||||||
|
|
||||||
omarchy-notification-send "Screen recording saved" "Open with Super + Alt + , (or click this)" \
|
omarchy-notification-send "$(omarchy-text "Screen recording saved")" "$(omarchy-text "Open with Super + Alt + , (or click this)")" \
|
||||||
-t 10000 --image "${preview:-$filename}" \
|
-t 10000 --image "${preview:-$filename}" \
|
||||||
--exec mpv -- "$filename"
|
--exec mpv -- "$filename"
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
mapfile -t devices < <(omarchy-capture-webcam-list)
|
mapfile -t devices < <(omarchy-capture-webcam-list)
|
||||||
if (( ${#devices[@]} == 0 )); then
|
if (( ${#devices[@]} == 0 )); then
|
||||||
omarchy-notification-send "No webcam devices found" -u critical -t 3000
|
omarchy-notification-send "$(omarchy-text "No webcam devices found")" -u critical -t 3000
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -23,4 +23,4 @@ TEXT=$(grim -g "$SELECTION" - | tesseract stdin stdout --oem 1 --psm 6 -l "${OMA
|
|||||||
[[ -z $TEXT ]] && exit 1
|
[[ -z $TEXT ]] && exit 1
|
||||||
|
|
||||||
printf "%s" "$TEXT" | wl-copy
|
printf "%s" "$TEXT" | wl-copy
|
||||||
omarchy-notification-send -g "Copied text from selection to clipboard"
|
omarchy-notification-send -g "$(omarchy-text "Copied text from selection to clipboard")"
|
||||||
@@ -47,9 +47,31 @@ validate_dev_checkout() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# The dev channel refreshes pacman with the checkout's own tools. A checkout
|
||||||
|
# without this machine's region profile would silently drop its repositories.
|
||||||
|
validate_dev_region() {
|
||||||
|
local checkout="$1" region_file="${OMARCHY_REGION_FILE:-/etc/omarchy/region}" region=global
|
||||||
|
|
||||||
|
[[ -f $region_file ]] && region=$(<"$region_file")
|
||||||
|
[[ $region == "global" ]] && return 0
|
||||||
|
|
||||||
|
# The refresh after linking needs a runnable helper and every fragment, not
|
||||||
|
# just a directory with the region's name: dev refreshes edge, and leaving
|
||||||
|
# dev later refreshes stable or rc with this checkout's tools.
|
||||||
|
local profile="$checkout/default/regions/$region/pacman" fragment supported=true
|
||||||
|
[[ -x $checkout/bin/omarchy-apply-pacman ]] || supported=false
|
||||||
|
for fragment in pacman.conf.append mirrorlist-stable.prepend mirrorlist-rc.prepend mirrorlist-edge.prepend; do
|
||||||
|
[[ -r $profile/$fragment ]] || supported=false
|
||||||
|
done
|
||||||
|
if ! $supported; then
|
||||||
|
fail "$checkout does not support the '$region' region, so switching would drop its package repositories. Check out a branch with default/regions/$region, or remove $region_file to use global defaults."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
link_dev_checkout() {
|
link_dev_checkout() {
|
||||||
local checkout="$1" required
|
local checkout="$1" required
|
||||||
[[ -d $checkout/.git ]] || git clone https://github.com/omacom/omarchy.git "$checkout"
|
[[ -d $checkout/.git ]] || git clone https://github.com/omacom/omarchy.git "$checkout"
|
||||||
|
validate_dev_region "$checkout"
|
||||||
|
|
||||||
# Check the destination before changing /etc/omarchy.conf or sudo's path.
|
# Check the destination before changing /etc/omarchy.conf or sudo's path.
|
||||||
# An existing checkout is not pulled automatically and may predate this policy.
|
# An existing checkout is not pulled automatically and may predate this policy.
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ copy_url() {
|
|||||||
|
|
||||||
[[ -n $url ]] || return 1
|
[[ -n $url ]] || return 1
|
||||||
printf '%s' "$url" | wl-copy --type text/plain
|
printf '%s' "$url" | wl-copy --type text/plain
|
||||||
omarchy-notification-send -g "URL copied to clipboard"
|
omarchy-notification-send -g "$(omarchy-text "URL copied to clipboard")"
|
||||||
}
|
}
|
||||||
|
|
||||||
reply_copied() {
|
reply_copied() {
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ download_url() {
|
|||||||
|
|
||||||
# Don't show anything until yt-dlp confirms there's actually a video to grab.
|
# Don't show anything until yt-dlp confirms there's actually a video to grab.
|
||||||
if ! yt-dlp --no-playlist --simulate --quiet --no-warnings --no-exec --no-exec-before-download -- "$url" >/dev/null 2>&1; then
|
if ! yt-dlp --no-playlist --simulate --quiet --no-warnings --no-exec --no-exec-before-download -- "$url" >/dev/null 2>&1; then
|
||||||
omarchy-notification-send -u critical -g "No video found for download" "$url"
|
omarchy-notification-send -u critical -g "$(omarchy-text "No video found for download")" "$url"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ download_url() {
|
|||||||
# toast would exit before the thumbnail cleanup below is ever scheduled.
|
# toast would exit before the thumbnail cleanup below is ever scheduled.
|
||||||
# `--` keeps mpv from parsing a leading-dash filename as an option; the path
|
# `--` keeps mpv from parsing a leading-dash filename as an option; the path
|
||||||
# is one discrete argument, so it never reaches a shell.
|
# is one discrete argument, so it never reaches a shell.
|
||||||
omarchy-notification-send -g "Download complete" "$title" \
|
omarchy-notification-send -g "$(omarchy-text "Download complete")" "$title" \
|
||||||
-t 10000 --image "${preview:-$filepath}" \
|
-t 10000 --image "${preview:-$filepath}" \
|
||||||
--exec mpv -- "$filepath" || true
|
--exec mpv -- "$filepath" || true
|
||||||
|
|
||||||
@@ -160,7 +160,7 @@ download_url() {
|
|||||||
rm -f "$preview"
|
rm -f "$preview"
|
||||||
) &
|
) &
|
||||||
else
|
else
|
||||||
omarchy-notification-send -u critical -g "Download failed" "$url"
|
omarchy-notification-send -u critical -g "$(omarchy-text "Download failed")" "$url"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
@@ -40,8 +40,8 @@ announce() {
|
|||||||
omarchy-notification-send \
|
omarchy-notification-send \
|
||||||
--urgency critical \
|
--urgency critical \
|
||||||
--glyph "$CRASH_GLYPH" \
|
--glyph "$CRASH_GLYPH" \
|
||||||
"Process crashed: $comm" \
|
"$(omarchy-text "Process crashed: %1" "$comm")" \
|
||||||
"Click to diagnose with AI" \
|
"$(omarchy-text "Click to diagnose with AI")" \
|
||||||
--exec omarchy-agent-crash "$pid" "$comm" "$exe" "$signal"
|
--exec omarchy-agent-crash "$pid" "$comm" "$exe" "$signal"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,4 +48,4 @@ fi
|
|||||||
|
|
||||||
env -u BROWSER xdg-settings set default-web-browser "$desktop_id" || exit 1
|
env -u BROWSER xdg-settings set default-web-browser "$desktop_id" || exit 1
|
||||||
|
|
||||||
omarchy-notification-send -g $glyph "$name is now the default browser"
|
omarchy-notification-send -g $glyph "$(omarchy-text "%1 is now the default browser" "$name")"
|
||||||
@@ -59,4 +59,4 @@ fi
|
|||||||
mkdir -p "$(dirname "$editor_file")"
|
mkdir -p "$(dirname "$editor_file")"
|
||||||
printf '%s\n' "$editor" >"$editor_file"
|
printf '%s\n' "$editor" >"$editor_file"
|
||||||
|
|
||||||
omarchy-notification-send -g $glyph "$name is now the default editor"
|
omarchy-notification-send -g $glyph "$(omarchy-text "%1 is now the default editor" "$name")"
|
||||||
@@ -48,4 +48,4 @@ cat >~/.config/xdg-terminals.list <<EOF
|
|||||||
$desktop_id
|
$desktop_id
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
omarchy-notification-send -g $glyph "$name is now the default terminal"
|
omarchy-notification-send -g $glyph "$(omarchy-text "%1 is now the default terminal" "$name")"
|
||||||
@@ -169,7 +169,7 @@ set_terminal_size() {
|
|||||||
[[ $prev_id =~ ^[0-9]+$ ]] && replace=(-r "$prev_id")
|
[[ $prev_id =~ ^[0-9]+$ ]] && replace=(-r "$prev_id")
|
||||||
local new_id
|
local new_id
|
||||||
new_id="$(omarchy-notification-send \
|
new_id="$(omarchy-notification-send \
|
||||||
"Restart Foot to apply the new terminal font size" \
|
"$(omarchy-text "Restart Foot to apply the new terminal font size")" \
|
||||||
"${replace[@]}" -p 2>/dev/null)" || true
|
"${replace[@]}" -p 2>/dev/null)" || true
|
||||||
[[ $new_id =~ ^[0-9]+$ ]] && printf '%s\n' "$new_id" >"$id_file"
|
[[ $new_id =~ ^[0-9]+$ ]] && printf '%s\n' "$new_id" >"$id_file"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -74,11 +74,11 @@ XML
|
|||||||
omarchy-restart-shell
|
omarchy-restart-shell
|
||||||
|
|
||||||
if pgrep -x ghostty; then
|
if pgrep -x ghostty; then
|
||||||
omarchy-notification-send -g "You must restart Ghostty to see font change"
|
omarchy-notification-send -g "$(omarchy-text "You must restart Ghostty to see font change")"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if pgrep -x foot; then
|
if pgrep -x foot; then
|
||||||
omarchy-notification-send -g "You must restart Foot to see font change"
|
omarchy-notification-send -g "$(omarchy-text "You must restart Foot to see font change")"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
omarchy-hook font-set "$font_name"
|
omarchy-hook font-set "$font_name"
|
||||||
@@ -10,7 +10,7 @@ if (( $# == 0 )); then
|
|||||||
mapfile -t cores < <(omarchy-games-retro-cores)
|
mapfile -t cores < <(omarchy-games-retro-cores)
|
||||||
|
|
||||||
if (( ${#cores[@]} == 0 )); then
|
if (( ${#cores[@]} == 0 )); then
|
||||||
omarchy-notification-send -g "No RetroArch cores found" "/usr/lib/libretro"
|
omarchy-notification-send -g "$(omarchy-text "No RetroArch cores found")" "/usr/lib/libretro"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -69,4 +69,4 @@ EOF
|
|||||||
chmod +x "$desktop_file"
|
chmod +x "$desktop_file"
|
||||||
update-desktop-database "$desktop_dir" &>/dev/null || true
|
update-desktop-database "$desktop_dir" &>/dev/null || true
|
||||||
|
|
||||||
omarchy-notification-send -g "$game_name installed" "Start it with Super + Space"
|
omarchy-notification-send -g "$(omarchy-text "%1 installed" "$game_name")" "$(omarchy-text "Start it with Super + Space")"
|
||||||
Executable
+41
@@ -0,0 +1,41 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# omarchy:summary=Show or set window corners: theme, sharp, or rounded
|
||||||
|
# omarchy:args=[theme|sharp|rounded]
|
||||||
|
# omarchy:examples=omarchy hyprland corners | omarchy hyprland corners rounded
|
||||||
|
|
||||||
|
TOGGLES_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/omarchy/toggles/hypr"
|
||||||
|
|
||||||
|
# Sharp and rounded are toggle files loaded after every theme, so they override
|
||||||
|
# the corners of whichever theme is current. Theme removes both.
|
||||||
|
if (( $# == 0 )); then
|
||||||
|
if [[ -f $TOGGLES_DIR/corners-sharp.lua ]]; then
|
||||||
|
echo "sharp"
|
||||||
|
elif [[ -f $TOGGLES_DIR/corners-rounded.lua ]]; then
|
||||||
|
echo "rounded"
|
||||||
|
else
|
||||||
|
echo "theme"
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
theme) LABEL=$(omarchy-text "Corners follow the theme") ;;
|
||||||
|
sharp) LABEL=$(omarchy-text "Sharp corners for all themes") ;;
|
||||||
|
rounded) LABEL=$(omarchy-text "Rounded corners for all themes") ;;
|
||||||
|
*)
|
||||||
|
echo "Usage: omarchy-hyprland-corners [theme|sharp|rounded]" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Save the new choice before dropping the old one, so a failed save keeps it.
|
||||||
|
if [[ $1 != "theme" ]]; then
|
||||||
|
mkdir -p "$TOGGLES_DIR" && cp "$OMARCHY_PATH/default/hypr/toggles/corners-$1.lua" "$TOGGLES_DIR/corners-$1.lua" || exit 1
|
||||||
|
fi
|
||||||
|
for mode in sharp rounded; do
|
||||||
|
[[ $mode == "$1" ]] || rm -f "$TOGGLES_DIR/corners-$mode.lua" || exit 1
|
||||||
|
done
|
||||||
|
|
||||||
|
hyprctl reload >/dev/null || exit 1
|
||||||
|
omarchy-notification-send -g "$LABEL"
|
||||||
@@ -16,7 +16,7 @@ wake() {
|
|||||||
on() {
|
on() {
|
||||||
if omarchy-hyprland-toggle-enabled $TOGGLE; then
|
if omarchy-hyprland-toggle-enabled $TOGGLE; then
|
||||||
omarchy-hyprland-toggle $TOGGLE off
|
omarchy-hyprland-toggle $TOGGLE off
|
||||||
omarchy-notification-send -g "Laptop display enabled"
|
omarchy-notification-send -g "$(omarchy-text "Laptop display enabled")"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
wake
|
wake
|
||||||
@@ -24,25 +24,25 @@ on() {
|
|||||||
|
|
||||||
off() {
|
off() {
|
||||||
if [[ -z $INTERNAL ]]; then
|
if [[ -z $INTERNAL ]]; then
|
||||||
omarchy-notification-send -g "No laptop display found"
|
omarchy-notification-send -g "$(omarchy-text "No laptop display found")"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# The name is written into generated Lua below, so only a plain connector
|
# The name is written into generated Lua below, so only a plain connector
|
||||||
# name may pass; anything else could execute on the next reload.
|
# name may pass; anything else could execute on the next reload.
|
||||||
if [[ ! $INTERNAL =~ ^[A-Za-z0-9._-]+$ ]]; then
|
if [[ ! $INTERNAL =~ ^[A-Za-z0-9._-]+$ ]]; then
|
||||||
omarchy-notification-send -g "Refusing unsafe monitor name"
|
omarchy-notification-send -g "$(omarchy-text "Refusing unsafe monitor name")"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! omarchy-hyprland-monitor-external-active; then
|
if ! omarchy-hyprland-monitor-external-active; then
|
||||||
omarchy-notification-send -g "Can't disable the only active display"
|
omarchy-notification-send -g "$(omarchy-text "Can't disable the only active display")"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if omarchy-hyprland-toggle-disabled $TOGGLE && omarchy-hyprland-toggle-disabled $MIRROR_TOGGLE; then
|
if omarchy-hyprland-toggle-disabled $TOGGLE && omarchy-hyprland-toggle-disabled $MIRROR_TOGGLE; then
|
||||||
printf 'hl.monitor({ output = "%s", disabled = true })\n' "$INTERNAL" >"$TOGGLE_FLAG"
|
printf 'hl.monitor({ output = "%s", disabled = true })\n' "$INTERNAL" >"$TOGGLE_FLAG"
|
||||||
omarchy-notification-send -g "Laptop display disabled"
|
omarchy-notification-send -g "$(omarchy-text "Laptop display disabled")"
|
||||||
hyprctl reload
|
hyprctl reload
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ EXTERNAL=$(hyprctl monitors -j | jq -r '.[] | select(.name | test("^(eDP|LVDS|DS
|
|||||||
|
|
||||||
on() {
|
on() {
|
||||||
if [[ -z $EXTERNAL ]]; then
|
if [[ -z $EXTERNAL ]]; then
|
||||||
omarchy-notification-send -g "No external monitors found for mirror"
|
omarchy-notification-send -g "$(omarchy-text "No external monitors found for mirror")"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -z $INTERNAL ]]; then
|
if [[ -z $INTERNAL ]]; then
|
||||||
omarchy-notification-send -g "No laptop monitor found to mirror"
|
omarchy-notification-send -g "$(omarchy-text "No laptop monitor found to mirror")"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ on() {
|
|||||||
# names may pass; a user-created headless output can carry any name.
|
# names may pass; a user-created headless output can carry any name.
|
||||||
for output in "$INTERNAL" "$EXTERNAL"; do
|
for output in "$INTERNAL" "$EXTERNAL"; do
|
||||||
if [[ ! $output =~ ^[A-Za-z0-9._-]+$ ]]; then
|
if [[ ! $output =~ ^[A-Za-z0-9._-]+$ ]]; then
|
||||||
omarchy-notification-send -g "Refusing unsafe monitor name"
|
omarchy-notification-send -g "$(omarchy-text "Refusing unsafe monitor name")"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@@ -35,7 +35,7 @@ on() {
|
|||||||
|
|
||||||
if omarchy-hyprland-toggle-disabled $TOGGLE; then
|
if omarchy-hyprland-toggle-disabled $TOGGLE; then
|
||||||
printf 'hl.monitor({ output = "%s", mode = "preferred", position = "auto", scale = 1, mirror = "%s" })\n' "$EXTERNAL" "$INTERNAL" >"$TOGGLE_FLAG"
|
printf 'hl.monitor({ output = "%s", mode = "preferred", position = "auto", scale = 1, mirror = "%s" })\n' "$EXTERNAL" "$INTERNAL" >"$TOGGLE_FLAG"
|
||||||
omarchy-notification-send -g "Mirroring enabled ($EXTERNAL)"
|
omarchy-notification-send -g "$(omarchy-text "Mirroring enabled (%1)" "$EXTERNAL")"
|
||||||
hyprctl reload
|
hyprctl reload
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -43,7 +43,7 @@ on() {
|
|||||||
off() {
|
off() {
|
||||||
if omarchy-hyprland-toggle-enabled $TOGGLE; then
|
if omarchy-hyprland-toggle-enabled $TOGGLE; then
|
||||||
omarchy-hyprland-toggle $TOGGLE off
|
omarchy-hyprland-toggle $TOGGLE off
|
||||||
omarchy-notification-send -g "Extended mode restored"
|
omarchy-notification-send -g "$(omarchy-text "Extended mode restored")"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Executable
+19
@@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# omarchy:summary=Returns true when the compositor holds a session lock no other locker is alive to own
|
||||||
|
# omarchy:args=<own-pid>
|
||||||
|
# omarchy:hidden=true
|
||||||
|
|
||||||
|
# Hyprland lets any client take over a held lock (misc:allow_session_lock_restore),
|
||||||
|
# so a shell that recovers a lock it merely sees can take the live lock screen of
|
||||||
|
# another shell, and strand it when it exits. A lock is stranded only while no
|
||||||
|
# other Quickshell or hyprlock is running; until then the answer is undetermined,
|
||||||
|
# so the caller keeps asking until that locker exits or it gives up.
|
||||||
|
#
|
||||||
|
# Exits 0 stranded, 1 unlocked, 2 undetermined. The caller passes its own pid,
|
||||||
|
# as a crash re-execs the shell in place.
|
||||||
|
omarchy-hyprland-session-locked || exit
|
||||||
|
|
||||||
|
if pgrep -u "$UID" -x 'quickshell|qs|hyprlock' | grep -qvxF "$1"; then
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
@@ -3,6 +3,6 @@
|
|||||||
# omarchy:summary=Toggle single-window square aspect ratio.
|
# omarchy:summary=Toggle single-window square aspect ratio.
|
||||||
|
|
||||||
case $(omarchy-hyprland-toggle single-window-aspect-ratio) in
|
case $(omarchy-hyprland-toggle single-window-aspect-ratio) in
|
||||||
on) omarchy-notification-send -g "Enable single-window square aspect ratio" ;;
|
on) omarchy-notification-send -g "$(omarchy-text "Enable single-window square aspect ratio")" ;;
|
||||||
off) omarchy-notification-send -g "Disable single-window square aspect ratio" ;;
|
off) omarchy-notification-send -g "$(omarchy-text "Disable single-window square aspect ratio")" ;;
|
||||||
esac
|
esac
|
||||||
Executable
+70
@@ -0,0 +1,70 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# omarchy:summary=Show or set how see-through windows are: opaque, transparent, or glassy
|
||||||
|
# omarchy:args=[opaque|transparent|glassy]
|
||||||
|
# omarchy:examples=omarchy hyprland window transparency | omarchy hyprland window transparency glassy
|
||||||
|
|
||||||
|
TOGGLES_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/omarchy/toggles/hypr"
|
||||||
|
|
||||||
|
# Opaque and glassy are toggle files loaded after every theme: opaque makes the
|
||||||
|
# windows Omarchy makes transparent solid, and glassy blurs what is behind any
|
||||||
|
# see-through window and gives terminals a see-through background. Transparent,
|
||||||
|
# the default, removes both.
|
||||||
|
current_mode() {
|
||||||
|
if [[ -f $TOGGLES_DIR/window-opaque.lua ]]; then
|
||||||
|
echo "opaque"
|
||||||
|
elif [[ -f $TOGGLES_DIR/window-glassy.lua ]]; then
|
||||||
|
echo "glassy"
|
||||||
|
else
|
||||||
|
echo "transparent"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Save the new choice before dropping the old one, so a failed save keeps it.
|
||||||
|
save_mode() {
|
||||||
|
if [[ $1 != "transparent" ]]; then
|
||||||
|
mkdir -p "$TOGGLES_DIR" && cp "$OMARCHY_PATH/default/hypr/toggles/window-$1.lua" "$TOGGLES_DIR/window-$1.lua" || return 1
|
||||||
|
fi
|
||||||
|
local mode
|
||||||
|
for mode in opaque glassy; do
|
||||||
|
[[ $mode == "$1" ]] || rm -f "$TOGGLES_DIR/window-$mode.lua" || return 1
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
if (( $# == 0 )); then
|
||||||
|
current_mode
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
opaque) LABEL=$(omarchy-text "Opaque windows") ;;
|
||||||
|
transparent) LABEL=$(omarchy-text "Transparent windows") ;;
|
||||||
|
glassy) LABEL=$(omarchy-text "Glassy windows") ;;
|
||||||
|
*)
|
||||||
|
echo "Usage: omarchy-hyprland-window-transparency [opaque|transparent|glassy]" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# A theme switch renders the next theme's terminal files from the saved choice
|
||||||
|
# and then replaces the current theme, so the choice and the glass written into
|
||||||
|
# the current theme are changed under its lock, or the switch could drop them.
|
||||||
|
exec 9>"${XDG_RUNTIME_DIR:-/tmp}/omarchy-theme-set.lock"
|
||||||
|
flock 9
|
||||||
|
|
||||||
|
# A choice whose glass cannot be written is taken back, so the saved choice
|
||||||
|
# is always the one on screen.
|
||||||
|
previous=$(current_mode)
|
||||||
|
save_mode "$1" || exit 1
|
||||||
|
if ! omarchy-theme-set-glass; then
|
||||||
|
save_mode "$previous"
|
||||||
|
omarchy-theme-set-glass
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
flock -u 9
|
||||||
|
|
||||||
|
hyprctl reload >/dev/null || exit 1
|
||||||
|
omarchy-restart-terminal
|
||||||
|
omarchy-theme-set-foot
|
||||||
|
omarchy-restart-btop
|
||||||
|
omarchy-notification-send -g "$LABEL"
|
||||||
@@ -40,14 +40,14 @@ notify_missing_width() {
|
|||||||
local key="$1"
|
local key="$1"
|
||||||
local workspace="$2"
|
local workspace="$2"
|
||||||
|
|
||||||
omarchy-notification-send -g "No saved width found for $key on workspace $workspace" "Use Super + Alt + Home to save one for this workspace."
|
omarchy-notification-send -g "$(omarchy-text "No saved width found for %1 on workspace %2" "$key" "$workspace")" "Use Super + Alt + Home to save one for this workspace."
|
||||||
}
|
}
|
||||||
|
|
||||||
notify_saved_width() {
|
notify_saved_width() {
|
||||||
local key="$1"
|
local key="$1"
|
||||||
local workspace="$2"
|
local workspace="$2"
|
||||||
|
|
||||||
omarchy-notification-send -g "Saved width for $key on workspace $workspace" "Restore using Super + Home on this workspace."
|
omarchy-notification-send -g "$(omarchy-text "Saved width for %1 on workspace %2" "$key" "$workspace")" "Restore using Super + Home on this workspace."
|
||||||
}
|
}
|
||||||
|
|
||||||
hypr_dispatch() {
|
hypr_dispatch() {
|
||||||
|
|||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# omarchy:summary=Print the layout of a workspace: dwindle, scrolling, or floating
|
||||||
|
# omarchy:args=[workspace-id]
|
||||||
|
|
||||||
|
if [[ -n $1 ]]; then
|
||||||
|
WORKSPACE_ID=$1
|
||||||
|
TILED_LAYOUT=$(hyprctl workspaces -j | jq -r --arg id "$WORKSPACE_ID" 'first(.[] | select((.id | tostring) == $id) | .tiledLayout) // empty')
|
||||||
|
else
|
||||||
|
read -r WORKSPACE_ID TILED_LAYOUT < <(hyprctl activeworkspace -j | jq -r '"\(.id) \(.tiledLayout // "")"')
|
||||||
|
fi
|
||||||
|
|
||||||
|
MODES_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/omarchy/workspace-layouts"
|
||||||
|
|
||||||
|
# Hyprland only reports the tiled layout, and floating is not one, so the mode is
|
||||||
|
# read back from the file omarchy-hyprland-workspace-layout-toggle wrote. Files
|
||||||
|
# saved before floating existed name no mode, and a workspace without a mode of
|
||||||
|
# its own follows the default layout.
|
||||||
|
if [[ $WORKSPACE_ID =~ ^[0-9]+$ ]] && (( WORKSPACE_ID >= 1 )); then
|
||||||
|
MODE=$(sed -n 's/.*mode = "\([a-z]*\)".*/\1/p' "$MODES_DIR/$WORKSPACE_ID.lua" 2>/dev/null)
|
||||||
|
|
||||||
|
if [[ -z $MODE && -f $MODES_DIR/default.lua ]]; then
|
||||||
|
MODE=$(omarchy-hyprland-workspace-layout-default)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
MODE=${MODE:-$TILED_LAYOUT}
|
||||||
|
echo "${MODE:-dwindle}"
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# omarchy:summary=Show or set the layout of workspaces without one of their own: dwindle, scrolling, or floating
|
||||||
|
# omarchy:args=[dwindle|scrolling|floating]
|
||||||
|
# omarchy:examples=omarchy hyprland workspace layout default | omarchy hyprland workspace layout default scrolling
|
||||||
|
|
||||||
|
MODES_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/omarchy/workspace-layouts"
|
||||||
|
DEFAULT_FILE="$MODES_DIR/default.lua"
|
||||||
|
|
||||||
|
# Without a saved default, Hyprland's own layout is the default, which the
|
||||||
|
# user's looknfeel may have set.
|
||||||
|
if (( $# == 0 )); then
|
||||||
|
MODE=$(sed -n 's/.*default = "\([a-z]*\)".*/\1/p' "$DEFAULT_FILE" 2>/dev/null)
|
||||||
|
[[ -n $MODE ]] || MODE=$(hyprctl getoption general.layout -j 2>/dev/null | jq -r '.str // empty')
|
||||||
|
echo "${MODE:-dwindle}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
dwindle) LABEL=tiling ;;
|
||||||
|
scrolling | floating) LABEL=$1 ;;
|
||||||
|
*)
|
||||||
|
echo "Usage: omarchy-hyprland-workspace-layout-default [dwindle|scrolling|floating]" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Saved even for dwindle, so the choice also wins over a layout set in the
|
||||||
|
# user's own looknfeel. Workspaces given a layout with Super + L keep theirs.
|
||||||
|
mkdir -p "$MODES_DIR"
|
||||||
|
printf 'o.workspace_mode({ default = "%s" })\n' "$1" >"$DEFAULT_FILE"
|
||||||
|
|
||||||
|
hyprctl reload >/dev/null
|
||||||
|
omarchy-shell -q omarchy.workspaces refresh
|
||||||
|
omarchy-notification-send -g "$(omarchy-text "New workspaces use the %1 layout" "$LABEL")"
|
||||||
@@ -1,21 +1,69 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# omarchy:summary=Toggle the layout on the current active workspace between dwindle and scrolling
|
# omarchy:summary=Cycle the current active workspace through the dwindle, scrolling, and floating layouts
|
||||||
|
# omarchy:args=[back]
|
||||||
|
|
||||||
|
DIRECTION=${1:-next}
|
||||||
|
if [[ $DIRECTION != "next" && $DIRECTION != "back" ]]; then
|
||||||
|
echo "Usage: omarchy-hyprland-workspace-layout-toggle [back]" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
ACTIVE_WORKSPACE=$(hyprctl activeworkspace -j | jq -r '.id')
|
ACTIVE_WORKSPACE=$(hyprctl activeworkspace -j | jq -r '.id')
|
||||||
[[ $ACTIVE_WORKSPACE =~ ^-?[0-9]+$ ]] || exit 1
|
# Named workspaces report a negative id, and Hyprland reads a leading "-" as a
|
||||||
CURRENT_LAYOUT=$(hyprctl activeworkspace -j | jq -r '.tiledLayout')
|
# selector relative to the current workspace: targeting one lands on workspace 1
|
||||||
LAYOUTS_DIR="$HOME/.local/state/omarchy/workspace-layouts"
|
# and reconfigures that instead.
|
||||||
LAYOUT_FILE="$LAYOUTS_DIR/$ACTIVE_WORKSPACE.lua"
|
[[ $ACTIVE_WORKSPACE =~ ^[0-9]+$ ]] || exit 1
|
||||||
|
MODES_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/omarchy/workspace-layouts"
|
||||||
|
MODE_FILE="$MODES_DIR/$ACTIVE_WORKSPACE.lua"
|
||||||
|
|
||||||
case "$CURRENT_LAYOUT" in
|
CURRENT_MODE=$(omarchy-hyprland-workspace-layout-current)
|
||||||
dwindle) NEW_LAYOUT=scrolling ;;
|
|
||||||
*) NEW_LAYOUT=dwindle ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
mkdir -p "$LAYOUTS_DIR"
|
if [[ $DIRECTION == "back" ]]; then
|
||||||
printf 'hl.workspace_rule({ workspace = "%s", layout = "%s" })\n' "$ACTIVE_WORKSPACE" "$NEW_LAYOUT" >"$LAYOUT_FILE"
|
case "$CURRENT_MODE" in
|
||||||
|
dwindle) NEW_MODE=floating ;;
|
||||||
|
floating) NEW_MODE=scrolling ;;
|
||||||
|
*) NEW_MODE=dwindle ;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
case "$CURRENT_MODE" in
|
||||||
|
dwindle) NEW_MODE=scrolling ;;
|
||||||
|
scrolling) NEW_MODE=floating ;;
|
||||||
|
*) NEW_MODE=dwindle ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
hyprctl eval "hl.workspace_rule({ workspace = \"$ACTIVE_WORKSPACE\", layout = \"$NEW_LAYOUT\" })" >/dev/null 2>&1 || \
|
APPLY="o.workspace_mode({ workspace = \"$ACTIVE_WORKSPACE\", mode = \"$NEW_MODE\" })"
|
||||||
hyprctl keyword workspace "$ACTIVE_WORKSPACE, layout:$NEW_LAYOUT"
|
|
||||||
omarchy-notification-send -g "Workspace layout set to $NEW_LAYOUT"
|
# Saving a mode that did not apply would leave the file naming one layout while
|
||||||
|
# the screen shows another, and restore it at the next login.
|
||||||
|
APPLIED=0
|
||||||
|
if hyprctl eval "$APPLY" >/dev/null 2>&1; then
|
||||||
|
APPLIED=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if (( ! APPLIED )); then
|
||||||
|
omarchy-notification-send -g "$(omarchy-text "Workspace layout needs a Hyprland reload")"
|
||||||
|
elif [[ $NEW_MODE == "$(omarchy-hyprland-workspace-layout-default)" ]] && rm -f "$MODE_FILE"; then
|
||||||
|
# Cycled onto the default, a workspace goes back to following it, so a later
|
||||||
|
# change of the default reaches it too.
|
||||||
|
omarchy-notification-send -g "$(omarchy-text "Workspace layout set to %1" "$NEW_MODE")"
|
||||||
|
elif mkdir -p "$MODES_DIR" && printf '%s\n' "$APPLY" >"$MODE_FILE"; then
|
||||||
|
omarchy-notification-send -g "$(omarchy-text "Workspace layout set to %1" "$NEW_MODE")"
|
||||||
|
else
|
||||||
|
# The mode is on screen but nothing will bring it back, and the next press
|
||||||
|
# reads the mode from this file, so say so rather than counting it as set.
|
||||||
|
omarchy-notification-send -g "$(omarchy-text "Workspace layout set to %1 but could not be saved" "$NEW_MODE")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# The bar shows the focused workspace's layout.
|
||||||
|
if (( APPLIED )); then
|
||||||
|
omarchy-shell -q omarchy.workspaces refresh
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Titlebars and shadows are set up while the config loads, and only
|
||||||
|
# when something floats, so the first floating workspace needs a reload to get
|
||||||
|
# them. Once the titlebar plugin is in, later ones have them already.
|
||||||
|
if (( APPLIED )) && [[ $NEW_MODE == "floating" ]] && ! hyprctl plugin list -j 2>/dev/null | jq -e 'any(.[]?; .name == "hyprbars")' >/dev/null 2>&1; then
|
||||||
|
hyprctl reload >/dev/null
|
||||||
|
fi
|
||||||
@@ -92,6 +92,9 @@ phoenix)
|
|||||||
;;
|
;;
|
||||||
rust)
|
rust)
|
||||||
echo -e "Installing Rust...\n"
|
echo -e "Installing Rust...\n"
|
||||||
|
# Crates that generate C bindings with bindgen, including Ruby gems built
|
||||||
|
# with rb-sys, load libclang from clang.
|
||||||
|
omarchy-pkg-add clang
|
||||||
bash -c "$(curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs)" -- -y
|
bash -c "$(curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs)" -- -y
|
||||||
;;
|
;;
|
||||||
java)
|
java)
|
||||||
|
|||||||
@@ -23,5 +23,5 @@ superwhisper shortcuts set toggle "Alt+Space" >/dev/null
|
|||||||
superwhisper shortcuts set hold none >/dev/null
|
superwhisper shortcuts set hold none >/dev/null
|
||||||
omarchy-dictation-use superwhisper
|
omarchy-dictation-use superwhisper
|
||||||
hyprctl reload >/dev/null
|
hyprctl reload >/dev/null
|
||||||
omarchy-notification-send -g "Superwhisper Dictation Ready" "Hold Right Alt or F9 to dictate (or toggle with Super + Ctrl + X)." -t 10000
|
omarchy-notification-send -g "$(omarchy-text "Superwhisper Dictation Ready")" "$(omarchy-text "Hold Right Alt or F9 to dictate (or toggle with Super + Ctrl + X).")" -t 10000
|
||||||
superwhisper settings
|
superwhisper settings
|
||||||
@@ -33,4 +33,4 @@ systemctl --user enable --now voxtype.service
|
|||||||
|
|
||||||
omarchy-dictation-use voxtype
|
omarchy-dictation-use voxtype
|
||||||
hyprctl reload >/dev/null
|
hyprctl reload >/dev/null
|
||||||
omarchy-notification-send -g "Voxtype Dictation Ready" "Hold Right Alt or F9 to dictate (or toggle with Super + Ctrl + X)." -t 10000
|
omarchy-notification-send -g "$(omarchy-text "Voxtype Dictation Ready")" "$(omarchy-text "Hold Right Alt or F9 to dictate (or toggle with Super + Ctrl + X).")" -t 10000
|
||||||
@@ -15,17 +15,15 @@ if gum confirm "Are you sure you want to restore all preinstalled web apps, TUI
|
|||||||
aether \
|
aether \
|
||||||
cliamp \
|
cliamp \
|
||||||
libreoffice-fresh \
|
libreoffice-fresh \
|
||||||
xournalpp \
|
|
||||||
pinta \
|
pinta \
|
||||||
obsidian \
|
obsidian \
|
||||||
obs-studio \
|
|
||||||
kdenlive \
|
|
||||||
moonlight-qt \
|
moonlight-qt \
|
||||||
omacut \
|
omacut \
|
||||||
monologue \
|
monologue \
|
||||||
omacalc \
|
omacalc \
|
||||||
omawrite \
|
omawrite \
|
||||||
hype; then
|
hype \
|
||||||
|
signed; then
|
||||||
echo -e "\nPreinstalls are still marked as removed. Fix the errors above and try again."
|
echo -e "\nPreinstalls are still marked as removed. Fix the errors above and try again."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
Executable
+46
@@ -0,0 +1,46 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# omarchy:summary=Show or switch the system language between English and Simplified Chinese
|
||||||
|
# omarchy:args=[en|zh]
|
||||||
|
# omarchy:examples=omarchy language | omarchy language zh
|
||||||
|
# omarchy:requires-sudo=true
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
locale_conf=/etc/locale.conf
|
||||||
|
|
||||||
|
if (($# == 0)); then
|
||||||
|
lang=$(sed -n 's/^LANG=//p' "$locale_conf")
|
||||||
|
# locale.conf may quote the value.
|
||||||
|
lang=${lang#[\"\']}
|
||||||
|
printf '%s\n' "${lang%[\"\']}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
case ${1:-} in
|
||||||
|
en) lang=en_US.UTF-8 ;;
|
||||||
|
zh) lang=zh_CN.UTF-8 ;;
|
||||||
|
*)
|
||||||
|
echo "Usage: omarchy-language [en|zh]" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
sudo sed -i "s/^#\(${lang/./\\.} UTF-8\)/\1/" /etc/locale.gen
|
||||||
|
sudo locale-gen
|
||||||
|
if grep -q '^LANG=' "$locale_conf"; then
|
||||||
|
sudo sed -i "s/^LANG=.*/LANG=$lang/" "$locale_conf"
|
||||||
|
else
|
||||||
|
sudo sed -i '$a\' "$locale_conf"
|
||||||
|
echo "LANG=$lang" | sudo tee -a "$locale_conf" >/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
# The language reaches only a new session, so offer one in the new language.
|
||||||
|
prompt=$(LANG=$lang omarchy-text "Log out now to switch the language?")
|
||||||
|
log_out=$(LANG=$lang omarchy-text "Log out now")
|
||||||
|
later=$(LANG=$lang omarchy-text "Later")
|
||||||
|
if [[ -t 0 && -t 1 ]] && gum confirm --affirmative "$log_out" --negative "$later" "$prompt" 2>&1; then
|
||||||
|
omarchy-system-logout
|
||||||
|
else
|
||||||
|
LANG=$lang omarchy-text "Log back in to switch the language."
|
||||||
|
fi
|
||||||
@@ -11,5 +11,5 @@ if [[ -z $path ]]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
omarchy-notification-send -u low "Editing config file" "$path"
|
omarchy-notification-send -u low "$(omarchy-text "Editing config file")" "$path"
|
||||||
exec omarchy-launch-editor "$path"
|
exec omarchy-launch-editor "$path"
|
||||||
@@ -16,7 +16,7 @@ terminal=$(xdg-terminal-exec --print-id)
|
|||||||
case $terminal in
|
case $terminal in
|
||||||
*Alacritty* | *ghostty* | *foot* | *kitty*) ;;
|
*Alacritty* | *ghostty* | *foot* | *kitty*) ;;
|
||||||
*)
|
*)
|
||||||
omarchy-notification-send -g ✋ "Screensaver only runs in Alacritty, Foot, Ghostty, or Kitty"
|
omarchy-notification-send -g ✋ "$(omarchy-text "Screensaver only runs in Alacritty, Foot, Ghostty, or Kitty")"
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ rows=$(jq -r --arg icon "$PLUGIN_ICON" \
|
|||||||
". as \$plugins
|
". as \$plugins
|
||||||
| .[] | select($filter)
|
| .[] | select($filter)
|
||||||
| \$icon + \"\\t\" + .name + \"\\t\" + .id" <<<"$plugins")
|
| \$icon + \"\\t\" + .name + \"\\t\" + .id" <<<"$plugins")
|
||||||
[[ -n $rows ]] || { omarchy-notification-send "No plugin to ${1}"; exit 0; }
|
[[ -n $rows ]] || { omarchy-notification-send "$(omarchy-text "No plugin to $1")"; exit 0; }
|
||||||
|
|
||||||
selection=$(omarchy-menu-select "${1^} plugin" <<<"$rows") || exit 0
|
selection=$(omarchy-menu-select "${1^} plugin" <<<"$rows") || exit 0
|
||||||
[[ -n $selection ]] || exit 0
|
[[ -n $selection ]] || exit 0
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ else
|
|||||||
picked=$(omarchy-file-select "${select_args[@]}") || status=$?
|
picked=$(omarchy-file-select "${select_args[@]}") || status=$?
|
||||||
|
|
||||||
if ((${status:-0} > 1)); then
|
if ((${status:-0} > 1)); then
|
||||||
omarchy-notification-send -g "" -u critical "Could not share" "The file chooser did not open"
|
omarchy-notification-send -g "" -u critical "$(omarchy-text "Could not share")" "$(omarchy-text "The file chooser did not open")"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -9,4 +9,4 @@ set -e
|
|||||||
timezone=$(timedatectl list-timezones | omarchy-menu-select "Set timezone" -- --width 520 --maxheight 520) || exit 1
|
timezone=$(timedatectl list-timezones | omarchy-menu-select "Set timezone" -- --width 520 --maxheight 520) || exit 1
|
||||||
sudo timedatectl set-timezone "$timezone"
|
sudo timedatectl set-timezone "$timezone"
|
||||||
omarchy-shell -q omarchy.clock refresh
|
omarchy-shell -q omarchy.clock refresh
|
||||||
omarchy-notification-send "Timezone is now set to $timezone"
|
omarchy-notification-send "$(omarchy-text "Timezone is now set to %1" "$timezone")"
|
||||||
@@ -21,9 +21,9 @@ pending_migrations=$(omarchy-migrate --pending 2>/dev/null) || exit 0
|
|||||||
pending_count=$(printf '%s\n' "$pending_migrations" | sed '/^[[:space:]]*$/d' | wc -l)
|
pending_count=$(printf '%s\n' "$pending_migrations" | sed '/^[[:space:]]*$/d' | wc -l)
|
||||||
|
|
||||||
if (( pending_count == 1 )); then
|
if (( pending_count == 1 )); then
|
||||||
message="Click to run 1 pending migration."
|
message=$(omarchy-text "Click to run 1 pending migration.")
|
||||||
else
|
else
|
||||||
message="Click to run $pending_count pending migrations."
|
message=$(omarchy-text "Click to run %1 pending migrations." "$pending_count")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# This runs from omarchy-migrate-notify.service after graphical-session.target,
|
# This runs from omarchy-migrate-notify.service after graphical-session.target,
|
||||||
@@ -40,7 +40,7 @@ fi
|
|||||||
|
|
||||||
# The shell keeps the click command with the toast, so this oneshot can hand the
|
# The shell keeps the click command with the toast, so this oneshot can hand the
|
||||||
# invitation over and exit instead of staying activated until it is answered.
|
# invitation over and exit instead of staying activated until it is answered.
|
||||||
omarchy-notification-send -u critical -g "Pending Omarchy Migrations" "$message" \
|
omarchy-notification-send -u critical -g "$(omarchy-text "Pending Omarchy Migrations")" "$message" \
|
||||||
--exec omarchy-launch-floating-terminal-with-presentation omarchy-migrate && exit 0
|
--exec omarchy-launch-floating-terminal-with-presentation omarchy-migrate && exit 0
|
||||||
|
|
||||||
# Reached when the notification could not be handed off, so fall back to telling
|
# Reached when the notification could not be handed off, so fall back to telling
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
# omarchy:summary=Show the current time and date notification
|
# omarchy:summary=Show the current time and date notification
|
||||||
|
|
||||||
omarchy-notification-send -g -u low "$(date +"%A %H:%M · %d %B %Y · Week %V")"
|
omarchy-notification-send -g -u low "$(date +"%A %H:%M · %d %B %Y") · $(omarchy-text "Week %1" "$(date +%V)")"
|
||||||
@@ -159,8 +159,8 @@ done
|
|||||||
omarchy-plugin-enable "$new_id" >/dev/null
|
omarchy-plugin-enable "$new_id" >/dev/null
|
||||||
clone_complete=1
|
clone_complete=1
|
||||||
omarchy-notification-send -g \
|
omarchy-notification-send -g \
|
||||||
"Editing Cloned Plugin" \
|
"$(omarchy-text "Editing Cloned Plugin")" \
|
||||||
"Original plugin has been replace by clone."
|
"$(omarchy-text "Original plugin has been replace by clone.")"
|
||||||
echo "Cloned $source_id to $target_dir and switched to $new_id"
|
echo "Cloned $source_id to $target_dir and switched to $new_id"
|
||||||
if (( edit_clone )); then
|
if (( edit_clone )); then
|
||||||
# Word-splitting is deliberate: EDITOR may carry flags.
|
# Word-splitting is deliberate: EDITOR may carry flags.
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ if [[ -z ${profile:-} ]] || ! profile_available "$profile"; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
powerprofilesctl set "$profile" || exit
|
powerprofilesctl set "$profile" || exit
|
||||||
|
omarchy-shell -q battery refreshPowerProfile >/dev/null 2>&1 || true
|
||||||
|
|
||||||
if [[ -n $requested_profile ]]; then
|
if [[ -n $requested_profile ]]; then
|
||||||
mkdir -p "$state_dir"
|
mkdir -p "$state_dir"
|
||||||
|
|||||||
@@ -187,11 +187,11 @@ tips=(
|
|||||||
"Super + Space opens the Omarchy menu for apps, settings, and more"
|
"Super + Space opens the Omarchy menu for apps, settings, and more"
|
||||||
"Super + K shows all the key bindings"
|
"Super + K shows all the key bindings"
|
||||||
"Super is the Windows or command key on your keyboard"
|
"Super is the Windows or command key on your keyboard"
|
||||||
"Use Xournal++ to sign PDFs"
|
"Sign PDFs and fill them in with Signed"
|
||||||
"Share files with phones and laptops using LocalSend"
|
"Share files with phones and laptops using LocalSend"
|
||||||
"Turn any website into an app with Install > Web App in the menu"
|
"Turn any website into an app with Install > Web App in the menu"
|
||||||
"Super + Return opens a terminal, Super + Shift + Return the browser"
|
"Super + Return opens a terminal, Super + Shift + Return the browser"
|
||||||
"Edit images with Pinta, videos with Kdenlive, docs with LibreOffice"
|
"Edit images with Pinta, trim videos with Omacut, docs with LibreOffice"
|
||||||
"Super + Ctrl + Print grabs text off the screen with OCR"
|
"Super + Ctrl + Print grabs text off the screen with OCR"
|
||||||
"Print takes a screenshot, Alt + Print records the screen"
|
"Print takes a screenshot, Alt + Print records the screen"
|
||||||
"Set a reminder with Super + Ctrl + R"
|
"Set a reminder with Super + Ctrl + R"
|
||||||
@@ -1174,15 +1174,6 @@ run_provisioning() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if omarchy-pkg-present usbguard; then
|
|
||||||
log_step "enrolling the owner's USB devices"
|
|
||||||
source "$OMARCHY_PATH/install/helpers/usb-authorization.sh"
|
|
||||||
usb_authorization_provision_owner "$username"
|
|
||||||
fi
|
|
||||||
|
|
||||||
log_step "enrolling the owner's Thunderbolt accessories"
|
|
||||||
/usr/bin/omarchy-thunderbolt-authorization-admin owner
|
|
||||||
|
|
||||||
log_step "cleaning up provisioning state"
|
log_step "cleaning up provisioning state"
|
||||||
cleanup_oem_state
|
cleanup_oem_state
|
||||||
log_step "first-boot setup complete"
|
log_step "first-boot setup complete"
|
||||||
|
|||||||
@@ -42,11 +42,29 @@ if [[ ! -f $templates/pacman-$channel.conf || ! -f $templates/mirrorlist-$channe
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
conf=$templates/pacman-$channel.conf mirrorlist=$templates/mirrorlist-$channel
|
||||||
|
# Regions render x86 pacman only (omarchy #13690).
|
||||||
|
if [[ $platform == x86 ]]; then
|
||||||
|
# Render the channel templates plus this machine's regional additions as the
|
||||||
|
# caller, so root only copies finished files. The scratch directory goes on
|
||||||
|
# every exit, including a failed render, a refused sudo prompt, or a signal;
|
||||||
|
# revoking the sudo timestamp stays the last thing the exit path does.
|
||||||
|
rendered=$(mktemp -d)
|
||||||
|
cleanup_refresh() {
|
||||||
|
local status=$?
|
||||||
|
rm -rf "$rendered"
|
||||||
|
omarchy_security_exit_with_revoked_sudo "$status"
|
||||||
|
}
|
||||||
|
trap cleanup_refresh EXIT
|
||||||
|
"$OMARCHY_PATH/bin/omarchy-apply-pacman" --render "$channel" "$rendered"
|
||||||
|
conf=$rendered/pacman.conf mirrorlist=$rendered/mirrorlist
|
||||||
|
fi
|
||||||
|
|
||||||
sudo cp -f /etc/pacman.conf /etc/pacman.conf.bak
|
sudo cp -f /etc/pacman.conf /etc/pacman.conf.bak
|
||||||
sudo cp -f /etc/pacman.d/mirrorlist /etc/pacman.d/mirrorlist.bak
|
sudo cp -f /etc/pacman.d/mirrorlist /etc/pacman.d/mirrorlist.bak
|
||||||
echo "Setting channel to $channel"
|
echo "Setting channel to $channel"
|
||||||
sudo cp -f "$templates/pacman-$channel.conf" /etc/pacman.conf
|
sudo cp -f "$conf" /etc/pacman.conf
|
||||||
sudo cp -f "$templates/mirrorlist-$channel" /etc/pacman.d/mirrorlist
|
sudo cp -f "$mirrorlist" /etc/pacman.d/mirrorlist
|
||||||
|
|
||||||
# Allow user customization of /etc/pacman.conf before the upgrade runs, so
|
# Allow user customization of /etc/pacman.conf before the upgrade runs, so
|
||||||
# custom repositories and IgnorePkg entries shape the downgrade-capable
|
# custom repositories and IgnorePkg entries shape the downgrade-capable
|
||||||
|
|||||||
Executable
+63
@@ -0,0 +1,63 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# omarchy:summary=Show or switch the region this machine is set up for
|
||||||
|
# omarchy:args=[global|cn]
|
||||||
|
# omarchy:examples=omarchy region | omarchy region cn
|
||||||
|
# omarchy:requires-sudo=true
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
region_file=/etc/omarchy/region
|
||||||
|
|
||||||
|
if (($# == 0)); then
|
||||||
|
if [[ ! -e $region_file ]]; then
|
||||||
|
echo "Global"
|
||||||
|
elif [[ $(<"$region_file") == "cn" ]]; then
|
||||||
|
echo "China"
|
||||||
|
else
|
||||||
|
echo "Unknown region in $region_file: $(<"$region_file")" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $1 != "global" && $1 != "cn" ]]; then
|
||||||
|
echo "Usage: omarchy-region [global|cn]" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
channel=$(omarchy-version-channel)
|
||||||
|
if [[ $channel != "stable" && $channel != "rc" && $channel != "edge" ]]; then
|
||||||
|
echo "Cannot tell this machine's package channel ($channel); run omarchy channel set first" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# The cn profile renders x86 pacman only (omarchy #13690).
|
||||||
|
if [[ $1 == "cn" && $(omarchy-hw-platform) != "x86" ]]; then
|
||||||
|
echo "The China region needs an x86 machine; $(omarchy-hw-platform) has no China profile yet" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $1 == "cn" ]]; then
|
||||||
|
# Upgrade first: the keyring install below syncs new databases.
|
||||||
|
omarchy-update-pacman -Syu --noconfirm
|
||||||
|
sudo env OMARCHY_REGION=cn OMARCHY_PATH="$OMARCHY_PATH" bash -e "$OMARCHY_PATH/install/config/region.sh"
|
||||||
|
# Trust ArchLinuxCN before the refresh upgrades through it.
|
||||||
|
rendered=$(mktemp -d)
|
||||||
|
trap 'rm -rf "$rendered"' EXIT
|
||||||
|
omarchy-apply-pacman --render "$channel" "$rendered"
|
||||||
|
mapfile -t profile_packages < <(grep -Ev '^[[:space:]]*(#|$)' "$OMARCHY_PATH/default/regions/cn/packages")
|
||||||
|
sudo pacman --config "$rendered/pacman.conf" -Sy --noconfirm --needed "${profile_packages[@]}"
|
||||||
|
sudo pacman-key --populate archlinuxcn
|
||||||
|
omarchy-refresh-pacman "$channel"
|
||||||
|
else
|
||||||
|
sudo env OMARCHY_REGION=global OMARCHY_PATH="$OMARCHY_PATH" bash -e "$OMARCHY_PATH/install/config/region.sh"
|
||||||
|
omarchy-refresh-pacman "$channel"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# The developer mirrors reach only a new session, so offer one.
|
||||||
|
if [[ -t 0 && -t 1 ]] && gum confirm --affirmative "$(omarchy-text "Log out now")" --negative "$(omarchy-text "Later")" "$(omarchy-text "Log out now to switch the developer mirrors?")"; then
|
||||||
|
omarchy-system-logout
|
||||||
|
else
|
||||||
|
omarchy-text "Log back in to switch the developer mirrors."
|
||||||
|
fi
|
||||||
+15
-14
@@ -57,16 +57,16 @@ show_reminders() {
|
|||||||
[[ -f $reminder_dir/${timer%.timer}.message ]] && reminder_message=$(<"$reminder_dir/${timer%.timer}.message")
|
[[ -f $reminder_dir/${timer%.timer}.message ]] && reminder_message=$(<"$reminder_dir/${timer%.timer}.message")
|
||||||
|
|
||||||
if [[ -n $reminder_message ]]; then
|
if [[ -n $reminder_message ]]; then
|
||||||
body+="$reminder_message in $(format_remaining $remaining) ($(date -d "@$next" +%-H:%M))"$'\n'
|
body+="$(omarchy-text "%1 in %2 (%3)" "$reminder_message" "$(format_remaining $remaining)" "$(date -d "@$next" +%-H:%M)")"$'\n'
|
||||||
else
|
else
|
||||||
body+="${reminder_minutes}-min reminder in $(format_remaining $remaining) ($(date -d "@$next" +%-H:%M))"$'\n'
|
body+="$(omarchy-text "%1-min reminder in %2 (%3)" "$reminder_minutes" "$(format_remaining $remaining)" "$(date -d "@$next" +%-H:%M)")"$'\n'
|
||||||
fi
|
fi
|
||||||
done < <(active_reminder_timers "$now")
|
done < <(active_reminder_timers "$now")
|
||||||
|
|
||||||
if [[ -z $body ]]; then
|
if [[ -z $body ]]; then
|
||||||
omarchy-notification-send -g "Upcoming reminders" "No outstanding reminders"
|
omarchy-notification-send -g "$(omarchy-text "Upcoming reminders")" "$(omarchy-text "No outstanding reminders")"
|
||||||
else
|
else
|
||||||
omarchy-notification-send -g "Upcoming reminders" "${body%$'\n'}"
|
omarchy-notification-send -g "$(omarchy-text "Upcoming reminders")" "${body%$'\n'}"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +75,8 @@ show_json() {
|
|||||||
local reminder_dir="${XDG_RUNTIME_DIR:-/tmp}/omarchy-reminders"
|
local reminder_dir="${XDG_RUNTIME_DIR:-/tmp}/omarchy-reminders"
|
||||||
local now=$(date +%s)
|
local now=$(date +%s)
|
||||||
local count=0
|
local count=0
|
||||||
local tooltip="Set Reminder"
|
local tooltip
|
||||||
|
tooltip=$(omarchy-text "Set Reminder")
|
||||||
|
|
||||||
while IFS=$'\t' read -r timer next; do
|
while IFS=$'\t' read -r timer next; do
|
||||||
count=$((count + 1))
|
count=$((count + 1))
|
||||||
@@ -91,7 +92,7 @@ show_json() {
|
|||||||
if [[ -n $reminder_message ]]; then
|
if [[ -n $reminder_message ]]; then
|
||||||
label=$reminder_message
|
label=$reminder_message
|
||||||
else
|
else
|
||||||
label="${reminder_minutes}-min reminder"
|
label=$(omarchy-text "%1-min reminder" "$reminder_minutes")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
item_json=$(jq -cn \
|
item_json=$(jq -cn \
|
||||||
@@ -109,9 +110,9 @@ show_json() {
|
|||||||
done < <(active_reminder_timers "$now")
|
done < <(active_reminder_timers "$now")
|
||||||
|
|
||||||
if ((count == 1)); then
|
if ((count == 1)); then
|
||||||
tooltip="1 reminder"
|
tooltip=$(omarchy-text "1 reminder")
|
||||||
elif ((count > 1)); then
|
elif ((count > 1)); then
|
||||||
tooltip="$count reminders"
|
tooltip=$(omarchy-text "%1 reminders" "$count")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
jq -cn --argjson count "$count" --arg tooltip "$tooltip" --argjson reminders "$reminders_json" '{count:$count,active:($count > 0),tooltip:$tooltip,reminders:$reminders}'
|
jq -cn --argjson count "$count" --arg tooltip "$tooltip" --argjson reminders "$reminders_json" '{count:$count,active:($count > 0),tooltip:$tooltip,reminders:$reminders}'
|
||||||
@@ -129,7 +130,7 @@ clear_reminders() {
|
|||||||
|
|
||||||
rm -f "$reminder_dir"/omarchy-reminder-*.message 2>/dev/null || true
|
rm -f "$reminder_dir"/omarchy-reminder-*.message 2>/dev/null || true
|
||||||
refresh_indicator
|
refresh_indicator
|
||||||
omarchy-notification-send -g "All reminders have been cleared"
|
omarchy-notification-send -g "$(omarchy-text "All reminders have been cleared")"
|
||||||
}
|
}
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
@@ -176,7 +177,7 @@ if [[ -z $minutes ]] || [[ ! $minutes =~ ^[0-9]+$ ]] || ((minutes == 0)); then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -z $message ]]; then
|
if [[ -z $message ]]; then
|
||||||
message="Your ${minutes} minutes are up"
|
message=$(omarchy-text "Your %1 minutes are up" "$minutes")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
set_at=$(date +%s)
|
set_at=$(date +%s)
|
||||||
@@ -184,18 +185,18 @@ remind_at=$(date -d "+${minutes} minutes" +%H:%M)
|
|||||||
unit="omarchy-reminder-${minutes}m-$set_at"
|
unit="omarchy-reminder-${minutes}m-$set_at"
|
||||||
reminder_dir="${XDG_RUNTIME_DIR:-/tmp}/omarchy-reminders"
|
reminder_dir="${XDG_RUNTIME_DIR:-/tmp}/omarchy-reminders"
|
||||||
message_file="$reminder_dir/$unit.message"
|
message_file="$reminder_dir/$unit.message"
|
||||||
confirmation="You'll be reminded at $remind_at"
|
confirmation=$(omarchy-text "You'll be reminded at %1" "$remind_at")
|
||||||
confirmation_title="Reminder set for ${minutes} minutes"
|
confirmation_title=$(omarchy-text "Reminder set for %1 minutes" "$minutes")
|
||||||
|
|
||||||
mkdir -p "$reminder_dir"
|
mkdir -p "$reminder_dir"
|
||||||
|
|
||||||
if [[ -n $custom_message ]]; then
|
if [[ -n $custom_message ]]; then
|
||||||
printf "%s" "$custom_message" >"$message_file"
|
printf "%s" "$custom_message" >"$message_file"
|
||||||
confirmation_title="$custom_message in ${minutes} minutes"
|
confirmation_title=$(omarchy-text "%1 in %2 minutes" "$custom_message" "$minutes")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
systemd-run --user --quiet --collect --on-active="${minutes}m" --unit="$unit" \
|
systemd-run --user --quiet --collect --on-active="${minutes}m" --unit="$unit" \
|
||||||
bash -c 'omarchy-notification-send -g "Reminder" "$1"; rm -f "$2"; omarchy-shell -q omarchy.indicators refresh >/dev/null 2>&1 || true' bash "$message" "$message_file"
|
bash -c 'omarchy-notification-send -g "$(omarchy-text "Reminder")" "$1"; rm -f "$2"; omarchy-shell -q omarchy.indicators refresh >/dev/null 2>&1 || true' bash "$message" "$message_file"
|
||||||
|
|
||||||
refresh_indicator
|
refresh_indicator
|
||||||
omarchy-notification-send -g "$confirmation_title" "$confirmation"
|
omarchy-notification-send -g "$confirmation_title" "$confirmation"
|
||||||
@@ -34,15 +34,13 @@ if gum confirm "Are you sure you want to remove all preinstalled web apps, TUI w
|
|||||||
aether \
|
aether \
|
||||||
cliamp \
|
cliamp \
|
||||||
libreoffice-fresh \
|
libreoffice-fresh \
|
||||||
xournalpp \
|
|
||||||
pinta \
|
pinta \
|
||||||
obsidian \
|
obsidian \
|
||||||
obs-studio \
|
|
||||||
kdenlive \
|
|
||||||
moonlight-qt \
|
moonlight-qt \
|
||||||
omacut \
|
omacut \
|
||||||
monologue \
|
monologue \
|
||||||
omacalc \
|
omacalc \
|
||||||
omawrite \
|
omawrite \
|
||||||
hype
|
hype \
|
||||||
|
signed
|
||||||
fi
|
fi
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# omarchy:summary=Restore Bolt's default authorization behavior
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
gum confirm "Restore Bolt's previous policy? New accessories may be authorized automatically when IOMMU protection is active." || exit 0
|
|
||||||
sudo /usr/bin/omarchy-thunderbolt-authorization-admin disable
|
|
||||||
systemctl --user disable --now omarchy-thunderbolt-authorization.service
|
|
||||||
echo "Previous Bolt policy restored. Saved Omarchy trust is retained for re-enabling."
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# omarchy:summary=Restore saved Thunderbolt firmware boot permissions
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
gum confirm "Restore the previous Thunderbolt firmware boot allowlists? Device approval will remain enabled." || exit 0
|
|
||||||
sudo /usr/bin/omarchy-thunderbolt-authorization-admin boot-disable
|
|
||||||
echo "Previous firmware boot permissions restored and verified."
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# omarchy:summary=Stop asking before new USB devices can access the system
|
|
||||||
# omarchy:args=[--boot-only] [--yes]
|
|
||||||
# omarchy:requires-sudo=true
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
assume_yes=0
|
|
||||||
boot_only=0
|
|
||||||
|
|
||||||
while (( $# > 0 )); do
|
|
||||||
case "$1" in
|
|
||||||
--yes) assume_yes=1 ;;
|
|
||||||
--boot-only) boot_only=1 ;;
|
|
||||||
-h | --help)
|
|
||||||
echo "Usage: omarchy-remove-security-usb-authorization [--boot-only] [--yes]"
|
|
||||||
echo
|
|
||||||
echo "Disables Omarchy's USB approval prompts and restores the kernel's"
|
|
||||||
echo "normal default-allow behavior."
|
|
||||||
echo "Use --boot-only to keep USBGuard enabled after the system starts."
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "omarchy-remove-security-usb-authorization: unknown option '$1'. Try --help." >&2
|
|
||||||
exit 2
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
|
|
||||||
if (( boot_only )); then
|
|
||||||
if (( ! assume_yes )); then
|
|
||||||
gum style --foreground 212 --bold "Remove USB authorization from boot"
|
|
||||||
echo
|
|
||||||
echo "USBGuard will continue blocking unknown devices after its service starts."
|
|
||||||
echo "Devices can reach kernel drivers earlier during boot."
|
|
||||||
echo
|
|
||||||
gum confirm "Disable USB authorization from kernel boot?" || exit 130
|
|
||||||
fi
|
|
||||||
|
|
||||||
sudo omarchy-usb-authorization-boot disable
|
|
||||||
echo
|
|
||||||
echo "Boot-time USB authorization is disabled and takes effect after reboot."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
state_dir="$HOME/.local/state/omarchy/usb-authorization"
|
|
||||||
unit="$HOME/.config/systemd/user/omarchy-usb-authorization.service"
|
|
||||||
|
|
||||||
if (( ! assume_yes )); then
|
|
||||||
gum style --foreground 212 --bold "Remove USB device authorization"
|
|
||||||
echo
|
|
||||||
echo "New USB devices will be allowed to bind to kernel drivers without approval."
|
|
||||||
echo
|
|
||||||
gum confirm "Disable USB device authorization?" || exit 130
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Rebuild a permissive boot image before stopping USBGuard. If rebuilding
|
|
||||||
# fails, the command stops here and leaves the complete policy enabled.
|
|
||||||
sudo omarchy-usb-authorization-boot disable
|
|
||||||
|
|
||||||
if omarchy-pkg-present usbguard; then
|
|
||||||
# Keep the watcher and its IPC access until blocking has actually stopped.
|
|
||||||
# In particular, a failed stop must not strand a running daemon without UI.
|
|
||||||
sudo systemctl disable --now usbguard.service
|
|
||||||
if systemctl is-active --quiet usbguard.service || systemctl is-enabled --quiet usbguard.service; then
|
|
||||||
echo "USBGuard is still active or enabled; approval prompts have been preserved." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
sudo omarchy-usb-authorization-restore-default
|
|
||||||
sudo usbguard remove-user "$USER"
|
|
||||||
fi
|
|
||||||
|
|
||||||
systemctl --user disable --now omarchy-usb-authorization.service 2>/dev/null || true
|
|
||||||
rm -f "$unit"
|
|
||||||
systemctl --user daemon-reload
|
|
||||||
|
|
||||||
if [[ -d $state_dir/requests ]]; then
|
|
||||||
find "$state_dir/requests" -mindepth 1 -maxdepth 1 -type f -delete
|
|
||||||
rmdir "$state_dir/requests" 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
rm -f "$state_dir/package-installed-by-omarchy" \
|
|
||||||
"$state_dir/policy-generated-by-omarchy" \
|
|
||||||
"$state_dir/service-enabled-by-omarchy"
|
|
||||||
rmdir "$state_dir" 2>/dev/null || true
|
|
||||||
|
|
||||||
echo "USB device authorization is disabled."
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# omarchy:summary=Require approval for new Thunderbolt PCIe accessories
|
|
||||||
# omarchy:args=[--quiet|status|recover]
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
source "$OMARCHY_PATH/install/helpers/thunderbolt-policy.sh"
|
|
||||||
source "$OMARCHY_PATH/install/helpers/thunderbolt-review.sh"
|
|
||||||
|
|
||||||
if [[ ${1:-} == "status" ]]; then
|
|
||||||
tb_status
|
|
||||||
elif [[ ${1:-} == "recover" && $# == 1 ]]; then
|
|
||||||
sudo /usr/bin/omarchy-thunderbolt-authorization-admin recover
|
|
||||||
elif [[ $# == 0 || ( $# == 1 && $1 == "--quiet" ) ]]; then
|
|
||||||
if [[ ${1:-} != "--quiet" ]]; then
|
|
||||||
if [[ -f $TB_PENDING ]]; then tb_status; fi
|
|
||||||
echo "First setup, including a deferred setup, trusts connected accessories. Re-enabling a completed setup preserves saved trust."
|
|
||||||
gum confirm "Require approval for new Thunderbolt accessories?" || exit 0
|
|
||||||
fi
|
|
||||||
# System units and rules are shipped by omarchy-settings.
|
|
||||||
sudo install -Dm644 "$OMARCHY_PATH/default/polkit/org.omarchy.thunderbolt.policy" /usr/share/polkit-1/actions/org.omarchy.thunderbolt.policy
|
|
||||||
sudo systemctl daemon-reload
|
|
||||||
action=enable
|
|
||||||
if [[ ${1:-} == "--quiet" ]]; then
|
|
||||||
action=migrate
|
|
||||||
fi
|
|
||||||
sudo /usr/bin/omarchy-thunderbolt-authorization-admin "$action"
|
|
||||||
systemctl --user daemon-reload
|
|
||||||
systemctl --user enable --now omarchy-thunderbolt-authorization.service
|
|
||||||
if [[ -f /etc/omarchy/thunderbolt-authorization.enabled ]]; then
|
|
||||||
for ((attempt=0; attempt<10; attempt++)); do
|
|
||||||
if tb_public_snapshot >/dev/null 2>&1; then break; fi
|
|
||||||
sleep 1
|
|
||||||
done
|
|
||||||
tb_status
|
|
||||||
elif [[ -f $TB_PENDING ]]; then
|
|
||||||
tb_status
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "Usage: omarchy-setup-security-thunderbolt-authorization [--quiet|status|recover]" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# omarchy:summary=Clear supported Thunderbolt firmware boot allowlists
|
|
||||||
# omarchy:args=[recover]
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
if [[ ${1:-} == "recover" && $# == 1 ]]; then
|
|
||||||
sudo /usr/bin/omarchy-thunderbolt-authorization-admin boot-recover
|
|
||||||
elif [[ $# == 0 ]]; then
|
|
||||||
gum style --bold "Thunderbolt at Boot"
|
|
||||||
echo "This trusts connected accessories for use after Linux starts, then clears the firmware boot allowlist."
|
|
||||||
echo "Trusted Thunderbolt keyboards, storage, and network adapters may be unavailable at disk unlock."
|
|
||||||
echo "You must be able to unlock and recover without Thunderbolt accessories."
|
|
||||||
echo "All controllers must be connected and support a boot allowlist in user or secure mode."
|
|
||||||
echo "Older snapshots or another operating system may restore firmware boot permissions."
|
|
||||||
gum confirm "Clear firmware boot access with these recovery limits?" || exit 0
|
|
||||||
sudo /usr/bin/omarchy-thunderbolt-authorization-admin boot-enable
|
|
||||||
echo "Firmware boot allowlists cleared and verified. Current connections were not disconnected."
|
|
||||||
else
|
|
||||||
echo "Usage: omarchy-setup-security-thunderbolt-boot [recover]" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
@@ -1,191 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# omarchy:summary=Ask before new USB devices can access the system
|
|
||||||
# omarchy:args=[--boot] [--yes] [--review-existing]
|
|
||||||
# omarchy:requires-sudo=true
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
assume_yes=0
|
|
||||||
from_boot=0
|
|
||||||
review_existing=0
|
|
||||||
|
|
||||||
while (( $# > 0 )); do
|
|
||||||
case "$1" in
|
|
||||||
--yes) assume_yes=1 ;;
|
|
||||||
--boot) from_boot=1 ;;
|
|
||||||
--review-existing) review_existing=1 ;;
|
|
||||||
-h | --help)
|
|
||||||
echo "Usage: omarchy-setup-security-usb-authorization [--boot] [--yes] [--review-existing]"
|
|
||||||
echo
|
|
||||||
echo "Trusts USB devices that are connected now, then blocks new devices"
|
|
||||||
echo "until you approve them from an Omarchy notification."
|
|
||||||
echo
|
|
||||||
echo "--boot also blocks USB devices from the start of kernel boot. Connected"
|
|
||||||
echo "devices are added to USBGuard's policy, but remain unavailable before"
|
|
||||||
echo "USBGuard starts, including at an encrypted-disk password prompt."
|
|
||||||
echo "Older snapshots without USBGuard keep all USB disabled after startup,"
|
|
||||||
echo "including keyboards, network adapters, and storage. Use --boot only if"
|
|
||||||
echo "disk unlock and recovery work without any USB devices."
|
|
||||||
echo
|
|
||||||
echo "--review-existing reviews connected devices with older port-bound approvals."
|
|
||||||
echo "Each portable approval requires confirmation; existing rules are preserved."
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "omarchy-setup-security-usb-authorization: unknown option '$1'. Try --help." >&2
|
|
||||||
exit 2
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
|
|
||||||
# Boot-time blocking goes into Limine's own configuration, which a Mac's boot
|
|
||||||
# package owns, so it is not offered there.
|
|
||||||
if (( from_boot )) && omarchy-hw-aarch64-apple; then
|
|
||||||
echo "USB authorization from boot is not available on Apple Silicon yet; USB device authorization after login still works." >&2
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
|
|
||||||
state_dir="$HOME/.local/state/omarchy/usb-authorization"
|
|
||||||
unit_source="$OMARCHY_PATH/default/systemd/user/omarchy-usb-authorization.service"
|
|
||||||
unit="$HOME/.config/systemd/user/omarchy-usb-authorization.service"
|
|
||||||
rules_file=/etc/usbguard/rules.conf
|
|
||||||
daemon_config=/etc/usbguard/usbguard-daemon.conf
|
|
||||||
|
|
||||||
source "$OMARCHY_PATH/install/helpers/usb-authorization.sh"
|
|
||||||
|
|
||||||
if (( review_existing )); then
|
|
||||||
# Older Omarchy rules have no per-rule ownership marker. They cannot safely
|
|
||||||
# be distinguished from intentionally restricted administrator rules.
|
|
||||||
(( ! assume_yes && ! from_boot )) || { echo "Review requires individual confirmation; do not combine it with --yes or --boot." >&2; exit 2; }
|
|
||||||
policy=$(usbguard list-rules)
|
|
||||||
declare -A reviewed=()
|
|
||||||
# Keep stdin attached to the terminal for gum (and any sudo prompt).
|
|
||||||
mapfile -t policy_lines <<<"$policy"
|
|
||||||
for line in "${policy_lines[@]}"; do
|
|
||||||
if [[ $line =~ ^[0-9]+:[[:space:]] ]]; then
|
|
||||||
rule=${line#*: }
|
|
||||||
[[ $rule == allow\ * ]] || continue
|
|
||||||
portable=$(usb_authorization_portable_rule "$rule") || continue
|
|
||||||
[[ ${portable% label *} != "$rule" ]] || continue
|
|
||||||
devices=$(usbguard list-devices "$rule")
|
|
||||||
mapfile -t candidates <<<"$devices"
|
|
||||||
for device in "${candidates[@]}"; do
|
|
||||||
[[ $device =~ ^([0-9]+):[[:space:]](allow[[:space:]].*)$ ]] || continue
|
|
||||||
id=${BASH_REMATCH[1]} current=${BASH_REMATCH[2]}
|
|
||||||
[[ ! -v reviewed[$id] ]] || continue
|
|
||||||
reviewed[$id]=1
|
|
||||||
echo
|
|
||||||
printf '%s\n' "$current" | LC_ALL=C tr -c '\11\12\15\40-\176' '?'
|
|
||||||
echo "This device has a location-bound approval. Details are supplied by the device."
|
|
||||||
if gum confirm "Trust this device on any USB port or hub?"; then
|
|
||||||
sudo /usr/bin/omarchy-usb-authorization-approve "$id" "$current"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
echo "Review complete. Disconnected devices can be approved when reconnected."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# The watcher runs in the session's environment, which may differ from a
|
|
||||||
# command invoked in a checkout. Fail before enabling blocking on mismatched
|
|
||||||
# or incomplete installations, including dangling dev-link unit symlinks.
|
|
||||||
session_environment=$(systemctl --user show-environment)
|
|
||||||
grep -Fqx -- "OMARCHY_PATH=$OMARCHY_PATH" <<<"$session_environment" || {
|
|
||||||
echo "The session and this command use different Omarchy installations. Update the session before enabling USB protection." >&2
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
for required in "$unit_source" /usr/share/omarchy/install/helpers/usb-authorization-policy.sh; do
|
|
||||||
[[ -r $required ]] || { echo "USB authorization installation is incomplete: $required" >&2; exit 1; }
|
|
||||||
done
|
|
||||||
for required in "$OMARCHY_PATH/bin/omarchy-usb-authorization-watch" \
|
|
||||||
"$OMARCHY_PATH/bin/omarchy-usb-authorization-event" \
|
|
||||||
"$OMARCHY_PATH/bin/omarchy-usb-authorization-review" \
|
|
||||||
/usr/bin/omarchy-usb-authorization-approve; do
|
|
||||||
[[ -r $required && -x $required ]] || { echo "USB authorization command is unavailable: $required" >&2; exit 1; }
|
|
||||||
done
|
|
||||||
|
|
||||||
if (( ! assume_yes )); then
|
|
||||||
if (( from_boot )); then
|
|
||||||
gum style --foreground 212 --bold "USB authorization from boot"
|
|
||||||
else
|
|
||||||
gum style --foreground 212 --bold "USB device authorization"
|
|
||||||
fi
|
|
||||||
echo
|
|
||||||
echo "Devices connected now will be trusted. Disconnect anything you do not trust."
|
|
||||||
echo "New USB devices will remain blocked until you approve them."
|
|
||||||
if (( from_boot )); then
|
|
||||||
echo
|
|
||||||
echo "Boot-time protection blocks all USB devices until USBGuard starts."
|
|
||||||
echo "A USB keyboard will not work at an encrypted-disk password prompt, even"
|
|
||||||
echo "when it is connected now."
|
|
||||||
echo
|
|
||||||
echo "Older snapshots without USBGuard keep ALL USB disabled after startup,"
|
|
||||||
echo "including keyboards, network adapters, and storage."
|
|
||||||
echo "Continue only if disk unlock and recovery work without any USB devices."
|
|
||||||
fi
|
|
||||||
echo
|
|
||||||
if (( from_boot )); then
|
|
||||||
gum confirm "Enable USB authorization from kernel boot?" || exit 130
|
|
||||||
else
|
|
||||||
gum confirm "Enable USB device authorization?" || exit 130
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
omarchy-pkg-add usbguard
|
|
||||||
|
|
||||||
usb_authorization_require_secure_settings "$daemon_config"
|
|
||||||
|
|
||||||
mkdir -p "$state_dir" "${unit%/*}"
|
|
||||||
chmod 700 "$state_dir"
|
|
||||||
|
|
||||||
if ! usb_authorization_rules_present "$rules_file"; then
|
|
||||||
policy=$(mktemp "${TMPDIR:-/tmp}/omarchy-usb-policy.XXXXXXXXXX")
|
|
||||||
trap 'rm -f "$policy"' EXIT
|
|
||||||
chmod 600 "$policy"
|
|
||||||
usb_authorization_generate_policy "$policy"
|
|
||||||
sudo install -Dm600 -o root -g root "$policy" "$rules_file"
|
|
||||||
touch "$state_dir/policy-generated-by-omarchy"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# This user can inspect USBGuard events and approve the device named by an
|
|
||||||
# event. Policy and daemon parameters remain unavailable through the IPC ACL.
|
|
||||||
sudo usbguard add-user "$USER" \
|
|
||||||
--devices=list,listen,modify \
|
|
||||||
--policy=list \
|
|
||||||
--exceptions=listen
|
|
||||||
|
|
||||||
sudo install -Dm644 "$OMARCHY_PATH/default/polkit/org.omarchy.usb.policy" /usr/share/polkit-1/actions/org.omarchy.usb.policy
|
|
||||||
|
|
||||||
# Install a real file: a link into a checkout can become dangling on a branch
|
|
||||||
# switch. Start the waiting watcher before USBGuard can block new devices.
|
|
||||||
unit_temporary=$(mktemp "${unit}.XXXXXXXXXX")
|
|
||||||
install -m644 "$unit_source" "$unit_temporary"
|
|
||||||
mv -fT "$unit_temporary" "$unit"
|
|
||||||
systemctl --user daemon-reload
|
|
||||||
systemctl --user enable omarchy-usb-authorization.service
|
|
||||||
systemctl --user restart omarchy-usb-authorization.service
|
|
||||||
systemctl --user is-active --quiet omarchy-usb-authorization.service
|
|
||||||
|
|
||||||
sudo systemctl enable usbguard.service
|
|
||||||
# add-user ACL changes are loaded only when the daemon starts, so restart an
|
|
||||||
# existing service as well as starting a fresh one.
|
|
||||||
sudo systemctl restart usbguard.service
|
|
||||||
systemctl is-active --quiet usbguard.service
|
|
||||||
systemctl --user is-active --quiet omarchy-usb-authorization.service
|
|
||||||
|
|
||||||
if (( from_boot )); then
|
|
||||||
# The fixed helper independently verifies each full live device snapshot.
|
|
||||||
usb_authorization_trust_present_devices
|
|
||||||
sudo omarchy-usb-authorization-boot enable
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo "USB device authorization is enabled."
|
|
||||||
echo "Devices connected during setup remain trusted; new devices require approval."
|
|
||||||
echo "To review older port-bound approvals, run: omarchy-setup-security-usb-authorization --review-existing"
|
|
||||||
if (( from_boot )); then
|
|
||||||
echo "Boot-time authorization is enabled and takes effect after reboot."
|
|
||||||
fi
|
|
||||||
@@ -462,7 +462,34 @@ root_dispatch() {
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# The bar indicator only probes on demand, so every grant change pushes a
|
||||||
|
# refresh. Root's expiry timer can't reach the user's shell, so a user timer
|
||||||
|
# refreshes once the deadline has passed. Both are best effort: a stale red
|
||||||
|
# indicator still revokes cleanly when clicked.
|
||||||
|
refresh_indicator() {
|
||||||
|
/usr/bin/omarchy-shell -q omarchy.indicators refresh >/dev/null 2>&1 || true
|
||||||
|
}
|
||||||
|
|
||||||
|
# A failed enable can still change the grant (a renewal that rolls back removes
|
||||||
|
# the previous policy), so refresh whatever the privileged action returned.
|
||||||
|
change_grant() {
|
||||||
|
local status=0
|
||||||
|
/usr/bin/sudo "$@" || status=$?
|
||||||
|
refresh_indicator
|
||||||
|
return "$status"
|
||||||
|
}
|
||||||
|
|
||||||
|
# A wall-clock deadline, like the sudoers rule and root's timer, so expiry
|
||||||
|
# during suspend still refreshes on resume.
|
||||||
|
schedule_expiry_refresh() {
|
||||||
|
[[ $minutes == "permanent" ]] && return 0
|
||||||
|
/usr/bin/systemd-run --user --quiet --collect --on-calendar="@$((EPOCHSECONDS + 10#$minutes * 60 + 2))" \
|
||||||
|
--timer-property=AccuracySec=1s \
|
||||||
|
-- /usr/bin/omarchy-shell -q omarchy.indicators refresh >/dev/null 2>&1 || true
|
||||||
|
}
|
||||||
|
|
||||||
show_enabled() {
|
show_enabled() {
|
||||||
|
schedule_expiry_refresh
|
||||||
if [[ $minutes == "permanent" ]]; then
|
if [[ $minutes == "permanent" ]]; then
|
||||||
echo "Passwordless sudo has been ENABLED permanently. Run this command again to disable it."
|
echo "Passwordless sudo has been ENABLED permanently. Run this command again to disable it."
|
||||||
else
|
else
|
||||||
@@ -542,12 +569,12 @@ else
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
if (( status == 0 )) && { (($# == 0)) || [[ $minutes == "--disable" ]]; }; then
|
if (( status == 0 )) && { (($# == 0)) || [[ $minutes == "--disable" ]]; }; then
|
||||||
/usr/bin/sudo -n -N -- "$INSTALLED_SELF" __disable "$uid"
|
change_grant -n -N -- "$INSTALLED_SELF" __disable "$uid"
|
||||||
echo "Passwordless sudo has been DISABLED. Sudo will require a password again."
|
echo "Passwordless sudo has been DISABLED. Sudo will require a password again."
|
||||||
elif (( status == STATUS_INACTIVE )) && [[ $minutes == "--disable" ]]; then
|
elif (( status == STATUS_INACTIVE )) && [[ $minutes == "--disable" ]]; then
|
||||||
echo "Passwordless sudo is already DISABLED."
|
echo "Passwordless sudo is already DISABLED."
|
||||||
elif (( status == 0 )) && [[ $minutes != "permanent" ]]; then
|
elif (( status == 0 )) && [[ $minutes != "permanent" ]]; then
|
||||||
/usr/bin/sudo -N -- "$INSTALLED_SELF" __enable "$uid" "$minutes"
|
change_grant -N -- "$INSTALLED_SELF" __enable "$uid" "$minutes"
|
||||||
show_enabled
|
show_enabled
|
||||||
else
|
else
|
||||||
if (( status != 0 && status != STATUS_INACTIVE )); then
|
if (( status != 0 && status != STATUS_INACTIVE )); then
|
||||||
@@ -587,7 +614,7 @@ else
|
|||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
if /usr/bin/gum confirm "Enable passwordless sudo $duration? This is a significant security risk!"; then
|
if /usr/bin/gum confirm "Enable passwordless sudo $duration? This is a significant security risk!"; then
|
||||||
/usr/bin/sudo -N -- "$INSTALLED_SELF" __enable "$uid" "$minutes"
|
change_grant -N -- "$INSTALLED_SELF" __enable "$uid" "$minutes"
|
||||||
echo ""
|
echo ""
|
||||||
show_enabled
|
show_enabled
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -462,12 +462,6 @@ scrub_factory_accounts() {
|
|||||||
sanitize_factory_baseline() {
|
sanitize_factory_baseline() {
|
||||||
local factory="$1"
|
local factory="$1"
|
||||||
btrfs property set -ts "$factory" ro false
|
btrfs property set -ts "$factory" ro false
|
||||||
if [[ -d $factory/var/lib/omarchy/thunderbolt-authorization || -f $factory/etc/omarchy/thunderbolt-authorization.enabled || -f $factory/etc/omarchy/thunderbolt-authorization.pending ]]; then
|
|
||||||
if ! /usr/bin/omarchy-thunderbolt-authorization-admin reset-root "$factory"; then
|
|
||||||
btrfs property set -ts "$factory" ro true
|
|
||||||
fail "could not reset Thunderbolt authorization in the factory baseline"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! scrub_factory_accounts "$factory"; then
|
if ! scrub_factory_accounts "$factory"; then
|
||||||
btrfs property set -ts "$factory" ro true
|
btrfs property set -ts "$factory" ro true
|
||||||
@@ -493,14 +487,6 @@ stage_full_reset() {
|
|||||||
[[ -f $unit_src/omarchy-provision-owner.service && -x $next/usr/bin/omarchy-provision-owner ]] ||
|
[[ -f $unit_src/omarchy-provision-owner.service && -x $next/usr/bin/omarchy-provision-owner ]] ||
|
||||||
fail "the factory snapshot predates provisioning support; cannot reset from it"
|
fail "the factory snapshot predates provisioning support; cannot reset from it"
|
||||||
|
|
||||||
# A normal install's factory snapshot includes the original owner's USB
|
|
||||||
# policy and enabled daemon. Keep input usable during the new owner's setup;
|
|
||||||
# provisioning enrolls their devices before enabling USBGuard again.
|
|
||||||
if [[ -f $next/usr/lib/systemd/system/usbguard.service ]]; then
|
|
||||||
systemctl --root="$next" disable usbguard.service >>"$LOG_FILE" 2>&1 ||
|
|
||||||
fail "could not disable USBGuard in the factory system (see $LOG_FILE)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
log "Scrubbing machine identity from the factory system"
|
log "Scrubbing machine identity from the factory system"
|
||||||
systemd-id128 new >"$next/etc/machine-id"
|
systemd-id128 new >"$next/etc/machine-id"
|
||||||
rm -f "$next"/etc/ssh/ssh_host_*
|
rm -f "$next"/etc/ssh/ssh_host_*
|
||||||
@@ -516,13 +502,6 @@ stage_full_reset() {
|
|||||||
scrub_factory_accounts "$next" ||
|
scrub_factory_accounts "$next" ||
|
||||||
fail "could not remove account credentials from the factory system (see $LOG_FILE)"
|
fail "could not remove account credentials from the factory system (see $LOG_FILE)"
|
||||||
|
|
||||||
# Leave the new owner's input available before interactive enrollment. Clear
|
|
||||||
# inherited accessory identities in both roots; never change the live daemon.
|
|
||||||
if [[ -d $next/var/lib/omarchy/thunderbolt-authorization || -f $next/etc/omarchy/thunderbolt-authorization.enabled || -f $next/etc/omarchy/thunderbolt-authorization.pending ]]; then
|
|
||||||
/usr/bin/omarchy-thunderbolt-authorization-admin reset-root "$next" ||
|
|
||||||
fail "could not reset Thunderbolt authorization in the staged root"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# @factory itself survives the wipe as the baseline for future resets. If it
|
# @factory itself survives the wipe as the baseline for future resets. If it
|
||||||
# came from a normal install it still holds the seller's account and
|
# came from a normal install it still holds the seller's account and
|
||||||
# /etc/shadow, which the new wheel user could mount and read — and a second
|
# /etc/shadow, which the new wheel user could mount and read — and a second
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
nohup bash -c "sleep 2 && uwsm stop" >/dev/null 2>&1 &
|
nohup bash -c "sleep 2 && uwsm stop" >/dev/null 2>&1 &
|
||||||
|
|
||||||
omarchy-osd -i logout -m "Logging out" -d 5000
|
omarchy-osd -i logout -m "$(omarchy-text "Logging out")" -d 5000
|
||||||
|
|
||||||
# Now close all windows
|
# Now close all windows
|
||||||
omarchy-hyprland-window-close-all
|
omarchy-hyprland-window-close-all
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
# scope cannot terminate it before it runs.
|
# scope cannot terminate it before it runs.
|
||||||
systemd-run --user --collect --quiet --on-active="2s" --timer-property=AccuracySec=100ms systemctl reboot --no-wall || exit 1
|
systemd-run --user --collect --quiet --on-active="2s" --timer-property=AccuracySec=100ms systemctl reboot --no-wall || exit 1
|
||||||
|
|
||||||
omarchy-osd -i reboot -m "Rebooting" -d 5000
|
omarchy-osd -i reboot -m "$(omarchy-text "Rebooting")" -d 5000
|
||||||
|
|
||||||
omarchy-state clear re*-required
|
omarchy-state clear re*-required
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
if [[ ${1:-} == "--inhibited" ]]; then
|
if [[ ${1:-} == "--inhibited" ]]; then
|
||||||
# Close windows in the background so they cannot delay power-off.
|
# Close windows in the background so they cannot delay power-off.
|
||||||
(
|
(
|
||||||
omarchy-osd -i shutdown -m "Shutting down" -d 5000
|
omarchy-osd -i shutdown -m "$(omarchy-text "Shutting down")" -d 5000
|
||||||
omarchy-state clear re*-required
|
omarchy-state clear re*-required
|
||||||
omarchy-hyprland-window-close-all
|
omarchy-hyprland-window-close-all
|
||||||
) &
|
) &
|
||||||
@@ -21,7 +21,7 @@ elif [[ ${1:-} == "--inhibit" ]]; then
|
|||||||
--who=Omarchy --why="Shutdown in progress" --mode=block \
|
--who=Omarchy --why="Shutdown in progress" --mode=block \
|
||||||
"$0" --inhibited || {
|
"$0" --inhibited || {
|
||||||
status=$?
|
status=$?
|
||||||
omarchy-notification-send -u critical "Shutdown failed" "Could not complete shutdown. Please try again."
|
omarchy-notification-send -u critical "$(omarchy-text "Shutdown failed")" "$(omarchy-text "Could not complete shutdown. Please try again.")"
|
||||||
exit "$status"
|
exit "$status"
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -98,8 +98,8 @@ report_unsecured() {
|
|||||||
"$1" >&2
|
"$1" >&2
|
||||||
|
|
||||||
omarchy-notification-send -u critical -g \
|
omarchy-notification-send -u critical -g \
|
||||||
"Screen did not lock before suspend" \
|
"$(omarchy-text "Screen did not lock before suspend")" \
|
||||||
"The session was left unlocked ($1)." >/dev/null 2>&1 || true
|
"$(omarchy-text "The session was left unlocked (%1)." "$1")" >/dev/null 2>&1 || true
|
||||||
|
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ claim_path() {
|
|||||||
announce() {
|
announce() {
|
||||||
local path="$1"
|
local path="$1"
|
||||||
local name="${path##*/}"
|
local name="${path##*/}"
|
||||||
local args=("Received $name" "Saved to ${dir/#$HOME/~}" -u critical)
|
local args=("$(omarchy-text "Received %1" "$name")" "$(omarchy-text "Saved to %1" "${dir/#$HOME/~}")" -u critical)
|
||||||
|
|
||||||
case "${name,,}" in
|
case "${name,,}" in
|
||||||
*.png | *.jpg | *.jpeg | *.gif | *.webp | *.avif | *.bmp | *.tif | *.tiff)
|
*.png | *.jpg | *.jpeg | *.gif | *.webp | *.avif | *.bmp | *.tif | *.tiff)
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ if ((${#files[@]} == 0)); then
|
|||||||
picked=$(omarchy-file-select --title "Send to $name" --multiple) || status=$?
|
picked=$(omarchy-file-select --title "Send to $name" --multiple) || status=$?
|
||||||
|
|
||||||
if ((${status:-0} > 1)); then
|
if ((${status:-0} > 1)); then
|
||||||
omarchy-notification-send -g "" -u critical "Could not send to $name" \
|
omarchy-notification-send -g "" -u critical "$(omarchy-text "Could not send to %1" "$name")" \
|
||||||
"The file chooser did not open"
|
"$(omarchy-text "The file chooser did not open")"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -43,8 +43,8 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if error=$(tailscale file cp --update-interval=0 -- "${files[@]}" "$machine:" 2>&1); then
|
if error=$(tailscale file cp --update-interval=0 -- "${files[@]}" "$machine:" 2>&1); then
|
||||||
omarchy-notification-send -g "" "Sent to $name" "$what"
|
omarchy-notification-send -g "" "$(omarchy-text "Sent to %1" "$name")" "$what"
|
||||||
else
|
else
|
||||||
omarchy-notification-send -g "" -u critical "Could not send to $name" "${error:-Taildrop transfer failed}"
|
omarchy-notification-send -g "" -u critical "$(omarchy-text "Could not send to %1" "$name")" "${error:-$(omarchy-text "Taildrop transfer failed")}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
Executable
+38
@@ -0,0 +1,38 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# omarchy:summary=Print an Omarchy message in the session's language, with %1.. filled from the arguments
|
||||||
|
# omarchy:args=<english> [args...]
|
||||||
|
# omarchy:examples=omarchy-text "Sent to %1" phone
|
||||||
|
# omarchy:hidden=true
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
if (($# < 1)); then
|
||||||
|
echo "Usage: omarchy-text <english> [args...]" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
text=$1
|
||||||
|
shift
|
||||||
|
|
||||||
|
# The shell's table is the one source: one JSON-encoded "english": "chinese" pair per line.
|
||||||
|
if [[ ${LANG:-} == zh_CN* ]]; then
|
||||||
|
translated=$(grep -E '^ ".*": ".*",?$' "$OMARCHY_PATH/shell/Commons/I18nZh.js" | sed 's/,$//' | paste -sd, |
|
||||||
|
sed 's/^/{/; s/$/}/' | jq -r --arg key "$text" '.[$key] // empty')
|
||||||
|
[[ -z $translated ]] || text=$translated
|
||||||
|
fi
|
||||||
|
|
||||||
|
# One pass over the template, so an argument that holds %2 is printed as given.
|
||||||
|
out=""
|
||||||
|
rest=$text
|
||||||
|
while [[ $rest =~ ^([^%]*)%(.)(.*)$ ]]; do
|
||||||
|
out+=${BASH_REMATCH[1]}
|
||||||
|
mark=${BASH_REMATCH[2]}
|
||||||
|
rest=${BASH_REMATCH[3]}
|
||||||
|
if [[ $mark == [1-9] ]] && ((mark <= $#)); then
|
||||||
|
out+=${!mark}
|
||||||
|
else
|
||||||
|
out+="%$mark"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
printf '%s\n' "$out$rest"
|
||||||
@@ -10,12 +10,12 @@ toggle="$HOME/.local/state/omarchy/toggles/background-intros-off"
|
|||||||
case ${1:-} in
|
case ${1:-} in
|
||||||
enable)
|
enable)
|
||||||
rm -f "$toggle"
|
rm -f "$toggle"
|
||||||
omarchy-notification-send "Background Intros" "Enabled"
|
omarchy-notification-send "$(omarchy-text "Background Intros")" "$(omarchy-text "Enabled")"
|
||||||
;;
|
;;
|
||||||
disable)
|
disable)
|
||||||
mkdir -p "$(dirname "$toggle")"
|
mkdir -p "$(dirname "$toggle")"
|
||||||
touch "$toggle"
|
touch "$toggle"
|
||||||
omarchy-notification-send "Background Intros" "Disabled"
|
omarchy-notification-send "$(omarchy-text "Background Intros")" "$(omarchy-text "Disabled")"
|
||||||
;;
|
;;
|
||||||
toggle)
|
toggle)
|
||||||
if [[ -f $toggle ]]; then
|
if [[ -f $toggle ]]; then
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ mapfile -d '' -t BACKGROUNDS < <(
|
|||||||
TOTAL=${#BACKGROUNDS[@]}
|
TOTAL=${#BACKGROUNDS[@]}
|
||||||
|
|
||||||
if (( TOTAL == 0 )); then
|
if (( TOTAL == 0 )); then
|
||||||
omarchy-notification-send "No background was found for theme" -t 2000
|
omarchy-notification-send "$(omarchy-text "No background was found for theme")" -t 2000
|
||||||
else
|
else
|
||||||
# Get current background from symlink
|
# Get current background from symlink
|
||||||
if [[ -L $CURRENT_BACKGROUND_LINK ]]; then
|
if [[ -L $CURRENT_BACKGROUND_LINK ]]; then
|
||||||
|
|||||||
@@ -20,6 +20,6 @@ fi
|
|||||||
# Create symlink to the new background media
|
# Create symlink to the new background media
|
||||||
ln -nsf "$BACKGROUND" "$CURRENT_BACKGROUND_LINK"
|
ln -nsf "$BACKGROUND" "$CURRENT_BACKGROUND_LINK"
|
||||||
|
|
||||||
# Update the live shell background immediately when it is running. The
|
# Update the live shell background when it is running. Nothing watches the
|
||||||
# background plugin also polls this symlink, but IPC avoids the visible delay.
|
# symlink, so this is how the shell learns of the new background.
|
||||||
omarchy-shell -q background set "$BACKGROUND"
|
omarchy-shell -q background set "$BACKGROUND"
|
||||||
@@ -35,5 +35,5 @@ fi
|
|||||||
|
|
||||||
# Now remove the theme directory for THEME_NAME
|
# Now remove the theme directory for THEME_NAME
|
||||||
rm -rf "$THEME_PATH"
|
rm -rf "$THEME_PATH"
|
||||||
omarchy-notification-send "Theme removed" "$THEME_NAME" || true
|
omarchy-notification-send "$(omarchy-text "Theme removed")" "$THEME_NAME" || true
|
||||||
echo "Removed $THEME_NAME"
|
echo "Removed $THEME_NAME"
|
||||||
@@ -190,7 +190,7 @@ set_theme_background() {
|
|||||||
|
|
||||||
if [[ -z $CHOSEN_THEME_BACKGROUND || ! -f $CHOSEN_THEME_BACKGROUND ]]; then
|
if [[ -z $CHOSEN_THEME_BACKGROUND || ! -f $CHOSEN_THEME_BACKGROUND ]]; then
|
||||||
if ! choose_theme_background; then
|
if ! choose_theme_background; then
|
||||||
omarchy-notification-send "No background was found for theme" -t 2000
|
omarchy-notification-send "$(omarchy-text "No background was found for theme")" -t 2000
|
||||||
shell_ipc shell applyTheme "$colors_payload" "$shell_payload" || true
|
shell_ipc shell applyTheme "$colors_payload" "$shell_payload" || true
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
@@ -207,11 +207,14 @@ set_theme_background() {
|
|||||||
shell_ipc shell applyTheme "$colors_payload" "$shell_payload" || true
|
shell_ipc shell applyTheme "$colors_payload" "$shell_payload" || true
|
||||||
ln -nsf "$new_background" "$CURRENT_BACKGROUND_LINK"
|
ln -nsf "$new_background" "$CURRENT_BACKGROUND_LINK"
|
||||||
(
|
(
|
||||||
if ! omarchy-theme-bg-boot-intro --theme-switch "$new_background" "$theme_id" "$intro_prepared"; then
|
# Played or not, the shell gets the new still: it still holds the old
|
||||||
if [[ $(readlink -f "$CURRENT_BACKGROUND_LINK") == "$(readlink -f "$new_background")" &&
|
# theme's path, which the theme swap above deleted, and loads it again
|
||||||
$(stat -Lc '%d:%i' "$CURRENT_THEME_PATH" 2>/dev/null) == "$theme_id" ]]; then
|
# when OWE hands the desktop back after the intro. While the intro plays
|
||||||
shell_ipc background setInstant "$new_background" || true
|
# the shell's background is suspended under it, so the swap is unseen.
|
||||||
fi
|
omarchy-theme-bg-boot-intro --theme-switch "$new_background" "$theme_id" "$intro_prepared" || true
|
||||||
|
if [[ $(readlink -f "$CURRENT_BACKGROUND_LINK") == "$(readlink -f "$new_background")" &&
|
||||||
|
$(stat -Lc '%d:%i' "$CURRENT_THEME_PATH" 2>/dev/null) == "$theme_id" ]]; then
|
||||||
|
shell_ipc background setInstant "$new_background" || true
|
||||||
fi
|
fi
|
||||||
shell_ipc shell finishThemeIntro "$theme_id" || true
|
shell_ipc shell finishThemeIntro "$theme_id" || true
|
||||||
wait_for_theme_intro themeIntroStatus "$theme_id" "pending"
|
wait_for_theme_intro themeIntroStatus "$theme_id" "pending"
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# omarchy:summary=Apply current Omarchy theme colors to running Foot terminals
|
# omarchy:summary=Apply current Omarchy theme colors and background alpha to running Foot terminals
|
||||||
# omarchy:hidden=true
|
# omarchy:hidden=true
|
||||||
|
|
||||||
colors_toml=$HOME/.local/state/omarchy/current/theme/colors.toml
|
colors_toml=$HOME/.local/state/omarchy/current/theme/colors.toml
|
||||||
|
foot_ini=$HOME/.local/state/omarchy/current/theme/foot.ini
|
||||||
|
|
||||||
if [[ ! -f $colors_toml ]] || ! pgrep -x foot >/dev/null; then
|
if [[ ! -f $colors_toml ]] || ! pgrep -x foot >/dev/null; then
|
||||||
exit 0
|
exit 0
|
||||||
@@ -12,6 +13,16 @@ fi
|
|||||||
foot_osc=$(omarchy-theme-osc "$colors_toml")
|
foot_osc=$(omarchy-theme-osc "$colors_toml")
|
||||||
[[ -n $foot_osc ]] || exit 0
|
[[ -n $foot_osc ]] || exit 0
|
||||||
|
|
||||||
|
# foot takes a background alpha as an urxvt-style [percent] prefix, so a theme
|
||||||
|
# going see-through or back, as with Glassy windows, reaches running terminals.
|
||||||
|
# The last alpha in the theme's foot.ini wins, as it does when foot reads it.
|
||||||
|
alpha=$(sed -n 's/^[[:space:]]*alpha[[:space:]]*=[[:space:]]*\([0-9.]*\).*/\1/p' "$foot_ini" 2>/dev/null | tail -n 1)
|
||||||
|
background=$(omarchy-theme-color --file "$colors_toml" background 2>/dev/null)
|
||||||
|
if [[ -n $background ]]; then
|
||||||
|
percent=$(awk -v alpha="${alpha:-1}" 'BEGIN { printf "%d", alpha * 100 + 0.5 }')
|
||||||
|
foot_osc+=$(printf '\033]11;[%d]%s\007' "$percent" "$background")
|
||||||
|
fi
|
||||||
|
|
||||||
for foot_pid in $(pgrep -x foot); do
|
for foot_pid in $(pgrep -x foot); do
|
||||||
for child_pid in $(pgrep -P "$foot_pid"); do
|
for child_pid in $(pgrep -P "$foot_pid"); do
|
||||||
tty=$(readlink "/proc/$child_pid/fd/1" 2>/dev/null)
|
tty=$(readlink "/proc/$child_pid/fd/1" 2>/dev/null)
|
||||||
|
|||||||
Executable
+122
@@ -0,0 +1,122 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# omarchy:summary=Give terminals, btop, and GTK apps a see-through background while windows are glassy
|
||||||
|
# omarchy:args=[theme-dir]
|
||||||
|
# omarchy:hidden=true
|
||||||
|
|
||||||
|
# A Hyprland opacity rule fades a terminal's text along with its background,
|
||||||
|
# and foot turns compositor blur down unless its own config asks for it, so the
|
||||||
|
# glass belongs in each terminal's theme file, as in the glassy Starship
|
||||||
|
# (#14726). The lines sit between markers so leaving glassy takes them out
|
||||||
|
# again, and a theme that sets its own opacity keeps it.
|
||||||
|
|
||||||
|
THEME_DIR="${1:-$HOME/.local/state/omarchy/current/theme}"
|
||||||
|
TOGGLES_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/omarchy/toggles/hypr"
|
||||||
|
GLASSY=false
|
||||||
|
[[ -f $TOGGLES_DIR/window-glassy.lua ]] && GLASSY=true
|
||||||
|
status=0
|
||||||
|
|
||||||
|
# A literal for a sed address, whose delimiter is /.
|
||||||
|
regex() {
|
||||||
|
sed 's/[][\\.*^$/]/\\&/g' <<<"$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# A block added to a file that did not end in a newline has to supply one, so
|
||||||
|
# its begin marker says so, and taking the block out takes that newline back.
|
||||||
|
# Leaving glassy then gives the file back exactly as it was. Markers come as
|
||||||
|
# an opening and a closing part, so CSS can wrap them in a comment.
|
||||||
|
remove_block() {
|
||||||
|
local file="$1" open="$2" close="$3"
|
||||||
|
local begin end
|
||||||
|
begin=$(regex "$open omarchy-glass begin")
|
||||||
|
end=$(regex "$open omarchy-glass end$close")
|
||||||
|
[[ -f $file ]] && grep -qF "$open omarchy-glass begin" "$file" || return 0
|
||||||
|
|
||||||
|
local added_newline=false
|
||||||
|
grep -qxF "$open omarchy-glass begin after a line without a newline$close" "$file" && added_newline=true
|
||||||
|
sed -i "/^$begin/,/^$end\$/d" "$file" || return 1
|
||||||
|
if [[ $added_newline == "true" && -s $file && -z $(tail -c 1 "$file") ]]; then
|
||||||
|
truncate -s -1 "$file" || return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
append_block() {
|
||||||
|
local file="$1" open="$2" close="$3" lines="$4"
|
||||||
|
if [[ -s $file && -n $(tail -c 1 "$file") ]]; then
|
||||||
|
printf '\n%s\n%s\n%s\n' "$open omarchy-glass begin after a line without a newline$close" "$lines" "$open omarchy-glass end$close" >>"$file"
|
||||||
|
else
|
||||||
|
printf '%s\n%s\n%s\n' "$open omarchy-glass begin$close" "$lines" "$open omarchy-glass end$close" >>"$file"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Each setting comes with a pattern for the theme setting it already, which
|
||||||
|
# keeps the theme's own; an empty pattern always adds it. Lines that belong in
|
||||||
|
# a section go in under its header. A file that already has the section gets
|
||||||
|
# them inside it, since TOML refuses a table declared twice; otherwise the
|
||||||
|
# header comes along with them.
|
||||||
|
glass() {
|
||||||
|
local file="$THEME_DIR/$1" section="$2"
|
||||||
|
shift 2
|
||||||
|
[[ -f $file ]] || return 0
|
||||||
|
|
||||||
|
remove_block "$file" "#" "" || return 1
|
||||||
|
[[ $GLASSY == "true" ]] || return 0
|
||||||
|
|
||||||
|
local lines=""
|
||||||
|
while (( $# >= 2 )); do
|
||||||
|
if [[ -z $1 ]] || ! grep -qE "$1" "$file"; then
|
||||||
|
lines+="${lines:+$'\n'}$2"
|
||||||
|
fi
|
||||||
|
shift 2
|
||||||
|
done
|
||||||
|
[[ -n $lines ]] || return 0
|
||||||
|
|
||||||
|
# A header may carry trailing space or a comment.
|
||||||
|
local header="^$(regex "$section")[[:space:]]*(#.*)?\$"
|
||||||
|
if [[ -n $section ]] && grep -qE "$header" "$file"; then
|
||||||
|
local block
|
||||||
|
block=$(mktemp) || return 1
|
||||||
|
printf '# omarchy-glass begin\n%s\n# omarchy-glass end\n' "$lines" >"$block"
|
||||||
|
sed -i -E "0,/$header/{/$header/r $block
|
||||||
|
}" "$file"
|
||||||
|
local result=$?
|
||||||
|
rm -f "$block"
|
||||||
|
return $result
|
||||||
|
fi
|
||||||
|
|
||||||
|
append_block "$file" "#" "" "${section:+$section$'\n'}$lines"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Alacritty's own blur works only on macOS and KDE; Hyprland blurs it anyway.
|
||||||
|
glass alacritty.toml '[window]' \
|
||||||
|
'^[[:space:]]*opacity[[:space:]]*=' 'opacity = 0.65' || status=1
|
||||||
|
glass foot.ini '[colors-dark]' \
|
||||||
|
'^[[:space:]]*alpha[[:space:]]*=' 'alpha=0.65' \
|
||||||
|
'^[[:space:]]*blur[[:space:]]*=' 'blur=yes' || status=1
|
||||||
|
glass kitty.conf '' \
|
||||||
|
'^[[:space:]]*background_opacity[[:space:]]' 'background_opacity 0.65' || status=1
|
||||||
|
# btop paints its own background over the terminal's glass. An empty main_bg
|
||||||
|
# uses the terminal background; the last theme value wins, so removing the
|
||||||
|
# block restores the theme's colour without changing btop's user config.
|
||||||
|
glass btop.theme '' \
|
||||||
|
'^[[:space:]]*theme\[main_bg\][[:space:]]*=[[:space:]]*""' 'theme[main_bg]=""' || status=1
|
||||||
|
# GTK only asks Hyprland for blur under a CSS backdrop-filter, which Ghostty
|
||||||
|
# takes as custom CSS and reloads live; its background-blur speaks only KDE's
|
||||||
|
# blur protocol.
|
||||||
|
glass ghostty.conf '' \
|
||||||
|
'^[[:space:]]*background-opacity[[:space:]]*=' 'background-opacity = 0.65' \
|
||||||
|
'' "gtk-custom-css = $OMARCHY_PATH/default/gtk/glass.css" || status=1
|
||||||
|
|
||||||
|
# Other GTK apps, such as Nautilus, read the user's gtk.css at launch, so the
|
||||||
|
# same backdrop blur is imported there. It follows the mode alone, so a theme
|
||||||
|
# switch, which names the theme it is rendering, leaves it be.
|
||||||
|
if (( $# == 0 )); then
|
||||||
|
gtk_css="${XDG_CONFIG_HOME:-$HOME/.config}/gtk-4.0/gtk.css"
|
||||||
|
remove_block "$gtk_css" "/*" " */" || status=1
|
||||||
|
if [[ $GLASSY == "true" ]]; then
|
||||||
|
{ mkdir -p "${gtk_css%/*}" &&
|
||||||
|
append_block "$gtk_css" "/*" " */" "@import url(\"file://$OMARCHY_PATH/default/gtk/glass.css\");"; } || status=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit $status
|
||||||
@@ -451,3 +451,4 @@ if [[ -f $COLORS_FILE ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
apply_shell_section_overrides
|
apply_shell_section_overrides
|
||||||
|
omarchy-theme-set-glass "$NEXT_THEME_DIR"
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
#!/bin/bash -p
|
|
||||||
|
|
||||||
# omarchy:summary=Manage system Thunderbolt authorization settings
|
|
||||||
# omarchy:hidden=true
|
|
||||||
|
|
||||||
# This root entrypoint uses installed code and rejects unsafe Bash startup.
|
|
||||||
if [[ $- != *p* ]]; then exit 126; fi
|
|
||||||
source /usr/bin/omarchy-security-functions || exit 126
|
|
||||||
omarchy_security_require_privileged_bash_startup || exit 126
|
|
||||||
omarchy_security_sanitize_bash_environment "$0" "$@"
|
|
||||||
set -euo pipefail
|
|
||||||
(( EUID == 0 )) || exit 126
|
|
||||||
export PATH=/usr/bin:/bin LC_ALL=C
|
|
||||||
unset DBUS_SYSTEM_BUS_ADDRESS DBUS_SESSION_BUS_ADDRESS
|
|
||||||
source /usr/share/omarchy/install/helpers/thunderbolt-policy.sh
|
|
||||||
source /usr/share/omarchy/install/helpers/thunderbolt-setup.sh
|
|
||||||
tb_admin "$@"
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
#!/bin/bash -p
|
|
||||||
|
|
||||||
# omarchy:summary=Approve one verified Thunderbolt connection
|
|
||||||
# omarchy:hidden=true
|
|
||||||
|
|
||||||
# pkexec permits this exact program for an active local wheel user. Suppress
|
|
||||||
# startup injection before reading input; it cannot dispatch general root work.
|
|
||||||
if [[ $- != *p* ]]; then exit 126; fi
|
|
||||||
source /usr/bin/omarchy-security-functions || exit 126
|
|
||||||
omarchy_security_require_privileged_bash_startup || exit 126
|
|
||||||
omarchy_security_sanitize_bash_environment "$0" "$@"
|
|
||||||
set -euo pipefail
|
|
||||||
(( EUID == 0 )) || exit 126
|
|
||||||
export PATH=/usr/bin:/bin LC_ALL=C
|
|
||||||
unset DBUS_SYSTEM_BUS_ADDRESS DBUS_SESSION_BUS_ADDRESS
|
|
||||||
source /usr/share/omarchy/install/helpers/thunderbolt-policy.sh
|
|
||||||
|
|
||||||
[[ $# == 2 && ( $1 == "true" || $1 == "false" ) ]] || exit 64
|
|
||||||
(( ${#2} <= 16384 )) || exit 64
|
|
||||||
jq -e 'type == "object"' <<< "$2" >/dev/null
|
|
||||||
exec 9> "$TB_LOCK"
|
|
||||||
flock -x 9
|
|
||||||
result=$(tb_approve "$2" "$1" true)
|
|
||||||
tb_json_write "$TB_RUNTIME/snapshot.json" 644 <<< "$result"
|
|
||||||
printf '%s\n' "$result"
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# omarchy:hidden=true
|
|
||||||
# omarchy:summary=Check whether Thunderbolt firmware boot access is restricted
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
source "$OMARCHY_PATH/install/helpers/thunderbolt-policy.sh"
|
|
||||||
tb_public_snapshot | jq -e .boot_protection >/dev/null
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#!/bin/bash -p
|
|
||||||
|
|
||||||
# omarchy:summary=Restore trusted Thunderbolt devices and publish their status
|
|
||||||
# omarchy:hidden=true
|
|
||||||
|
|
||||||
# Keep root startup independent of a caller's environment or checkout.
|
|
||||||
if [[ $- != *p* ]]; then exit 126; fi
|
|
||||||
source /usr/bin/omarchy-security-functions || exit 126
|
|
||||||
omarchy_security_require_privileged_bash_startup || exit 126
|
|
||||||
omarchy_security_sanitize_bash_environment "$0" "$@"
|
|
||||||
set -euo pipefail
|
|
||||||
(( EUID == 0 )) || exit 126
|
|
||||||
export PATH=/usr/bin:/bin LC_ALL=C
|
|
||||||
unset DBUS_SYSTEM_BUS_ADDRESS DBUS_SESSION_BUS_ADDRESS
|
|
||||||
source /usr/share/omarchy/install/helpers/thunderbolt-policy.sh
|
|
||||||
tb_daemon
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# omarchy:hidden=true
|
|
||||||
# omarchy:summary=Handle Thunderbolt device approval review
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
source "$OMARCHY_PATH/install/helpers/thunderbolt-policy.sh"
|
|
||||||
source "$OMARCHY_PATH/install/helpers/thunderbolt-review.sh"
|
|
||||||
[[ $# == 1 ]] || exit 64
|
|
||||||
tb_review "$1"
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# omarchy:hidden=true
|
|
||||||
# omarchy:summary=Handle Thunderbolt device approval watch
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
source "$OMARCHY_PATH/install/helpers/thunderbolt-policy.sh"
|
|
||||||
source "$OMARCHY_PATH/install/helpers/thunderbolt-review.sh"
|
|
||||||
tb_watch
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# omarchy:summary=Toggle animations, transparency and other effects that are slow without a GPU
|
# omarchy:summary=Toggle animations, blur and shadows, which are slow without a GPU
|
||||||
# omarchy:args=[toggle|on|off]
|
# omarchy:args=[toggle|on|off]
|
||||||
# omarchy:examples=omarchy toggle animations | omarchy toggle animations off | omarchy toggle animations on
|
# omarchy:examples=omarchy toggle animations | omarchy toggle animations off | omarchy toggle animations on
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ off) omarchy-hyprland-toggle no-animations on ;;
|
|||||||
esac
|
esac
|
||||||
|
|
||||||
if omarchy-hyprland-toggle-enabled no-animations; then
|
if omarchy-hyprland-toggle-enabled no-animations; then
|
||||||
omarchy-notification-send -g "Animations disabled"
|
omarchy-notification-send -g "$(omarchy-text "Animations disabled")"
|
||||||
else
|
else
|
||||||
omarchy-notification-send -g "Animations enabled"
|
omarchy-notification-send -g "$(omarchy-text "Animations enabled")"
|
||||||
fi
|
fi
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# omarchy:summary=Toggle bar visibility without killing the Omarchy shell
|
# omarchy:summary=Toggle bar visibility without killing the Omarchy shell (on hides the bar, off shows it)
|
||||||
# omarchy:args=[toggle|on|off]
|
# omarchy:args=[toggle|on|off]
|
||||||
# omarchy:examples=omarchy toggle bar | omarchy toggle bar off | omarchy toggle bar on
|
# omarchy:examples=omarchy toggle bar | omarchy toggle bar off | omarchy toggle bar on
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ omarchy-toggle crash-capture-off
|
|||||||
# starting only settles this session; the next login reads the flag itself.
|
# starting only settles this session; the next login reads the flag itself.
|
||||||
if omarchy-toggle-enabled crash-capture-off; then
|
if omarchy-toggle-enabled crash-capture-off; then
|
||||||
systemctl --user stop omarchy-crash-watch.service
|
systemctl --user stop omarchy-crash-watch.service
|
||||||
omarchy-notification-send -g "$CRASH_GLYPH" "Crash capture disabled"
|
omarchy-notification-send -g "$CRASH_GLYPH" "$(omarchy-text "Crash capture disabled")"
|
||||||
else
|
else
|
||||||
systemctl --user start omarchy-crash-watch.service
|
systemctl --user start omarchy-crash-watch.service
|
||||||
omarchy-notification-send -g "$CRASH_GLYPH" "Crash capture enabled"
|
omarchy-notification-send -g "$CRASH_GLYPH" "$(omarchy-text "Crash capture enabled")"
|
||||||
fi
|
fi
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
omarchy-toggle screensaver-off
|
omarchy-toggle screensaver-off
|
||||||
|
|
||||||
if omarchy-toggle-enabled screensaver-off; then
|
if omarchy-toggle-enabled screensaver-off; then
|
||||||
omarchy-notification-send -g "Screensaver disabled"
|
omarchy-notification-send -g "$(omarchy-text "Screensaver disabled")"
|
||||||
else
|
else
|
||||||
omarchy-notification-send -g "Screensaver enabled"
|
omarchy-notification-send -g "$(omarchy-text "Screensaver enabled")"
|
||||||
fi
|
fi
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
omarchy-toggle suspend-off
|
omarchy-toggle suspend-off
|
||||||
|
|
||||||
if omarchy-toggle-enabled suspend-off; then
|
if omarchy-toggle-enabled suspend-off; then
|
||||||
omarchy-notification-send -g "Suspend removed from system menu"
|
omarchy-notification-send -g "$(omarchy-text "Suspend removed from system menu")"
|
||||||
else
|
else
|
||||||
omarchy-notification-send -g "Suspend now available in system menu"
|
omarchy-notification-send -g "$(omarchy-text "Suspend now available in system menu")"
|
||||||
fi
|
fi
|
||||||
Loaded 100 of 377 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user