Compare commits
48
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 from the configured pacman repos, Omarchy's included; use `omarchy-pkg-aur-add` for AUR packages
|
- `omarchy-pkg-add` - install packages (handles both pacman and AUR)
|
||||||
- `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,10 +113,6 @@ 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`;
|
||||||
|
|||||||
@@ -38,17 +38,6 @@ 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,7 +2,6 @@
|
|||||||
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,7 +2,6 @@
|
|||||||
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,7 +2,6 @@
|
|||||||
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,7 +2,6 @@
|
|||||||
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,7 +2,6 @@
|
|||||||
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,7 +2,6 @@
|
|||||||
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,7 +2,6 @@
|
|||||||
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,7 +2,6 @@
|
|||||||
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,7 +2,6 @@
|
|||||||
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
|
||||||
|
|||||||
+9
-103
@@ -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] | background [opaque|glassy|none|cycle] | put <id> [placement] | move <id> [placement] | set <id> <key> <value> [--json] [placement] | get <id> <key>
|
# 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: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,19 +16,13 @@ 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; prints the current one
|
position <top|bottom|left|right> Bar position
|
||||||
when given none
|
transparent <true|false|toggle> Bar transparency
|
||||||
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
|
||||||
@@ -198,94 +192,32 @@ 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() {
|
||||||
if (( $# == 0 )); then
|
local position="${1:-}"
|
||||||
jq -r '.bar.position // "top"' "$(source_file)"
|
[[ -n $position ]] || fail "position is required"
|
||||||
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
|
||||||
[[ $(current_background) == "none" ]] && transparent="false" || transparent="true"
|
commit "$NORMALIZE | .bar.transparent = (.bar.transparent != true)"
|
||||||
fi
|
echo "Bar transparency toggled"
|
||||||
if [[ $transparent == "true" ]]; then
|
|
||||||
cmd_background none
|
|
||||||
else
|
else
|
||||||
cmd_background opaque
|
commit "$NORMALIZE | .bar.transparent = \$transparent" --argjson transparent "$transparent"
|
||||||
|
echo "Bar transparency set to $transparent"
|
||||||
fi
|
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() {
|
||||||
local catalog
|
local catalog
|
||||||
catalog=$(omarchy-plugin-catalog 2>/dev/null) || {
|
catalog=$(omarchy-plugin-catalog 2>/dev/null) || {
|
||||||
@@ -431,21 +363,6 @@ 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:-}"
|
||||||
@@ -468,14 +385,6 @@ 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 "$@"
|
||||||
;;
|
;;
|
||||||
@@ -485,9 +394,6 @@ case "$command" in
|
|||||||
set)
|
set)
|
||||||
cmd_set "$@"
|
cmd_set "$@"
|
||||||
;;
|
;;
|
||||||
get)
|
|
||||||
cmd_get "$@"
|
|
||||||
;;
|
|
||||||
-h | --help | help | "")
|
-h | --help | help | "")
|
||||||
usage
|
usage
|
||||||
;;
|
;;
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
#!/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="Corners follow the theme" ;;
|
|
||||||
sharp) LABEL="Sharp corners for all themes" ;;
|
|
||||||
rounded) LABEL="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"
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#!/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
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
#!/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="Opaque windows" ;;
|
|
||||||
transparent) LABEL="Transparent windows" ;;
|
|
||||||
glassy) LABEL="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"
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
#!/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}"
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
#!/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 "New workspaces use the $LABEL layout"
|
|
||||||
@@ -1,69 +1,21 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# omarchy:summary=Cycle the current active workspace through the dwindle, scrolling, and floating layouts
|
# omarchy:summary=Toggle the layout on the current active workspace between dwindle and scrolling
|
||||||
# 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')
|
||||||
# Named workspaces report a negative id, and Hyprland reads a leading "-" as a
|
[[ $ACTIVE_WORKSPACE =~ ^-?[0-9]+$ ]] || exit 1
|
||||||
# selector relative to the current workspace: targeting one lands on workspace 1
|
CURRENT_LAYOUT=$(hyprctl activeworkspace -j | jq -r '.tiledLayout')
|
||||||
# and reconfigures that instead.
|
LAYOUTS_DIR="$HOME/.local/state/omarchy/workspace-layouts"
|
||||||
[[ $ACTIVE_WORKSPACE =~ ^[0-9]+$ ]] || exit 1
|
LAYOUT_FILE="$LAYOUTS_DIR/$ACTIVE_WORKSPACE.lua"
|
||||||
MODES_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/omarchy/workspace-layouts"
|
|
||||||
MODE_FILE="$MODES_DIR/$ACTIVE_WORKSPACE.lua"
|
|
||||||
|
|
||||||
CURRENT_MODE=$(omarchy-hyprland-workspace-layout-current)
|
case "$CURRENT_LAYOUT" in
|
||||||
|
dwindle) NEW_LAYOUT=scrolling ;;
|
||||||
|
*) NEW_LAYOUT=dwindle ;;
|
||||||
|
esac
|
||||||
|
|
||||||
if [[ $DIRECTION == "back" ]]; then
|
mkdir -p "$LAYOUTS_DIR"
|
||||||
case "$CURRENT_MODE" in
|
printf 'hl.workspace_rule({ workspace = "%s", layout = "%s" })\n' "$ACTIVE_WORKSPACE" "$NEW_LAYOUT" >"$LAYOUT_FILE"
|
||||||
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
|
|
||||||
|
|
||||||
APPLY="o.workspace_mode({ workspace = \"$ACTIVE_WORKSPACE\", mode = \"$NEW_MODE\" })"
|
hyprctl eval "hl.workspace_rule({ workspace = \"$ACTIVE_WORKSPACE\", layout = \"$NEW_LAYOUT\" })" >/dev/null 2>&1 || \
|
||||||
|
hyprctl keyword workspace "$ACTIVE_WORKSPACE, layout:$NEW_LAYOUT"
|
||||||
# Saving a mode that did not apply would leave the file naming one layout while
|
omarchy-notification-send -g "Workspace layout set to $NEW_LAYOUT"
|
||||||
# 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 "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 "Workspace layout set to $NEW_MODE"
|
|
||||||
elif mkdir -p "$MODES_DIR" && printf '%s\n' "$APPLY" >"$MODE_FILE"; then
|
|
||||||
omarchy-notification-send -g "Workspace layout set to $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 "Workspace layout set to $NEW_MODE but could not be saved"
|
|
||||||
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,9 +92,6 @@ 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)
|
||||||
|
|||||||
@@ -15,15 +15,17 @@ 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 \
|
hype; then
|
||||||
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
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ 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"
|
||||||
"Sign PDFs and fill them in with Signed"
|
"Use Xournal++ to sign PDFs"
|
||||||
"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, trim videos with Omacut, docs with LibreOffice"
|
"Edit images with Pinta, videos with Kdenlive, 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"
|
||||||
|
|||||||
@@ -34,13 +34,15 @@ 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
|
||||||
@@ -462,34 +462,7 @@ 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
|
||||||
@@ -569,12 +542,12 @@ else
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
if (( status == 0 )) && { (($# == 0)) || [[ $minutes == "--disable" ]]; }; then
|
if (( status == 0 )) && { (($# == 0)) || [[ $minutes == "--disable" ]]; }; then
|
||||||
change_grant -n -N -- "$INSTALLED_SELF" __disable "$uid"
|
/usr/bin/sudo -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
|
||||||
change_grant -N -- "$INSTALLED_SELF" __enable "$uid" "$minutes"
|
/usr/bin/sudo -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
|
||||||
@@ -614,7 +587,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
|
||||||
change_grant -N -- "$INSTALLED_SELF" __enable "$uid" "$minutes"
|
/usr/bin/sudo -N -- "$INSTALLED_SELF" __enable "$uid" "$minutes"
|
||||||
echo ""
|
echo ""
|
||||||
show_enabled
|
show_enabled
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -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 when it is running. Nothing watches the
|
# Update the live shell background immediately when it is running. The
|
||||||
# symlink, so this is how the shell learns of the new background.
|
# background plugin also polls this symlink, but IPC avoids the visible delay.
|
||||||
omarchy-shell -q background set "$BACKGROUND"
|
omarchy-shell -q background set "$BACKGROUND"
|
||||||
@@ -207,14 +207,11 @@ 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"
|
||||||
(
|
(
|
||||||
# Played or not, the shell gets the new still: it still holds the old
|
if ! omarchy-theme-bg-boot-intro --theme-switch "$new_background" "$theme_id" "$intro_prepared"; then
|
||||||
# theme's path, which the theme swap above deleted, and loads it again
|
if [[ $(readlink -f "$CURRENT_BACKGROUND_LINK") == "$(readlink -f "$new_background")" &&
|
||||||
# when OWE hands the desktop back after the intro. While the intro plays
|
$(stat -Lc '%d:%i' "$CURRENT_THEME_PATH" 2>/dev/null) == "$theme_id" ]]; then
|
||||||
# the shell's background is suspended under it, so the swap is unseen.
|
shell_ipc background setInstant "$new_background" || true
|
||||||
omarchy-theme-bg-boot-intro --theme-switch "$new_background" "$theme_id" "$intro_prepared" || true
|
fi
|
||||||
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,10 +1,9 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# omarchy:summary=Apply current Omarchy theme colors and background alpha to running Foot terminals
|
# omarchy:summary=Apply current Omarchy theme colors 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
|
||||||
@@ -13,16 +12,6 @@ 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)
|
||||||
|
|||||||
@@ -1,122 +0,0 @@
|
|||||||
#!/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,4 +451,3 @@ if [[ -f $COLORS_FILE ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
apply_shell_section_overrides
|
apply_shell_section_overrides
|
||||||
omarchy-theme-set-glass "$NEXT_THEME_DIR"
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# omarchy:summary=Toggle animations, blur and shadows, which are slow without a GPU
|
# omarchy:summary=Toggle animations, transparency and other effects that 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 "Animations disabled"
|
||||||
else
|
else
|
||||||
omarchy-notification-send -g "Animations enabled"
|
omarchy-notification-send -g "Animations enabled"
|
||||||
fi
|
fi
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# omarchy:summary=Toggle bar visibility without killing the Omarchy shell (on hides the bar, off shows it)
|
# omarchy:summary=Toggle bar visibility without killing the Omarchy shell
|
||||||
# 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
|
||||||
|
|
||||||
|
|||||||
@@ -234,11 +234,6 @@ if [[ -n $MIME_TYPES ]]; then
|
|||||||
printf 'MimeType=%s\n' "$(desktop_string_escape "$MIME_TYPES")" >>"$DESKTOP_FILE"
|
printf 'MimeType=%s\n' "$(desktop_string_escape "$MIME_TYPES")" >>"$DESKTOP_FILE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Floating titlebars name the window after this entry rather than its page title.
|
|
||||||
if [[ -z $CUSTOM_EXEC ]]; then
|
|
||||||
printf 'StartupWMClass=%s\n' "$(desktop_string_escape "$(omarchy-webapp-window-class "$APP_URL")")" >>"$DESKTOP_FILE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
chmod +x "$DESKTOP_FILE"
|
chmod +x "$DESKTOP_FILE"
|
||||||
|
|
||||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# omarchy:summary=Print the window class Chromium gives a web app opened at a URL
|
|
||||||
# omarchy:args=<url>
|
|
||||||
# omarchy:hidden=true
|
|
||||||
|
|
||||||
# Chromium names an --app window after the URL's host and path, so a web app's
|
|
||||||
# launcher can name its window in StartupWMClass, which titlebars use to show
|
|
||||||
# the app's name rather than the page title.
|
|
||||||
|
|
||||||
url=${1:-}
|
|
||||||
if [[ -z $url ]]; then
|
|
||||||
echo "Usage: omarchy-webapp-window-class <url>" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
address=${url#*://}
|
|
||||||
address=${address%%[?#]*}
|
|
||||||
host=${address%%/*}
|
|
||||||
path=${address:${#host}}
|
|
||||||
host=${host##*@}
|
|
||||||
host=${host%%:*}
|
|
||||||
|
|
||||||
printf 'chrome-%s_%s-Default\n' "${host,,}" "${path:-/}" | sed 's|/|_|g'
|
|
||||||
@@ -9,9 +9,7 @@
|
|||||||
[Hotkey/DeactivateKeys]
|
[Hotkey/DeactivateKeys]
|
||||||
0=Muhenkan
|
0=Muhenkan
|
||||||
|
|
||||||
# A lone Shift leaves an engine like Pinyin for Latin input and returns to it.
|
|
||||||
[Hotkey/AltTriggerKeys]
|
[Hotkey/AltTriggerKeys]
|
||||||
0=Shift_L
|
|
||||||
|
|
||||||
[Hotkey/EnumerateGroupForwardKeys]
|
[Hotkey/EnumerateGroupForwardKeys]
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,9 @@
|
|||||||
name = "terminal"
|
name = "terminal"
|
||||||
|
|
||||||
[theme.custom]
|
[theme.custom]
|
||||||
# The tab bar sits on the terminal's own background, like tmux's bg=default, so
|
# The active tab is drawn as panel_bg text on an accent background, so panel_bg
|
||||||
# it turns see-through with the rest of the terminal under Glassy windows. With
|
# has to be dark for it to read - same colors as status-left's "#[fg=black,bg=blue]"
|
||||||
# no panel_bg the active tab's text falls back to surface_dim, so that is black
|
panel_bg = "black"
|
||||||
# for dark text on the accent - same colors as status-left's "#[fg=black,bg=blue]"
|
|
||||||
panel_bg = "reset"
|
|
||||||
surface_dim = "black"
|
|
||||||
|
|
||||||
[terminal]
|
[terminal]
|
||||||
# Matches -c "#{pane_current_path}" on every split, window, and session
|
# Matches -c "#{pane_current_path}" on every split, window, and session
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
-- input = {
|
-- input = {
|
||||||
-- -- Use multiple keyboard layouts and switch between them with Left Alt + Right Alt.
|
-- -- Use multiple keyboard layouts and switch between them with Left Alt + Right Alt.
|
||||||
-- kb_layout = "us,dk,eu",
|
-- kb_layout = "us,dk,eu",
|
||||||
-- kb_options = "omarchy:shift_caps_compose,grp:alts_toggle",
|
-- kb_options = "compose:caps,shift:both_capslock_cancel,grp:alts_toggle",
|
||||||
--
|
--
|
||||||
-- -- Use a specific keyboard variant if needed (e.g. intl for international keyboards).
|
-- -- Use a specific keyboard variant if needed (e.g. intl for international keyboards).
|
||||||
-- kb_variant = "intl",
|
-- kb_variant = "intl",
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
},
|
},
|
||||||
"bar": {
|
"bar": {
|
||||||
"position": "top",
|
"position": "top",
|
||||||
"background": "opaque",
|
"transparent": false,
|
||||||
"centerAnchor": "omarchy.clock",
|
"centerAnchor": "omarchy.clock",
|
||||||
"layout": {
|
"layout": {
|
||||||
"left": [
|
"left": [
|
||||||
|
|||||||
@@ -0,0 +1,268 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--The Xournal++ settings file. Do not edit this file! Most settings are available in the Settings dialog, the others are commented in this file, but handle with care!-->
|
||||||
|
<settings>
|
||||||
|
<property name="pressureSensitivity" value="true"/>
|
||||||
|
<property name="minimumPressure" value="0.05"/>
|
||||||
|
<property name="pressureMultiplier" value="1"/>
|
||||||
|
<property name="zoomGesturesEnabled" value="true"/>
|
||||||
|
<property name="selectedToolbar" value="Portrait"/>
|
||||||
|
<property name="lastSavePath" value=""/>
|
||||||
|
<property name="lastOpenPath" value=""/>
|
||||||
|
<property name="lastImagePath" value=""/>
|
||||||
|
<property name="edgePanSpeed" value="20"/>
|
||||||
|
<property name="edgePanMaxMult" value="5"/>
|
||||||
|
<property name="zoomStep" value="10"/>
|
||||||
|
<property name="zoomStepScroll" value="2"/>
|
||||||
|
<property name="displayDpi" value="72"/>
|
||||||
|
<property name="mainWndWidth" value="800"/>
|
||||||
|
<property name="mainWndHeight" value="600"/>
|
||||||
|
<property name="maximized" value="true"/>
|
||||||
|
<property name="showToolbar" value="true"/>
|
||||||
|
<property name="showSidebar" value="true"/>
|
||||||
|
<property name="sidebarWidth" value="150"/>
|
||||||
|
<property name="sidebarNumberingStyle" value="1"/>
|
||||||
|
<property name="sidebarOnRight" value="false"/>
|
||||||
|
<property name="scrollbarOnLeft" value="false"/>
|
||||||
|
<property name="menubarVisible" value="true"/>
|
||||||
|
<property name="filepathShownInTitlebar" value="false"/>
|
||||||
|
<property name="numColumns" value="1"/>
|
||||||
|
<property name="numRows" value="1"/>
|
||||||
|
<property name="viewFixedRows" value="false"/>
|
||||||
|
<property name="showPairedPages" value="false"/>
|
||||||
|
<property name="layoutVertical" value="false"/>
|
||||||
|
<property name="layoutRightToLeft" value="false"/>
|
||||||
|
<property name="layoutBottomToTop" value="false"/>
|
||||||
|
<property name="numPairsOffset" value="1"/>
|
||||||
|
<!--The icon theme, allowed values are "disabled", "onDrawOfLastPage", and "onScrollOfLastPage"-->
|
||||||
|
<property name="emptyLastPageAppend" value="disabled"/>
|
||||||
|
<property name="presentationMode" value="false"/>
|
||||||
|
<!--Which GUI elements are shown in default view mode, separated by a colon (,)-->
|
||||||
|
<property name="defaultViewModeAttributes" value="showMenubar,showToolbar,showSidebar"/>
|
||||||
|
<!--Which GUI elements are shown in fullscreen view mode, separated by a colon (,)-->
|
||||||
|
<property name="fullscreenViewModeAttributes" value="goFullscren,showToolbar,showSidebar"/>
|
||||||
|
<!--Which GUI elements are shown in presentation view mode, separated by a colon (,)-->
|
||||||
|
<property name="presentationViewModeAttributes" value="goFullscren,showToolbar"/>
|
||||||
|
<!--The cursor icon used with a stylus, allowed values are "none", "dot", "big", "arrow"-->
|
||||||
|
<property name="stylusCursorType" value="dot"/>
|
||||||
|
<!--The eraser cursor visibility used with a stylus, allowed values are "never", "always", "hover", "touch"-->
|
||||||
|
<property name="eraserVisibility" value="always"/>
|
||||||
|
<!--The icon theme, allowed values are "iconsColor", "iconsLucide"-->
|
||||||
|
<property name="iconTheme" value="iconsColor"/>
|
||||||
|
<!--Dark/light mode, allowed values are "useSystem", "forceLight", "forceDark"-->
|
||||||
|
<property name="themeVariant" value="forceDark"/>
|
||||||
|
<property name="highlightPosition" value="false"/>
|
||||||
|
<property name="cursorHighlightColor" value="2164260608"/>
|
||||||
|
<property name="cursorHighlightBorderColor" value="2147483903"/>
|
||||||
|
<property name="cursorHighlightRadius" value="30"/>
|
||||||
|
<property name="cursorHighlightBorderWidth" value="0"/>
|
||||||
|
<property name="useStockIcons" value="false"/>
|
||||||
|
<property name="disableScrollbarFadeout" value="false"/>
|
||||||
|
<property name="disableAudio" value="false"/>
|
||||||
|
<!--Hides scroolbars in the main window, allowed values: "none", "horizontal", "vertical", "both"-->
|
||||||
|
<property name="scrollbarHideType" value="none"/>
|
||||||
|
<property name="autoloadMostRecent" value="false"/>
|
||||||
|
<property name="autoloadPdfXoj" value="true"/>
|
||||||
|
<property name="defaultSaveName" value="%F-Note-%H-%M"/>
|
||||||
|
<property name="defaultPdfExportName" value="%{name}_annotated"/>
|
||||||
|
<property name="autosaveEnabled" value="true"/>
|
||||||
|
<property name="autosaveTimeout" value="3"/>
|
||||||
|
<property name="addHorizontalSpace" value="false"/>
|
||||||
|
<property name="addHorizontalSpaceAmount" value="150"/>
|
||||||
|
<property name="addVerticalSpace" value="false"/>
|
||||||
|
<property name="addVerticalSpaceAmount" value="150"/>
|
||||||
|
<property name="drawDirModsEnabled" value="false"/>
|
||||||
|
<property name="drawDirModsRadius" value="50"/>
|
||||||
|
<property name="snapRotation" value="true"/>
|
||||||
|
<property name="snapRotationTolerance" value="0.3"/>
|
||||||
|
<property name="snapGrid" value="true"/>
|
||||||
|
<property name="snapGridTolerance" value="0.5"/>
|
||||||
|
<property name="snapGridSize" value="14.17"/>
|
||||||
|
<property name="strokeRecognizerMinSize" value="40"/>
|
||||||
|
<property name="touchDrawing" value="false"/>
|
||||||
|
<property name="gtkTouchInertialScrolling" value="true"/>
|
||||||
|
<property name="pressureGuessing" value="false"/>
|
||||||
|
<property name="selectionBorderColor" value="4294901760"/>
|
||||||
|
<property name="backgroundColor" value="4292664021"/>
|
||||||
|
<property name="selectionMarkerColor" value="4285702095"/>
|
||||||
|
<property name="touchZoomStartThreshold" value="0"/>
|
||||||
|
<property name="pageRerenderThreshold" value="5"/>
|
||||||
|
<!--The count of rendered PDF pages which will be cached.-->
|
||||||
|
<property name="pdfPageCacheSize" value="10"/>
|
||||||
|
<property name="preloadPagesBefore" value="3"/>
|
||||||
|
<property name="preloadPagesAfter" value="5"/>
|
||||||
|
<property name="eagerPageCleanup" value="true"/>
|
||||||
|
<!--Config for new pages-->
|
||||||
|
<property name="pageTemplate" value="xoj/template copyLastPageSettings=true size=595.275591x841.889764 backgroundType=lined backgroundColor=#ffffff "/>
|
||||||
|
<property name="sizeUnit" value=""/>
|
||||||
|
<property name="audioFolder" value=""/>
|
||||||
|
<property name="audioInputDevice" value="-1"/>
|
||||||
|
<property name="audioOutputDevice" value="-1"/>
|
||||||
|
<property name="audioSampleRate" value="44100"/>
|
||||||
|
<property name="audioGain" value="1"/>
|
||||||
|
<property name="defaultSeekTime" value="5"/>
|
||||||
|
<property name="pluginEnabled" value=""/>
|
||||||
|
<property name="pluginDisabled" value=""/>
|
||||||
|
<property name="strokeFilterIgnoreTime" value="150"/>
|
||||||
|
<property name="strokeFilterIgnoreLength" value="1"/>
|
||||||
|
<property name="strokeFilterSuccessiveTime" value="500"/>
|
||||||
|
<property name="strokeFilterEnabled" value="false"/>
|
||||||
|
<property name="doActionOnStrokeFiltered" value="false"/>
|
||||||
|
<property name="trySelectOnStrokeFiltered" value="false"/>
|
||||||
|
<property name="snapRecognizedShapesEnabled" value="false"/>
|
||||||
|
<property name="restoreLineWidthEnabled" value="false"/>
|
||||||
|
<property name="numIgnoredStylusEvents" value="0"/>
|
||||||
|
<property name="inputSystemTPCButton" value="false"/>
|
||||||
|
<property name="inputSystemDrawOutsideWindow" value="true"/>
|
||||||
|
<property name="preferredLocale" value=""/>
|
||||||
|
<property name="stabilizerAveragingMethod" value="0"/>
|
||||||
|
<property name="stabilizerPreprocessor" value="0"/>
|
||||||
|
<property name="stabilizerBuffersize" value="20"/>
|
||||||
|
<property name="stabilizerSigma" value="0.5"/>
|
||||||
|
<property name="stabilizerDeadzoneRadius" value="1.3"/>
|
||||||
|
<property name="stabilizerDrag" value="0.4"/>
|
||||||
|
<property name="stabilizerMass" value="5"/>
|
||||||
|
<property name="stabilizerCuspDetection" value="true"/>
|
||||||
|
<property name="stabilizerFinalizeStroke" value="true"/>
|
||||||
|
<property name="latexSettings.autoCheckDependencies" value="true"/>
|
||||||
|
<property name="latexSettings.defaultText" value="x^2"/>
|
||||||
|
<property name="latexSettings.globalTemplatePath" value="/usr/share/xournalpp/resources/default_template.tex"/>
|
||||||
|
<property name="latexSettings.genCmd" value="pdflatex -halt-on-error -interaction=nonstopmode '{}'"/>
|
||||||
|
<property name="latexSettings.sourceViewThemeId" value=""/>
|
||||||
|
<property name="latexSettings.editorFont" value="Monospace 12"/>
|
||||||
|
<property name="latexSettings.useCustomEditorFont" value="false"/>
|
||||||
|
<property name="latexSettings.editorWordWrap" value="true"/>
|
||||||
|
<property name="latexSettings.sourceViewAutoIndent" value="true"/>
|
||||||
|
<property name="latexSettings.sourceViewSyntaxHighlight" value="true"/>
|
||||||
|
<property name="latexSettings.sourceViewShowLineNumbers" value="false"/>
|
||||||
|
<property name="font" font="Sans" size="12"/>
|
||||||
|
<data name="buttonConfig">
|
||||||
|
<data name="default">
|
||||||
|
<attribute name="color" type="hex" value="ff000000"/>
|
||||||
|
<attribute name="drawingType" type="string" value="default"/>
|
||||||
|
<attribute name="size" type="string" value="thin"/>
|
||||||
|
<attribute name="tool" type="string" value="pen"/>
|
||||||
|
</data>
|
||||||
|
<data name="eraser">
|
||||||
|
<attribute name="eraserMode" type="string" value="none"/>
|
||||||
|
<attribute name="size" type="string" value="none"/>
|
||||||
|
<attribute name="tool" type="string" value="eraser"/>
|
||||||
|
</data>
|
||||||
|
<data name="middle">
|
||||||
|
<attribute name="tool" type="string" value="hand"/>
|
||||||
|
</data>
|
||||||
|
<data name="right">
|
||||||
|
<attribute name="tool" type="string" value="none"/>
|
||||||
|
</data>
|
||||||
|
<data name="stylus">
|
||||||
|
<attribute name="tool" type="string" value="none"/>
|
||||||
|
</data>
|
||||||
|
<data name="stylus2">
|
||||||
|
<attribute name="tool" type="string" value="none"/>
|
||||||
|
</data>
|
||||||
|
<data name="touch">
|
||||||
|
<attribute name="device" type="string" value=""/>
|
||||||
|
<attribute name="disableDrawing" type="boolean" value="false"/>
|
||||||
|
<attribute name="tool" type="string" value="none"/>
|
||||||
|
</data>
|
||||||
|
</data>
|
||||||
|
<data name="deviceClasses">
|
||||||
|
<data name="Wayland Finger Scrolling">
|
||||||
|
<attribute name="deviceClass" type="int" value="1"/>
|
||||||
|
<attribute name="deviceSource" type="int" value="6"/>
|
||||||
|
</data>
|
||||||
|
<data name="Wayland Pointer">
|
||||||
|
<attribute name="deviceClass" type="int" value="1"/>
|
||||||
|
<attribute name="deviceSource" type="int" value="0"/>
|
||||||
|
</data>
|
||||||
|
</data>
|
||||||
|
<data name="tools">
|
||||||
|
<attribute name="current" type="string" value="text"/>
|
||||||
|
<data name="drawArrow">
|
||||||
|
<attribute name="drawingType" type="string" value="default"/>
|
||||||
|
</data>
|
||||||
|
<data name="drawCoordinateSystem">
|
||||||
|
<attribute name="drawingType" type="string" value="default"/>
|
||||||
|
</data>
|
||||||
|
<data name="drawDoubleArrow">
|
||||||
|
<attribute name="drawingType" type="string" value="default"/>
|
||||||
|
</data>
|
||||||
|
<data name="drawEllipse">
|
||||||
|
<attribute name="drawingType" type="string" value="default"/>
|
||||||
|
</data>
|
||||||
|
<data name="drawRect">
|
||||||
|
<attribute name="drawingType" type="string" value="default"/>
|
||||||
|
</data>
|
||||||
|
<data name="drawSpline">
|
||||||
|
<attribute name="drawingType" type="string" value="default"/>
|
||||||
|
</data>
|
||||||
|
<data name="eraser">
|
||||||
|
<attribute name="drawingType" type="string" value="default"/>
|
||||||
|
<attribute name="size" type="string" value="MEDIUM"/>
|
||||||
|
<attribute name="type" type="string" value="default"/>
|
||||||
|
</data>
|
||||||
|
<data name="hand">
|
||||||
|
<attribute name="drawingType" type="string" value="default"/>
|
||||||
|
</data>
|
||||||
|
<data name="highlighter">
|
||||||
|
<attribute name="color" type="hex" value="ffffff00"/>
|
||||||
|
<attribute name="drawingType" type="string" value="default"/>
|
||||||
|
<attribute name="fill" type="int" value="0"/>
|
||||||
|
<attribute name="fillAlpha" type="int" value="128"/>
|
||||||
|
<attribute name="size" type="string" value="MEDIUM"/>
|
||||||
|
</data>
|
||||||
|
<data name="image">
|
||||||
|
<attribute name="drawingType" type="string" value="default"/>
|
||||||
|
</data>
|
||||||
|
<data name="pen">
|
||||||
|
<attribute name="color" type="hex" value="ff3333cc"/>
|
||||||
|
<attribute name="drawingType" type="string" value="default"/>
|
||||||
|
<attribute name="fill" type="int" value="0"/>
|
||||||
|
<attribute name="fillAlpha" type="int" value="128"/>
|
||||||
|
<attribute name="size" type="string" value="MEDIUM"/>
|
||||||
|
<attribute name="style" type="string" value="plain"/>
|
||||||
|
</data>
|
||||||
|
<data name="playObject">
|
||||||
|
<attribute name="drawingType" type="string" value="default"/>
|
||||||
|
</data>
|
||||||
|
<data name="selectMultiLayerRect">
|
||||||
|
<attribute name="drawingType" type="string" value="default"/>
|
||||||
|
</data>
|
||||||
|
<data name="selectMultiLayerRegion">
|
||||||
|
<attribute name="drawingType" type="string" value="default"/>
|
||||||
|
</data>
|
||||||
|
<data name="selectObject">
|
||||||
|
<attribute name="drawingType" type="string" value="default"/>
|
||||||
|
</data>
|
||||||
|
<data name="selectPdfTextLinear">
|
||||||
|
<attribute name="color" type="hex" value="ff000000"/>
|
||||||
|
<attribute name="drawingType" type="string" value="default"/>
|
||||||
|
</data>
|
||||||
|
<data name="selectPdfTextRect">
|
||||||
|
<attribute name="color" type="hex" value="ff000000"/>
|
||||||
|
<attribute name="drawingType" type="string" value="default"/>
|
||||||
|
</data>
|
||||||
|
<data name="selectRect">
|
||||||
|
<attribute name="drawingType" type="string" value="default"/>
|
||||||
|
</data>
|
||||||
|
<data name="selectRegion">
|
||||||
|
<attribute name="drawingType" type="string" value="default"/>
|
||||||
|
</data>
|
||||||
|
<data name="showFloatingToolbox">
|
||||||
|
<attribute name="drawingType" type="string" value="default"/>
|
||||||
|
</data>
|
||||||
|
<data name="text">
|
||||||
|
<attribute name="color" type="hex" value="ff000000"/>
|
||||||
|
<attribute name="drawingType" type="string" value="default"/>
|
||||||
|
</data>
|
||||||
|
<data name="verticalSpace">
|
||||||
|
<attribute name="drawingType" type="string" value="default"/>
|
||||||
|
</data>
|
||||||
|
</data>
|
||||||
|
<data name="touch">
|
||||||
|
<attribute name="cmdDisable" type="string" value=""/>
|
||||||
|
<attribute name="cmdEnable" type="string" value=""/>
|
||||||
|
<attribute name="disableTouch" type="boolean" value="false"/>
|
||||||
|
<attribute name="method" type="string" value="auto"/>
|
||||||
|
<attribute name="timeout" type="int" value="1000"/>
|
||||||
|
</data>
|
||||||
|
</settings>
|
||||||
@@ -2,12 +2,12 @@
|
|||||||
name: omarchy
|
name: omarchy
|
||||||
description: >
|
description: >
|
||||||
REQUIRED for end-user customization of Linux desktop, window manager, or system config.
|
REQUIRED for end-user customization of Linux desktop, window manager, or system config.
|
||||||
Use when editing ANY file in ~/.config/, ~/.config/hypr/, ~/.config/omarchy/,
|
Use when editing ~/.config/hypr/, ~/.config/omarchy/,
|
||||||
~/.config/alacritty/, ~/.config/foot/, ~/.config/kitty/, or ~/.config/ghostty/.
|
~/.config/alacritty/, ~/.config/foot/, ~/.config/kitty/, or ~/.config/ghostty/.
|
||||||
Triggers: Hyprland, window rules, window behavior, animations, keybindings, monitors, gaps, borders,
|
Triggers: Hyprland, window rules, animations, keybindings, monitors, gaps, borders,
|
||||||
blur, opacity, omarchy-shell, bar, widgets, terminal config, themes, fonts, background,
|
blur, opacity, omarchy-shell, bar, terminal config, themes, background,
|
||||||
night light, idle, lock screen, screenshots, screen recording, reminders, layer rules, workspace
|
night light, idle, lock screen, screenshots, reminders, layer rules, workspace
|
||||||
settings, display config, appearance changes, and user-facing omarchy commands. Excludes Omarchy
|
settings, display config, and user-facing omarchy commands. Excludes Omarchy
|
||||||
source development through `omarchy dev link` workflows.
|
source development through `omarchy dev link` workflows.
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -18,6 +18,24 @@ Manage [Omarchy](https://omarchy.org/) Linux systems - a beautiful, fun, agentic
|
|||||||
This skill is for end-user customization on installed systems.
|
This skill is for end-user customization on installed systems.
|
||||||
It is not for contributing to Omarchy source code.
|
It is not for contributing to Omarchy source code.
|
||||||
|
|
||||||
|
## When This Skill MUST Be Used
|
||||||
|
|
||||||
|
**ALWAYS invoke this skill for end-user requests involving ANY of these:**
|
||||||
|
|
||||||
|
- Editing ANY file in `~/.config/hypr/` (window rules, animations, keybindings, monitors, etc.)
|
||||||
|
- Editing `~/.config/omarchy/shell.json` (status bar layout, widgets)
|
||||||
|
- Editing terminal configs (alacritty, foot, kitty, ghostty)
|
||||||
|
- Editing ANY file in `~/.config/omarchy/`
|
||||||
|
- Window behavior, animations, opacity, blur, gaps, borders
|
||||||
|
- Layer rules, workspace settings, display/monitor configuration
|
||||||
|
- Themes, backgrounds, fonts, appearance changes
|
||||||
|
- User-facing `omarchy` commands (`omarchy theme ...`, `omarchy refresh ...`, `omarchy restart ...`, etc.)
|
||||||
|
- Screenshots, screen recording, reminders, night light, idle behavior, lock screen
|
||||||
|
|
||||||
|
**If you're about to edit a config file in ~/.config/ on this system, STOP and use this skill first.**
|
||||||
|
|
||||||
|
**Do NOT use this skill for Omarchy development tasks** (editing the Omarchy source tree, creating migrations, or running `omarchy dev ...` workflows).
|
||||||
|
|
||||||
## Topic Guides
|
## Topic Guides
|
||||||
|
|
||||||
Deeper instructions for common areas live next to this file. Read the
|
Deeper instructions for common areas live next to this file. Read the
|
||||||
|
|||||||
@@ -17,25 +17,6 @@ changes. `idle.screensaver` and `idle.lock` are seconds since user idle began.
|
|||||||
|
|
||||||
**Commands:** `omarchy restart shell`, `omarchy refresh shell`
|
**Commands:** `omarchy restart shell`, `omarchy refresh shell`
|
||||||
|
|
||||||
## Plugin UI Safety
|
|
||||||
|
|
||||||
Plugins run inside Omarchy's long-lived, unsandboxed shell. Treat text from network responses, files, IPC, settings, environment variables, and command output as untrusted.
|
|
||||||
|
|
||||||
- QML `Text` defaults to `Text.AutoText`. Do not bind untrusted data to an AutoText sink: markup-shaped input such as `<img src="https://example.invalid/tracker">` can be interpreted as rich text and load a resource.
|
|
||||||
- For display text owned by the plugin, set `textFormat: Text.PlainText`. Prefer a local `PlainText` component when the plugin has multiple text elements.
|
|
||||||
|
|
||||||
```qml
|
|
||||||
Text {
|
|
||||||
textFormat: Text.PlainText
|
|
||||||
text: modelData.name
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- When passing dynamic text to an Omarchy-owned component whose internal `Text` format the plugin cannot set, neutralize markup in the plugin first with a helper of its own, and add a regression test; Omarchy ships no such helper. Never edit the packaged component to add a plain-text option: that belongs in a pull request to Omarchy.
|
|
||||||
- Bound and validate downloaded data before displaying or saving it: limit response and collection sizes, string lengths, identifiers, and timestamps.
|
|
||||||
- Keep network access explicit. Use fixed HTTPS sources, timeouts, response-size limits, and validation. For periodic background refreshes, disclose the behavior and let users enable or disable it. Never execute downloaded content or interpolate untrusted values into shell commands.
|
|
||||||
- Add regression coverage for markup-shaped input and every shared tooltip or notification sink that receives dynamic text.
|
|
||||||
|
|
||||||
## Bar Layout
|
## Bar Layout
|
||||||
|
|
||||||
Use the `omarchy bar` group to move and manage widgets:
|
Use the `omarchy bar` group to move and manage widgets:
|
||||||
|
|||||||
@@ -1,298 +1,6 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
|
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
|
||||||
<fontconfig>
|
<fontconfig>
|
||||||
<!-- CJK: fold the language tag onto one tag per Noto CJK variant -->
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="eq">
|
|
||||||
<string>zh</string>
|
|
||||||
</test>
|
|
||||||
<edit name="lang" mode="assign">
|
|
||||||
<string>zh-cn</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="eq">
|
|
||||||
<string>zh-hant</string>
|
|
||||||
</test>
|
|
||||||
<edit name="lang" mode="assign">
|
|
||||||
<string>zh-tw</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="contains">
|
|
||||||
<string>zh-hant-hk</string>
|
|
||||||
</test>
|
|
||||||
<edit name="lang" mode="assign">
|
|
||||||
<string>zh-hk</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="contains">
|
|
||||||
<string>zh-hant-mo</string>
|
|
||||||
</test>
|
|
||||||
<edit name="lang" mode="assign">
|
|
||||||
<string>zh-hk</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="contains">
|
|
||||||
<string>zh-hant</string>
|
|
||||||
</test>
|
|
||||||
<edit name="lang" mode="assign">
|
|
||||||
<string>zh-tw</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="contains">
|
|
||||||
<string>zh-hans</string>
|
|
||||||
</test>
|
|
||||||
<edit name="lang" mode="assign">
|
|
||||||
<string>zh-cn</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="contains">
|
|
||||||
<string>zh-sg</string>
|
|
||||||
</test>
|
|
||||||
<edit name="lang" mode="assign">
|
|
||||||
<string>zh-cn</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="contains">
|
|
||||||
<string>zh-mo</string>
|
|
||||||
</test>
|
|
||||||
<edit name="lang" mode="assign">
|
|
||||||
<string>zh-hk</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="eq">
|
|
||||||
<string>yue</string>
|
|
||||||
</test>
|
|
||||||
<edit name="lang" mode="assign">
|
|
||||||
<string>zh-hk</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="contains">
|
|
||||||
<string>yue-hans</string>
|
|
||||||
</test>
|
|
||||||
<edit name="lang" mode="assign">
|
|
||||||
<string>zh-cn</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="contains">
|
|
||||||
<string>yue-cn</string>
|
|
||||||
</test>
|
|
||||||
<edit name="lang" mode="assign">
|
|
||||||
<string>zh-cn</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="contains">
|
|
||||||
<string>yue</string>
|
|
||||||
</test>
|
|
||||||
<edit name="lang" mode="assign">
|
|
||||||
<string>zh-hk</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<!-- Then append that variant after the generic family it falls back from -->
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="contains">
|
|
||||||
<string>zh-cn</string>
|
|
||||||
</test>
|
|
||||||
<test name="family">
|
|
||||||
<string>sans-serif</string>
|
|
||||||
</test>
|
|
||||||
<edit name="family" mode="append" binding="strong">
|
|
||||||
<string>Noto Sans CJK SC</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="contains">
|
|
||||||
<string>zh-cn</string>
|
|
||||||
</test>
|
|
||||||
<test name="family">
|
|
||||||
<string>serif</string>
|
|
||||||
</test>
|
|
||||||
<edit name="family" mode="append" binding="strong">
|
|
||||||
<string>Noto Serif CJK SC</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="contains">
|
|
||||||
<string>zh-cn</string>
|
|
||||||
</test>
|
|
||||||
<test name="family">
|
|
||||||
<string>monospace</string>
|
|
||||||
</test>
|
|
||||||
<edit name="family" mode="append" binding="strong">
|
|
||||||
<string>Noto Sans Mono CJK SC</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="contains">
|
|
||||||
<string>zh-hk</string>
|
|
||||||
</test>
|
|
||||||
<test name="family">
|
|
||||||
<string>sans-serif</string>
|
|
||||||
</test>
|
|
||||||
<edit name="family" mode="append" binding="strong">
|
|
||||||
<string>Noto Sans CJK HK</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="contains">
|
|
||||||
<string>zh-hk</string>
|
|
||||||
</test>
|
|
||||||
<test name="family">
|
|
||||||
<string>serif</string>
|
|
||||||
</test>
|
|
||||||
<edit name="family" mode="append" binding="strong">
|
|
||||||
<string>Noto Serif CJK HK</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="contains">
|
|
||||||
<string>zh-hk</string>
|
|
||||||
</test>
|
|
||||||
<test name="family">
|
|
||||||
<string>monospace</string>
|
|
||||||
</test>
|
|
||||||
<edit name="family" mode="append" binding="strong">
|
|
||||||
<string>Noto Sans Mono CJK HK</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="contains">
|
|
||||||
<string>zh-tw</string>
|
|
||||||
</test>
|
|
||||||
<test name="family">
|
|
||||||
<string>sans-serif</string>
|
|
||||||
</test>
|
|
||||||
<edit name="family" mode="append" binding="strong">
|
|
||||||
<string>Noto Sans CJK TC</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="contains">
|
|
||||||
<string>zh-tw</string>
|
|
||||||
</test>
|
|
||||||
<test name="family">
|
|
||||||
<string>serif</string>
|
|
||||||
</test>
|
|
||||||
<edit name="family" mode="append" binding="strong">
|
|
||||||
<string>Noto Serif CJK TC</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="contains">
|
|
||||||
<string>zh-tw</string>
|
|
||||||
</test>
|
|
||||||
<test name="family">
|
|
||||||
<string>monospace</string>
|
|
||||||
</test>
|
|
||||||
<edit name="family" mode="append" binding="strong">
|
|
||||||
<string>Noto Sans Mono CJK TC</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="contains">
|
|
||||||
<langset><string>ja</string></langset>
|
|
||||||
</test>
|
|
||||||
<test name="family">
|
|
||||||
<string>sans-serif</string>
|
|
||||||
</test>
|
|
||||||
<edit name="family" mode="append" binding="strong">
|
|
||||||
<string>Noto Sans CJK JP</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="contains">
|
|
||||||
<langset><string>ja</string></langset>
|
|
||||||
</test>
|
|
||||||
<test name="family">
|
|
||||||
<string>serif</string>
|
|
||||||
</test>
|
|
||||||
<edit name="family" mode="append" binding="strong">
|
|
||||||
<string>Noto Serif CJK JP</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="contains">
|
|
||||||
<langset><string>ja</string></langset>
|
|
||||||
</test>
|
|
||||||
<test name="family">
|
|
||||||
<string>monospace</string>
|
|
||||||
</test>
|
|
||||||
<edit name="family" mode="append" binding="strong">
|
|
||||||
<string>Noto Sans Mono CJK JP</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="contains">
|
|
||||||
<langset><string>ko</string></langset>
|
|
||||||
</test>
|
|
||||||
<test name="family">
|
|
||||||
<string>sans-serif</string>
|
|
||||||
</test>
|
|
||||||
<edit name="family" mode="append" binding="strong">
|
|
||||||
<string>Noto Sans CJK KR</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="contains">
|
|
||||||
<langset><string>ko</string></langset>
|
|
||||||
</test>
|
|
||||||
<test name="family">
|
|
||||||
<string>serif</string>
|
|
||||||
</test>
|
|
||||||
<edit name="family" mode="append" binding="strong">
|
|
||||||
<string>Noto Serif CJK KR</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<match target="pattern">
|
|
||||||
<test name="lang" qual="first" compare="contains">
|
|
||||||
<langset><string>ko</string></langset>
|
|
||||||
</test>
|
|
||||||
<test name="family">
|
|
||||||
<string>monospace</string>
|
|
||||||
</test>
|
|
||||||
<edit name="family" mode="append" binding="strong">
|
|
||||||
<string>Noto Sans Mono CJK KR</string>
|
|
||||||
</edit>
|
|
||||||
</match>
|
|
||||||
|
|
||||||
<match target="pattern">
|
<match target="pattern">
|
||||||
<test name="family" qual="any">
|
<test name="family" qual="any">
|
||||||
<string>sans-serif</string>
|
<string>sans-serif</string>
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
/* GTK asks the compositor to blur behind a see-through window only where a
|
|
||||||
backdrop-filter blur covers it, so Glassy windows load this into GTK apps,
|
|
||||||
such as Ghostty and Nautilus. The compositor's own blur settings decide
|
|
||||||
how it looks. */
|
|
||||||
window {
|
|
||||||
backdrop-filter: blur(20px);
|
|
||||||
}
|
|
||||||
@@ -11,8 +11,7 @@ o.bind("SUPER + ALT + F", "Full width", hl.dsp.window.fullscreen({ mode = "maxim
|
|||||||
o.bind("SUPER + O", "Pop window out (float & pin)", "omarchy-hyprland-window-pop")
|
o.bind("SUPER + O", "Pop window out (float & pin)", "omarchy-hyprland-window-pop")
|
||||||
o.bind("SUPER + ALT + Home", "Save window width", "omarchy-hyprland-window-width save")
|
o.bind("SUPER + ALT + Home", "Save window width", "omarchy-hyprland-window-width save")
|
||||||
o.bind("SUPER + Home", "Restore window width", "omarchy-hyprland-window-width restore")
|
o.bind("SUPER + Home", "Restore window width", "omarchy-hyprland-window-width restore")
|
||||||
o.bind("SUPER + L", "Cycle workspace layout", "omarchy-hyprland-workspace-layout-toggle")
|
o.bind("SUPER + L", "Toggle workspace layout", "omarchy-hyprland-workspace-layout-toggle")
|
||||||
o.bind("SUPER + ALT + L", "Cycle workspace layout back", "omarchy-hyprland-workspace-layout-toggle back")
|
|
||||||
|
|
||||||
o.bind("SUPER + LEFT", "Focus on left window", hl.dsp.focus({ direction = "l" }))
|
o.bind("SUPER + LEFT", "Focus on left window", hl.dsp.focus({ direction = "l" }))
|
||||||
o.bind("SUPER + RIGHT", "Focus on right window", hl.dsp.focus({ direction = "r" }))
|
o.bind("SUPER + RIGHT", "Focus on right window", hl.dsp.focus({ direction = "r" }))
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
-- Frosted glass from the glassy Starship (#14726), shared by Glassy windows and
|
|
||||||
-- the Glassy bar: whatever is behind a see-through surface is blurred.
|
|
||||||
return function()
|
|
||||||
hl.config({
|
|
||||||
decoration = {
|
|
||||||
blur = {
|
|
||||||
enabled = true,
|
|
||||||
size = 4,
|
|
||||||
passes = 2,
|
|
||||||
new_optimizations = true,
|
|
||||||
xray = false,
|
|
||||||
contrast = 1.0,
|
|
||||||
brightness = 0.75,
|
|
||||||
noise = 0.01,
|
|
||||||
vibrancy = 0.35,
|
|
||||||
vibrancy_darkness = 0.35,
|
|
||||||
popups = true,
|
|
||||||
special = true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
end
|
|
||||||
@@ -281,8 +281,7 @@ function o.window(match, rules)
|
|||||||
hl.window_rule(rules)
|
hl.window_rule(rules)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Opt a window in to Omarchy's standard active/inactive transparency. The tag
|
-- Opt a window in to Omarchy's standard active/inactive transparency.
|
||||||
-- lets Appearance > Window Transparency turn these windows opaque or glassy.
|
|
||||||
function o.transparent_window(match, opacity)
|
function o.transparent_window(match, opacity)
|
||||||
o.window(match, { opacity = opacity or "0.985 0.96", tag = "+transparent-window" })
|
o.window(match, { opacity = opacity or "0.985 0.96" })
|
||||||
end
|
end
|
||||||
@@ -11,9 +11,11 @@ local vconsole = keyboard.selected()
|
|||||||
|
|
||||||
local kb_layout = vconsole.XKBLAYOUT or "us"
|
local kb_layout = vconsole.XKBLAYOUT or "us"
|
||||||
local kb_variant = vconsole.XKBVARIANT or ""
|
local kb_variant = vconsole.XKBVARIANT or ""
|
||||||
-- Caps Lock is Caps Lock, and Shift + Caps Lock is the compose key. Stock XKB
|
-- CapsLock is the compose key, so Caps Lock itself has to live somewhere else.
|
||||||
-- has no such option, so Omarchy defines it in /etc/xkb.
|
-- Both Shifts together is the usual home for it, but it's easy to hit by
|
||||||
local kb_options = "omarchy:shift_caps_compose"
|
-- accident while typing. The _cancel variant sets Caps Lock the same way and
|
||||||
|
-- releases it on the next lone Shift, so a misfire clears itself.
|
||||||
|
local kb_options = "compose:caps,shift:both_capslock_cancel"
|
||||||
|
|
||||||
-- Hyprland resolves keybindings against the first entry in kb_layout, not the
|
-- Hyprland resolves keybindings against the first entry in kb_layout, not the
|
||||||
-- layout that's currently active, so Omarchy's Latin-keysym bindings (SUPER + W
|
-- layout that's currently active, so Omarchy's Latin-keysym bindings (SUPER + W
|
||||||
|
|||||||
@@ -14,9 +14,7 @@ hl.config({
|
|||||||
inactive_border = inactive_border_color,
|
inactive_border = inactive_border_color,
|
||||||
},
|
},
|
||||||
|
|
||||||
resize_on_border = true,
|
resize_on_border = false,
|
||||||
extend_border_grab_area = 8,
|
|
||||||
hover_icon_on_border = true,
|
|
||||||
allow_tearing = false,
|
allow_tearing = false,
|
||||||
layout = "dwindle",
|
layout = "dwindle",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,38 +1,9 @@
|
|||||||
local function cursor_theme(value)
|
|
||||||
if value and value ~= "" and value ~= "omarchy-startup" then return value end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function normal_theme(interrupted)
|
|
||||||
local current = os.getenv("XCURSOR_THEME")
|
|
||||||
local theme = cursor_theme(current)
|
|
||||||
-- Only a lost preference needs recovering; an unset theme still means the default alias.
|
|
||||||
if theme or not (interrupted or current == "omarchy-startup") then return theme or "default" end
|
|
||||||
theme = cursor_theme(os.getenv("OMARCHY_STARTUP_CURSOR_THEME"))
|
|
||||||
if theme then return theme end
|
|
||||||
local pipe = io.popen("gsettings get org.gnome.desktop.interface cursor-theme 2>/dev/null", "r")
|
|
||||||
if pipe then
|
|
||||||
theme = cursor_theme((pipe:read("*a") or ""):match("^'(.-)'%s*$"))
|
|
||||||
pipe:close()
|
|
||||||
end
|
|
||||||
return theme or "default"
|
|
||||||
end
|
|
||||||
|
|
||||||
local function normal_path()
|
|
||||||
local kept = {}
|
|
||||||
for entry in (os.getenv("XCURSOR_PATH") or "~/.local/share/icons:~/.icons:/usr/share/icons:/usr/share/pixmaps"):gmatch("[^:]+") do
|
|
||||||
if not entry:match("/default/hypr/cursors$") then table.insert(kept, entry) end
|
|
||||||
end
|
|
||||||
return table.concat(kept, ":")
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Hyprland polls cursor.invisible, so its first frames need a blank cursor too.
|
-- Hyprland polls cursor.invisible, so its first frames need a blank cursor too.
|
||||||
function omarchy_startup_cursor_restore(loaded)
|
function omarchy_startup_cursor_restore(loaded)
|
||||||
if not omarchy_startup_cursor_pending then return end
|
if not omarchy_startup_cursor_pending then return end
|
||||||
local cursor = omarchy_startup_cursor
|
local cursor = omarchy_startup_cursor
|
||||||
if loaded then
|
if loaded then
|
||||||
omarchy_startup_cursor_pending = false
|
omarchy_startup_cursor_pending = false
|
||||||
hl.env("OMARCHY_STARTUP_CURSOR_SESSION", "")
|
|
||||||
hl.env("OMARCHY_STARTUP_CURSOR_THEME", "")
|
|
||||||
hl.config({ cursor = cursor.config })
|
hl.config({ cursor = cursor.config })
|
||||||
if cursor.config.enable_hyprcursor and cursor.hyprcursor then
|
if cursor.config.enable_hyprcursor and cursor.hyprcursor then
|
||||||
hl.exec_cmd("hyprctl setcursor " .. o.shell_quote(cursor.hyprcursor) .. " " .. cursor.size)
|
hl.exec_cmd("hyprctl setcursor " .. o.shell_quote(cursor.hyprcursor) .. " " .. cursor.size)
|
||||||
@@ -40,25 +11,15 @@ function omarchy_startup_cursor_restore(loaded)
|
|||||||
elseif not cursor.restoring then
|
elseif not cursor.restoring then
|
||||||
-- Reload the normal Xcursor fallback before enabling Hyprcursor or GSettings.
|
-- Reload the normal Xcursor fallback before enabling Hyprcursor or GSettings.
|
||||||
cursor.restoring = true
|
cursor.restoring = true
|
||||||
hl.env("XCURSOR_PATH", cursor.path)
|
|
||||||
hl.env("XCURSOR_THEME", cursor.xcursor)
|
|
||||||
hl.exec_cmd("dbus-update-activation-environment --systemd XCURSOR_PATH XCURSOR_THEME")
|
|
||||||
local complete = "if omarchy_startup_cursor and omarchy_startup_cursor.xcursor == " .. string.format("%q", cursor.xcursor)
|
|
||||||
.. " and omarchy_startup_cursor.size == " .. cursor.size .. " then omarchy_startup_cursor_restore(true) end"
|
|
||||||
hl.exec_cmd("hyprctl setcursor " .. o.shell_quote(cursor.xcursor) .. " " .. cursor.size
|
hl.exec_cmd("hyprctl setcursor " .. o.shell_quote(cursor.xcursor) .. " " .. cursor.size
|
||||||
.. " && hyprctl eval " .. o.shell_quote(complete))
|
.. " && hyprctl eval 'omarchy_startup_cursor_restore(true)'")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
hl.on("config.reloaded", function()
|
hl.on("config.reloaded", function()
|
||||||
local recover = false
|
|
||||||
if omarchy_startup_cursor_pending == nil then
|
if omarchy_startup_cursor_pending == nil then
|
||||||
-- An ordinary reload must not hide the pointer, but an interrupted reveal survives.
|
-- Config updates in an existing compositor must not hide its pointer.
|
||||||
local cold = #hl.get_monitors() == 0
|
omarchy_startup_cursor_pending = #hl.get_monitors() == 0
|
||||||
local session = os.getenv("HYPRLAND_INSTANCE_SIGNATURE")
|
|
||||||
local interrupted = session and os.getenv("OMARCHY_STARTUP_CURSOR_SESSION") == session
|
|
||||||
recover = not cold and not interrupted and os.getenv("XCURSOR_THEME") == "omarchy-startup"
|
|
||||||
omarchy_startup_cursor_pending = cold or interrupted or recover
|
|
||||||
if omarchy_startup_cursor_pending then
|
if omarchy_startup_cursor_pending then
|
||||||
local hyprcursor = hl.get_config("cursor.enable_hyprcursor")
|
local hyprcursor = hl.get_config("cursor.enable_hyprcursor")
|
||||||
omarchy_startup_cursor = {
|
omarchy_startup_cursor = {
|
||||||
@@ -69,31 +30,17 @@ hl.on("config.reloaded", function()
|
|||||||
},
|
},
|
||||||
hyprcursor = os.getenv("HYPRCURSOR_THEME"),
|
hyprcursor = os.getenv("HYPRCURSOR_THEME"),
|
||||||
size = tonumber((hyprcursor and os.getenv("HYPRCURSOR_SIZE")) or os.getenv("XCURSOR_SIZE")) or 24,
|
size = tonumber((hyprcursor and os.getenv("HYPRCURSOR_SIZE")) or os.getenv("XCURSOR_SIZE")) or 24,
|
||||||
path = normal_path(),
|
path = os.getenv("XCURSOR_PATH") or "~/.local/share/icons:~/.icons:/usr/share/icons:/usr/share/pixmaps",
|
||||||
xcursor = normal_theme(interrupted),
|
xcursor = os.getenv("XCURSOR_THEME") or "default",
|
||||||
}
|
}
|
||||||
if omarchy_startup_cursor.size <= 0 then omarchy_startup_cursor.size = 24 end
|
if omarchy_startup_cursor.size <= 0 then omarchy_startup_cursor.size = 24 end
|
||||||
-- Compositor environment survives Lua reloads; a session id prevents stale inheritance.
|
hl.env("XCURSOR_PATH", os.getenv("OMARCHY_PATH") .. "/default/hypr/cursors:" .. omarchy_startup_cursor.path)
|
||||||
hl.env("OMARCHY_STARTUP_CURSOR_THEME", omarchy_startup_cursor.xcursor)
|
hl.env("XCURSOR_THEME", "omarchy-startup")
|
||||||
hl.env("OMARCHY_STARTUP_CURSOR_SESSION", os.getenv("HYPRLAND_INSTANCE_SIGNATURE"))
|
|
||||||
if cold then
|
|
||||||
hl.env("XCURSOR_PATH", os.getenv("OMARCHY_PATH") .. "/default/hypr/cursors:" .. omarchy_startup_cursor.path)
|
|
||||||
hl.env("XCURSOR_THEME", "omarchy-startup")
|
|
||||||
else
|
|
||||||
hl.env("XCURSOR_PATH", omarchy_startup_cursor.path)
|
|
||||||
hl.env("XCURSOR_THEME", omarchy_startup_cursor.xcursor)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if omarchy_startup_cursor_pending then
|
if omarchy_startup_cursor_pending then
|
||||||
-- Keep the temporary cursor private to the compositor, including GSettings.
|
-- Keep the temporary cursor private to the compositor, including GSettings.
|
||||||
hl.config({ cursor = { invisible = true, enable_hyprcursor = false, sync_gsettings_theme = false } })
|
hl.config({ cursor = { invisible = true, enable_hyprcursor = false, sync_gsettings_theme = false } })
|
||||||
hl.timer(function()
|
hl.timer(function() omarchy_startup_cursor_restore() end, { timeout = 15000, type = "oneshot" })
|
||||||
if omarchy_startup_cursor_pending then
|
|
||||||
omarchy_startup_cursor.restoring = false
|
|
||||||
omarchy_startup_cursor_restore()
|
|
||||||
end
|
|
||||||
end, { timeout = 15000, type = "oneshot" })
|
|
||||||
if recover then omarchy_startup_cursor_restore() end
|
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
-- The Glassy bar: the shell draws the bar see-through, and Hyprland blurs what
|
|
||||||
-- is behind it.
|
|
||||||
require("default.hypr.glass")()
|
|
||||||
|
|
||||||
hl.layer_rule({
|
|
||||||
match = { namespace = "^omarchy-bar$" },
|
|
||||||
blur = true,
|
|
||||||
ignore_alpha = 0.3,
|
|
||||||
})
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
-- Round window corners, whatever the theme sets. Matches Solitude's corners.
|
|
||||||
hl.config({
|
|
||||||
decoration = {
|
|
||||||
rounding = 6,
|
|
||||||
rounding_power = 3,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
-- Square window corners, whatever the theme sets.
|
|
||||||
hl.config({
|
|
||||||
decoration = {
|
|
||||||
rounding = 0,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
-- Draw nothing just for show, for machines that render on the CPU, like a VM:
|
-- Draw nothing just for show, for machines that render on the CPU, like a VM:
|
||||||
-- no animations, blur or shadows. How see-through windows are is left to
|
-- no animations, blur or shadows, and opaque windows, so nothing behind a
|
||||||
-- Appearance > Window Transparency.
|
-- window has to be blended into it.
|
||||||
hl.config({
|
hl.config({
|
||||||
animations = {
|
animations = {
|
||||||
enabled = false,
|
enabled = false,
|
||||||
@@ -16,3 +16,5 @@ hl.config({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
o.window(".*", { opacity = "1 1" })
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
-- Frosted glass from the glassy Starship (#14726): whatever is behind a
|
|
||||||
-- see-through window or shell surface is blurred. Terminals get the see-through
|
|
||||||
-- background itself from omarchy-theme-set-glass, which keeps their text crisp.
|
|
||||||
require("default.hypr.glass")()
|
|
||||||
|
|
||||||
-- GTK apps fade as a whole, since GTK draws their backgrounds solid, and get
|
|
||||||
-- their blur from the backdrop-filter Glassy adds to the user's gtk.css.
|
|
||||||
o.window("org\\.gnome\\.Nautilus", { opacity = "0.75 0.75" })
|
|
||||||
|
|
||||||
hl.layer_rule({
|
|
||||||
match = { namespace = "^(omarchy-bar|omarchy-menu|omarchy-notifications|omarchy-osd|omarchy-polkit|omarchy-reminders|omarchy-clipboard|omarchy-emojis|omarchy-image-selector|omarchy-keyboard-panel|omarchy-network-qr)$" },
|
|
||||||
blur = true,
|
|
||||||
ignore_alpha = 0.3,
|
|
||||||
})
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
-- Opaque windows, even those Omarchy makes transparent by default.
|
|
||||||
o.window({ tag = "transparent-window" }, { opacity = "1 1" })
|
|
||||||
@@ -3,19 +3,6 @@
|
|||||||
local paths = require("default.hypr.paths")
|
local paths = require("default.hypr.paths")
|
||||||
local require_all = require("default.hypr.require_all")
|
local require_all = require("default.hypr.require_all")
|
||||||
|
|
||||||
-- The saved files call o.workspace_mode, so it has to exist before they load.
|
|
||||||
local workspace_modes = require("default.hypr.workspace-modes")
|
|
||||||
|
|
||||||
local layouts_dir = paths.state_home .. "/omarchy/workspace-layouts"
|
local layouts_dir = paths.state_home .. "/omarchy/workspace-layouts"
|
||||||
|
|
||||||
-- The directory is found through XDG_STATE_HOME but the files are loaded by
|
|
||||||
-- module name, and bootstrap only puts ~/.local/state on the search path. A
|
|
||||||
-- state home anywhere else would list the saved layouts and then fail to require
|
|
||||||
-- them, or load same-named ones from under the home directory instead.
|
|
||||||
package.path = paths.state_home .. "/?.lua;" .. package.path
|
|
||||||
|
|
||||||
require_all.files(layouts_dir, "omarchy.workspace-layouts", { reload = true })
|
require_all.files(layouts_dir, "omarchy.workspace-layouts", { reload = true })
|
||||||
|
|
||||||
-- With every saved mode known, bring the open windows in line and set up what a
|
|
||||||
-- floating workspace needs.
|
|
||||||
workspace_modes.apply()
|
|
||||||
@@ -1,385 +0,0 @@
|
|||||||
-- Workspace modes for omarchy-hyprland-workspace-layout-toggle.
|
|
||||||
--
|
|
||||||
-- Hyprland has dwindle and scrolling as tiled layouts, but nothing that floats a
|
|
||||||
-- whole workspace: it reports a workspace's `tiledLayout` and takes an unknown
|
|
||||||
-- layout name in silence, falling back to dwindle. So floating is applied to the
|
|
||||||
-- windows themselves.
|
|
||||||
--
|
|
||||||
-- Ending the mode has to tile the windows the mode floated and only those, so
|
|
||||||
-- each one is tagged. The tag lives on the window: it dies with it, follows it
|
|
||||||
-- between workspaces, and survives the config reload that a monitor being
|
|
||||||
-- plugged in performs, none of which a table on this side would do.
|
|
||||||
--
|
|
||||||
-- Every window on a floating workspace also carries a second tag, whether the
|
|
||||||
-- mode floated it or it was floating already. Titlebars, shadows, and full
|
|
||||||
-- opacity follow that tag, so a dialog on a floating workspace can be dragged by
|
|
||||||
-- its titlebar too, and a window carried out to a tiled one loses it.
|
|
||||||
|
|
||||||
require("default.hypr.helpers")
|
|
||||||
local paths = require("default.hypr.paths")
|
|
||||||
|
|
||||||
local FLOATED_TAG = "omarchy-mode-floated"
|
|
||||||
local WORKSPACE_TAG = "omarchy-floating-workspace"
|
|
||||||
local TITLEBARS = "/usr/lib/omarchy-hyprland-titlebars/titlebars.so"
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
local modes = {}
|
|
||||||
local default_mode = nil
|
|
||||||
local watching = false
|
|
||||||
local cascade = 0
|
|
||||||
|
|
||||||
local function set_floating(window, floating)
|
|
||||||
hl.dispatch(hl.dsp.window.float({ action = floating and "on" or "off", window = window }))
|
|
||||||
end
|
|
||||||
|
|
||||||
local function set_claimed(window, claimed)
|
|
||||||
hl.dispatch(hl.dsp.window.tag({ tag = (claimed and "+" or "-") .. FLOATED_TAG, window = window }))
|
|
||||||
end
|
|
||||||
|
|
||||||
local function set_on_floating_workspace(window, on)
|
|
||||||
hl.dispatch(hl.dsp.window.tag({ tag = (on and "+" or "-") .. WORKSPACE_TAG, window = window }))
|
|
||||||
end
|
|
||||||
|
|
||||||
local function claimed()
|
|
||||||
local addresses = {}
|
|
||||||
|
|
||||||
for _, window in ipairs(hl.get_windows({ tag = FLOATED_TAG })) do
|
|
||||||
addresses[window.address] = true
|
|
||||||
end
|
|
||||||
|
|
||||||
return addresses
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Special workspaces, such as the scratchpad, and named ones, which report a
|
|
||||||
-- negative id, keep whatever state a window arrived with.
|
|
||||||
local function floating_workspace(id)
|
|
||||||
id = tonumber(id)
|
|
||||||
|
|
||||||
if not id or id < 1 then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
local mode = modes[tostring(id)]
|
|
||||||
if mode then
|
|
||||||
return mode == "floating"
|
|
||||||
end
|
|
||||||
|
|
||||||
return default_mode == "floating"
|
|
||||||
end
|
|
||||||
|
|
||||||
local function anything_floats()
|
|
||||||
if default_mode == "floating" then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, mode in pairs(modes) do
|
|
||||||
if mode == "floating" then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- A window the mode floats opens at a comfortable size in the middle of its
|
|
||||||
-- monitor, each one stepped from the last so a workspace floated all at once does
|
|
||||||
-- not leave every window stacked exactly on the one beneath it.
|
|
||||||
local function place(window)
|
|
||||||
local monitor = window.monitor
|
|
||||||
if not monitor or not monitor.width then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local width = math.floor(monitor.width / monitor.scale)
|
|
||||||
local height = math.floor(monitor.height / monitor.scale)
|
|
||||||
|
|
||||||
if (monitor.transform or 0) % 2 == 1 then
|
|
||||||
width, height = height, width
|
|
||||||
end
|
|
||||||
|
|
||||||
local reserved = monitor.reserved or {}
|
|
||||||
width = width - (reserved.left or 0) - (reserved.right or 0)
|
|
||||||
height = height - (reserved.top or 0) - (reserved.bottom or 0)
|
|
||||||
|
|
||||||
hl.dispatch(hl.dsp.window.resize({
|
|
||||||
x = math.min(1100, math.floor(width * 0.64)),
|
|
||||||
y = math.min(760, math.floor(height * 0.68)),
|
|
||||||
relative = false,
|
|
||||||
window = window,
|
|
||||||
}))
|
|
||||||
hl.dispatch(hl.dsp.window.center({ window = window }))
|
|
||||||
|
|
||||||
cascade = (cascade + 1) % 5
|
|
||||||
hl.dispatch(hl.dsp.window.move({ x = cascade * 24 - 48, y = cascade * 24 - 48, relative = true, window = window }))
|
|
||||||
end
|
|
||||||
|
|
||||||
-- A window already floating on its own account -- an app with a float rule of
|
|
||||||
-- its own, a dialog, one popped out with SUPER + T -- is left unclaimed, so it
|
|
||||||
-- is still floating when the mode ends. A fullscreen window is left as it is.
|
|
||||||
--
|
|
||||||
-- Every tiled window is claimed before any of them is floated: floating one
|
|
||||||
-- member of a group floats the rest, and a single pass would then find those
|
|
||||||
-- already floating and leave them to be stranded when the mode ends.
|
|
||||||
local function float_for_mode(windows)
|
|
||||||
local claiming = {}
|
|
||||||
|
|
||||||
for _, window in ipairs(windows) do
|
|
||||||
set_on_floating_workspace(window, true)
|
|
||||||
|
|
||||||
if not window.floating and (window.fullscreen or 0) == 0 then
|
|
||||||
set_claimed(window, true)
|
|
||||||
table.insert(claiming, window)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, window in ipairs(claiming) do
|
|
||||||
set_floating(window, true)
|
|
||||||
place(window)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- A pinned window is one the user asked to keep above everything, and tiling it
|
|
||||||
-- would unpin it as well, so the mode leaves it be.
|
|
||||||
local function tile_for_mode(window, mine)
|
|
||||||
set_on_floating_workspace(window, false)
|
|
||||||
|
|
||||||
if not mine[window.address] or window.pinned then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
set_claimed(window, false)
|
|
||||||
set_floating(window, false)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- The workspace is passed in when a window is still on its way to it.
|
|
||||||
local function arrange(windows, workspace)
|
|
||||||
local floating = {}
|
|
||||||
local mine = claimed()
|
|
||||||
|
|
||||||
for _, window in ipairs(windows) do
|
|
||||||
local id = tonumber(workspace and workspace.id or (window.workspace and window.workspace.id))
|
|
||||||
|
|
||||||
if id and id >= 1 then
|
|
||||||
if floating_workspace(id) then
|
|
||||||
table.insert(floating, window)
|
|
||||||
else
|
|
||||||
tile_for_mode(window, mine)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
float_for_mode(floating)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Overlapping windows are placed with the pointer, so a floating workspace
|
|
||||||
-- focuses on click rather than on hover. Every other workspace keeps the user's
|
|
||||||
-- own setting.
|
|
||||||
local input = {}
|
|
||||||
|
|
||||||
local function update_input()
|
|
||||||
local workspace = hl.get_active_workspace()
|
|
||||||
local active = workspace ~= nil and floating_workspace(workspace.id)
|
|
||||||
|
|
||||||
if active == input.floating then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
input.floating = active
|
|
||||||
|
|
||||||
hl.config({ input = { follow_mouse = active and 0 or input.follow_mouse } })
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Windows arrive by opening and by being carried in, and a window rule only ever
|
|
||||||
-- fires for the first. One carried back out gives up the floating the mode gave
|
|
||||||
-- it rather than staying floating somewhere that tiles.
|
|
||||||
local function watch()
|
|
||||||
if watching then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
watching = true
|
|
||||||
|
|
||||||
input.follow_mouse = hl.get_config("input.follow_mouse")
|
|
||||||
|
|
||||||
hl.on("window.open", function(window)
|
|
||||||
arrange({ window })
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- A move is still being committed when this fires, and changing the window's
|
|
||||||
-- floating state underneath it loses the move. Let it land first.
|
|
||||||
hl.on("window.move_to_workspace", function(window, workspace)
|
|
||||||
hl.timer(function()
|
|
||||||
arrange({ window }, workspace)
|
|
||||||
end, { type = "oneshot", timeout = 1 })
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- A fullscreen window is left as it is, so it is arranged once it comes back
|
|
||||||
-- out: a tiled one leaving fullscreen on a floating workspace floats then.
|
|
||||||
hl.on("window.fullscreen", function(window)
|
|
||||||
hl.timer(function()
|
|
||||||
arrange({ window })
|
|
||||||
end, { type = "oneshot", timeout = 1 })
|
|
||||||
end)
|
|
||||||
|
|
||||||
hl.on("workspace.active", update_input)
|
|
||||||
hl.on("monitor.focused", update_input)
|
|
||||||
end
|
|
||||||
|
|
||||||
function o.workspace_mode(spec)
|
|
||||||
watch()
|
|
||||||
|
|
||||||
-- The default for every workspace that has no mode of its own, chosen under
|
|
||||||
-- Trigger > Appearance > Workspace Layout. A tiled default is Hyprland's own
|
|
||||||
-- layout; a floating one is arranged once the saved modes have all loaded.
|
|
||||||
if spec.default then
|
|
||||||
default_mode = spec.default
|
|
||||||
if spec.default ~= "floating" then
|
|
||||||
hl.config({ general = { layout = spec.default } })
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local workspace = tostring(spec.workspace)
|
|
||||||
|
|
||||||
-- Floating keeps whatever tiled layout the workspace had, so nothing has to be
|
|
||||||
-- chosen for it on the way back out.
|
|
||||||
if spec.mode ~= "floating" then
|
|
||||||
hl.workspace_rule({ workspace = workspace, layout = spec.mode })
|
|
||||||
end
|
|
||||||
|
|
||||||
modes[workspace] = spec.mode
|
|
||||||
|
|
||||||
arrange(hl.get_workspace_windows(workspace))
|
|
||||||
update_input()
|
|
||||||
end
|
|
||||||
|
|
||||||
local function theme_colors()
|
|
||||||
local colors = {}
|
|
||||||
-- omarchy-theme-set writes the current theme under ~/.local/state whatever
|
|
||||||
-- XDG_STATE_HOME says, and Hyprland loads the theme's own config from there.
|
|
||||||
local file = io.open(paths.home .. "/.local/state/omarchy/current/theme/colors.toml", "r")
|
|
||||||
|
|
||||||
if file then
|
|
||||||
for line in file:lines() do
|
|
||||||
local key, value = line:match('^%s*([%w_]+)%s*=%s*"#(%x%x%x%x%x%x)"')
|
|
||||||
if key then
|
|
||||||
colors[key] = "rgb(" .. value .. ")"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
file:close()
|
|
||||||
end
|
|
||||||
|
|
||||||
local background = colors.background or "rgb(1a1b26)"
|
|
||||||
-- A titlebar in the window's own background color runs into the window, so it
|
|
||||||
-- takes the theme's raised surface. Themes that make that the background too
|
|
||||||
-- fall back to their selection color.
|
|
||||||
local titlebar = colors.lighter_background
|
|
||||||
if not titlebar or titlebar == background then
|
|
||||||
titlebar = colors.selection or background
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
|
||||||
background = background,
|
|
||||||
foreground = colors.foreground or "rgb(c0caf5)",
|
|
||||||
titlebar = titlebar,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Titlebars come from omarchy-hyprland-titlebars, loaded only while something
|
|
||||||
-- floats. Hyprland keeps a plugin loaded after the config stops asking for it,
|
|
||||||
-- but resets its options, and the plugin draws nothing until enabled here.
|
|
||||||
-- The plugin reloads the config once it is in, which is the pass that finds its
|
|
||||||
-- options here.
|
|
||||||
local function titlebars()
|
|
||||||
local file = io.open(TITLEBARS, "r")
|
|
||||||
if not file then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
file:close()
|
|
||||||
|
|
||||||
hl.plugin.load(TITLEBARS)
|
|
||||||
|
|
||||||
if not hl.plugin.hyprbars then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local colors = theme_colors()
|
|
||||||
local window = [[window = "address:%WINDOW%"]]
|
|
||||||
|
|
||||||
hl.config({
|
|
||||||
plugin = {
|
|
||||||
hyprbars = {
|
|
||||||
enabled = true,
|
|
||||||
workspace_tag = WORKSPACE_TAG,
|
|
||||||
bar_height = 30,
|
|
||||||
bar_color = colors.titlebar,
|
|
||||||
col = { text = colors.foreground },
|
|
||||||
bar_text_font = "monospace",
|
|
||||||
bar_text_size = 12,
|
|
||||||
bar_text_weight = "normal",
|
|
||||||
bar_text_align = "left",
|
|
||||||
bar_buttons_alignment = "right",
|
|
||||||
bar_part_of_window = true,
|
|
||||||
bar_precedence_over_border = true,
|
|
||||||
bar_padding = 10,
|
|
||||||
bar_button_padding = 8,
|
|
||||||
button_rounding = 0,
|
|
||||||
icon_on_hover = false,
|
|
||||||
inactive_button_color = colors.titlebar,
|
|
||||||
on_double_click = "hyprctl dispatch 'hl.dsp.window.fullscreen({ mode = \"maximized\", action = \"toggle\", " .. window .. " })'",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
for _, button in ipairs({
|
|
||||||
{ icon = "×", action = "hyprctl dispatch 'hl.dsp.window.close({ " .. window .. " })'" },
|
|
||||||
{ icon = "□", action = "hyprctl dispatch 'hl.dsp.window.fullscreen({ mode = \"maximized\", action = \"toggle\", " .. window .. " })'" },
|
|
||||||
}) do
|
|
||||||
hl.plugin.hyprbars.add_button({
|
|
||||||
bg_color = colors.titlebar,
|
|
||||||
fg_color = colors.foreground,
|
|
||||||
size = 20,
|
|
||||||
icon = button.icon,
|
|
||||||
action = button.action,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Runs once every saved mode has loaded. A reload is a fresh start on this side
|
|
||||||
-- but not for the windows, so each one is brought in line with the modes as they
|
|
||||||
-- now stand: moving the default away from floating has to give back what it
|
|
||||||
-- floated, even though nothing names those workspaces any more.
|
|
||||||
function M.apply()
|
|
||||||
-- A default that no longer floats can leave no saved mode at all to start the
|
|
||||||
-- watchers, while the windows it floated still carry its tags.
|
|
||||||
local leftovers = #hl.get_windows({ tag = FLOATED_TAG }) > 0 or #hl.get_windows({ tag = WORKSPACE_TAG }) > 0
|
|
||||||
|
|
||||||
if anything_floats() or leftovers then
|
|
||||||
watch()
|
|
||||||
end
|
|
||||||
|
|
||||||
if watching then
|
|
||||||
arrange(hl.get_windows())
|
|
||||||
update_input()
|
|
||||||
end
|
|
||||||
|
|
||||||
if not anything_floats() then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Overlapping windows need depth to tell apart, and a translucent window over
|
|
||||||
-- another is hard to read.
|
|
||||||
if not hl.get_config("decoration.shadow.enabled") then
|
|
||||||
hl.config({ decoration = { shadow = { enabled = true, range = 16, render_power = 3, color = "rgba(00000035)" } } })
|
|
||||||
o.window(".*", { no_shadow = true })
|
|
||||||
o.window({ tag = WORKSPACE_TAG }, { no_shadow = false })
|
|
||||||
end
|
|
||||||
|
|
||||||
o.window({ tag = WORKSPACE_TAG }, { opacity = "1.0 override 1.0 override" })
|
|
||||||
|
|
||||||
titlebars()
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@@ -108,6 +108,7 @@ def defaults(config_home, fresh=False):
|
|||||||
stock_lists = {
|
stock_lists = {
|
||||||
"Hotkey/ActivateKeys": {"0": "Hangul_Hanja"},
|
"Hotkey/ActivateKeys": {"0": "Hangul_Hanja"},
|
||||||
"Hotkey/DeactivateKeys": {"0": "Hangul_Romaja"},
|
"Hotkey/DeactivateKeys": {"0": "Hangul_Romaja"},
|
||||||
|
"Hotkey/AltTriggerKeys": {"0": "Shift_L"},
|
||||||
"Hotkey/EnumerateGroupForwardKeys": {"0": "Super+space"},
|
"Hotkey/EnumerateGroupForwardKeys": {"0": "Super+space"},
|
||||||
"Hotkey/EnumerateGroupBackwardKeys": {"0": "Super+Shift+space"},
|
"Hotkey/EnumerateGroupBackwardKeys": {"0": "Super+Shift+space"},
|
||||||
"TriggerKey": {"0": "Super+grave", "1": "Super+semicolon"},
|
"TriggerKey": {"0": "Super+grave", "1": "Super+semicolon"},
|
||||||
|
|||||||
@@ -53,60 +53,7 @@
|
|||||||
"learn.community": {"icon":"","label":"Community","action":"omarchy-launch-discord-community"},
|
"learn.community": {"icon":"","label":"Community","action":"omarchy-launch-discord-community"},
|
||||||
|
|
||||||
// Trigger
|
// Trigger
|
||||||
"trigger.appearance": {"icon":"","label":"Appearance"},
|
|
||||||
"trigger.appearance.animations": {"icon":"","label":"Animations","action":"omarchy-toggle-animations"},
|
|
||||||
"trigger.appearance.top-bar": {"icon":"","label":"Menu Bar"},
|
|
||||||
"trigger.appearance.top-bar.hide": {"icon":"","label":"Hide Bar","when":"! omarchy-toggle-enabled bar-off","action":"omarchy-toggle-bar"},
|
|
||||||
"trigger.appearance.top-bar.show": {"icon":"","label":"Show Bar","when":"omarchy-toggle-enabled bar-off","action":"omarchy-toggle-bar"},
|
|
||||||
"trigger.appearance.top-bar.position": {"icon":"","label":"Position Bar"},
|
|
||||||
"trigger.appearance.top-bar.background": {"icon":"","label":"Bar Background"},
|
|
||||||
"trigger.appearance.top-bar.background.opaque": {"icon":"","label":"Opaque Bar","checked":"[[ $(omarchy-bar background) == \"opaque\" ]]","action":"omarchy-bar background opaque"},
|
|
||||||
"trigger.appearance.top-bar.background.glassy": {"icon":"","label":"Glassy Bar","checked":"[[ $(omarchy-bar background) == \"glassy\" ]]","action":"omarchy-bar background glassy"},
|
|
||||||
"trigger.appearance.top-bar.background.clear": {"icon":"","label":"Clear Bar","checked":"[[ $(omarchy-bar background) == \"none\" ]]","action":"omarchy-bar background none"},
|
|
||||||
"trigger.appearance.top-bar.indicators": {"icon":"","label":"Bar Indicators"},
|
|
||||||
"trigger.appearance.top-bar.indicators.battery-percentage": {"icon":"","label":"Battery Percentage","when":"omarchy-hw-laptop","action":"omarchy-shell omarchy.power togglePercentage"},
|
|
||||||
"trigger.appearance.top-bar.indicators.clock": {"icon":"","label":"Clock"},
|
|
||||||
"trigger.appearance.top-bar.indicators.clock.sunday-24h": {"icon":"","label":"Sunday 14:30","when":"[[ $(omarchy-bar position) != \"left\" && $(omarchy-bar position) != \"right\" ]]","checked":"[[ $(omarchy-bar get omarchy.clock format) == \"dddd HH:mm\" ]]","action":"omarchy-bar set omarchy.clock format \"dddd HH:mm\""},
|
|
||||||
"trigger.appearance.top-bar.indicators.clock.sunday-12h": {"icon":"","label":"Sunday 2:30 PM","when":"[[ $(omarchy-bar position) != \"left\" && $(omarchy-bar position) != \"right\" ]]","checked":"[[ $(omarchy-bar get omarchy.clock format) == \"dddd h:mm AP\" ]]","action":"omarchy-bar set omarchy.clock format \"dddd h:mm AP\""},
|
|
||||||
"trigger.appearance.top-bar.indicators.clock.sunday-seconds-24h": {"icon":"","label":"Sunday 14:30:05","when":"[[ $(omarchy-bar position) != \"left\" && $(omarchy-bar position) != \"right\" ]]","checked":"[[ $(omarchy-bar get omarchy.clock format) == \"dddd HH:mm:ss\" ]]","action":"omarchy-bar set omarchy.clock format \"dddd HH:mm:ss\""},
|
|
||||||
"trigger.appearance.top-bar.indicators.clock.sunday-seconds-12h": {"icon":"","label":"Sunday 2:30:05 PM","when":"[[ $(omarchy-bar position) != \"left\" && $(omarchy-bar position) != \"right\" ]]","checked":"[[ $(omarchy-bar get omarchy.clock format) == \"dddd h:mm:ss AP\" ]]","action":"omarchy-bar set omarchy.clock format \"dddd h:mm:ss AP\""},
|
|
||||||
"trigger.appearance.top-bar.indicators.clock.time-24h": {"icon":"","label":"14:30","when":"[[ $(omarchy-bar position) != \"left\" && $(omarchy-bar position) != \"right\" ]]","checked":"[[ $(omarchy-bar get omarchy.clock format) == \"HH:mm\" ]]","action":"omarchy-bar set omarchy.clock format \"HH:mm\""},
|
|
||||||
"trigger.appearance.top-bar.indicators.clock.time-12h": {"icon":"","label":"2:30 PM","when":"[[ $(omarchy-bar position) != \"left\" && $(omarchy-bar position) != \"right\" ]]","checked":"[[ $(omarchy-bar get omarchy.clock format) == \"h:mm AP\" ]]","action":"omarchy-bar set omarchy.clock format \"h:mm AP\""},
|
|
||||||
"trigger.appearance.top-bar.indicators.clock.date-24h": {"icon":"","label":"Sun 3 May 14:30","when":"[[ $(omarchy-bar position) != \"left\" && $(omarchy-bar position) != \"right\" ]]","checked":"[[ $(omarchy-bar get omarchy.clock format) == \"ddd d MMM HH:mm\" ]]","action":"omarchy-bar set omarchy.clock format \"ddd d MMM HH:mm\""},
|
|
||||||
"trigger.appearance.top-bar.indicators.clock.date-12h": {"icon":"","label":"Sun 3 May 2:30 PM","when":"[[ $(omarchy-bar position) != \"left\" && $(omarchy-bar position) != \"right\" ]]","checked":"[[ $(omarchy-bar get omarchy.clock format) == \"ddd d MMM h:mm AP\" ]]","action":"omarchy-bar set omarchy.clock format \"ddd d MMM h:mm AP\""},
|
|
||||||
"trigger.appearance.top-bar.indicators.clock.week": {"icon":"","label":"3 May W18 2026","when":"[[ $(omarchy-bar position) != \"left\" && $(omarchy-bar position) != \"right\" ]]","checked":"[[ $(omarchy-bar get omarchy.clock format) == \"d MMMM 'W'ww yyyy\" ]]","action":"omarchy-bar set omarchy.clock format \"d MMMM 'W'ww yyyy\""},
|
|
||||||
"trigger.appearance.top-bar.indicators.clock.iso": {"icon":"","label":"2026-05-03 14:30","when":"[[ $(omarchy-bar position) != \"left\" && $(omarchy-bar position) != \"right\" ]]","checked":"[[ $(omarchy-bar get omarchy.clock format) == \"yyyy-MM-dd HH:mm\" ]]","action":"omarchy-bar set omarchy.clock format \"yyyy-MM-dd HH:mm\""},
|
|
||||||
"trigger.appearance.top-bar.indicators.clock.stacked-24h": {"icon":"","label":"14 — 30","when":"[[ $(omarchy-bar position) == \"left\" || $(omarchy-bar position) == \"right\" ]]","checked":"[[ $(omarchy-bar get omarchy.clock verticalFormat) == $'HH\\n—\\nmm' ]]","action":"omarchy-bar set omarchy.clock verticalFormat $'HH\\n—\\nmm'"},
|
|
||||||
"trigger.appearance.top-bar.indicators.clock.stacked-12h": {"icon":"","label":"2 — 30 PM","when":"[[ $(omarchy-bar position) == \"left\" || $(omarchy-bar position) == \"right\" ]]","checked":"[[ $(omarchy-bar get omarchy.clock verticalFormat) == $'h\\n—\\nmm\\nAP' ]]","action":"omarchy-bar set omarchy.clock verticalFormat $'h\\n—\\nmm\\nAP'"},
|
|
||||||
"trigger.appearance.top-bar.indicators.clock.stacked-date": {"icon":"","label":"03 May W18 '26","when":"[[ $(omarchy-bar position) == \"left\" || $(omarchy-bar position) == \"right\" ]]","checked":"[[ $(omarchy-bar get omarchy.clock verticalFormat) == $'dd\\nMMM\\n\\'W\\'ww\\n\\'\\'yy' ]]","action":"omarchy-bar set omarchy.clock verticalFormat $'dd\\nMMM\\n\\'W\\'ww\\n\\'\\'yy'"},
|
|
||||||
"trigger.appearance.top-bar.indicators.clock.stacked-time": {"icon":"","label":"14 30","when":"[[ $(omarchy-bar position) == \"left\" || $(omarchy-bar position) == \"right\" ]]","checked":"[[ $(omarchy-bar get omarchy.clock verticalFormat) == $'HH\\nmm' ]]","action":"omarchy-bar set omarchy.clock verticalFormat $'HH\\nmm'"},
|
|
||||||
"trigger.appearance.top-bar.position.top": {"icon":"","label":"Top Bar","action":"omarchy-bar position top"},
|
|
||||||
"trigger.appearance.top-bar.position.bottom": {"icon":"","label":"Bottom Bar","action":"omarchy-bar position bottom"},
|
|
||||||
"trigger.appearance.top-bar.position.left": {"icon":"","label":"Left Bar","action":"omarchy-bar position left"},
|
|
||||||
"trigger.appearance.top-bar.position.right": {"icon":"","label":"Right Bar","action":"omarchy-bar position right"},
|
|
||||||
"trigger.appearance.window-gaps": {"icon":"","label":"Window Gaps","action":"omarchy-hyprland-window-gaps-toggle"},
|
|
||||||
"trigger.appearance.window-corners": {"icon":"","label":"Window Corners"},
|
|
||||||
"trigger.appearance.window-corners.theme": {"icon":"","label":"Theme Corners","checked":"[[ $(omarchy-hyprland-corners) == \"theme\" ]]","action":"omarchy-hyprland-corners theme"},
|
|
||||||
"trigger.appearance.window-corners.sharp": {"icon":"","label":"Sharp Corners","checked":"[[ $(omarchy-hyprland-corners) == \"sharp\" ]]","action":"omarchy-hyprland-corners sharp"},
|
|
||||||
"trigger.appearance.window-corners.rounded": {"icon":"","label":"Rounded Corners","checked":"[[ $(omarchy-hyprland-corners) == \"rounded\" ]]","action":"omarchy-hyprland-corners rounded"},
|
|
||||||
"trigger.appearance.window-transparency": {"icon":"","label":"Window Transparency"},
|
|
||||||
"trigger.appearance.window-transparency.opaque": {"icon":"","label":"Opaque Windows","checked":"[[ $(omarchy-hyprland-window-transparency) == \"opaque\" ]]","action":"omarchy-hyprland-window-transparency opaque"},
|
|
||||||
"trigger.appearance.window-transparency.transparent": {"icon":"","label":"Transparent Windows","checked":"[[ $(omarchy-hyprland-window-transparency) == \"transparent\" ]]","action":"omarchy-hyprland-window-transparency transparent"},
|
|
||||||
"trigger.appearance.window-transparency.glassy": {"icon":"","label":"Glassy Windows","checked":"[[ $(omarchy-hyprland-window-transparency) == \"glassy\" ]]","action":"omarchy-hyprland-window-transparency glassy"},
|
|
||||||
"trigger.appearance.one-window-ratio": {"icon":"","label":"1-Window Ratio","action":"omarchy-hyprland-window-single-square-aspect-toggle"},
|
|
||||||
"trigger.appearance.workspace-layout": {"icon":"","label":"Workspace Layout","title":"Default Workspace Layout"},
|
|
||||||
"trigger.appearance.workspace-layout.dwindle": {"icon":"","label":"Tiling","checked":"[[ $(omarchy-hyprland-workspace-layout-default) == \"dwindle\" ]]","action":"omarchy-hyprland-workspace-layout-default dwindle"},
|
|
||||||
"trigger.appearance.workspace-layout.scrolling": {"icon":"","label":"Scrolling","checked":"[[ $(omarchy-hyprland-workspace-layout-default) == \"scrolling\" ]]","action":"omarchy-hyprland-workspace-layout-default scrolling"},
|
|
||||||
"trigger.appearance.workspace-layout.floating": {"icon":"","label":"Floating","checked":"[[ $(omarchy-hyprland-workspace-layout-default) == \"floating\" ]]","action":"omarchy-hyprland-workspace-layout-default floating"},
|
|
||||||
"trigger.appearance.theme-sync": {"icon":"","label":"Herdr Theme Sync","when":"omarchy-theme-set-herdr-machines --available","action":"omarchy-toggle-theme-sync"},
|
|
||||||
"trigger.toggle": {"icon":"","label":"Toggle"},
|
|
||||||
"trigger.toggle.idle-lock": {"icon":"","label":"Stay Awake","action":"omarchy-toggle-idle"},
|
|
||||||
"trigger.toggle.notifications": {"icon":"","label":"Notifications","action":"omarchy-toggle-notification-silencing"},
|
|
||||||
"trigger.toggle.nightlight": {"icon":"","label":"Nightlight","action":"omarchy-toggle-nightlight"},
|
|
||||||
"trigger.toggle.screensaver": {"icon":"","label":"Screensaver","action":"omarchy-toggle-screensaver"},
|
|
||||||
"trigger.toggle.crash-capture": {"icon":"","label":"Crash Capture","action":"omarchy-toggle-crash-capture"},
|
|
||||||
"trigger.emoji": {"icon":"","label":"Emoji","aliases":["emoji","emojis"],"action":"omarchy-menu-emoji"},
|
"trigger.emoji": {"icon":"","label":"Emoji","aliases":["emoji","emojis"],"action":"omarchy-menu-emoji"},
|
||||||
"trigger.clipboard-history": {"icon":"","label":"Clipboard History","action":"omarchy-shell shell summon omarchy.clipboard"},
|
|
||||||
"trigger.reminder": {"icon":"","label":"Reminder","aliases":["reminder"]},
|
"trigger.reminder": {"icon":"","label":"Reminder","aliases":["reminder"]},
|
||||||
"trigger.capture": {"icon":"","label":"Capture","aliases":["capture","screenshot","screenrecord","screen-record","screenrecording"]},
|
"trigger.capture": {"icon":"","label":"Capture","aliases":["capture","screenshot","screenrecord","screen-record","screenrecording"]},
|
||||||
"trigger.capture.screenshot": {"icon":"","label":"Screenshot","action":"omarchy-capture-screenshot"},
|
"trigger.capture.screenshot": {"icon":"","label":"Screenshot","action":"omarchy-capture-screenshot"},
|
||||||
@@ -121,6 +68,7 @@
|
|||||||
"trigger.capture.screenrecord.webcam": {"icon":"","label":"With desktop + microphone audio + webcam","when":"omarchy-hw-webcam","action":"omarchy-capture-screenrecording-with-webcam"},
|
"trigger.capture.screenrecord.webcam": {"icon":"","label":"With desktop + microphone audio + webcam","when":"omarchy-hw-webcam","action":"omarchy-capture-screenrecording-with-webcam"},
|
||||||
"trigger.transcode": {"icon":"","label":"Transcode","action":"omarchy-transcode"},
|
"trigger.transcode": {"icon":"","label":"Transcode","action":"omarchy-transcode"},
|
||||||
"trigger.share": {"icon":"","label":"Share","aliases":["share"]},
|
"trigger.share": {"icon":"","label":"Share","aliases":["share"]},
|
||||||
|
"trigger.toggle": {"icon":"","label":"Toggle","aliases":["toggle","toggles"]},
|
||||||
"trigger.hardware": {"icon":"","label":"Hardware","aliases":["hardware","hw"]},
|
"trigger.hardware": {"icon":"","label":"Hardware","aliases":["hardware","hw"]},
|
||||||
"trigger.tests": {"icon":"","label":"Speed Test"},
|
"trigger.tests": {"icon":"","label":"Speed Test"},
|
||||||
"trigger.hardware.laptop-display": {"icon":"","label":"Laptop Display","when":"omarchy-hw-laptop","action":"omarchy-hyprland-monitor-internal toggle"},
|
"trigger.hardware.laptop-display": {"icon":"","label":"Laptop Display","when":"omarchy-hw-laptop","action":"omarchy-hyprland-monitor-internal toggle"},
|
||||||
@@ -139,6 +87,18 @@
|
|||||||
"trigger.share.file": {"icon":"","label":"File","action":"omarchy-menu-share file"},
|
"trigger.share.file": {"icon":"","label":"File","action":"omarchy-menu-share file"},
|
||||||
"trigger.share.folder": {"icon":"","label":"Folder","action":"omarchy-menu-share folder"},
|
"trigger.share.folder": {"icon":"","label":"Folder","action":"omarchy-menu-share folder"},
|
||||||
"trigger.share.receive": {"icon":"","label":"Receive","action":"uwsm-app -- localsend"},
|
"trigger.share.receive": {"icon":"","label":"Receive","action":"uwsm-app -- localsend"},
|
||||||
|
"trigger.toggle.idle-lock": {"icon":"","label":"Stay Awake","action":"omarchy-toggle-idle"},
|
||||||
|
"trigger.toggle.notifications": {"icon":"","label":"Notifications","action":"omarchy-toggle-notification-silencing"},
|
||||||
|
"trigger.toggle.crash-capture": {"icon":"","label":"Crash Capture","action":"omarchy-toggle-crash-capture"},
|
||||||
|
"trigger.toggle.screensaver": {"icon":"","label":"Screensaver","action":"omarchy-toggle-screensaver"},
|
||||||
|
"trigger.toggle.theme-sync": {"icon":"","label":"Herdr Theme Sync","when":"omarchy-theme-set-herdr-machines --available","action":"omarchy-toggle-theme-sync"},
|
||||||
|
"trigger.toggle.nightlight": {"icon":"","label":"Nightlight","action":"omarchy-toggle-nightlight"},
|
||||||
|
"trigger.toggle.top-bar": {"icon":"","label":"Menu Bar","action":"omarchy-toggle-bar"},
|
||||||
|
"trigger.toggle.battery-percentage": {"icon":"","label":"Battery Percentage","when":"omarchy-hw-laptop","action":"omarchy-shell omarchy.power togglePercentage"},
|
||||||
|
"trigger.toggle.workspace-layout": {"icon":"","label":"Workspace Layout","action":"omarchy-hyprland-workspace-layout-toggle"},
|
||||||
|
"trigger.toggle.window-gaps": {"icon":"","label":"Window Gaps","action":"omarchy-hyprland-window-gaps-toggle"},
|
||||||
|
"trigger.toggle.animations": {"icon":"","label":"Animations","action":"omarchy-toggle-animations"},
|
||||||
|
"trigger.toggle.one-window-ratio": {"icon":"","label":"1-Window Ratio","action":"omarchy-hyprland-window-single-square-aspect-toggle"},
|
||||||
"trigger.tests.network-speedtest": {"icon":"","label":"Network Speed Test","action":"omarchy-shell shell summon omarchy.speedtest"},
|
"trigger.tests.network-speedtest": {"icon":"","label":"Network Speed Test","action":"omarchy-shell shell summon omarchy.speedtest"},
|
||||||
"trigger.tests.disk-speedtest": {"icon":"","label":"Disk Speed Test","action":"omarchy-shell shell summon omarchy.disk-speedtest"},
|
"trigger.tests.disk-speedtest": {"icon":"","label":"Disk Speed Test","action":"omarchy-shell shell summon omarchy.disk-speedtest"},
|
||||||
|
|
||||||
@@ -147,9 +107,16 @@
|
|||||||
"style.background": {"icon":"","label":"Background","aliases":["background","wallpaper"],"action":"background=$(omarchy-theme-bg-switcher); [[ -n $background ]] && omarchy-theme-bg-set \"$background\""},
|
"style.background": {"icon":"","label":"Background","aliases":["background","wallpaper"],"action":"background=$(omarchy-theme-bg-switcher); [[ -n $background ]] && omarchy-theme-bg-set \"$background\""},
|
||||||
"style.unlock": {"icon":"","label":"Unlock","aliases":["unlock"],"action":"unlock=$(omarchy-plymouth-switcher); if [[ $unlock == default ]]; then omarchy-launch-floating-terminal-with-presentation omarchy-plymouth-reset; elif [[ -n $unlock ]]; then omarchy-launch-floating-terminal-with-presentation \"omarchy-plymouth-set-by-theme $(printf %q \"$unlock\")\"; fi"},
|
"style.unlock": {"icon":"","label":"Unlock","aliases":["unlock"],"action":"unlock=$(omarchy-plymouth-switcher); if [[ $unlock == default ]]; then omarchy-launch-floating-terminal-with-presentation omarchy-plymouth-reset; elif [[ -n $unlock ]]; then omarchy-launch-floating-terminal-with-presentation \"omarchy-plymouth-set-by-theme $(printf %q \"$unlock\")\"; fi"},
|
||||||
"style.font": {"icon":"","label":"Font","provider":"fonts"},
|
"style.font": {"icon":"","label":"Font","provider":"fonts"},
|
||||||
|
"style.bar": {"icon":"","label":"Menu Bar"},
|
||||||
|
"style.bar.position": {"icon":"","label":"Position"},
|
||||||
|
"style.bar.transparency": {"icon":"","label":"Transparency","action":"omarchy-bar transparent toggle"},
|
||||||
"style.hyprland": {"icon":"","label":"Hyprland","action":"omarchy-launch-config-editor \"$HOME/.config/hypr/looknfeel.lua\""},
|
"style.hyprland": {"icon":"","label":"Hyprland","action":"omarchy-launch-config-editor \"$HOME/.config/hypr/looknfeel.lua\""},
|
||||||
"style.screensaver": {"icon":"","label":"Screensaver"},
|
"style.screensaver": {"icon":"","label":"Screensaver"},
|
||||||
"style.about": {"icon":"","label":"About"},
|
"style.about": {"icon":"","label":"About"},
|
||||||
|
"style.bar.position.top": {"icon":"","label":"Top","action":"omarchy-bar position top"},
|
||||||
|
"style.bar.position.bottom": {"icon":"","label":"Bottom","action":"omarchy-bar position bottom"},
|
||||||
|
"style.bar.position.left": {"icon":"","label":"Left","action":"omarchy-bar position left"},
|
||||||
|
"style.bar.position.right": {"icon":"","label":"Right","action":"omarchy-bar position right"},
|
||||||
"style.about.text": {"icon":"","label":"Edit Text","action":"omarchy-branding-about text"},
|
"style.about.text": {"icon":"","label":"Edit Text","action":"omarchy-branding-about text"},
|
||||||
"style.about.image": {"icon":"","label":"Set From Image","action":"omarchy-branding-about image"},
|
"style.about.image": {"icon":"","label":"Set From Image","action":"omarchy-branding-about image"},
|
||||||
"style.about.default": {"icon":"","label":"Restore Default","action":"omarchy-branding-about reset"},
|
"style.about.default": {"icon":"","label":"Restore Default","action":"omarchy-branding-about reset"},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=Fcitx5 input methods and XCompose sequences
|
Description=Fcitx5 input methods and XCompose sequences
|
||||||
# fcitx5 turns the Shift + CapsLock compose sequences in ~/.XCompose into text for
|
# fcitx5 turns the CapsLock compose sequences in ~/.XCompose into text for
|
||||||
# Wayland clients.
|
# Wayland clients.
|
||||||
#
|
#
|
||||||
# Wait for the compositor: fcitx5 needs WAYLAND_DISPLAY and DISPLAY, which uwsm
|
# Wait for the compositor: fcitx5 needs WAYLAND_DISPLAY and DISPLAY, which uwsm
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
[colors-dark]
|
[colors-dark]
|
||||||
foreground={{ foreground_strip }}
|
foreground={{ foreground_strip }}
|
||||||
background={{ background_strip }}
|
background={{ background_strip }}
|
||||||
# Blur only applies while the background is see-through, as with Glassy windows,
|
|
||||||
# and foot reads it only at launch, so it is on from the start.
|
|
||||||
blur=yes
|
|
||||||
selection-foreground={{ selection_foreground_strip }}
|
selection-foreground={{ selection_foreground_strip }}
|
||||||
selection-background={{ selection_background_strip }}
|
selection-background={{ selection_background_strip }}
|
||||||
|
|
||||||
|
|||||||
@@ -6,10 +6,6 @@ selection_background {{ selection_background }}
|
|||||||
cursor {{ bright_foreground }}
|
cursor {{ bright_foreground }}
|
||||||
cursor_text_color {{ background }}
|
cursor_text_color {{ background }}
|
||||||
|
|
||||||
# Lets a reload change the background opacity, as Glassy windows do, since
|
|
||||||
# kitty only allows that when this is on from launch.
|
|
||||||
dynamic_background_opacity yes
|
|
||||||
|
|
||||||
active_border_color {{ accent }}
|
active_border_color {{ accent }}
|
||||||
active_tab_background {{ accent }}
|
active_tab_background {{ accent }}
|
||||||
|
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ config/** ──► omarchy-settings /etc/skel/.config/
|
|||||||
/usr/share/omarchy/config/** (resync source)
|
/usr/share/omarchy/config/** (resync source)
|
||||||
etc/fastfetch/config.jsonc ──► omarchy-settings /etc/fastfetch/config.jsonc
|
etc/fastfetch/config.jsonc ──► omarchy-settings /etc/fastfetch/config.jsonc
|
||||||
etc/xdg/kitty/kitty.conf ──► omarchy-settings /etc/xdg/kitty/kitty.conf
|
etc/xdg/kitty/kitty.conf ──► omarchy-settings /etc/xdg/kitty/kitty.conf
|
||||||
etc/xkb/{rules/evdev,symbols/omarchy}
|
|
||||||
──► omarchy-settings /etc/xkb/ (Shift + Caps Lock compose option)
|
|
||||||
|
|
||||||
applications/*.desktop ──► omarchy-settings /etc/skel/.local/share/applications/
|
applications/*.desktop ──► omarchy-settings /etc/skel/.local/share/applications/
|
||||||
/usr/share/omarchy/applications/
|
/usr/share/omarchy/applications/
|
||||||
|
|||||||
@@ -94,8 +94,8 @@ You can still install by hand: drop a plugin into
|
|||||||
`~/.config/omarchy/plugins/<id>/`, run `omarchy-shell shell rescanPlugins`, then
|
`~/.config/omarchy/plugins/<id>/`, run `omarchy-shell shell rescanPlugins`, then
|
||||||
`omarchy plugin enable <id>`. A bar widget starts in its declared default
|
`omarchy plugin enable <id>`. A bar widget starts in its declared default
|
||||||
section; enabling a full bar replaces the one in use. `omarchy bar` drives the
|
section; enabling a full bar replaces the one in use. `omarchy bar` drives the
|
||||||
bar from the CLI — `use | reset | defaults | position | background | put |
|
bar from the CLI — `use | reset | defaults | position | transparent | put |
|
||||||
move | set | get`, with placement flags such as `--section` and `--index`.
|
move | set`, with placement flags such as `--section` and `--index`.
|
||||||
The lower-level IPC methods remain available through `omarchy-shell shell ...`.
|
The lower-level IPC methods remain available through `omarchy-shell shell ...`.
|
||||||
|
|
||||||
## Elsewhen
|
## Elsewhen
|
||||||
@@ -121,7 +121,7 @@ or `omarchy.power`. There is no `bar` target.
|
|||||||
| `rescanPlugins` | re-walk plugin dirs and hot-reload plugin code |
|
| `rescanPlugins` | re-walk plugin dirs and hot-reload plugin code |
|
||||||
| `reloadConfig` | reload shell.json |
|
| `reloadConfig` | reload shell.json |
|
||||||
| `applyTheme <colorsB64> <shellB64>` | push theme colors + shell.toml |
|
| `applyTheme <colorsB64> <shellB64>` | push theme colors + shell.toml |
|
||||||
| `toggleBarTransparency` | cycle the bar background from clear to glassy to opaque |
|
| `toggleBarTransparency` | flip the bar background between solid and transparent |
|
||||||
| `cycleInput <next\|back>` | switch to the next or previous input method or layout (Super+I, Super+Shift+I); `not running` without the input reader |
|
| `cycleInput <next\|back>` | switch to the next or previous input method or layout (Super+I, Super+Shift+I); `not running` without the input reader |
|
||||||
| `setPluginEnabled <id> <"true"\|…>` | flip enabled bit (`ok` / `unknown`) |
|
| `setPluginEnabled <id> <"true"\|…>` | flip enabled bit (`ok` / `unknown`) |
|
||||||
| `enablePlugin <id> <placementJson>` | enable and place in one mutation |
|
| `enablePlugin <id> <placementJson>` | enable and place in one mutation |
|
||||||
@@ -148,7 +148,7 @@ string on a miss.
|
|||||||
"bar": {
|
"bar": {
|
||||||
"id": "omarchy.bar",
|
"id": "omarchy.bar",
|
||||||
"position": "top",
|
"position": "top",
|
||||||
"background": "opaque",
|
"transparent": false,
|
||||||
"centerAnchor": "omarchy.clock",
|
"centerAnchor": "omarchy.clock",
|
||||||
"layout": {
|
"layout": {
|
||||||
"left": [ { "id": "omarchy.menu" } ],
|
"left": [ { "id": "omarchy.menu" } ],
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
`omarchy-sudo-passwordless` publishes a timed or permanent grant for the numeric UID authenticated by sudo. Its user interface inspects sudo policy without prompting and authenticates only the enable action when access is off, without a reusable sudo timestamp; fixed installed internal actions run as root and serialize on `/run/lock/omarchy-sudo-passwordless.lock`.
|
`omarchy-sudo-passwordless` publishes a timed or permanent grant for the numeric UID authenticated by sudo. Its user interface inspects sudo policy without prompting and authenticates only the enable action when access is off, without a reusable sudo timestamp; fixed installed internal actions run as root and serialize on `/run/lock/omarchy-sudo-passwordless.lock`.
|
||||||
|
|
||||||
The menu bar's `PasswordlessSudo` indicator runs `--active` when the shell starts and whenever `omarchy.indicators` is refreshed, and shows the passwordless sudo icon in red while access is active. The probe normally reads sudo's noninteractive long policy listing for the installed `__status` action and checks its `!authenticate` tag. If listing requires authentication, it falls back to a noninteractive `__status` call that ignores cached credentials. Neither path prompts or updates the credential cache. Interactive setup likewise falls back to noninteractive status and, when authentication is unavailable, leaves validation to the single confirmed enable action. Clicking the active indicator runs `--disable` noninteractively without opening a terminal, so a grant expiring between display and click cannot start the enable flow. The indicator never polls: every enable or disable attempt refreshes it directly, failed ones included since a rolled-back renewal can remove the previous grant, and enabling a timed grant also starts a transient user timer on the same wall-clock deadline that refreshes it two seconds later, so expiry during suspend shows on resume. The root expiry timer cannot reach the user's shell. If that refresh is missed, the indicator stays red past expiry, and clicking it reports access is already disabled and clears it.
|
The menu bar's `PasswordlessSudo` indicator polls `--active` every five seconds and shows the passwordless sudo icon in red while access is active. The probe normally reads sudo's noninteractive long policy listing for the installed `__status` action and checks its `!authenticate` tag. If listing requires authentication, it falls back to a noninteractive `__status` call that ignores cached credentials. Neither path prompts or updates the credential cache. Interactive setup likewise falls back to noninteractive status and, when authentication is unavailable, leaves validation to the single confirmed enable action. Clicking the active indicator runs `--disable` noninteractively without opening a terminal, so a grant expiring between display and click cannot start the enable flow.
|
||||||
|
|
||||||
## Grant lifecycle
|
## Grant lifecycle
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@ Beyond `colors.toml` and hand-written config overrides, a first-party theme can
|
|||||||
|
|
||||||
A theme can pair a still background with a silent intro video using matching filenames: `backgrounds/0-winding-road.webp` and `backgrounds/intros/0-winding-road.mp4`. The video plays automatically at login and when switching to that theme with this background selected. No registration, checksum file or manual setting is needed. Supported video extensions are `mp4`, `m4v`, `mov`, `webm`, `mkv` and `avi`. Intro videos stay inside the nested `intros/` directory so the background picker does not list them as looping wallpapers. An image selected from another directory looks for its intro in that directory's own `intros/`, so a same-named custom image cannot inherit a theme's video.
|
A theme can pair a still background with a silent intro video using matching filenames: `backgrounds/0-winding-road.webp` and `backgrounds/intros/0-winding-road.mp4`. The video plays automatically at login and when switching to that theme with this background selected. No registration, checksum file or manual setting is needed. Supported video extensions are `mp4`, `m4v`, `mov`, `webm`, `mkv` and `avi`. Intro videos stay inside the nested `intros/` directory so the background picker does not list them as looping wallpapers. An image selected from another directory looks for its intro in that directory's own `intros/`, so a same-named custom image cannot inherit a theme's video.
|
||||||
|
|
||||||
Aim for a video between five and seven seconds long that opens on its scene setup and ends on the matching still. The shell provides the opening crossfade, so an added fade from black is unnecessary. OWE owns decoding, mute and the handoff back to that image. The theme picker prepares the highlighted theme's remembered intro offscreen, paused at its opening frame. OWE keeps one prepared clip and an idle renderer for up to one minute, then releases them. A theme switch also starts preparation while its templates render; OWE compares the selected video with the prepared clip before resuming it. Older OWE versions use the ordinary startup path. Hyprland and the SDDM greeter use a black compositor background. On a fresh login, the persistent shell host keeps an opaque black cover above the bar and wallpaper until the bar has loaded and OWE has a moving video frame, then fades both in together over 420 ms. Hyprland initializes with a transparent cursor so its visibility polling cannot expose a pointer in the first frames. The temporary Xcursor theme stays private to the compositor; applications inherit the normal cursor environment. The opening fade restores the selected cursor and settings. Shell restarts and a fifteen-second compositor timeout recover a cursor left hidden by an interrupted startup. With intros disabled or unavailable, it waits for the still to be ready instead. A ten-second deadline releases the cover if a missing wallpaper or failed plugin never becomes ready. Ordinary shell restarts preload the selected still alongside the bar without mapping that login cover. Login intros use the Hyprland instance signature, so logging out and back in plays the intro again. The launcher consumes the current session before waiting up to five seconds for OWE. Shell restarts and a daemon starting after that window cannot play a delayed intro. Theme switches synchronize OWE with the selected image and use its first-frame start mode. An interrupted video supplies its currently playing frame as the outgoing snapshot. Rapid selections wait for the previous opening fade to finish before capturing it. Theme replacement and playback wait for the outgoing cover to decode and reach the compositor on every screen. A persistent layer holds that outgoing wallpaper until OWE hides the shell background and reports a ready video with an advancing playback position and no outgoing still transition, then crossfades it over 420 ms while applying the new bar palette. The shell retains its background service and decoded wallpaper while it is hidden, so handing the still back does not recreate them. App retints wait until the opening crossfade completes, with a three-second bound, so they do not compete with its first frames. The compositor reload waits until playback finishes because reloading Hyprland pauses video presentation. A superseded intro skips that reload. Failed playback releases the pending palette, and a newer theme invalidates the older handoff. Refreshing a theme, headless setup, and cycling backgrounds within the same theme do not trigger intros. Appearance > Animations suppresses playback along with the other animations. The `omarchy theme bg intro toggle` command can toggle intros separately.
|
Aim for a video between five and seven seconds long that opens on its scene setup and ends on the matching still. The shell provides the opening crossfade, so an added fade from black is unnecessary. OWE owns decoding, mute and the handoff back to that image. The theme picker prepares the highlighted theme's remembered intro offscreen, paused at its opening frame. OWE keeps one prepared clip and an idle renderer for up to one minute, then releases them. A theme switch also starts preparation while its templates render; OWE compares the selected video with the prepared clip before resuming it. Older OWE versions use the ordinary startup path. Hyprland and the SDDM greeter use a black compositor background. On a fresh login, the persistent shell host keeps an opaque black cover above the bar and wallpaper until the bar has loaded and OWE has a moving video frame, then fades both in together over 420 ms. Hyprland initializes with a transparent cursor so its visibility polling cannot expose a pointer in the first frames. The temporary Xcursor theme stays private to the compositor; applications inherit the normal cursor environment. The opening fade restores the selected cursor and settings. Shell restarts and a fifteen-second compositor timeout recover a cursor left hidden by an interrupted startup. With intros disabled or unavailable, it waits for the still to be ready instead. A ten-second deadline releases the cover if a missing wallpaper or failed plugin never becomes ready. Ordinary shell restarts preload the selected still alongside the bar without mapping that login cover. Login intros use the Hyprland instance signature, so logging out and back in plays the intro again. The launcher consumes the current session before waiting up to five seconds for OWE. Shell restarts and a daemon starting after that window cannot play a delayed intro. Theme switches synchronize OWE with the selected image and use its first-frame start mode. An interrupted video supplies its currently playing frame as the outgoing snapshot. Rapid selections wait for the previous opening fade to finish before capturing it. Theme replacement and playback wait for the outgoing cover to decode and reach the compositor on every screen. A persistent layer holds that outgoing wallpaper until OWE hides the shell background and reports a ready video with an advancing playback position and no outgoing still transition, then crossfades it over 420 ms while applying the new bar palette. The shell retains its background service and decoded wallpaper while it is hidden, so handing the still back does not recreate them. App retints wait until the opening crossfade completes, with a three-second bound, so they do not compete with its first frames. The compositor reload waits until playback finishes because reloading Hyprland pauses video presentation. A superseded intro skips that reload. Failed playback releases the pending palette, and a newer theme invalidates the older handoff. Refreshing a theme, headless setup, and cycling backgrounds within the same theme do not trigger intros. Toggle > Animations suppresses playback along with the other animations. The `omarchy theme bg intro toggle` command can toggle intros separately.
|
||||||
|
|
||||||
A theme installed from a git repo is held to a much shorter list; see [What an installed theme may not ship](#what-an-installed-theme-may-not-ship).
|
A theme installed from a git repo is held to a much shorter list; see [What an installed theme may not ship](#what-an-installed-theme-may-not-ship).
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
// Omarchy's own XKB option. libxkbcommon reads /etc/xkb before the system
|
|
||||||
// rules, which supply everything else.
|
|
||||||
! include %S/evdev
|
|
||||||
|
|
||||||
! option = symbols
|
|
||||||
omarchy:shift_caps_compose = +omarchy(shift_caps_compose)
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
// Caps Lock stays Caps Lock; Shift + Caps Lock is the Compose key. The actions
|
|
||||||
// are explicit so the Shift level never inherits the key's Lock modifier,
|
|
||||||
// which would toggle Caps Lock on every compose.
|
|
||||||
partial modifier_keys
|
|
||||||
xkb_symbols "shift_caps_compose" {
|
|
||||||
key <CAPS> {
|
|
||||||
type[Group1] = "TWO_LEVEL",
|
|
||||||
symbols[Group1] = [ Caps_Lock, Multi_key ],
|
|
||||||
actions[Group1] = [ LockMods(modifiers = Lock), NoAction() ]
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -15,6 +15,7 @@ bolt
|
|||||||
brightnessctl
|
brightnessctl
|
||||||
btop
|
btop
|
||||||
chromium
|
chromium
|
||||||
|
clang
|
||||||
cliamp
|
cliamp
|
||||||
cups
|
cups
|
||||||
cups-filters
|
cups-filters
|
||||||
@@ -69,6 +70,7 @@ inotify-tools
|
|||||||
inxi
|
inxi
|
||||||
networkmanager
|
networkmanager
|
||||||
jq
|
jq
|
||||||
|
kdenlive
|
||||||
kernel-modules-hook
|
kernel-modules-hook
|
||||||
lazygit
|
lazygit
|
||||||
less
|
less
|
||||||
@@ -76,6 +78,7 @@ libsecret
|
|||||||
libvips
|
libvips
|
||||||
libyaml
|
libyaml
|
||||||
libreoffice-fresh
|
libreoffice-fresh
|
||||||
|
llvm
|
||||||
localsend
|
localsend
|
||||||
lua51
|
lua51
|
||||||
luarocks
|
luarocks
|
||||||
@@ -94,12 +97,12 @@ noto-fonts-cjk
|
|||||||
noto-fonts-emoji
|
noto-fonts-emoji
|
||||||
nss-mdns
|
nss-mdns
|
||||||
nvim
|
nvim
|
||||||
|
obs-studio
|
||||||
obsidian
|
obsidian
|
||||||
omacalc
|
omacalc
|
||||||
omacut
|
omacut
|
||||||
omawrite
|
omawrite
|
||||||
omarchy-nvim
|
omarchy-nvim
|
||||||
omarchy-hyprland-titlebars
|
|
||||||
omasnap
|
omasnap
|
||||||
# OWE owns desktop video backgrounds and feeds the lock screen its frames.
|
# OWE owns desktop video backgrounds and feeds the lock screen its frames.
|
||||||
owe
|
owe
|
||||||
@@ -126,7 +129,6 @@ quickshell
|
|||||||
ripgrep
|
ripgrep
|
||||||
ruby
|
ruby
|
||||||
sddm
|
sddm
|
||||||
signed
|
|
||||||
slurp
|
slurp
|
||||||
socat
|
socat
|
||||||
starship
|
starship
|
||||||
@@ -159,6 +161,7 @@ woff2-font-awesome
|
|||||||
xdg-desktop-portal-gtk
|
xdg-desktop-portal-gtk
|
||||||
xdg-desktop-portal-hyprland
|
xdg-desktop-portal-hyprland
|
||||||
xdg-terminal-exec
|
xdg-terminal-exec
|
||||||
|
xournalpp
|
||||||
yaru-icon-theme
|
yaru-icon-theme
|
||||||
yay
|
yay
|
||||||
yt-dlp
|
yt-dlp
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
# A VM usually renders on the CPU, where animations and transparency cost
|
# A VM usually renders on the CPU, where animations and transparency cost
|
||||||
# every frame, so start it without them and with opaque windows.
|
# every frame, so start it without them. omarchy-toggle-animations brings them
|
||||||
# omarchy-toggle-animations and Appearance > Window Transparency bring them
|
# back. This runs before any Hyprland session exists, so place the flag
|
||||||
# back. This runs before any Hyprland session exists, so place the flags
|
# directly rather than through omarchy-hyprland-toggle, which reloads Hyprland.
|
||||||
# directly rather than through the commands, which reload Hyprland.
|
|
||||||
if omarchy-hw-vm; then
|
if omarchy-hw-vm; then
|
||||||
echo "Detected a virtual machine. Turning off animations and transparency."
|
echo "Detected a virtual machine. Turning off animations and transparency."
|
||||||
mkdir -p "$HOME/.local/state/omarchy/toggles/hypr"
|
mkdir -p "$HOME/.local/state/omarchy/toggles/hypr"
|
||||||
cp "$OMARCHY_PATH/default/hypr/toggles/no-animations.lua" "$HOME/.local/state/omarchy/toggles/hypr/"
|
cp "$OMARCHY_PATH/default/hypr/toggles/no-animations.lua" "$HOME/.local/state/omarchy/toggles/hypr/"
|
||||||
cp "$OMARCHY_PATH/default/hypr/toggles/window-opaque.lua" "$HOME/.local/state/omarchy/toggles/hypr/"
|
|
||||||
fi
|
fi
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# Set default XCompose that is triggered with Shift + CapsLock
|
# Set default XCompose that is triggered with CapsLock
|
||||||
tee ~/.XCompose >/dev/null <<EOF
|
tee ~/.XCompose >/dev/null <<EOF
|
||||||
# Run omarchy-restart-xcompose to apply changes
|
# Run omarchy-restart-xcompose to apply changes
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Welcome to Omarchy!
|
# Welcome to Omarchy!
|
||||||
|
|
||||||
Omarchy is an [omakase](https://manuals.omamix.org/3/omacom/76/omakase-computing) Linux distribution based on [Arch](https://archlinux.org/), the tiling window manager [Hyprland](https://hypr.land/), and the desktop construction-kit [Quickshell](https://quickshell.org/). It ships with everything a modern, savvy computer user needs to be productive immediately. From [Neovim](https://neovim.io/) (btw) to Chromium, [Obsidian](https://obsidian.md/) to LibreOffice, and [Hype](https://github.com/omacom/hype) to [Monologue](https://github.com/omacom/monologue). Hell, even a retro Winamp-style music player is there!
|
Omarchy is an [omakase](https://manuals.omamix.org/3/omacom/76/omakase-computing) Linux distribution based on [Arch](https://archlinux.org/), the tiling window manager [Hyprland](https://hypr.land/), and the desktop construction-kit [Quickshell](https://quickshell.org/). It ships with everything a modern, savvy computer user needs to be productive immediately. From [Neovim](https://neovim.io/) (btw) to Chromium, [Obsidian](https://obsidian.md/) to LibreOffice, and Kdenlive to OBS Studio. Hell, even a retro Winamp-style music player is there!
|
||||||
|
|
||||||
This isn't just a grab bag of preinstalled packages, though. It's a complete system designed with both aesthetics and productivity in mind. Because a _beautiful_ system is a _motivating_ system, and productivity has always been [downstream from motivation](https://world.hey.com/dhh/beautiful-motivations-6fef7c73). There's zero bloat here: Just everything I use.
|
This isn't just a grab bag of preinstalled packages, though. It's a complete system designed with both aesthetics and productivity in mind. Because a _beautiful_ system is a _motivating_ system, and productivity has always been [downstream from motivation](https://world.hey.com/dhh/beautiful-motivations-6fef7c73). There's zero bloat here: Just everything I use.
|
||||||
|
|
||||||
|
|||||||
@@ -34,11 +34,9 @@ Omarchy's default layout is called dwindle. It keeps all the windows you open on
|
|||||||
|
|
||||||
But you can also choose to turn a workspace into the scrolling layout where windows are lined up side-by-side, beyond the visible edge of the display. You turn a single workspace into this layout via `Super + L`.
|
But you can also choose to turn a workspace into the scrolling layout where windows are lined up side-by-side, beyond the visible edge of the display. You turn a single workspace into this layout via `Super + L`.
|
||||||
|
|
||||||
Pressing `Super + L` again turns the workspace floating, where windows overlap freely and you place them yourself, and a third press returns it to dwindle. `Super + Alt + L` goes through them the other way. A window that floats anyway — one you popped out with `Super + T`, or an app that always opens floating — keeps floating when the workspace goes back to tiling. The top bar marks the workspace you're on with its layout: a square for dwindle, a circle for scrolling, and a triangle for floating. Clicking that mark cycles the layout too.
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
The choice is per workspace, and it sticks. So you can keep workspace 1 on dwindle for browsing and workspace 2 on scrolling for code, and they'll come back that way after a restart.
|
The choice is per workspace, and it sticks. So you can keep workspace 1 on dwindle for browsing and workspace 2 on scrolling for code, and they'll come back that way after a restart. (The same toggle is under _Trigger > Toggle > Workspace Layout_ in the Omarchy menu).
|
||||||
|
|
||||||
If you wish to use the scrolling layout as the default, you can set that in `~/.config/hypr/looknfeel.lua`:
|
If you wish to use the scrolling layout as the default, you can set that in `~/.config/hypr/looknfeel.lua`:
|
||||||
|
|
||||||
@@ -50,12 +48,6 @@ hl.config({
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
### Floating workspaces
|
|
||||||
|
|
||||||
A floating workspace works like a traditional desktop: windows overlap, and you move and size them yourself. Each window gets a titlebar in your theme's colors, with buttons to maximize and close. Click a window to bring it forward. Resize it from any edge or corner. Double-click a titlebar to maximize the window while keeping the top bar in view, and again to get its old size back.
|
|
||||||
|
|
||||||
New workspaces, and any you haven't given a layout of their own with `Super + L`, use the default layout. Pick it under _Trigger > Appearance > Workspace Layout_: Tiling, Scrolling, or Floating. `omarchy-hyprland-workspace-layout-default scrolling` sets it from a terminal.
|
|
||||||
|
|
||||||
### Grouping windows
|
### Grouping windows
|
||||||
|
|
||||||
Windows can be grouped using `Super + G`. Once you're in a group, every window you start while that's active will belong to the group. You can move between these grouped windows using `Super + Ctrl + Arrow Left/Right` or `Super + Alt + 1/2/3/4` to go directly to grouped window in order.
|
Windows can be grouped using `Super + G`. Once you're in a group, every window you start while that's active will belong to the group. You can move between these grouped windows using `Super + Ctrl + Arrow Left/Right` or `Super + Alt + 1/2/3/4` to go directly to grouped window in order.
|
||||||
|
|||||||
@@ -81,15 +81,15 @@ If you'd rather they were always visible, set `alwaysShow` to `true` on the widg
|
|||||||
|
|
||||||
The bar configures itself. You don't have to open a config file to move things.
|
The bar configures itself. You don't have to open a config file to move things.
|
||||||
|
|
||||||
Grab an empty patch of the bar around the center and drag it toward another screen edge, and the bar moves there — left, right, top, or bottom all work, and every widget adapts (vertical bars fall back to compact icon-only forms). A click-and-hold starts the same drag. Double-left-click that same empty space to cycle the bar background from clear to glassy to opaque. And drag any widget to reorder it or throw it into another section.
|
Grab an empty patch of the bar around the center and drag it toward another screen edge, and the bar moves there — left, right, top, or bottom all work, and every widget adapts (vertical bars fall back to compact icon-only forms). A click-and-hold starts the same drag. Double-left-click that same empty space to toggle transparency. And drag any widget to reorder it or throw it into another section.
|
||||||
|
|
||||||
If you'd rather pick from a menu, **Trigger → Appearance → Menu Bar** has the position, and **Bar Background** picks how the bar is drawn: **Opaque Bar**, **Glassy Bar** (see-through, with what's behind it blurred), or **Clear Bar**.
|
If you'd rather pick from a menu, **Style → Menu Bar** has both position and transparency.
|
||||||
|
|
||||||
The same things have commands, which is what you want for a [dotfiles](31-dotfiles.md) setup:
|
The same things have commands, which is what you want for a [dotfiles](31-dotfiles.md) setup:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
omarchy bar position bottom
|
omarchy bar position bottom
|
||||||
omarchy bar background glassy # opaque, glassy, none, or cycle
|
omarchy bar transparent toggle
|
||||||
omarchy bar move omarchy.clock --section center --index 0
|
omarchy bar move omarchy.clock --section center --index 0
|
||||||
omarchy bar set omarchy.clock format "HH:mm"
|
omarchy bar set omarchy.clock format "HH:mm"
|
||||||
omarchy bar defaults # back to the shipped layout
|
omarchy bar defaults # back to the shipped layout
|
||||||
@@ -104,7 +104,7 @@ omarchy plugin disable omarchy.weather
|
|||||||
|
|
||||||
## Hiding the bar
|
## Hiding the bar
|
||||||
|
|
||||||
`Super + Shift + Space` toggles the bar off and back on without killing the shell — panels and hotkeys keep working, you just get the pixels back. It's also in the menu under **Trigger → Appearance → Menu Bar → Hide Bar**.
|
`Super + Shift + Space` toggles the bar off and back on without killing the shell — panels and hotkeys keep working, you just get the pixels back. It's also in the menu under **Trigger → Toggle → Menu Bar**.
|
||||||
|
|
||||||
## The config file
|
## The config file
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ All of it is stored in `~/.config/omarchy/shell.json`, under the `bar` key. Here
|
|||||||
"version": 1,
|
"version": 1,
|
||||||
"bar": {
|
"bar": {
|
||||||
"position": "top",
|
"position": "top",
|
||||||
"background": "opaque",
|
"transparent": false,
|
||||||
"centerAnchor": "omarchy.clock",
|
"centerAnchor": "omarchy.clock",
|
||||||
"layout": {
|
"layout": {
|
||||||
"left": [{ "id": "omarchy.menu" }, { "id": "omarchy.workspaces" }],
|
"left": [{ "id": "omarchy.menu" }, { "id": "omarchy.workspaces" }],
|
||||||
|
|||||||
+27
-28
@@ -15,8 +15,7 @@ You can see all the main keyboard bindings with `Super + K` (Tmux bindings with
|
|||||||
| `Super + T` | Toggle window between tiling/floating |
|
| `Super + T` | Toggle window between tiling/floating |
|
||||||
| `Super + J` | Toggle window position (horizontal/vertical) |
|
| `Super + J` | Toggle window position (horizontal/vertical) |
|
||||||
| `Super + O` | Toggle popping window into sticky'n'floating |
|
| `Super + O` | Toggle popping window into sticky'n'floating |
|
||||||
| `Super + L` | Cycle through the dwindle, scrolling, and floating layouts |
|
| `Super + L` | Toggle between dwindle and scrolling layout |
|
||||||
| `Super + Alt + L` | Cycle through the layouts in reverse |
|
|
||||||
| `Super + P` | Toggle pseudo window style (natural v stretch) |
|
| `Super + P` | Toggle pseudo window style (natural v stretch) |
|
||||||
| `Super + F` | Go full screen |
|
| `Super + F` | Go full screen |
|
||||||
| `Super + Alt + F` | Go full width |
|
| `Super + Alt + F` | Go full width |
|
||||||
@@ -340,36 +339,36 @@ You can use `Super + Ctrl + E` to show a complete emoji picker that'll put the s
|
|||||||
|
|
||||||
| Hotkey | EM | Clue |
|
| Hotkey | EM | Clue |
|
||||||
| ------------ | -- | ---------- |
|
| ------------ | -- | ---------- |
|
||||||
| `Shift + CapsLock M S` | 😄 | smile |
|
| `CapsLock M S` | 😄 | smile |
|
||||||
| `Shift + CapsLock M C` | 😂 | cry |
|
| `CapsLock M C` | 😂 | cry |
|
||||||
| `Shift + CapsLock M L` | 😍 | love |
|
| `CapsLock M L` | 😍 | love |
|
||||||
| `Shift + CapsLock M V` | ✌️ | victory |
|
| `CapsLock M V` | ✌️ | victory |
|
||||||
| `Shift + CapsLock M H` | ❤️ | heart |
|
| `CapsLock M H` | ❤️ | heart |
|
||||||
| `Shift + CapsLock M Y` | 👍 | yes |
|
| `CapsLock M Y` | 👍 | yes |
|
||||||
| `Shift + CapsLock M N` | 👎 | no |
|
| `CapsLock M N` | 👎 | no |
|
||||||
| `Shift + CapsLock M F` | 🖕 | fuck |
|
| `CapsLock M F` | 🖕 | fuck |
|
||||||
| `Shift + CapsLock M W` | 🤞 | wish |
|
| `CapsLock M W` | 🤞 | wish |
|
||||||
| `Shift + CapsLock M R` | 🤘 | rock |
|
| `CapsLock M R` | 🤘 | rock |
|
||||||
| `Shift + CapsLock M K` | 😘 | kiss |
|
| `CapsLock M K` | 😘 | kiss |
|
||||||
| `Shift + CapsLock M E` | 🙄 | eyeroll |
|
| `CapsLock M E` | 🙄 | eyeroll |
|
||||||
| `Shift + CapsLock M I` | 😉 | wink |
|
| `CapsLock M I` | 😉 | wink |
|
||||||
| `Shift + CapsLock M P` | 🙏 | pray |
|
| `CapsLock M P` | 🙏 | pray |
|
||||||
| `Shift + CapsLock M D` | 🤤 | drool |
|
| `CapsLock M D` | 🤤 | drool |
|
||||||
| `Shift + CapsLock M M` | 💰 | money |
|
| `CapsLock M M` | 💰 | money |
|
||||||
| `Shift + CapsLock M X` | 🎉 | xellebrate |
|
| `CapsLock M X` | 🎉 | xellebrate |
|
||||||
| `Shift + CapsLock M 1` | 💯 | 100% |
|
| `CapsLock M 1` | 💯 | 100% |
|
||||||
| `Shift + CapsLock M T` | 🥂 | toast |
|
| `CapsLock M T` | 🥂 | toast |
|
||||||
| `Shift + CapsLock M O` |👌 | ok |
|
| `CapsLock M O` |👌 | ok |
|
||||||
| `Shift + CapsLock M G` |👋 | greeting |
|
| `CapsLock M G` |👋 | greeting |
|
||||||
| `Shift + CapsLock M A` |💪 | arm |
|
| `CapsLock M A` |💪 | arm |
|
||||||
| `Shift + CapsLock M B` |🤯 | blowing |
|
| `CapsLock M B` |🤯 | blowing |
|
||||||
|
|
||||||
## Quick Completions
|
## Quick Completions
|
||||||
|
|
||||||
| Hotkey | Completion |
|
| Hotkey | Completion |
|
||||||
| ------------ | ---------- |
|
| ------------ | ---------- |
|
||||||
| `Shift + CapsLock Space Space` | — (mdash) |
|
| `CapsLock Space Space` | — (mdash) |
|
||||||
| `Shift + CapsLock Space N` | Your name (as entered on setup) |
|
| `CapsLock Space N` | Your name (as entered on setup) |
|
||||||
| `Shift + CapsLock Space E` | Your email (as entered on setup) |
|
| `CapsLock Space E` | Your email (as entered on setup) |
|
||||||
|
|
||||||
You can add more of your own by editing `~/.XCompose`, then running `omarchy-restart-xcompose` in the terminal to get the changes picked up.
|
You can add more of your own by editing `~/.XCompose`, then running `omarchy-restart-xcompose` in the terminal to get the changes picked up.
|
||||||
@@ -4,7 +4,7 @@ A lot of what you change day to day isn't really a setting. It's a mode you flip
|
|||||||
|
|
||||||
### The toggle menu
|
### The toggle menu
|
||||||
|
|
||||||
`Super + Ctrl + O` opens _Trigger > Toggle_ directly, or you can walk there from the Omarchy menu (`Super + Space`). Everything in that list is a switch you can flip without thinking about where the state lives. Switches for how the desktop looks sit next to it, under _Trigger > Appearance_.
|
`Super + Ctrl + O` opens _Trigger > Toggle_ directly, or you can walk there from the Omarchy menu (`Super + Space`). Everything in that list is a switch you can flip without thinking about where the state lives.
|
||||||
|
|
||||||
From the terminal, the same switches are `omarchy toggle <thing>`. Run `omarchy toggle` on its own to see the whole group.
|
From the terminal, the same switches are `omarchy toggle <thing>`. Run `omarchy toggle` on its own to see the whole group.
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ From the terminal, the same switches are `omarchy toggle <thing>`. Run `omarchy
|
|||||||
|
|
||||||
The touchpad, touchscreen, and hybrid GPU switches live under _Trigger > Hardware_ (`Super + Ctrl + H`) rather than under Toggle, since they only show up when you actually have that hardware. The touchpad and touchscreen ones survive a Hyprland reload — the disabled device's name is saved to a small state file that Hyprland reads on startup to disable it again.
|
The touchpad, touchscreen, and hybrid GPU switches live under _Trigger > Hardware_ (`Super + Ctrl + H`) rather than under Toggle, since they only show up when you actually have that hardware. The touchpad and touchscreen ones survive a Hyprland reload — the disabled device's name is saved to a small state file that Hyprland reads on startup to disable it again.
|
||||||
|
|
||||||
_Trigger > Appearance_ holds the menu bar and animations, plus a few things that aren't `omarchy toggle` commands but behave the same: battery percentage in the bar, the default workspace layout, window gaps (`Super + Shift + Backspace`), and the 1-window square aspect (`Super + Ctrl + Backspace`).
|
The Toggle menu also carries a few things that aren't `omarchy toggle` commands but behave the same: battery percentage in the bar, workspace layout (`Super + L`), window gaps (`Super + Shift + Backspace`), and the 1-window square aspect (`Super + Ctrl + Backspace`).
|
||||||
|
|
||||||
Most of these are just a flag file under `~/.local/state/omarchy/toggles/`. If you want to branch on one in a script, `omarchy-toggle-enabled` gives you an exit code instead of making you go looking:
|
Most of these are just a flag file under `~/.local/state/omarchy/toggles/`. If you want to branch on one in a script, `omarchy-toggle-enabled` gives you an exit code instead of making you go looking:
|
||||||
|
|
||||||
|
|||||||
+12
-6
@@ -69,12 +69,6 @@ You start LibreOffice via the application launcher (`Super + Space`).
|
|||||||
|
|
||||||
You start Hype via the application launcher (`Super + Space`). Press `?` inside it to see every shortcut.
|
You start Hype via the application launcher (`Super + Space`). Press `?` inside it to see every shortcut.
|
||||||
|
|
||||||
## Signed
|
|
||||||
|
|
||||||
[Signed](https://github.com/omacom/signed) is Omarchy's own dead-simple way to sign PDFs and fill them in. Put your saved signature, text, and today's date anywhere on a page, then save a signed copy beside the original. See [Filling out PDFs](27-filling-out-pdfs.md) for how.
|
|
||||||
|
|
||||||
You start Signed via the application launcher (`Super + Space`), or open a PDF with it from the file manager.
|
|
||||||
|
|
||||||
## Omacalc
|
## Omacalc
|
||||||
|
|
||||||
[Omacalc](https://github.com/omacom-io/omacalc) is Omarchy's own dead-simple calculator, which opens in a floating window.
|
[Omacalc](https://github.com/omacom-io/omacalc) is Omarchy's own dead-simple calculator, which opens in a floating window.
|
||||||
@@ -93,6 +87,18 @@ You start Signal with `Super + Shift + G`. It's not part of the base install, so
|
|||||||
|
|
||||||
You start mpv via the application launcher (`Super + Space`) or just double-click on a video in the file manager.
|
You start mpv via the application launcher (`Super + Space`) or just double-click on a video in the file manager.
|
||||||
|
|
||||||
|
## OBS Studio
|
||||||
|
|
||||||
|
[OBS Studio](https://obsproject.com/) lets you record or stream video from multiple inputs. You can mix a screencast with a webcam with a microphone input. It's what was used to record the Omarchy screencasts.
|
||||||
|
|
||||||
|
You start OBS Studio via the application launcher (`Super + Space`).
|
||||||
|
|
||||||
|
## Kdenlive
|
||||||
|
|
||||||
|
[Kdenlive](https://kdenlive.org/) is an excellent video editor. Perfect for working on video that comes out of OBS Studio before sharing it.
|
||||||
|
|
||||||
|
You start Kdenlive via the application launcher (`Super + Space`).
|
||||||
|
|
||||||
## Omacut
|
## Omacut
|
||||||
|
|
||||||
[Omacut](https://github.com/omacom-io/omacut) is Omarchy's own dead-simple video trimmer. When all you need is to cut the start and end off a clip, it beats firing up a full video editor.
|
[Omacut](https://github.com/omacom-io/omacut) is Omarchy's own dead-simple video trimmer. When all you need is to cut the start and end off a clip, it beats firing up a full video editor.
|
||||||
|
|||||||
@@ -2,10 +2,8 @@
|
|||||||
|
|
||||||
Omarchy ships with a nice, basic PDF viewer called Document Viewer. This is the program that'll open any PDFs you just double click on.
|
Omarchy ships with a nice, basic PDF viewer called Document Viewer. This is the program that'll open any PDFs you just double click on.
|
||||||
|
|
||||||
But you can only use Document Viewer to fill out PDFs that have been setup as forms. If you need to fill out PDFs that haven't, or you need to sign a PDF, use [Signed](https://github.com/omacom/signed). Start it via the application launcher (`Super + Space`), or right-click the file, select _Open With..._, and pick Signed.
|
But you can only use Document Viewer to fill out PDFs that have been setup as forms. If you need to fill out PDFs that haven't, or you need to sign a PDF, you'll have to right-click the file, select _Open With..._, and pick Xournal++.
|
||||||
|
|
||||||
Press `T` to type text and `D` to put down today's date. Both land where your mouse pointer is. Drag anything to move it, drag its corner to make it bigger or smaller, and double-click text to change it.
|
Xournal++ will let you write anywhere on a PDF using the T tool. If you need to sign a document, you'll need an image of your signature, and you can use the Image tool to insert this signature and resize it.
|
||||||
|
|
||||||
To sign, you'll need a picture of your signature: a scan, or a well-lit photo of it on white paper. Open the _Signature_ menu (`Shift + S`), choose _Add signature..._, pick the picture, and give it a name. Signed removes the paper and keeps the ink. From then on, `S` puts your signature under the mouse pointer.
|
When you're done filling out the PDF, use _File > Export as PDF_ to save the final version.
|
||||||
|
|
||||||
When you're done, use _Save signed copy..._ (`Ctrl + S`) to save the filled-out PDF beside the original, which is never changed. Press `?` inside Signed to see every shortcut.
|
|
||||||
@@ -101,4 +101,4 @@ For plugin development, see the [shell reference](https://github.com/omacom/omar
|
|||||||
|
|
||||||
Once you've made something you like, put it in a public git repo. That's the whole distribution mechanism — anyone can then run `omarchy plugin add` against your URL and have it running in seconds.
|
Once you've made something you like, put it in a public git repo. That's the whole distribution mechanism — anyone can then run `omarchy plugin add` against your URL and have it running in seconds.
|
||||||
|
|
||||||
To help people actually find it, list it at [plugins.omarchy.org](https://plugins.omarchy.org). That's the marketplace for Omarchy shell plugins, and it's the first place to look when you're wondering whether someone has already built the widget you're about to write. Browse it before you start!
|
To help people actually find it, list it at [omarchyplugins.com](https://omarchyplugins.com). That's the community directory of Omarchy shell plugins, and it's the first place to look when you're wondering whether someone has already built the widget you're about to write. Browse it before you start!
|
||||||
@@ -9,7 +9,7 @@ hl.config({
|
|||||||
input = {
|
input = {
|
||||||
-- Use multiple keyboard layouts and switch between them with Left Alt + Right Alt
|
-- Use multiple keyboard layouts and switch between them with Left Alt + Right Alt
|
||||||
kb_layout = "us,dk",
|
kb_layout = "us,dk",
|
||||||
kb_options = "omarchy:shift_caps_compose,grp:alts_toggle",
|
kb_options = "compose:caps,shift:both_capslock_cancel,grp:alts_toggle",
|
||||||
|
|
||||||
-- Change speed of keyboard repeat
|
-- Change speed of keyboard repeat
|
||||||
repeat_rate = 40,
|
repeat_rate = 40,
|
||||||
@@ -37,7 +37,7 @@ o.window("(Alacritty|kitty|foot)", { scroll_touchpad = 1.5 })
|
|||||||
|
|
||||||
You can [see all the input options](https://wiki.hypr.land/Configuring/Basics/Variables/#input) on the Hyprland wiki for inputs.
|
You can [see all the input options](https://wiki.hypr.land/Configuring/Basics/Variables/#input) on the Hyprland wiki for inputs.
|
||||||
|
|
||||||
CapsLock works as a normal Caps Lock, and `Shift + CapsLock` is the compose key for [quick emojis](07-hotkeys.md#quick-emojis) and [other completions](07-hotkeys.md#quick-completions). If you'd rather have the compose key elsewhere, replace `omarchy:shift_caps_compose` in `kb_options`. For example, this moves the compose key to Right Alt:
|
By default, Omarchy uses CapsLock as the compose key for [quick emojis](07-hotkeys.md#quick-emojis) and [other completions](07-hotkeys.md#quick-completions). If you'd rather use CapsLock as Caps Lock, move the compose key elsewhere by changing `compose:caps` in `kb_options`. For example, this moves the compose key to Right Alt:
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
hl.config({
|
hl.config({
|
||||||
@@ -61,7 +61,7 @@ On Dell XPS laptops with a haptic touchpad, you can also set the click strength
|
|||||||
|
|
||||||
Select Japanese, Korean, Chinese (Simplified, Pinyin), or Chinese (Traditional, Zhuyin) when the installer asks for your keyboard. Omarchy configures the keyboard and matching input engine automatically, including during offline first-boot setup. Japanese uses Mozc, Korean uses standard two-set Hangul, Simplified Chinese uses Pinyin, and Traditional Chinese uses Chewing's standard Zhuyin arrangement. Japanese (US keyboard) provides Mozc with a US keyboard layout.
|
Select Japanese, Korean, Chinese (Simplified, Pinyin), or Chinese (Traditional, Zhuyin) when the installer asks for your keyboard. Omarchy configures the keyboard and matching input engine automatically, including during offline first-boot setup. Japanese uses Mozc, Korean uses standard two-set Hangul, Simplified Chinese uses Pinyin, and Traditional Chinese uses Chewing's standard Zhuyin arrangement. Japanese (US keyboard) provides Mozc with a US keyboard layout.
|
||||||
|
|
||||||
Typing starts in Latin mode. Press `Super + I` to cycle through configured input methods, and `Super + Shift + I` to cycle back. Tap `Shift` on its own to step out of an input method like Pinyin into Latin letters, and tap it again to go back, the way Sogou, Microsoft Pinyin, and macOS work; `Shift` plus a letter still types a capital. On Japanese keyboards, 全角/半角 toggles input, 変換 turns it on, and 無変換 turns it off. On a Korean keyboard layout, dedicated 한/영 and 한자 keys switch Hangul and convert to Hanja. `Ctrl + Space` stays available for Tmux and Herdr; `Shift + CapsLock` stays the compose key.
|
Typing starts in Latin mode. Press `Super + I` to cycle through configured input methods, and `Super + Shift + I` to cycle back. On Japanese keyboards, 全角/半角 toggles input, 変換 turns it on, and 無変換 turns it off. On a Korean keyboard layout, dedicated 한/영 and 한자 keys switch Hangul and convert to Hanja. `Ctrl + Space` stays available for Tmux and Herdr; CapsLock stays the compose key.
|
||||||
|
|
||||||
The keyboard indicator appears on the right of the bar when you have multiple keyboard layouts or input methods. Click it to switch input languages; Japanese displays あ for hiragana. For Japanese character choices, switch to Japanese, type a word such as `nihongo`, then press Space twice. Press Enter to accept your choice. If you also have multiple keyboard layouts, right-click the indicator to cycle those.
|
The keyboard indicator appears on the right of the bar when you have multiple keyboard layouts or input methods. Click it to switch input languages; Japanese displays あ for hiragana. For Japanese character choices, switch to Japanese, type a word such as `nihongo`, then press Space twice. Press Enter to accept your choice. If you also have multiple keyboard layouts, right-click the indicator to cycle those.
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ Use _Setup > Typing > Keyboard Layouts_ to select layouts such as English and Fr
|
|||||||
|
|
||||||
Run `omarchy setup keyboard` or `omarchy setup input` to open the same pickers. To append one language from the command line, use `omarchy setup input mozc`, `hangul`, `pinyin`, or `chewing`. Your custom switching keys are preserved. For alternative engine layouts or keys, install `fcitx5-configtool` with `omarchy pkg add fcitx5-configtool` and launch it from a terminal. Selecting an input language does not change the desktop language.
|
Run `omarchy setup keyboard` or `omarchy setup input` to open the same pickers. To append one language from the command line, use `omarchy setup input mozc`, `hangul`, `pinyin`, or `chewing`. Your custom switching keys are preserved. For alternative engine layouts or keys, install `fcitx5-configtool` with `omarchy pkg add fcitx5-configtool` and launch it from a terminal. Selecting an input language does not change the desktop language.
|
||||||
|
|
||||||
Use `Super + I` to cycle through input methods or keyboard layouts, and `Super + Shift + I` to go back the other way, so with three configured you can move between two neighbours. The input indicator appears on the right of the bar only when more than one input method or layout is configured. This desktop binding works alongside your existing Fcitx switching keys; you can override it in `~/.config/hypr/bindings.lua`. Input engines and the compose sequences use the [Fcitx5](https://fcitx-im.org/) service already running in every session.
|
Use `Super + I` to cycle through input methods or keyboard layouts, and `Super + Shift + I` to go back the other way, so with three configured you can move between two neighbours. The input indicator appears on the right of the bar only when more than one input method or layout is configured. This desktop binding works alongside your existing Fcitx switching keys; you can override it in `~/.config/hypr/bindings.lua`. Tapping Shift alone is not an input switch: Omarchy uses both Shift keys for CapsLock, which changes how input methods see Shift release. Input engines and the CapsLock compose sequences use the [Fcitx5](https://fcitx-im.org/) service already running in every session.
|
||||||
|
|
||||||
### Use ALT as SUPER
|
### Use ALT as SUPER
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ On some keyboards, it's not convenient to use the primary meta key (Windows/cmd
|
|||||||
```lua
|
```lua
|
||||||
hl.config({
|
hl.config({
|
||||||
input = {
|
input = {
|
||||||
kb_options = "omarchy:shift_caps_compose,altwin:swap_alt_win",
|
kb_options = "compose:caps,shift:both_capslock_cancel,altwin:swap_alt_win",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
@@ -8,7 +8,7 @@ Backgrounds can be videos as well as stills. Drop an `mp4`, `m4v`, `mov`, `webm`
|
|||||||
|
|
||||||
Themes can include a short intro for a still background. For `backgrounds/road.webp`, the matching video lives at `backgrounds/intros/road.mp4`. It plays automatically at boot and when switching to a theme with that background selected, then returns to the still. Intro videos stay out of the background picker and never loop.
|
Themes can include a short intro for a still background. For `backgrounds/road.webp`, the matching video lives at `backgrounds/intros/road.mp4`. It plays automatically at boot and when switching to a theme with that background selected, then returns to the still. Intro videos stay out of the background picker and never loop.
|
||||||
|
|
||||||
Turning off _Trigger > Appearance > Animations_ also turns off background intros. Omarchy does this by default in a virtual machine. The `omarchy theme bg intro toggle` command can toggle intros separately. Refreshing a theme or choosing another background within the same theme does not play an intro.
|
Turning off _Toggle > Animations_ also turns off background intros. Omarchy does this by default in a virtual machine. The `omarchy theme bg intro toggle` command can toggle intros separately. Refreshing a theme or choosing another background within the same theme does not play an intro.
|
||||||
|
|
||||||
You can find a huge collection of cool curated backgrounds on https://github.com/dharmx/walls.
|
You can find a huge collection of cool curated backgrounds on https://github.com/dharmx/walls.
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,6 @@ The Apple T2 Security Chip was introduced in 2017. The T2 chip was discontinued
|
|||||||
- MacBook Pro 13-inch (2019, two Thunderbolt 3 ports) – Model: A2159
|
- MacBook Pro 13-inch (2019, two Thunderbolt 3 ports) – Model: A2159
|
||||||
- MacBook Pro 13-inch (2019, four Thunderbolt 3 ports) – Model: A2178
|
- MacBook Pro 13-inch (2019, four Thunderbolt 3 ports) – Model: A2178
|
||||||
- MacBook Pro 15-inch (2019) – Model: A1990
|
- MacBook Pro 15-inch (2019) – Model: A1990
|
||||||
- iMac (Retina 5K, 27-inch, 2020) – Model: A2115 (iMac20,1 and iMac20,2)
|
|
||||||
- MacBook Pro 13-inch (2020, two Thunderbolt 3 ports) – Model: A2265
|
- MacBook Pro 13-inch (2020, two Thunderbolt 3 ports) – Model: A2265
|
||||||
- MacBook Pro 15-inch (2020) – Model: A1990
|
- MacBook Pro 15-inch (2020) – Model: A1990
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,18 @@ Omarchy assumes a 2x high-resolution display, which requires setting `GDK_SCALE`
|
|||||||
|
|
||||||
For Spotify, you can use `Ctrl + Minus` to shrink the UI (and `Ctrl + Plus` to make it bigger).
|
For Spotify, you can use `Ctrl + Minus` to shrink the UI (and `Ctrl + Plus` to make it bigger).
|
||||||
|
|
||||||
|
### Why isn't Caps Lock working?
|
||||||
|
|
||||||
|
In Omarchy, Caps Lock has been designated to be the xcompose key. That's how you get [quick emojis](07-hotkeys.md#quick-emojis) and [other autocompletions](07-hotkeys.md#quick-completions) done. If you really miss using Caps Lock, you can remap the xcompose key to something else by editing `~/.config/hypr/input.lua`, like setting it to the right alt key:
|
||||||
|
|
||||||
|
```
|
||||||
|
hl.config({
|
||||||
|
input = {
|
||||||
|
kb_options = "compose:ralt",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
### My Wi-Fi, Bluetooth, audio, or trackpad just stopped working
|
### My Wi-Fi, Bluetooth, audio, or trackpad just stopped working
|
||||||
|
|
||||||
Before you reboot, try restarting the offending subsystem on its own. _Update > Hardware_ in the Omarchy menu has Wi-Fi, Bluetooth, Audio, and Trackpad, and reloading one of those clears up the majority of "it worked five minutes ago" situations — a Bluetooth headset that won't reconnect, a trackpad that went dead after a suspend, sound that vanished when you unplugged a monitor.
|
Before you reboot, try restarting the offending subsystem on its own. _Update > Hardware_ in the Omarchy menu has Wi-Fi, Bluetooth, Audio, and Trackpad, and reloading one of those clears up the majority of "it worked five minutes ago" situations — a Bluetooth headset that won't reconnect, a trackpad that went dead after a suspend, sound that vanished when you unplugged a monitor.
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ hl.config({
|
|||||||
input = {
|
input = {
|
||||||
-- Use multiple keyboard layouts and switch between them with Left Alt + Right Alt
|
-- Use multiple keyboard layouts and switch between them with Left Alt + Right Alt
|
||||||
kb_layout = "us,fr",
|
kb_layout = "us,fr",
|
||||||
kb_options = "omarchy:shift_caps_compose,grp:alts_toggle",
|
kb_options = "compose:caps,shift:both_capslock_cancel,grp:alts_toggle",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
echo "Drop saved workspace layouts belonging to named workspaces"
|
|
||||||
|
|
||||||
# omarchy-hyprland-workspace-layout-toggle acted on whatever id activeworkspace
|
|
||||||
# reported, and a named workspace reports a negative one. Hyprland reads a
|
|
||||||
# leading "-" as a selector relative to the current workspace, so a layout saved
|
|
||||||
# for one is applied to workspace 1 at every login instead. The command no longer
|
|
||||||
# writes these; this clears the ones already on disk. It wrote to ~/.local/state
|
|
||||||
# whatever XDG_STATE_HOME said, so both are cleared.
|
|
||||||
removed=0
|
|
||||||
|
|
||||||
for state_home in "$HOME/.local/state" "${XDG_STATE_HOME:-}"; do
|
|
||||||
[[ -n $state_home ]] || continue
|
|
||||||
|
|
||||||
layouts_dir="$state_home/omarchy/workspace-layouts"
|
|
||||||
[[ -d $layouts_dir ]] || continue
|
|
||||||
|
|
||||||
for saved in "$layouts_dir"/-*.lua; do
|
|
||||||
if [[ -f $saved ]]; then
|
|
||||||
rm -f -- "$saved"
|
|
||||||
removed=1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
done
|
|
||||||
|
|
||||||
# The package hook reloads Hyprland before migrations run, so the rule from the
|
|
||||||
# file just deleted is already applied to workspace 1. Hyprland watches the files
|
|
||||||
# it required and picks the deletion up on its own, but not for a user who has
|
|
||||||
# turned autoreload off, so ask for one.
|
|
||||||
if (( removed )); then
|
|
||||||
hyprctl reload >/dev/null 2>&1 || true
|
|
||||||
fi
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
echo "Install titlebars for floating workspaces"
|
|
||||||
|
|
||||||
omarchy-pkg-add omarchy-hyprland-titlebars
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
echo "Let a lone Shift switch out of an input method and back"
|
|
||||||
|
|
||||||
# An earlier migration wrote this list empty. Fill only that empty list: a
|
|
||||||
# missing one already falls back to Fcitx's Shift_L, and a filled one is the
|
|
||||||
# user's choice.
|
|
||||||
config="${XDG_CONFIG_HOME:-$HOME/.config}/fcitx5/config"
|
|
||||||
if [[ -f $config ]] && awk '/^\[Hotkey\/AltTriggerKeys\]$/ { in_list = 1; found = 1; next } /^\[/ { in_list = 0 } in_list && /=/ { filled = 1 } END { exit !(found && !filled) }' "$config"; then
|
|
||||||
sed -i --follow-symlinks '/^\[Hotkey\/AltTriggerKeys\]$/a 0=Shift_L' "$config"
|
|
||||||
busctl --user call org.fcitx.Fcitx5 /controller org.fcitx.Fcitx.Controller1 ReloadConfig 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
echo "Name web app windows in their launchers, so titlebars show the app's name"
|
|
||||||
|
|
||||||
# Chromium names a web app window after its URL, and the launcher's
|
|
||||||
# StartupWMClass is how titlebars find the launcher's Name for it. Launchers
|
|
||||||
# that already name a class, and those with custom commands, are left alone.
|
|
||||||
for desktop in "${XDG_DATA_HOME:-$HOME/.local/share}"/applications/*.desktop; do
|
|
||||||
[[ -f $desktop ]] || continue
|
|
||||||
grep -q '^StartupWMClass=' "$desktop" && continue
|
|
||||||
|
|
||||||
exec_line=$(grep -m1 '^Exec=omarchy-launch-webapp ' "$desktop") || continue
|
|
||||||
|
|
||||||
# The installer escaped the URL twice: as one Exec argument, then as desktop
|
|
||||||
# file text. Undo the file layer, then the argument quoting.
|
|
||||||
url=${exec_line#Exec=omarchy-launch-webapp }
|
|
||||||
url=${url//\\\\/\\}
|
|
||||||
if [[ $url == \"*\" ]]; then
|
|
||||||
url=$(sed 's/\\\(.\)/\1/g' <<<"${url:1:${#url}-2}")
|
|
||||||
fi
|
|
||||||
url=${url//%%/%}
|
|
||||||
[[ $url =~ ^https?:// && $url != *[[:space:]]* ]] || continue
|
|
||||||
|
|
||||||
class=$(omarchy-webapp-window-class "$url")
|
|
||||||
target=$(realpath "$desktop")
|
|
||||||
CLASS=${class//\\/\\\\} awk '!done && /^Exec=/ { print; print "StartupWMClass=" ENVIRON["CLASS"]; done = 1; next } { print }' "$target" >"$target.omarchy-migrate" &&
|
|
||||||
cat "$target.omarchy-migrate" >"$target"
|
|
||||||
rm -f "$target.omarchy-migrate"
|
|
||||||
done
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
echo "Save workspace layouts as modes, so a default layout keeps them"
|
|
||||||
|
|
||||||
# Workspace layouts were saved as plain Hyprland rules. Floating and the default
|
|
||||||
# layout read the mode a workspace was given, and a rule names none, so a
|
|
||||||
# workspace set to scrolling would follow a floating default instead. The old
|
|
||||||
# toggle wrote to ~/.local/state whatever XDG_STATE_HOME said, so both are read.
|
|
||||||
for state_home in "$HOME/.local/state" "${XDG_STATE_HOME:-}"; do
|
|
||||||
[[ -n $state_home ]] || continue
|
|
||||||
|
|
||||||
for saved in "$state_home"/omarchy/workspace-layouts/*.lua; do
|
|
||||||
[[ -f $saved ]] || continue
|
|
||||||
sed -i --follow-symlinks 's/^hl\.workspace_rule({ workspace = "\([0-9]*\)", layout = "\([a-z]*\)" })$/o.workspace_mode({ workspace = "\1", mode = "\2" })/' "$saved"
|
|
||||||
done
|
|
||||||
done
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
echo "Keep windows opaque where animations are turned off"
|
|
||||||
|
|
||||||
# Turning animations off used to make windows opaque too. It no longer touches
|
|
||||||
# transparency, so drop that rule from the saved flag, where it would keep
|
|
||||||
# windows opaque whatever Appearance > Window Transparency says, and carry it
|
|
||||||
# over as Window Transparency > Opaque for anyone who has not picked one yet.
|
|
||||||
# omarchy-hyprland-toggle saved flags under ~/.local/state whatever
|
|
||||||
# XDG_STATE_HOME said, while Hyprland reads them from XDG_STATE_HOME, so both
|
|
||||||
# are fixed.
|
|
||||||
for state_home in "$HOME/.local/state" "${XDG_STATE_HOME:-}"; do
|
|
||||||
[[ -n $state_home ]] || continue
|
|
||||||
toggles_dir="$state_home/omarchy/toggles/hypr"
|
|
||||||
[[ -f $toggles_dir/no-animations.lua ]] || continue
|
|
||||||
|
|
||||||
sed -i '/^o\.window("\.\*", { opacity = "1 1" })$/d' "$toggles_dir/no-animations.lua"
|
|
||||||
|
|
||||||
if [[ ! -f $toggles_dir/window-opaque.lua && ! -f $toggles_dir/window-glassy.lua ]]; then
|
|
||||||
cp "$OMARCHY_PATH/default/hypr/toggles/window-opaque.lua" "$toggles_dir/"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
echo "Install Signed, the PDF signing app"
|
|
||||||
|
|
||||||
if [[ ! -f $HOME/.local/state/omarchy/preinstalls-removed ]]; then
|
|
||||||
omarchy-pkg-add signed
|
|
||||||
fi
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
echo "Let herdr's tab bar show the terminal's background, so it turns glassy too"
|
|
||||||
|
|
||||||
config="$HOME/.config/herdr/config.toml"
|
|
||||||
|
|
||||||
# Dotfile managers may own the file or a parent directory through a symlink.
|
|
||||||
# Preserve that layout rather than detaching or editing its target.
|
|
||||||
path="$config"
|
|
||||||
while [[ $path != "$HOME" && $path != / ]]; do
|
|
||||||
if [[ -L $path ]]; then
|
|
||||||
echo "Preserving symlink-managed herdr config: $config"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
path=$(dirname "$path")
|
|
||||||
done
|
|
||||||
|
|
||||||
# Only a tab bar still on the shipped black changes; any other choice is kept,
|
|
||||||
# and a surface_dim of the user's own is never given a second one.
|
|
||||||
if [[ -f $config ]] && grep -qx 'panel_bg = "black"' "$config" && ! grep -q '^[[:space:]]*surface_dim[[:space:]]*=' "$config"; then
|
|
||||||
sed -i 's/^panel_bg = "black"$/panel_bg = "reset"\nsurface_dim = "black"/' "$config"
|
|
||||||
omarchy-restart-herdr || true
|
|
||||||
fi
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
echo "Let Neovim's current line and status line show the terminal background"
|
|
||||||
|
|
||||||
# ~/.config/nvim is copied once from omarchy-nvim, so it misses the package's
|
|
||||||
# later changes. Bring in the transparency file and lualine spec it now ships.
|
|
||||||
config="$HOME/.config/nvim"
|
|
||||||
package="/usr/share/omarchy-nvim/config"
|
|
||||||
files=(plugin/after/transparency.lua lua/plugins/lualine-transparent.lua)
|
|
||||||
|
|
||||||
[[ -d $config ]] || exit 0
|
|
||||||
|
|
||||||
# Dotfile managers may own a file or a parent directory through a symlink.
|
|
||||||
# Preserve that layout rather than detaching or editing its target.
|
|
||||||
for file in "${files[@]}"; do
|
|
||||||
path="$config/$file"
|
|
||||||
while [[ $path != "$HOME" && $path != / ]]; do
|
|
||||||
if [[ -L $path ]]; then
|
|
||||||
echo "Preserving symlink-managed Neovim config: $path"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
path=$(dirname "$path")
|
|
||||||
done
|
|
||||||
done
|
|
||||||
|
|
||||||
# Updates install packages before migrations. An older package leaves this
|
|
||||||
# pending rather than copying files it does not have yet.
|
|
||||||
if [[ ! -f $package/${files[1]} ]]; then
|
|
||||||
echo "Update omarchy-nvim to 2026.9.21-5 or newer before rerunning this migration." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# A copy staged beside its target and moved into place whole, so a failed
|
|
||||||
# write leaves the original for a retry.
|
|
||||||
staged=""
|
|
||||||
trap 'rm -f -- ${staged:+"$staged"}' EXIT
|
|
||||||
install_from_package() {
|
|
||||||
staged=$(mktemp "$config/$1.new.XXXXXX")
|
|
||||||
install -m 0644 "$package/$1" "$staged"
|
|
||||||
mv -fT -- "$staged" "$config/$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Only a transparency file still as Omarchy shipped it is replaced, so one the
|
|
||||||
# user changed is kept.
|
|
||||||
if [[ -f $config/${files[0]} ]]; then
|
|
||||||
case $(sha256sum <"$config/${files[0]}") in
|
|
||||||
bd833dc094e3546b5fad512e61cfb09f3032c2a4461c23be7bd90851de80688e* | \
|
|
||||||
6e31b917f13e16514ac94ff9270d47f24e76509a3e559ca85116a5aa2d61306a* | \
|
|
||||||
33d29360df84ed48c70606580749536520384ec64afe650151d4e26e7922b410*)
|
|
||||||
install_from_package "${files[0]}"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -d $config/lua/plugins && ! -e $config/${files[1]} ]]; then
|
|
||||||
install_from_package "${files[1]}"
|
|
||||||
fi
|
|
||||||
@@ -353,7 +353,6 @@ QtObject {
|
|||||||
readonly property int iconSlot: root.barToken("icon-slot", 27)
|
readonly property int iconSlot: root.barToken("icon-slot", 27)
|
||||||
readonly property int iconCanvas: root.barToken("icon-canvas", 16)
|
readonly property int iconCanvas: root.barToken("icon-canvas", 16)
|
||||||
readonly property int iconFont: root.barToken("icon-font", 13)
|
readonly property int iconFont: root.barToken("icon-font", 13)
|
||||||
readonly property int iconSize: Math.min(iconCanvas, root.barToken("icon-size", 12))
|
|
||||||
readonly property int statusSlot: root.barToken("status-slot", 21)
|
readonly property int statusSlot: root.barToken("status-slot", 21)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,9 +424,7 @@ QtObject {
|
|||||||
} else if (section === "bar") {
|
} else if (section === "bar") {
|
||||||
if (key === "scale-with-font") {
|
if (key === "scale-with-font") {
|
||||||
nextBarScaleWithFont = boolToken(raw, nextBarScaleWithFont)
|
nextBarScaleWithFont = boolToken(raw, nextBarScaleWithFont)
|
||||||
} else if (key === "size-horizontal" || key === "size-vertical" || key === "notch-height"
|
} else if (key === "size-horizontal" || key === "size-vertical" || key === "notch-height") {
|
||||||
|| key === "icon-slot" || key === "icon-canvas" || key === "icon-font"
|
|
||||||
|| key === "icon-size" || key === "status-slot") {
|
|
||||||
var b = parseInt(raw, 10)
|
var b = parseInt(raw, 10)
|
||||||
if (isFinite(b)) barOut[key] = b
|
if (isFinite(b)) barOut[key] = b
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,8 +18,6 @@ Item {
|
|||||||
property size decodeSize: Qt.size(0, 0)
|
property size decodeSize: Qt.size(0, 0)
|
||||||
readonly property var current: imageLoader.item
|
readonly property var current: imageLoader.item
|
||||||
readonly property bool ready: current ? current.ready : false
|
readonly property bool ready: current ? current.ready : false
|
||||||
// The file behind path could not be loaded, as when it was deleted.
|
|
||||||
readonly property bool failed: current ? current.failed : false
|
|
||||||
readonly property bool video: Util.isVideoPath(path)
|
readonly property bool video: Util.isVideoPath(path)
|
||||||
// Cache-bust images selected in a running lock session, so a theme switch
|
// Cache-bust images selected in a running lock session, so a theme switch
|
||||||
// that replaces the file behind an unchanged path shows the new pixels.
|
// that replaces the file behind an unchanged path shows the new pixels.
|
||||||
@@ -37,7 +35,6 @@ Item {
|
|||||||
|
|
||||||
Image {
|
Image {
|
||||||
readonly property bool ready: status === Image.Ready
|
readonly property bool ready: status === Image.Ready
|
||||||
readonly property bool failed: status === Image.Error
|
|
||||||
source: !root.constrainDecode || root.decodeSize.width > 0 ? root.imageUrl : ""
|
source: !root.constrainDecode || root.decodeSize.width > 0 ? root.imageUrl : ""
|
||||||
fillMode: Image.PreserveAspectCrop
|
fillMode: Image.PreserveAspectCrop
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
|
|||||||
+28
-67
@@ -8,91 +8,52 @@ WidgetButton {
|
|||||||
property Component iconComponent: null
|
property Component iconComponent: null
|
||||||
property real slotSize: Style.bar.iconSlot
|
property real slotSize: Style.bar.iconSlot
|
||||||
property real opticalSize: Style.bar.iconCanvas
|
property real opticalSize: Style.bar.iconCanvas
|
||||||
property real iconSize: Math.min(Style.bar.iconSize, opticalSize)
|
|
||||||
readonly property real visualIconSize: Style.bar.iconSize
|
|
||||||
readonly property real canvasSize: Math.max(visualIconSize, opticalSize)
|
|
||||||
property string labelText: ""
|
|
||||||
property bool debugOpticalBounds: Quickshell.env("OMARCHY_DEBUG_BAR_ICONS") === "1"
|
property bool debugOpticalBounds: Quickshell.env("OMARCHY_DEBUG_BAR_ICONS") === "1"
|
||||||
// A label shifts the icon within the centered group.
|
// Measured against the slot, which the open-panel underline centers on.
|
||||||
readonly property real opticalCenterErrorX:
|
readonly property real opticalCenterErrorX: glyph.visible ? opticalCanvas.x + glyph.paintedCenterX - root.width / 2 : 0
|
||||||
content.x + opticalCanvas.x + (glyph.visible ? glyph.paintedCenterX : customIcon.width / 2 + customIcon.centerErrorX) - root.width / 2
|
readonly property real glyphPaintedWidth: glyph.visible ? glyph.tightWidth : 0
|
||||||
- (label.visible ? (label.implicitWidth + Style.space(4)) / 2 : 0)
|
|
||||||
readonly property real opticalCenterErrorY:
|
|
||||||
content.y + (glyph.visible ? glyph.paintedCenterY : customIcon.height / 2 + customIcon.centerErrorY) - root.height / 2
|
|
||||||
readonly property real glyphPaintedWidth: glyph.visible ? glyph.paintedWidth : 0
|
|
||||||
readonly property real glyphPaintedHeight: glyph.visible ? glyph.paintedHeight : 0
|
|
||||||
readonly property real glyphBaselineY: glyph.visible ? glyph.baselineY : 0
|
readonly property real glyphBaselineY: glyph.visible ? glyph.baselineY : 0
|
||||||
readonly property int glyphFontSize: glyph.visible ? glyph.renderedFontSize : 0
|
readonly property int glyphFontSize: glyph.visible ? glyph.renderedFontSize : 0
|
||||||
readonly property real componentPaintedWidth: customIcon.visible ? customIcon.paintedWidth : 0
|
|
||||||
readonly property real componentPaintedHeight: customIcon.visible ? customIcon.paintedHeight : 0
|
|
||||||
readonly property rect componentSourceBounds: customIcon.sourceBounds
|
|
||||||
|
|
||||||
labelVisible: false
|
labelVisible: false
|
||||||
hasVisualContent: text !== "" || iconComponent !== null || labelText !== ""
|
hasVisualContent: text !== "" || iconComponent !== null
|
||||||
fontSize: Style.bar.iconFont
|
fontSize: Style.bar.iconFont
|
||||||
fixedWidth: vertical ? -1 : slotSize
|
fixedWidth: vertical ? -1 : slotSize
|
||||||
fixedHeight: vertical ? slotSize : -1
|
fixedHeight: vertical ? slotSize : -1
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: content
|
id: opticalCanvas
|
||||||
// Exact coordinates preserve the center of odd-width slots.
|
// Placed exactly, not anchored: centerIn snaps an even canvas in an odd slot
|
||||||
|
// to a whole pixel, pulling every glyph off the open-panel underline.
|
||||||
x: (root.width - width) / 2
|
x: (root.width - width) / 2
|
||||||
y: (root.height - height) / 2
|
y: (root.height - height) / 2
|
||||||
width: root.canvasSize + (label.visible ? label.implicitWidth + Style.space(4) : 0)
|
width: root.opticalSize
|
||||||
height: root.canvasSize
|
height: root.opticalSize
|
||||||
|
|
||||||
Text {
|
OpticalGlyph {
|
||||||
id: label
|
id: glyph
|
||||||
visible: root.labelText !== ""
|
anchors.fill: parent
|
||||||
textFormat: Text.PlainText
|
visible: root.iconComponent === null
|
||||||
text: root.labelText
|
text: root.text
|
||||||
font.family: root.fontFamily
|
fontFamily: root.fontFamily
|
||||||
font.pixelSize: root.fontSize
|
fontSize: root.fontSize
|
||||||
color: root.active && root.useActiveColor ? root.activeColor : root.foreground
|
color: root.active && root.useActiveColor ? root.activeColor : root.foreground
|
||||||
y: (parent.height - height) / 2
|
rotation: root.textRotation
|
||||||
+ (labelMetrics.descent - labelMetrics.ascent + labelMetrics.tightBoundingRect("0").height) / 2
|
debugBounds: root.debugOpticalBounds
|
||||||
renderType: Text.NativeRendering
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FontMetrics {
|
Loader {
|
||||||
id: labelMetrics
|
anchors.fill: parent
|
||||||
font: label.font
|
visible: root.iconComponent !== null
|
||||||
|
sourceComponent: root.iconComponent
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Rectangle {
|
||||||
id: opticalCanvas
|
visible: root.debugOpticalBounds && root.iconComponent !== null
|
||||||
x: label.visible ? label.implicitWidth + Style.space(4) : 0
|
anchors.fill: parent
|
||||||
width: root.canvasSize
|
color: "transparent"
|
||||||
height: root.canvasSize
|
border.width: 1
|
||||||
|
border.color: "#4488ff"
|
||||||
OpticalGlyph {
|
|
||||||
id: glyph
|
|
||||||
anchors.fill: parent
|
|
||||||
visible: root.iconComponent === null
|
|
||||||
text: root.text
|
|
||||||
fontFamily: root.fontFamily
|
|
||||||
fontSize: root.fontSize
|
|
||||||
paintedSize: root.visualIconSize
|
|
||||||
color: root.active && root.useActiveColor ? root.activeColor : root.foreground
|
|
||||||
rotation: root.textRotation
|
|
||||||
debugBounds: root.debugOpticalBounds
|
|
||||||
}
|
|
||||||
|
|
||||||
BarIconContent {
|
|
||||||
id: customIcon
|
|
||||||
anchors.fill: parent
|
|
||||||
visible: root.iconComponent !== null
|
|
||||||
sourceComponent: root.iconComponent
|
|
||||||
sourceSize: root.opticalSize
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
visible: root.debugOpticalBounds && root.iconComponent !== null
|
|
||||||
anchors.fill: parent
|
|
||||||
color: "transparent"
|
|
||||||
border.width: 1
|
|
||||||
border.color: "#4488ff"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
import QtQuick
|
|
||||||
import qs.Commons
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
property Component sourceComponent: null
|
|
||||||
property real sourceSize: Style.bar.iconCanvas
|
|
||||||
readonly property rect sourceBounds: bounds.mappedBounds
|
|
||||||
readonly property real contentScale: sourceBounds.width > 0 && sourceBounds.height > 0
|
|
||||||
? Style.bar.iconSize / Math.max(sourceBounds.width, sourceBounds.height) : 1
|
|
||||||
readonly property real paintedWidth: sourceBounds.width * contentScale
|
|
||||||
readonly property real paintedHeight: sourceBounds.height * contentScale
|
|
||||||
readonly property real centerErrorX: content.x + (sourceBounds.x + sourceBounds.width / 2) * contentScale - width / 2
|
|
||||||
readonly property real centerErrorY: content.y + (sourceBounds.y + sourceBounds.height / 2) * contentScale - height / 2
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: content
|
|
||||||
sourceComponent: root.sourceComponent
|
|
||||||
onLoaded: {
|
|
||||||
// Keep declared dimensions. Empty wrapper items receive a source canvas.
|
|
||||||
if (!(item instanceof Image)) {
|
|
||||||
if (item.width <= 0) item.width = Qt.binding(function() { return root.sourceSize })
|
|
||||||
if (item.height <= 0) item.height = Qt.binding(function() { return root.sourceSize })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
transformOrigin: Item.TopLeft
|
|
||||||
scale: root.contentScale
|
|
||||||
x: root.width / 2 - (root.sourceBounds.x + root.sourceBounds.width / 2) * scale
|
|
||||||
y: root.height / 2 - (root.sourceBounds.y + root.sourceBounds.height / 2) * scale
|
|
||||||
}
|
|
||||||
|
|
||||||
IconContentBounds {
|
|
||||||
id: bounds
|
|
||||||
sourceItem: content.item
|
|
||||||
boundsParent: content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -13,12 +13,9 @@ BarIconButton {
|
|||||||
property string indicatorBlock: "single"
|
property string indicatorBlock: "single"
|
||||||
property var indicatorHost: null
|
property var indicatorHost: null
|
||||||
property var activeOverride: null
|
property var activeOverride: null
|
||||||
// An indicator with nothing to turn on, such as a remote session, shows only
|
|
||||||
// while it is active, never among the inactive ones a hover reveals.
|
|
||||||
property bool revealWhenInactive: true
|
|
||||||
readonly property bool effectiveActive: activeOverride === null || activeOverride === undefined ? active : activeOverride === true
|
readonly property bool effectiveActive: activeOverride === null || activeOverride === undefined ? active : activeOverride === true
|
||||||
readonly property bool belongsInBlock: indicatorBlock === "active" ? effectiveActive : (indicatorBlock === "inactive" ? !effectiveActive && revealWhenInactive : true)
|
readonly property bool belongsInBlock: indicatorBlock === "active" ? effectiveActive : (indicatorBlock === "inactive" ? !effectiveActive : true)
|
||||||
readonly property bool inactiveRevealed: !effectiveActive && revealWhenInactive && !!indicatorHost && indicatorHost.revealInactiveIndicators
|
readonly property bool inactiveRevealed: !effectiveActive && !!indicatorHost && indicatorHost.revealInactiveIndicators
|
||||||
|
|
||||||
function extractData(raw) {
|
function extractData(raw) {
|
||||||
return Util.parseModuleJson(raw)
|
return Util.parseModuleJson(raw)
|
||||||
@@ -46,6 +43,7 @@ BarIconButton {
|
|||||||
useActiveColor: false
|
useActiveColor: false
|
||||||
maintainIndicatorReveal: indicatorBlock === "inactive"
|
maintainIndicatorReveal: indicatorBlock === "inactive"
|
||||||
revealHost: indicatorHost
|
revealHost: indicatorHost
|
||||||
|
fontSize: Style.font.caption
|
||||||
horizontalMargin: 5
|
horizontalMargin: 5
|
||||||
verticalPadding: 5
|
verticalPadding: 5
|
||||||
fixedWidth: vertical ? -1 : Style.bar.statusSlot
|
fixedWidth: vertical ? -1 : Style.bar.statusSlot
|
||||||
|
|||||||
@@ -1,141 +0,0 @@
|
|||||||
import QtQuick
|
|
||||||
import QtQuick.Shapes
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
property Item sourceItem: null
|
|
||||||
property Item boundsParent: null
|
|
||||||
property rect mappedBounds: Qt.rect(0, 0, 0, 0)
|
|
||||||
visible: false
|
|
||||||
|
|
||||||
readonly property bool textItem: sourceItem instanceof Text
|
|
||||||
readonly property bool imageItem: sourceItem instanceof Image
|
|
||||||
readonly property bool shapeItem: sourceItem instanceof Shape
|
|
||||||
readonly property bool boxItem: sourceItem instanceof Rectangle
|
|
||||||
|| sourceItem instanceof Canvas || sourceItem instanceof ShaderEffect
|
|
||||||
|
|
||||||
function unionBounds(a, b) {
|
|
||||||
if (b.width <= 0 || b.height <= 0) return a
|
|
||||||
if (a.width <= 0 || a.height <= 0) return b
|
|
||||||
var x = Math.min(a.x, b.x)
|
|
||||||
var y = Math.min(a.y, b.y)
|
|
||||||
return Qt.rect(x, y, Math.max(a.x + a.width, b.x + b.width) - x,
|
|
||||||
Math.max(a.y + a.height, b.y + b.height) - y)
|
|
||||||
}
|
|
||||||
|
|
||||||
function shapeBounds(item) {
|
|
||||||
var bounds = item.boundingRect
|
|
||||||
var sx = 1
|
|
||||||
var sy = 1
|
|
||||||
if (item.fillMode !== Shape.NoResize && item.implicitWidth > 0 && item.implicitHeight > 0) {
|
|
||||||
sx = item.width / item.implicitWidth
|
|
||||||
sy = item.height / item.implicitHeight
|
|
||||||
if (item.fillMode === Shape.PreserveAspectFit) sx = sy = Math.min(sx, sy)
|
|
||||||
else if (item.fillMode === Shape.PreserveAspectCrop) sx = sy = Math.max(sx, sy)
|
|
||||||
}
|
|
||||||
var spareWidth = item.width - item.implicitWidth * sx
|
|
||||||
var spareHeight = item.height - item.implicitHeight * sy
|
|
||||||
var x = item.horizontalAlignment === Shape.AlignHCenter ? spareWidth / 2
|
|
||||||
: (item.horizontalAlignment === Shape.AlignRight ? spareWidth : 0)
|
|
||||||
var y = item.verticalAlignment === Shape.AlignVCenter ? spareHeight / 2
|
|
||||||
: (item.verticalAlignment === Shape.AlignBottom ? spareHeight : 0)
|
|
||||||
return Qt.rect(x + bounds.x * sx, y + bounds.y * sy, bounds.width * sx, bounds.height * sy)
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly property rect paintedBounds: {
|
|
||||||
var item = sourceItem
|
|
||||||
var bounds = Qt.rect(0, 0, 0, 0)
|
|
||||||
if (!item || !item.visible || item.opacity <= 0) return bounds
|
|
||||||
if (textItem) {
|
|
||||||
var ink = textMetrics.tightBoundingRect
|
|
||||||
var spareWidth = item.width - item.leftPadding - item.rightPadding - item.contentWidth
|
|
||||||
var textX = item.leftPadding
|
|
||||||
if (item.effectiveHorizontalAlignment === Text.AlignHCenter) textX += spareWidth / 2
|
|
||||||
else if (item.effectiveHorizontalAlignment === Text.AlignRight) textX += spareWidth
|
|
||||||
bounds = Qt.rect(textX + ink.x, item.baselineOffset + ink.y, ink.width, ink.height)
|
|
||||||
} else if (imageItem) {
|
|
||||||
var w = item.paintedWidth
|
|
||||||
var h = item.paintedHeight
|
|
||||||
var x = item.horizontalAlignment === Image.AlignLeft ? 0
|
|
||||||
: (item.horizontalAlignment === Image.AlignRight ? item.width - w : (item.width - w) / 2)
|
|
||||||
var y = item.verticalAlignment === Image.AlignTop ? 0
|
|
||||||
: (item.verticalAlignment === Image.AlignBottom ? item.height - h : (item.height - h) / 2)
|
|
||||||
if (item.fillMode === Image.PreserveAspectFit) {
|
|
||||||
bounds = Qt.rect(x, y, w, h)
|
|
||||||
} else if (item.fillMode === Image.Pad) {
|
|
||||||
var left = Math.max(0, x)
|
|
||||||
var top = Math.max(0, y)
|
|
||||||
bounds = Qt.rect(left, top, Math.max(0, Math.min(item.width, x + w) - left),
|
|
||||||
Math.max(0, Math.min(item.height, y + h) - top))
|
|
||||||
} else {
|
|
||||||
bounds = Qt.rect(0, 0, item.width, item.height)
|
|
||||||
}
|
|
||||||
} else if (shapeItem) {
|
|
||||||
bounds = shapeBounds(item)
|
|
||||||
} else if (boxItem) {
|
|
||||||
bounds = Qt.rect(0, 0, item.width, item.height)
|
|
||||||
}
|
|
||||||
for (var i = 0; i < childrenBounds.count; i++) {
|
|
||||||
var child = childrenBounds.itemAt(i)
|
|
||||||
if (child) bounds = unionBounds(bounds, child.mappedBounds)
|
|
||||||
}
|
|
||||||
if (item.clip && bounds.width > 0 && bounds.height > 0) {
|
|
||||||
var left = Math.max(0, bounds.x)
|
|
||||||
var top = Math.max(0, bounds.y)
|
|
||||||
bounds = Qt.rect(left, top,
|
|
||||||
Math.max(0, Math.min(item.width, bounds.x + bounds.width) - left),
|
|
||||||
Math.max(0, Math.min(item.height, bounds.y + bounds.height) - top))
|
|
||||||
}
|
|
||||||
return bounds
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateMappedBounds() {
|
|
||||||
var b = paintedBounds
|
|
||||||
mappedBounds = sourceItem && boundsParent && b.width > 0 && b.height > 0
|
|
||||||
? sourceItem.mapToItem(boundsParent, b.x, b.y, b.width, b.height)
|
|
||||||
: b
|
|
||||||
}
|
|
||||||
|
|
||||||
function configureSource() {
|
|
||||||
if (sourceItem instanceof Text) sourceItem.renderType = Text.CurveRendering
|
|
||||||
updateMappedBounds()
|
|
||||||
}
|
|
||||||
|
|
||||||
onPaintedBoundsChanged: updateMappedBounds()
|
|
||||||
onSourceItemChanged: configureSource()
|
|
||||||
onBoundsParentChanged: updateMappedBounds()
|
|
||||||
Component.onCompleted: updateMappedBounds()
|
|
||||||
|
|
||||||
TextMetrics {
|
|
||||||
id: textMetrics
|
|
||||||
font: root.textItem ? root.sourceItem.font : Qt.font({ pixelSize: 12 })
|
|
||||||
text: root.textItem ? root.sourceItem.text : ""
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: root.sourceItem
|
|
||||||
function onXChanged() { root.updateMappedBounds() }
|
|
||||||
function onYChanged() { root.updateMappedBounds() }
|
|
||||||
function onWidthChanged() { root.updateMappedBounds() }
|
|
||||||
function onHeightChanged() { root.updateMappedBounds() }
|
|
||||||
function onScaleChanged() { root.updateMappedBounds() }
|
|
||||||
function onRotationChanged() { root.updateMappedBounds() }
|
|
||||||
function onTransformOriginChanged() { root.updateMappedBounds() }
|
|
||||||
}
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
id: childrenBounds
|
|
||||||
model: root.sourceItem ? root.sourceItem.children : []
|
|
||||||
delegate: Loader {
|
|
||||||
id: childLoader
|
|
||||||
required property var modelData
|
|
||||||
readonly property rect mappedBounds: item ? item.mappedBounds : Qt.rect(0, 0, 0, 0)
|
|
||||||
source: Qt.resolvedUrl("IconContentBounds.qml")
|
|
||||||
onLoaded: {
|
|
||||||
item.sourceItem = Qt.binding(function() { return childLoader.modelData })
|
|
||||||
item.boundsParent = Qt.binding(function() { return root.sourceItem })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,22 +8,14 @@ Item {
|
|||||||
property string text: ""
|
property string text: ""
|
||||||
property string fontFamily: Style.font.family
|
property string fontFamily: Style.font.family
|
||||||
property real fontSize: Style.font.body
|
property real fontSize: Style.font.body
|
||||||
property real paintedSize: 0
|
|
||||||
property color color: Commons.Color.foreground
|
property color color: Commons.Color.foreground
|
||||||
property bool debugBounds: false
|
property bool debugBounds: false
|
||||||
|
|
||||||
readonly property int renderedFontSize: Math.max(1, Math.round(fontSize))
|
readonly property int renderedFontSize: Math.max(1, Math.round(fontSize))
|
||||||
readonly property real tightWidth: Math.max(1, glyphMetrics.tightBoundingRect.width)
|
readonly property real tightWidth: Math.max(1, glyphMetrics.tightBoundingRect.width)
|
||||||
readonly property real tightHeight: Math.max(1, glyphMetrics.tightBoundingRect.height)
|
|
||||||
readonly property real paintedScale: paintedSize > 0
|
|
||||||
? Math.min(paintedSize, width, height) / Math.max(tightWidth, tightHeight)
|
|
||||||
: 1
|
|
||||||
readonly property real paintedWidth: tightWidth * paintedScale
|
|
||||||
readonly property real paintedHeight: tightHeight * paintedScale
|
|
||||||
readonly property real horizontalCorrection: glyph.implicitWidth / 2 - (glyphMetrics.tightBoundingRect.x + tightWidth / 2)
|
readonly property real horizontalCorrection: glyph.implicitWidth / 2 - (glyphMetrics.tightBoundingRect.x + tightWidth / 2)
|
||||||
readonly property real paintedCenterX: glyph.x + (glyphMetrics.tightBoundingRect.x + tightWidth / 2) * paintedScale
|
readonly property real paintedCenterX: glyph.x + glyphMetrics.tightBoundingRect.x + tightWidth / 2
|
||||||
readonly property real paintedCenterY: glyph.y + (glyph.baselineOffset + glyphMetrics.tightBoundingRect.y + tightHeight / 2) * paintedScale
|
readonly property real baselineY: glyph.y + glyph.baselineOffset
|
||||||
readonly property real baselineY: glyph.y + glyph.baselineOffset * paintedScale
|
|
||||||
|
|
||||||
TextMetrics {
|
TextMetrics {
|
||||||
id: glyphMetrics
|
id: glyphMetrics
|
||||||
@@ -35,18 +27,17 @@ Item {
|
|||||||
Text {
|
Text {
|
||||||
id: glyph
|
id: glyph
|
||||||
textFormat: Text.PlainText
|
textFormat: Text.PlainText
|
||||||
// Bar icons fit their painted bounds. Text labels retain their line box.
|
// Keep the shared line box and baseline intact. Correcting only the
|
||||||
x: root.width / 2 - (glyphMetrics.tightBoundingRect.x + root.tightWidth / 2) * root.paintedScale
|
// horizontal painted bounds avoids per-glyph vertical drift.
|
||||||
y: root.paintedSize > 0
|
// The correction is fractional, so x is set exactly: centerIn would snap it
|
||||||
? root.height / 2 - (baselineOffset + glyphMetrics.tightBoundingRect.y + root.tightHeight / 2) * root.paintedScale
|
// to a whole pixel and undo it. y still snaps, keeping the baseline crisp.
|
||||||
: Math.round((root.height - height) / 2)
|
x: (root.width - width) / 2 + root.horizontalCorrection
|
||||||
|
y: Math.round((root.height - height) / 2)
|
||||||
text: root.text
|
text: root.text
|
||||||
color: root.color
|
color: root.color
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
font.pixelSize: root.renderedFontSize
|
font.pixelSize: root.renderedFontSize
|
||||||
transformOrigin: Item.TopLeft
|
renderType: Text.NativeRendering
|
||||||
scale: root.paintedScale
|
|
||||||
renderType: root.paintedSize > 0 ? Text.CurveRendering : Text.NativeRendering
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
|||||||
@@ -65,31 +65,11 @@ Item {
|
|||||||
// Width of the painted label, for bar chrome that wants to line up with the
|
// Width of the painted label, for bar chrome that wants to line up with the
|
||||||
// text rather than with the slot it sits in. Zero on icon-only buttons.
|
// text rather than with the slot it sits in. Zero on icon-only buttons.
|
||||||
readonly property real labelWidth: label.visible ? label.implicitWidth : 0
|
readonly property real labelWidth: label.visible ? label.implicitWidth : 0
|
||||||
readonly property bool iconLabel: labelVisible && isIconGlyph(text)
|
|
||||||
readonly property real iconPaintedWidth: iconLabel && iconLoader.item ? iconLoader.item.paintedWidth : 0
|
|
||||||
readonly property real iconPaintedHeight: iconLabel && iconLoader.item ? iconLoader.item.paintedHeight : 0
|
|
||||||
readonly property real iconCenterErrorX: iconLabel && iconLoader.item
|
|
||||||
? iconLoader.x + iconLoader.item.paintedCenterX - width / 2 : 0
|
|
||||||
readonly property real iconCenterErrorY: iconLabel && iconLoader.item
|
|
||||||
? iconLoader.y + iconLoader.item.paintedCenterY - height / 2 : 0
|
|
||||||
|
|
||||||
function isIconGlyph(value) {
|
|
||||||
var text = String(value || "")
|
|
||||||
if (!text) return false
|
|
||||||
var code = text.codePointAt(0)
|
|
||||||
if (text.length !== (code > 0xffff ? 2 : 1)) return false
|
|
||||||
return (code >= 0xe000 && code <= 0xf8ff)
|
|
||||||
|| (code >= 0xf0000 && code <= 0xffffd)
|
|
||||||
|| (code >= 0x100000 && code <= 0x10fffd)
|
|
||||||
|| (code >= 0x2190 && code <= 0x2bff)
|
|
||||||
}
|
|
||||||
|
|
||||||
visible: hasVisualContent || keepSpace
|
visible: hasVisualContent || keepSpace
|
||||||
opacity: !hasVisualContent || concealed ? 0 : (dimmed ? 0.45 : 1)
|
opacity: !hasVisualContent || concealed ? 0 : (dimmed ? 0.45 : 1)
|
||||||
implicitWidth: fixedWidth > 0 ? fixedWidth
|
implicitWidth: fixedWidth > 0 ? fixedWidth : (vertical ? barSize : Math.max(12, label.implicitWidth + scaledHorizontalMargin * 2))
|
||||||
: (vertical ? barSize : (iconLabel ? Style.bar.iconSlot : Math.max(12, label.implicitWidth + scaledHorizontalMargin * 2)))
|
implicitHeight: fixedHeight > 0 ? fixedHeight : (vertical ? Math.max(12, label.implicitHeight + scaledVerticalPadding * 2) : barSize)
|
||||||
implicitHeight: fixedHeight > 0 ? fixedHeight
|
|
||||||
: (vertical ? (iconLabel ? Style.bar.iconSlot : Math.max(12, label.implicitHeight + scaledVerticalPadding * 2)) : barSize)
|
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
NumberAnimation { duration: Style.duration(140); easing.type: Easing.OutCubic }
|
NumberAnimation { duration: Style.duration(140); easing.type: Easing.OutCubic }
|
||||||
@@ -98,7 +78,7 @@ Item {
|
|||||||
Text {
|
Text {
|
||||||
id: label
|
id: label
|
||||||
textFormat: Text.PlainText
|
textFormat: Text.PlainText
|
||||||
visible: root.labelVisible && !root.iconLabel
|
visible: root.labelVisible
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
// Centering the line box puts the figures above the bar's middle, since
|
// Centering the line box puts the figures above the bar's middle, since
|
||||||
// the box keeps room for descenders. Center the figure height instead, so
|
// the box keeps room for descenders. Center the figure height instead, so
|
||||||
@@ -126,25 +106,6 @@ Item {
|
|||||||
font: label.font
|
font: label.font
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: iconLoader
|
|
||||||
active: root.iconLabel
|
|
||||||
width: Style.bar.iconCanvas
|
|
||||||
height: Style.bar.iconCanvas
|
|
||||||
x: (root.width - width) / 2
|
|
||||||
y: (root.height - height) / 2
|
|
||||||
sourceComponent: Component {
|
|
||||||
OpticalGlyph {
|
|
||||||
text: root.text
|
|
||||||
fontFamily: root.fontFamily
|
|
||||||
fontSize: root.fontSize
|
|
||||||
paintedSize: Style.bar.iconSize
|
|
||||||
color: root.active && root.useActiveColor ? root.activeColor : root.foreground
|
|
||||||
rotation: root.textRotation
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: mouseArea
|
id: mouseArea
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|||||||
Loaded 100 of 175 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user