Merge pull request #5467 from basecamp/rc

Omarchy 3.7.0
This commit is contained in:
David Heinemeier Hansson
2026-05-04 15:44:57 +02:00
committed by GitHub
423 changed files with 4673 additions and 997 deletions
+1
View File
@@ -12,6 +12,7 @@
All commands start with `omarchy-`. Prefixes indicate purpose: All commands start with `omarchy-`. Prefixes indicate purpose:
- `cmd-` - check if commands exist, misc utility commands - `cmd-` - check if commands exist, misc utility commands
- `capture-` - screenshots, screen recordings, and other capture tools
- `pkg-` - package management helpers - `pkg-` - package management helpers
- `hw-` - hardware detection (return exit codes for use in conditionals) - `hw-` - hardware detection (return exit codes for use in conditionals)
- `refresh-` - copy default config to user's `~/.config/` - `refresh-` - copy default config to user's `~/.config/`
+2
View File
@@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true
Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Executable
+1028
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# Returns true if AC power is connected. # omarchy:summary=Returns true if AC power is connected.
for ac in /sys/class/power_supply/AC* /sys/class/power_supply/ADP*; do for ac in /sys/class/power_supply/AC* /sys/class/power_supply/ADP*; do
[[ -r $ac/online && $(cat "$ac/online") == "1" ]] && exit 0 [[ -r $ac/online && $(cat "$ac/online") == "1" ]] && exit 0
+21
View File
@@ -0,0 +1,21 @@
#!/bin/bash
# omarchy:summary=Toggle microphone mute. Drives the hardware mic-mute LED on laptops that expose one.
wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle >/dev/null
if pactl get-source-mute @DEFAULT_SOURCE@ | rg -q 'yes'; then
led=on
osd_message='Microphone muted'
osd_icon='microphone-sensitivity-muted-symbolic'
else
led=off
osd_message='Microphone on'
osd_icon='audio-input-microphone-symbolic'
fi
omarchy-brightness-keyboard-mute "$led"
omarchy-swayosd-client \
--custom-message "$osd_message" \
--custom-icon "$osd_icon"
@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# Switch between audio outputs while preserving the mute status. By default mapped to Super + Mute. # omarchy:summary=Switch between audio outputs while preserving the mute status. By default mapped to Super + Mute.
sinks=$(pactl -f json list sinks | jq '[.[] | select((.ports | length == 0) or ([.ports[]? | .availability != "not available"] | any))]') sinks=$(pactl -f json list sinks | jq '[.[] | select((.ports | length == 0) or ([.ports[]? | .availability != "not available"] | any))]')
sinks_count=$(echo "$sinks" | jq '. | length') sinks_count=$(echo "$sinks" | jq '. | length')
+1 -2
View File
@@ -1,7 +1,6 @@
#!/bin/bash #!/bin/bash
# Returns the battery full capacity in Wh (rounded to whole number). # omarchy:summary=Returns the battery full capacity in Wh (rounded to whole number).
# Used by omarchy-battery-status for displaying battery capacity.
battery_info=$(upower -i $(upower -e | grep BAT)) battery_info=$(upower -i $(upower -e | grep BAT))
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# Designed to be run by systemd timer every 30 seconds and alerts if battery is low # omarchy:summary=Designed to be run by systemd timer every 30 seconds and alerts if battery is low
BATTERY_THRESHOLD=10 BATTERY_THRESHOLD=10
NOTIFICATION_FLAG="/run/user/$UID/omarchy_battery_notified" NOTIFICATION_FLAG="/run/user/$UID/omarchy_battery_notified"
+1 -2
View File
@@ -1,7 +1,6 @@
#!/bin/bash #!/bin/bash
# Returns true if a battery is present on the system. # omarchy:summary=Returns true if a battery is present on the system.
# Used by the battery monitor and other battery-related checks.
for bat in /sys/class/power_supply/BAT*; do for bat in /sys/class/power_supply/BAT*; do
[[ -r $bat/present ]] && [[ -r $bat/present ]] &&
+1 -2
View File
@@ -1,7 +1,6 @@
#!/bin/bash #!/bin/bash
# Returns the battery percentage remaining as an integer. # omarchy:summary=Returns the battery percentage remaining as an integer.
# Used by the battery monitor and the Ctrl + Shift + Super + B hotkey.
upower -i $(upower -e | grep BAT) | awk '/percentage/ { upower -i $(upower -e | grep BAT) | awk '/percentage/ {
print int($2) print int($2)
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# Returns the battery time remaining (to empty or full) in a compact format. # omarchy:summary=Returns the battery time remaining (to empty or full) in a compact format.
battery_info=$(upower -i $(upower -e | grep BAT)) battery_info=$(upower -i $(upower -e | grep BAT))
+1 -2
View File
@@ -1,7 +1,6 @@
#!/bin/bash #!/bin/bash
# Returns a formatted battery status string with percentage and power draw/charge. # omarchy:summary=Returns a formatted battery status string with percentage and power draw/charge.
# Used by the battery notification hotkey (Ctrl + Shift + Super + B).
battery_info=$(upower -i $(upower -e | grep BAT)) battery_info=$(upower -i $(upower -e | grep BAT))
+2 -1
View File
@@ -1,6 +1,7 @@
#!/bin/bash #!/bin/bash
# Set the branch for Omarchy's git repository. # omarchy:summary=Set the branch for Omarchy's git repository.
# omarchy:args=<master|rc|dev>
if (($# == 0)); then if (($# == 0)); then
echo "Usage: omarchy-branch-set [master|rc|dev]" echo "Usage: omarchy-branch-set [master|rc|dev]"
+32 -2
View File
@@ -1,10 +1,15 @@
#!/bin/bash #!/bin/bash
# Adjust brightness on the most likely display device. # omarchy:summary=Adjust brightness on the most likely display device.
# Usage: omarchy-brightness-display <step> # omarchy:args=<step>
step="${1:-+5%}" step="${1:-+5%}"
if omarchy-hyprland-monitor-focused-apple; then
omarchy-brightness-display-apple "$step"
exit
fi
# Start with the first possible output, then refine to the most likely given an order heuristic. # Start with the first possible output, then refine to the most likely given an order heuristic.
device="$(ls -1 /sys/class/backlight 2>/dev/null | head -n1)" device="$(ls -1 /sys/class/backlight 2>/dev/null | head -n1)"
for candidate in amdgpu_bl* intel_backlight acpi_video*; do for candidate in amdgpu_bl* intel_backlight acpi_video*; do
@@ -14,6 +19,31 @@ for candidate in amdgpu_bl* intel_backlight acpi_video*; do
fi fi
done done
# Current brightness percentage
current=$(brightnessctl -d "$device" -m | cut -d',' -f4 | tr -d '%')
# Apply non-uniform step size: 1% steps if at or below 5%, otherwise set an
# absolute target percentage to avoid raw backlight rounding causing uneven OSD steps.
if [[ $step == "+5%" ]]; then
if (( current < 5 )); then
(( target = current + 1 ))
else
(( target = current + 5 ))
fi
(( target > 100 )) && target=100
step="$target%"
elif [[ $step == "5%-" ]]; then
if (( current <= 5 )); then
(( target = current - 1 ))
else
(( target = current - 5 ))
fi
(( target < 1 )) && target=1
step="$target%"
fi
# Set the actual brightness of the display device. # Set the actual brightness of the display device.
brightnessctl -d "$device" set "$step" >/dev/null brightnessctl -d "$device" set "$step" >/dev/null
+24 -4
View File
@@ -1,12 +1,32 @@
#!/bin/bash #!/bin/bash
# Adjust the brightness on Apple Studio Displays and Apple XDR Displays using asdcontrol. # omarchy:summary=Adjust the brightness on Apple Studio Displays and Apple XDR Displays using asdcontrol.
if (( $# == 0 )); then if (( $# == 0 )); then
echo "Adjust Apple Display Brightness by passing +5000 or -5000 (or any range from 0-60000)" echo "Adjust Apple Display brightness by passing +5%, 5%-, or 100%"
else else
device="$(sudo asdcontrol --detect /dev/usb/hiddev* | grep ^/dev/usb/hiddev | cut -d: -f1)" step="$1"
sudo asdcontrol "$device" -- "$1" >/dev/null if [[ $step =~ ^([0-9]+)%-$ ]]; then
step="-${BASH_REMATCH[1]}%"
fi
devices=()
for path in /dev/usb/hiddev* /dev/hiddev*; do
[[ -e $path ]] && devices+=("$path")
done
if (( ${#devices[@]} == 0 )); then
echo "No Apple Display HID device found"
exit 1
fi
device="$(sudo asdcontrol --detect "${devices[@]}" | grep -E '^/dev/(usb/)?hiddev' | cut -d: -f1 | head -n1)"
if [[ -z $device ]]; then
echo "No Apple Display HID device found"
exit 1
fi
sudo asdcontrol "$device" -- "$step" >/dev/null
value="$(sudo asdcontrol "$device" | awk -F= '/BRIGHTNESS=/{print $2+0}')" value="$(sudo asdcontrol "$device" | awk -F= '/BRIGHTNESS=/{print $2+0}')"
omarchy-swayosd-brightness "$(( value * 100 / 60000 ))" omarchy-swayosd-brightness "$(( value * 100 / 60000 ))"
fi fi
+2 -2
View File
@@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
# Adjust keyboard backlight brightness using available steps. # omarchy:summary=Adjust keyboard backlight brightness using available steps.
# Usage: omarchy-brightness-keyboard <up|down|cycle> # omarchy:args=<up|down|cycle>
direction="${1:-up}" direction="${1:-up}"
+14
View File
@@ -0,0 +1,14 @@
#!/bin/bash
# omarchy:summary=Set the mic-mute indicator LED on laptops that expose a platform::micmute LED node.
# omarchy:args=<on|off>
if [[ -e /sys/class/leds/platform::micmute/brightness ]]; then
case "$1" in
on) value=1 ;;
off) value=0 ;;
*) echo "Usage: $(basename "$0") <on|off>" >&2; exit 1 ;;
esac
brightnessctl --device="platform::micmute" set "$value" >/dev/null 2>&1 || true
fi
+294
View File
@@ -0,0 +1,294 @@
#!/bin/bash
# omarchy:summary=Start or stop screen recording
# omarchy:group=capture
# omarchy:args=[--with-desktop-audio] [--with-microphone-audio] [--with-webcam] [--webcam-device=<device>] [--resolution=<size>] [--stop-recording]
# omarchy:examples=omarchy screenrecord | omarchy capture screenrecord --with-desktop-audio
# omarchy:aliases=omarchy screenrecord
#
# Env: OMARCHY_SCREENRECORD_USE_PORTAL=true skips the built-in slurp picker and
# uses gpu-screen-recorder's xdg-desktop-portal capture backend instead. The
# portal backend was originally added (PR #3401) for HDR-aware capture, support
# for monitors driven by external GPUs, and window capture — enable it if any
# of those matter to you. Off by default because the portal path can fail EGL
# DMA-BUF modifier import on some configurations, leaving recording unable to
# start.
#
# Env: OMARCHY_SCREENRECORD_DEBUG=true appends gpu-screen-recorder's stderr (and
# the picker target it was launched with) to /tmp/omarchy-screenrecord.log so
# users can attach a log when reporting capture failures.
[[ -f ~/.config/user-dirs.dirs ]] && source ~/.config/user-dirs.dirs
OUTPUT_DIR="${OMARCHY_SCREENRECORD_DIR:-${XDG_VIDEOS_DIR:-$HOME/Videos}}"
if [[ ! -d $OUTPUT_DIR ]]; then
notify-send "Screen recording directory does not exist: $OUTPUT_DIR" -u critical -t 3000
exit 1
fi
DESKTOP_AUDIO="false"
MICROPHONE_AUDIO="false"
WEBCAM="false"
WEBCAM_DEVICE=""
RESOLUTION=""
STOP_RECORDING="false"
RECORDING_FILE="/tmp/omarchy-screenrecord-filename"
LOG_FILE=$([[ ${OMARCHY_SCREENRECORD_DEBUG:-false} == "true" ]] && echo "/tmp/omarchy-screenrecord.log" || echo "/dev/null")
for arg in "$@"; do
case "$arg" in
--with-desktop-audio) DESKTOP_AUDIO="true" ;;
--with-microphone-audio) MICROPHONE_AUDIO="true" ;;
--with-webcam) WEBCAM="true" ;;
--webcam-device=*) WEBCAM_DEVICE="${arg#*=}" ;;
--resolution=*) RESOLUTION="${arg#*=}" ;;
--stop-recording) STOP_RECORDING="true" ;;
esac
done
start_webcam_overlay() {
cleanup_webcam
# Auto-detect first available webcam if none specified
if [[ -z $WEBCAM_DEVICE ]]; then
WEBCAM_DEVICE=$(v4l2-ctl --list-devices 2>/dev/null | grep -m1 "^[[:space:]]*/dev/video" | tr -d '\t')
if [[ -z $WEBCAM_DEVICE ]]; then
notify-send "No webcam devices found" -u critical -t 3000
return 1
fi
fi
# Get monitor scale
local scale=$(hyprctl monitors -j | jq -r '.[] | select(.focused == true) | .scale')
# Target width (base 360px, scaled to monitor)
local target_width=$(awk "BEGIN {printf \"%.0f\", 360 * $scale}")
# Try preferred 16:9 resolutions in order, use first available
local preferred_resolutions=("640x360" "1280x720" "1920x1080")
local video_size_arg=""
local available_formats=$(v4l2-ctl --list-formats-ext -d "$WEBCAM_DEVICE" 2>/dev/null)
for resolution in "${preferred_resolutions[@]}"; do
if echo "$available_formats" | grep -q "$resolution"; then
video_size_arg="-video_size $resolution"
break
fi
done
ffplay -f v4l2 $video_size_arg -framerate 30 "$WEBCAM_DEVICE" \
-vf "crop=iw/2:ih,scale=${target_width}:-1" \
-window_title "WebcamOverlay" \
-noborder \
-fflags nobuffer -flags low_delay \
-probesize 32 -analyzeduration 0 \
-loglevel quiet &
sleep 1
}
cleanup_webcam() {
pkill -f "WebcamOverlay" 2>/dev/null
}
default_resolution() {
local width height
read -r width height < <(hyprctl monitors -j | jq -r '.[] | select(.focused == true) | "\(.width) \(.height)"')
if ((width > 3840 || height > 2160)); then
echo "3840x2160"
else
echo "0x0"
fi
}
# Monitor + window rectangles on the focused workspace, in slurp's "X,Y WxH" format.
# Mirrors omarchy-capture-screenshot so the picker UX is identical.
get_rectangles() {
local active_workspace=$(hyprctl monitors -j | jq -r '.[] | select(.focused == true) | .activeWorkspace.id')
hyprctl monitors -j | jq -r --arg ws "$active_workspace" '
.[] | select(.activeWorkspace.id == ($ws | tonumber)) |
"\(.x),\(.y) \(.width / .scale | floor)x\(.height / .scale | floor)"'
hyprctl clients -j | jq -r --arg ws "$active_workspace" '
.[] | select(.workspace.id == ($ws | tonumber)) |
"\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"'
}
# Echoes "monitor:NAME" when the selection matches an entire monitor, otherwise
# "region:WxH+X+Y" with physical-pixel coordinates ready for gpu-screen-recorder.
# Returns non-zero if the user cancelled the picker.
select_capture_target() {
local rects=$(get_rectangles)
hyprpicker -r -z >/dev/null 2>&1 &
local picker_pid=$!
sleep .1
local selection=$(echo "$rects" | slurp 2>/dev/null)
kill $picker_pid 2>/dev/null
# X and Y can be negative (Hyprland monitor positions in multi-display layouts);
# widths and heights are always positive.
[[ $selection =~ ^(-?[0-9]+),(-?[0-9]+)[[:space:]]([0-9]+)x([0-9]+)$ ]] || return 1
local sx=${BASH_REMATCH[1]} sy=${BASH_REMATCH[2]}
local sw=${BASH_REMATCH[3]} sh=${BASH_REMATCH[4]}
# A bare click (area < 20px²) snaps to whichever rectangle the click landed
# inside, so users don't end up with accidental 2px recordings.
if ((sw * sh < 20)); then
while IFS= read -r rect; do
[[ $rect =~ ^(-?[0-9]+),(-?[0-9]+)[[:space:]]([0-9]+)x([0-9]+)$ ]] || continue
local rx=${BASH_REMATCH[1]} ry=${BASH_REMATCH[2]}
local rw=${BASH_REMATCH[3]} rh=${BASH_REMATCH[4]}
if ((sx >= rx && sx < rx + rw && sy >= ry && sy < ry + rh)); then
sx=$rx sy=$ry sw=$rw sh=$rh
break
fi
done <<<"$rects"
fi
# When the selection exactly matches a monitor, prefer -w <monitor> over a
# region capture — same kms backend, but no scaling math and full native res.
local monitor=$(hyprctl monitors -j | jq -r --argjson x "$sx" --argjson y "$sy" --argjson w "$sw" --argjson h "$sh" '
.[] | select(.x == $x and .y == $y and (.width / .scale | floor) == $w and (.height / .scale | floor) == $h) | .name' | head -1)
if [[ -n $monitor ]]; then
echo "monitor:$monitor"
return
fi
# gpu-screen-recorder wants region geometry in the compositor's logical
# coordinate space — same space slurp returns — so pass the values through
# untouched. (gsr scales to physical pixels itself based on the monitor.)
echo "region:${sw}x${sh}+${sx}+${sy}"
}
start_screenrecording() {
local capture_args=()
local target
# Opt-in path for HDR, external-GPU monitors, and window capture (all things
# the portal backend supports and the kms backend doesn't). Default flow uses
# slurp + the kms backend, which avoids the EGL DMA-BUF modifier import
# failures the portal path can hit on some configurations.
if [[ ${OMARCHY_SCREENRECORD_USE_PORTAL:-false} == "true" ]]; then
target="portal"
capture_args=(-w portal -s "${RESOLUTION:-$(default_resolution)}")
else
target=$(select_capture_target) || return 1
case $target in
monitor:*)
capture_args=(-w "${target#monitor:}" -s "${RESOLUTION:-$(default_resolution)}")
;;
region:*)
capture_args=(-w "${target#region:}")
[[ -n $RESOLUTION ]] && capture_args+=(-s "$RESOLUTION")
;;
esac
fi
[[ $WEBCAM == "true" ]] && start_webcam_overlay
local filename="$OUTPUT_DIR/screenrecording-$(date +'%Y-%m-%d_%H-%M-%S').mp4"
local audio_devices=""
local audio_args=()
[[ $DESKTOP_AUDIO == "true" ]] && audio_devices+="default_output"
if [[ $MICROPHONE_AUDIO == "true" ]]; then
# Merge audio tracks into one - separate tracks only play one at a time in most players
[[ -n $audio_devices ]] && audio_devices+="|"
audio_devices+="default_input"
fi
[[ -n $audio_devices ]] && audio_args+=(-a "$audio_devices" -ac aac)
echo "===== $(date '+%F %T') args: $* target: $target =====" >>"$LOG_FILE"
gpu-screen-recorder "${capture_args[@]}" -k auto -f 60 -fm cfr -fallback-cpu-encoding yes -o "$filename" "${audio_args[@]}" 2>>"$LOG_FILE" &
local pid=$!
while kill -0 $pid 2>/dev/null && [[ ! -f $filename ]]; do
sleep 0.2
done
if kill -0 $pid 2>/dev/null; then
echo "$filename" >"$RECORDING_FILE"
toggle_screenrecording_indicator
fi
}
stop_screenrecording() {
pkill -SIGINT -f "^gpu-screen-recorder" # SIGINT required to save video properly
# Wait a maximum of 5 seconds to finish before hard killing
local count=0
while pgrep -f "^gpu-screen-recorder" >/dev/null && ((count < 50)); do
sleep 0.1
count=$((count + 1))
done
toggle_screenrecording_indicator
cleanup_webcam
if pgrep -f "^gpu-screen-recorder" >/dev/null; then
pkill -9 -f "^gpu-screen-recorder"
notify-send "Screen recording error" "Recording process had to be force-killed. Video may be corrupted." -u critical -t 5000
else
finalize_recording
local filename=$(cat "$RECORDING_FILE" 2>/dev/null)
local preview="${filename%.mp4}-preview.png"
# Generate a preview thumbnail from the first frame
ffmpeg -y -i "$filename" -ss 00:00:00.1 -vframes 1 -q:v 2 "$preview" -loglevel quiet 2>/dev/null
(
ACTION=$(notify-send "Screen recording saved" "Open with Super + Alt + , (or click this)" -t 10000 -i "${preview:-$filename}" -A "default=open")
[[ $ACTION == "default" ]] && mpv "$filename"
rm -f "$preview"
) &
fi
rm -f "$RECORDING_FILE"
}
toggle_screenrecording_indicator() {
pkill -RTMIN+8 waybar
}
screenrecording_active() {
pgrep -f "^gpu-screen-recorder" >/dev/null
}
finalize_recording() {
local latest
latest=$(cat "$RECORDING_FILE" 2>/dev/null)
[[ -f $latest ]] || return
# Re-encode only when the first GOP contains discardable warmup packets — stream copy can't
# trim those (it rewinds to the keyframe). Clean recordings stay on the fast stream-copy path.
local video_codec=(-c:v copy)
if ffprobe -v error -select_streams v:0 -read_intervals %+0.2 -show_entries packet=flags -of csv=p=0 "$latest" 2>/dev/null | grep -q D; then
video_codec=(-c:v libx264 -preset veryfast -crf 20)
fi
# Trim the first frame, and normalize audio to -14 LUFS if present, in a single pass
local args=(-y -ss 0.1 -i "$latest" "${video_codec[@]}")
if ffprobe -v error -select_streams a -show_entries stream=codec_type -of csv=p=0 "$latest" 2>/dev/null | grep -q audio; then
# Hard-mute the first 400ms to drop the PipeWire capture-open pop (a near-clipping
# transient around 130-200ms that a gentle fade-in can't attenuate enough), then a
# 50ms fade avoids a click at the boundary before loudnorm normalizes the rest.
args+=(-af "volume=enable='lt(t,0.4)':volume=0,afade=t=in:st=0.4:d=0.05,loudnorm=I=-14:TP=-1.5:LRA=11")
fi
local processed="${latest%.mp4}-processed.mp4"
if ffmpeg "${args[@]}" "$processed" -loglevel quiet 2>/dev/null; then
mv "$processed" "$latest"
else
rm -f "$processed"
fi
}
if screenrecording_active; then
stop_screenrecording
elif [[ $STOP_RECORDING == "true" ]]; then
exit 1
else
start_screenrecording || cleanup_webcam
fi
@@ -1,8 +1,10 @@
#!/bin/bash #!/bin/bash
# Take a screenshot of the whole screen, a specific window, or a user-drawn region. # omarchy:summary=Take a screenshot
# Saves to ~/Pictures by default, but that can be changed via OMARCHY_SCREENSHOT_DIR or XDG_PICTURES_DIR ENVs. # omarchy:group=capture
# Editor defaults to Satty but can be changed via --editor=<name> or OMARCHY_SCREENSHOT_EDITOR env # omarchy:args=[smart|region|windows|fullscreen] [slurp|copy] [--editor=<name>]
# omarchy:examples=omarchy screenshot | omarchy capture screenshot region
# omarchy:aliases=omarchy screenshot
[[ -f ~/.config/user-dirs.dirs ]] && source ~/.config/user-dirs.dirs [[ -f ~/.config/user-dirs.dirs ]] && source ~/.config/user-dirs.dirs
OUTPUT_DIR="${OMARCHY_SCREENSHOT_DIR:-${XDG_PICTURES_DIR:-$HOME/Pictures}}" OUTPUT_DIR="${OMARCHY_SCREENSHOT_DIR:-${XDG_PICTURES_DIR:-$HOME/Pictures}}"
@@ -63,6 +65,13 @@ get_rectangles() {
hyprctl clients -j | jq -r --arg ws "$active_workspace" '.[] | select(.workspace.id == ($ws | tonumber)) | "\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"' hyprctl clients -j | jq -r --arg ws "$active_workspace" '.[] | select(.workspace.id == ($ws | tonumber)) | "\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"'
} }
# Keep hyprpicker alive until after grim captures so the screenshot sees the
# frozen overlay rather than live content shifting during teardown.
cleanup_freeze() {
[[ -n $PID ]] && kill $PID 2>/dev/null
}
trap cleanup_freeze EXIT
# Select based on mode # Select based on mode
case "$MODE" in case "$MODE" in
region) region)
@@ -70,14 +79,12 @@ region)
PID=$! PID=$!
sleep .1 sleep .1
SELECTION=$(slurp 2>/dev/null) SELECTION=$(slurp 2>/dev/null)
kill $PID 2>/dev/null
;; ;;
windows) windows)
hyprpicker -r -z >/dev/null 2>&1 & hyprpicker -r -z >/dev/null 2>&1 &
PID=$! PID=$!
sleep .1 sleep .1
SELECTION=$(get_rectangles | slurp -r 2>/dev/null) SELECTION=$(get_rectangles | slurp -r 2>/dev/null)
kill $PID 2>/dev/null
;; ;;
fullscreen) fullscreen)
SELECTION=$(hyprctl monitors -j | jq -r "${JQ_MONITOR_GEO} .[] | select(.focused == true) | format_geo") SELECTION=$(hyprctl monitors -j | jq -r "${JQ_MONITOR_GEO} .[] | select(.focused == true) | format_geo")
@@ -88,7 +95,6 @@ smart | *)
PID=$! PID=$!
sleep .1 sleep .1
SELECTION=$(echo "$RECTS" | slurp 2>/dev/null) SELECTION=$(echo "$RECTS" | slurp 2>/dev/null)
kill $PID 2>/dev/null
# If the selection area is L * W < 20, we'll assume you were trying to select whichever # If the selection area is L * W < 20, we'll assume you were trying to select whichever
# window or output it was inside of to prevent accidental 2px snapshots # window or output it was inside of to prevent accidental 2px snapshots
+26
View File
@@ -0,0 +1,26 @@
#!/bin/bash
# omarchy:summary=Extract text from a screenshot region with OCR
# omarchy:group=capture
# omarchy:examples=omarchy capture ocr
# Keep hyprpicker alive until after grim captures so the screenshot sees the
# frozen overlay rather than live content shifting during teardown.
cleanup_freeze() {
[[ -n $PID ]] && kill $PID 2>/dev/null
}
trap cleanup_freeze EXIT
hyprpicker -r -z >/dev/null 2>&1 &
PID=$!
sleep .1
SELECTION=$(slurp 2>/dev/null)
[[ -z $SELECTION ]] && exit 0
TEXT=$(grim -g "$SELECTION" - | tesseract stdin stdout --oem 1 --psm 6 -l eng --dpi 300 -c preserve_interword_spaces=1 2>/dev/null) || exit 1
[[ -z $TEXT ]] && exit 1
printf "%s" "$TEXT" | wl-copy
notify-send "󰴑 Copied text from selection to clipboard"
+3 -12
View File
@@ -1,17 +1,8 @@
#!/bin/bash #!/bin/bash
# Set the Omarchy channel, which dictates what git branch and package repository is used. # omarchy:summary=Set the Omarchy channel, which dictates what git branch and package repository is used.
# # omarchy:args=<stable|rc|edge|dev>
# Stable uses the master branch, which only sees updates on official releases, and # omarchy:requires-sudo=true
# the stable package repository, which typically lags the edge by a month to ensure
# better compatibility.
#
# Edge tracks the latest package repository, but still relies on the master branch,
# so new packages which require config changes may cause conflicts or errors.
#
# Dev tracks the active development dev branch, which may include partial or broken updates,
# as well as the latest package repository. This should only be used by Omarchy developers
# and people with a lot of experience managing Linux systems.
if (($# == 0)); then if (($# == 0)); then
echo "Usage: omarchy-channel-set [stable|rc|edge|dev]" echo "Usage: omarchy-channel-set [stable|rc|edge|dev]"
-11
View File
@@ -1,11 +0,0 @@
#!/bin/bash
# Toggle microphone mute. Dell XPS and ThinkPad systems get special handling for the hardware LED.
if omarchy-hw-match "XPS"; then
omarchy-cmd-mic-mute-xps
elif omarchy-hw-match "ThinkPad"; then
omarchy-cmd-mic-mute-thinkpad
else
omarchy-swayosd-client --input-volume mute-toggle
fi
-23
View File
@@ -1,23 +0,0 @@
#!/bin/bash
# Toggle microphone mute on ThinkPad systems. Uses wpctl for reliable toggling
# and syncs the platform::micmute LED via brightnessctl.
wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle >/dev/null
if pactl get-source-mute @DEFAULT_SOURCE@ | grep -q 'yes'; then
osd_message='Microphone muted'
osd_icon='microphone-sensitivity-muted-symbolic'
led_value=1
else
osd_message='Microphone on'
osd_icon='audio-input-microphone-symbolic'
led_value=0
fi
brightnessctl --device="platform::micmute" set "$led_value" >/dev/null 2>&1 || true
swayosd-client \
--monitor "$(omarchy-hyprland-monitor-focused)" \
--custom-message "$osd_message" \
--custom-icon "$osd_icon"
-43
View File
@@ -1,43 +0,0 @@
#!/bin/bash
# Toggle microphone mute on Dell XPS systems. Uses wpctl for reliable toggling
# and syncs the ALSA capture switch so the hardware mic mute LED follows state.
wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle >/dev/null
if pactl get-source-mute @DEFAULT_SOURCE@ | rg -q 'yes'; then
alsa_value='off,off'
osd_message='Microphone muted'
osd_icon='microphone-sensitivity-muted-symbolic'
else
alsa_value='on,on'
osd_message='Microphone on'
osd_icon='audio-input-microphone-symbolic'
fi
if [[ -e /sys/class/leds/platform::micmute/brightness ]]; then
default_source=$(pactl get-default-source)
alsa_card=$(pactl -f json list sources | jq -r --arg source "$default_source" '
.[] | select(.name == $source) |
.properties["alsa.card"] // .properties["api.alsa.card"] // .properties["api.alsa.pcm.card"] // empty
' | head -1)
if [[ -n $alsa_card ]]; then
cards=("$alsa_card")
else
mapfile -t cards < <(compgen -G '/proc/asound/card*' | rg -o 'card[0-9]+' | sed 's/card//' | sort -u)
fi
for card in "${cards[@]}"; do
while IFS= read -r control; do
if [[ $control != *"Jack Microphone"* ]]; then
amixer -c "$card" cset "$control" "$alsa_value" >/dev/null 2>&1 || true
break 2
fi
done < <(amixer -c "$card" controls 2>/dev/null | rg -o "name='[^']*Microphone Capture Switch'")
done
fi
omarchy-swayosd-client \
--custom-message "$osd_message" \
--custom-icon "$osd_icon"
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# Returns true if any of the commands passed in as arguments are missing on the system. # omarchy:summary=Check whether any required commands are missing
for cmd in "$@"; do for cmd in "$@"; do
if ! command -v "$cmd" &>/dev/null; then if ! command -v "$cmd" &>/dev/null; then
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# Returns true if all the commands passed in as arguments exit on the system. # omarchy:summary=Check whether all required commands are available
for cmd in "$@"; do for cmd in "$@"; do
command -v "$cmd" &>/dev/null || exit 1 command -v "$cmd" &>/dev/null || exit 1
-191
View File
@@ -1,191 +0,0 @@
#!/bin/bash
# Start and stop a screenrecording, which will be saved to ~/Videos by default.
# Alternative location can be set via OMARCHY_SCREENRECORD_DIR or XDG_VIDEOS_DIR ENVs.
# Resolution is capped to 4K for monitors above 4K, native otherwise.
# Override via --resolution= (e.g. --resolution=1920x1080, --resolution=0x0 for native).
[[ -f ~/.config/user-dirs.dirs ]] && source ~/.config/user-dirs.dirs
OUTPUT_DIR="${OMARCHY_SCREENRECORD_DIR:-${XDG_VIDEOS_DIR:-$HOME/Videos}}"
if [[ ! -d $OUTPUT_DIR ]]; then
notify-send "Screen recording directory does not exist: $OUTPUT_DIR" -u critical -t 3000
exit 1
fi
DESKTOP_AUDIO="false"
MICROPHONE_AUDIO="false"
WEBCAM="false"
WEBCAM_DEVICE=""
RESOLUTION=""
STOP_RECORDING="false"
RECORDING_FILE="/tmp/omarchy-screenrecord-filename"
for arg in "$@"; do
case "$arg" in
--with-desktop-audio) DESKTOP_AUDIO="true" ;;
--with-microphone-audio) MICROPHONE_AUDIO="true" ;;
--with-webcam) WEBCAM="true" ;;
--webcam-device=*) WEBCAM_DEVICE="${arg#*=}" ;;
--resolution=*) RESOLUTION="${arg#*=}" ;;
--stop-recording) STOP_RECORDING="true" ;;
esac
done
start_webcam_overlay() {
cleanup_webcam
# Auto-detect first available webcam if none specified
if [[ -z $WEBCAM_DEVICE ]]; then
WEBCAM_DEVICE=$(v4l2-ctl --list-devices 2>/dev/null | grep -m1 "^[[:space:]]*/dev/video" | tr -d '\t')
if [[ -z $WEBCAM_DEVICE ]]; then
notify-send "No webcam devices found" -u critical -t 3000
return 1
fi
fi
# Get monitor scale
local scale=$(hyprctl monitors -j | jq -r '.[] | select(.focused == true) | .scale')
# Target width (base 360px, scaled to monitor)
local target_width=$(awk "BEGIN {printf \"%.0f\", 360 * $scale}")
# Try preferred 16:9 resolutions in order, use first available
local preferred_resolutions=("640x360" "1280x720" "1920x1080")
local video_size_arg=""
local available_formats=$(v4l2-ctl --list-formats-ext -d "$WEBCAM_DEVICE" 2>/dev/null)
for resolution in "${preferred_resolutions[@]}"; do
if echo "$available_formats" | grep -q "$resolution"; then
video_size_arg="-video_size $resolution"
break
fi
done
ffplay -f v4l2 $video_size_arg -framerate 30 "$WEBCAM_DEVICE" \
-vf "crop=iw/2:ih,scale=${target_width}:-1" \
-window_title "WebcamOverlay" \
-noborder \
-fflags nobuffer -flags low_delay \
-probesize 32 -analyzeduration 0 \
-loglevel quiet &
sleep 1
}
cleanup_webcam() {
pkill -f "WebcamOverlay" 2>/dev/null
}
default_resolution() {
local width height
read -r width height < <(hyprctl monitors -j | jq -r '.[] | select(.focused == true) | "\(.width) \(.height)"')
if ((width > 3840 || height > 2160)); then
echo "3840x2160"
else
echo "0x0"
fi
}
start_screenrecording() {
local filename="$OUTPUT_DIR/screenrecording-$(date +'%Y-%m-%d_%H-%M-%S').mp4"
local audio_devices=""
local audio_args=()
[[ $DESKTOP_AUDIO == "true" ]] && audio_devices+="default_output"
if [[ $MICROPHONE_AUDIO == "true" ]]; then
# Merge audio tracks into one - separate tracks only play one at a time in most players
[[ -n $audio_devices ]] && audio_devices+="|"
audio_devices+="default_input"
fi
[[ -n $audio_devices ]] && audio_args+=(-a "$audio_devices" -ac aac)
local resolution="${RESOLUTION:-$(default_resolution)}"
gpu-screen-recorder -w portal -k auto -s "$resolution" -f 60 -fm cfr -fallback-cpu-encoding yes -o "$filename" "${audio_args[@]}" &
local pid=$!
# Wait for recording to actually start (file appears after portal selection)
while kill -0 $pid 2>/dev/null && [[ ! -f $filename ]]; do
sleep 0.2
done
if kill -0 $pid 2>/dev/null; then
echo "$filename" >"$RECORDING_FILE"
toggle_screenrecording_indicator
fi
}
stop_screenrecording() {
pkill -SIGINT -f "^gpu-screen-recorder" # SIGINT required to save video properly
# Wait a maximum of 5 seconds to finish before hard killing
local count=0
while pgrep -f "^gpu-screen-recorder" >/dev/null && ((count < 50)); do
sleep 0.1
count=$((count + 1))
done
toggle_screenrecording_indicator
cleanup_webcam
if pgrep -f "^gpu-screen-recorder" >/dev/null; then
pkill -9 -f "^gpu-screen-recorder"
notify-send "Screen recording error" "Recording process had to be force-killed. Video may be corrupted." -u critical -t 5000
else
finalize_recording
local filename=$(cat "$RECORDING_FILE" 2>/dev/null)
local preview="${filename%.mp4}-preview.png"
# Generate a preview thumbnail from the first frame
ffmpeg -y -i "$filename" -ss 00:00:00.1 -vframes 1 -q:v 2 "$preview" -loglevel quiet 2>/dev/null
(
ACTION=$(notify-send "Screen recording saved" "Open with Super + Alt + , (or click this)" -t 10000 -i "${preview:-$filename}" -A "default=open")
[[ $ACTION == "default" ]] && mpv "$filename"
rm -f "$preview"
) &
fi
rm -f "$RECORDING_FILE"
}
toggle_screenrecording_indicator() {
pkill -RTMIN+8 waybar
}
screenrecording_active() {
pgrep -f "^gpu-screen-recorder" >/dev/null
}
finalize_recording() {
local latest
latest=$(cat "$RECORDING_FILE" 2>/dev/null)
[[ -f $latest ]] || return
# Trim the first frame, and normalize audio to -14 LUFS if present, in a single pass
local args=(-y -ss 0.1 -i "$latest")
if ffprobe -v error -select_streams a -show_entries stream=codec_type -of csv=p=0 "$latest" 2>/dev/null | grep -q audio; then
args+=(-af loudnorm=I=-14:TP=-1.5:LRA=11 -c:v copy)
else
args+=(-c copy)
fi
local processed="${latest%.mp4}-processed.mp4"
if ffmpeg "${args[@]}" "$processed" -loglevel quiet 2>/dev/null; then
mv "$processed" "$latest"
else
rm -f "$processed"
fi
}
if screenrecording_active; then
stop_screenrecording
elif [[ $STOP_RECORDING == "true" ]]; then
exit 1
else
[[ $WEBCAM == "true" ]] && start_webcam_overlay
start_screenrecording || cleanup_webcam
fi
+1 -3
View File
@@ -1,9 +1,7 @@
#!/bin/bash #!/bin/bash
# Returns the current working directory of the active terminal window, # omarchy:summary=Print the current working directory of the active terminal window
# so a new terminal window can be started in the same directory.
# Go from current active terminal to its child shell process and run cwd there
terminal_pid=$(hyprctl activewindow | awk '/pid:/ {print $2}') terminal_pid=$(hyprctl activewindow | awk '/pid:/ {print $2}')
shell_pid=$(pgrep -P "$terminal_pid" | tail -n1) shell_pid=$(pgrep -P "$terminal_pid" | tail -n1)
+30 -17
View File
@@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
# Add an EFI boot entry for the Omarchy UKI, allowing the system to boot directly # omarchy:summary=Add or remove an EFI boot entry for the Omarchy UKI, allowing the system to boot directly
# without a bootloader like Limine. Requires UEFI firmware and a built UKI. # omarchy:requires-sudo=true
if [[ ! -d /sys/firmware/efi ]]; then if [[ ! -d /sys/firmware/efi ]]; then
echo "Error: System is not booted in UEFI mode" >&2 echo "Error: System is not booted in UEFI mode" >&2
@@ -23,23 +23,36 @@ if cat /sys/class/dmi/id/bios_vendor 2>/dev/null | grep -qi "Apple"; then
exit 1 exit 1
fi fi
uki_file=$(find /boot/EFI/Linux/ -name "omarchy*.efi" -printf "%f\n" 2>/dev/null | head -1) existing_entry=$(efibootmgr | grep -E "^Boot[0-9A-Fa-f]+\*? Omarchy([[:space:]]|$)" | head -1)
if [[ -z $uki_file ]]; then if [[ -n $existing_entry ]]; then
echo "Error: No Omarchy UKI found in /boot/EFI/Linux/" >&2 boot_num=$(echo "$existing_entry" | sed -n 's/^Boot\([0-9A-Fa-f]\+\).*/\1/p')
exit 1
fi
boot_source=$(findmnt -n -o SOURCE /boot) if gum confirm "Disable direct boot (remove Omarchy EFI entry)?"; then
disk=$(echo "$boot_source" | sed 's/p\?[0-9]*$//') echo "Removing EFI boot entry $boot_num"
part=$(echo "$boot_source" | grep -o 'p\?[0-9]*$' | sed 's/^p//') sudo efibootmgr --bootnum "$boot_num" --delete-bootnum >/dev/null
fi
if gum confirm "Setup direct boot (so snapshot booting must be done via bios)?"; then exit 0
echo "Creating EFI boot entry for $uki_file" else
uki_file=$(find /boot/EFI/Linux/ -name "omarchy*.efi" -printf "%f\n" 2>/dev/null | head -1)
sudo efibootmgr --create \ if [[ -z $uki_file ]]; then
--disk "$disk" \ echo "Error: No Omarchy UKI found in /boot/EFI/Linux/" >&2
--part "$part" \ exit 1
--label "Omarchy" \ fi
--loader "\\EFI\\Linux\\$uki_file"
boot_source=$(findmnt -n -o SOURCE /boot)
disk=$(echo "$boot_source" | sed 's/p\?[0-9]*$//')
part=$(echo "$boot_source" | grep -o 'p\?[0-9]*$' | sed 's/^p//')
if gum confirm "Setup direct boot (so snapshot booting must be done via bios)?"; then
echo "Creating EFI boot entry for $uki_file"
sudo efibootmgr --create \
--disk "$disk" \
--part "$part" \
--label "Omarchy" \
--loader "\\EFI\\Linux\\$uki_file"
fi
fi fi
+4 -1
View File
@@ -1,6 +1,9 @@
#!/bin/bash #!/bin/bash
# Return exhaustive debugging information about the system to help diagnose problems. # omarchy:summary=Print debugging information
# omarchy:args=[--no-sudo] [--print]
# omarchy:examples=omarchy debug --print --no-sudo
# omarchy:requires-sudo=true
NO_SUDO=false NO_SUDO=false
PRINT_ONLY=false PRINT_ONLY=false
+1 -2
View File
@@ -1,7 +1,6 @@
#!/bin/bash #!/bin/bash
# Creates a new Omarchy migration named after the unix timestamp of the last commit. # omarchy:summary=Creates a new Omarchy migration named after the unix timestamp of the last commit.
# Only intended for Omarchy developers.
cd ~/.local/share/omarchy cd ~/.local/share/omarchy
migration_file="$HOME/.local/share/omarchy/migrations/$(git log -1 --format=%cd --date=unix).sh" migration_file="$HOME/.local/share/omarchy/migrations/$(git log -1 --format=%cd --date=unix).sh"
+111
View File
@@ -0,0 +1,111 @@
#!/bin/bash
# omarchy:summary=Measure Omarchy CLI response times
# omarchy:args=[--repeat=<count>]
# omarchy:examples=omarchy dev benchmark | omarchy dev benchmark --repeat=10
set -euo pipefail
OMARCHY_BIN_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
CLI="$OMARCHY_BIN_DIR/omarchy"
REPEAT=5
show_help() {
cat <<'EOF'
Usage:
omarchy dev benchmark [--repeat=<count>]
Measure response times for common Omarchy CLI surfaces.
Options:
--repeat=<count> Number of times to run each case (default: 5)
EOF
}
now_us() {
local now="${EPOCHREALTIME/./}"
printf '%s' "$now"
}
format_ms() {
local us="$1"
printf '%d.%03d' "$(( us / 1000 ))" "$(( us % 1000 ))"
}
run_case() {
local label="$1"
shift
local total_us=0
local min_us=0
local max_us=0
local elapsed_us=0
local start_us=0
local end_us=0
local status=0
for (( i = 1; i <= REPEAT; i++ )); do
start_us=$(now_us)
if "$@" >/dev/null; then
status=0
else
status=$?
fi
end_us=$(now_us)
if (( status != 0 )); then
printf '%-34s failed (exit %d)\n' "$label" "$status"
return "$status"
fi
elapsed_us=$(( end_us - start_us ))
total_us=$(( total_us + elapsed_us ))
if (( i == 1 || elapsed_us < min_us )); then
min_us=$elapsed_us
fi
if (( elapsed_us > max_us )); then
max_us=$elapsed_us
fi
done
printf '%-34s avg %8s ms min %8s ms max %8s ms\n' \
"$label" \
"$(format_ms "$(( total_us / REPEAT ))")" \
"$(format_ms "$min_us")" \
"$(format_ms "$max_us")"
}
while (( $# > 0 )); do
case "$1" in
--repeat=*)
REPEAT="${1#*=}"
;;
--help | -h)
show_help
exit 0
;;
*)
echo "Unknown option: $1" >&2
show_help >&2
exit 2
;;
esac
shift
done
if [[ ! $REPEAT =~ ^[0-9]+$ ]] || (( REPEAT < 1 )); then
echo "--repeat must be a positive integer" >&2
exit 2
fi
printf 'Omarchy CLI benchmark (%d runs each)\n\n' "$REPEAT"
run_case "omarchy" "$CLI"
run_case "omarchy --help" "$CLI" --help
run_case "omarchy commands" "$CLI" commands
run_case "omarchy commands --json" "$CLI" commands --json
run_case "omarchy commands --all --json" "$CLI" commands --all --json
run_case "omarchy theme set --help" "$CLI" theme set --help
run_case "omarchy screenshot --help" "$CLI" screenshot --help
run_case "omarchy restart --help" "$CLI" restart --help
run_case "omarchy theme current" "$CLI" theme current
+86
View File
@@ -0,0 +1,86 @@
#!/bin/bash
# omarchy:summary=Show Omarchy bin metadata fields and defaults
# omarchy:args=[--json]
set -euo pipefail
show_json() {
jq -n '{
ok: true,
defaults: {
group: "first filename segment after omarchy-",
name: "remaining filename segments with dashes converted to spaces",
route: "omarchy <group> <name>",
binary: "filename",
requires_sudo: false
},
fields: [
{name: "summary", required: true, type: "string", note: "One-line human and agent-facing description."},
{name: "group", required: false, type: "string", note: "Only set when the route group should differ from the filename-derived group."},
{name: "name", required: false, type: "string", note: "Only set when the route name should differ from the filename-derived name. May be empty for root commands."},
{name: "args", required: false, type: "string", note: "Only set when the command accepts arguments."},
{name: "examples", required: false, type: "string", note: "Pipe-separated examples."},
{name: "aliases", required: false, type: "string", note: "Pipe-separated alternate routes, e.g. omarchy screenshot."},
{name: "requires-sudo", required: false, type: "true", default: false, note: "Only include when true."}
]
}'
}
show_help() {
cat <<'EOF'
Omarchy bin metadata
Metadata lives in the top comment block of each executable bin/omarchy-* file.
Keep it slim: define only fields that are required or override defaults.
Required:
# omarchy:summary=<one-line description>
Inferred defaults:
group first filename segment after omarchy-
name remaining filename segments, with dashes converted to spaces
route omarchy <group> <name>
binary filename
requires-sudo false
Optional fields:
# omarchy:group=<group> route override only
# omarchy:name=<name> route override only; may be empty
# omarchy:args=<args> only if the command accepts args
# omarchy:examples=<cmd> | <cmd> pipe-separated examples
# omarchy:aliases=<route> | <route> pipe-separated alternate routes
# omarchy:requires-sudo=true only when true
Do not define:
binary inferred from filename
usage derived from route + args
false flags or empty args
Examples:
# omarchy:summary=Restart Walker and related user services
# omarchy:summary=Take a screenshot
# omarchy:group=capture
# omarchy:args=[smart|region|windows|fullscreen] [slurp|copy] [--editor=<name>]
# omarchy:examples=omarchy screenshot | omarchy capture screenshot region
# omarchy:aliases=omarchy screenshot
EOF
}
case "${1:-}" in
--json)
show_json
;;
--help | -h)
show_help
;;
"")
show_help
;;
*)
echo "Unknown option: $1" >&2
show_help >&2
exit 2
;;
esac
+2 -1
View File
@@ -1,6 +1,7 @@
#!/bin/bash #!/bin/bash
# Returns drive information about a given volumne, like /dev/nvme0, which is used by omarchy-drive-select. # omarchy:summary=Print drive information such as size, model, and mount details
# omarchy:args=<drive>
if (($# == 0)); then if (($# == 0)); then
echo "Usage: omarchy-drive-info [/dev/drive]" echo "Usage: omarchy-drive-info [/dev/drive]"
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# Select a drive from a list with info that includes space and brand. Used by omarchy-drive-set-password. # omarchy:summary=Select a drive from a list with info that includes space and brand. Used by omarchy-drive-set-password.
if (($# == 0)); then if (($# == 0)); then
drives=$(lsblk -dpno NAME | grep -E '/dev/(sd|hd|vd|nvme|mmcblk|xv)') drives=$(lsblk -dpno NAME | grep -E '/dev/(sd|hd|vd|nvme|mmcblk|xv)')
+3 -2
View File
@@ -1,11 +1,12 @@
#!/bin/bash #!/bin/bash
# Set a new encryption password for a drive selected. # omarchy:summary=Set a new encryption password for a drive selected.
# omarchy:requires-sudo=true
encrypted_drives=$(blkid -t TYPE=crypto_LUKS -o device) encrypted_drives=$(blkid -t TYPE=crypto_LUKS -o device)
if [[ -n $encrypted_drives ]]; then if [[ -n $encrypted_drives ]]; then
if (( $(wc -l <<<encrypted_drives) == 1 )); then if (( $(wc -l <<<"$encrypted_drives") == 1 )); then
drive_to_change="$encrypted_drives" drive_to_change="$encrypted_drives"
else else
drive_to_change="$(omarchy-drive-select "$encrypted_drives")" drive_to_change="$(omarchy-drive-select "$encrypted_drives")"
@@ -1,6 +1,7 @@
#!/bin/bash #!/bin/bash
# Finish the installation of Omarchy with items that can only be done after logging in. # omarchy:summary=Finish the installation of Omarchy with items that can only be done after logging in.
# omarchy:requires-sudo=true
set -e set -e
+2 -2
View File
@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# Returns the name of the current monospace font being used by extracting it from the Waybar stylesheet. # omarchy:summary=Show current monospace font
# This can be changed using omarchy-font-set. # omarchy:examples=omarchy font current
grep -oP 'font-family:\s*["'\'']?\K[^;"'\'']+' ~/.config/waybar/style.css | head -n1 grep -oP 'font-family:\s*["'\'']?\K[^;"'\'']+' ~/.config/waybar/style.css | head -n1
+2 -1
View File
@@ -1,5 +1,6 @@
#!/bin/bash #!/bin/bash
# Returns a list of all the monospace fonts available on the system that can be set using omarchy-font-set. # omarchy:summary=List available monospace fonts
# omarchy:examples=omarchy font list | omarchy font set "CaskaydiaMono Nerd Font"
fc-list :spacing=100 -f "%{family[0]}\n" | grep -v -i -E 'emoji|signwriting|omarchy' | sort -u fc-list :spacing=100 -f "%{family[0]}\n" | grep -v -i -E 'emoji|signwriting|omarchy' | sort -u
+3 -2
View File
@@ -1,7 +1,8 @@
#!/bin/bash #!/bin/bash
# Set the system-wide monospace font that should be used by the terminal, hyprlock, waybar, swayosd, etc. # omarchy:summary=Set the system monospace font
# The font name must be one of the ones returned by omarchy-font-list. # omarchy:args=<font-name>
# omarchy:examples=omarchy font list | omarchy font set "CaskaydiaMono Nerd Font"
font_name="$1" font_name="$1"
+2
View File
@@ -1,5 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# omarchy:summary=Run the Synaptics touchpad haptic feedback daemon
"""Haptic feedback daemon for Synaptics touchpads with Manual Trigger. """Haptic feedback daemon for Synaptics touchpads with Manual Trigger.
Monitors touchpad button press events and sends haptic pulses via HID Monitors touchpad button press events and sends haptic pulses via HID
+2 -1
View File
@@ -1,6 +1,7 @@
#!/bin/bash #!/bin/bash
# Check if hibernation is supported # omarchy:summary=Check if hibernation is supported
if [[ ! -f /sys/power/image_size ]]; then if [[ ! -f /sys/power/image_size ]]; then
exit 1 exit 1
fi fi
+2 -2
View File
@@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
# Removes hibernation setup: disables swap, removes swapfile, removes fstab entry, # omarchy:summary=Remove hibernation setup including swap and boot resume settings
# removes resume hook, and removes suspend-then-hibernate configuration. # omarchy:requires-sudo=true
MKINITCPIO_CONF="/etc/mkinitcpio.conf.d/omarchy_resume.conf" MKINITCPIO_CONF="/etc/mkinitcpio.conf.d/omarchy_resume.conf"
+28 -13
View File
@@ -1,14 +1,27 @@
#!/bin/bash #!/bin/bash
# Creates a swap file in the btrfs subvolume, adds the swap file to /etc/fstab, # omarchy:summary=Set up hibernation with swap and boot resume configuration
# adds a resume hook to mkinitcpio, and configures suspend-then-hibernate. # omarchy:requires-sudo=true
# omarchy:args=[--force] [--no-rebuild]
FORCE=false
NO_REBUILD=false
for arg in "$@"; do
case "$arg" in
--force) FORCE=true ;;
--no-rebuild) NO_REBUILD=true ;;
esac
done
if [[ ! -f /sys/power/image_size ]]; then if [[ ! -f /sys/power/image_size ]]; then
echo -e "Hibernation is not supported on your system" >&2 echo -e "Hibernation is not supported on your system" >&2
exit 0 exit 0
fi fi
if ! command -v limine-mkinitcpio &>/dev/null; then # When --no-rebuild is set, the caller is responsible for the UKI rebuild
# (e.g. running before limine-mkinitcpio-hook is installed during initial
# install), so we only require limine-mkinitcpio when we'd invoke it ourselves.
if ! $NO_REBUILD && ! command -v limine-mkinitcpio &>/dev/null; then
echo "Skipping hibernation setup (requires Limine bootloader)" echo "Skipping hibernation setup (requires Limine bootloader)"
exit 0 exit 0
fi fi
@@ -26,15 +39,14 @@ if [[ -f $MKINITCPIO_CONF ]] && grep -q "^HOOKS+=(resume)$" "$MKINITCPIO_CONF";
echo "Fixing empty resume_offset ($RESUME_OFFSET)" echo "Fixing empty resume_offset ($RESUME_OFFSET)"
sudo sed -i "s/resume_offset=\"$/resume_offset=$RESUME_OFFSET\"/" "$RESUME_DROP_IN" sudo sed -i "s/resume_offset=\"$/resume_offset=$RESUME_OFFSET\"/" "$RESUME_DROP_IN"
sudo sed -i "s/resume_offset=\"$/resume_offset=$RESUME_OFFSET\"/" /etc/default/limine sudo sed -i "s/resume_offset=\"$/resume_offset=$RESUME_OFFSET\"/" /etc/default/limine
sudo limine-mkinitcpio $NO_REBUILD || sudo limine-mkinitcpio
sudo limine-update
fi fi
fi fi
echo "Hibernation is already set up" echo "Hibernation is already set up"
exit 0 exit 0
fi fi
if [[ $1 != "--force" ]]; then if ! $FORCE; then
MEM_TOTAL_HUMAN=$(free --human | awk '/Mem/ {print $2}') MEM_TOTAL_HUMAN=$(free --human | awk '/Mem/ {print $2}')
if ! gum confirm "Use $MEM_TOTAL_HUMAN on boot drive to make hibernation available?"; then if ! gum confirm "Use $MEM_TOTAL_HUMAN on boot drive to make hibernation available?"; then
exit 0 exit 0
@@ -105,13 +117,16 @@ if grep -q "\[s2idle\]" /sys/power/mem_sleep 2>/dev/null; then
fi fi
fi fi
# Regenerate initramfs and boot entry if ! $NO_REBUILD; then
echo "Regenerating initramfs..." # limine-mkinitcpio rebuilds initramfs/UKI for all kernels and updates the
sudo limine-mkinitcpio # /boot/limine.conf entries via limine-entry-tool. The limine bootloader
sudo limine-update # binary on the ESP doesn't change here, so we don't need limine-update
# (which would also re-deploy the binary and rebuild a second time).
echo "Regenerating initramfs..."
sudo limine-mkinitcpio
echo
fi
echo if ! $FORCE && ! $NO_REBUILD && gum confirm "Reboot to enable hibernation?"; then
if [[ $1 != "--force" ]] && gum confirm "Reboot to enable hibernation?"; then
omarchy-system-reboot omarchy-system-reboot
fi fi
+2 -1
View File
@@ -1,6 +1,7 @@
#!/bin/bash #!/bin/bash
# Run a named hook, like post-update (available in ~/.config/omarchy/hooks/post-update). # omarchy:summary=Run a named hook, like post-update (available in ~/.config/omarchy/hooks/post-update).
# omarchy:args=[name] [args...]
set -e set -e
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
# omarchy:summary=Detect ASUS ExpertBook B9406 series laptops on Intel Panther Lake.
omarchy-hw-match "B9406" && omarchy-hw-intel-ptl
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# Detect whether the computer is an Asus ROG machine. # omarchy:summary=Detect whether the computer is an Asus ROG machine.
[[ $(cat /sys/class/dmi/id/sys_vendor 2>/dev/null) == "ASUSTeK COMPUTER INC." ]] && [[ $(cat /sys/class/dmi/id/sys_vendor 2>/dev/null) == "ASUSTeK COMPUTER INC." ]] &&
grep -q "ROG" /sys/class/dmi/id/product_family 2>/dev/null grep -q "ROG" /sys/class/dmi/id/product_family 2>/dev/null
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# Match Dell XPS systems with LG OLED panel on Intel Panther Lake (Xe3) GPU. # omarchy:summary=Match Dell XPS systems with LG OLED panel on Intel Panther Lake (Xe3) GPU.
omarchy-hw-match "XPS" \ omarchy-hw-match "XPS" \
&& omarchy-hw-intel-ptl \ && omarchy-hw-intel-ptl \
+1 -2
View File
@@ -1,7 +1,6 @@
#!/bin/bash #!/bin/bash
# Returns true when an external monitor is physically connected. # omarchy:summary=Returns true when an external monitor is physically connected.
# Uses kernel DRM state so the result is independent of Hyprland's startup timing.
for status in /sys/class/drm/card*-*/status; do for status in /sys/class/drm/card*-*/status; do
[[ "$status" == *-eDP-*/status ]] && continue [[ "$status" == *-eDP-*/status ]] && continue
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# Detect whether the computer is a Framework Laptop 16. # omarchy:summary=Detect whether the computer is a Framework Laptop 16.
[[ $(cat /sys/class/dmi/id/sys_vendor 2>/dev/null) == "Framework" ]] && [[ $(cat /sys/class/dmi/id/sys_vendor 2>/dev/null) == "Framework" ]] &&
omarchy-hw-match "Laptop 16" omarchy-hw-match "Laptop 16"
+7 -1
View File
@@ -1,3 +1,9 @@
#!/bin/bash #!/bin/bash
(($(lspci | grep -cE 'VGA|3D|Display') >= 2)) # omarchy:summary=Detect whether the system has an active hybrid GPU configuration
if command -v supergfxctl &>/dev/null; then
supergfxctl -s 2>/dev/null | grep -qw Hybrid
else
(($(lspci | grep -cE 'VGA|3D|Display') >= 2))
fi
+1 -1
View File
@@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
# Detect whether the computer has an Intel CPU. # omarchy:summary=Detect whether the computer has an Intel CPU.
[[ $(grep -m1 "vendor_id" /proc/cpuinfo 2>/dev/null | cut -d: -f2 | tr -d ' ') == "GenuineIntel" ]] [[ $(grep -m1 "vendor_id" /proc/cpuinfo 2>/dev/null | cut -d: -f2 | tr -d ' ') == "GenuineIntel" ]]
+1 -1
View File
@@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
# Detect whether the computer has an Intel Panther Lake GPU. # omarchy:summary=Detect whether the computer has an Intel Panther Lake GPU.
lspci | grep -iE 'vga|3d|display' | grep -qi 'panther lake' lspci | grep -iE 'vga|3d|display' | grep -qi 'panther lake'
+2 -2
View File
@@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
# Match against the computer's DMI product name or product family (case-insensitive). # omarchy:summary=Match against the computer's DMI product name or product family (case-insensitive).
# Usage: omarchy-hw-match "XPS" or omarchy-hw-match "ThinkPad" # omarchy:args=<pattern>
grep -qi "$1" /sys/class/dmi/id/product_name 2>/dev/null || grep -qi "$1" /sys/class/dmi/id/product_name 2>/dev/null ||
grep -qi "$1" /sys/class/dmi/id/product_family 2>/dev/null grep -qi "$1" /sys/class/dmi/id/product_family 2>/dev/null
+6
View File
@@ -0,0 +1,6 @@
#!/bin/bash
# omarchy:summary=Detect whether the computer has an NVIDIA GPU with GSP firmware (Turing or newer).
# GTX 16xx, RTX 20xx-50xx, RTX Pro, Quadro RTX, datacenter A/H/T/L series.
lspci | grep -i 'nvidia' | grep -qE "GTX 16[0-9]{2}|RTX [2-5][0-9]{3}|RTX PRO [0-9]{4}|Quadro RTX|RTX A[0-9]{4}|A[1-9][0-9]{2}|H[1-9][0-9]{2}|T4|L[0-9]+"
+6
View File
@@ -0,0 +1,6 @@
#!/bin/bash
# omarchy:summary=Detect whether the computer has an NVIDIA GPU without GSP firmware (Maxwell/Pascal/Volta).
# GTX 9xx/10xx, GT 10xx, Quadro P/M/GV, MX series, Titan X/Xp/V, Tesla V100.
lspci | grep -i 'nvidia' | grep -qE "GTX (9[0-9]{2}|10[0-9]{2})|GT 10[0-9]{2}|Quadro [PM][0-9]{3,4}|Quadro GV100|MX *[0-9]+|Titan (X|Xp|V)|Tesla V100"
+1 -3
View File
@@ -1,8 +1,6 @@
#!/bin/bash #!/bin/bash
# Clear the internal-monitor-disable toggle if no external display is connected. # omarchy:summary=Clear the internal-monitor-disable toggle if no external display is connected.
# Runs before the graphical session so Hyprland doesn't block on having no output
# to render to when the user rebooted with the external unplugged.
TOGGLE="$HOME/.local/state/omarchy/toggles/hypr/internal-monitor-disable.conf" TOGGLE="$HOME/.local/state/omarchy/toggles/hypr/internal-monitor-disable.conf"
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# Detect whether the computer is a Microsoft Surface device. # omarchy:summary=Detect whether the computer is a Microsoft Surface device.
[[ $(cat /sys/class/dmi/id/sys_vendor 2>/dev/null) == "Microsoft Corporation" ]] && [[ $(cat /sys/class/dmi/id/sys_vendor 2>/dev/null) == "Microsoft Corporation" ]] &&
omarchy-hw-match "Surface" omarchy-hw-match "Surface"
+2
View File
@@ -1,4 +1,6 @@
#!/bin/bash #!/bin/bash
# omarchy:summary=Print the detected Hyprland touchpad or trackpad device name
device=$(hyprctl devices -j | jq -r '[.mice[] | .name | select(test("touchpad|trackpad"; "i"))] | first // empty') device=$(hyprctl devices -j | jq -r '[.mice[] | .name | select(test("touchpad|trackpad"; "i"))] | first // empty')
[[ -n $device ]] && echo "$device" [[ -n $device ]] && echo "$device"
+6
View File
@@ -0,0 +1,6 @@
#!/bin/bash
# omarchy:summary=Print the detected Hyprland touchscreen or tablet device name
device=$(hyprctl devices -j | jq -r '[.touch[]?.name, .tablets[]?.name] | first // empty')
[[ -n $device ]] && echo "$device"
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# Detect whether Vulkan is available. # omarchy:summary=Detect whether Vulkan is available.
[[ -d /usr/share/vulkan/icd.d ]] && [[ -d /usr/share/vulkan/icd.d ]] &&
find /usr/share/vulkan/icd.d -maxdepth 1 -name "*.json" -print -quit | grep -q . find /usr/share/vulkan/icd.d -maxdepth 1 -name "*.json" -print -quit | grep -q .
@@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
# Toggles transparency for the currently focused window. # omarchy:summary=Toggles transparency for the currently focused window.
hyprctl dispatch setprop "address:$(hyprctl activewindow -j | jq -r '.address')" opaque toggle hyprctl dispatch setprop "address:$(hyprctl activewindow -j | jq -r '.address')" opaque toggle
+1 -1
View File
@@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
# Print the name of the currently focused Hyprland monitor. # omarchy:summary=Print the name of the currently focused Hyprland monitor.
hyprctl monitors -j | jq -r '.[] | select(.focused == true).name' hyprctl monitors -j | jq -r '.[] | select(.focused == true).name'
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
# omarchy:summary=Return success if the focused Hyprland monitor is an Apple display.
hyprctl monitors -j | jq -e '.[] | select(.focused == true) | select(.make == "Apple Computer Inc" and (.model | test("StudioDisplay|ProDisplayXDR")))' >/dev/null
+14 -5
View File
@@ -1,6 +1,14 @@
#!/bin/bash #!/bin/bash
# omarchy:summary=Enable, disable, toggle, or recover the internal laptop display
# omarchy:args=<on|off|toggle|recover>
TOGGLE="internal-monitor-disable" TOGGLE="internal-monitor-disable"
TOGGLE_FLAG="$HOME/.local/state/omarchy/toggles/hypr/$TOGGLE.conf"
MIRROR_TOGGLE="internal-monitor-mirror"
# Get internal monitor name dynamically
INTERNAL=$(hyprctl monitors -j | jq -r '.[] | select(.name | contains("eDP")).name' | head -n 1)
enable() { enable() {
if omarchy-hyprland-toggle-enabled "$TOGGLE"; then if omarchy-hyprland-toggle-enabled "$TOGGLE"; then
@@ -9,14 +17,15 @@ enable() {
} }
disable() { disable() {
if omarchy-hw-external-monitors; then if ! omarchy-hw-external-monitors; then
if omarchy-hyprland-toggle-disabled "$TOGGLE"; then
omarchy-hyprland-toggle --enabled-notification "󰍹 Laptop display disabled" "$TOGGLE"
fi
else
notify-send -u low "󰍹 Can't disable the only active display" notify-send -u low "󰍹 Can't disable the only active display"
exit 1 exit 1
fi fi
if omarchy-hyprland-toggle-disabled "$TOGGLE" && omarchy-hyprland-toggle-disabled "$MIRROR_TOGGLE"; then
echo "monitor=$INTERNAL,disable" >"$TOGGLE_FLAG"
notify-send -u low "󰍹 Laptop display disabled"
hyprctl reload
fi
} }
recover() { recover() {
+58
View File
@@ -0,0 +1,58 @@
#!/bin/bash
# omarchy:summary=Enable, disable, toggle, or recover mirroring the internal display to an external monitor
# omarchy:args=<on|off|toggle|recover>
TOGGLE="internal-monitor-mirror"
TOGGLE_FLAG="$HOME/.local/state/omarchy/toggles/hypr/$TOGGLE.conf"
DISABLE_TOGGLE="internal-monitor-disable"
# Get names dynamically
INTERNAL=$(hyprctl monitors -j | jq -r '.[] | select(.name | contains("eDP")).name' | head -n 1)
# Get the first available external monitor
EXTERNAL=$(hyprctl monitors -j | jq -r '.[] | select(.name | contains("eDP") | not).name' | head -n 1)
enable() {
if [[ -z "$EXTERNAL" ]]; then
notify-send -u low "󰍹 No external monitors found for mirror"
exit 1
fi
if [[ -z "$INTERNAL" ]]; then
notify-send -u low "󰍹 No laptop monitor found to mirror"
exit 1
fi
if omarchy-hyprland-toggle-enabled "$DISABLE_TOGGLE"; then
omarchy-hyprland-toggle "$DISABLE_TOGGLE"
fi
if omarchy-hyprland-toggle-disabled "$TOGGLE"; then
echo "monitor=$EXTERNAL, preferred, auto, 1, mirror, $INTERNAL" > "$TOGGLE_FLAG"
notify-send -u low "󰍹 Mirroring enabled ($EXTERNAL)"
hyprctl reload
fi
}
disable() {
if omarchy-hyprland-toggle-enabled "$TOGGLE"; then
omarchy-hyprland-toggle --disabled-notification "󰍹 Extended mode restored" "$TOGGLE"
fi
}
recover() {
if ! omarchy-hw-external-monitors && omarchy-hyprland-toggle-enabled "$TOGGLE"; then
omarchy-hyprland-toggle "$TOGGLE"
fi
}
case "$1" in
on) enable ;;
off) disable ;;
toggle) if omarchy-hyprland-toggle-enabled "$TOGGLE"; then disable; else enable; fi ;;
recover) recover ;;
*)
echo "Usage: $(basename "$0") {on|off|toggle|recover}" >&2
exit 1
;;
esac
+13 -1
View File
@@ -1,6 +1,7 @@
#!/bin/bash #!/bin/bash
# Get the active monitor (the one with the cursor) # omarchy:summary=Cycle scaling for the focused Hyprland monitor
MONITOR_INFO=$(hyprctl monitors -j | jq -r '.[] | select(.focused == true)') MONITOR_INFO=$(hyprctl monitors -j | jq -r '.[] | select(.focused == true)')
ACTIVE_MONITOR=$(echo "$MONITOR_INFO" | jq -r '.name') ACTIVE_MONITOR=$(echo "$MONITOR_INFO" | jq -r '.name')
CURRENT_SCALE=$(echo "$MONITOR_INFO" | jq -r '.scale') CURRENT_SCALE=$(echo "$MONITOR_INFO" | jq -r '.scale')
@@ -32,4 +33,15 @@ fi
NEW_SCALE=${SCALES[$NEW_IDX]} NEW_SCALE=${SCALES[$NEW_IDX]}
hyprctl keyword monitor "$ACTIVE_MONITOR,${WIDTH}x${HEIGHT}@${REFRESH_RATE},auto,$NEW_SCALE" hyprctl keyword monitor "$ACTIVE_MONITOR,${WIDTH}x${HEIGHT}@${REFRESH_RATE},auto,$NEW_SCALE"
# Persist to monitors.conf if the user has a single generic catch-all line
# (ignoring disabled monitors), so the scale survives reboots.
MONITOR_CONF="$HOME/.config/hypr/monitors.conf"
if [[ -f $MONITOR_CONF ]]; then
mapfile -t ACTIVE_LINES < <(grep -E '^[[:space:]]*monitor=' "$MONITOR_CONF" | grep -vE 'disable[[:space:]]*$')
if [[ ${#ACTIVE_LINES[@]} -eq 1 ]] && [[ "${ACTIVE_LINES[0]}" =~ ^monitor=,preferred,auto, ]]; then
sed -i -E "s|^(monitor=,preferred,auto,).*|\\1${NEW_SCALE}|" "$MONITOR_CONF"
fi
fi
notify-send -u low "󰍹 Display scaling set to ${NEW_SCALE}x" notify-send -u low "󰍹 Display scaling set to ${NEW_SCALE}x"
+2 -2
View File
@@ -1,7 +1,6 @@
#!/bin/bash #!/bin/bash
# Listen on Hyprland's event socket and recover the internal display whenever # omarchy:summary=Watch Hyprland monitor events and recover monitor toggles when a monitor is removed
# a monitor is removed.
SOCKET="$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock" SOCKET="$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock"
@@ -9,6 +8,7 @@ socat -U - "UNIX-CONNECT:$SOCKET" | while read -r event; do
case "$event" in case "$event" in
monitorremoved\>\>*|monitorremovedv2\>\>*) monitorremoved\>\>*|monitorremovedv2\>\>*)
omarchy-hyprland-monitor-internal recover omarchy-hyprland-monitor-internal recover
omarchy-hyprland-monitor-internal-mirror recover
;; ;;
esac esac
done done
+2 -1
View File
@@ -1,6 +1,7 @@
#!/bin/bash #!/bin/bash
# Toggle permanent Hyprland flags by copying them into a directory that's sourced entirely. # omarchy:summary=Toggle permanent Hyprland flags by copying them into a directory that's sourced entirely.
# omarchy:args=[--enabled-notification <text>] [--disabled-notification <text>] <flag-name>
ENABLED_NOTIFICATION="" ENABLED_NOTIFICATION=""
DISABLED_NOTIFICATION="" DISABLED_NOTIFICATION=""
+2 -1
View File
@@ -1,5 +1,6 @@
#!/bin/bash #!/bin/bash
# Check if a Hyprland toggle is currently disabled (missing). # omarchy:summary=Check if a Hyprland toggle is currently disabled (missing).
# omarchy:args=<flag-name>
[[ ! -f "$HOME/.local/state/omarchy/toggles/hypr/$1.conf" ]] [[ ! -f "$HOME/.local/state/omarchy/toggles/hypr/$1.conf" ]]
+2 -1
View File
@@ -1,5 +1,6 @@
#!/bin/bash #!/bin/bash
# Check if a Hyprland toggle is currently enabled. # omarchy:summary=Check if a Hyprland toggle is currently enabled.
# omarchy:args=<flag-name>
[[ -f "$HOME/.local/state/omarchy/toggles/hypr/$1.conf" ]] [[ -f "$HOME/.local/state/omarchy/toggles/hypr/$1.conf" ]]
+2 -1
View File
@@ -1,6 +1,7 @@
#!/bin/bash #!/bin/bash
# Close all open windows # omarchy:summary=Close all open windows
hyprctl clients -j | \ hyprctl clients -j | \
jq -r ".[].address" | \ jq -r ".[].address" | \
xargs -I{} hyprctl dispatch closewindow address:{} xargs -I{} hyprctl dispatch closewindow address:{}
+1 -1
View File
@@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
# Toggles the window gaps globally between no gaps and the default. # omarchy:summary=Toggles the window gaps globally between no gaps and the default.
omarchy-hyprland-toggle window-no-gaps omarchy-hyprland-toggle window-no-gaps
+2 -14
View File
@@ -1,19 +1,7 @@
#!/bin/bash #!/bin/bash
# Toggle to pop-out a tile to stay fixed on a display basis. # omarchy:summary=Toggle to pop-out a tile to stay fixed on a display basis.
# omarchy:args=[width height x y]
# Usage:
# omarchy-hyprland-window-pop [width height [x y]]
#
# Arguments:
# width Optional. Width of the floating window. Default: 1300
# height Optional. Height of the floating window. Default: 900
# x Optional. X position of the window. Must provide both X and Y to take effect.
# y Optional. Y position of the window. Must provide both X and Y to take effect.
#
# Behavior:
# - If the window is already pinned, it will be unpinned and removed from the pop layer.
# - If the window is not pinned, it will be floated, resized, moved/centered, pinned, brought to top, and popped.
width=${1:-1300} width=${1:-1300}
height=${2:-900} height=${2:-900}
@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# Toggle single-window square aspect ratio. # omarchy:summary=Toggle single-window square aspect ratio.
omarchy-hyprland-toggle \ omarchy-hyprland-toggle \
--enabled-notification " Enable single-window square aspect ratio" \ --enabled-notification " Enable single-window square aspect ratio" \
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# Toggle the layout on the current active workspace between dwindle and scrolling # omarchy:summary=Toggle the layout on the current active workspace between dwindle and scrolling
ACTIVE_WORKSPACE=$(hyprctl activeworkspace -j | jq -r '.id') ACTIVE_WORKSPACE=$(hyprctl activeworkspace -j | jq -r '.id')
CURRENT_LAYOUT=$(hyprctl activeworkspace -j | jq -r '.tiledLayout') CURRENT_LAYOUT=$(hyprctl activeworkspace -j | jq -r '.tiledLayout')
+2 -2
View File
@@ -1,9 +1,9 @@
#!/bin/bash #!/bin/bash
# Allow Chromium to sign in to Google accounts by adding the correct # omarchy:summary=Allow Chromium to sign in to Google accounts by adding the required OAuth credentials
# oauth client id and secret to ~/.config/chromium-flags.conf.
if [[ -f ~/.config/chromium-flags.conf ]]; then if [[ -f ~/.config/chromium-flags.conf ]]; then
echo "Installing Chromium Google account support..."
CONF=~/.config/chromium-flags.conf CONF=~/.config/chromium-flags.conf
grep -qxF -- "--oauth2-client-id=77185425430.apps.googleusercontent.com" "$CONF" || grep -qxF -- "--oauth2-client-id=77185425430.apps.googleusercontent.com" "$CONF" ||
+5 -1
View File
@@ -1,6 +1,10 @@
#!/bin/bash #!/bin/bash
# Install one of the supported development environments. Usually called via Install > Development > * in the Omarchy Menu. # omarchy:summary=Install a supported development environment
# omarchy:name=dev-env
# omarchy:args=<ruby|node|bun|deno|go|laravel|symfony|php|python|elixir|phoenix|rust|java|zig|ocaml|dotnet|clojure|scala>
# omarchy:examples=omarchy install dev-env ruby | omarchy install dev-env node
# omarchy:requires-sudo=true
if [[ -z $1 ]]; then if [[ -z $1 ]]; then
echo "Usage: omarchy-install-dev-env <ruby|node|bun|deno|go|laravel|symfony|php|python|elixir|phoenix|rust|java|zig|ocaml|dotnet|clojure|scala>" >&2 echo "Usage: omarchy-install-dev-env <ruby|node|bun|deno|go|laravel|symfony|php|python|elixir|phoenix|rust|java|zig|ocaml|dotnet|clojure|scala>" >&2
+3 -2
View File
@@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
# Install one of the supported databases in a Docker container with the suitable development options. # omarchy:summary=Install one of the supported databases in a Docker container with the suitable development options.
# Usually called via Install > Development > Docker DB from the Omarchy Menu. # omarchy:requires-sudo=true
options=("MySQL" "PostgreSQL" "Redis" "MongoDB" "MariaDB" "MSSQL") options=("MySQL" "PostgreSQL" "Redis" "MongoDB" "MariaDB" "MSSQL")
@@ -13,6 +13,7 @@ fi
if [[ -n $choices ]]; then if [[ -n $choices ]]; then
for db in $choices; do for db in $choices; do
echo "Installing $db..."
case $db in case $db in
MySQL) sudo docker run -d --restart unless-stopped -p "127.0.0.1:3306:3306" --name=mysql8 -e MYSQL_ROOT_PASSWORD= -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql:8.4 ;; MySQL) sudo docker run -d --restart unless-stopped -p "127.0.0.1:3306:3306" --name=mysql8 -e MYSQL_ROOT_PASSWORD= -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql:8.4 ;;
PostgreSQL) sudo docker run -d --restart unless-stopped -p "127.0.0.1:5432:5432" --name=postgres18 -e POSTGRES_HOST_AUTH_METHOD=trust postgres:18 ;; PostgreSQL) sudo docker run -d --restart unless-stopped -p "127.0.0.1:5432:5432" --name=postgres18 -e POSTGRES_HOST_AUTH_METHOD=trust postgres:18 ;;
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# Install and start the Dropbox service. Must then be authenticated via the web. # omarchy:summary=Install and start the Dropbox service. Must then be authenticated via the web.
echo "Installing all dependencies..." echo "Installing all dependencies..."
omarchy-pkg-add dropbox dropbox-cli libappindicator-gtk3 python-gpgme nautilus-dropbox omarchy-pkg-add dropbox dropbox-cli libappindicator-gtk3 python-gpgme nautilus-dropbox
@@ -1,9 +1,10 @@
#!/bin/bash #!/bin/bash
# Install and launch Geforce Now. # omarchy:summary=Install and launch Geforce Now.
set -e set -e
echo "Installing GeForce NOW..."
omarchy-pkg-add flatpak omarchy-pkg-add flatpak
cd /tmp cd /tmp
+28
View File
@@ -0,0 +1,28 @@
#!/bin/bash
# omarchy:summary=Install lib32 graphics drivers (Vulkan + NVIDIA) for any detected GPUs.
# omarchy:requires-sudo=true
set -e
echo "Installing lib32 graphics drivers..."
PACKAGES=()
declare -A VULKAN_DRIVERS=(
[Intel]=lib32-vulkan-intel
[AMD]=lib32-vulkan-radeon
)
for vendor in "${!VULKAN_DRIVERS[@]}"; do
if lspci | grep -iE "(VGA|Display).*$vendor" >/dev/null; then
PACKAGES+=("${VULKAN_DRIVERS[$vendor]}")
fi
done
if omarchy-hw-nvidia-gsp; then
PACKAGES+=(lib32-nvidia-utils)
elif omarchy-hw-nvidia-without-gsp; then
PACKAGES+=(lib32-nvidia-580xx-utils)
fi
[[ ${#PACKAGES[@]} -gt 0 ]] && omarchy-pkg-add "${PACKAGES[@]}"
+12
View File
@@ -0,0 +1,12 @@
#!/bin/bash
# omarchy:summary=Install Heroic Games Launcher (Epic, GOG, Amazon Prime Gaming) with graphics drivers.
# omarchy:requires-sudo=true
set -e
echo "Installing Heroic Games Launcher..."
omarchy-pkg-add heroic-games-launcher-bin
omarchy-install-gaming-gpu-lib32
setsid gtk-launch heroic >/dev/null 2>&1 &
+23
View File
@@ -0,0 +1,23 @@
#!/bin/bash
# omarchy:summary=Install Lutris with Wine + DXVK for running Windows games (Battle.net, EA, Ubisoft Connect, etc.)
# omarchy:requires-sudo=true
set -e
echo "Installing Lutris..."
omarchy-pkg-add lutris umu-launcher wine-staging wine-mono wine-gecko winetricks python-protobuf
omarchy-install-gaming-gpu-lib32
# Lutris ships with `#!/usr/bin/env python3`, which resolves to mise's Python and
# fails to import the lutris module. Pin the shebang to the system Python.
sudo sed -i '/env python3/ c\#!/bin/python3' /usr/bin/lutris
cat <<'EOF'
Lutris will open and auto-fetch its DXVK and VKD3D runtimes in the background
(watch the bottom status bar). Once that finishes, click the + to add or install games.
EOF
setsid lutris >/dev/null 2>&1 &
+11
View File
@@ -0,0 +1,11 @@
#!/bin/bash
# omarchy:summary=Install Moonlight (NVIDIA GameStream / Sunshine client) for streaming games to this PC.
# omarchy:requires-sudo=true
set -e
echo "Installing Moonlight..."
omarchy-pkg-add moonlight-qt
setsid gtk-launch com.moonlight_stream.Moonlight.desktop >/dev/null 2>&1 &
+80
View File
@@ -0,0 +1,80 @@
#!/bin/bash
# omarchy:summary=Install RetroArch with the full libretro core set plus FBNeo and a ~/Games ROM directory.
set -e
echo "Installing RetroArch..."
omarchy-pkg-add \
retroarch \
retroarch-assets-glui retroarch-assets-ozone retroarch-assets-xmb \
libretro-beetle-pce libretro-beetle-pce-fast libretro-beetle-psx libretro-beetle-psx-hw libretro-beetle-supergrafx \
libretro-blastem \
libretro-bsnes libretro-bsnes-hd libretro-bsnes2014 \
libretro-core-info \
libretro-desmume libretro-dolphin libretro-flycast \
libretro-gambatte libretro-genesis-plus-gx \
libretro-kronos \
libretro-mame libretro-mame2016 libretro-melonds libretro-mesen libretro-mesen-s libretro-mgba libretro-mupen64plus-next \
libretro-nestopia \
libretro-overlays \
libretro-parallel-n64 libretro-picodrive libretro-play libretro-ppsspp \
libretro-sameboy libretro-scummvm libretro-shaders-slang libretro-snes9x \
libretro-yabause \
libretro-fbneo-git \
libretro-database-git
# Set up ~/Games for BIOS files and ROMs
mkdir -p "$HOME/Games/bios" "$HOME/Games/roms"
CFG="$HOME/.config/retroarch/retroarch.cfg"
mkdir -p "$(dirname "$CFG")"
touch "$CFG"
set_cfg() {
local key=$1 value=$2
if grep -q "^$key = " "$CFG"; then
sed -i "s|^$key = .*|$key = \"$value\"|" "$CFG"
else
echo "$key = \"$value\"" >>"$CFG"
fi
}
set_cfg rgui_browser_directory "$HOME/Games/roms"
set_cfg system_directory "$HOME/Games/bios"
# Point at the cores and assets installed by pacman
set_cfg libretro_directory "/usr/lib/libretro"
set_cfg libretro_info_path "/usr/share/libretro/info"
set_cfg overlay_directory "/usr/share/libretro/overlays"
set_cfg osk_overlay_directory "/usr/share/libretro/overlays/keyboards"
set_cfg video_shader_dir "/usr/share/libretro/shaders/shaders_slang"
# Point at the database, cheats, and cursors from libretro-database-git
set_cfg content_database_path "/usr/share/libretro/database/rdb"
set_cfg cheat_database_path "/usr/share/libretro/database/cht"
set_cfg cursor_directory "/usr/share/libretro/database/cursors"
# Vulkan is required for slang shaders and unlocks hardware renderers in beetle-psx-hw, parallel-n64, dolphin
set_cfg video_driver "vulkan"
# XMB is the classic PS3-style menu (vs. ozone/rgui/glui)
set_cfg menu_driver "xmb"
# Default to crt-royale shader for that classic CRT look. The global preset is
# auto-loaded by RetroArch when auto_shaders_enable is true and no per-core/per-game
# preset takes precedence — setting video_shader alone in retroarch.cfg is not enough.
set_cfg video_shader_enable "true"
set_cfg auto_shaders_enable "true"
mkdir -p ~/.config/retroarch/config
echo '#reference "/usr/share/libretro/shaders/shaders_slang/crt/crt-royale.slangp"' \
> ~/.config/retroarch/config/global.slangp
# Hide Images and Video tabs in the main menu sidebar
set_cfg content_show_images "false"
set_cfg content_show_video "false"
echo ""
echo "Put your roms and bios files in ~/Games. Then start RetroArch from the app launcher (Super + Space)."
setsid nautilus "$HOME/Games" >/dev/null 2>&1 &
+15
View File
@@ -0,0 +1,15 @@
#!/bin/bash
# omarchy:summary=Install Steam and graphics drivers selected for this system
# omarchy:requires-sudo=true
set -e
echo "Installing Steam..."
omarchy-pkg-add steam
omarchy-install-gaming-gpu-lib32
echo ""
echo "Steam will start automatically now. This might take a while..."
setsid gtk-launch steam >/dev/null 2>&1 &
+10
View File
@@ -0,0 +1,10 @@
#!/bin/bash
# omarchy:summary=Install Xbox Cloud Gaming as a web app and launch it.
set -e
echo "Installing Xbox Cloud Gaming..."
omarchy-webapp-install "Xbox Cloud Gaming" "https://www.xbox.com/en-US/play" "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/xbox.png"
setsid omarchy-launch-webapp "https://www.xbox.com/en-US/play" >/dev/null 2>&1 &
+37
View File
@@ -0,0 +1,37 @@
#!/bin/bash
# omarchy:summary=Install support for using Xbox controllers with Steam/RetroArch/etc.
# omarchy:requires-sudo=true
set -e
echo "Installing Xbox controller Bluetooth support..."
# Install xpadneo to ensure controllers work out of the box
omarchy-pkg-add linux-headers xpadneo-dkms
# Prevent xpad/xpadneo driver conflict
echo blacklist xpad | sudo tee /etc/modprobe.d/blacklist-xpad.conf >/dev/null
echo hid_xpadneo | sudo tee /etc/modules-load.d/xpadneo.conf >/dev/null
# Ensure user is in the input group (controllers need it)
needs_reboot=false
if ! id -nG "$USER" | grep -qw input; then
sudo usermod -aG input "$USER"
needs_reboot=true
fi
# Swap drivers in the running kernel so a reboot isn't needed otherwise
if lsmod | grep -q '^xpad '; then
sudo modprobe -r xpad 2>/dev/null || needs_reboot=true
fi
if $needs_reboot; then
gum confirm "Reboot needed to finish setup. Reboot now?" && sudo reboot now
exit 0
fi
sudo modprobe hid_xpadneo
echo ""
echo "Now you can pair your Xbox controller with Bluetooth using Super + Ctrl + B."
+28
View File
@@ -0,0 +1,28 @@
#!/bin/bash
# Install Helix and configure it to use the current Omarchy theme.
echo "Installing Helix..."
omarchy-pkg-add helix
mkdir -p ~/.config/helix/themes
# Symlink the rendered Omarchy theme so Helix tracks the active theme
ln -sf ~/.config/omarchy/current/theme/helix.toml ~/.config/helix/themes/omarchy.toml
# Only seed a config.toml if the user does not already have one
if [[ ! -f ~/.config/helix/config.toml ]]; then
cat >~/.config/helix/config.toml <<'EOF'
theme = "omarchy"
EOF
fi
# Ensure the symlink target exists for users whose current theme predates this template
if [[ ! -e ~/.config/omarchy/current/theme/helix.toml ]]; then
omarchy-theme-refresh
fi
# Arch-based distros ship Helix as 'helix' rather than the upstream 'hx'.
if ! grep -q '^alias hx="helix"' ~/.bashrc 2>/dev/null; then
echo 'alias hx="helix"' >>~/.bashrc
fi
+2 -1
View File
@@ -1,6 +1,7 @@
#!/bin/bash #!/bin/bash
# Install the NordVPN service with optional GUI. # omarchy:summary=Install the NordVPN service with optional GUI.
# omarchy:requires-sudo=true
echo "Installing NordVPN..." echo "Installing NordVPN..."
omarchy-pkg-aur-add nordvpn-bin omarchy-pkg-aur-add nordvpn-bin
+2 -1
View File
@@ -1,6 +1,7 @@
#!/bin/bash #!/bin/bash
# Install the ONCE service, enable its background service, and launch the TUI. # omarchy:summary=Install the ONCE service, enable its background service, and launch the TUI.
# omarchy:requires-sudo=true
echo "Installing ONCE..." echo "Installing ONCE..."
omarchy-pkg-add once-bin omarchy-pkg-add once-bin
-9
View File
@@ -1,9 +0,0 @@
#!/bin/bash
# Install and launch Steam after first letting the user pick the correct grahics card drivers.
set -e
echo "Now pick dependencies matching your graphics card"
sudo pacman -S steam
setsid gtk-launch steam >/dev/null 2>&1 &
+2 -1
View File
@@ -1,6 +1,7 @@
#!/bin/bash #!/bin/bash
# Install the Tailscale mesh VPN service and a web app for the Tailscale Admin Console. # omarchy:summary=Install the Tailscale mesh VPN service and a web app for the Tailscale Admin Console.
# omarchy:requires-sudo=true
echo -e "\nInstalling Tailscale..." echo -e "\nInstalling Tailscale..."
omarchy-pkg-add tailscale omarchy-pkg-add tailscale
+5 -1
View File
@@ -1,6 +1,8 @@
#!/bin/bash #!/bin/bash
# Install one of the approved terminals and set it as the default for Omarchy (Super + Return etc). # omarchy:summary=Install one of the approved terminals and set it as the default for Omarchy (Super + Return etc).
# omarchy:args=<alacritty|ghostty|kitty>
# omarchy:requires-sudo=true
if (($# == 0)); then if (($# == 0)); then
echo "Usage: omarchy-install-terminal [alacritty|ghostty|kitty]" echo "Usage: omarchy-install-terminal [alacritty|ghostty|kitty]"
@@ -20,6 +22,8 @@ kitty) desktop_id="kitty.desktop" ;;
;; ;;
esac esac
echo "Installing $package..."
# Install package # Install package
if omarchy-pkg-add $package; then if omarchy-pkg-add $package; then
# Copy custom desktop entry for alacritty with X-TerminalArg* keys # Copy custom desktop entry for alacritty with X-TerminalArg* keys
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# Install VSCode and configure it to use the gnome-libsecret password store, not to update automatically, and to use the current Omarchy theme. # omarchy:summary=Install VS Code and configure Omarchy defaults for secrets, updates, and theme
echo "Installing VSCode..." echo "Installing VSCode..."
omarchy-pkg-add visual-studio-code-bin omarchy-pkg-add visual-studio-code-bin
-19
View File
@@ -1,19 +0,0 @@
#!/bin/bash
# Install support for using Xbox controllers with Steam/RetroArch/etc.
set -e
# Install xpadneo to ensure controllers work out of the box
omarchy-pkg-add linux-headers
omarchy-pkg-aur-add xpadneo-dkms
# Prevent xpad/xpadneo driver conflict
echo blacklist xpad | sudo tee /etc/modprobe.d/blacklist-xpad.conf >/dev/null
echo hid_xpadneo | sudo tee /etc/modules-load.d/xpadneo.conf >/dev/null
# Give user access to game controllers
sudo usermod -a -G input $USER
# Modules need to be loaded
gum confirm "Install requires reboot. Ready?" && sudo reboot now
+1 -1
View File
@@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
# Launch the fastfetch TUI that gives information about the current system. # omarchy:summary=Launch the fastfetch TUI that gives information about the current system.
exec omarchy-launch-or-focus-tui "bash -c 'fastfetch; read -n 1 -s'" exec omarchy-launch-or-focus-tui "bash -c 'fastfetch; read -n 1 -s'"
+1 -1
View File
@@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
# Launch the Omarchy audio controls TUI (provided by wiremix). # omarchy:summary=Launch the Omarchy audio controls TUI (provided by wiremix).
omarchy-launch-or-focus-tui wiremix omarchy-launch-or-focus-tui wiremix

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