initial commit
This commit is contained in:
Executable
+30
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env bash
|
||||
# Backlight control with a dunst OSD. usage: brightness up|down|set <n>
|
||||
set -uo pipefail
|
||||
|
||||
STEP="${BRIGHTNESS_STEP:-5}"
|
||||
MIN=1 # never go fully dark — that looks like a crash
|
||||
ID=2594
|
||||
|
||||
command -v brightnessctl >/dev/null || { echo "brightnessctl not found" >&2; exit 1; }
|
||||
|
||||
pct() { brightnessctl -m | awk -F, '{gsub(/%/,"",$4); print $4}'; }
|
||||
|
||||
case "${1:-}" in
|
||||
up) brightnessctl -q set "${STEP}%+" ;;
|
||||
down) brightnessctl -q set "${STEP}%-" ;;
|
||||
set) brightnessctl -q set "${2:?need a percentage}%" ;;
|
||||
""|-h|--help) echo "usage: brightness up|down|set <percent>"; exit 0 ;;
|
||||
*) echo "unknown action: $1" >&2; exit 2 ;;
|
||||
esac
|
||||
|
||||
# Enforce the floor
|
||||
current="$(pct)"
|
||||
if (( current < MIN )); then
|
||||
brightnessctl -q set "${MIN}%"
|
||||
current="$MIN"
|
||||
fi
|
||||
|
||||
command -v dunstify >/dev/null && \
|
||||
dunstify -a osd -u low -r "$ID" -h "int:value:$current" \
|
||||
-i display-brightness "Brightness ${current}%"
|
||||
Executable
+60
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env bash
|
||||
# ---------------------------------------------------------------------------
|
||||
# Minimal xrandr multi-monitor switcher.
|
||||
# display auto | duplicate | extend | internal | external | list
|
||||
# "internal" is whichever output name looks like a laptop panel.
|
||||
# ---------------------------------------------------------------------------
|
||||
set -uo pipefail
|
||||
|
||||
command -v xrandr >/dev/null || { echo "xrandr not installed" >&2; exit 1; }
|
||||
|
||||
mapfile -t CONNECTED < <(xrandr --query | awk '/ connected/{print $1}')
|
||||
INTERNAL="$(printf '%s\n' "${CONNECTED[@]}" | grep -m1 -E '^(eDP|LVDS|DSI)' || true)"
|
||||
[[ -z "$INTERNAL" ]] && INTERNAL="${CONNECTED[0]:-}"
|
||||
mapfile -t EXTERNALS < <(printf '%s\n' "${CONNECTED[@]}" | grep -v "^${INTERNAL}$" || true)
|
||||
|
||||
reload_bar() { "$HOME/.config/polybar/launch.sh" >/dev/null 2>&1 & }
|
||||
restore_bg() { "$HOME/.local/bin/set-wallpaper" >/dev/null 2>&1 & }
|
||||
|
||||
case "${1:-auto}" in
|
||||
list)
|
||||
xrandr --query | grep -E ' connected|disconnected' ; exit 0 ;;
|
||||
|
||||
internal)
|
||||
args=(--output "$INTERNAL" --auto --primary)
|
||||
for e in "${EXTERNALS[@]}"; do args+=(--output "$e" --off); done
|
||||
xrandr "${args[@]}" ;;
|
||||
|
||||
external)
|
||||
if [[ ${#EXTERNALS[@]} -eq 0 ]]; then echo "no external display connected" >&2; exit 1; fi
|
||||
args=(--output "${EXTERNALS[0]}" --auto --primary --output "$INTERNAL" --off)
|
||||
for e in "${EXTERNALS[@]:1}"; do args+=(--output "$e" --off); done
|
||||
xrandr "${args[@]}" ;;
|
||||
|
||||
duplicate)
|
||||
if [[ ${#EXTERNALS[@]} -eq 0 ]]; then echo "no external display connected" >&2; exit 1; fi
|
||||
args=(--output "$INTERNAL" --auto --primary)
|
||||
for e in "${EXTERNALS[@]}"; do args+=(--output "$e" --auto --same-as "$INTERNAL"); done
|
||||
xrandr "${args[@]}" ;;
|
||||
|
||||
extend)
|
||||
if [[ ${#EXTERNALS[@]} -eq 0 ]]; then echo "no external display connected" >&2; exit 1; fi
|
||||
args=(--output "$INTERNAL" --auto --primary)
|
||||
prev="$INTERNAL"
|
||||
for e in "${EXTERNALS[@]}"; do
|
||||
args+=(--output "$e" --auto --right-of "$prev")
|
||||
prev="$e"
|
||||
done
|
||||
xrandr "${args[@]}" ;;
|
||||
|
||||
auto)
|
||||
# Extend if something external is plugged in, otherwise laptop panel only.
|
||||
if [[ ${#EXTERNALS[@]} -gt 0 ]]; then exec "$0" extend; else exec "$0" internal; fi ;;
|
||||
|
||||
*)
|
||||
echo "usage: display auto|duplicate|extend|internal|external|list" >&2; exit 2 ;;
|
||||
esac
|
||||
|
||||
sleep 0.5
|
||||
restore_bg
|
||||
reload_bar
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env bash
|
||||
# Restart a daemon idempotently — safe to call from i3's exec_always.
|
||||
# usage: restart-daemon <name> [args…]
|
||||
set -uo pipefail
|
||||
|
||||
name="${1:?usage: restart-daemon <name> [args...]}"
|
||||
shift || true
|
||||
|
||||
command -v "$name" >/dev/null 2>&1 || { echo "restart-daemon: $name not installed" >&2; exit 0; }
|
||||
|
||||
pkill -x "$name" >/dev/null 2>&1 || true
|
||||
for _ in {1..20}; do
|
||||
pgrep -x "$name" >/dev/null || break
|
||||
sleep 0.1
|
||||
done
|
||||
pgrep -x "$name" >/dev/null && pkill -9 -x "$name"
|
||||
|
||||
log="${XDG_CACHE_HOME:-$HOME/.cache}/$name.log"
|
||||
mkdir -p "$(dirname "$log")"
|
||||
exec "$name" "$@" >>"$log" 2>&1 &
|
||||
Executable
+49
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
# ---------------------------------------------------------------------------
|
||||
# Screenshots with maim. usage: screenshot full|area|window [--clip-only]
|
||||
# Images land in ~/Pictures/Screenshots and are copied to the clipboard.
|
||||
# ---------------------------------------------------------------------------
|
||||
set -uo pipefail
|
||||
|
||||
DIR="${SCREENSHOT_DIR:-$(xdg-user-dir PICTURES 2>/dev/null || echo "$HOME/Pictures")/Screenshots}"
|
||||
STAMP="$(date +%Y-%m-%d_%H-%M-%S)"
|
||||
FILE="$DIR/screenshot_$STAMP.png"
|
||||
MODE="${1:-full}"
|
||||
CLIP_ONLY=0
|
||||
[[ "${2:-}" == "--clip-only" ]] && CLIP_ONLY=1
|
||||
|
||||
command -v maim >/dev/null || { echo "maim not installed" >&2; exit 1; }
|
||||
mkdir -p "$DIR"
|
||||
|
||||
# Selection colour = Catppuccin mauve (maim wants floats 0-1)
|
||||
SELECT_COLOR="0.776,0.627,0.965,0.5"
|
||||
|
||||
case "$MODE" in
|
||||
full)
|
||||
maim --hidecursor --quality 10 "$FILE" ;;
|
||||
area)
|
||||
maim --select --hidecursor --quality 10 --color="$SELECT_COLOR" \
|
||||
--bordersize=2 --nodrag "$FILE" ;;
|
||||
window)
|
||||
maim --window "$(xdotool getactivewindow)" --hidecursor --quality 10 "$FILE" ;;
|
||||
*)
|
||||
echo "usage: screenshot full|area|window [--clip-only]" >&2; exit 2 ;;
|
||||
esac
|
||||
|
||||
# maim exits non-zero when the user cancels an area selection with Escape.
|
||||
if [[ ! -s "$FILE" ]]; then
|
||||
rm -f "$FILE"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
command -v xclip >/dev/null && xclip -selection clipboard -t image/png -i "$FILE"
|
||||
|
||||
if [[ "$CLIP_ONLY" == "1" ]]; then
|
||||
rm -f "$FILE"
|
||||
command -v dunstify >/dev/null && \
|
||||
dunstify -a screenshot -i camera-photo "Screenshot" "Copied to clipboard"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
command -v dunstify >/dev/null && \
|
||||
dunstify -a screenshot -i "$FILE" "Screenshot saved" "$(basename "$FILE")\nCopied to clipboard"
|
||||
Executable
+65
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env bash
|
||||
# ---------------------------------------------------------------------------
|
||||
# Apply a wallpaper with feh and remember the choice.
|
||||
#
|
||||
# set-wallpaper # restore the remembered wallpaper
|
||||
# set-wallpaper /path/img.png # set a specific image
|
||||
# set-wallpaper --random # pick a random one from the wallpaper dir
|
||||
# set-wallpaper --cache # (re)build the betterlockscreen cache
|
||||
#
|
||||
# The current selection is stored in $XDG_STATE_HOME/current-wallpaper.
|
||||
# ---------------------------------------------------------------------------
|
||||
set -uo pipefail
|
||||
|
||||
WALLPAPER_DIR="${WALLPAPER_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/wallpapers}"
|
||||
STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}"
|
||||
STATE_FILE="$STATE_DIR/current-wallpaper"
|
||||
MODE="${FEH_MODE:---bg-fill}"
|
||||
|
||||
mkdir -p "$STATE_DIR" "$WALLPAPER_DIR"
|
||||
|
||||
pick_random() {
|
||||
find -L "$WALLPAPER_DIR" -type f \
|
||||
\( -iname '*.png' -o -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.webp' \) \
|
||||
| shuf -n1
|
||||
}
|
||||
|
||||
first_available() {
|
||||
find -L "$WALLPAPER_DIR" -type f \
|
||||
\( -iname '*.png' -o -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.webp' \) \
|
||||
| sort | head -n1
|
||||
}
|
||||
|
||||
cache_lockscreen=0
|
||||
target=""
|
||||
|
||||
case "${1:-}" in
|
||||
--random) target="$(pick_random)" ;;
|
||||
--cache) cache_lockscreen=1 ;;
|
||||
"") target="$(cat "$STATE_FILE" 2>/dev/null || true)" ;;
|
||||
-*) echo "unknown option: $1" >&2; exit 2 ;;
|
||||
*) target="$1"; cache_lockscreen=1 ;;
|
||||
esac
|
||||
|
||||
# Fall back through: remembered -> anything in the dir -> a flat Macchiato base
|
||||
if [[ -z "$target" || ! -f "$target" ]]; then
|
||||
target="$(first_available)"
|
||||
fi
|
||||
|
||||
if [[ -z "$target" || ! -f "$target" ]]; then
|
||||
echo "set-wallpaper: no image found in $WALLPAPER_DIR — using a flat colour" >&2
|
||||
command -v xsetroot >/dev/null && xsetroot -solid "#24273a"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
command -v feh >/dev/null || { echo "set-wallpaper: feh is not installed" >&2; exit 1; }
|
||||
|
||||
feh --no-fehbg "$MODE" "$target"
|
||||
printf '%s\n' "$target" > "$STATE_FILE"
|
||||
|
||||
# Keep the lock screen in sync with the desktop. Caching is slow (imagemagick
|
||||
# blurs the image at every resolution), so only do it when the image changed.
|
||||
if [[ "$cache_lockscreen" == "1" ]] && command -v betterlockscreen >/dev/null; then
|
||||
( betterlockscreen --update "$target" --blur 0.5 >/dev/null 2>&1 &
|
||||
disown ) 2>/dev/null || true
|
||||
fi
|
||||
Executable
+66
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env bash
|
||||
# Volume / mic control with a dunst OSD. usage: volume up|down|mute|micmute|set <n>
|
||||
set -uo pipefail
|
||||
|
||||
STEP="${VOLUME_STEP:-5}"
|
||||
MAX="${VOLUME_MAX:-100}"
|
||||
SINK="@DEFAULT_AUDIO_SINK@"
|
||||
SOURCE="@DEFAULT_AUDIO_SOURCE@"
|
||||
ID=2593 # fixed notification id => the OSD replaces itself instead of stacking
|
||||
|
||||
have() { command -v "$1" >/dev/null 2>&1; }
|
||||
have wpctl || { echo "wpctl (wireplumber) not found" >&2; exit 1; }
|
||||
|
||||
get_volume() {
|
||||
wpctl get-volume "$SINK" | awk '{printf "%d", $2 * 100}'
|
||||
}
|
||||
is_muted() {
|
||||
wpctl get-volume "$SINK" | grep -q MUTED
|
||||
}
|
||||
|
||||
osd() {
|
||||
have dunstify || return 0
|
||||
local icon="$1" text="$2" value="$3"
|
||||
dunstify -a osd -u low -r "$ID" -h "int:value:$value" -i "$icon" "$text"
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
up)
|
||||
wpctl set-mute "$SINK" 0
|
||||
wpctl set-volume -l "$(awk "BEGIN{print $MAX/100}")" "$SINK" "${STEP}%+"
|
||||
;;
|
||||
down)
|
||||
wpctl set-mute "$SINK" 0
|
||||
wpctl set-volume "$SINK" "${STEP}%-"
|
||||
;;
|
||||
set)
|
||||
wpctl set-volume -l "$(awk "BEGIN{print $MAX/100}")" "$SINK" "${2:?need a percentage}%"
|
||||
;;
|
||||
mute)
|
||||
wpctl set-mute "$SINK" toggle
|
||||
;;
|
||||
micmute)
|
||||
wpctl set-mute "$SOURCE" toggle
|
||||
if wpctl get-volume "$SOURCE" | grep -q MUTED; then
|
||||
osd microphone-sensitivity-muted "Microphone muted" 0
|
||||
else
|
||||
osd microphone-sensitivity-high "Microphone live" 100
|
||||
fi
|
||||
exit 0
|
||||
;;
|
||||
""|-h|--help)
|
||||
echo "usage: volume up|down|mute|micmute|set <percent>"; exit 0 ;;
|
||||
*)
|
||||
echo "unknown action: $1" >&2; exit 2 ;;
|
||||
esac
|
||||
|
||||
vol="$(get_volume)"
|
||||
if is_muted; then
|
||||
osd audio-volume-muted "Muted" 0
|
||||
elif (( vol >= 66 )); then osd audio-volume-high "Volume ${vol}%" "$vol"
|
||||
elif (( vol >= 33 )); then osd audio-volume-medium "Volume ${vol}%" "$vol"
|
||||
else osd audio-volume-low "Volume ${vol}%" "$vol"
|
||||
fi
|
||||
|
||||
# Nudge polybar so the bar updates instantly rather than on its 5s poll
|
||||
pkill -RTMIN+1 polybar 2>/dev/null || true
|
||||
Reference in New Issue
Block a user