421 lines
16 KiB
Bash
Executable file
421 lines
16 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
|
|
QUICKSHELL_CONFIG_NAME="ii"
|
|
XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
|
|
XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"
|
|
XDG_STATE_HOME="${XDG_STATE_HOME:-$HOME/.local/state}"
|
|
CONFIG_DIR="$XDG_CONFIG_HOME/quickshell/$QUICKSHELL_CONFIG_NAME"
|
|
CACHE_DIR="$XDG_CACHE_HOME/quickshell"
|
|
STATE_DIR="$XDG_STATE_HOME/quickshell"
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
SHELL_CONFIG_FILE="$XDG_CONFIG_HOME/illogical-impulse/config.json"
|
|
MATUGEN_DIR="$XDG_CONFIG_HOME/matugen"
|
|
terminalscheme="$SCRIPT_DIR/terminal/scheme-base.json"
|
|
|
|
handle_kde_material_you_colors() {
|
|
# Check if Qt app theming is enabled in config
|
|
if [ -f "$SHELL_CONFIG_FILE" ]; then
|
|
enable_qt_apps=$(jq -r '.appearance.wallpaperTheming.enableQtApps' "$SHELL_CONFIG_FILE")
|
|
if [ "$enable_qt_apps" == "false" ]; then
|
|
return
|
|
fi
|
|
fi
|
|
|
|
# Map $type_flag to allowed scheme variants for kde-material-you-colors-wrapper.sh
|
|
local kde_scheme_variant=""
|
|
case "$type_flag" in
|
|
scheme-content|scheme-expressive|scheme-fidelity|scheme-fruit-salad|scheme-monochrome|scheme-neutral|scheme-rainbow|scheme-tonal-spot)
|
|
kde_scheme_variant="$type_flag"
|
|
;;
|
|
*)
|
|
kde_scheme_variant="scheme-tonal-spot" # default
|
|
;;
|
|
esac
|
|
"$XDG_CONFIG_HOME"/matugen/templates/kde/kde-material-you-colors-wrapper.sh --scheme-variant "$kde_scheme_variant"
|
|
}
|
|
|
|
pre_process() {
|
|
local mode_flag="$1"
|
|
# Set GNOME color-scheme if mode_flag is dark or light
|
|
if [[ "$mode_flag" == "dark" ]]; then
|
|
gsettings set org.gnome.desktop.interface color-scheme 'prefer-dark'
|
|
gsettings set org.gnome.desktop.interface gtk-theme 'adw-gtk3-dark'
|
|
elif [[ "$mode_flag" == "light" ]]; then
|
|
gsettings set org.gnome.desktop.interface color-scheme 'prefer-light'
|
|
gsettings set org.gnome.desktop.interface gtk-theme 'adw-gtk3'
|
|
fi
|
|
|
|
if [ ! -d "$CACHE_DIR"/user/generated ]; then
|
|
mkdir -p "$CACHE_DIR"/user/generated
|
|
fi
|
|
}
|
|
|
|
post_process() {
|
|
local screen_width="$1"
|
|
local screen_height="$2"
|
|
local wallpaper_path="$3"
|
|
|
|
|
|
handle_kde_material_you_colors &
|
|
|
|
# Determine the largest region on the wallpaper that's sufficiently un-busy to put widgets in
|
|
# if [ ! -f "$MATUGEN_DIR/scripts/least_busy_region.py" ]; then
|
|
# echo "Error: least_busy_region.py script not found in $MATUGEN_DIR/scripts/"
|
|
# else
|
|
# "$MATUGEN_DIR/scripts/least_busy_region.py" \
|
|
# --screen-width "$screen_width" --screen-height "$screen_height" \
|
|
# --width 300 --height 200 \
|
|
# "$wallpaper_path" > "$STATE_DIR"/user/generated/wallpaper/least_busy_region.json
|
|
# fi
|
|
}
|
|
|
|
check_and_prompt_upscale() {
|
|
local img="$1"
|
|
min_width_desired="$(hyprctl monitors -j | jq '([.[].width] | max)' | xargs)" # max monitor width
|
|
min_height_desired="$(hyprctl monitors -j | jq '([.[].height] | max)' | xargs)" # max monitor height
|
|
|
|
if command -v identify &>/dev/null && [ -f "$img" ]; then
|
|
local img_width img_height
|
|
if is_video "$img"; then # Not check resolution for videos, just let em pass
|
|
img_width=$min_width_desired
|
|
img_height=$min_height_desired
|
|
else
|
|
img_width=$(identify -format "%w" "$img" 2>/dev/null)
|
|
img_height=$(identify -format "%h" "$img" 2>/dev/null)
|
|
fi
|
|
if [[ "$img_width" -lt "$min_width_desired" || "$img_height" -lt "$min_height_desired" ]]; then
|
|
action=$(notify-send "Upscale?" \
|
|
"Image resolution (${img_width}x${img_height}) is lower than screen resolution (${min_width_desired}x${min_height_desired})" \
|
|
-A "open_upscayl=Open Upscayl"\
|
|
-a "Wallpaper switcher")
|
|
if [[ "$action" == "open_upscayl" ]]; then
|
|
if command -v upscayl &>/dev/null; then
|
|
nohup upscayl > /dev/null 2>&1 &
|
|
else
|
|
action2=$(notify-send \
|
|
-a "Wallpaper switcher" \
|
|
-c "im.error" \
|
|
-A "install_upscayl=Install Upscayl (Arch)" \
|
|
"Install Upscayl?" \
|
|
"yay -S upscayl-bin")
|
|
if [[ "$action2" == "install_upscayl" ]]; then
|
|
kitty -1 yay -S upscayl-bin
|
|
if command -v upscayl &>/dev/null; then
|
|
nohup upscayl > /dev/null 2>&1 &
|
|
fi
|
|
fi
|
|
fi
|
|
fi
|
|
fi
|
|
fi
|
|
}
|
|
|
|
CUSTOM_DIR="$XDG_CONFIG_HOME/hypr/custom"
|
|
RESTORE_SCRIPT_DIR="$CUSTOM_DIR/scripts"
|
|
RESTORE_SCRIPT="$RESTORE_SCRIPT_DIR/__restore_video_wallpaper.sh"
|
|
THUMBNAIL_DIR="$RESTORE_SCRIPT_DIR/mpvpaper_thumbnails"
|
|
VIDEO_OPTS="no-audio loop hwdec=auto scale=bilinear interpolation=no video-sync=display-resample panscan=1.0 video-scale-x=1.0 video-scale-y=1.0 video-align-x=0.5 video-align-y=0.5 load-scripts=no"
|
|
|
|
is_video() {
|
|
local extension="${1##*.}"
|
|
[[ "$extension" == "mp4" || "$extension" == "webm" || "$extension" == "mkv" || "$extension" == "avi" || "$extension" == "mov" ]] && return 0 || return 1
|
|
}
|
|
|
|
kill_existing_mpvpaper() {
|
|
pkill -f -9 mpvpaper || true
|
|
}
|
|
|
|
create_restore_script() {
|
|
local video_path=$1
|
|
cat > "$RESTORE_SCRIPT.tmp" << EOF
|
|
#!/bin/bash
|
|
# Generated by switchwall.sh - Don't modify it by yourself.
|
|
# Time: $(date)
|
|
|
|
pkill -f -9 mpvpaper
|
|
|
|
for monitor in \$(hyprctl monitors -j | jq -r '.[] | .name'); do
|
|
mpvpaper -o "$VIDEO_OPTS" "\$monitor" "$video_path" &
|
|
sleep 0.1
|
|
done
|
|
EOF
|
|
mv "$RESTORE_SCRIPT.tmp" "$RESTORE_SCRIPT"
|
|
chmod +x "$RESTORE_SCRIPT"
|
|
}
|
|
|
|
remove_restore() {
|
|
cat > "$RESTORE_SCRIPT.tmp" << EOF
|
|
#!/bin/bash
|
|
# The content of this script will be generated by switchwall.sh - Don't modify it by yourself.
|
|
EOF
|
|
mv "$RESTORE_SCRIPT.tmp" "$RESTORE_SCRIPT"
|
|
}
|
|
|
|
set_wallpaper_path() {
|
|
local path="$1"
|
|
if [ -f "$SHELL_CONFIG_FILE" ]; then
|
|
jq --arg path "$path" '.background.wallpaperPath = $path' "$SHELL_CONFIG_FILE" > "$SHELL_CONFIG_FILE.tmp" && mv "$SHELL_CONFIG_FILE.tmp" "$SHELL_CONFIG_FILE"
|
|
fi
|
|
}
|
|
|
|
set_thumbnail_path() {
|
|
local path="$1"
|
|
if [ -f "$SHELL_CONFIG_FILE" ]; then
|
|
jq --arg path "$path" '.background.thumbnailPath = $path' "$SHELL_CONFIG_FILE" > "$SHELL_CONFIG_FILE.tmp" && mv "$SHELL_CONFIG_FILE.tmp" "$SHELL_CONFIG_FILE"
|
|
fi
|
|
}
|
|
|
|
switch() {
|
|
imgpath="$1"
|
|
mode_flag="$2"
|
|
type_flag="$3"
|
|
color_flag="$4"
|
|
color="$5"
|
|
read scale screenx screeny screensizey < <(hyprctl monitors -j | jq '.[] | select(.focused) | .scale, .x, .y, .height' | xargs)
|
|
cursorposx=$(hyprctl cursorpos -j | jq '.x' 2>/dev/null) || cursorposx=960
|
|
cursorposx=$(bc <<< "scale=0; ($cursorposx - $screenx) * $scale / 1")
|
|
cursorposy=$(hyprctl cursorpos -j | jq '.y' 2>/dev/null) || cursorposy=540
|
|
cursorposy=$(bc <<< "scale=0; ($cursorposy - $screeny) * $scale / 1")
|
|
cursorposy_inverted=$((screensizey - cursorposy))
|
|
|
|
if [[ "$color_flag" == "1" ]]; then
|
|
matugen_args=(color hex "$color")
|
|
generate_colors_material_args=(--color "$color")
|
|
else
|
|
if [[ -z "$imgpath" ]]; then
|
|
echo 'Aborted'
|
|
exit 0
|
|
fi
|
|
|
|
check_and_prompt_upscale "$imgpath" &
|
|
kill_existing_mpvpaper
|
|
|
|
if is_video "$imgpath"; then
|
|
mkdir -p "$THUMBNAIL_DIR"
|
|
|
|
missing_deps=()
|
|
if ! command -v mpvpaper &> /dev/null; then
|
|
missing_deps+=("mpvpaper")
|
|
fi
|
|
if ! command -v ffmpeg &> /dev/null; then
|
|
missing_deps+=("ffmpeg")
|
|
fi
|
|
if [ ${#missing_deps[@]} -gt 0 ]; then
|
|
echo "Missing deps: ${missing_deps[*]}"
|
|
echo "Arch: sudo pacman -S ${missing_deps[*]}"
|
|
action=$(notify-send \
|
|
-a "Wallpaper switcher" \
|
|
-c "im.error" \
|
|
-A "install_arch=Install (Arch)" \
|
|
"Can't switch to video wallpaper" \
|
|
"Missing dependencies: ${missing_deps[*]}")
|
|
if [[ "$action" == "install_arch" ]]; then
|
|
kitty -1 sudo pacman -S "${missing_deps[*]}"
|
|
if command -v mpvpaper &>/dev/null && command -v ffmpeg &>/dev/null; then
|
|
notify-send 'Wallpaper switcher' 'Alright, try again!' -a "Wallpaper switcher"
|
|
fi
|
|
fi
|
|
exit 0
|
|
fi
|
|
|
|
# Set wallpaper path
|
|
set_wallpaper_path "$imgpath"
|
|
|
|
# Set video wallpaper
|
|
local video_path="$imgpath"
|
|
monitors=$(hyprctl monitors -j | jq -r '.[] | .name')
|
|
for monitor in $monitors; do
|
|
mpvpaper -o "$VIDEO_OPTS" "$monitor" "$video_path" &
|
|
sleep 0.1
|
|
done
|
|
|
|
# Extract first frame for color generation
|
|
thumbnail="$THUMBNAIL_DIR/$(basename "$imgpath").jpg"
|
|
ffmpeg -y -i "$imgpath" -vframes 1 "$thumbnail" 2>/dev/null
|
|
|
|
# Set thumbnail path
|
|
set_thumbnail_path "$thumbnail"
|
|
|
|
if [ -f "$thumbnail" ]; then
|
|
matugen_args=(image "$thumbnail")
|
|
generate_colors_material_args=(--path "$thumbnail")
|
|
create_restore_script "$video_path"
|
|
else
|
|
echo "Cannot create image to colorgen"
|
|
remove_restore
|
|
exit 1
|
|
fi
|
|
else
|
|
matugen_args=(image "$imgpath")
|
|
generate_colors_material_args=(--path "$imgpath")
|
|
# Update wallpaper path in config
|
|
set_wallpaper_path "$imgpath"
|
|
remove_restore
|
|
fi
|
|
fi
|
|
|
|
# Determine mode if not set
|
|
if [[ -z "$mode_flag" ]]; then
|
|
current_mode=$(gsettings get org.gnome.desktop.interface color-scheme 2>/dev/null | tr -d "'")
|
|
if [[ "$current_mode" == "prefer-dark" ]]; then
|
|
mode_flag="dark"
|
|
else
|
|
mode_flag="light"
|
|
fi
|
|
fi
|
|
|
|
# enforce dark mode for terminal
|
|
if [[ -n "$mode_flag" ]]; then
|
|
matugen_args+=(--mode "$mode_flag")
|
|
if [[ $(jq -r '.appearance.wallpaperTheming.terminalGenerationProps.forceDarkMode' "$SHELL_CONFIG_FILE") == "true" ]]; then
|
|
generate_colors_material_args+=(--mode "dark")
|
|
else
|
|
generate_colors_material_args+=(--mode "$mode_flag")
|
|
fi
|
|
fi
|
|
[[ -n "$type_flag" ]] && matugen_args+=(--type "$type_flag") && generate_colors_material_args+=(--scheme "$type_flag")
|
|
generate_colors_material_args+=(--termscheme "$terminalscheme" --blend_bg_fg)
|
|
generate_colors_material_args+=(--cache "$STATE_DIR/user/generated/color.txt")
|
|
|
|
pre_process "$mode_flag"
|
|
|
|
# Check if app and shell theming is enabled in config
|
|
if [ -f "$SHELL_CONFIG_FILE" ]; then
|
|
enable_apps_shell=$(jq -r '.appearance.wallpaperTheming.enableAppsAndShell' "$SHELL_CONFIG_FILE")
|
|
if [ "$enable_apps_shell" == "false" ]; then
|
|
echo "App and shell theming disabled, skipping matugen and color generation"
|
|
return
|
|
fi
|
|
fi
|
|
|
|
# Set harmony and related properties
|
|
if [ -f "$SHELL_CONFIG_FILE" ]; then
|
|
harmony=$(jq -r '.appearance.wallpaperTheming.terminalGenerationProps.harmony' "$SHELL_CONFIG_FILE")
|
|
harmonize_threshold=$(jq -r '.appearance.wallpaperTheming.terminalGenerationProps.harmonizeThreshold' "$SHELL_CONFIG_FILE")
|
|
term_fg_boost=$(jq -r '.appearance.wallpaperTheming.terminalGenerationProps.termFgBoost' "$SHELL_CONFIG_FILE")
|
|
[[ "$harmony" != "null" && -n "$harmony" ]] && generate_colors_material_args+=(--harmony "$harmony")
|
|
[[ "$harmonize_threshold" != "null" && -n "$harmonize_threshold" ]] && generate_colors_material_args+=(--harmonize_threshold "$harmonize_threshold")
|
|
[[ "$term_fg_boost" != "null" && -n "$term_fg_boost" ]] && generate_colors_material_args+=(--term_fg_boost "$term_fg_boost")
|
|
fi
|
|
|
|
matugen "${matugen_args[@]}"
|
|
source "$(eval echo $ILLOGICAL_IMPULSE_VIRTUAL_ENV)/bin/activate"
|
|
python3 "$SCRIPT_DIR/generate_colors_material.py" "${generate_colors_material_args[@]}" \
|
|
> "$STATE_DIR"/user/generated/material_colors.scss
|
|
"$SCRIPT_DIR"/applycolor.sh
|
|
deactivate
|
|
|
|
# Pass screen width, height, and wallpaper path to post_process
|
|
max_width_desired="$(hyprctl monitors -j | jq '([.[].width] | min)' | xargs)"
|
|
max_height_desired="$(hyprctl monitors -j | jq '([.[].height] | min)' | xargs)"
|
|
post_process "$max_width_desired" "$max_height_desired" "$imgpath"
|
|
}
|
|
|
|
main() {
|
|
imgpath=""
|
|
mode_flag=""
|
|
type_flag=""
|
|
color_flag=""
|
|
color=""
|
|
noswitch_flag=""
|
|
|
|
get_type_from_config() {
|
|
jq -r '.appearance.palette.type' "$SHELL_CONFIG_FILE" 2>/dev/null || echo "auto"
|
|
}
|
|
|
|
detect_scheme_type_from_image() {
|
|
local img="$1"
|
|
"$SCRIPT_DIR"/scheme_for_image.py "$img" 2>/dev/null | tr -d '\n'
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--mode)
|
|
mode_flag="$2"
|
|
shift 2
|
|
;;
|
|
--type)
|
|
type_flag="$2"
|
|
shift 2
|
|
;;
|
|
--color)
|
|
color_flag="1"
|
|
if [[ "$2" =~ ^#?[A-Fa-f0-9]{6}$ ]]; then
|
|
color="$2"
|
|
shift 2
|
|
else
|
|
color=$(hyprpicker --no-fancy)
|
|
shift
|
|
fi
|
|
;;
|
|
--image)
|
|
imgpath="$2"
|
|
shift 2
|
|
;;
|
|
--noswitch)
|
|
noswitch_flag="1"
|
|
imgpath=$(jq -r '.background.wallpaperPath' "$SHELL_CONFIG_FILE" 2>/dev/null || echo "")
|
|
shift
|
|
;;
|
|
*)
|
|
if [[ -z "$imgpath" ]]; then
|
|
imgpath="$1"
|
|
fi
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# If type_flag is not set, get it from config
|
|
if [[ -z "$type_flag" ]]; then
|
|
type_flag="$(get_type_from_config)"
|
|
fi
|
|
|
|
# Validate type_flag (allow 'auto' as well)
|
|
allowed_types=(scheme-content scheme-expressive scheme-fidelity scheme-fruit-salad scheme-monochrome scheme-neutral scheme-rainbow scheme-tonal-spot auto)
|
|
valid_type=0
|
|
for t in "${allowed_types[@]}"; do
|
|
if [[ "$type_flag" == "$t" ]]; then
|
|
valid_type=1
|
|
break
|
|
fi
|
|
done
|
|
if [[ $valid_type -eq 0 ]]; then
|
|
echo "[switchwall.sh] Warning: Invalid type '$type_flag', defaulting to 'auto'" >&2
|
|
type_flag="auto"
|
|
fi
|
|
|
|
# Only prompt for wallpaper if not using --color and not using --noswitch and no imgpath set
|
|
if [[ -z "$imgpath" && -z "$color_flag" && -z "$noswitch_flag" ]]; then
|
|
cd "$(xdg-user-dir PICTURES)/Wallpapers/showcase" 2>/dev/null || cd "$(xdg-user-dir PICTURES)/Wallpapers" 2>/dev/null || cd "$(xdg-user-dir PICTURES)" || return 1
|
|
imgpath="$(kdialog --getopenfilename . --title 'Choose wallpaper')"
|
|
fi
|
|
|
|
# If type_flag is 'auto', detect scheme type from image (after imgpath is set)
|
|
if [[ "$type_flag" == "auto" ]]; then
|
|
if [[ -n "$imgpath" && -f "$imgpath" ]]; then
|
|
detected_type="$(detect_scheme_type_from_image "$imgpath")"
|
|
# Only use detected_type if it's valid
|
|
valid_detected=0
|
|
for t in "${allowed_types[@]}"; do
|
|
if [[ "$detected_type" == "$t" && "$detected_type" != "auto" ]]; then
|
|
valid_detected=1
|
|
break
|
|
fi
|
|
done
|
|
if [[ $valid_detected -eq 1 ]]; then
|
|
type_flag="$detected_type"
|
|
else
|
|
echo "[switchwall] Warning: Could not auto-detect a valid scheme, defaulting to 'scheme-tonal-spot'" >&2
|
|
type_flag="scheme-tonal-spot"
|
|
fi
|
|
else
|
|
echo "[switchwall] Warning: No image to auto-detect scheme from, defaulting to 'scheme-tonal-spot'" >&2
|
|
type_flag="scheme-tonal-spot"
|
|
fi
|
|
fi
|
|
|
|
switch "$imgpath" "$mode_flag" "$type_flag" "$color_flag" "$color"
|
|
}
|
|
|
|
main "$@"
|