aboutsummaryrefslogtreecommitdiffstats
path: root/config/hypr/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'config/hypr/scripts')
-rwxr-xr-xconfig/hypr/scripts/ChangeLayout.sh31
-rwxr-xr-xconfig/hypr/scripts/DarkLight.sh15
-rwxr-xr-xconfig/hypr/scripts/Distro_update.sh2
-rwxr-xr-xconfig/hypr/scripts/Hypridle.sh3
-rwxr-xr-xconfig/hypr/scripts/KeyBinds.sh136
-rwxr-xr-xconfig/hypr/scripts/KeyHints.sh3
-rwxr-xr-xconfig/hypr/scripts/KeyboardLayout.sh119
-rwxr-xr-xconfig/hypr/scripts/KillActiveProcess.sh7
-rwxr-xr-xconfig/hypr/scripts/KooLsDotsUpdate.sh12
-rwxr-xr-xconfig/hypr/scripts/Kool_Quick_Settings.sh153
-rwxr-xr-xconfig/hypr/scripts/PortalHyprland.sh40
-rwxr-xr-xconfig/hypr/scripts/RofiSearch.sh15
-rwxr-xr-xconfig/hypr/scripts/ScreenShot.sh3
-rwxr-xr-xconfig/hypr/scripts/Sounds.sh17
-rwxr-xr-xconfig/hypr/scripts/SwitchKeyboardLayout.sh103
-rwxr-xr-xconfig/hypr/scripts/Tak0-Per-Window-Switch.sh20
-rwxr-xr-xconfig/hypr/scripts/ThemeChanger.sh145
-rwxr-xr-xconfig/hypr/scripts/TouchPad.sh48
-rwxr-xr-xconfig/hypr/scripts/Volume.sh132
-rwxr-xr-xconfig/hypr/scripts/WallustSwww.sh81
-rwxr-xr-xconfig/hypr/scripts/WaybarScripts.sh10
-rwxr-xr-xconfig/hypr/scripts/keybinds_parser.py245
-rwxr-xr-xconfig/hypr/scripts/sddm_wallpaper.sh51
-rwxr-xr-xconfig/hypr/scripts/update_WindowRules.sh60
24 files changed, 1121 insertions, 330 deletions
diff --git a/config/hypr/scripts/ChangeLayout.sh b/config/hypr/scripts/ChangeLayout.sh
index e2436b79..221f9637 100755
--- a/config/hypr/scripts/ChangeLayout.sh
+++ b/config/hypr/scripts/ChangeLayout.sh
@@ -6,19 +6,34 @@ notif="$HOME/.config/swaync/images/ja.png"
LAYOUT=$(hyprctl -j getoption general:layout | jq '.str' | sed 's/"//g')
+# Reverse layout value to reuse toggle logic. So layouts don't get swapped initially.
+if [ "$1" = "init" ]; then
+ if [ "$LAYOUT" = "master" ]; then
+ LAYOUT="dwindle"
+ else
+ LAYOUT="master"
+ fi
+fi
+
case $LAYOUT in
"master")
- hyprctl keyword general:layout dwindle
- # SUPER+J/K are global and managed by KeybindsLayoutInit.sh; only manage SUPER+O here
- hyprctl keyword bind SUPER,O,togglesplit
+ hyprctl keyword general:layout dwindle
+ hyprctl keyword unbind SUPER,J
+ hyprctl keyword unbind SUPER,K
+ hyprctl keyword bind SUPER,J,cyclenext
+ hyprctl keyword bind SUPER,K,cyclenext,prev
+ hyprctl keyword bind SUPER,O,togglesplit
notify-send -e -u low -i "$notif" " Dwindle Layout"
- ;;
+ ;;
"dwindle")
- hyprctl keyword general:layout master
- # Drop togglesplit binding on SUPER+O when switching back to master
- hyprctl keyword unbind SUPER,O
+ hyprctl keyword general:layout master
+ hyprctl keyword unbind SUPER,J
+ hyprctl keyword unbind SUPER,K
+ hyprctl keyword unbind SUPER,O
+ hyprctl keyword bind SUPER,J,layoutmsg,cyclenext
+ hyprctl keyword bind SUPER,K,layoutmsg,cycleprev
notify-send -e -u low -i "$notif" " Master Layout"
- ;;
+ ;;
*) ;;
esac
diff --git a/config/hypr/scripts/DarkLight.sh b/config/hypr/scripts/DarkLight.sh
index e473efb2..37016ec3 100755
--- a/config/hypr/scripts/DarkLight.sh
+++ b/config/hypr/scripts/DarkLight.sh
@@ -4,7 +4,8 @@
# Note: Scripts are looking for keywords Light or Dark except for wallpapers as the are in a separate directories
# Paths
-wallpaper_base_path="$HOME/Pictures/wallpapers/Dynamic-Wallpapers"
+PICTURES_DIR="$(xdg-user-dir PICTURES 2>/dev/null || echo "$HOME/Pictures")"
+wallpaper_base_path="$PICTURES_DIR/wallpapers/Dynamic-Wallpapers"
dark_wallpapers="$wallpaper_base_path/Dark"
light_wallpapers="$wallpaper_base_path/Light"
hypr_config_path="$HOME/.config/hypr"
@@ -19,6 +20,10 @@ kitty_conf="$HOME/.config/kitty/kitty.conf"
wallust_config="$HOME/.config/wallust/wallust.toml"
pallete_dark="dark16"
pallete_light="light16"
+qt5ct_dark="$HOME/.config/qt5ct/colors/Catppuccin-Mocha.conf"
+qt5ct_light="$HOME/.config/qt5ct/colors/Catppuccin-Latte.conf"
+qt6ct_dark="$HOME/.config/qt6ct/colors/Catppuccin-Mocha.conf"
+qt6ct_light="$HOME/.config/qt6ct/colors/Catppuccin-Latte.conf"
# intial kill process
for pid in waybar rofi swaync ags swaybg; do
@@ -43,6 +48,14 @@ else
# Logic for Light mode
wallpaper_path="$light_wallpapers"
fi
+# Select Qt color scheme templates for the upcoming mode
+if [ "$next_mode" = "Dark" ]; then
+ qt5ct_color_scheme="$qt5ct_dark"
+ qt6ct_color_scheme="$qt6ct_dark"
+else
+ qt5ct_color_scheme="$qt5ct_light"
+ qt6ct_color_scheme="$qt6ct_light"
+fi
# Function to update theme mode for the next cycle
update_theme_mode() {
diff --git a/config/hypr/scripts/Distro_update.sh b/config/hypr/scripts/Distro_update.sh
index 2b3376e3..917f303b 100755
--- a/config/hypr/scripts/Distro_update.sh
+++ b/config/hypr/scripts/Distro_update.sh
@@ -27,7 +27,7 @@ elif command -v dnf &> /dev/null; then
notify-send -i "$iDIR/ja.png" -u low 'Fedora system' 'has been updated.'
elif command -v apt &> /dev/null; then
# Debian-based (Debian, Ubuntu, etc.)
- kitty -T update sudo apt update && sudo apt upgrade -y
+ kitty -T update bash -c "sudo apt update && sudo apt upgrade -y"
notify-send -i "$iDIR/ja.png" -u low 'Debian/Ubuntu system' 'has been updated.'
elif command -v zypper &> /dev/null; then
# openSUSE-based
diff --git a/config/hypr/scripts/Hypridle.sh b/config/hypr/scripts/Hypridle.sh
index 6acff434..a9bb90d7 100755
--- a/config/hypr/scripts/Hypridle.sh
+++ b/config/hypr/scripts/Hypridle.sh
@@ -15,7 +15,8 @@ elif [[ "$1" == "toggle" ]]; then
if pgrep -x "$PROCESS" >/dev/null; then
pkill "$PROCESS"
else
- "$PROCESS"
+ "$PROCESS" >/dev/null 2>&1 &
+ disown
fi
else
echo "Usage: $0 {status|toggle}"
diff --git a/config/hypr/scripts/KeyBinds.sh b/config/hypr/scripts/KeyBinds.sh
index 4158b762..26ae832b 100755
--- a/config/hypr/scripts/KeyBinds.sh
+++ b/config/hypr/scripts/KeyBinds.sh
@@ -21,135 +21,19 @@ msg='☣️ NOTE ☣️: Clicking with Mouse or Pressing ENTER will have NO func
files=("$keybinds_conf" "$user_keybinds_conf")
[[ -f "$laptop_conf" ]] && files+=("$laptop_conf")
-# Parse binds/unbinds from files, detect overrides, and keep unique effective binds
-declare -A binding_map # combo -> bind line (effective)
-declare -A source_map # combo -> source file
-declare -A user_bind_map # combo -> user bind line
-declare -A unbound_user # combo -> 1 if explicitly unbound in user file
-declare -A seen_any_bind # combo -> 1 if any bind seen (for iteration)
-declare -A default_seen # combo -> 1 if default bind exists
-declare -a missing_unbind_suggestions_arr
+# Parse binds using the python script for speed
+# The last argument must be the user config for override logic to work correctly
+display_keybinds=$("$HOME/.config/hypr/scripts/keybinds_parser.py" "${files[@]}")
-normalize_combo() { echo "$1" | sed -E 's/[[:space:]]//g'; }
-
-extract_combo() {
- # arg: a bind/unbind line; returns "mods,key" via echo
- local s="$1"
- s="$(echo "$s" | sed -E 's/[[:space:]]+#.*$//')"
- if [[ "$s" =~ = ]]; then
- local rhs="${s#*=}"
- local mods="$(echo "$rhs" | awk -F',' '{gsub(/^[ \t]+|[ \t]+$/,"",$1); print $1}')"
- local key="$(echo "$rhs" | awk -F',' '{gsub(/^[ \t]+|[ \t]+$/,"",$2); print $2}')"
- echo "${mods},${key}"
- fi
-}
-
-for file in "${files[@]}"; do
- [[ ! -f "$file" ]] && continue
- while IFS= read -r line; do
- [[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue
-
- if [[ "$line" =~ ^[[:space:]]*bind[a-z]*[[:space:]]*= ]]; then
- combo_raw="$(extract_combo "$line")"
- [[ -z "$combo_raw" ]] && continue
- combo="$(normalize_combo "$combo_raw")"
- seen_any_bind["$combo"]=1
-
- if [[ "$file" != "$user_keybinds_conf" ]]; then
- default_seen["$combo"]=1
- fi
-
- # prefer user bind, else first seen
- if [[ -z "${source_map[$combo]}" ]]; then
- binding_map["$combo"]="$line"
- source_map["$combo"]="$file"
- fi
- if [[ "$file" == "$user_keybinds_conf" ]]; then
- user_bind_map["$combo"]="$line"
- binding_map["$combo"]="$line"
- source_map["$combo"]="$file"
- fi
-
- elif [[ "$line" =~ ^[[:space:]]*unbind[[:space:]]*= ]]; then
- combo_raw="$(extract_combo "$line")"
- [[ -z "$combo_raw" ]] && continue
- combo="$(normalize_combo "$combo_raw")"
- if [[ "$file" == "$user_keybinds_conf" ]]; then
- unbound_user["$combo"]=1
- fi
- fi
- done < "$file"
-done
-
-# Build raw_keybinds for display and collect missing unbind suggestions
-raw_keybinds=""
-for combo in "${!seen_any_bind[@]}"; do
- eff_line="${binding_map[$combo]}"
- src="${source_map[$combo]}"
- [[ -z "$eff_line" ]] && continue
- raw_keybinds+="$eff_line"$'\n'
-
- # If user overrides a default but didn't unbind in user file, suggest unbind
- if [[ "$src" == "$user_keybinds_conf" && -n "${default_seen[$combo]}" && -z "${unbound_user[$combo]}" ]]; then
- suggest="$(echo "$eff_line" | sed -E 's/^[[:space:]]*bind[a-z]*/unbind/')"
- missing_unbind_suggestions_arr+=("$suggest")
+# Check for suggestions file created by python script
+if [[ -f "/tmp/hypr_keybind_suggestions_file" ]]; then
+ suggestions_file=$(cat "/tmp/hypr_keybind_suggestions_file")
+ rm "/tmp/hypr_keybind_suggestions_file"
+ if [[ -n "$suggestions_file" && -f "$suggestions_file" ]]; then
+ count=$(wc -l < "$suggestions_file")
+ msg="$msg | Overrides missing unbind: $count (suggestions: $suggestions_file)"
fi
-done
-
-# If there are missing unbinds, write suggestions to a temp file and note in message
-if (( ${#missing_unbind_suggestions_arr[@]} > 0 )); then
- suggestions_file="$(mktemp -t hypr-unbind-suggestions.XXXX.conf)"
- printf '%s\n' "${missing_unbind_suggestions_arr[@]}" > "$suggestions_file"
- msg="$msg | Overrides missing unbind: ${#missing_unbind_suggestions_arr[@]} (suggestions: $suggestions_file)"
fi
-# check for any keybinds to display
-if [[ -z "$raw_keybinds" ]]; then
- echo "no keybinds found."
- exit 1
-fi
-
-# transform into a readable list: MODS+KEY — DESCRIPTION (for bindd) or DISPATCHER [PARAMS] (for bind)
-display_keybinds=$(echo "$raw_keybinds" | awk -F'=' '
- function trim(s){ gsub(/^[ \t]+|[ \t]+$/,"",s); return s }
- /^[[:space:]]*bind/ {
- binder=$1; gsub(/[ \t]/, "", binder);
- hasdesc = (index(binder, "d")>0);
-
- rhs=$2; rhs=trim(rhs);
- n=split(rhs, a, /[ \t]*,[ \t]*/);
-
- mods=trim(a[1]); key=(n>=2?trim(a[2]):"");
- desc=""; dispatcher=""; params="";
-
- if (hasdesc) {
- desc=(n>=3?trim(a[3]):"");
- dispatcher=(n>=4?trim(a[4]):"");
- start=5;
- } else {
- dispatcher=(n>=3?trim(a[3]):"");
- start=4;
- }
-
- for(i=start;i<=n;i++){ if(length(a[i])){ p=trim(a[i]); if(p!="") params = (params?params", ":"") p } }
-
- gsub(/\$mainMod/,"SUPER",mods);
- gsub(/[ \t]+/,"+",mods);
-
- combo = (mods && key) ? mods "+" key : (key?key:mods);
-
- if (hasdesc && desc != "") {
- print combo, " — ", desc;
- } else {
- if (dispatcher != "" && params != "")
- print combo, " — ", dispatcher, " ", params;
- else if (dispatcher != "")
- print combo, " — ", dispatcher;
- else
- print combo;
- }
- }
-')
-
# use rofi to display the keybinds
printf '%s\n' "$display_keybinds" | rofi -dmenu -i -config "$rofi_theme" -mesg "$msg"
diff --git a/config/hypr/scripts/KeyHints.sh b/config/hypr/scripts/KeyHints.sh
index 8a478039..5511cfed 100755
--- a/config/hypr/scripts/KeyHints.sh
+++ b/config/hypr/scripts/KeyHints.sh
@@ -34,6 +34,7 @@ GDK_BACKEND=$BACKEND yad \
" D" "Application Launcher" "(rofi-wayland)" \
" E" "Open File Manager" "(Thunar)" \
" S" "Google Search using rofi" "(rofi)" \
+" T" "Global theme switcher" "(rofi)" \
" Q" "close active window" "(not kill)" \
" Shift Q " "kills an active window" "(kill)" \
" ALT mouse scroll up/down " "Desktop Zoom" "Desktop Magnifier" \
@@ -69,4 +70,4 @@ GDK_BACKEND=$BACKEND yad \
" ALT E" "Rofi Emoticons" "Emoticon" \
" H" "Launch this Quick Cheat Sheet" "" \
"" "" "" \
-"More tips:" "https://github.com/JaKooLit/Hyprland-Dots/wiki" ""\ \ No newline at end of file
+"More tips:" "https://github.com/JaKooLit/Hyprland-Dots/wiki" ""\
diff --git a/config/hypr/scripts/KeyboardLayout.sh b/config/hypr/scripts/KeyboardLayout.sh
new file mode 100755
index 00000000..ec280826
--- /dev/null
+++ b/config/hypr/scripts/KeyboardLayout.sh
@@ -0,0 +1,119 @@
+#!/usr/bin/env bash
+# /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ##
+# This is for changing kb_layouts. Set kb_layouts in "$HOME/.config/hypr/UserConfigs/UserSettings.conf"
+
+notif_icon="$HOME/.config/swaync/images/ja.png"
+SCRIPTSDIR="$HOME/.config/hypr/scripts"
+
+# Refined ignore list with patterns or specific device names
+ignore_patterns=(
+ "--(avrcp)"
+ "Bluetooth Speaker"
+ "Other Device
+ Name"
+)
+
+# Function to get keyboard names
+get_keyboard_names() {
+ hyprctl devices -j | jq -r '.keyboards[].name'
+}
+
+# Function to check if a device matches any ignore pattern
+is_ignored() {
+ local device_name=$1
+ for pattern in "${ignore_patterns[@]}"; do
+ if [[ "$device_name" == *"$pattern"* ]]; then
+ return 0 # Device matches ignore pattern
+ fi
+ done
+ return 1 # Device does not match any ignore pattern
+}
+
+# Function to get current layout info
+# Stores values in layout_mapping, variant_mapping and layout_index
+get_current_layout_info() {
+ local found_kb=false
+
+ # Read from the first non-ignored layout
+ while read -r name; do
+ if ! is_ignored "$name"; then
+ found_kb=true
+ local layout_mapping_str=$(hyprctl devices -j |
+ jq -r --arg name "$name" '.keyboards[] | select(.name==$name).layout')
+ IFS="," read -r -a layout_mapping <<<"$layout_mapping_str"
+
+ local variant_mapping_str=$(hyprctl devices -j |
+ jq -r --arg name "$name" '.keyboards[] | select(.name==$name).variant')
+ IFS="," read -r -a variant_mapping <<<"$variant_mapping_str"
+
+ layout_index=$(hyprctl devices -j |
+ jq -r --arg name "$name" '.keyboards[] | select(.name==$name).active_layout_index')
+ break
+ fi
+ done <<< "$(get_keyboard_names)"
+
+ $found_kb && return 0
+ return 1
+}
+
+# Function to change keyboard layout
+change_layout() {
+ local error_found=false
+
+ while read -r name; do
+ if is_ignored "$name"; then
+ echo "Skipping ignored device: $name"
+ continue
+ fi
+
+ echo "Switching layout for $name to $new_layout..."
+ hyprctl switchxkblayout "$name" "$next_index"
+ if [ $? -ne 0 ]; then
+ echo "Error while switching layout for $name." >&2
+ error_found=true
+ fi
+ done <<<"$(get_keyboard_names)"
+
+ $error_found && return 1
+ return 0
+}
+
+
+# Stores values in layout_mapping, variant_mapping and layout_index
+if ! get_current_layout_info; then
+ echo "Could not get current layout information." >&2
+ echo "There might not be any keyboards available, \
+ or some were unnecessarily set as ignored." >&2
+ notify-send -u low -t 2000 'kb_layout' " Error:" " Layout change failed"
+ echo "Exiting $0 $@" >&2
+ exit 1
+fi
+
+current_layout=${layout_mapping[$layout_index]}
+current_variant=${variant_mapping[$layout_index]}
+
+if [[ "$1" == "status" ]]; then
+ echo "$current_layout${current_variant:+($current_variant)}"
+elif [[ "$1" == "switch" ]]; then
+ echo "Current layout: $current_layout($current_variant)"
+
+ layout_count=${#layout_mapping[@]}
+ echo "Number of layouts: $layout_count"
+
+ next_index=$(( (layout_index + 1) % layout_count ))
+ new_layout="${layout_mapping[$next_index]}"
+ new_variant="${variant_mapping[$next_index]}"
+ echo "Next layout: $new_layout"
+
+ # Execute layout change and notify
+ if ! change_layout; then
+ notify-send -u low -t 2000 'kb_layout' " Error:" " Layout change failed"
+ echo "Layout change failed." >&2
+ exit 1
+ else
+ notify-send -u low -i "$notif_icon" " kb_layout: $new_layout${new_variant:+($new_variant)}"
+ echo "Layout change notification sent."
+ fi
+else
+ echo "Usage: $0 {status|switch}"
+fi
diff --git a/config/hypr/scripts/KillActiveProcess.sh b/config/hypr/scripts/KillActiveProcess.sh
index 2bc108f2..d9d26bb3 100755
--- a/config/hypr/scripts/KillActiveProcess.sh
+++ b/config/hypr/scripts/KillActiveProcess.sh
@@ -7,5 +7,10 @@
# Get id of an active window
active_pid=$(hyprctl activewindow | grep -o 'pid: [0-9]*' | cut -d' ' -f2)
+if [[ -z "$active_pid" || ! "$active_pid" =~ ^[0-9]+$ ]]; then
+ notify-send -u low -i "$HOME/.config/swaync/images/error.png" "Kill Active Window" "No active window PID found."
+ exit 1
+fi
+
# Close active window
-kill $active_pid \ No newline at end of file
+kill "$active_pid"
diff --git a/config/hypr/scripts/KooLsDotsUpdate.sh b/config/hypr/scripts/KooLsDotsUpdate.sh
index 51277ab1..a49f5430 100755
--- a/config/hypr/scripts/KooLsDotsUpdate.sh
+++ b/config/hypr/scripts/KooLsDotsUpdate.sh
@@ -5,12 +5,12 @@
# Local Paths
local_dir="$HOME/.config/hypr"
iDIR="$HOME/.config/swaync/images/"
-local_version=$(ls $local_dir/v* 2>/dev/null | sort -V | tail -n 1 | sed 's/.*v\(.*\)/\1/')
+local_version=$(find "$local_dir" -maxdepth 1 -name 'v*' -printf '%f\n' 2>/dev/null | sort -V | tail -n 1 | sed 's/^v//')
KooL_Dots_DIR="$HOME/Hyprland-Dots"
# exit if cannot find local version
if [ -z "$local_version" ]; then
- notify-send -i "$iDIR/error.png" "ERROR "!?!?!!"" "Unable to find KooL's dots version . exiting.... "
+ notify-send -i "$iDIR/error.png" 'ERROR !?!?!!' "Unable to find KooL's dots version. Exiting."
exit 1
fi
@@ -19,7 +19,7 @@ branch="main"
github_url="https://github.com/JaKooLit/Hyprland-Dots/tree/$branch/config/hypr/"
# Fetch the version from GitHub URL - KooL's dots
-github_version=$(curl -s $github_url | grep -o 'v[0-9]\+\.[0-9]\+\.[0-9]\+' | sort -V | tail -n 1 | sed 's/v//')
+github_version=$(curl -s "$github_url" | grep -o 'v[0-9]\+\.[0-9]\+\.[0-9]\+' | sort -V | tail -n 1 | sed 's/v//')
# Cant find GitHub URL - KooL's dots version
if [ -z "$github_version" ]; then
@@ -39,13 +39,13 @@ else
case "$response" in
"action1")
- if [ -d $KooL_Dots_DIR ]; then
+ if [ -d "$KooL_Dots_DIR" ]; then
if ! command -v kitty &> /dev/null; then
notify-send -i "$iDIR/error.png" "E-R-R-O-R" "Kitty terminal not found. Please install Kitty terminal."
exit 1
fi
kitty -e bash -c "
- cd $KooL_Dots_DIR &&
+ cd \"$KooL_Dots_DIR\" &&
git stash &&
git pull &&
./copy.sh &&
@@ -59,7 +59,7 @@ else
fi
kitty -e bash -c "
git clone --depth=1 https://github.com/JaKooLit/Hyprland-Dots.git $KooL_Dots_DIR &&
- cd $KooL_Dots_DIR &&
+ cd \"$KooL_Dots_DIR\" &&
chmod +x copy.sh &&
./copy.sh &&
notify-send -u critical -i "$iDIR/ja.png" 'Update Completed:' 'Kindly log out and relogin to take effect'
diff --git a/config/hypr/scripts/Kool_Quick_Settings.sh b/config/hypr/scripts/Kool_Quick_Settings.sh
index 8ab71ba2..0cd58f48 100755
--- a/config/hypr/scripts/Kool_Quick_Settings.sh
+++ b/config/hypr/scripts/Kool_Quick_Settings.sh
@@ -22,7 +22,154 @@ UserScripts="$HOME/.config/hypr/UserScripts"
# Function to show info notification
show_info() {
- notify-send -i "$iDIR/info.png" "Info" "$1"
+ if [[ -f "$iDIR/info.png" ]]; then
+ notify-send -i "$iDIR/info.png" "Info" "$1"
+ else
+ notify-send "Info" "$1"
+ fi
+}
+# Function to toggle Rainbow Borders script availability and refresh UI components
+toggle_rainbow_borders() {
+ local rainbow_script="$UserScripts/RainbowBorders.sh"
+ local disabled_sh_bak="${rainbow_script}.bak" # RainbowBorders.sh.bak
+ local disabled_bak_sh="$UserScripts/RainbowBorders.bak.sh" # RainbowBorders.bak.sh (created by copy.sh when disabled)
+ local refresh_script="$scriptsDir/Refresh.sh"
+ local status=""
+
+ # If both disabled variants exist, keep the newer one to avoid ambiguity
+ if [[ -f "$disabled_sh_bak" && -f "$disabled_bak_sh" ]]; then
+ if [[ "$disabled_sh_bak" -nt "$disabled_bak_sh" ]]; then
+ rm -f "$disabled_bak_sh"
+ else
+ rm -f "$disabled_sh_bak"
+ fi
+ fi
+
+ if [[ -f "$rainbow_script" ]]; then
+ # Currently enabled -> disable to canonical .sh.bak
+ if mv "$rainbow_script" "$disabled_sh_bak"; then
+ status="disabled"
+ if command -v hyprctl &>/dev/null; then
+ hyprctl reload >/dev/null 2>&1 || true
+ fi
+ fi
+ elif [[ -f "$disabled_sh_bak" ]]; then
+ # Disabled (.sh.bak) -> enable
+ if mv "$disabled_sh_bak" "$rainbow_script"; then
+ status="enabled"
+ fi
+ elif [[ -f "$disabled_bak_sh" ]]; then
+ # Disabled (.bak.sh) -> enable (normalize to .sh)
+ if mv "$disabled_bak_sh" "$rainbow_script"; then
+ status="enabled"
+ fi
+ else
+ show_info "RainbowBorders script not found in $UserScripts (checked .sh, .sh.bak, .bak.sh)."
+ return
+ fi
+
+ # Run refresh if available, otherwise apply borders directly
+ if [[ -x "$refresh_script" ]]; then
+ "$refresh_script" >/dev/null 2>&1 &
+ elif [[ "$current" != "disabled" && -x "$rainbow_script" ]]; then
+ "$rainbow_script" >/dev/null 2>&1 &
+ fi
+
+ if [[ -n "$status" ]]; then
+ show_info "Rainbow Borders ${status}."
+ fi
+}
+
+# Submenu to choose Rainbow Borders mode (disable, wallust_random, rainbow, gradient_flow)
+rainbow_borders_menu() {
+ local rainbow_script="$UserScripts/RainbowBorders.sh"
+ local disabled_sh_bak="${rainbow_script}.bak"
+ local disabled_bak_sh="$UserScripts/RainbowBorders.bak.sh"
+ local refresh_script="$scriptsDir/Refresh.sh"
+
+ # Determine current mode/status (internal)
+ local current="disabled"
+ if [[ -f "$rainbow_script" ]]; then
+ current=$(grep -E '^EFFECT_TYPE=' "$rainbow_script" 2>/dev/null | sed -E 's/^EFFECT_TYPE="?([^"]*)"?/\1/')
+ [[ -z "$current" ]] && current="unknown"
+ fi
+
+ # Map internal mode to friendly display
+ local current_display="$current"
+ case "$current" in
+ wallust_random) current_display="Wallust Color" ;;
+ rainbow) current_display="Original Rainbow" ;;
+ gradient_flow) current_display="Gradient Flow" ;;
+ disabled) current_display="Disabled" ;;
+ esac
+
+
+ # Build options and prompt
+ local options="Disable Rainbow Borders\nWallust Color\nOriginal Rainbow\nGradient Flow"
+ local choice
+ choice=$(printf "%b" "$options" | rofi -i -dmenu -config "$rofi_theme" -mesg "Rainbow Borders: current = $current_display")
+
+ [[ -z "$choice" ]] && return
+
+ local previous="$current"
+
+ case "$choice" in
+ "Disable Rainbow Borders")
+ if [[ -f "$rainbow_script" ]]; then
+ mv "$rainbow_script" "$disabled_sh_bak"
+ fi
+ current="disabled"
+ if command -v hyprctl &>/dev/null; then
+ hyprctl reload >/dev/null 2>&1 || true
+ fi
+ ;;
+ "Wallust Color"|"Original Rainbow"|"Gradient Flow")
+ local mode=""
+ case "$choice" in
+ "Wallust Color") mode="wallust_random" ;;
+ "Original Rainbow") mode="rainbow" ;;
+ "Gradient Flow") mode="gradient_flow" ;;
+ esac
+ # Ensure script is enabled
+ if [[ ! -f "$rainbow_script" ]]; then
+ if [[ -f "$disabled_sh_bak" ]]; then
+ mv "$disabled_sh_bak" "$rainbow_script"
+ elif [[ -f "$disabled_bak_sh" ]]; then
+ mv "$disabled_bak_sh" "$rainbow_script"
+ else
+ show_info "RainbowBorders script not found in $UserScripts."
+ return
+ fi
+ fi
+
+ # Update EFFECT_TYPE in place; insert if missing
+ if grep -q '^EFFECT_TYPE=' "$rainbow_script" 2>/dev/null; then
+ sed -i 's/^EFFECT_TYPE=.*/EFFECT_TYPE="'"$mode"'"/' "$rainbow_script"
+ else
+ if head -n1 "$rainbow_script" | grep -q '^#!'; then
+ sed -i '1a EFFECT_TYPE="'"$mode"'"' "$rainbow_script"
+ else
+ sed -i '1i EFFECT_TYPE="'"$mode"'"' "$rainbow_script"
+ fi
+ fi
+ # Set current to chosen mode
+ current="$mode"
+ ;;
+ *)
+ return ;;
+ esac
+
+ # Run refresh if available
+ if [[ -x "$refresh_script" ]]; then
+ "$refresh_script" >/dev/null 2>&1 &
+ fi
+
+ # Apply mode immediately (in case refresh doesn't trigger it)
+ if [[ "$current" != "disabled" && -x "$rainbow_script" ]]; then
+ "$rainbow_script" >/dev/null 2>&1 &
+ fi
+
+ # No notifications; mode is shown in the menu
}
# Function to display the menu options without numbers
@@ -44,6 +191,7 @@ Edit System Default Startup Apps
Edit System Default Window Rules
Edit System Default Settings
--- UTILITIES ---
+Set SDDM Wallpaper
Choose Kitty Terminal Theme
Configure Monitors (nwg-displays)
Configure Workspace Rules (nwg-displays)
@@ -56,6 +204,7 @@ Choose Rofi Themes
Search for Keybinds
Toggle Game Mode
Switch Dark-Light Theme
+Rainbow Borders Mode
EOF
}
@@ -78,6 +227,7 @@ main() {
"Edit System Default Startup Apps") file="$configs/Startup_Apps.conf" ;;
"Edit System Default Window Rules") file="$configs/WindowRules.conf" ;;
"Edit System Default Settings") file="$configs/SystemSettings.conf" ;;
+ "Set SDDM Wallpaper") $scriptsDir/sddm_wallpaper.sh --normal ;;
"Choose Kitty Terminal Theme") $scriptsDir/Kitty_themes.sh ;;
"Configure Monitors (nwg-displays)")
if ! command -v nwg-displays &>/dev/null; then
@@ -115,6 +265,7 @@ main() {
"Search for Keybinds") $scriptsDir/KeyBinds.sh ;;
"Toggle Game Mode") $scriptsDir/GameMode.sh ;;
"Switch Dark-Light Theme") $scriptsDir/DarkLight.sh ;;
+ "Rainbow Borders Mode") rainbow_borders_menu ;;
*) return ;; # Do nothing for invalid choices
esac
diff --git a/config/hypr/scripts/PortalHyprland.sh b/config/hypr/scripts/PortalHyprland.sh
index 21cb7db4..653e9b58 100755
--- a/config/hypr/scripts/PortalHyprland.sh
+++ b/config/hypr/scripts/PortalHyprland.sh
@@ -2,15 +2,39 @@
# /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ##
# For manually starting xdg-desktop-portal-hyprland
+set -euo pipefail
+
+kill_quietly() {
+ killall -q "$1" 2>/dev/null || true
+}
+
+start_portal_binary() {
+ local description="$1"
+ shift
+ for candidate in "$@"; do
+ if [[ -x "$candidate" ]]; then
+ "$candidate" &
+ return 0
+ fi
+ done
+ echo "Warning: no $description binary found (checked: $*)" >&2
+ return 1
+}
+
sleep 1
-killall xdg-desktop-portal-hyprland
-killall xdg-desktop-portal-wlr
-killall xdg-desktop-portal-gnome
-killall xdg-desktop-portal
+kill_quietly xdg-desktop-portal-hyprland
+kill_quietly xdg-desktop-portal-wlr
+kill_quietly xdg-desktop-portal-gnome
+kill_quietly xdg-desktop-portal
sleep 1
-/usr/lib/xdg-desktop-portal-hyprland &
-/usr/libexec/xdg-desktop-portal-hyprland &
+
+start_portal_binary "xdg-desktop-portal-hyprland" \
+ /usr/lib/xdg-desktop-portal-hyprland \
+ /usr/libexec/xdg-desktop-portal-hyprland
+
sleep 2
-/usr/lib/xdg-desktop-portal &
-/usr/libexec/xdg-desktop-portal &
+
+start_portal_binary "xdg-desktop-portal" \
+ /usr/lib/xdg-desktop-portal \
+ /usr/libexec/xdg-desktop-portal
diff --git a/config/hypr/scripts/RofiSearch.sh b/config/hypr/scripts/RofiSearch.sh
index 8ef12c46..dfeb19ac 100755
--- a/config/hypr/scripts/RofiSearch.sh
+++ b/config/hypr/scripts/RofiSearch.sh
@@ -4,6 +4,10 @@
# Define the path to the config file
config_file=$HOME/.config/hypr/UserConfigs/01-UserDefaults.conf
+if ! command -v jq >/dev/null 2>&1; then
+ notify-send -u low "Rofi Search" "jq is required for URL encoding. Please install jq."
+ exit 1
+fi
# Check if the config file exists
if [[ ! -f "$config_file" ]]; then
@@ -32,5 +36,12 @@ if pgrep -x "rofi" >/dev/null; then
pkill rofi
fi
-# Open Rofi and pass the selected query to xdg-open for Google search
-echo "" | rofi -dmenu -config "$rofi_theme" -mesg "$msg" | xargs -I{} xdg-open $Search_Engine \ No newline at end of file
+# Open Rofi and pass the selected query to xdg-open for the configured search engine
+query=$(printf '' | rofi -dmenu -config "$rofi_theme" -mesg "$msg")
+
+if [[ -z "$query" ]]; then
+ exit 0
+fi
+
+encoded_query=$(printf '%s' "$query" | jq -sRr @uri)
+xdg-open "${Search_Engine}${encoded_query}" >/dev/null 2>&1 &
diff --git a/config/hypr/scripts/ScreenShot.sh b/config/hypr/scripts/ScreenShot.sh
index 0ef70964..3d578a51 100755
--- a/config/hypr/scripts/ScreenShot.sh
+++ b/config/hypr/scripts/ScreenShot.sh
@@ -4,7 +4,8 @@
# variables
time=$(date "+%d-%b_%H-%M-%S")
-dir="$(xdg-user-dir PICTURES)/Screenshots"
+PICTURES_DIR="$(xdg-user-dir PICTURES 2>/dev/null || echo "$HOME/Pictures")"
+dir="$PICTURES_DIR/Screenshots"
file="Screenshot_${time}_${RANDOM}.png"
iDIR="$HOME/.config/swaync/icons"
diff --git a/config/hypr/scripts/Sounds.sh b/config/hypr/scripts/Sounds.sh
index b372d714..e92248da 100755
--- a/config/hypr/scripts/Sounds.sh
+++ b/config/hypr/scripts/Sounds.sh
@@ -73,5 +73,18 @@ if ! test -f "$sound_file"; then
fi
fi
-# pipewire priority, fallback pulseaudio
-pw-play "$sound_file" || pa-play "$sound_file" \ No newline at end of file
+# Play the sound: prefer PipeWire, then PulseAudio, then ALSA
+if command -v pw-play >/dev/null 2>&1; then
+ pw-play "$sound_file" && exit 0
+fi
+
+if command -v paplay >/dev/null 2>&1; then
+ paplay "$sound_file" && exit 0
+fi
+
+if command -v aplay >/dev/null 2>&1; then
+ aplay "$sound_file" && exit 0
+fi
+
+echo "Error: No suitable audio player (pw-play/paplay/aplay) found."
+exit 1
diff --git a/config/hypr/scripts/SwitchKeyboardLayout.sh b/config/hypr/scripts/SwitchKeyboardLayout.sh
deleted file mode 100755
index 34d008a1..00000000
--- a/config/hypr/scripts/SwitchKeyboardLayout.sh
+++ /dev/null
@@ -1,103 +0,0 @@
-#!/usr/bin/env bash
-# /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ##
-# This is for changing kb_layouts. Set kb_layouts in $settings_file
-
-layout_file="$HOME/.cache/kb_layout"
-settings_file="$HOME/.config/hypr/configs/SystemSettings.conf"
-notif_icon="$HOME/.config/swaync/images/ja.png"
-
-# Refined ignore list with patterns or specific device names
-ignore_patterns=(
- "--(avrcp)"
- "Bluetooth Speaker"
- "Other Device
- Name"
-)
-
-# Create layout file with default layout if it does not exist
-if [ ! -f "$layout_file" ]; then
- echo "Creating layout file..."
- default_layout=$(grep 'kb_layout = ' "$settings_file" | cut -d '=' -f 2 | tr -d '[:space:]' | cut -d ',' -f 1 2>/dev/null)
- default_layout=${default_layout:-"us"} # Default to 'us' layout
- echo "$default_layout" >"$layout_file"
- echo "Default layout set to $default_layout"
-fi
-
-current_layout=$(cat "$layout_file")
-echo "Current layout: $current_layout"
-
-# Read available layouts from settings file
-if [ -f "$settings_file" ]; then
- kb_layout_line=$(grep 'kb_layout = ' "$settings_file" | cut -d '=' -f 2)
- # Remove leading and trailing spaces around each layout
- kb_layout_line=$(echo "$kb_layout_line" | tr -d '[:space:]')
- IFS=',' read -r -a layout_mapping <<<"$kb_layout_line"
-else
- echo "Settings file not found!"
- exit 1
-fi
-
-layout_count=${#layout_mapping[@]}
-echo "Number of layouts: $layout_count"
-
-# Find current layout index and calculate next layout
-for ((i = 0; i < layout_count; i++)); do
- if [ "$current_layout" == "${layout_mapping[i]}" ]; then
- current_index=$i
- break
- fi
-done
-
-next_index=$(((current_index + 1) % layout_count))
-new_layout="${layout_mapping[next_index]}"
-echo "Next layout: $new_layout"
-
-# Function to get keyboard names
-get_keyboard_names() {
- hyprctl devices -j | jq -r '.keyboards[].name'
-}
-
-# Function to check if a device matches any ignore pattern
-is_ignored() {
- local device_name=$1
- for pattern in "${ignore_patterns[@]}"; do
- if [[ "$device_name" == *"$pattern"* ]]; then
- return 0 # Device matches ignore pattern
- fi
- done
- return 1 # Device does not match any ignore pattern
-}
-
-# Function to change keyboard layout
-change_layout() {
- local error_found=false
-
- while read -r name; do
- if is_ignored "$name"; then
- echo "Skipping ignored device: $name"
- continue
- fi
-
- echo "Switching layout for $name to $new_layout..."
- hyprctl switchxkblayout "$name" "$next_index"
- if [ $? -ne 0 ]; then
- echo "Error while switching layout for $name." >&2
- error_found=true
- fi
- done <<<"$(get_keyboard_names)"
-
- $error_found && return 1
- return 0
-}
-
-# Execute layout change and notify
-if ! change_layout; then
- notify-send -u low -t 2000 'kb_layout' " Error:" " Layout change failed"
- echo "Layout change failed." >&2
- exit 1
-else
- notify-send -u low -i "$notif_icon" " kb_layout: $new_layout"
- echo "Layout change notification sent."
-fi
-
-echo "$new_layout" >"$layout_file"
diff --git a/config/hypr/scripts/Tak0-Per-Window-Switch.sh b/config/hypr/scripts/Tak0-Per-Window-Switch.sh
index 7879fb85..7cec89a6 100755
--- a/config/hypr/scripts/Tak0-Per-Window-Switch.sh
+++ b/config/hypr/scripts/Tak0-Per-Window-Switch.sh
@@ -17,6 +17,7 @@ MAP_FILE="$HOME/.cache/kb_layout_per_window"
CFG_FILE="$HOME/.config/hypr/configs/SystemSettings.conf"
ICON="$HOME/.config/swaync/images/ja.png"
SCRIPT_NAME="$(basename "$0")"
+LISTENER_PIDFILE="$HOME/.cache/kb_layout_per_window.listener.pid"
# Ensure map file exists
touch "$MAP_FILE"
@@ -99,7 +100,7 @@ subscribe() {
local SOCKET2="$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock"
[[ -S "$SOCKET2" ]] || {
echo "Error: Hyprland socket not found." >&2
- exit 1
+ return 1
}
socat -u UNIX-CONNECT:"$SOCKET2" - | while read -r line; do
@@ -108,9 +109,20 @@ subscribe() {
}
# Ensure only one listener
-if ! pgrep -f "$SCRIPT_NAME.*--listener" >/dev/null; then
- subscribe --listener &
-fi
+start_listener_once() {
+ if [[ -f "$LISTENER_PIDFILE" ]]; then
+ local existing_pid
+ existing_pid=$(cat "$LISTENER_PIDFILE" 2>/dev/null || true)
+ if [[ -n "$existing_pid" ]] && kill -0 "$existing_pid" 2>/dev/null; then
+ return
+ fi
+ fi
+
+ subscribe &
+ echo $! >"$LISTENER_PIDFILE"
+}
+
+start_listener_once
# CLI
case "$1" in
diff --git a/config/hypr/scripts/ThemeChanger.sh b/config/hypr/scripts/ThemeChanger.sh
new file mode 100755
index 00000000..19ee3298
--- /dev/null
+++ b/config/hypr/scripts/ThemeChanger.sh
@@ -0,0 +1,145 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+# SPDX-FileCopyrightText: 2025-present Ahum Maitra theahummaitra@gmail.com
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# Repository url : https://github.com/TheAhumMaitra/cautious-waddle
+
+require() {
+ command -v "$1" >/dev/null 2>&1 || {
+ printf '%s\n' "Missing dependency: $1" >&2
+ exit 127
+ }
+}
+
+require wallust
+require rofi
+
+# notify-send is optional
+have_notify() { command -v notify-send >/dev/null 2>&1; }
+
+# Prompt for theme; guard -e on cancel
+set +e
+choice="$(wallust theme list \
+ | sed -e '1d' -e 's/^- //' \
+ | rofi -dmenu -i -p 'Select Global Theme')"
+prompt_status=$?
+set -e
+
+# Exit cleanly on cancel or empty selection
+if (( prompt_status != 0 )) || [[ -z "${choice}" ]]; then
+ exit 0
+fi
+
+# Record time before applying so we can wait for fresh template outputs
+start_ts=$(date +%s)
+
+# Apply the theme and report result
+if wallust theme -- "${choice}"; then
+ have_notify && notify-send -a ThemeChanger \
+ -h string:x-dunst-stack-tag:themechanger \
+ "Global theme changed" "Selected: ${choice}"
+
+ # Wait until template targets exist, are newer than start_ts, and are stable (size/mtime stops changing)
+ # Ensure Ghostty directory exists so Wallust can write target even if Ghostty isn't installed
+ mkdir -p "$HOME/.config/ghostty" || true
+
+ targets=(
+ "$HOME/.config/waybar/wallust/colors-waybar.css"
+ "$HOME/.config/rofi/wallust/colors-rofi.rasi"
+ "$HOME/.config/kitty/kitty-themes/01-Wallust.conf"
+ "$HOME/.config/hypr/wallust/wallust-hyprland.conf"
+ "$HOME/.config/ghostty/wallust.conf"
+ )
+
+ # Normalize Ghostty palette syntax in case upstream templates or older targets used ':'
+ ghostty_conf="$HOME/.config/ghostty/wallust.conf"
+ if [ -f "$ghostty_conf" ]; then
+ sed -i -E 's/^(\s*palette\s*=\s*)([0-9]{1,2}):/\1\2=/' "$ghostty_conf" 2>/dev/null || true
+ fi
+
+ # Phase 1: appearance + freshness
+ for _ in $(seq 1 100); do # up to ~10s
+ ok=1
+ for f in "${targets[@]}"; do
+ [ -s "$f" ] || { ok=0; break; }
+ mtime=$(stat -c %Y "$f" 2>/dev/null || echo 0)
+ [ "$mtime" -ge "$start_ts" ] || { ok=0; break; }
+ done
+ [ $ok -eq 1 ] && break
+ sleep 0.1
+ done
+
+ # Phase 2: stability (avoid reading half-written files)
+ if [ $ok -eq 1 ]; then
+ for _ in 1 2 3; do
+ sizes_a=(); mtimes_a=()
+ for f in "${targets[@]}"; do
+ sizes_a+=("$(stat -c %s "$f" 2>/dev/null || echo 0)")
+ mtimes_a+=("$(stat -c %Y "$f" 2>/dev/null || echo 0)")
+ done
+ sleep 0.15
+ sizes_b=(); mtimes_b=()
+ for f in "${targets[@]}"; do
+ sizes_b+=("$(stat -c %s "$f" 2>/dev/null || echo 0)")
+ mtimes_b+=("$(stat -c %Y "$f" 2>/dev/null || echo 0)")
+ done
+ if [ "${sizes_a[*]}" = "${sizes_b[*]}" ] && [ "${mtimes_a[*]}" = "${mtimes_b[*]}" ]; then
+ break
+ fi
+ done
+ else
+ # As a safety net, wait a bit to avoid racing rofi reload against template writes
+ sleep 0.5
+ fi
+
+ # Small cushion before refresh to mirror wallpaper flow
+ sleep 0.2
+ # Normalize Rofi selection colors to use the palette's accent (color12)
+ rofi_colors="$HOME/.config/rofi/wallust/colors-rofi.rasi"
+ if [ -f "$rofi_colors" ]; then
+ accent_hex=$(sed -n 's/^\s*color12:\s*\(#[0-9A-Fa-f]\{6\}\).*/\1/p' "$rofi_colors" | head -n1)
+ [ -z "$accent_hex" ] && accent_hex=$(sed -n 's/^\s*color13:\s*\(#[0-9A-Fa-f]\{6\}\).*/\1/p' "$rofi_colors" | head -n1)
+ if [ -n "$accent_hex" ]; then
+ sed -i -E "s|^(\s*selected-normal-background:\s*).*$|\1$accent_hex;|" "$rofi_colors"
+ sed -i -E "s|^(\s*selected-active-background:\s*).*$|\1$accent_hex;|" "$rofi_colors"
+ sed -i -E "s|^(\s*selected-urgent-background:\s*).*$|\1$accent_hex;|" "$rofi_colors"
+ sed -i -E "s|^(\s*selected-normal-foreground:\s*).*$|\1#000000;|" "$rofi_colors"
+ sed -i -E "s|^(\s*selected-active-foreground:\s*).*$|\1#000000;|" "$rofi_colors"
+ sed -i -E "s|^(\s*selected-urgent-foreground:\s*).*$|\1#000000;|" "$rofi_colors"
+ fi
+ fi
+
+ # Reload Hyprland so new border colors from wallust-hyprland.conf take effect
+ if command -v hyprctl >/dev/null 2>&1; then
+ hyprctl reload >/dev/null 2>&1 || true
+ fi
+
+ # Refresh bars/menus after files are ready
+ if [ -x "$HOME/.config/hypr/scripts/Refresh.sh" ]; then
+ "$HOME/.config/hypr/scripts/Refresh.sh" >/dev/null 2>&1 || true
+ else
+ if command -v waybar-msg >/dev/null 2>&1; then
+ waybar-msg cmd reload >/dev/null 2>&1 || true
+ else
+ pkill -SIGUSR2 waybar >/dev/null 2>&1 || true
+ fi
+ fi
+
+ # Ask kitty to reload its config so the new 01-Wallust.conf is picked up
+ if pidof kitty >/dev/null; then
+ for pid in $(pidof kitty); do kill -SIGUSR1 "$pid" 2>/dev/null || true; done
+ fi
+
+ # Ask ghostty to reload its config so the updated wallust.conf is applied
+ if pidof ghostty >/dev/null; then
+ for pid in $(pidof ghostty); do kill -SIGUSR2 "$pid" 2>/dev/null || true; done
+ fi
+else
+ have_notify && notify-send -u critical -a ThemeChanger \
+ -h string:x-dunst-stack-tag:themechanger \
+ "Failed to apply theme" "${choice}"
+ exit 1
+fi
diff --git a/config/hypr/scripts/TouchPad.sh b/config/hypr/scripts/TouchPad.sh
index 030c36de..f14165a0 100755
--- a/config/hypr/scripts/TouchPad.sh
+++ b/config/hypr/scripts/TouchPad.sh
@@ -5,28 +5,50 @@
# use hyprctl devices to get your system touchpad device name
# source https://github.com/hyprwm/Hyprland/discussions/4283?sort=new#discussioncomment-8648109
+set -euo pipefail
+
notif="$HOME/.config/swaync/images/ja.png"
+laptops_conf="$HOME/.config/hypr/UserConfigs/Laptops.conf"
+
+touchpad_device="${TOUCHPAD_DEVICE:-}"
+if [[ -z "$touchpad_device" && -f "$laptops_conf" ]]; then
+ touchpad_device="$(
+ awk -F= '/^\$Touchpad_Device/ {
+ gsub(/[[:space:]]*/, "", $1);
+ gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2);
+ print $2;
+ exit
+ }' "$laptops_conf"
+ )"
+fi
+
+if [[ -z "$touchpad_device" ]]; then
+ notify-send -u low -i "$notif" " Touchpad" " Device name not set (check Laptops.conf)"
+ exit 1
+fi
-export STATUS_FILE="$XDG_RUNTIME_DIR/touchpad.status"
+touchpad_keyword="${TOUCHPAD_KEYWORD:-device:${touchpad_device}:enabled}"
+status_file="${XDG_RUNTIME_DIR:-/tmp}/touchpad.status"
enable_touchpad() {
- printf "true" >"$STATUS_FILE"
- notify-send -u low -i $notif " Enabling" " touchpad"
- hyprctl keyword '$TOUCHPAD_ENABLED' "true" -r
+ printf "true" >"$status_file"
+ notify-send -u low -i "$notif" " Enabling" " touchpad"
+ hyprctl keyword "$touchpad_keyword" true -r
}
disable_touchpad() {
- printf "false" >"$STATUS_FILE"
- notify-send -u low -i $notif " Disabling" " touchpad"
- hyprctl keyword '$TOUCHPAD_ENABLED' "false" -r
+ printf "false" >"$status_file"
+ notify-send -u low -i "$notif" " Disabling" " touchpad"
+ hyprctl keyword "$touchpad_keyword" false -r
}
-if ! [ -f "$STATUS_FILE" ]; then
- enable_touchpad
-else
- if [ $(cat "$STATUS_FILE") = "true" ]; then
+current_state="false"
+if [[ -f "$status_file" ]]; then
+ current_state="$(<"$status_file")"
+fi
+
+if [[ "$current_state" == "true" ]]; then
disable_touchpad
- elif [ $(cat "$STATUS_FILE") = "false" ]; then
+else
enable_touchpad
- fi
fi
diff --git a/config/hypr/scripts/Volume.sh b/config/hypr/scripts/Volume.sh
index 4c82f543..e1034a68 100755
--- a/config/hypr/scripts/Volume.sh
+++ b/config/hypr/scripts/Volume.sh
@@ -7,8 +7,14 @@ sDIR="$HOME/.config/hypr/scripts"
# Get Volume
get_volume() {
+ if [[ "$(pamixer --get-mute)" == "true" ]]; then
+ echo "Muted"
+ return
+ fi
+
+ local volume
volume=$(pamixer --get-volume)
- if [[ "$volume" -eq "0" ]]; then
+ if [[ "$volume" -eq 0 ]]; then
echo "Muted"
else
echo "$volume %"
@@ -17,12 +23,15 @@ get_volume() {
# Get icons
get_icon() {
- current=$(get_volume)
- if [[ "$current" == "Muted" ]]; then
+ if [[ "$(pamixer --get-mute)" == "true" ]]; then
echo "$iDIR/volume-mute.png"
- elif [[ "${current%\%}" -le 30 ]]; then
+ return
+ fi
+
+ current=$(pamixer --get-volume)
+ if [[ "$current" -le 30 ]]; then
echo "$iDIR/volume-low.png"
- elif [[ "${current%\%}" -le 60 ]]; then
+ elif [[ "$current" -le 60 ]]; then
echo "$iDIR/volume-mid.png"
else
echo "$iDIR/volume-high.png"
@@ -31,11 +40,18 @@ get_icon() {
# Notify
notify_user() {
- if [[ "$(get_volume)" == "Muted" ]]; then
- notify-send -e -h string:x-canonical-private-synchronous:volume_notif -h boolean:SWAYNC_BYPASS_DND:true -u low -i "$(get_icon)" " Volume:" " Muted"
+ local muted="$(pamixer --get-mute)"
+ local level="$(pamixer --get-volume)"
+
+ if [[ "$muted" == "true" || "$level" -eq 0 ]]; then
+ notify-send -e -h string:x-canonical-private-synchronous:volume_notif \
+ -h boolean:SWAYNC_BYPASS_DND:true -u low -i "$(get_icon)" \
+ " Volume:" " Muted"
else
- notify-send -e -h int:value:"$(get_volume | sed 's/%//')" -h string:x-canonical-private-synchronous:volume_notif -h boolean:SWAYNC_BYPASS_DND:true -u low -i "$(get_icon)" " Volume Level:" " $(get_volume)" &&
- "$sDIR/Sounds.sh" --volume
+ notify-send -e -h int:value:"$level" -h string:x-canonical-private-synchronous:volume_notif \
+ -h boolean:SWAYNC_BYPASS_DND:true -u low -i "$(get_icon)" \
+ " Volume Level:" " ${level}%" &&
+ "$sDIR/Sounds.sh" --volume
fi
}
@@ -44,7 +60,7 @@ inc_volume() {
if [ "$(pamixer --get-mute)" == "true" ]; then
toggle_mute
else
- pamixer -i 5 --allow-boost --set-limit 150 && notify_user
+ pamixer -i "$1" --allow-boost --set-limit 150 && notify_user
fi
}
@@ -53,7 +69,7 @@ dec_volume() {
if [ "$(pamixer --get-mute)" == "true" ]; then
toggle_mute
else
- pamixer -d 5 && notify_user
+ pamixer -d "$1" && notify_user
fi
}
@@ -71,13 +87,14 @@ toggle_mic() {
if [ "$(pamixer --default-source --get-mute)" == "false" ]; then
pamixer --default-source -m && notify-send -e -u low -h boolean:SWAYNC_BYPASS_DND:true -i "$iDIR/microphone-mute.png" " Microphone:" " Switched OFF"
elif [ "$(pamixer --default-source --get-mute)" == "true" ]; then
- pamixer -u --default-source u && notify-send -e -u low -h boolean:SWAYNC_BYPASS_DND:true -i "$iDIR/microphone.png" " Microphone:" " Switched ON"
+ pamixer --default-source -u && notify-send -e -u low -h boolean:SWAYNC_BYPASS_DND:true -i "$iDIR/microphone.png" " Microphone:" " Switched ON"
fi
}
# Get Mic Icon
get_mic_icon() {
- current=$(pamixer --default-source --get-volume)
- if [[ "$current" -eq "0" ]]; then
+ local muted="$(pamixer --default-source --get-mute)"
+ local current="$(pamixer --default-source --get-volume)"
+ if [[ "$muted" == "true" || "$current" -eq "0" ]]; then
echo "$iDIR/microphone-mute.png"
else
echo "$iDIR/microphone.png"
@@ -86,8 +103,14 @@ get_mic_icon() {
# Get Microphone Volume
get_mic_volume() {
+ if [[ "$(pamixer --default-source --get-mute)" == "true" ]]; then
+ echo "Muted"
+ return
+ fi
+
+ local volume
volume=$(pamixer --default-source --get-volume)
- if [[ "$volume" -eq "0" ]]; then
+ if [[ "$volume" -eq 0 ]]; then
echo "Muted"
else
echo "$volume %"
@@ -96,9 +119,21 @@ get_mic_volume() {
# Notify for Microphone
notify_mic_user() {
- volume=$(get_mic_volume)
- icon=$(get_mic_icon)
- notify-send -e -h int:value:"$volume" -h "string:x-canonical-private-synchronous:volume_notif" -h boolean:SWAYNC_BYPASS_DND:true -u low -i "$icon" " Mic Level:" " $volume"
+ local muted="$(pamixer --default-source --get-mute)"
+ local level="$(pamixer --default-source --get-volume)"
+ local icon message
+
+ if [[ "$muted" == "true" || "$level" -eq 0 ]]; then
+ icon="$iDIR/microphone-mute.png"
+ notify-send -e -h "string:x-canonical-private-synchronous:volume_notif" \
+ -h boolean:SWAYNC_BYPASS_DND:true -u low -i "$icon" \
+ " Mic Level:" " Muted"
+ else
+ icon="$iDIR/microphone.png"
+ notify-send -e -h int:value:"$level" -h "string:x-canonical-private-synchronous:volume_notif" \
+ -h boolean:SWAYNC_BYPASS_DND:true -u low -i "$icon" \
+ " Mic Level:" " ${level}%"
+ fi
}
# Increase MIC Volume
@@ -113,31 +148,48 @@ inc_mic_volume() {
# Decrease MIC Volume
dec_mic_volume() {
if [ "$(pamixer --default-source --get-mute)" == "true" ]; then
- toggle-mic
+ toggle_mic
else
pamixer --default-source -d 5 && notify_mic_user
fi
}
# Execute accordingly
-if [[ "$1" == "--get" ]]; then
- get_volume
-elif [[ "$1" == "--inc" ]]; then
- inc_volume
-elif [[ "$1" == "--dec" ]]; then
- dec_volume
-elif [[ "$1" == "--toggle" ]]; then
- toggle_mute
-elif [[ "$1" == "--toggle-mic" ]]; then
- toggle_mic
-elif [[ "$1" == "--get-icon" ]]; then
- get_icon
-elif [[ "$1" == "--get-mic-icon" ]]; then
- get_mic_icon
-elif [[ "$1" == "--mic-inc" ]]; then
- inc_mic_volume
-elif [[ "$1" == "--mic-dec" ]]; then
- dec_mic_volume
-else
- get_volume
-fi \ No newline at end of file
+case "$1" in
+"--get")
+ get_volume
+ ;;
+"--inc")
+ inc_volume 5
+ ;;
+"--inc-precise")
+ inc_volume 1
+ ;;
+"--dec")
+ dec_volume 5
+ ;;
+"--dec-precise")
+ dec_volume 1
+ ;;
+"--toggle")
+ toggle_mute
+ ;;
+"--toggle-mic")
+ toggle_mic
+ ;;
+"--get-icon")
+ get_icon
+ ;;
+"--get-mic-icon")
+ get_mic_icon
+ ;;
+"--mic-inc")
+ inc_mic_volume
+ ;;
+"--mic-dec")
+ dec_mic_volume
+ ;;
+*)
+ get_volume
+ ;;
+esac
diff --git a/config/hypr/scripts/WallustSwww.sh b/config/hypr/scripts/WallustSwww.sh
index 657f41ab..63911036 100755
--- a/config/hypr/scripts/WallustSwww.sh
+++ b/config/hypr/scripts/WallustSwww.sh
@@ -10,6 +10,27 @@ passed_path="${1:-}"
cache_dir="$HOME/.cache/swww/"
rofi_link="$HOME/.config/rofi/.current_wallpaper"
wallpaper_current="$HOME/.config/hypr/wallpaper_effects/.wallpaper_current"
+read_cached_wallpaper() {
+ local cache_file="$1"
+ if [[ -f "$cache_file" ]]; then
+ awk 'NF && $0 !~ /^filter/ {print; exit}' "$cache_file"
+ fi
+}
+
+read_wallpaper_from_query() {
+ local monitor="$1"
+ swww query | awk -v mon="$monitor" '
+ /^Monitor/ {
+ cur=$2
+ gsub(":", "", cur)
+ }
+ /image:/ && cur==mon {
+ sub(/^.*image: /,"")
+ print
+ exit
+ }
+ '
+}
# Helper: get focused monitor name (prefer JSON)
get_focused_monitor() {
@@ -39,8 +60,11 @@ else
if [[ -f "$cache_file" ]]; then
# The first non-filter line is the original wallpaper path
- # wallpaper_path="$(grep -v 'Lanczos3' "$cache_file" | head -n 1)"
- wallpaper_path=$(swww query | grep $current_monitor | awk '{print $9}')
+ wallpaper_path="$(read_cached_wallpaper "$cache_file")"
+ fi
+
+ if [[ -z "$wallpaper_path" ]]; then
+ wallpaper_path="$(read_wallpaper_from_query "$current_monitor")"
fi
fi
@@ -54,6 +78,59 @@ ln -sf "$wallpaper_path" "$rofi_link" || true
mkdir -p "$(dirname "$wallpaper_current")"
cp -f "$wallpaper_path" "$wallpaper_current" || true
+# Ensure Ghostty directory exists so Wallust can write target even if Ghostty isn't installed
+mkdir -p "$HOME/.config/ghostty" || true
+wait_for_templates() {
+ local start_ts="$1"
+ shift
+ local files=("$@")
+ for _ in {1..50}; do
+ local ready=true
+ for file in "${files[@]}"; do
+ if [[ ! -s "$file" ]]; then
+ ready=false
+ break
+ fi
+ local mtime
+ mtime=$(stat -c %Y "$file" 2>/dev/null || echo 0)
+ if (( mtime < start_ts )); then
+ ready=false
+ break
+ fi
+ done
+ $ready && return 0
+ sleep 0.1
+ done
+ return 1
+}
+
# Run wallust (silent) to regenerate templates defined in ~/.config/wallust/wallust.toml
# -s is used in this repo to keep things quiet and avoid extra prompts
+start_ts=$(date +%s)
wallust run -s "$wallpaper_path" || true
+wallust_targets=(
+ "$HOME/.config/waybar/wallust/colors-waybar.css"
+ "$HOME/.config/rofi/wallust/colors-rofi.rasi"
+)
+wait_for_templates "$start_ts" "${wallust_targets[@]}" || true
+
+# Normalize Ghostty palette syntax in case ':' was used by older files
+if [ -f "$HOME/.config/ghostty/wallust.conf" ]; then
+ sed -i -E 's/^(\s*palette\s*=\s*)([0-9]{1,2}):/\1\2=/' "$HOME/.config/ghostty/wallust.conf" 2>/dev/null || true
+fi
+
+# Light wait for Ghostty colors file to be present then signal Ghostty to reload (SIGUSR2)
+for _ in 1 2 3; do
+ [ -s "$HOME/.config/ghostty/wallust.conf" ] && break
+ sleep 0.1
+done
+if pidof ghostty >/dev/null; then
+ for pid in $(pidof ghostty); do kill -SIGUSR2 "$pid" 2>/dev/null || true; done
+fi
+
+# Prompt Waybar to reload colors
+if command -v waybar-msg >/dev/null 2>&1; then
+ waybar-msg cmd reload >/dev/null 2>&1 || true
+elif pidof waybar >/dev/null; then
+ killall -SIGUSR2 waybar 2>/dev/null || true
+fi
diff --git a/config/hypr/scripts/WaybarScripts.sh b/config/hypr/scripts/WaybarScripts.sh
index d2205c42..54f7a4b4 100755
--- a/config/hypr/scripts/WaybarScripts.sh
+++ b/config/hypr/scripts/WaybarScripts.sh
@@ -24,6 +24,14 @@ if [[ -z "$term" ]]; then
fi
# Execute accordingly based on the passed argument
+launch_files() {
+ if [[ -z "$files" ]]; then
+ notify-send -u low -i "$HOME/.config/swaync/images/error.png" "Waybar: files" "Set \$files in 01-UserDefaults.conf or install a default file manager."
+ return 1
+ fi
+ eval "$files &"
+}
+
if [[ "$1" == "--btop" ]]; then
$term --title btop sh -c 'btop'
elif [[ "$1" == "--nvtop" ]]; then
@@ -33,7 +41,7 @@ elif [[ "$1" == "--nmtui" ]]; then
elif [[ "$1" == "--term" ]]; then
$term &
elif [[ "$1" == "--files" ]]; then
- $files &
+ launch_files
else
echo "Usage: $0 [--btop | --nvtop | --nmtui | --term]"
echo "--btop : Open btop in a new term"
diff --git a/config/hypr/scripts/keybinds_parser.py b/config/hypr/scripts/keybinds_parser.py
new file mode 100755
index 00000000..d12e3854
--- /dev/null
+++ b/config/hypr/scripts/keybinds_parser.py
@@ -0,0 +1,245 @@
+#!/usr/bin/env python3
+import sys
+import re
+import os
+
+def normalize_combo(combo):
+ return combo.replace(" ", "").replace("\t", "")
+
+def extract_combo(line):
+ # Remove comments and whitespace
+ line = re.sub(r'\s*#.*$', '', line).strip()
+
+ if '=' not in line:
+ return None
+
+ try:
+ rhs = line.split('=', 1)[1]
+ parts = [p.strip() for p in rhs.split(',')]
+ if len(parts) < 2:
+ return None
+
+ mods = parts[0]
+ key = parts[1]
+ return f"{mods},{key}"
+ except Exception:
+ return None
+
+def parse_files(files):
+ # Data structures to match original logic
+ binding_map = {} # combo -> effective line
+ source_map = {} # combo -> source file
+ user_bind_map = {} # combo -> user bind line
+ unbound_user = {} # combo -> True if explicitly unbound in user file
+ seen_any_bind = {} # combo -> True if seen
+ default_seen = {} # combo -> True if default bind exists
+
+ # We assume the last file in the list is the user config (UserKeybinds.conf)
+ # This matches the bash script logic where user_keybinds_conf is passed last
+ if not files:
+ return [], []
+
+ user_conf_path = files[-1] if len(files) > 1 else None
+
+ for file_path in files:
+ if not os.path.exists(file_path):
+ continue
+
+ try:
+ with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
+ for line in f:
+ line = line.rstrip('\n')
+ if not line or line.strip().startswith('#'):
+ continue
+
+ is_bind = re.match(r'^\s*bind[a-z]*\s*=', line)
+ is_unbind = re.match(r'^\s*unbind\s*=', line)
+
+ if is_bind:
+ combo_raw = extract_combo(line)
+ if not combo_raw:
+ continue
+ combo = normalize_combo(combo_raw)
+ seen_any_bind[combo] = True
+
+ is_user_file = (file_path == user_conf_path)
+
+ if not is_user_file:
+ default_seen[combo] = True
+
+ # prefer user bind, else first seen
+ if combo not in source_map:
+ binding_map[combo] = line
+ source_map[combo] = file_path
+
+ if is_user_file:
+ user_bind_map[combo] = line
+ binding_map[combo] = line
+ source_map[combo] = file_path
+
+ elif is_unbind:
+ combo_raw = extract_combo(line)
+ if not combo_raw:
+ continue
+ combo = normalize_combo(combo_raw)
+
+ if file_path == user_conf_path:
+ unbound_user[combo] = True
+
+ # If unbind is found, we should remove the bind from our map
+ # so it doesn't show up in the menu.
+ if combo in binding_map:
+ del binding_map[combo]
+ if combo in source_map:
+ del source_map[combo]
+
+ except Exception as e:
+ # Silently ignore read errors to mimic bash behavior or log to stderr
+ sys.stderr.write(f"Error reading {file_path}: {e}\n")
+ continue
+
+ # Build results
+ raw_keybinds = []
+ missing_unbind_suggestions = []
+
+ for combo in seen_any_bind:
+ eff_line = binding_map.get(combo)
+ src = source_map.get(combo)
+
+ if not eff_line:
+ continue
+
+ raw_keybinds.append(eff_line)
+
+ # Check for missing unbind suggestions
+ # If user overrides a default but didn't unbind in user file
+ if (src == user_conf_path and
+ combo in default_seen and
+ combo not in unbound_user):
+
+ # Create suggestion: replace 'bind' with 'unbind'
+ suggest = re.sub(r'^\s*bind[a-z]*', 'unbind', eff_line)
+ missing_unbind_suggestions.append(suggest)
+
+ return raw_keybinds, missing_unbind_suggestions
+
+def format_for_rofi(raw_binds):
+ formatted_lines = []
+
+ for line in raw_binds:
+ # line is like "bind = MODS, KEY, DISPATCHER, PARAMS" or "bindd = ..."
+ # Parsing logic from awk script:
+
+ # 1. Cleaner binder
+ match = re.match(r'^\s*(bind[a-z]*)\s*=(.*)', line)
+ if not match:
+ continue
+
+ binder = match.group(1).replace(" ", "").replace("\t", "")
+ rhs = match.group(2).strip()
+
+ # "bind" ends in d, but doesn't have a description. "bindd" does.
+ # Original script logic `index(binder, "d")>0` was likely buggy for "bind".
+ # We'll assume strict check for bindd or similar if needed,
+ # but avoiding "bind" having a description is crucial for correct output.
+ has_desc = 'd' in binder and binder != 'bind'
+
+ # Split by comma regex (handling spaces)
+ parts = [p.strip() for p in rhs.split(',')]
+
+ if len(parts) < 2:
+ continue
+
+ mods = parts[0]
+ key = parts[1]
+
+ desc = ""
+ dispatcher = ""
+ params = ""
+
+ start_idx = 0
+
+ if has_desc:
+ desc = parts[2] if len(parts) >= 3 else ""
+ dispatcher = parts[3] if len(parts) >= 4 else ""
+ start_idx = 4
+ else:
+ dispatcher = parts[2] if len(parts) >= 3 else ""
+ start_idx = 3
+
+ # Collect params
+ remaining_parts = []
+ if start_idx < len(parts):
+ for i in range(start_idx, len(parts)):
+ if parts[i]:
+ remaining_parts.append(parts[i])
+
+ if remaining_parts:
+ params = ", ".join(remaining_parts)
+
+ # Formatting mods
+ mods = mods.replace("$mainMod", "SUPER")
+ mods = re.sub(r'[ \t]+', '+', mods)
+
+ # Build combo string
+ if mods and key:
+ combo_str = f"{mods}+{key}"
+ elif key:
+ combo_str = key
+ else:
+ combo_str = mods
+
+ # Final Print Format
+ if has_desc and desc:
+ formatted_lines.append(f"{combo_str} — {desc}")
+ elif dispatcher:
+ if params:
+ formatted_lines.append(f"{combo_str} — {dispatcher} {params}")
+ else:
+ formatted_lines.append(f"{combo_str} — {dispatcher}")
+ else:
+ formatted_lines.append(combo_str)
+
+ return formatted_lines
+
+def main():
+ if len(sys.argv) < 2:
+ # No files provided
+ sys.exit(0)
+
+ config_files = sys.argv[1:]
+
+ binds, suggestions = parse_files(config_files)
+
+ if not binds:
+ print("no keybinds found.")
+ sys.exit(1)
+
+ formatted = format_for_rofi(binds)
+
+ for line in formatted:
+ print(line)
+
+ # Handle suggestions (print to stderr or a specific file if needed,
+ # but the original script assigns it to a variable 'msg'.
+ # To pass this back to bash, we might need a separate mechanism or just print to a known file.)
+ if suggestions:
+ import tempfile
+ try:
+ with tempfile.NamedTemporaryFile(mode='w', delete=False, prefix='hypr-unbind-suggestions-', suffix='.conf') as tf:
+ tf.write('\n'.join(suggestions) + '\n')
+ # We print a special marker line to stdout that the bash script can capture?
+ # Or better, just print to stderr and let the user ignore it,
+ # OR, since the original script specifically puts it in the Rofi message,
+ # we can print a special string at the END of stdout or to a side channel.
+
+ # Let's decide to print the valid keybinds to stdout (for rofi).
+ # And print the suggestion file path to a known location or specific fd if possible.
+ # Simplest: Write to a fixed temp file location that the bash script checks.
+ with open("/tmp/hypr_keybind_suggestions_file", "w") as sf:
+ sf.write(tf.name)
+ except Exception:
+ pass
+
+if __name__ == "__main__":
+ main()
diff --git a/config/hypr/scripts/sddm_wallpaper.sh b/config/hypr/scripts/sddm_wallpaper.sh
index 9dca2f72..17640f40 100755
--- a/config/hypr/scripts/sddm_wallpaper.sh
+++ b/config/hypr/scripts/sddm_wallpaper.sh
@@ -6,7 +6,8 @@
# variables
terminal=kitty
-wallDIR="$HOME/Pictures/wallpapers"
+PICTURES_DIR="$(xdg-user-dir PICTURES 2>/dev/null || echo "$HOME/Pictures")"
+wallDIR="$PICTURES_DIR/wallpapers"
SCRIPTSDIR="$HOME/.config/hypr/scripts"
wallpaper_current="$HOME/.config/hypr/wallpaper_effects/.wallpaper_current"
wallpaper_modified="$HOME/.config/hypr/wallpaper_effects/.wallpaper_modified"
@@ -20,6 +21,10 @@ sddm_simple="$sddm_themes_dir/simple_sddm_2"
# rofi-wallust-sddm colors path
rofi_wallust="$HOME/.config/rofi/wallust/colors-rofi.rasi"
sddm_theme_conf="$sddm_simple/theme.conf"
+if [[ ! -f "$rofi_wallust" ]]; then
+ notify-send -i "$iDIR/error.png" "SDDM" "Wallust colors file not found ($rofi_wallust). Aborting."
+ exit 1
+fi
# Directory for swaync
iDIR="$HOME/.config/swaync/images"
@@ -33,15 +38,45 @@ elif [[ "$1" == "--effects" ]]; then
mode="effects"
fi
+# Abort if SDDM is not running (avoid errors on non-SDDM systems)
+if command -v systemctl >/dev/null 2>&1; then
+ if ! systemctl is-active --quiet sddm; then
+ notify-send -i "$iDIR/error.png" "SDDM" "SDDM is not running. Skipping SDDM wallpaper update."
+ exit 0
+ fi
+elif ! pidof sddm >/dev/null 2>&1; then
+ notify-send -i "$iDIR/error.png" "SDDM" "SDDM is not running. Skipping SDDM wallpaper update."
+ exit 0
+fi
+
# Extract colors from rofi wallust config
-color0=$(grep -oP 'color1:\s*\K#[A-Fa-f0-9]+' "$rofi_wallust")
-color1=$(grep -oP 'color0:\s*\K#[A-Fa-f0-9]+' "$rofi_wallust")
-color7=$(grep -oP 'color14:\s*\K#[A-Fa-f0-9]+' "$rofi_wallust")
-color10=$(grep -oP 'color10:\s*\K#[A-Fa-f0-9]+' "$rofi_wallust")
-color12=$(grep -oP 'color12:\s*\K#[A-Fa-f0-9]+' "$rofi_wallust")
-color13=$(grep -oP 'color13:\s*\K#[A-Fa-f0-9]+' "$rofi_wallust")
-foreground=$(grep -oP 'foreground:\s*\K#[A-Fa-f0-9]+' "$rofi_wallust")
+extract_color() {
+ local key="$1"
+ local value
+ value=$(grep -oP "$key:\s*\K#[A-Fa-f0-9]+" "$rofi_wallust" | head -n1)
+ echo "$value"
+}
+
+color0=$(extract_color "color1")
+color1=$(extract_color "color0")
+color7=$(extract_color "color14")
+color10=$(extract_color "color10")
+color12=$(extract_color "color12")
+color13=$(extract_color "color13")
+foreground=$(extract_color "foreground")
+
+missing_colors=()
+for var in color0 color1 color7 color10 color12 color13 foreground; do
+ if [[ -z "${!var}" ]]; then
+ missing_colors+=("$var")
+ fi
+done
+
+if [[ ${#missing_colors[@]} -gt 0 ]]; then
+ notify-send -i "$iDIR/error.png" "SDDM" "Missing color(s): ${missing_colors[*]}. Run Wallust first."
+ exit 1
+fi
#background-color=$(grep -oP 'background:\s*\K#[A-Fa-f0-9]+' "$rofi_wallust")
# wallpaper to use
diff --git a/config/hypr/scripts/update_WindowRules.sh b/config/hypr/scripts/update_WindowRules.sh
new file mode 100755
index 00000000..8b4262ba
--- /dev/null
+++ b/config/hypr/scripts/update_WindowRules.sh
@@ -0,0 +1,60 @@
+#!/usr/bin/env bash
+# Script to update WindowRules config if Hyprland version is >= 0.53
+
+CONFIGS_DIR="$HOME/.config/hypr/configs"
+TARGET_FILE="$CONFIGS_DIR/WindowRules.conf"
+V3_FILE="$CONFIGS_DIR/WindowRules-config-v3.conf"
+
+if [[ ! -f "$V3_FILE" ]]; then
+ echo "Error: Source configuration file not found: $V3_FILE"
+ exit 1
+fi
+
+get_hyprland_version() {
+ local ver="0.0.0"
+ local raw_ver=""
+
+ if command -v hyprctl &>/dev/null; then
+ raw_ver=$(hyprctl version 2>/dev/null | grep "Tag:" | cut -d 'v' -f2)
+ fi
+
+ if [ -z "$raw_ver" ] && command -v Hyprland &>/dev/null; then
+ raw_ver=$(Hyprland --version 2>/dev/null | grep "Tag:" | cut -d 'v' -f2 | awk '{print $1}')
+ fi
+
+ if [ -n "$raw_ver" ]; then
+ ver=$(echo "$raw_ver" | grep -oE '^[0-9]+\.[0-9]+(\.[0-9]+)?')
+ fi
+
+ if [ -z "$ver" ]; then
+ echo "0.0.0"
+ else
+ echo "$ver"
+ fi
+}
+
+VERSION=$(get_hyprland_version)
+REQUIRED_VER="0.53"
+
+# Check if version >= REQUIRED_VER
+SMALLEST=$(printf '%s\n' "$REQUIRED_VER" "$VERSION" | sort -V | head -n1)
+
+if [ "$SMALLEST" = "$REQUIRED_VER" ]; then
+ echo "Version $VERSION >= $REQUIRED_VER. Updating WindowRules config..."
+ # Backup existing config if it exists
+ if [ -f "$TARGET_FILE" ]; then
+ echo "Backing up existing WindowRules.conf to WindowRules.conf.bak"
+ mv "$TARGET_FILE" "$TARGET_FILE.bak"
+ fi
+ cp "$V3_FILE" "$TARGET_FILE"
+
+ if command -v hyprctl &>/dev/null; then
+ if hyprctl instances &>/dev/null; then
+ echo "Reloading Hyprland..."
+ hyprctl reload
+ fi
+ fi
+else
+ echo "Version $VERSION < $REQUIRED_VER. No update needed."
+fi
+
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage