I am batman

This commit is contained in:
2026-07-10 20:07:29 -04:00
commit 4aac54bff6
175 changed files with 18136 additions and 0 deletions

83
scripts/amdgpu.py Executable file
View File

@@ -0,0 +1,83 @@
import pyamdgpuinfo
import json
def format_frequency(frequency_hz: int) -> str:
"""
Takes a frequency (in Hz) and normalizes it: `Hz`, `MHz`, or `GHz`
Returns:
str: frequency string with the appropriate suffix applied
"""
return (
format_size(frequency_hz, binary=False)
.replace("B", "Hz")
.replace("bytes", "Hz")
)
def format_size(size: int, binary=True) -> str:
"""
Format size in bytes to a human-readable format.
Args:
size (int): Size in bytes.
binary (bool): If True, use binary (base 1024) units.
Returns:
str: Formatted size string.
"""
suffixes = ["B", "KiB", "MiB", "GiB", "TiB"] if binary else ["B", "KB", "MB", "GB", "TB"]
base = 1024 if binary else 1000
index = 0
while size >= base and index < len(suffixes) - 1:
size /= base
index += 1
return f"{size:.0f} {suffixes[index]}"
def main():
# Detect the number of GPUs available
n_devices = pyamdgpuinfo.detect_gpus()
if n_devices == 0:
print("No AMD GPUs detected.")
return
# Get GPU information for the first GPU (index 0)
first_gpu = pyamdgpuinfo.get_gpu(0)
try:
# Query GPU temperature
temperature = first_gpu.query_temperature()
temperature = f"{temperature:.0f}°C" # Format temperature to 2 digits with "°C"
# Query GPU core clock
core_clock_hz = first_gpu.query_sclk() # In Hz
formatted_core_clock = format_frequency(core_clock_hz)
# Query GPU power consumption
power_usage = first_gpu.query_power()
# Query GPU load
gpu_load = first_gpu.query_load()
formatted_gpu_load = f"{gpu_load:.1f}%" # Format GPU load to 1 decimal place
# Create a dictionary with the GPU information
gpu_info = {
"GPU Temperature": temperature,
"GPU Load": formatted_gpu_load,
"GPU Core Clock": formatted_core_clock,
"GPU Power Usage": f"{power_usage} Watts"
}
# Convert the dictionary to a JSON string, ensure_ascii=False to prevent escaping
json_output = json.dumps(gpu_info, ensure_ascii=False)
# Print the JSON string
print(json_output)
except Exception as e:
print(f"Error: {str(e)}")
if __name__ == "__main__":
main()

84
scripts/animations.sh Executable file
View File

@@ -0,0 +1,84 @@
#!/usr/bin/env bash
# Define paths
scrDir=$(dirname "$(realpath "$0")")
source "$scrDir/globalcontrol.sh"
config_dir="$HOME/.config"
animations_dir="$config_dir/hypr/animations"
animations_conf="$config_dir/hypr/animations.conf"
rofi_theme="$config_dir/rofi/clipboard.rasi"
# Set rofi scaling
[[ "${rofiScale}" =~ ^[0-9]+$ ]] || rofiScale=10
r_scale="configuration {font: \"JetBrainsMono Nerd Font ${rofiScale}\";}"
wind_border=$((hypr_border * 3 / 2))
elem_border=$([ $hypr_border -eq 0 ] && echo "5" || echo $hypr_border)
# Evaluate spawn position
readarray -t curPos < <(hyprctl cursorpos -j | jq -r '.x,.y')
readarray -t monRes < <(hyprctl -j monitors | jq '.[] | select(.focused==true) | .width,.height,.scale,.x,.y')
readarray -t offRes < <(hyprctl -j monitors | jq -r '.[] | select(.focused==true).reserved | map(tostring) | join("\n")')
monRes[2]="$(echo "${monRes[2]}" | sed "s/\.//")"
monRes[0]="$(( ${monRes[0]} * 100 / ${monRes[2]} ))"
monRes[1]="$(( ${monRes[1]} * 100 / ${monRes[2]} ))"
curPos[0]="$(( ${curPos[0]} - ${monRes[3]} ))"
curPos[1]="$(( ${curPos[1]} - ${monRes[4]} ))"
if [ "${curPos[0]}" -ge "$((${monRes[0]} / 2))" ] ; then
x_pos="east"
x_off="-$(( ${monRes[0]} - ${curPos[0]} - ${offRes[2]} ))"
else
x_pos="west"
x_off="$(( ${curPos[0]} - ${offRes[0]} ))"
fi
if [ "${curPos[1]}" -ge "$((${monRes[1]} / 2))" ] ; then
y_pos="south"
y_off="-$(( ${monRes[1]} - ${curPos[1]} - ${offRes[3]} ))"
else
y_pos="north"
y_off="$(( ${curPos[1]} - ${offRes[1]} ))"
fi
r_override="window{location:${x_pos} ${y_pos};anchor:${x_pos} ${y_pos};x-offset:${x_off}px;y-offset:${y_off}px;border:${hypr_width}px;border-radius:${wind_border}px;} wallbox{border-radius:${elem_border}px;} element{border-radius:${elem_border}px;}"
# Ensure the animations directory exists
if [ ! -d "$animations_dir" ]; then
notify-send "Error" "Animations directory does not exist at $animations_dir"
exit 1
fi
# List available .conf files in animations directory
animation_files=$(ls "$animations_dir"/*.conf 2>/dev/null)
if [ -z "$animation_files" ]; then
notify-send "Error" "No .conf files found in $animations_dir"
exit 1
fi
# Display options using Rofi with custom scaling, positioning, and placeholder
selected_animation=$(echo "$animation_files" | awk -F/ '{print $NF}' | \
rofi -dmenu \
-p "Select animation" \
-theme-str "entry { placeholder: \"Select animation...\"; }" \
-theme-str "${r_scale}" \
-theme-str "${r_override}" \
-theme "$rofi_theme")
# Exit if no selection was made
if [ -z "$selected_animation" ]; then
exit 0
fi
# Generate the new source line
selected_path="$animations_dir/$selected_animation"
new_source_line="source = $selected_path"
# Update the animations.conf file
if grep -q "^source = " "$animations_conf"; then
sed -i "s|^source = .*|$new_source_line|" "$animations_conf"
else
echo "$new_source_line" >> "$animations_conf"
fi
# Notify the user
notify-send "Animation Updated" "Sourced $selected_animation"

228
scripts/batterynotify.sh Executable file
View File

@@ -0,0 +1,228 @@
#!/usr/bin/env bash
undock=false
scrDir=$(dirname "$(realpath "$0")")
source $scrDir/globalcontrol.sh
batterynotify_conf="${hydeConfDir}/hyde.conf" # Shared with hyde configuration
config_info() {
cat << EOF
Modify $batterynotify_conf to set options.
STATUS THRESHOLD INTERVAL
Full $battery_full_threshold $notify Minutes
Critical $battery_critical_threshold $timer Seconds then '$execute_critical'
Low $battery_low_threshold $interval Percent then '$execute_low'
Unplug $unplug_charger_threshold $interval Percent then '$execute_unplug'
Charging: $execute_charging
Discharging: $execute_discharging
EOF
}
is_laptop() { # Check if the system is a laptop
if grep -q "Battery" /sys/class/power_supply/BAT*/type; then
return 0 # It's a laptop
else
echo "No battery detected. If you think this is an error please post a report to the repo"
exit 0 # It's not a laptop
fi
}
is_laptop
fn_verbose () {
if $verbose; then
cat << VERBOSE
=============================================
Battery Status: $battery_status
Battery Percentage: $battery_percentage
=============================================
VERBOSE
fi
}
fn_notify () { # Send notification
notify-send -a "Power" $1 -u $2 "$3" "$4" -p # Call the notify-send command with the provided arguments \$1 is the flags \$2 is the urgency \$3 is the title \$4 is the message
}
fn_percentage () {
if [[ "$battery_percentage" -ge "$unplug_charger_threshold" ]] && [[ "$battery_status" != "Discharging" ]] && [[ "$battery_status" != "Full" ]] && (( (battery_percentage - last_notified_percentage) >= $interval )); then if $verbose; then echo "Prompt:UNPLUG: $battery_unplug_threshold $battery_status $battery_percentage" ; fi
fn_notify "-t 5000 " "CRITICAL" "Battery Charged" "Battery is at $battery_percentage%. You can unplug the charger!"
last_notified_percentage=$battery_percentage
elif [[ "$battery_percentage" -le "$battery_critical_threshold" ]]; then
count=$(( timer > $mnt ? timer : $mnt )) # reset count
while [ $count -gt 0 ] && [[ $battery_status == "Discharging"* ]]; do
for battery in /sys/class/power_supply/BAT*; do battery_status=$(< "$battery/status") ; done
if [[ $battery_status != "Discharging" ]] ; then break ; fi
fn_notify "-t 5000 -r 69 " "CRITICAL" "Battery Critically Low" "$battery_percentage% is critically low. Device will execute $execute_critical in $((count/60)):$((count%60)) ."
count=$((count-1))
sleep 1
done
[ $count -eq 0 ] && fn_action
elif [[ "$battery_percentage" -le "$battery_low_threshold" ]] && [[ "$battery_status" == "Discharging" ]] && (( (last_notified_percentage - battery_percentage) >= $interval )); then if $verbose; then echo "Prompt:LOW: $battery_low_threshold $battery_status $battery_percentage" ; fi
fn_notify "-t 5000 " "CRITICAL" "Battery Low" "Battery is at $battery_percentage%. Connect the charger."
last_notified_percentage=$battery_percentage
fi
}
fn_action () { #handles the $execute_critical command #? This is special as it will try to execute always
count=$(( timer > $mnt ? timer : $mnt )) # reset count
nohup $execute_critical
}
fn_status () {
if [[ $battery_percentage -ge $battery_full_threshold ]] && [[ "$battery_status" != *"Discharging"* ]]; then echo "Full and $battery_status"
battery_status="Full" ;fi
case "$battery_status" in # Handle the power supply status
"Discharging") if $verbose; then echo "Case:$battery_status Level: $battery_percentage" ;fi
if [[ "$prev_status" != "Discharging" ]] || [[ "$prev_status" == "Full" ]] ; then
prev_status=$battery_status
urgency=$([[ $battery_percentage -le "$battery_low_threshold" ]] && echo "CRITICAL" || echo "NORMAL")
fn_notify "-t 5000 -r 54321 " "$urgency" "Charger Plug OUT" "Battery is at $battery_percentage%."
$execute_discharging
fi
fn_percentage
;;
"Not"*|"Charging") if $verbose; then echo "Case:$battery_status Level: $battery_percentage" ;fi
if [[ "$prev_status" == "Discharging" ]] || [[ "$prev_status" == "Not"* ]] ; then
prev_status=$battery_status
count=$(( timer > $mnt ? timer : $mnt )) # reset count
urgency=$([[ "$battery_percentage" -ge $unplug_charger_threshold ]] && echo "CRITICAL" || echo "NORMAL")
fn_notify "-t 5000 -r 54321 " "$urgency" "Charger Plug In" "Battery is at $battery_percentage%."
$execute_charging
fi
fn_percentage
;;
"Full") if $verbose; then echo "Case:$battery_status Level: $battery_percentage" ;fi
if [[ $battery_status != "Discharging" ]]; then
now=$(date +%s)
if [[ "$prev_status" == *"harging"* ]] || ((now - lt >= $((notify*60)) )); then
fn_notify "-t 5000 -r 54321" "CRITICAL" "Battery Full" "Please unplug your Charger"
prev_status=$battery_status lt=$now
$execute_charging
fi
fi
;;
*)
if [[ ! -f "/tmp/hyprdots.batterynotify.status.fallback.$battery_status-$$" ]]; then
echo "Status: '==>> "$battery_status" <<==' Script on Fallback mode,Unknown power supply status.Please copy this line and raise an issue to the Github Repo.Also run 'ls /tmp/hyprdots.batterynotify' to see the list of lock files.*"
touch "/tmp/hyprdots.batterynotify.status.fallback.$battery_status-$$"
fi
fn_percentage
;;
esac
}
get_battery_info() { #TODO Might change this if we can get an effective way to parse dbus. I will do it some time...
total_percentage=0 battery_count=0
for battery in /sys/class/power_supply/BAT*; do
battery_status=$(<"$battery/status") battery_percentage=$(<"$battery/capacity")
total_percentage=$((total_percentage + battery_percentage))
battery_count=$((battery_count + 1))
done
battery_percentage=$((total_percentage / battery_count)) #? For Multiple Battery
}
fn_status_change () { # Handle when status changes
get_battery_info
# Add these two lines at the beginning of the function
local executed_low=false
local executed_unplug=false
if [ "$battery_status" != "$last_battery_status" ] || [ "$battery_percentage" != "$last_battery_percentage" ]; then
last_battery_status=$battery_status
last_battery_percentage=$battery_percentage # Check if battery status or percentage has changed
fn_verbose
fn_percentage
if [[ "$battery_percentage" -le "$battery_low_threshold" ]] && ! $executed_low; then $execute_low
executed_low=true executed_unplug=false
fi
if [[ "$battery_percentage" -ge "$unplug_charger_threshold" ]] && ! $executed_unplug; then $execute_unplug
executed_unplug=true executed_low=false
fi
if $undock; then fn_status; fi
fi
}
# resume_processes() { for pid in $pids ; do if [ "$pid" -ne "$current_pid" ] ; then kill -CONT $pid ; notify-send -a "Battery Notify" -t 2000 -r 9889 -u "CRITICAL" "Debugging ENDED, Resuming Regular Process" ; fi ; done }
main() { # Main function
rm -fr /tmp/hyprdots.batterynotify* # Cleaning the lock file
battery_full_threshold=${battery_full_threshold:-100}
battery_critical_threshold=${battery_critical_threshold:-5}
unplug_charger_threshold=${unplug_charger_threshold:-80}
battery_low_threshold=${battery_low_threshold:-20}
timer=${timer:-120}
notify=${notify:-1140}
interval=${interval:-5}
execute_critical=${execute_critical:-"systemctl suspend"}
execute_low=${execute_low:-}
execute_unplug=${execute_unplug:-}
config_info
if $verbose; then for line in "Verbose Mode is ON..." "" "" "" "" ; do echo $line ; done;
#TODO Might still need this in the future but for now we don't have any battery notify issues
# current_pid=$$
# pids=$(pgrep -f "/usr/bin/env bash ${scrDir}/batterynotify.sh" )
# for pid in $pids ; do if [ "$pid" -ne $current_pid ] ;then kill -STOP "$pid" ;notify-send -a "Battery Notify" -t 2000 -r 9889 -u "CRITICAL" "Debugging STARTED, Pausing Regular Process" ;fi ; done ; trap resume_processes SIGINT ;
fi
get_battery_info # initiate the function
last_notified_percentage=$battery_percentage
prev_status=$battery_status
dbus-monitor --system "type='signal',interface='org.freedesktop.DBus.Properties',path='$(upower -e | grep battery)'" 2> /dev/null | while read -r battery_status_change; do fn_status_change ; done
}
verbose=false
case "$1" in
-m|--modify)
EDITOR="${EDITOR:-code}" #* Use VS Code as the default editor
echo -e "[Editor]: $EDITOR \n To change editor, run 'export EDITOR=preferred-editor' \n[Modifying]: $batterynotify_conf \nPress Any Key if done editing"
#kitty -o allow_remote_control=yes -o listen_on=unix:/tmp/mykitty $(which $EDITOR) "$batterynotify_conf" > /dev/null 2>&1 &
kitty "$(which $EDITOR)" "$batterynotify_conf" > /dev/null 2>&1 &
LAST_MD5SUM=$(md5sum "$batterynotify_conf")
while true; do CURRENT_MD5SUM=$(md5sum "$batterynotify_conf")
if [ "$CURRENT_MD5SUM" != "$LAST_MD5SUM" ]; then
notify-send "Config Changed: Needs reboot or restart $0"
LAST_MD5SUM="$CURRENT_MD5SUM"
fi ; read -t 2 -n 1 > /dev/null && break #? loop every 2 seconds
done
exit 0
;;
-i|--info)
config_info
exit 0
;;
-v|--verbose)
verbose=true
;;
-*)
cat << HELP
Usage: $0 [options]
[-m|--modify] Modify configuration file
[-i|--info] Display configuration information
[-v|--verbose] Debugging mode
[-h|--help] This Message
HELP
exit 0
;;
esac
mnc=2 mxc=50 mnl=10 mxl=80 mnu=50 mxu=100 mnt=60 mxt=1000 mnf=80 mxf=100 mnn=1 mxn=1140 mni=1 mxi=10 #Defaults Ranges
check_range() {
local var=$1 min=$2 max=$3 error_message=$4
if [[ $var =~ ^[0-9]+$ ]] && (( var >= min && var <= max )); then
var=$var ; shift 2
else
echo -e "$1 WARNING: $error_message must be $min - $max." >&2
fi
}
check_range "$battery_full_threshold" $mnf $mxf "Full Threshold"
check_range "$battery_critical_threshold" $mnc $mxc "Critical Threshold"
check_range "$battery_low_threshold" $mnl $mxl "Low Threshold"
check_range "$unplug_charger_threshold" $mnu $mxu "Unplug Threshold"
check_range "$timer" $mnt $mxt "Timer"
check_range "$notify" $mnn $mxn "Notify"
check_range "$interval" $mni $mxi "Interval"
main

111
scripts/brightnesscontrol.sh Executable file
View File

@@ -0,0 +1,111 @@
#!/usr/bin/env bash
# Check if the script is already running
pgrep -cf "${0##*/}" | grep -qv 1 && echo "An instance of the script is already running..." && exit 1
scrDir=`dirname "$(realpath "$0")"`
source $scrDir/globalcontrol.sh
# Check if SwayOSD is installed
use_swayosd=false
if command -v swayosd-client >/dev/null 2>&1 && pgrep -x swayosd-server >/dev/null; then
use_swayosd=true
fi
print_error()
{
cat << EOF
$(basename ${0}) <action> [step] [mode]
...valid actions are...
i -- <i>ncrease brightness [+5%]
d -- <d>ecrease brightness [-5%]
Example:
$(basename ${0}) i 10 # Increase brightness by 10%
$(basename ${0}) d # Decrease brightness by default step (5%)
$(basename ${0}) i 5 -q # Increase brightness by 5% quietly
EOF
}
notify="${waybar_brightness_notification:-true}" # Default: notifications are enabled
action="" # Will store 'increase' or 'decrease'
step=5 # Default step value
# Parse all arguments
for arg in "$@"; do
case $arg in
i|-i)
[ -n "$action" ] &&
{
echo -e "\033[38;2;255;0;0mOne or more actions are provided\033[0m";
print_error;
exit 1;
} # Prevent multiple actions
action="increase" ;; # Increase brightness
d|-d)
[ -n "$action" ] &&
{
echo -e "\033[38;2;255;0;0mOne or more actions are provided\033[0m";
print_error;
exit 1;
} # Prevent multiple actions
action="decrease" ;; # Decrease brightness
q|-q)
notify=false ;; # Disabling notification
[0-9]*)
if ! echo "$arg" | grep -Eq '^[0-9]+$'; then
print_error
exit 1
fi
step=$arg ;; # Step value
*)
print_error && exit 1 ;; # Invalid input
esac
done
if [ -z "$action" ]; then # If actions are missing with mode/value
echo -e "\033[38;2;255;0;0mActions are not provided\033[0m"
print_error
exit 1
fi
send_notification() {
brightness=`brightnessctl info | grep -oP "(?<=\()\d+(?=%)" | cat`
brightinfo=$(brightnessctl info | awk -F "'" '/Device/ {print $2}')
angle="$(((($brightness + 2) / 5) * 5))"
ico="$HOME/.config/dunst/icons/vol/vol-${angle}.svg"
bar=$(seq -s "." $(($brightness / 15)) | sed 's/[0-9]//g')
notify-send -a "t2" -r 91190 -t 800 -i "${ico}" "${brightness}${bar}" "${brightinfo}"
}
get_brightness() {
brightnessctl -m | grep -o '[0-9]\+%' | head -c-2
}
case $action in
increase) # increase the backlight
if [[ $(get_brightness) -lt 10 ]] ; then
# increase the backlight by 1% if less than 10%
step=1
fi
$use_swayosd && swayosd-client --brightness raise "$step" && exit 0
brightnessctl set +${step}%
[ "$notify" = true ] && send_notification ;;
decrease) # decrease the backlight
if [[ $(get_brightness) -le 10 ]] ; then
# decrease the backlight by 1% if less than 10%
step=1
fi
if [[ $(get_brightness) -le 1 ]]; then
brightnessctl set ${step}%
$use_swayosd && exit 0
else
$use_swayosd && swayosd-client --brightness lower "$step" && exit 0
brightnessctl set ${step}%-
fi
[ "$notify" = true ] && send_notification ;;
esac

16
scripts/center-window.sh Executable file
View File

@@ -0,0 +1,16 @@
#!/usr/bin/env bash
# Toggle single_window_aspect_ratio in dwindle layout
# This script toggles between enforcing a 1:1 aspect ratio and allowing full width
# Get current dwindle settings
CURRENT_RATIO=$(hyprctl getoption dwindle:single_window_aspect_ratio | grep -oP 'vec2: \K.*')
if [ "$CURRENT_RATIO" = "[1, 1]" ]; then
# Disable aspect ratio (set to 0 0 to disable)
hyprctl keyword dwindle:single_window_aspect_ratio "0 0"
else
# Enable aspect ratio (1 1 for square)
hyprctl keyword dwindle:single_window_aspect_ratio "1 1"
fi

9
scripts/cliphist-paste.sh Executable file
View File

@@ -0,0 +1,9 @@
#!/usr/bin/env sh
selected_item="$(/run/current-system/sw/bin/cliphist list | rofi -dmenu -i -p 'Clipboard')"
[ -z "$selected_item" ] && exit 0
printf '%s' "$selected_item" | /run/current-system/sw/bin/cliphist decode | /run/current-system/sw/bin/wl-copy
sleep 0.05
/run/current-system/sw/bin/wtype -M ctrl -k v -m ctrl

182
scripts/cliphist.sh Executable file
View File

@@ -0,0 +1,182 @@
#!/usr/bin/env sh
# Set variables
scrDir=$(dirname "$(realpath "$0")")
source "$scrDir/globalcontrol.sh"
roconf="${confDir}/rofi/clipboard.rasi"
favoritesFile="${HOME}/.cliphist_favorites"
# Set rofi scaling
[[ "${rofiScale}" =~ ^[0-9]+$ ]] || rofiScale=10
r_scale="configuration {font: \"JetBrainsMono Nerd Font ${rofiScale}\";}"
wind_border=$((hypr_border * 3 / 2))
elem_border=$([ $hypr_border -eq 0 ] && echo "5" || echo $hypr_border)
# Evaluate spawn position
readarray -t curPos < <(hyprctl cursorpos -j | jq -r '.x,.y')
readarray -t monRes < <(hyprctl -j monitors | jq '.[] | select(.focused==true) | .width,.height,.scale,.x,.y')
readarray -t offRes < <(hyprctl -j monitors | jq -r '.[] | select(.focused==true).reserved | map(tostring) | join("\n")')
monRes[2]="$(echo "${monRes[2]}" | sed "s/\.//")"
monRes[0]="$(( ${monRes[0]} * 100 / ${monRes[2]} ))"
monRes[1]="$(( ${monRes[1]} * 100 / ${monRes[2]} ))"
curPos[0]="$(( ${curPos[0]} - ${monRes[3]} ))"
curPos[1]="$(( ${curPos[1]} - ${monRes[4]} ))"
if [ "${curPos[0]}" -ge "$((${monRes[0]} / 2))" ] ; then
x_pos="east"
x_off="-$(( ${monRes[0]} - ${curPos[0]} - ${offRes[2]} ))"
else
x_pos="west"
x_off="$(( ${curPos[0]} - ${offRes[0]} ))"
fi
if [ "${curPos[1]}" -ge "$((${monRes[1]} / 2))" ] ; then
y_pos="south"
y_off="-$(( ${monRes[1]} - ${curPos[1]} - ${offRes[3]} ))"
else
y_pos="north"
y_off="$(( ${curPos[1]} - ${offRes[1]} ))"
fi
r_override="window{location:${x_pos} ${y_pos};anchor:${x_pos} ${y_pos};x-offset:${x_off}px;y-offset:${y_off}px;border:${hypr_width}px;border-radius:${wind_border}px;} wallbox{border-radius:${elem_border}px;} element{border-radius:${elem_border}px;}"
# Show main menu if no arguments are passed
if [ $# -eq 0 ]; then
main_action=$(echo -e "History\nDelete\nView Favorites\nManage Favorites\nClear History" | rofi -dmenu -theme-str "entry { placeholder: \"Choose action\";}" -theme-str "${r_scale}" -theme-str "${r_override}" -config "${roconf}")
else
main_action="History"
fi
case "${main_action}" in
"History")
selected_item=$(stash list | rofi -dmenu -theme-str "entry { placeholder: \"History...\";}" -theme-str "${r_scale}" -theme-str "${r_override}" -config "${roconf}")
if [ -n "$selected_item" ]; then
echo "$selected_item" | stash decode | wl-copy
notify-send "Copied to clipboard."
fi
;;
"Delete")
selected_item=$(stash list | rofi -dmenu -theme-str "entry { placeholder: \"Delete...\";}" -theme-str "${r_scale}" -theme-str "${r_override}" -config "${roconf}")
if [ -n "$selected_item" ]; then
echo "$selected_item" | stash delete
notify-send "Deleted."
fi
;;
"View Favorites")
if [ -f "$favoritesFile" ] && [ -s "$favoritesFile" ]; then
# Read each Base64 encoded favorite as a separate line
mapfile -t favorites < "$favoritesFile"
# Prepare a list of decoded single-line representations for rofi
decoded_lines=()
for favorite in "${favorites[@]}"; do
decoded_favorite=$(echo "$favorite" | base64 --decode)
# Replace newlines with spaces for rofi display
single_line_favorite=$(echo "$decoded_favorite" | tr '\n' ' ')
decoded_lines+=("$single_line_favorite")
done
selected_favorite=$(printf "%s\n" "${decoded_lines[@]}" | rofi -dmenu -theme-str "entry { placeholder: \"View Favorites\";}" -theme-str "${r_scale}" -theme-str "${r_override}" -config "${roconf}")
if [ -n "$selected_favorite" ]; then
# Find the index of the selected favorite
index=$(printf "%s\n" "${decoded_lines[@]}" | grep -nxF "$selected_favorite" | cut -d: -f1)
# Use the index to get the Base64 encoded favorite
if [ -n "$index" ]; then
selected_encoded_favorite="${favorites[$((index - 1))]}"
# Decode and copy the full multi-line content to clipboard
echo "$selected_encoded_favorite" | base64 --decode | wl-copy
notify-send "Copied to clipboard."
else
notify-send "Error: Selected favorite not found."
fi
fi
else
notify-send "No favorites."
fi
;;
"Manage Favorites")
manage_action=$(echo -e "Add to Favorites\nDelete from Favorites\nClear All Favorites" | rofi -dmenu -theme-str "entry { placeholder: \"Manage Favorites\";}" -theme-str "${r_scale}" -theme-str "${r_override}" -config "${roconf}")
case "${manage_action}" in
"Add to Favorites")
# Show clipboard history to add to favorites
item=$(stash list | rofi -dmenu -theme-str "entry { placeholder: \"Add to Favorites...\";}" -theme-str "${r_scale}" -theme-str "${r_override}" -config "${roconf}")
if [ -n "$item" ]; then
full_item=$(echo "$item" | stash decode)
encoded_item=$(echo "$full_item" | base64 -w 0)
# Check if the item is already in the favorites file
if grep -Fxq "$encoded_item" "$favoritesFile"; then
notify-send "Item is already in favorites."
else
# Add the encoded item to the favorites file
echo "$encoded_item" >> "$favoritesFile"
notify-send "Added in favorites."
fi
fi
;;
"Delete from Favorites")
if [ -f "$favoritesFile" ] && [ -s "$favoritesFile" ]; then
# Read each Base64 encoded favorite as a separate line
mapfile -t favorites < "$favoritesFile"
# Prepare a list of decoded single-line representations for rofi
decoded_lines=()
for favorite in "${favorites[@]}"; do
decoded_favorite=$(echo "$favorite" | base64 --decode)
# Replace newlines with spaces for rofi display
single_line_favorite=$(echo "$decoded_favorite" | tr '\n' ' ')
decoded_lines+=("$single_line_favorite")
done
selected_favorite=$(printf "%s\n" "${decoded_lines[@]}" | rofi -dmenu -theme-str "entry { placeholder: \"Remove from Favorites...\";}" -theme-str "${r_scale}" -theme-str "${r_override}" -config "${roconf}")
if [ -n "$selected_favorite" ]; then
index=$(printf "%s\n" "${decoded_lines[@]}" | grep -nxF "$selected_favorite" | cut -d: -f1)
if [ -n "$index" ]; then
selected_encoded_favorite="${favorites[$((index - 1))]}"
# Handle case where only one item is present
if [ "$(wc -l < "$favoritesFile")" -eq 1 ]; then
# Remove the single encoded item from the file
> "$favoritesFile"
else
# Remove the selected encoded item from the favorites file
grep -vF -x "$selected_encoded_favorite" "$favoritesFile" > "${favoritesFile}.tmp" && mv "${favoritesFile}.tmp" "$favoritesFile"
fi
notify-send "Item removed from favorites."
else
notify-send "Error: Selected favorite not found."
fi
fi
else
notify-send "No favorites to remove."
fi
;;
"Clear All Favorites")
if [ -f "$favoritesFile" ] && [ -s "$favoritesFile" ]; then
confirm=$(echo -e "Yes\nNo" | rofi -dmenu -theme-str "entry { placeholder: \"Clear All Favorites?\";}" -theme-str "${r_scale}" -theme-str "${r_override}" -config "${roconf}")
if [ "$confirm" = "Yes" ]; then
> "$favoritesFile"
notify-send "All favorites have been deleted."
fi
else
notify-send "No favorites to delete."
fi
;;
*)
echo "Invalid action"
exit 1
;;
esac
;;
"Clear History")
if [ "$(echo -e "Yes\nNo" | rofi -dmenu -theme-str "entry { placeholder: \"Clear Clipboard History?\";}" -theme-str "${r_scale}" -theme-str "${r_override}" -config "${roconf}")" == "Yes" ] ; then
stash db wipe --expired
notify-send "Clipboard history cleared."
fi
;;
*)
echo "Invalid action"
exit 1
;;
esac

64
scripts/cpuinfo.sh Executable file
View File

@@ -0,0 +1,64 @@
#!/usr/bin/env sh
map_floor() {
IFS=', ' read -r -a pairs <<< "$1"
if [[ ${pairs[-1]} != *":"* ]]; then
def_val="${pairs[-1]}"
unset 'pairs[${#pairs[@]}-1]'
fi
for pair in "${pairs[@]}"; do
IFS=':' read -r key value <<< "$pair"
if [ ${2%%.*} -gt $key ]; then
echo "$value"
return
fi
done
[ -n "$def_val" ] && echo $def_val || echo " "
}
# Define glyphs
if [[ $NO_EMOJI -eq 1 ]]; then
temp_lv="85:, 65:, 45:☁, ❄"
else
temp_lv="85:🌋, 65:🔥, 45:☁️, ❄️"
fi
util_lv="90:, 60:󰓅, 30:󰾅, 󰾆"
# Get static CPU information
model=$(lscpu | awk -F': ' '/Model name/ {gsub(/^ *| *$| CPU.*/,"",$2); print $2}')
maxfreq=$(lscpu | awk '/CPU max MHz/ { sub(/\..*/,"",$4); print $4}')
# Get CPU stat
statFile=$(cat /proc/stat | head -1)
prevStat=$(awk '{print $2+$3+$4+$6+$7+$8 }' <<< $statFile)
prevIdle=$(awk '{print $5 }' <<< $statFile)
while true; do
# Get CPU stat
statFile=$(cat /proc/stat | head -1)
currStat=$(awk '{print $2+$3+$4+$6+$7+$8 }' <<< $statFile)
currIdle=$(awk '{print $5 }' <<< $statFile)
diffStat=$((currStat-prevStat))
diffIdle=$((currIdle-prevIdle))
# Get dynamic CPU information
utilization=$(awk -v stat="$diffStat" -v idle="$diffIdle" 'BEGIN {printf "%.1f", (stat/(stat+idle))*100}')
temperature=$(sensors | awk -F': ' '/Package id 0|Tctl/ { gsub(/^ *\+?|\..*/,"",$2); print $2; f=1; exit} END { if (!f) print "N/A"; }')
frequency=$(cat /proc/cpuinfo | awk '/cpu MHz/{ sum+=$4; c+=1 } END { printf "%.0f", sum/c }')
# Generate glyphs
icons=$(echo "$(map_floor "$util_lv" $utilization)$(map_floor "$temp_lv" $temperature)")
speedo=$(echo ${icons:0:1})
thermo=$(echo ${icons:1:1})
emoji=$(echo ${icons:2})
# Print the output
echo "{\"text\":\"$thermo $temperature°C\", \"tooltip\":\"$model\n$thermo Temperature: $temperature°C $emoji\n$speedo Utilization: $utilization%\n Clock Speed: $frequency/$maxfreq MHz\"}"
# Store state and sleep
prevStat=$currStat
prevIdle=$currIdle
sleep 5
done

5
scripts/dontkillsteam.sh Executable file
View File

@@ -0,0 +1,5 @@
if [[ $(hyprctl activewindow -j | jq -r ".class") == "Steam" ]]; then
xdotool windowunmap $(xdotool getactivewindow)
else
hyprctl dispatch killactive ""
fi

96
scripts/gamelauncher.sh Executable file
View File

@@ -0,0 +1,96 @@
#!/usr/bin/env sh
# set variables
MODE=${1:-5}
scrDir=`dirname "$(realpath "$0")"`
source $scrDir/globalcontrol.sh
ThemeSet="${confDir}/hypr/themes/theme.conf"
RofiConf="${confDir}/rofi/steam/gamelauncher_${MODE}.rasi"
# set rofi override
elem_border=$(( hypr_border * 2 ))
icon_border=$(( elem_border - 3 ))
r_override="element{border-radius:${elem_border}px;} element-icon{border-radius:${icon_border}px;}"
fn_steam() {
# check steam mount paths
SteamPaths=`grep '"path"' $SteamLib | awk -F '"' '{print $4}'`
ManifestList=`find $SteamPaths/steamapps/ -type f -name "appmanifest_*.acf" 2>/dev/null`
# read installed games
GameList=$(echo "$ManifestList" | while read acf
do
appid=`grep '"appid"' $acf | cut -d '"' -f 4`
if [ -f ${SteamThumb}/${appid}_library_600x900.jpg ] ; then
game=`grep '"name"' $acf | cut -d '"' -f 4`
echo "$game|$appid"
else
continue
fi
done | sort)
# launch rofi menu
RofiSel=$( echo "$GameList" | while read acf
do
appid=`echo $acf | cut -d '|' -f 2`
game=`echo $acf | cut -d '|' -f 1`
echo -en "$game\x00icon\x1f${SteamThumb}/${appid}_library_600x900.jpg\n"
done | rofi -dmenu -theme-str "${r_override}" -config $RofiConf)
# launch game
if [ ! -z "$RofiSel" ] ; then
launchid=`echo "$GameList" | grep "$RofiSel" | cut -d '|' -f 2`
${steamlaunch} -applaunch "${launchid} [gamemoderun %command%]" &
# dunstify "t1" -a "Launching ${RofiSel}..." -i ${SteamThumb}/${launchid}_header.jpg -r 91190 -t 2200
notify-send -a "t1" -i "${SteamThumb}/${launchid}_header.jpg" "Launching ${RofiSel}..."
fi
}
fn_lutris() {
[ ! -e "${icon_path}" ] && icon_path="${HOME}/.local/share/lutris/coverart"
[ ! -e "${icon_path}" ] && icon_path="${HOME}/.cache/lutris/coverart"
meta_data="/tmp/hyprdots-$(id -u)-lutrisgames.json"
# Retrieve the list of games from Lutris in JSON format
#TODO Only call this if new apps are installed...
# [ ! -s "${meta_data}" ] &&
notify-send -a "t1" "Please wait... " -t 4000
eval "${run_lutris}" -j -l 2> /dev/null| jq --arg icons "$icon_path/" --arg prefix ".jpg" '.[] |= . + {"select": (.name + "\u0000icon\u001f" + $icons + .slug + $prefix)}' > "${meta_data}"
[ ! -s "${meta_data}" ] && notify-send -a "t1" "Cannot Fetch Lutris Games!" && exit 1
CHOICE=$(jq -r '.[].select' "${meta_data}" | rofi -dmenu -p Lutris -theme-str "${r_override}" -config "${RofiConf}" )
[ -z "$CHOICE" ] && exit 0
SLUG=$(jq -r --arg choice "$CHOICE" '.[] | select(.name == $choice).slug' "${meta_data}" )
notify-send -a "t1" -i "${icon_path}/${SLUG}.jpg" "Launching ${CHOICE}..."
exec xdg-open "lutris:rungame/${SLUG}"
}
# Handle if flatpak or pkgmgr
run_lutris=""
( flatpak list --columns=application | grep -q "net.lutris.Lutris" ) && run_lutris="flatpak run net.lutris.Lutris" ; icon_path="${HOME}/.var/app/net.lutris.Lutris/data/lutris/coverart/"
[ -z "${run_lutris}" ] && ( pkg_installed 'lutris' ) && run_lutris="lutris"
if [ -z "${run_lutris}" ] || echo "$*" | grep -q "steam" ; then
# set steam library
if pkg_installed steam ; then
SteamLib="${XDG_DATA_HOME:-$HOME/.local/share}/Steam/config/libraryfolders.vdf"
SteamThumb="${XDG_DATA_HOME:-$HOME/.local/share}/Steam/appcache/librarycache"
steamlaunch="steam"
else
SteamLib="$HOME/.var/app/com.valvesoftware.Steam/.local/share/Steam/config/libraryfolders.vdf"
SteamThumb="$HOME/.var/app/com.valvesoftware.Steam/.local/share/Steam/appcache/librarycache"
steamlaunch="flatpak run com.valvesoftware.Steam"
fi
if [ ! -f $SteamLib ] || [ ! -d $SteamThumb ] ; then
notify-send -a "t1" "Steam library not found!"
exit 1
fi
fn_steam
else
fn_lutris
fi

16
scripts/gamemode.nix Normal file
View File

@@ -0,0 +1,16 @@
{ pkgs }:
pkgs.writeShellScriptBin "gamemode" ''
# Toggle animations on/off for gaming mode
status=$(${pkgs.hyprland}/bin/hyprctl getoption animations:enabled | grep -oP 'int: \K[0-9]+')
if [ "$status" = "1" ]; then
# Disable animations
${pkgs.hyprland}/bin/hyprctl keyword animations:enabled 0
${pkgs.libnotify}/bin/notify-send "Gamemode: ON" "Animations disabled"
else
# Enable animations
${pkgs.hyprland}/bin/hyprctl keyword animations:enabled 1
${pkgs.libnotify}/bin/notify-send "Gamemode: OFF" "Animations enabled"
fi
''

29
scripts/gamemode.sh Executable file
View File

@@ -0,0 +1,29 @@
#!/usr/bin/env sh
HYPRGAMEMODE=$(hyprctl getoption animations:enabled | sed -n '1p' | awk '{print $2}')
# Waybar performance
FILE="$HOME/.config/waybar/style.css"
sed -i 's/\/\* \(.*animation:.*\) \*\//\1/g' $FILE
sed -i 's/\/\* \(.*transition:.*\) \*\//\1/g' $FILE
if [ $HYPRGAMEMODE = 1 ]; then
sed -i 's/^\(.*animation:.*\)$/\/\* \1 \*\//g' $FILE
sed -i 's/^\(.*transition:.*\)$/\/\* \1 \*\//g' $FILE
fi
killall waybar
waybar >/dev/null 2>&1 &
# Hyprland performance
if [ $HYPRGAMEMODE = 1 ]; then
hyprctl --batch "\
keyword animations:enabled 0;\
keyword decoration:drop_shadow 0;\
keyword decoration:blur:enabled 0;\
keyword general:gaps_in 0;\
keyword general:gaps_out 0;\
keyword general:border_size 1;\
keyword decoration:rounding 0"
exit
else
hyprctl reload
fi

159
scripts/globalcontrol.sh Executable file
View File

@@ -0,0 +1,159 @@
#!/usr/bin/env bash
#// hyde envs
export confDir="${XDG_CONFIG_HOME:-$HOME/.config}"
export hydeConfDir="${confDir}/hyde"
export cacheDir="$HOME/.cache/hyde"
export thmbDir="${cacheDir}/thumbs"
export dcolDir="${cacheDir}/dcols"
export hashMech="sha1sum"
get_hashmap()
{
unset wallHash
unset wallList
unset skipStrays
unset verboseMap
for wallSource in "$@"; do
[ -z "${wallSource}" ] && continue
[ "${wallSource}" == "--skipstrays" ] && skipStrays=1 && continue
[ "${wallSource}" == "--verbose" ] && verboseMap=1 && continue
hashMap=$(find "${wallSource}" -type f \( -iname "*.gif" -o -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" \) -exec "${hashMech}" {} + | sort -k2)
if [ -z "${hashMap}" ] ; then
echo "WARNING: No image found in \"${wallSource}\""
continue
fi
while read -r hash image ; do
wallHash+=("${hash}")
wallList+=("${image}")
done <<< "${hashMap}"
done
if [ -z "${#wallList[@]}" ] || [[ "${#wallList[@]}" -eq 0 ]] ; then
if [[ "${skipStrays}" -eq 1 ]] ; then
return 1
else
echo "ERROR: No image found in any source"
exit 1
fi
fi
if [[ "${verboseMap}" -eq 1 ]] ; then
echo "// Hash Map //"
for indx in "${!wallHash[@]}" ; do
echo ":: \${wallHash[${indx}]}=\"${wallHash[indx]}\" :: \${wallList[${indx}]}=\"${wallList[indx]}\""
done
fi
}
get_themes()
{
unset thmSortS
unset thmListS
unset thmWallS
unset thmSort
unset thmList
unset thmWall
while read thmDir ; do
if [ ! -e "$(readlink "${thmDir}/wall.set")" ] ; then
get_hashmap "${thmDir}" --skipstrays || continue
echo "fixig link :: ${thmDir}/wall.set"
ln -fs "${wallList[0]}" "${thmDir}/wall.set"
fi
[ -f "${thmDir}/.sort" ] && thmSortS+=("$(head -1 "${thmDir}/.sort")") || thmSortS+=("0")
thmListS+=("$(basename "${thmDir}")")
thmWallS+=("$(readlink "${thmDir}/wall.set")")
done < <(find "${hydeConfDir}/themes" -mindepth 1 -maxdepth 1 -type d)
while IFS='|' read -r sort theme wall ; do
thmSort+=("${sort}")
thmList+=("${theme}")
thmWall+=("${wall}")
done < <(parallel --link echo "{1}\|{2}\|{3}" ::: "${thmSortS[@]}" ::: "${thmListS[@]}" ::: "${thmWallS[@]}" | sort -n -k 1 -k 2)
if [ "${1}" == "--verbose" ] ; then
echo "// Theme Control //"
for indx in "${!thmList[@]}" ; do
echo -e ":: \${thmSort[${indx}]}=\"${thmSort[indx]}\" :: \${thmList[${indx}]}=\"${thmList[indx]}\" :: \${thmWall[${indx}]}=\"${thmWall[indx]}\""
done
fi
}
[ -f "${hydeConfDir}/hyde.conf" ] && source "${hydeConfDir}/hyde.conf"
case "${enableWallDcol}" in
0|1|2|3) ;;
*) enableWallDcol=0 ;;
esac
if [ -z "${hydeTheme}" ] || [ ! -d "${hydeConfDir}/themes/${hydeTheme}" ] ; then
get_themes
hydeTheme="${thmList[0]}"
fi
export hydeTheme
export hydeThemeDir="${hydeConfDir}/themes/${hydeTheme}"
export wallbashDir="${hydeConfDir}/wallbash"
export enableWallDcol
#// hypr vars
if printenv HYPRLAND_INSTANCE_SIGNATURE &> /dev/null; then
export hypr_border="$(hyprctl -j getoption decoration:rounding | jq '.int')"
export hypr_width="$(hyprctl -j getoption general:border_size | jq '.int')"
fi
#// extra fns
pkg_installed()
{
local pkgIn=$1
if pacman -Qi "${pkgIn}" &> /dev/null ; then
return 0
elif pacman -Qi "flatpak" &> /dev/null && flatpak info "${pkgIn}" &> /dev/null ; then
return 0
elif command -v "${pkgIn}" &> /dev/null ; then
return 0
else
return 1
fi
}
get_aurhlpr()
{
if pkg_installed yay
then
aurhlpr="yay"
elif pkg_installed paru
then
aurhlpr="paru"
fi
}
set_conf()
{
local varName="${1}"
local varData="${2}"
touch "${hydeConfDir}/hyde.conf"
if [ $(grep -c "^${varName}=" "${hydeConfDir}/hyde.conf") -eq 1 ] ; then
sed -i "/^${varName}=/c${varName}=\"${varData}\"" "${hydeConfDir}/hyde.conf"
else
echo "${varName}=\"${varData}\"" >> "${hydeConfDir}/hyde.conf"
fi
}
set_hash()
{
local hashImage="${1}"
"${hashMech}" "${hashImage}" | awk '{print $1}'
}

292
scripts/gpuinfo.sh Executable file
View File

@@ -0,0 +1,292 @@
#!/usr/bin/env bash
# shellcheck disable=SC2312
# shellcheck disable=SC1090
scrDir=`dirname "$(realpath "$0")"`
gpuQ="/tmp/hyprdots-${UID}-gpuinfo-query"
tired=false
[[ " $* " =~ " tired " ]] && ! grep -q "tired" "${gpuQ}" && echo "tired=true" >>"${gpuQ}"
[[ " $* " =~ " no_emoji " ]] && ! grep -q "NO_EMOJI" "${gpuQ}" && echo "NO_EMOJI=1" >>"${gpuQ}"
if [[ ! " $* " =~ " startup " ]]; then
gpuQ="${gpuQ}$2"
fi
detect() { # Auto detect Gpu used by Hyprland(declared using env = WLR_DRM_DEVICES) Sophisticated?
card=$(echo "${WLR_DRM_DEVICES}" | cut -d':' -f1 | cut -d'/' -f4)
# shellcheck disable=SC2010
slot_number=$(ls -l /dev/dri/by-path/ | grep "${card}" | awk -F'pci-0000:|-card' '{print $2}')
vendor_id=$(lspci -nn -s "${slot_number}" )
declare -A vendors=(["10de"]="nvidia" ["8086"]="intel" ["1002"]="amd")
for vendor in "${!vendors[@]}"; do
if [[ ${vendor_id} == *"${vendor}"* ]]; then
initGPU="${vendors[${vendor}]}"
break
fi
done
if [[ -n ${initGPU} ]]; then
$0 --use "${initGPU}" startup
fi
}
query() {
nvidia_flag=0 amd_flag=0 intel_flag=0
touch "${gpuQ}"
if lsmod | grep -q 'nouveau'; then
echo "nvidia_gpu=\"Linux\"" >>"${gpuQ}" #? Incase If nouveau is installed
echo "nvidia_flag=1 # Using nouveau an open-source nvidia driver" >>"${gpuQ}"
elif command -v nvidia-smi &> /dev/null; then
nvidia_gpu=$(nvidia-smi --query-gpu=gpu_name --format=csv,noheader,nounits | head -n 1)
if [[ -n "${nvidia_gpu}" ]] ; then # Check for NVIDIA GPU
if [[ "${nvidia_gpu}" == *"NVIDIA-SMI has failed"* ]]; then #? Second Layer for dGPU
echo "nvidia_flag=0 # NVIDIA-SMI has failed" >> "${gpuQ}"
else
nvidia_address=$(lspci | grep -Ei "VGA|3D" | grep -i "${nvidia_gpu/NVIDIA /}" | cut -d' ' -f1)
{ echo "nvidia_address=\"${nvidia_address}\""
echo "nvidia_gpu=\"${nvidia_gpu/NVIDIA /}\""
echo "nvidia_flag=1"
} >> "${gpuQ}"
fi
fi
fi
if lspci -nn | grep -E "(VGA|3D)" | grep -iq "1002"; then
amd_gpu="$(lspci -nn | grep -Ei "VGA|3D" | grep -m 1 "1002" | awk -F'Advanced Micro Devices, Inc. ' '{gsub(/ *\[[^\]]*\]/,""); gsub(/ *\([^)]*\)/,""); print $2}')"
amd_address=$(lspci | grep -Ei "VGA|3D" | grep -i "${amd_gpu}" | cut -d' ' -f1)
{ echo "amd_address=\"${amd_address}\""
echo "amd_flag=1" # Check for Amd GPU
echo "amd_gpu=\"${amd_gpu}\""
} >> "${gpuQ}";fi
if lspci -nn | grep -E "(VGA|3D)" | grep -iq "8086"; then
intel_gpu="$(lspci -nn | grep -Ei "VGA|3D" | grep -m 1 "8086" | awk -F'Intel Corporation ' '{gsub(/ *\[[^\]]*\]/,""); gsub(/ *\([^)]*\)/,""); print $2}')"
intel_address=$(lspci | grep -Ei "VGA|3D" | grep -i "${intel_gpu}" | cut -d' ' -f1)
{ echo "intel_address=\"${intel_address}\""
echo "intel_flag=1" # Check for Intel GPU
echo "intel_gpu=\"${intel_gpu}\""
} >>"${gpuQ}"; fi
if ! grep -q "prioGPU=" "${gpuQ}" && [[ -n "${WLR_DRM_DEVICES}" ]]; then
trap detect EXIT
fi
}
toggle() {
if [[ -n "$1" ]]; then
next_prioGPU="$1_flag"
else
# Initialize gpu_flags and prioGPU if they don't exist
if ! grep -q "gpu_flags=" "${gpuQ}"; then
gpu_flags=$(grep "flag=1" "${gpuQ}" | cut -d '=' -f 1 | tr '\n' ' ' | tr -d '#')
echo "" >> "${gpuQ}"
echo "gpu_flags=\"${gpu_flags[*]}\"" >> "${gpuQ}"
fi
if ! grep -q "prioGPU=" "${gpuQ}"; then
gpu_flags=$(grep "gpu_flags=" "${gpuQ}" | cut -d'=' -f 2)
initGPU=$(echo "${gpu_flags}" | cut -d ' ' -f 1)
echo "prioGPU=${initGPU}" >> "${gpuQ}"
fi
mapfile -t anchor < <(grep "flag=1" "${gpuQ}" | cut -d '=' -f 1)
prioGPU=$(grep "prioGPU=" "${gpuQ}" | cut -d'=' -f 2) # Get the current prioGPU from the file
# Find the index of the current prioGPU in the anchor array
for index in "${!anchor[@]}"; do
if [[ "${anchor[${index}]}" = "${prioGPU}" ]]; then
current_index=${index}
fi
done
next_index=$(( (current_index + 1) % ${#anchor[@]} ))
next_prioGPU=${anchor[${next_index}]#\#}
fi
# Set the next prioGPU and remove the '#' character
sed -i 's/^\(nvidia_flag=1\|amd_flag=1\|intel_flag=1\)/#\1/' "${gpuQ}" # Comment out all the gpu flags in the file
sed -i "s/^#${next_prioGPU}/${next_prioGPU}/" "${gpuQ}" # Uncomment the next prioGPU in the file
sed -i "s/prioGPU=${prioGPU}/prioGPU=${next_prioGPU}/" "${gpuQ}" # Update the prioGPU in the file
}
# Thee shalt find the greatest one,
# He who not more than the chosen one
map_floor() {
# From the depths of the string, words arise,
# Keys in pairs, a treasure in disguise.
IFS=', ' read -r -a pairs <<< "$1"
# If the final token stands alone and bold,
# Declare it the default, its worth untold.
if [[ ${pairs[-1]} != *":"* ]]; then
def_val="${pairs[-1]}"
unset 'pairs[${#pairs[@]}-1]'
fi
# Scans the map, a peak it seeks,
# The highest passed, the value speaks.
for pair in "${pairs[@]}"; do
IFS=':' read -r key value <<< "$pair"
# Behold! Thou holds the secrets they seek,
# Declare it and silence the whispers unique.
if [ ${2%%.*} -gt $key ]; then
echo "$value"
return
fi
done
# On this lonely shore, where silence dwells
# Even the waves, echoes words unheard
[ -n "$def_val" ] && echo $def_val || echo " "
}
generate_json() {
# Generate glyphs
icons=$(echo "$(map_floor "$util_lv" $utilization)$(map_floor "$temp_lv" $temperature)")
speedo=$(echo ${icons:0:1})
thermo=$(echo ${icons:1:1})
emoji=$(echo ${icons:2})
local json="{\"text\":\"${thermo} ${temperature}°C\", \"tooltip\":\"${primary_gpu}\n${thermo} Temperature: ${temperature}°C ${emoji}"
#? Soon Add Something incase needed.
declare -A tooltip_parts
if [[ -n "${utilization}" ]]; then tooltip_parts["\n$speedo Utilization: "]="${utilization}%" ; fi
if [[ -n "${current_clock_speed}" ]] && [[ -n "${max_clock_speed}" ]]; then tooltip_parts["\n Clock Speed: "]="${current_clock_speed}/${max_clock_speed} MHz" ; fi
if [[ -n "${gpu_load}" ]]; then tooltip_parts["\n$speedo Utilization: "]="${gpu_load}%" ; fi
if [[ -n "${core_clock}" ]]; then tooltip_parts["\n Clock Speed: "]="${core_clock} MHz" ;fi
if [[ -n "${power_usage}" ]]; then if [[ -n "${power_limit}" ]]; then
tooltip_parts["\n󱪉 Power Usage: "]="${power_usage}/${power_limit} W"
else
tooltip_parts["\n󱪉 Power Usage: "]="${power_usage} W"
fi
fi
if [[ -n "${power_discharge}" ]] && [[ "${power_discharge}" != "0" ]]; then tooltip_parts["\n Power Discharge: "]="${power_discharge} W" ;fi
for key in "${!tooltip_parts[@]}"; do
local value="${tooltip_parts[${key}]}"
if [[ -n "${value}" && "${value}" =~ [a-zA-Z0-9] ]]; then
json+="${key}${value}"
fi
done
json="${json}\"}"
echo "${json}"
}
general_query() { # Function to get temperature from 'sensors'
filter=''
temperature=$(sensors | ${filter} grep -m 1 -E "(edge|Package id.*|another keyword)" | awk -F ':' '{print int($2)}') #! We can get json data from sensors too
# gpu_load=$()
# core_clock=$()
for file in /sys/class/power_supply/BAT*/power_now; do
[[ -f "${file}" ]] && power_discharge=$(awk '{print $1*10^-6 ""}' "${file}") && break
done
[[ -z "${power_discharge}" ]] && for file in /sys/class/power_supply/BAT*/current_now; do
[[ -e "${file}" ]] && power_discharge=$(awk -v current="$(cat "${file}")" -v voltage="$(cat "${file/current_now/voltage_now}")" 'BEGIN {print (current * voltage) / 10^12 ""}') && break
done
# power_limit=$()
utilization=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1" "}')
current_clock_speed=$(awk '{sum += $1; n++} END {if (n > 0) print sum / n / 1000 ""}' /sys/devices/system/cpu/cpufreq/policy*/scaling_cur_freq)
max_clock_speed=$(awk '{print $1/1000}' /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq)
}
intel_GPU() { #? Function to query basic intel GPU
primary_gpu="Intel ${intel_gpu}"
general_query
}
nvidia_GPU() { #? Function to query Nvidia GPU
primary_gpu="NVIDIA ${nvidia_gpu}"
if [[ "${nvidia_gpu}" == "Linux" ]]; then general_query ; return ; fi #? Open source driver
#? Tired Flag for not using nvidia-smi if GPU is in suspend mode.
if ${tired}; then is_suspend="$(cat /sys/bus/pci/devices/0000:"${nvidia_address}"/power/runtime_status)"
if [[ ${is_suspend} == *"suspend"* ]]; then
printf '{"text":"󰤂", "tooltip":"%s ⏾ Suspended mode"}' "${primary_gpu}"; exit ;fi
fi
gpu_info=$(nvidia-smi --query-gpu=temperature.gpu,utilization.gpu,clocks.current.graphics,clocks.max.graphics,power.draw,power.limit --format=csv,noheader,nounits)
# Split the comma-separated values into an array
IFS=',' read -ra gpu_data <<< "${gpu_info}"
# Extract individual values
temperature="${gpu_data[0]// /}"
utilization="${gpu_data[1]// /}"
current_clock_speed="${gpu_data[2]// /}"
max_clock_speed="${gpu_data[3]// /}"
power_usage="${gpu_data[4]// /}"
power_limit="${gpu_data[5]// /}"
}
amd_GPU() { #? Function to query amd GPU
primary_gpu="AMD ${amd_gpu}"
# Execute the AMD GPU Python script and use its output
amd_output=$(python3 ${scrDir}/amdgpu.py)
if [[ ! ${amd_output} == *"No AMD GPUs detected."* ]] && [[ ! ${amd_output} == *"Unknown query failure"* ]]; then
# Extract GPU Temperature, GPU Load, GPU Core Clock, and GPU Power Usage from amd_output
temperature=$(echo "${amd_output}" | jq -r '.["GPU Temperature"]' | sed 's/°C//')
gpu_load=$(echo "${amd_output}" | jq -r '.["GPU Load"]' | sed 's/%//')
core_clock=$(echo "${amd_output}" | jq -r '.["GPU Core Clock"]' | sed 's/ GHz//;s/ MHz//')
power_usage=$(echo "${amd_output}" | jq -r '.["GPU Power Usage"]' | sed 's/ Watts//')
else
general_query
fi
}
if [[ ! -f "${gpuQ}" ]]; then
query ; echo -e "Initialized Variable:\n$(cat "${gpuQ}")\n\nReboot or '$0 --reset' to RESET Variables"
fi
source "${gpuQ}"
case "$1" in
"--toggle"|"-t")
toggle
echo -e "Sensor: ${next_prioGPU} GPU" | sed 's/_flag//g'
exit
;;
"--use"|"-u")
toggle "$2"
;;
"--reset"|"-rf")
rm -fr "${gpuQ}"*
query
echo -e "Initialized Variable:\n$(cat "${gpuQ}" || true)\n\nReboot or '$0 --reset' to RESET Variables"
exit
;;
*"-"*)
gpu_flags=$(grep "flag=1" "${gpuQ}" | cut -d '=' -f 1 | tr '\n' ' ' | tr -d '#')
cat << EOF
Available GPU: ${gpu_flags//_flag/}
[options]
--toggle * Toggle available GPU
--use [GPU] * Only call the specified GPU (Useful for adding specific GPU on waybar)
--reset * Remove & restart all query
[flags]
tired * Adding this option will not query nvidia-smi if gpu is in suspend mode
startup * Useful if you want a certain GPU to be set at startup
no_emoji * Use glyphs instead of emoji
* If ${USER} declared env = WLR_DRM_DEVICES on hyprland then use this as the primary GPU
EOF
exit
;;
esac
# Define glyphs
if [[ $NO_EMOJI -eq 1 ]]; then
temp_lv="85:, 65:, 45:☁, ❄"
else
temp_lv="85:🌋, 65:🔥, 45:☁️, ❄️"
fi
util_lv="90:, 60:󰓅, 30:󰾅, 󰾆"
nvidia_flag=${nvidia_flag:-0} intel_flag=${intel_flag:-0} amd_flag=${amd_flag:-0}
#? Based on the flags, call the corresponding function multi flags means multi GPU.
if [[ "${nvidia_flag}" -eq 1 ]]; then
nvidia_GPU
elif [[ "${amd_flag}" -eq 1 ]]; then
amd_GPU
elif [[ "${intel_flag}" -eq 1 ]]; then
intel_GPU
else primary_gpu="Not found"
general_query
fi
generate_json #? AutoGen the Json txt for Waybar

96
scripts/install.sh Normal file
View File

@@ -0,0 +1,96 @@
# #!/usr/bin/env bash
# # install.sh - Setup Cody's Dotfiles Environment (Nix + Home Manager)
#
# set -e
# # Always cd to the parent (repo root) so all operations work from repo base directory
# cd "$(dirname "$0")/.."
#
# # Colors for prettiness
# green='\033[0;32m'
# red='\033[0;31m'
# yellow='\033[1;33m'
# normal='\033[0m'
#
# info() { echo -e "${green}[INFO]${normal} $*"; }
# warn() { echo -e "${yellow}[WARN]${normal} $*"; }
# err() { echo -e "${red}[ERROR]${normal} $*"; }
#
# ## Step 1: Check for Nix
# if ! command -v nix &> /dev/null; then
# err "Nix is not installed! Please install Nix first: https://nixos.org/download.html"
# exit 1
# else
# info "Nix is installed."
# fi
#
# ## Step 2: Enable flakes (if needed)
# if ! nix --experimental-features 'nix-command flakes' flake show &> /dev/null; then
# warn "Nix flakes may not be enabled. Ensure your Nix version supports flakes!"
# info "Try adding experimental-features in /etc/nix/nix.conf or your user config."
# exit 1
# else
# info "Nix flakes are working."
# fi
#
# ## Step 3: Home Manager presence (not mandatory but recommended)
# if ! nix flake show | grep -q 'homeConfigurations'; then
# warn "Home Manager config not detected in flake output. Ensure it's declared if you want full integration."
# fi
#
# ## Step 4: Detect host
# HOST="$(hostname)"
#
# # Step 4a: Ensure hosts/ exists
# if [[ ! -d hosts ]]; then
# warn "No hosts/ directory detected. Creating one."
# mkdir hosts
# info "Created hosts/ directory."
# fi
#
# # Step 4b: Prompt for host if needed; create scaffold if host missing
# if [[ ! -d "hosts/$HOST" ]]; then
# warn "No host config found for '$HOST' in hosts/."
# ls -1 hosts/ || info "No hosts configured yet."
# read -rp "Enter the host name you want to use (type exactly): " HOST
# if [[ ! -d "hosts/$HOST" ]]; then
# info "Scaffolding minimal host config in hosts/$HOST ..."
# mkdir -p "hosts/$HOST"
# # Make home.nix
# cat > "hosts/$HOST/home.nix" << EOF
# { config, pkgs, ... }:
# {
# home.username = "$USER";
# home.homeDirectory = "/home/$USER";
# programs.zsh.enable = true;
# home.stateVersion = "24.05";
# }
# EOF
# # Make configuration.nix
# cat > "hosts/$HOST/configuration.nix" << EOF
# { config, pkgs, ... }:
# {
# imports = [ ];
# networking.hostName = "$HOST";
# system.stateVersion = "24.05";
# }
# EOF
# info "Scaffolded hosts/$HOST/home.nix and configuration.nix."
# warn "You MUST now add this new host to your flake.nix under nixosConfigurations and/or homeConfigurations."
# info "See hosts/$HOST/home.nix and configuration.nix for templates."
# fi
# fi
# info "Using host: $HOST"
#
# ## Step 5: Run Home Manager activation
# info "Applying Nix Flake config using Home Manager..."
# nix run .#homeConfigurations."$HOST".activationPackage
#
# ## Step 6: Symlink basic shell dotfiles (optional)
# info "Symlinking .p10k.zsh (Powerlevel10k config)..."
# ln -sf "$PWD/.p10k.zsh" "$HOME/.p10k.zsh"
#
# info "Install complete!"
# echo -e "${green}Dotfiles and system config applied for $HOST. You may wish to relogin, or reload your shell, or review configs now.${normal}"
#
# exit 0

418
scripts/keybinds_hint.sh Executable file
View File

@@ -0,0 +1,418 @@
#!/usr/bin/env sh
#* jq to parse and create a metadata.
#* Users are advised to use bindd to explicitly add the description
#* Please inform us if there are new Categories upstream will try to add comments to this script
#* Khing 🦆
pkill -x rofi && exit
scrDir=$(dirname "$(realpath "$0")")
source "$scrDir/globalcontrol.sh"
confDir="${XDG_CONFIG_HOME:-$HOME/.config}"
keyconfDir="$confDir/hypr"
kb_hint_conf=("$keyconfDir/hyprland.conf" "$keyconfDir/keybindings.conf" "$keyconfDir/userprefs.conf" )
tmpMapDir="/tmp"
tmpMap="$tmpMapDir/hyde-keybinds.jq"
keycodeFile="${hydeConfDir}/keycode.kb"
modmaskFile="${hydeConfDir}/modmask.kb"
keyFile="${hydeConfDir}/key.kb"
categoryFile="${hydeConfDir}/category.kb"
dispatcherFile="${hydeConfDir}/dispatcher.kb"
roDir="$confDir/rofi"
roconf="$HOME/.config/rofi/user.rasi"
HELP() {
cat <<HELP
Usage: $(basename "$0") [options]
Options:
-j Show the JSON format
-p Show the pretty format
-d Add custom delimiter symbol (default '>')
-f Add custom file
-w Custom width
-h Custom height
--help Display this help message
Example:
$(basename "$0") -j -p -d '>' -f custom_file.txt -w 80 -h 90"
Users can also add a global overrides inside ${hydeConfDir}/hyde.conf
Available overrides:
kb_hint_delim=">" ﯦ add a custom custom delimiter
kb_hint_conf=("file1.conf" "file2.conf") ﯦ add a custom keybinds.conf path (add it like an array)
kb_hint_width="30em" ﯦ custom width supports [ 'em' '%' 'px' ]
kb_hint_height="35em" ﯦ custom height supports [ 'em' '%' 'px' ]
kb_hint_line=13 ﯦ adjust how many lines are listed
Users can also add a key overrides inside ${hydeConfDir}
List of file override:
${keycodeFile} => keycode
${modmaskFile} => modmask
${keyFile} => keys
${categoryFile} => category
${dispatcherFile} => dispatcher
Example for keycode override
create a file named $keycodeFile and use the following format:
"number": "display name/symbol",
"61": "/",
HELP
}
while [ "$#" -gt 0 ]; do
case "$1" in
-j) # show the json format
kb_hint_json=true
;;
-p) # show the pretty format
kb_hint_pretty=true
;;
-d) # Add custom delimiter symbol default '>'
shift
kb_hint_delim="$1"
;;
-f) # Add custom file
shift
kb_hint_conf+=("${@}")
;;
-w) # Custom kb_hint_width
shift
kb_hint_width="$1"
;;
-h) # Custom height
shift
kb_hint_height="$1"
;;
-l) # Custom number of line
shift
kb_hint_line="$1"
;;
-*) # Add Help message
HELP
exit
;;
esac
shift
done
#? Read all the variables in the configuration file
#! Intentional globbing on the $keyconf variable
# shellcheck disable=SC2086
keyVars="$(awk -F '=' '/^ *\$/ && !/^ *#[^#]/ || /^ *##/ {gsub(/^ *\$| *$/, "", $1); gsub(/#.*/, "", $2); gsub(/^ *| *$/, "", $2); print $1 "='\''"$2"'\''"}' ${kb_hint_conf[@]})"
keyVars+="
"
keyVars+="HOME=$HOME"
# echo "$keyVars"
#? This part substitutes the variables into the actual value.
#TODO It will be easier if hyprland will expose the variables.
substitute_vars() {
local s="$1"
local IFS=$'\n'
for var in $keyVars; do
varName="${var%%=*}"
varValue="${var#*=}"
varValue="${varValue#\'}"
varValue="${varValue%\'}"
s="${s//\$$varName/$varValue}"
done
IFS=$' \t\n'
echo "$s"
}
#? Other accurate but risky option
# eval "$keyVars"
# substitute_vars() {
# local s="$1"
# local IFS=$'\n'
# for var in $keyVars; do
# varName="${var%%=*}"
# s="${s//\$$varName/${!varName}}"
# done
# IFS=$' \t\n'
# echo "$s"
# }
initialized_comments=$(awk -F ',' '!/^#/ && /bind*/ && $3 ~ /exec/ && NF && $4 !~ /^ *$/ { print $4}' ${kb_hint_conf[@]} | sed "s#\"#'#g")
comments=$(substitute_vars "$initialized_comments" | awk -F'#' \
'{gsub(/^ */, "", $1);\
gsub(/ *$/, "", $1);\
split($2, a, " ");\
a[1] = toupper(substr(a[1], 1, 1)) substr(a[1], 2);\
$2 = a[1]; for(i=2;\
i<=length(a); i++) $2 = $2" "a[i];\
gsub(/^ */, "", $2);\
gsub(/ *$/, "", $2);\
if (length($1) > 0) print "\""$1"\" : \""(length($2) > 0 ? $2 : $1)"\","}' |
awk '!seen[$0]++')
# echo "$comments"
cat <<OVERRIDES >$tmpMap
# hyde-keybinds.jq
#! This is Our Translator for some binds #🦆
def executables_mapping: { #? Derived from .args to parse scripts to be Readable
#? Auto Generated Comment Conversion
$comments
#? Defaults
" empty " : "Empty",
"r+1" : "Relative Right",
"r-1" : "Relative Left",
"e+1" : "Next",
"e-1" : "Previous",
"movewindow" : "Move window",
"resizewindow" : "Resize window",
"d" : "Down",
"l" : "Left",
"r" : "Right",
"u" : "Up",
"f" : "Forward",
"b" : "Backward",
};
def keycode_mapping: { #? Fetches keycode from a file
"0": "",
$([ -f "${keycodeFile}" ] && cat "${keycodeFile}")
};
def modmask_mapping: { #? Define mapping for modmask numbers represents bitmask
"64": " ", #? SUPER  󰻀 Also added 2 En space ' ' <<<
"8": "ALT",
"4": "CTRL",
"1": "SHIFT",
"0": " ",
$([ -f "${modmaskFile}" ] && cat "${modmaskFile}")
};
def key_mapping: { #?Define mappings for .keys to be readable symbols
"mouse_up" : "󱕑",
"mouse_down" : "󱕐",
"mouse:272" : "󰍽",
"mouse:273" : "󰍽",
"UP" : "",
"DOWN" : "",
"LEFT" : "",
"RIGHT" : "",
"XF86AudioLowerVolume" : "󰝞",
"XF86AudioMicMute" : "󰍭",
"XF86AudioMute" : "󰓄",
"XF86AudioNext" : "󰒭",
"XF86AudioPause" : "󰏤",
"XF86AudioPlay" : "󰐊",
"XF86AudioPrev" : "󰒮",
"XF86AudioRaiseVolume" : "󰝝",
"XF86MonBrightnessDown" : "󰃜",
"XF86MonBrightnessUp" : "󰃠",
"switch:on:Lid Switch" : "󰛧",
"backspace" : "󰁮 ",
$([ -f "${keyFile}" ] && cat "${keyFile}")
};
def category_mapping: { #? Define Category Names, derive from Dispatcher #? This will serve as the Group header
"exec" : "Execute a Command:",
"global": "Global:",
"exit" : "Exit Hyprland Session",
"fullscreen" : "Toggle Functions",
"fakefullscreen" : "Toggle Functions",
"mouse" : "Mouse functions",
"movefocus" : "Window functions",
"movewindow" : "Window functions",
"resizeactive" : "Window functions",
"togglefloating" : "Toggle Functions",
"togglegroup" : "Toggle Functions",
"togglespecialworkspace" : "Toggle Functions",
"togglesplit" : "Toggle Functions",
"workspace" : "Navigate Workspace",
"movetoworkspace" : "Navigate Workspace",
"movetoworkspacesilent" : "Navigate Workspace",
"changegroupactive" : "Change Active Group",
$([ -f "${categoryFile}" ] && cat "${categoryFile}")
};
def arg_mapping: { #! Do not Change this used for Demo only... As this will change .args! will be fatal
"arg2": "mapped_arg2",
};
def description_mapping: { #? Derived from dispatcher and Gives Description for Dispatchers; Basically translates dispatcher.
"movefocus": "Move Focus",
"resizeactive": "Resize Active Floating Window",
"exit" : "End Hyprland Session",
"movetoworkspacesilent" : "Silently Move to Workspace",
"movewindow" : "Move Window",
"exec" : "" , #? Remove exec as executable will give the Description from separate function
"movetoworkspace" : "Move To Workspace:",
"workspace" : "Navigate to Workspace:",
"togglefloating" : "Toggle Floating",
"fullscreen" : "Toggle Fullscreen",
"togglegroup" : "Toggle Group",
"togglesplit" : "Toggle Split",
"togglespecialworkspace" : "Toggle Special Workspace",
"mouse" : "Use Mouse",
"changegroupactive" : "Switch Active group",
$([ -f "${dispatcherFile}" ] && cat "${dispatcherFile}")
};
OVERRIDES
#? Script to re Modify hyprctl json output
#? Basically we are using jq to handle json data and outputs a pretty and friendly output
jsonData="$(
hyprctl binds -j | jq -L "$tmpMapDir" -c '
include "hyde-keybinds";
#? Functions to Convert modmask into Keys, There should be a better math for this but Im lazy
#? Also we can just map it manually too
def get_keys:
if . == 0 then
""
elif . >= 64 then
. -= 64 | modmask_mapping["64"] + " " + get_keys
elif . >= 32 then
. -= 32 | modmask_mapping["32"] + " " + get_keys
elif . >= 16 then
. -= 16 | modmask_mapping["16"] + " " + get_keys
elif . >= 8 then
. -= 8 | modmask_mapping["8"] + " " + get_keys
elif . >= 4 then
. -= 4 | modmask_mapping["4"] + " " + get_keys
elif . >= 2 then
. -= 2 | modmask_mapping["2"] + " " + get_keys
elif . >= 1 then
. -= 1 | modmask_mapping["1"] + " " + get_keys
else
.
end;
def get_keycode:
(keycode_mapping[(. | tostring)] // .); #? use the keycode conversion... and turn to string
.[] | #? Filter 1
.dispatcher as $dispatcher | .desc_dispatcher = $dispatcher | #? Value conversions for the description
.dispatcher as $dispatcher | .category = $dispatcher | #? Value conversions for the category
.arg as $arg | .desc_executable = $arg | #? creates new key .desc_executable to be use later
.modmask |= (get_keys | ltrimstr(" ")) | #? Execute Momask conversions, b
.keycode |= (get_keycode // .) | #? Apply the get_keycode transformation
.key |= (key_mapping[.] // .) | #? Apply the get_key
# .keybind = (.modmask | tostring // "") + (.key // "") | #! Same as below but without the keycode
.keybind = (.modmask | tostring // "") + (.key // "") + ((.keycode // 0) | tostring) | #? Show the keybindings
.flags = " locked=" + (.locked | tostring) + " mouse=" + (.mouse | tostring) + " release=" + (.release | tostring) + " repeat=" + (.repeat | tostring) + " non_consuming=" + (.non_consuming | tostring) | #? This are the flags repeat,lock etc
.category |= (category_mapping[.] // .) | #? Group by Categories will be use for headers
#!if .modmask and .modmask != " " and .modmask != "" then .modmask |= (split(" ") | map(select(length > 0)) | if length > 1 then join(" + ") else .[0] end) else .modmask = "" end |
if .keybind and .keybind != " " and .keybind != "" then .keybind |= (split(" ") | map(select(length > 0)) | if length > 1 then join(" + ") else .[0] end) else .keybind = "" end | #? Clean up
.arg |= (arg_mapping[.] // .) | #? See above for how arg is converted
#! .desc_executable |= gsub(".sh"; "") | #? Maybe Useful soon removes ".sh" to file
#? Creates a key desc... for fallback if "has description" is false
.desc_executable |= (executables_mapping[.] // .) | #? exclusive for "exec" dispatchers
.desc_dispatcher |= (description_mapping[.] // .) | #? for all other dispatchers
.description = if .has_description == false then "\(.desc_dispatcher) \(.desc_executable)" else.description end
' #* <---- There is a ' do not delete this'
)"
#? Now we have the metadata we can Group it accordingly
GROUP() {
awk -v cols="$cols" -F '!=!' '
{
category = $1
binds[category] = binds[category]? binds[category] "\n" $0 : $0
}
END {
n = asorti(binds, b)
for (i = 1; i <= n; i++) {
print b[i] # Print the header name
gsub(/\[.*\] =/, "", b[i])
split(binds[b[i]], lines, "\n")
for (j in lines) {
line = substr(lines[j], index(lines[j], "=") + 2)
print line
}
for (j = 1; j <= cols; j++) printf "━"
printf "\n"
}
}'
}
#? Display the JSON format
[ "$kb_hint_json" = true ] && jq <<< "$jsonData" && exit 0
#? Format this is how the keybinds are displayed.
DISPLAY() { awk -v kb_hint_delim="${kb_hint_delim:->}" -F '!=!' '{if ($0 ~ /=/ && $6 != "") printf "%-25s %-2s %-30s\n", $5, kb_hint_delim, $6; else if ($0 ~ /=/) printf "%-25s\n", $5; else print $0}'; }
#? Extra design use for distinction
header="$(printf "%-35s %-1s %-20s\n" "󰌌 Keybinds" "󱧣" "Description")"
cols=$(tput cols)
cols=${cols:-999}
linebreak="$(printf '%.0s━' $(seq 1 "${cols}") "")"
#! this Part Gives extra loading time as I don't have efforts to make single space for each class
metaData="$(jq -r '"\(.category) !=! \(.modmask) !=! \(.key) !=! \(.dispatcher) !=! \(.arg) !=! \(.keybind) !=! \(.description) !=! \(.flags)"' <<< "${jsonData}" | tr -s ' ' | sort -k 1)"
#? This formats the pretty output
display="$(GROUP <<< "$metaData" | DISPLAY)"
# output=$(echo -e "${header}\n${linebreak}\n${primMenu}\n${linebreak}\n${display}")
output=$(echo -e "${header}\n${linebreak}\n${display}")
[ "$kb_hint_pretty" = true ] && echo -e "$output" && exit 0
#? will display on the terminal if rofi is not found or have -j flag
if ! command -v rofi &>/dev/null; then
echo "$output"
echo "rofi not detected. Displaying on terminal instead"
exit 0
fi
#? Put rofi configuration here
# Read hypr theme border
wind_border=$((hypr_border * 3 / 2))
elem_border=$([ "$hypr_border" -eq 0 ] && echo "5" || echo "$hypr_border")
# TODO Dynamic scaling for text and the window >>> I do not know if rofi is capable of this
r_width="width: ${kb_hint_width:-35em};"
r_height="height: ${kb_hint_height:-35em};"
r_listview="listview { lines: ${kb_hint_line:-13}; }"
r_override="window {$r_height $r_width border: ${hypr_width}px; border-radius: ${wind_border}px;} entry {border-radius: ${elem_border}px;} element {border-radius: ${elem_border}px;} ${r_listview} "
# Read hypr font size
fnt_override=$(gsettings get org.gnome.desktop.interface font-name | awk '{gsub(/'\''/,""); print $NF}')
fnt_override="configuration {font: \"JetBrainsMono Nerd Font ${fnt_override}\";}"
# Read hypr theme icon
icon_override=$(gsettings get org.gnome.desktop.interface icon-theme | sed "s/'//g")
icon_override="configuration {icon-theme: \"${icon_override}\";}"
#? Actions to do when selected
selected=$(echo "$output" | rofi -dmenu -p -i -theme-str "${fnt_override}" -theme-str "${r_override}" -theme-str "${icon_override}" -config "${roconf}" | sed 's/.*\s*//')
if [ -z "$selected" ]; then exit 0; fi
sel_1=$(awk -F "${kb_hint_delim:->}" '{print $1}' <<< "$selected" | awk '{$1=$1};1')
sel_2=$(awk -F "${kb_hint_delim:->}" '{print $2}' <<< "$selected" | awk '{$1=$1};1')
run="$(grep "$sel_1" <<< "$metaData" | grep "$sel_2")"
run_flg="$(echo "$run" | awk -F '!=!' '{print $8}')"
run_sel="$(echo "$run" | awk -F '!=!' '{gsub(/^ *| *$/, "", $5); if ($5 ~ /[[:space:]]/ && $5 !~ /^[0-9]+$/ && substr($5, 1, 1) != "-") print $4, "\""$5"\""; else print $4, $5}')"
# echo "$run_sel" ; echo "$run_flg"
#?
RUN() { case "$(eval "hyprctl dispatch $run_sel")" in *"Not enough arguments"*) exec $0 ;; esac }
#? If flag is repeat then repeat rofi if not then just execute once
if [ -n "$run_sel" ] && [ "$(echo "$run_sel" | wc -l)" -eq 1 ]; then
eval "$run_flg"
if [ "$repeat" = true ]; then
while true; do
repeat_command=$(echo -e "Repeat" | rofi -dmenu -no-custom -p "[Enter] repeat; [ESC] exit") #? Needed a separate Rasi ? Dunno how to make; Maybe Something like confirmation rasi for buttons Yes and No then the -p will be the Question like Proceed? Repeat?
if [ "$repeat_command" = "Repeat" ]; then
# Repeat the command here
RUN
else
exit 0
fi
done
else
RUN
fi
else
exec $0
fi

10
scripts/keyboardswitch.sh Executable file
View File

@@ -0,0 +1,10 @@
#!/usr/bin/env sh
scrDir=`dirname "$(realpath "$0")"`
source $scrDir/globalcontrol.sh
hyprctl switchxkblayout all next
layMain=$(hyprctl -j devices | jq '.keyboards' | jq '.[] | select (.main == true)' | awk -F '"' '{if ($2=="active_keymap") print $4}')
notify-send -a "t1" -r 91190 -t 800 -i "~/.config/dunst/icons/keyboard.svg" "${layMain}"

35
scripts/launch-vm.sh Normal file
View File

@@ -0,0 +1,35 @@
#!/usr/bin/env bash
ISO_URL="https://blackarch.org/blackarch-linux-live-2023.12.01-x86_64.iso"
ISO_PATH="$HOME/blackarch.iso"
VM_DISK="$HOME/blackarch.qcow2"
# Ensure required binaries are available
nix shell nixpkgs#qemu nixpkgs#wget -c bash <<EOF
# Check if ISO exists, if not, download it
if [ ! -f "$ISO_PATH" ]; then
echo "Downloading BlackArch ISO..."
wget -O "$ISO_PATH" "$ISO_URL"
fi
# Create VM disk if it doesn’t exist
if [ ! -f "$VM_DISK" ]; then
echo "Creating BlackArch VM disk..."
qemu-img create -f qcow2 "$VM_DISK" 50G
fi
echo "Launching BlackArch VM..."
qemu-system-x86_64 \
-enable-kvm \
-m 4096 \
-smp 4 \
-cpu host \
-drive file="$VM_DISK",format=qcow2 \
-cdrom "$ISO_PATH" \
-boot d \
-netdev user,id=net0 -device e1000,netdev=net0 \
-display default,show-cursor=on
EOF

85
scripts/logoutlaunch.sh Executable file
View File

@@ -0,0 +1,85 @@
#!/usr/bin/env sh
#// Check if wlogout is already running
if pgrep -x "wlogout" > /dev/null
then
pkill -x "wlogout"
exit 0
fi
#// set file variables
scrDir=`dirname "$(realpath "$0")"`
source $scrDir/globalcontrol.sh
[ -z "${1}" ] || wlogoutStyle="${1}"
wLayout="${confDir}/wlogout/layout_${wlogoutStyle}"
wlTmplt="${confDir}/wlogout/style_${wlogoutStyle}.css"
if [ ! -f "${wLayout}" ] || [ ! -f "${wlTmplt}" ] ; then
echo "ERROR: Config ${wlogoutStyle} not found..."
wlogoutStyle=1
wLayout="${confDir}/wlogout/layout_${wlogoutStyle}"
wlTmplt="${confDir}/wlogout/style_${wlogoutStyle}.css"
fi
#// detect monitor res
x_mon=$(hyprctl -j monitors | jq '.[] | select(.focused==true) | .width')
y_mon=$(hyprctl -j monitors | jq '.[] | select(.focused==true) | .height')
hypr_scale=$(hyprctl -j monitors | jq '.[] | select (.focused == true) | .scale' | sed 's/\.//')
#// scale config layout and style
case "${wlogoutStyle}" in
1) wlColms=6
export mgn=$(( y_mon * 28 / hypr_scale ))
export hvr=$(( y_mon * 23 / hypr_scale )) ;;
2) wlColms=2
export x_mgn=$(( x_mon * 35 / hypr_scale ))
export y_mgn=$(( y_mon * 25 / hypr_scale ))
export x_hvr=$(( x_mon * 32 / hypr_scale ))
export y_hvr=$(( y_mon * 20 / hypr_scale )) ;;
esac
#// scale font size
export fntSize=$(( y_mon * 2 / 100 ))
#// detect wallpaper brightness
[ -f "${cacheDir}/wall.dcol" ] && source "${cacheDir}/wall.dcol"
# Theme mode: detects the color-scheme set in hypr.theme and falls back if nothing is parsed.
if [ "${enableWallDcol}" -eq 0 ]; then
colorScheme="$({ grep -q "^[[:space:]]*\$COLOR[-_]SCHEME\s*=" "${hydeThemeDir}/hypr.theme" && grep "^[[:space:]]*\$COLOR[-_]SCHEME\s*=" "${hydeThemeDir}/hypr.theme" | cut -d '=' -f2 | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' ;} ||
grep 'gsettings set org.gnome.desktop.interface color-scheme' "${hydeThemeDir}/hypr.theme" | awk -F "'" '{print $((NF - 1))}')"
colorScheme=${colorScheme:-$(gsettings get org.gnome.desktop.interface color-scheme)}
# should be declared explicitly so we can easily debug
grep -q "dark" <<< "${colorScheme}" && dcol_mode="dark"
grep -q "light" <<< "${colorScheme}" && dcol_mode="light"
[ -f "${hydeThemeDir}/theme.dcol" ] && source "${hydeThemeDir}/theme.dcol"
fi
[ "${dcol_mode}" == "dark" ] && export BtnCol="white" || export BtnCol="black"
#// eval hypr border radius
export active_rad=$(( hypr_border * 5 ))
export button_rad=$(( hypr_border * 8 ))
#// eval config files
wlStyle="$(envsubst < $wlTmplt)"
#// launch wlogout
wlogout -b "${wlColms}" -c 0 -r 0 -m 0 --layout "${wLayout}" --css <(echo "${wlStyle}") --protocol layer-shell

183
scripts/mediaplayer.py Executable file
View File

@@ -0,0 +1,183 @@
#!/usr/bin/env python3
import gi
gi.require_version("Playerctl", "2.0")
from gi.repository import Playerctl, GLib
from gi.repository.Playerctl import Player
import argparse
import logging
import sys
import signal
import gi
import json
import os
from typing import List
logger = logging.getLogger(__name__)
def signal_handler(sig, frame):
logger.info("Received signal to stop, exiting")
sys.stdout.write("\n")
sys.stdout.flush()
# loop.quit()
sys.exit(0)
class PlayerManager:
def __init__(self, selected_player=None):
self.manager = Playerctl.PlayerManager()
self.loop = GLib.MainLoop()
self.manager.connect(
"name-appeared", lambda *args: self.on_player_appeared(*args))
self.manager.connect(
"player-vanished", lambda *args: self.on_player_vanished(*args))
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
self.selected_player = selected_player
self.init_players()
def init_players(self):
for player in self.manager.props.player_names:
if self.selected_player is not None and self.selected_player != player.name:
logger.debug(f"{player.name} is not the filtered player, skipping it")
continue
self.init_player(player)
def run(self):
logger.info("Starting main loop")
self.loop.run()
def init_player(self, player):
logger.info(f"Initialize new player: {player.name}")
player = Playerctl.Player.new_from_name(player)
player.connect("playback-status",
self.on_playback_status_changed, None)
player.connect("metadata", self.on_metadata_changed, None)
self.manager.manage_player(player)
self.on_metadata_changed(player, player.props.metadata)
def get_players(self) -> List[Player]:
return self.manager.props.players
def write_output(self, text, player, tooltip):
logger.debug(f"Writing output: {text}")
output = {"text": text,
"class": "custom-" + player.props.player_name,
"alt": player.props.player_name,
"tooltip": tooltip}
sys.stdout.write(json.dumps(output) + "\n")
sys.stdout.flush()
def clear_output(self):
sys.stdout.write("\n")
sys.stdout.flush()
def on_playback_status_changed(self, player, status, _=None):
logger.debug(f"Playback status changed for player {player.props.player_name}: {status}")
self.on_metadata_changed(player, player.props.metadata)
def get_first_playing_player(self):
players = self.get_players()
logger.debug(f"Getting first playing player from {len(players)} players")
if len(players) > 0:
# if any are playing, show the first one that is playing
# reverse order, so that the most recently added ones are preferred
for player in players[::-1]:
if player.props.status == "Playing":
return player
# if none are playing, show the first one
return players[0]
else:
logger.debug("No players found")
return None
def show_most_important_player(self):
logger.debug("Showing most important player")
# show the currently playing player
# or else show the first paused player
# or else show nothing
current_player = self.get_first_playing_player()
if current_player is not None:
self.on_metadata_changed(current_player, current_player.props.metadata)
else:
self.clear_output()
def on_metadata_changed(self, player, metadata, _=None):
logger.debug(f"Metadata changed for player {player.props.player_name}")
player_name = player.props.player_name
artist = player.get_artist()
title = player.get_title()
track_info = ""
if player_name == "spotify" and "mpris:trackid" in metadata.keys() and ":ad:" in player.props.metadata["mpris:trackid"]:
track_info = "Advertisement"
elif artist is not None and title is not None:
track_info = f"{artist} - {title}"
else:
track_info = title
tooltip = track_info
if track_info:
if player.props.status == "Playing":
track_info = "" + track_info
else:
track_info = "" + track_info
# only print output if no other player is playing
current_playing = self.get_first_playing_player()
if current_playing is None or current_playing.props.player_name == player.props.player_name:
self.write_output(track_info, player, tooltip)
else:
logger.debug(f"Other player {current_playing.props.player_name} is playing, skipping")
def on_player_appeared(self, _, player):
logger.info(f"Player has appeared: {player.name}")
if player is not None and (self.selected_player is None or player.name == self.selected_player):
self.init_player(player)
else:
logger.debug(
"New player appeared, but it's not the selected player, skipping")
def on_player_vanished(self, _, player):
logger.info(f"Player {player.props.player_name} has vanished")
self.show_most_important_player()
def parse_arguments():
parser = argparse.ArgumentParser()
# Increase verbosity with every occurrence of -v
parser.add_argument("-v", "--verbose", action="count", default=0)
# Define for which player we"re listening
parser.add_argument("--player")
parser.add_argument("--enable-logging", action="store_true")
return parser.parse_args()
def main():
arguments = parse_arguments()
# Initialize logging
if arguments.enable_logging:
logfile = os.path.join(os.path.dirname(
os.path.realpath(__file__)), "media-player.log")
logging.basicConfig(filename=logfile, level=logging.DEBUG,
format="%(asctime)s %(name)s %(levelname)s:%(lineno)d %(message)s")
# Logging is set by default to WARN and higher.
# With every occurrence of -v it's lowered by one
logger.setLevel(max((3 - arguments.verbose) * 10, 0))
logger.info("Creating player manager")
if arguments.player:
logger.info(f"Filtering for player: {arguments.player}")
player = PlayerManager(arguments.player)
player.run()
if __name__ == "__main__":
main()

57
scripts/move-floating.sh Normal file
View File

@@ -0,0 +1,57 @@
# #!/usr/bin/env bash
#
# # Move floating window or fallback to tiling move
# direction=$1
# amount=${2:-10}
#
# # normalize direction to the single-letter hyprctl form
# case "${direction,,}" in
# left|l) dir=l ;;
# right|r) dir=r ;;
# up|u|top|t) dir=u ;;
# down|d|bottom|b) dir=d ;;
# *)
# echo "Usage: move-floating.sh <left|right|up|down|l|r|u|d> [amount]"
# exit 1
# ;;
# esac
#
# # ensure dependencies
# if ! command -v hyprctl >/dev/null 2>&1; then
# echo "hyprctl not found in PATH" >&2
# exit 1
# fi
# if ! command -v jq >/dev/null 2>&1; then
# echo "jq not found in PATH" >&2
# exit 1
# fi
#
# if hyprctl activewindow -j | jq -r .floating | grep -q true; then
# hyprctl dispatch moveactive "$dir" "$amount"
# else
# hyprctl dispatch movewindow "$dir"
# fi
#
#!/usr/bin/env sh
# move_floating.sh
STEP=50
case "$1" in
l)
hyprctl dispatch moveactive -50 0
;;
r)
hyprctl dispatch moveactive 50 0
;;
u)
hyprctl dispatch moveactive 0 -50
;;
d)
hyprctl dispatch moveactive 0 50
;;
*)
echo "Usage: $0 {left|right|up|down}"
exit 1
;;
esac

55
scripts/notifications.py Executable file
View File

@@ -0,0 +1,55 @@
#!/usr/bin/python3
import subprocess
import json
import sys
def get_dunst_history():
result = subprocess.run(['dunstctl', 'history'], stdout=subprocess.PIPE)
history = json.loads(result.stdout.decode('utf-8'))
return history
def format_history(history):
count = len(history['data'][0])
alt = 'none'
tooltip_click = []
tooltip_click.append("󰎟 Notifications")
tooltip_click.append("󰳽 scroll-down:  history pop")
tooltip_click.append("󰳽 click-left:  Enable & Disable DND")
tooltip_click.append("󰳽 click-middle: 󰛌 clear history")
tooltip_click.append("󰳽 click-right: 󱄊 close all")
tooltip = []
if count > 0:
notifications = history['data'][0][:10] # Get the first 10 notifications
for notification in notifications:
body = notification.get('body', {}).get('data', '')
category = notification.get('category', {}).get('data', '')
if category:
alt = category + '-notification'
tooltip.append(f"{body} ({category})\n")
else:
alt = 'notification'
tooltip.append(f"{body}\n")
isDND = subprocess.run(['dunstctl', 'get-pause-level'], stdout=subprocess.PIPE)
isDND = isDND.stdout.decode('utf-8').strip()
if isDND != '0':
alt = "dnd"
formatted_history = {
"text": str(count),
"alt": alt,
"tooltip": '\n '.join(tooltip_click) + '\n\n ' + '\n '.join(tooltip),
"class": alt
}
return formatted_history
def main():
history = get_dunst_history()
formatted_history = format_history(history)
sys.stdout.write(json.dumps(formatted_history) + '\n')
sys.stdout.flush()
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,85 @@
#!/usr/bin/env bash
# Open Google Calendar as a floating web app window using Firefox
# Check if Firefox is already running with the calendar
EXISTING=$(pgrep -f "firefox.*calendar.google.com" | head -1)
if [ ! -z "$EXISTING" ]; then
# Focus the existing window instead
WINDOW_ADDRESS=$(hyprctl clients -j | jq -r ".[] | select(.pid == $EXISTING) | .address" | head -1)
if [ ! -z "$WINDOW_ADDRESS" ]; then
hyprctl dispatch focuswindow "address:$WINDOW_ADDRESS"
fi
exit 0
fi
# Create a dedicated Firefox profile for calendar app
PROFILE_DIR="$HOME/.mozilla/firefox/calendar-app"
if [ ! -d "$PROFILE_DIR" ]; then
mkdir -p "$PROFILE_DIR/chrome"
# Create user.js to customize Firefox UI
cat > "$PROFILE_DIR/user.js" << 'EOF'
// Hide Firefox UI elements
user_pref("browser.chrome.toolbar_tips", false);
user_pref("browser.tabs.drawInTitlebar", true);
user_pref("browser.tabs.tabmanager.enabled", false);
user_pref("browser.uidensity", 2);
// Disable notifications and other UI clutter
user_pref("extensions.activeThemeID", "firefox-compact-dark@mozilla.org");
user_pref("browser.startup.homepage_override.mstone", "ignore");
// Hide various UI elements
user_pref("toolkit.legacyUserProfileCustomizations.stylesheets", true);
EOF
# Create userChrome.css to hide the toolbar and tabs
cat > "$PROFILE_DIR/chrome/userChrome.css" << 'EOF'
/* Hide the entire toolbar area */
#navigator-toolbox {
display: none !important;
}
/* Hide tabs bar */
#TabsToolbar {
display: none !important;
}
/* Hide sidebar button */
#sidebar-button {
display: none !important;
}
/* Make content fill the window */
#content {
margin: 0 !important;
}
EOF
fi
# Open Firefox with the dedicated profile in a new window
firefox --new-instance --profile "$PROFILE_DIR" "https://calendar.google.com" &
FIREFOX_PID=$!
# Wait for window to open
sleep 1.5
# Get the window address
WINDOW_ADDRESS=$(hyprctl clients -j | jq -r ".[] | select(.pid == $FIREFOX_PID) | .address" | head -1)
if [ ! -z "$WINDOW_ADDRESS" ]; then
# Make it floating
hyprctl dispatch togglefloating "address:$WINDOW_ADDRESS"
# Resize to a smaller window size (900x700)
hyprctl dispatch resizewindowpixel "exact 900 700" "address:$WINDOW_ADDRESS"
# Center it on screen
hyprctl dispatch centerwindow "address:$WINDOW_ADDRESS"
# Collapse sidebar - press 'm' to toggle sidebar in Google Calendar
(
sleep 2
xdotool search --name "calendar" key "m" 2>/dev/null || true
) &
fi

10
scripts/polkitkdeauth.sh Executable file
View File

@@ -0,0 +1,10 @@
#!/usr/bin/env sh
# Use different directory on NixOS
if [ -d /run/current-system/sw/libexec ]; then
libDir=/run/current-system/sw/libexec
else
libDir=/usr/lib
fi
${libDir}/polkit-gnome/polkit-gnome-authentication-agent-1 &

77
scripts/quickapps.sh Executable file
View File

@@ -0,0 +1,77 @@
#!/usr/bin/env bash
# set variables
scrDir=`dirname "$(realpath "$0")"`
source $scrDir/globalcontrol.sh
roconf="~/.config/rofi/quickapps.rasi"
if [ $# -eq 0 ] ; then
echo "usage: ./quickapps.sh <app1> <app2> ... <app[n]>"
exit 1
else
appCount="$#"
fi
# set position
x_mon=$( cat /sys/class/drm/*/modes | head -1 )
y_mon=$( echo $x_mon | cut -d 'x' -f 2 )
x_mon=$( echo $x_mon | cut -d 'x' -f 1 )
x_cur=$(hyprctl cursorpos | sed 's/ //g')
y_cur=$( echo $x_cur | cut -d ',' -f 2 )
x_cur=$( echo $x_cur | cut -d ',' -f 1 )
if [ ${x_cur} -le $(( x_mon/3 )) ] ; then
x_rofi="west"
x_offset="x-offset: 20px;"
elif [ ${x_cur} -ge $(( x_mon/3*2 )) ] ; then
x_rofi="east"
x_offset="x-offset: -20px;"
else
unset x_rofi
fi
if [ ${y_cur} -le $(( y_mon/3 )) ] ; then
y_rofi="north"
y_offset="y-offset: 20px;"
elif [ ${y_cur} -ge $(( y_mon/3*2 )) ] ; then
y_rofi="south"
y_offset="y-offset: -20px;"
else
unset y_rofi
fi
if [ ! -z $x_rofi ] || [ ! -z $y_rofi ] ; then
pos="window {location: $y_rofi $x_rofi; $x_offset $y_offset}"
fi
# override rofi
dockHeight=$(( x_mon * 3 / 100))
dockWidth=$(( dockHeight * appCount ))
iconSize=$(( dockHeight - 4 ))
wind_border=$(( hypr_border * 3/2 ))
r_override="window{height:${dockHeight};width:${dockWidth};border-radius:${wind_border}px;} listview{columns:${appCount};} element{border-radius:${wind_border}px;} element-icon{size:${iconSize}px;}"
# launch rofi menu
if [ -d /run/current-system/sw/share/applications ]; then
appDir=/run/current-system/sw/share/applications
else
appDir=/usr/share/applications
fi
RofiSel=$( for qapp in "$@"
do
Lkp=`grep "$qapp" $appDir/* | grep 'Exec=' | awk -F ':' '{print $1}' | head -1`
Ico=`grep 'Icon=' $Lkp | awk -F '=' '{print $2}' | head -1`
echo -en "${qapp}\x00icon\x1f${Ico}\n"
done | rofi -no-fixed-num-lines -dmenu -theme-str "${r_override}" -theme-str "${pos}" -config $roconf)
$RofiSel &

20
scripts/resetxdgportal.sh Executable file
View File

@@ -0,0 +1,20 @@
#!/usr/bin/env bash
sleep 1
killall xdg-desktop-portal-hyprland
killall xdg-desktop-portal-gnome
killall xdg-desktop-portal-kde
killall xdg-desktop-portal-lxqt
killall xdg-desktop-portal-wlr
killall xdg-desktop-portal
sleep 1
# Use different directory on NixOS
if [ -d /run/current-system/sw/libexec ]; then
libDir=/run/current-system/sw/libexec
else
libDir=/usr/lib
fi
$libDir/xdg-desktop-portal-hyprland &
sleep 2
$libDir/xdg-desktop-portal &

84
scripts/rofi-network.sh Executable file
View File

@@ -0,0 +1,84 @@
#!/usr/bin/env bash
# Simple rofi-based WiFi network manager with pywal color support
# Function to get WiFi networks
get_networks() {
nmcli --fields SSID,SIGNAL device wifi list 2>/dev/null | tail -n +2 | awk '
{
ssid = $1
signal = $2
if (ssid == "") next
# Skip duplicates
if (seen[ssid]) next
seen[ssid] = 1
# Signal strength icons
if (signal >= 75) icon = "󰤾"
else if (signal >= 50) icon = "󰤿"
else if (signal >= 25) icon = "󰤽"
else icon = "󰤼"
printf "%s %s (%d%%)\n", icon, ssid, signal
}' | sort -u
}
# Start background scan immediately
nmcli device wifi rescan >/dev/null 2>&1 &
SCAN_PID=$!
# Get initial networks (cached from previous scan)
networks=$(get_networks)
# Add action options at the top
menu="📶 Refresh Networks
🔆 Enable WiFi
🔅 Disable WiFi
---
$networks"
# Show rofi menu with network theme
selected=$(echo "$menu" | rofi -dmenu -theme network -p "WiFi" 2>/dev/null)
[[ -z "$selected" ]] && exit 0
case "$selected" in
"📶 Refresh Networks")
# Trigger a scan and call self again after short delay
nmcli device wifi rescan >/dev/null 2>&1
sleep 1
bash "$0"
;;
"🔆 Enable WiFi")
nmcli radio wifi on
notify-send "WiFi" "WiFi enabled" 2>/dev/null
;;
"🔅 Disable WiFi")
nmcli radio wifi off
notify-send "WiFi" "WiFi disabled" 2>/dev/null
;;
"---")
;;
*)
# Extract SSID from selection (remove icon and signal strength)
ssid=$(echo "$selected" | sed 's/^[^ ]* \(.*\) ([0-9]*%)$/\1/')
# Try to connect
if nmcli connection show | grep -q "^$ssid"; then
# Already saved connection
nmcli connection up "$ssid" 2>/dev/null && \
notify-send "WiFi" "Connected to $ssid" 2>/dev/null || \
notify-send "WiFi" "Failed to connect to $ssid" 2>/dev/null
else
# Need password
password=$(rofi -dmenu -password -theme network \
-p "Password for $ssid" 2>/dev/null)
if [[ -n "$password" ]]; then
nmcli device wifi connect "$ssid" password "$password" 2>/dev/null && \
notify-send "WiFi" "Connected to $ssid" 2>/dev/null || \
notify-send "WiFi" "Failed to connect to $ssid" 2>/dev/null
fi
fi
;;
esac

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env bash
# Rofi preview using chafa
# $1 is the file path of the wallpaper
if [[ -f "$1" ]]; then
chafa "$1" --fill=block --symbols=block --size=30x15
fi

2
scripts/rofilaunch.sh Executable file
View File

@@ -0,0 +1,2 @@
#!/usr/bin/env bash
rofi -show drun -theme ~/.config/rofi/config.rasi

51
scripts/rofiselect.sh Executable file
View File

@@ -0,0 +1,51 @@
#!/usr/bin/env sh
#// set variables
scrDir="$(dirname "$(realpath "$0")")"
source "${scrDir}/globalcontrol.sh"
rofiConf="${confDir}/rofi/selector.rasi"
rofiStyleDir="${confDir}/rofi/styles"
rofiAssetDir="${confDir}/rofi/assets"
#// set rofi scaling
[[ "${rofiScale}" =~ ^[0-9]+$ ]] || rofiScale=10
r_scale="configuration {font: \"JetBrainsMono Nerd Font ${rofiScale}\";}"
elem_border=$(( hypr_border * 5 ))
icon_border=$(( elem_border - 5 ))
#// scale for monitor
mon_x_res=$(hyprctl -j monitors | jq '.[] | select(.focused==true) | .width')
mon_scale=$(hyprctl -j monitors | jq '.[] | select(.focused==true) | .scale' | sed "s/\.//")
mon_x_res=$(( mon_x_res * 100 / mon_scale ))
#// generate config
elm_width=$(( (20 + 12 + 16 ) * rofiScale ))
max_avail=$(( mon_x_res - (4 * rofiScale) ))
col_count=$(( max_avail / elm_width ))
[[ "${col_count}" -gt 5 ]] && col_count=5
r_override="window{width:100%;} listview{columns:${col_count};} element{orientation:vertical;border-radius:${elem_border}px;} element-icon{border-radius:${icon_border}px;size:20em;} element-text{enabled:false;}"
#// launch rofi menu
RofiSel=$(ls ${rofiStyleDir}/style_*.rasi | awk -F '[_.]' '{print $((NF - 1))}' | while read styleNum
do
echo -en "${styleNum}\x00icon\x1f${rofiAssetDir}/style_${styleNum}.png\n"
done | sort -n | rofi -dmenu -theme-str "${r_override}" -config "${rofiConf}" -select "${rofiStyle}")
#// apply rofi style
if [ ! -z "${RofiSel}" ] ; then
set_conf "rofiStyle" "${RofiSel}"
notify-send -a "t1" -r 91190 -t 2200 -i "${rofiAssetDir}/style_${RofiSel}.png" " style ${RofiSel} applied..."
fi

63
scripts/screenshot.sh Executable file
View File

@@ -0,0 +1,63 @@
#!/usr/bin/env bash
# Restores the shader after screenshot has been taken
restore_shader() {
if [ -n "$shader" ]; then
hyprshade on "$shader"
fi
}
# Saves the current shader and turns it off
save_shader() {
shader=$(hyprshade current)
hyprshade off
trap restore_shader EXIT
}
save_shader # Saving the current shader
if [ -z "$XDG_PICTURES_DIR" ]; then
XDG_PICTURES_DIR="$HOME/Pictures"
fi
scrDir=$(dirname "$(realpath "$0")")
source $scrDir/globalcontrol.sh
swpy_dir="${confDir}/swappy"
save_dir="${2:-$XDG_PICTURES_DIR/Screenshots}"
save_file=$(date +'%y%m%d_%Hh%Mm%Ss_screenshot.png')
temp_screenshot="/tmp/screenshot.png"
mkdir -p $save_dir
mkdir -p $swpy_dir
echo -e "[Default]\nsave_dir=$save_dir\nsave_filename_format=$save_file" >$swpy_dir/config
function print_error
{
cat <<"EOF"
./screenshot.sh <action>
...valid actions are...
p : print all screens
s : snip current screen
sf : snip current screen (frozen)
m : print focused monitor
EOF
}
case $1 in
p) # print all outputs
grimblast copysave screen $temp_screenshot && restore_shader && swappy -f $temp_screenshot ;;
s) # drag to manually snip an area / click on a window to print it
grimblast copysave area $temp_screenshot && restore_shader && swappy -f $temp_screenshot ;;
sf) # frozen screen, drag to manually snip an area / click on a window to print it
grimblast --freeze copysave area $temp_screenshot && restore_shader && swappy -f $temp_screenshot ;;
m) # print focused monitor
grimblast copysave output $temp_screenshot && restore_shader && swappy -f $temp_screenshot ;;
*) # invalid option
print_error ;;
esac
rm "$temp_screenshot"
if [ -f "${save_dir}/${save_file}" ]; then
notify-send -a "t1" -i "${save_dir}/${save_file}" "saved in ${save_dir}"
fi

239
scripts/set-wallpaper.sh Executable file
View File

@@ -0,0 +1,239 @@
#!/usr/bin/env bash
# -----------------------------
# CONFIGURATION
# -----------------------------
WALLPAPER_DIR="$HOME/Pictures/wallpapers"
WAYBAR_CONFIG_DIR="$HOME/.config/waybar"
ROFI_CONFIG_DIR="$HOME/.config/rofi"
INDEX_FILE="/tmp/current_wallpaper_index"
# Collect wallpapers
WALLPAPERS=("${WALLPAPER_DIR}"/*)
TOTAL_WALLPAPERS=${#WALLPAPERS[@]}
# Load current index
if [[ -f "$INDEX_FILE" ]]; then
CURRENT_INDEX=$(<"$INDEX_FILE")
else
CURRENT_INDEX=0
fi
# -----------------------------
# HELPER FUNCTIONS
# -----------------------------
extract_rofi_colors() {
if [[ -f "$HOME/.cache/wal/colors-rofi-dark.rasi" ]]; then
awk '/^\* {/,/^}/' "$HOME/.cache/wal/colors-rofi-dark.rasi" > "$ROFI_CONFIG_DIR/colors.rasi" 2>/dev/null || true
fi
}
update_hyprlock_colors() {
# Extract colors from pywal JSON and update hyprlock config
local colors_json="$HOME/.cache/wal/colors.json"
if [[ -f "$colors_json" ]]; then
# This function is called after set_wallpaper, which updates the symlink
# Hyprlock will read the new wallpaper on next lock
# Note: Colors in hyprlock.nix are set statically at build time
# so they won't update dynamically - only the wallpaper updates
:
fi
}
copy_current_wallpaper() {
local wallpaper="$1"
local wallpaper_filename=$(basename "$wallpaper")
local output_file="$ROFI_CONFIG_DIR/current_wallpaper.$(echo "$wallpaper_filename" | awk -F. '{print $NF}')"
# Remove existing file if it's read-only
if [[ -f "$output_file" ]]; then
chmod u+w "$output_file" 2>/dev/null || true
fi
cp "$wallpaper" "$output_file" 2>/dev/null || true
}
generate_posting_theme() {
# Generate posting theme from pywal colors
local WAL_COLORS="${XDG_CACHE_HOME:-$HOME/.cache}/wal/colors"
if [ ! -f "$WAL_COLORS" ]; then
return
fi
# Read colors from wal
mapfile -t COLORS < "$WAL_COLORS"
# Extract colors (wal provides 16 colors)
BG="${COLORS[0]}" # background
COLOR1="${COLORS[1]}" # red
COLOR2="${COLORS[2]}" # green
COLOR3="${COLORS[3]}" # yellow
COLOR4="${COLORS[4]}" # blue
COLOR5="${COLORS[5]}" # magenta
COLOR6="${COLORS[6]}" # cyan
POSTING_THEME_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/posting/themes"
mkdir -p "$POSTING_THEME_DIR"
# Generate theme from pywal colors with proper variable substitution
cat > "$POSTING_THEME_DIR/pywal.yaml" <<THEMEOF
# Posting theme generated from pywal colors
name: pywal
primary: '$COLOR4' # Blue from wal
secondary: '$COLOR3' # Yellow from wal
accent: '$COLOR6' # Cyan from wal
background: '$BG' # Black background from wal
surface: '$COLOR1' # Dark red for panels
panel: '$COLOR2' # Green for panel backgrounds
error: '$COLOR1' # Red for errors
success: '$COLOR2' # Green for success
warning: '$COLOR3' # Yellow for warnings
dark: true
author: "pywal"
description: "Posting theme synchronized with pywal colors"
text_area:
gutter: "bold $COLOR6"
cursor: "reverse"
cursor_line: "dim"
selection: "reverse"
url:
base: "italic $COLOR6"
protocol: "bold $COLOR4"
separator: "dim"
syntax:
json_key: "italic $COLOR4"
json_string: "$COLOR2"
json_number: "$COLOR6"
json_boolean: "$COLOR2"
json_null: "underline $COLOR6"
method:
get: "$COLOR4"
post: "$COLOR2"
put: "$COLOR3"
delete: "$COLOR1"
patch: "$COLOR6"
options: "$COLOR5"
head: "$COLOR5"
variable:
resolved: "black on $COLOR2"
unresolved: "black on $COLOR1"
THEMEOF
}
set_wallpaper() {
local wallpaper="${WALLPAPERS[$CURRENT_INDEX]}"
echo "Setting wallpaper: $wallpaper"
# Change wallpaper using swww
swww img "$wallpaper" --transition-type random
# Generate colors with pywal (also generates colors-hyprland.conf via template)
wal -i "$wallpaper"
# Generate posting theme from the new pywal colors
generate_posting_theme
# Update Pywalfox Firefox theme (if firefox is running)
if pgrep firefox > /dev/null; then
pywalfox update
fi
# Reload Hyprland to apply new colors from generated config
hyprctl reload
# Copy Waybar color scheme
cp "$HOME/.cache/wal/colors-waybar.css" "$WAYBAR_CONFIG_DIR/colors-waybar.css"
cp "$HOME/.cache/wal/colors-waybar.css" "$HOME/.config/wlogout/colors-waybar.css"
cp "$HOME/.cache/wal/colors-wal.vim" "$HOME/.config/nvim/colors-wal.vim"
cp "$HOME/.cache/wal/colors.css" "$HOME/.config/wlogout/colors.css"
# Extract Rofi colors
extract_rofi_colors
# Copy current wallpaper for Rofi preview
copy_current_wallpaper "$wallpaper"
# Symlink wallpaper for hyprlock
ln -sf "$wallpaper" "$HOME/.cache/hyprlock_wallpaper"
# Update hyprlock colors dynamically using hyprctl
update_hyprlock_colors
# Reload swaync to apply new colors (CSS is cached until service restarts)
systemctl --user restart swaync.service 2>/dev/null || true
# Reload waybar to apply new colors
pkill -SIGUSR2 waybar 2>/dev/null || true
# Reload nvim colors if running
if pgrep nvim > /dev/null; then
nvim --server /tmp/nvim.pipe --remote-send '<Esc>:source $HOME/.cache/wal/colors-wal.vim<CR>'
fi
}
next_wallpaper() {
CURRENT_INDEX=$(( (CURRENT_INDEX + 1) % TOTAL_WALLPAPERS ))
echo "$CURRENT_INDEX" > "$INDEX_FILE"
set_wallpaper
}
prev_wallpaper() {
CURRENT_INDEX=$(( (CURRENT_INDEX - 1 + TOTAL_WALLPAPERS) % TOTAL_WALLPAPERS ))
echo "$CURRENT_INDEX" > "$INDEX_FILE"
set_wallpaper
}
select_wallpaper_rofi() {
local THUMB_DIR="$HOME/.cache/wallpaper-thumbs"
local selected=$(
for wp in "${WALLPAPERS[@]}"; do
filename="$(basename "$wp")"
name_no_ext="${filename%.*}"
thumb=$(find "$THUMB_DIR" -maxdepth 1 -type f -name "${name_no_ext}_*.png" | head -n1)
[[ -z "$thumb" ]] && thumb="$wp"
# IMPORTANT: real null byte + icon metadata
printf "%s\0icon\x1f%s\n" "$filename" "$thumb"
done | rofi -dmenu -i -show-icons \
-theme "$HOME/.config/rofi/wallpaper.rasi"
)
if [[ -n "$selected" ]]; then
for i in "${!WALLPAPERS[@]}"; do
if [[ "$(basename "${WALLPAPERS[$i]}")" == "$selected" ]]; then
CURRENT_INDEX=$i
echo "$CURRENT_INDEX" > "$INDEX_FILE"
set_wallpaper
break
fi
done
fi
}
case "$1" in
next)
next_wallpaper
;;
prev)
prev_wallpaper
;;
rofi)
select_wallpaper_rofi
;;
*)
echo "Usage: $0 {next|prev|rofi}"
;;
esac

View File

@@ -0,0 +1,50 @@
#!/usr/bin/env bash
# Setup Firefox calendar app profile with custom UI customizations
# Dark Reader should be installed manually via about:addons
PROFILE_DIR="$HOME/.mozilla/firefox/calendar-app"
# Create profile directory if it doesn't exist
mkdir -p "$PROFILE_DIR/chrome"
# Create user.js with preferences
cat > "$PROFILE_DIR/user.js" << 'EOF'
// Hide Firefox UI elements
user_pref("browser.chrome.toolbar_tips", false);
user_pref("browser.tabs.drawInTitlebar", true);
user_pref("browser.tabs.tabmanager.enabled", false);
user_pref("browser.uidensity", 2);
// Disable notifications and other UI clutter
user_pref("extensions.activeThemeID", "firefox-compact-dark@mozilla.org");
user_pref("browser.startup.homepage_override.mstone", "ignore");
// Hide various UI elements
user_pref("toolkit.legacyUserProfileCustomizations.stylesheets", true);
EOF
# Create userChrome.css to hide the toolbar and tabs
cat > "$PROFILE_DIR/chrome/userChrome.css" << 'EOF'
/* Hide the entire toolbar area */
#navigator-toolbox {
display: none !important;
}
/* Hide tabs bar */
#TabsToolbar {
display: none !important;
}
/* Hide sidebar button */
#sidebar-button {
display: none !important;
}
/* Make content fill the window */
#content {
margin: 0 !important;
}
EOF
echo "Firefox calendar app profile configured successfully"

View File

@@ -0,0 +1,9 @@
#!/usr/bin/env bash
current_workspace=$(hyprctl monitors | grep "active workspace" | awk '{print $NF}')
if [ "$1" == "up" ]; then
new_workspace=$((current_workspace + 1))
elif [ "$1" == "down" ]; then
new_workspace=$((current_workspace - 1))
fi
hyprctl dispatch workspace "$new_workspace"

265
scripts/swwwallbash.sh Executable file
View File

@@ -0,0 +1,265 @@
#!/usr/bin/env bash
#// set variables
export scrDir="$(dirname "$(realpath "$0")")"
source "${scrDir}/globalcontrol.sh"
wallbashImg="${1}"
#// validate input
if [ -z "${wallbashImg}" ] || [ ! -f "${wallbashImg}" ] ; then
echo "Error: Input wallpaper not found!"
exit 1
fi
wallbashOut="${dcolDir}/$(set_hash "${wallbashImg}").dcol"
if [ ! -f "${wallbashOut}" ] ; then
"${scrDir}/swwwallcache.sh" -w "${wallbashImg}" &> /dev/null
fi
set -a
source "${wallbashOut}"
if [ -f "${hydeThemeDir}/theme.dcol" ] && [ "${enableWallDcol}" -eq 0 ] ; then
source "${hydeThemeDir}/theme.dcol"
echo "[theme] Overriding dominant colors from \"${hydeTheme}\""
echo "[note] Remove \"${hydeThemeDir}/theme.dcol\" to use wallpaper dominant colors"
fi
[ "${dcol_mode}" == "dark" ] && dcol_invt="light" || dcol_invt="dark"
set +a
#// deploy wallbash colors
fn_wallbash () {
local tplt="${1}"
[ -f "${hydeConfDir}/hyde.conf" ] && source "${hydeConfDir}/hyde.conf"
# Skips the the template declared in ./hyde.conf
[[ " ${skip_wallbash[@]} " =~ " ${tplt} " ]] && echo "[skip: template] ${tplt}" && return 0
eval target="$(head -1 "${tplt}" | awk -F '|' '{print $1}')"
[ ! -d "$(dirname "${target}")" ] && echo "[skip: no dir] \"${target}\"" && return 0
appexe="$(head -1 "${tplt}" | awk -F '|' '{print $2}')"
sed '1d' "${tplt}" > "${target}"
if [[ "${enableWallDcol}" -eq 2 && "${dcol_mode}" == "light" ]] || [[ "${enableWallDcol}" -eq 3 && "${dcol_mode}" == "dark" ]] ; then
sed -i 's/<wallbash_mode>/'"${dcol_invt}"'/g
s/<wallbash_pry1>/'"${dcol_pry4}"'/g
s/<wallbash_txt1>/'"${dcol_txt4}"'/g
s/<wallbash_1xa1>/'"${dcol_4xa9}"'/g
s/<wallbash_1xa2>/'"${dcol_4xa8}"'/g
s/<wallbash_1xa3>/'"${dcol_4xa7}"'/g
s/<wallbash_1xa4>/'"${dcol_4xa6}"'/g
s/<wallbash_1xa5>/'"${dcol_4xa5}"'/g
s/<wallbash_1xa6>/'"${dcol_4xa4}"'/g
s/<wallbash_1xa7>/'"${dcol_4xa3}"'/g
s/<wallbash_1xa8>/'"${dcol_4xa2}"'/g
s/<wallbash_1xa9>/'"${dcol_4xa1}"'/g
s/<wallbash_pry2>/'"${dcol_pry3}"'/g
s/<wallbash_txt2>/'"${dcol_txt3}"'/g
s/<wallbash_2xa1>/'"${dcol_3xa9}"'/g
s/<wallbash_2xa2>/'"${dcol_3xa8}"'/g
s/<wallbash_2xa3>/'"${dcol_3xa7}"'/g
s/<wallbash_2xa4>/'"${dcol_3xa6}"'/g
s/<wallbash_2xa5>/'"${dcol_3xa5}"'/g
s/<wallbash_2xa6>/'"${dcol_3xa4}"'/g
s/<wallbash_2xa7>/'"${dcol_3xa3}"'/g
s/<wallbash_2xa8>/'"${dcol_3xa2}"'/g
s/<wallbash_2xa9>/'"${dcol_3xa1}"'/g
s/<wallbash_pry3>/'"${dcol_pry2}"'/g
s/<wallbash_txt3>/'"${dcol_txt2}"'/g
s/<wallbash_3xa1>/'"${dcol_2xa9}"'/g
s/<wallbash_3xa2>/'"${dcol_2xa8}"'/g
s/<wallbash_3xa3>/'"${dcol_2xa7}"'/g
s/<wallbash_3xa4>/'"${dcol_2xa6}"'/g
s/<wallbash_3xa5>/'"${dcol_2xa5}"'/g
s/<wallbash_3xa6>/'"${dcol_2xa4}"'/g
s/<wallbash_3xa7>/'"${dcol_2xa3}"'/g
s/<wallbash_3xa8>/'"${dcol_2xa2}"'/g
s/<wallbash_3xa9>/'"${dcol_2xa1}"'/g
s/<wallbash_pry4>/'"${dcol_pry1}"'/g
s/<wallbash_txt4>/'"${dcol_txt1}"'/g
s/<wallbash_4xa1>/'"${dcol_1xa9}"'/g
s/<wallbash_4xa2>/'"${dcol_1xa8}"'/g
s/<wallbash_4xa3>/'"${dcol_1xa7}"'/g
s/<wallbash_4xa4>/'"${dcol_1xa6}"'/g
s/<wallbash_4xa5>/'"${dcol_1xa5}"'/g
s/<wallbash_4xa6>/'"${dcol_1xa4}"'/g
s/<wallbash_4xa7>/'"${dcol_1xa3}"'/g
s/<wallbash_4xa8>/'"${dcol_1xa2}"'/g
s/<wallbash_4xa9>/'"${dcol_1xa1}"'/g
s/<wallbash_pry1_rgba(\([^)]*\))>/'"${dcol_pry4_rgba}"'/g
s/<wallbash_txt1_rgba(\([^)]*\))>/'"${dcol_txt4_rgba}"'/g
s/<wallbash_1xa1_rgba(\([^)]*\))>/'"${dcol_4xa9_rgba}"'/g
s/<wallbash_1xa2_rgba(\([^)]*\))>/'"${dcol_4xa8_rgba}"'/g
s/<wallbash_1xa3_rgba(\([^)]*\))>/'"${dcol_4xa7_rgba}"'/g
s/<wallbash_1xa4_rgba(\([^)]*\))>/'"${dcol_4xa6_rgba}"'/g
s/<wallbash_1xa5_rgba(\([^)]*\))>/'"${dcol_4xa5_rgba}"'/g
s/<wallbash_1xa6_rgba(\([^)]*\))>/'"${dcol_4xa4_rgba}"'/g
s/<wallbash_1xa7_rgba(\([^)]*\))>/'"${dcol_4xa3_rgba}"'/g
s/<wallbash_1xa8_rgba(\([^)]*\))>/'"${dcol_4xa2_rgba}"'/g
s/<wallbash_1xa9_rgba(\([^)]*\))>/'"${dcol_4xa1_rgba}"'/g
s/<wallbash_pry2_rgba(\([^)]*\))>/'"${dcol_pry3_rgba}"'/g
s/<wallbash_txt2_rgba(\([^)]*\))>/'"${dcol_txt3_rgba}"'/g
s/<wallbash_2xa1_rgba(\([^)]*\))>/'"${dcol_3xa9_rgba}"'/g
s/<wallbash_2xa2_rgba(\([^)]*\))>/'"${dcol_3xa8_rgba}"'/g
s/<wallbash_2xa3_rgba(\([^)]*\))>/'"${dcol_3xa7_rgba}"'/g
s/<wallbash_2xa4_rgba(\([^)]*\))>/'"${dcol_3xa6_rgba}"'/g
s/<wallbash_2xa5_rgba(\([^)]*\))>/'"${dcol_3xa5_rgba}"'/g
s/<wallbash_2xa6_rgba(\([^)]*\))>/'"${dcol_3xa4_rgba}"'/g
s/<wallbash_2xa7_rgba(\([^)]*\))>/'"${dcol_3xa3_rgba}"'/g
s/<wallbash_2xa8_rgba(\([^)]*\))>/'"${dcol_3xa2_rgba}"'/g
s/<wallbash_2xa9_rgba(\([^)]*\))>/'"${dcol_3xa1_rgba}"'/g
s/<wallbash_pry3_rgba(\([^)]*\))>/'"${dcol_pry2_rgba}"'/g
s/<wallbash_txt3_rgba(\([^)]*\))>/'"${dcol_txt2_rgba}"'/g
s/<wallbash_3xa1_rgba(\([^)]*\))>/'"${dcol_2xa9_rgba}"'/g
s/<wallbash_3xa2_rgba(\([^)]*\))>/'"${dcol_2xa8_rgba}"'/g
s/<wallbash_3xa3_rgba(\([^)]*\))>/'"${dcol_2xa7_rgba}"'/g
s/<wallbash_3xa4_rgba(\([^)]*\))>/'"${dcol_2xa6_rgba}"'/g
s/<wallbash_3xa5_rgba(\([^)]*\))>/'"${dcol_2xa5_rgba}"'/g
s/<wallbash_3xa6_rgba(\([^)]*\))>/'"${dcol_2xa4_rgba}"'/g
s/<wallbash_3xa7_rgba(\([^)]*\))>/'"${dcol_2xa3_rgba}"'/g
s/<wallbash_3xa8_rgba(\([^)]*\))>/'"${dcol_2xa2_rgba}"'/g
s/<wallbash_3xa9_rgba(\([^)]*\))>/'"${dcol_2xa1_rgba}"'/g
s/<wallbash_pry4_rgba(\([^)]*\))>/'"${dcol_pry1_rgba}"'/g
s/<wallbash_txt4_rgba(\([^)]*\))>/'"${dcol_txt1_rgba}"'/g
s/<wallbash_4xa1_rgba(\([^)]*\))>/'"${dcol_1xa9_rgba}"'/g
s/<wallbash_4xa2_rgba(\([^)]*\))>/'"${dcol_1xa8_rgba}"'/g
s/<wallbash_4xa3_rgba(\([^)]*\))>/'"${dcol_1xa7_rgba}"'/g
s/<wallbash_4xa4_rgba(\([^)]*\))>/'"${dcol_1xa6_rgba}"'/g
s/<wallbash_4xa5_rgba(\([^)]*\))>/'"${dcol_1xa5_rgba}"'/g
s/<wallbash_4xa6_rgba(\([^)]*\))>/'"${dcol_1xa4_rgba}"'/g
s/<wallbash_4xa7_rgba(\([^)]*\))>/'"${dcol_1xa3_rgba}"'/g
s/<wallbash_4xa8_rgba(\([^)]*\))>/'"${dcol_1xa2_rgba}"'/g
s/<wallbash_4xa9_rgba(\([^)]*\))>/'"${dcol_1xa1_rgba}"'/g' "${target}"
else
sed -i 's/<wallbash_mode>/'"${dcol_mode}"'/g
s/<wallbash_pry1>/'"${dcol_pry1}"'/g
s/<wallbash_txt1>/'"${dcol_txt1}"'/g
s/<wallbash_1xa1>/'"${dcol_1xa1}"'/g
s/<wallbash_1xa2>/'"${dcol_1xa2}"'/g
s/<wallbash_1xa3>/'"${dcol_1xa3}"'/g
s/<wallbash_1xa4>/'"${dcol_1xa4}"'/g
s/<wallbash_1xa5>/'"${dcol_1xa5}"'/g
s/<wallbash_1xa6>/'"${dcol_1xa6}"'/g
s/<wallbash_1xa7>/'"${dcol_1xa7}"'/g
s/<wallbash_1xa8>/'"${dcol_1xa8}"'/g
s/<wallbash_1xa9>/'"${dcol_1xa9}"'/g
s/<wallbash_pry2>/'"${dcol_pry2}"'/g
s/<wallbash_txt2>/'"${dcol_txt2}"'/g
s/<wallbash_2xa1>/'"${dcol_2xa1}"'/g
s/<wallbash_2xa2>/'"${dcol_2xa2}"'/g
s/<wallbash_2xa3>/'"${dcol_2xa3}"'/g
s/<wallbash_2xa4>/'"${dcol_2xa4}"'/g
s/<wallbash_2xa5>/'"${dcol_2xa5}"'/g
s/<wallbash_2xa6>/'"${dcol_2xa6}"'/g
s/<wallbash_2xa7>/'"${dcol_2xa7}"'/g
s/<wallbash_2xa8>/'"${dcol_2xa8}"'/g
s/<wallbash_2xa9>/'"${dcol_2xa9}"'/g
s/<wallbash_pry3>/'"${dcol_pry3}"'/g
s/<wallbash_txt3>/'"${dcol_txt3}"'/g
s/<wallbash_3xa1>/'"${dcol_3xa1}"'/g
s/<wallbash_3xa2>/'"${dcol_3xa2}"'/g
s/<wallbash_3xa3>/'"${dcol_3xa3}"'/g
s/<wallbash_3xa4>/'"${dcol_3xa4}"'/g
s/<wallbash_3xa5>/'"${dcol_3xa5}"'/g
s/<wallbash_3xa6>/'"${dcol_3xa6}"'/g
s/<wallbash_3xa7>/'"${dcol_3xa7}"'/g
s/<wallbash_3xa8>/'"${dcol_3xa8}"'/g
s/<wallbash_3xa9>/'"${dcol_3xa9}"'/g
s/<wallbash_pry4>/'"${dcol_pry4}"'/g
s/<wallbash_txt4>/'"${dcol_txt4}"'/g
s/<wallbash_4xa1>/'"${dcol_4xa1}"'/g
s/<wallbash_4xa2>/'"${dcol_4xa2}"'/g
s/<wallbash_4xa3>/'"${dcol_4xa3}"'/g
s/<wallbash_4xa4>/'"${dcol_4xa4}"'/g
s/<wallbash_4xa5>/'"${dcol_4xa5}"'/g
s/<wallbash_4xa6>/'"${dcol_4xa6}"'/g
s/<wallbash_4xa7>/'"${dcol_4xa7}"'/g
s/<wallbash_4xa8>/'"${dcol_4xa8}"'/g
s/<wallbash_4xa9>/'"${dcol_4xa9}"'/g
s/<wallbash_pry1_rgba(\([^)]*\))>/'"${dcol_pry1_rgba}"'/g
s/<wallbash_txt1_rgba(\([^)]*\))>/'"${dcol_txt1_rgba}"'/g
s/<wallbash_1xa1_rgba(\([^)]*\))>/'"${dcol_1xa1_rgba}"'/g
s/<wallbash_1xa2_rgba(\([^)]*\))>/'"${dcol_1xa2_rgba}"'/g
s/<wallbash_1xa3_rgba(\([^)]*\))>/'"${dcol_1xa3_rgba}"'/g
s/<wallbash_1xa4_rgba(\([^)]*\))>/'"${dcol_1xa4_rgba}"'/g
s/<wallbash_1xa5_rgba(\([^)]*\))>/'"${dcol_1xa5_rgba}"'/g
s/<wallbash_1xa6_rgba(\([^)]*\))>/'"${dcol_1xa6_rgba}"'/g
s/<wallbash_1xa7_rgba(\([^)]*\))>/'"${dcol_1xa7_rgba}"'/g
s/<wallbash_1xa8_rgba(\([^)]*\))>/'"${dcol_1xa8_rgba}"'/g
s/<wallbash_1xa9_rgba(\([^)]*\))>/'"${dcol_1xa9_rgba}"'/g
s/<wallbash_pry2_rgba(\([^)]*\))>/'"${dcol_pry2_rgba}"'/g
s/<wallbash_txt2_rgba(\([^)]*\))>/'"${dcol_txt2_rgba}"'/g
s/<wallbash_2xa1_rgba(\([^)]*\))>/'"${dcol_2xa1_rgba}"'/g
s/<wallbash_2xa2_rgba(\([^)]*\))>/'"${dcol_2xa2_rgba}"'/g
s/<wallbash_2xa3_rgba(\([^)]*\))>/'"${dcol_2xa3_rgba}"'/g
s/<wallbash_2xa4_rgba(\([^)]*\))>/'"${dcol_2xa4_rgba}"'/g
s/<wallbash_2xa5_rgba(\([^)]*\))>/'"${dcol_2xa5_rgba}"'/g
s/<wallbash_2xa6_rgba(\([^)]*\))>/'"${dcol_2xa6_rgba}"'/g
s/<wallbash_2xa7_rgba(\([^)]*\))>/'"${dcol_2xa7_rgba}"'/g
s/<wallbash_2xa8_rgba(\([^)]*\))>/'"${dcol_2xa8_rgba}"'/g
s/<wallbash_2xa9_rgba(\([^)]*\))>/'"${dcol_2xa9_rgba}"'/g
s/<wallbash_pry3_rgba(\([^)]*\))>/'"${dcol_pry3_rgba}"'/g
s/<wallbash_txt3_rgba(\([^)]*\))>/'"${dcol_txt3_rgba}"'/g
s/<wallbash_3xa1_rgba(\([^)]*\))>/'"${dcol_3xa1_rgba}"'/g
s/<wallbash_3xa2_rgba(\([^)]*\))>/'"${dcol_3xa2_rgba}"'/g
s/<wallbash_3xa3_rgba(\([^)]*\))>/'"${dcol_3xa3_rgba}"'/g
s/<wallbash_3xa4_rgba(\([^)]*\))>/'"${dcol_3xa4_rgba}"'/g
s/<wallbash_3xa5_rgba(\([^)]*\))>/'"${dcol_3xa5_rgba}"'/g
s/<wallbash_3xa6_rgba(\([^)]*\))>/'"${dcol_3xa6_rgba}"'/g
s/<wallbash_3xa7_rgba(\([^)]*\))>/'"${dcol_3xa7_rgba}"'/g
s/<wallbash_3xa8_rgba(\([^)]*\))>/'"${dcol_3xa8_rgba}"'/g
s/<wallbash_3xa9_rgba(\([^)]*\))>/'"${dcol_3xa9_rgba}"'/g
s/<wallbash_pry4_rgba(\([^)]*\))>/'"${dcol_pry4_rgba}"'/g
s/<wallbash_txt4_rgba(\([^)]*\))>/'"${dcol_txt4_rgba}"'/g
s/<wallbash_4xa1_rgba(\([^)]*\))>/'"${dcol_4xa1_rgba}"'/g
s/<wallbash_4xa2_rgba(\([^)]*\))>/'"${dcol_4xa2_rgba}"'/g
s/<wallbash_4xa3_rgba(\([^)]*\))>/'"${dcol_4xa3_rgba}"'/g
s/<wallbash_4xa4_rgba(\([^)]*\))>/'"${dcol_4xa4_rgba}"'/g
s/<wallbash_4xa5_rgba(\([^)]*\))>/'"${dcol_4xa5_rgba}"'/g
s/<wallbash_4xa6_rgba(\([^)]*\))>/'"${dcol_4xa6_rgba}"'/g
s/<wallbash_4xa7_rgba(\([^)]*\))>/'"${dcol_4xa7_rgba}"'/g
s/<wallbash_4xa8_rgba(\([^)]*\))>/'"${dcol_4xa8_rgba}"'/g
s/<wallbash_4xa9_rgba(\([^)]*\))>/'"${dcol_4xa9_rgba}"'/g' "${target}"
fi
[ -z "${appexe}" ] || bash -c "${appexe}"
}
export -f fn_wallbash
[ -n "$HYPRLAND_INSTANCE_SIGNATURE" ] && hyprctl keyword misc:disable_autoreload 1 -q && trap 'hyprctl reload -q && echo "[swwwallbash] reload :: Hyprland"' EXIT
#// switch theme <//> wall based colors
if [ "${enableWallDcol}" -eq 0 ] && [[ "${reload_flag}" -eq 1 ]] ; then
echo ":: deploying ${hydeTheme} colors :: ${dcol_mode} wallpaper detected"
mapfile -d '' -t deployList < <(find "${hydeThemeDir}" -type f -name "*.theme" -print0)
while read -r pKey ; do
fKey="$(find "${hydeThemeDir}" -type f -name "$(basename "${pKey%.dcol}.theme")")"
[ -z "${fKey}" ] && deployList+=("${pKey}")
done < <(find "${wallbashDir}/Wall-Dcol" -type f -name "*.dcol")
parallel fn_wallbash ::: "${deployList[@]}"
elif [ "${enableWallDcol}" -gt 0 ] ; then
echo ":: deploying wallbash colors :: ${dcol_mode} wallpaper detected"
find "${wallbashDir}/Wall-Dcol" -type f -name "*.dcol" | parallel fn_wallbash {}
fi
# Theme mode: detects the color-scheme set in hypr.theme and falls back if nothing is parsed.
if [ "${enableWallDcol}" -eq 0 ]; then
colorScheme="$({ grep -q "^[[:space:]]*\$COLOR-SCHEME\s*=" "${hydeThemeDir}/hypr.theme" && grep "^[[:space:]]*\$COLOR-SCHEME\s*=" "${hydeThemeDir}/hypr.theme" | cut -d '=' -f2 | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' ;} ||
grep 'gsettings set org.gnome.desktop.interface color-scheme' "${hydeThemeDir}/hypr.theme" | awk -F "'" '{print $((NF - 1))}')"
colorScheme=${colorScheme:-$(gsettings get org.gnome.desktop.interface color-scheme)}
# should be declared explicitly so we can easily debug
grep -q "dark" <<< "${colorScheme}" && enableWallDcol=2
grep -q "light" <<< "${colorScheme}" && enableWallDcol=3
fi
find "${wallbashDir}/Wall-Ways" -type f -name "*.dcol" | parallel fn_wallbash {}

91
scripts/swwwallcache.sh Executable file
View File

@@ -0,0 +1,91 @@
#!/usr/bin/env bash
#// set variables
export scrDir="$(dirname "$(realpath "$0")")"
source "${scrDir}/globalcontrol.sh"
export thmbDir
export dcolDir
[ -d "${hydeThemeDir}" ] && cacheIn="${hydeThemeDir}" || exit 1
[ -d "${thmbDir}" ] || mkdir -p "${thmbDir}"
[ -d "${dcolDir}" ] || mkdir -p "${dcolDir}"
[ -d "${cacheDir}/landing" ] || mkdir -p "${cacheDir}/landing"
if [ ! -z "${wallbashCustomCurve}" ] && [[ "${wallbashCustomCurve}" =~ ^([0-9]+[[:space:]][0-9]+\\n){8}[0-9]+[[:space:]][0-9]+$ ]] ; then
export wallbashCustomCurve
echo ":: wallbash --custom \"${wallbashCustomCurve}\""
else
export wallbashCustomCurve="32 50\n42 46\n49 40\n56 39\n64 38\n76 37\n90 33\n94 29\n100 20"
fi
#// define functions
fn_wallcache()
{
local x_hash="${1}"
local x_wall="${2}"
[ ! -e "${thmbDir}/${x_hash}.thmb" ] && magick "${x_wall}"[0] -strip -resize 1000 -gravity center -extent 1000 -quality 90 "${thmbDir}/${x_hash}.thmb"
[ ! -e "${thmbDir}/${x_hash}.sqre" ] && magick "${x_wall}"[0] -strip -thumbnail 500x500^ -gravity center -extent 500x500 "${thmbDir}/${x_hash}.sqre"
[ ! -e "${thmbDir}/${x_hash}.blur" ] && magick "${x_wall}"[0] -strip -scale 10% -blur 0x3 -resize 100% "${thmbDir}/${x_hash}.blur"
[ ! -e "${thmbDir}/${x_hash}.quad" ] && magick "${thmbDir}/${x_hash}.sqre" \( -size 500x500 xc:white -fill "rgba(0,0,0,0.7)" -draw "polygon 400,500 500,500 500,0 450,0" -fill black -draw "polygon 500,500 500,0 450,500" \) -alpha Off -compose CopyOpacity -composite "${thmbDir}/${x_hash}.png" && mv "${thmbDir}/${x_hash}.png" "${thmbDir}/${x_hash}.quad"
{ [ ! -e "${dcolDir}/${x_hash}.dcol" ] || [ "$(wc -l < "${dcolDir}/${x_hash}.dcol")" -ne 89 ] ;} && "${scrDir}/wallbash.sh" --custom "${wallbashCustomCurve}" "${thmbDir}/${x_hash}.thmb" "${dcolDir}/${x_hash}" &> /dev/null
}
fn_wallcache_force()
{
local x_hash="${1}"
local x_wall="${2}"
magick "${x_wall}"[0] -strip -resize 1000 -gravity center -extent 1000 -quality 90 "${thmbDir}/${x_hash}.thmb"
magick "${x_wall}"[0] -strip -thumbnail 500x500^ -gravity center -extent 500x500 "${thmbDir}/${x_hash}.sqre"
magick "${x_wall}"[0] -strip -scale 10% -blur 0x3 -resize 100% "${thmbDir}/${x_hash}.blur"
magick "${thmbDir}/${x_hash}.sqre" \( -size 500x500 xc:white -fill "rgba(0,0,0,0.7)" -draw "polygon 400,500 500,500 500,0 450,0" -fill black -draw "polygon 500,500 500,0 450,500" \) -alpha Off -compose CopyOpacity -composite "${thmbDir}/${x_hash}.png" && mv "${thmbDir}/${x_hash}.png" "${thmbDir}/${x_hash}.quad"
"${scrDir}/wallbash.sh" --custom "${wallbashCustomCurve}" "${thmbDir}/${x_hash}.thmb" "${dcolDir}/${x_hash}" &> /dev/null
}
export -f fn_wallcache
export -f fn_wallcache_force
#// evaluate options
while getopts "w:t:f" option ; do
case $option in
w ) # generate cache for input wallpaper
if [ -z "${OPTARG}" ] || [ ! -f "${OPTARG}" ] ; then
echo "Error: Input wallpaper \"${OPTARG}\" not found!"
exit 1
fi
cacheIn="${OPTARG}"
;;
t ) # generate cache for input theme
cacheIn="$(dirname "${hydeThemeDir}")/${OPTARG}"
if [ ! -d "${cacheIn}" ] ; then
echo "Error: Input theme \"${OPTARG}\" not found!"
exit 1
fi
;;
f ) # full cache rebuild
cacheIn="$(dirname "${hydeThemeDir}")"
mode="_force"
;;
* ) # invalid option
echo "... invalid option ..."
echo "$(basename "${0}") -[option]"
echo "w : generate cache for input wallpaper"
echo "t : generate cache for input theme"
echo "f : full cache rebuild"
exit 1 ;;
esac
done
#// generate cache
wallPathArray=("${cacheIn}")
wallPathArray+=("${wallAddCustomPath[@]}")
get_hashmap "${wallPathArray[@]}"
parallel --bar --link "fn_wallcache${mode}" ::: "${wallHash[@]}" ::: "${wallList[@]}"
exit 0

73
scripts/swwwallkon.sh Executable file
View File

@@ -0,0 +1,73 @@
#!/usr/bin/env bash
#// Set variables
scrDir=$(dirname "$(realpath "$0")")
source "${scrDir}/globalcontrol.sh"
scrName="$(basename "$0")"
kmenuPath="$HOME/.local/share/kio/servicemenus"
kmenuDesk="${kmenuPath}/hydewallpaper.desktop"
tgtPath="$(dirname "${hydeThemeDir}")"
get_themes
#// Evaluate options
while getopts "t:w:" option ; do
case $option in
t ) # Set theme
for x in "${!thmList[@]}" ; do
if [ "${thmList[x]}" == "$OPTARG" ] ; then
setTheme="${thmList[x]}"
break
fi
done
[ -z "${setTheme}" ] && echo "Error: '$OPTARG' theme not available..." && exit 1
;;
w ) # Set wallpaper
if [ -f "$OPTARG" ] && file --mime-type "$OPTARG" | grep -q 'image/' ; then
setWall="$OPTARG"
else
echo "Error: '$OPTARG' is not an image file..."
exit 1
fi
;;
* ) # Refresh menu
unset setTheme
unset setWall
;;
esac
done
#// Regenerate desktop
if [ ! -z "${setTheme}" ] && [ ! -z "${setWall}" ] ; then
inwallHash="$(set_hash "${setWall}")"
get_hashmap "${tgtPath}/${setTheme}"
if [[ "${wallHash[@]}" == *"${inwallHash}"* ]] ; then
notify-send -a "t2" -i "${thmbDir}/${inwallHash}.sqre" "Error" "Hash matched in ${setTheme}"
exit 0
fi
cp "${setWall}" "${tgtPath}/${setTheme}/wallpapers"
ln -fs "${tgtPath}/${setTheme}/wallpapers/$(basename "${setWall}")" "${tgtPath}/${setTheme}/wall.set"
"${scrDir}/themeswitch.sh" -s "${setTheme}"
notify-send -a "t1" -i "${thmbDir}/${inwallHash}.sqre" "Wallpaper set in ${setTheme}"
else
echo -e "[Desktop Entry]\nType=Service\nMimeType=image/png;image/jpeg;image/jpg;image/gif\nActions=Menu-Refresh$(printf ";%s" "${thmList[@]}")\nX-KDE-Submenu=Set As Wallpaper...\n\n[Desktop Action Menu-Refresh]\nName=.: Refresh List :.\nExec=${scrName}" > "${kmenuDesk}"
for i in "${!thmList[@]}" ; do
echo -e "\n[Desktop Action ${thmList[i]}]\nName=${thmList[i]}\nExec=${scrName} -t \"${thmList[i]}\" -w %u" >> "${kmenuDesk}"
done
fi

0
scripts/swwwallpaper.sh Executable file
View File

52
scripts/swwwallselect.sh Executable file
View File

@@ -0,0 +1,52 @@
#!/usr/bin/env bash
#// set variables
scrDir="$(dirname "$(realpath "$0")")"
source "${scrDir}/globalcontrol.sh"
rofiConf="${confDir}/rofi/selector.rasi"
#// set rofi scaling
[[ "${rofiScale}" =~ ^[0-9]+$ ]] || rofiScale=10
r_scale="configuration {font: \"JetBrainsMono Nerd Font ${rofiScale}\";}"
elem_border=$(( hypr_border * 3 ))
#// scale for monitor
mon_x_res=$(hyprctl -j monitors | jq '.[] | select(.focused==true) | .width')
mon_scale=$(hyprctl -j monitors | jq '.[] | select(.focused==true) | .scale' | sed "s/\.//")
mon_x_res=$(( mon_x_res * 100 / mon_scale ))
#// generate config
elm_width=$(( (28 + 8 + 5) * rofiScale ))
max_avail=$(( mon_x_res - (4 * rofiScale) ))
col_count=$(( max_avail / elm_width ))
r_override="window{width:100%;} listview{columns:${col_count};spacing:5em;} element{border-radius:${elem_border}px;orientation:vertical;} element-icon{size:28em;border-radius:0em;} element-text{padding:1em;}"
#// launch rofi menu
currentWall="$(basename "$(readlink "${hydeThemeDir}/wall.set")")"
wallPathArray=("${hydeThemeDir}")
wallPathArray+=("${wallAddCustomPath[@]}")
get_hashmap "${wallPathArray[@]}"
rofiSel=$(parallel --link echo -en "\$(basename "{1}")"'\\x00icon\\x1f'"${thmbDir}"'/'"{2}"'.sqre\\n' ::: "${wallList[@]}" ::: "${wallHash[@]}" | rofi -dmenu -theme-str "${r_scale}" -theme-str "${r_override}" -config "${rofiConf}" -select "${currentWall}")
#// apply wallpaper
if [ ! -z "${rofiSel}" ] ; then
for i in "${!wallPathArray[@]}" ; do
setWall="$(find "${wallPathArray[i]}" -type f -name "${rofiSel}")"
[ -z "${setWall}" ] || break
done
"${scrDir}/swwwallpaper.sh" -s "${setWall}"
notify-send -a "t1" -i "${thmbDir}/$(set_hash "${setWall}").sqre" " ${rofiSel}"
fi

14
scripts/sysmonlaunch.sh Executable file
View File

@@ -0,0 +1,14 @@
#!/usr/bin/env bash
scrDir="$(dirname "$(realpath "$0")")"
source "${scrDir}/globalcontrol.sh"
pkgChk=("io.missioncenter.MissionCenter" "htop" "btop" "top")
for sysMon in "${!pkgChk[@]}"; do
[ "${sysMon}" -gt 0 ] && term=$(cat $HOME/.config/hypr/keybindings.conf | grep ^'$term' | cut -d '=' -f2)
if pkg_installed "${pkgChk[sysMon]}" ; then
pkill -x "${pkgChk[sysMon]}" || ${term} "${pkgChk[sysMon]}" &
break
fi
done

53
scripts/systemupdate.sh Executable file
View File

@@ -0,0 +1,53 @@
#!/usr/bin/env bash
# Check release
if [ ! -f /etc/arch-release ] ; then
exit 0
fi
# source variables
scrDir=$(dirname "$(realpath "$0")")
source "$scrDir/globalcontrol.sh"
get_aurhlpr
export -f pkg_installed
fpk_exup="pkg_installed flatpak && flatpak update"
# Trigger upgrade
if [ "$1" == "up" ] ; then
trap 'pkill -RTMIN+20 waybar' EXIT
command="
fastfetch
$0 upgrade
${aurhlpr} -Syu
$fpk_exup
read -n 1 -p 'Press any key to continue...'
"
kitty --title systemupdate sh -c "${command}"
fi
# Check for AUR updates
aur=$(${aurhlpr} -Qua | wc -l)
ofc=$( (while pgrep -x checkupdates > /dev/null ; do sleep 1; done) ; checkupdates | wc -l)
# Check for flatpak updates
if pkg_installed flatpak ; then
fpk=$(flatpak remote-ls --updates | wc -l)
fpk_disp="\n󰏓 Flatpak $fpk"
else
fpk=0
fpk_disp=""
fi
# Calculate total available updates
upd=$(( ofc + aur + fpk ))
[ "${1}" == upgrade ] && printf "[Official] %-10s\n[AUR] %-10s\n[Flatpak] %-10s\n" "$ofc" "$aur" "$fpk" && exit
# Show tooltip
if [ $upd -eq 0 ] ; then
upd="" #Remove Icon completely
# upd="󰮯" #If zero Display Icon only
echo "{\"text\":\"$upd\", \"tooltip\":\" Packages are up to date\"}"
else
echo "{\"text\":\"󰮯 $upd\", \"tooltip\":\"󱓽 Official $ofc\n󱓾 AUR $aur$fpk_disp\"}"
fi

27
scripts/testrunner.sh Executable file
View File

@@ -0,0 +1,27 @@
#!/usr/bin/env bash
scrDir=`dirname "$(realpath "$0")"`
source $scrDir/globalcontrol.sh
rofDir="${confDir}/rofi"
if [ "${1}" == "--verbose" ] || [ "${1}" == "-v" ] ; then
case ${enableWallDcol} in
0) wallbashStatus="disabled";;
1) wallbashStatus="enabled // auto change based on wallpaper brightness";;
2) wallbashStatus="enabled // dark mode --forced";;
3) wallbashStatus="enabled // light mode --forced";;
esac
echo -e "\n\ncurrent theme :: \"${hydeTheme}\" :: \"$(readlink "${hydeThemeDir}/wall.set")\""
echo -e "wallbash status :: ${enableWallDcol} :: ${wallbashStatus}\n"
get_themes
for x in "${!thmList[@]}" ; do
echo -e "\nTheme $((x + 1)) :: \${thmList[${x}]}=\"${thmList[x]}\" :: \${thmWall[${x}]}=\"${thmWall[x]}\"\n"
get_hashmap "$(dirname "${hydeThemeDir}")/${thmList[x]}" --verbose
echo -e "\n"
done
exit 0
fi

59
scripts/themeselect.sh Executable file
View File

@@ -0,0 +1,59 @@
#!/usr/bin/env bash
#// set variables
scrDir="$(dirname "$(realpath "$0")")"
source "${scrDir}/globalcontrol.sh"
rofiConf="${confDir}/rofi/selector.rasi"
#// set rofi scaling
[[ "${rofiScale}" =~ ^[0-9]+$ ]] || rofiScale=10
r_scale="configuration {font: \"JetBrainsMono Nerd Font ${rofiScale}\";}"
elem_border=$(( hypr_border * 5 ))
icon_border=$(( elem_border - 5 ))
#// scale for monitor
mon_x_res=$(hyprctl -j monitors | jq '.[] | select(.focused==true) | .width')
mon_scale=$(hyprctl -j monitors | jq '.[] | select(.focused==true) | .scale' | sed "s/\.//")
mon_x_res=$(( mon_x_res * 100 / mon_scale ))
#// generate config
case "${themeSelect}" in
2) # adapt to style 2
elm_width=$(( (20 + 12) * rofiScale * 2 ))
max_avail=$(( mon_x_res - (4 * rofiScale) ))
col_count=$(( max_avail / elm_width ))
r_override="window{width:100%;background-color:#00000003;} listview{columns:${col_count};} element{border-radius:${elem_border}px;background-color:@main-bg;} element-icon{size:20em;border-radius:${icon_border}px 0px 0px ${icon_border}px;}"
thmbExtn="quad" ;;
*) # default to style 1
elm_width=$(( (23 + 12 + 1) * rofiScale * 2 ))
max_avail=$(( mon_x_res - (4 * rofiScale) ))
col_count=$(( max_avail / elm_width ))
r_override="window{width:100%;} listview{columns:${col_count};} element{border-radius:${elem_border}px;padding:0.5em;} element-icon{size:23em;border-radius:${icon_border}px;}"
thmbExtn="sqre" ;;
esac
#// launch rofi menu
get_themes
rofiSel=$(for i in ${!thmList[@]} ; do
echo -en "${thmList[i]}\x00icon\x1f${thmbDir}/$(set_hash "${thmWall[i]}").${thmbExtn}\n"
done | rofi -dmenu -theme-str "${r_scale}" -theme-str "${r_override}" -config "${rofiConf}" -select "${hydeTheme}")
#// apply theme
if [ ! -z "${rofiSel}" ] ; then
"${scrDir}/themeswitch.sh" -s "${rofiSel}"
notify-send -a "t1" -i "$HOME/.config/dunst/icons/hyprdots.png" " ${rofiSel}"
fi

42
scripts/themestyle.sh Executable file
View File

@@ -0,0 +1,42 @@
#!/usr/bin/env bash
#// set variables
scrDir="$(dirname "$(realpath "$0")")"
source "${scrDir}/globalcontrol.sh"
rofiConf="${confDir}/rofi/selector.rasi"
rofiAssetDir="${confDir}/rofi/assets"
#// set rofi scaling
[[ "${rofiScale}" =~ ^[0-9]+$ ]] || rofiScale=15
r_scale="configuration {font: \"JetBrainsMono Nerd Font ${rofiScale}\";}"
elem_border=$(( hypr_border * 5 ))
icon_border=$(( elem_border - 5 ))
#// defining 2 png files to select from
options="Style 1\x00icon\x1f${rofiAssetDir}/theme_style_1.png\nStyle 2\x00icon\x1f${rofiAssetDir}/theme_style_2.png"
#// generate config
mon_x_res=$(hyprctl -j monitors | jq '.[] | select(.focused==true) | .width')
mon_scale=$(hyprctl -j monitors | jq '.[] | select(.focused==true) | .scale' | sed "s/\.//")
mon_x_res=$(( mon_x_res * 100 / mon_scale ))
elm_width=$(( (20 + 12 + 16 ) * rofiScale ))
max_avail=$(( mon_x_res - (4 * rofiScale) ))
col_count=$(( max_avail / elm_width ))
[[ "${col_count}" -gt 5 ]] && col_count=5
r_override="window{width:100%;} listview{columns:${col_count};} element{orientation:vertical;border-radius:${elem_border}px;} element-icon{border-radius:${icon_border}px;size:20em;} element-text{enabled:false;}"
#// launch rofi menu
RofiSel=$(echo -e "$options" | rofi -dmenu -theme-str "${r_override}" -config "${rofiConf}")
#// apply selected theme
if [ ! -z "${RofiSel}" ]; then
#// extract selected style number ('Style 1' -> '1')
selectedStyle=$(echo "${RofiSel}" | awk -F '\x00' '{print $1}' | sed 's/Style //')
#// notify the user
notify-send -a "t1" -r 91190 -t 2200 -i "${rofiAssetDir}/theme_style_${selectedStyle}.png" "Style ${selectedStyle} applied..."
#// save selection in config file
set_conf "themeSelect" "${selectedStyle}"
fi

121
scripts/themeswitch.sh Executable file
View File

@@ -0,0 +1,121 @@
#!/usr/bin/env bash
#// set variables
scrDir="$(dirname "$(realpath "$0")")"
source "${scrDir}/globalcontrol.sh"
[ -z "${hydeTheme}" ] && echo "ERROR: unable to detect theme" && exit 1
get_themes
#// define functions
Theme_Change()
{
local x_switch=$1
for i in ${!thmList[@]} ; do
if [ "${thmList[i]}" == "${hydeTheme}" ] ; then
if [ "${x_switch}" == 'n' ] ; then
setIndex=$(( (i + 1) % ${#thmList[@]} ))
elif [ "${x_switch}" == 'p' ] ; then
setIndex=$(( i - 1 ))
fi
themeSet="${thmList[setIndex]}"
break
fi
done
}
#// evaluate options
while getopts "nps:" option ; do
case $option in
n ) # set next theme
Theme_Change n
export xtrans="grow" ;;
p ) # set previous theme
Theme_Change p
export xtrans="outer" ;;
s ) # set selected theme
themeSet="$OPTARG" ;;
* ) # invalid option
echo "... invalid option ..."
echo "$(basename "${0}") -[option]"
echo "n : set next theme"
echo "p : set previous theme"
echo "s : set input theme"
exit 1 ;;
esac
done
#// update control file
if ! $(echo "${thmList[@]}" | grep -wq "${themeSet}") ; then
themeSet="${hydeTheme}"
fi
set_conf "hydeTheme" "${themeSet}"
echo ":: applying theme :: \"${themeSet}\""
export reload_flag=1
source "${scrDir}/globalcontrol.sh"
#// hypr
[ -n "$HYPRLAND_INSTANCE_SIGNATURE" ] && hyprctl keyword misc:disable_autoreload 1 -q
sed '1d' "${hydeThemeDir}/hypr.theme" > "${confDir}/hypr/themes/theme.conf" # Useless and already handled by swwwallbash.sh but kept for robustness
gtkTheme="$(
{ grep -q "^[[:space:]]*\$GTK[-_]THEME\s*=" "${hydeThemeDir}/hypr.theme" && grep "^[[:space:]]*\$GTK[-_]THEME\s*=" "${hydeThemeDir}/hypr.theme" | cut -d '=' -f2 | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' ;} ||
grep 'gsettings set org.gnome.desktop.interface gtk-theme' "${hydeThemeDir}/hypr.theme" | awk -F "'" '{print $((NF - 1))}'
)"
gtkIcon="$(
{ grep -q "^[[:space:]]*\$ICON[-_]THEME\s*=" "${hydeThemeDir}/hypr.theme" && grep "^[[:space:]]*\$ICON[-_]THEME\s*=" "${hydeThemeDir}/hypr.theme" | cut -d '=' -f2 | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' ;} ||
grep 'gsettings set org.gnome.desktop.interface icon-theme' "${hydeThemeDir}/hypr.theme" | awk -F "'" '{print $(NF - 1)}'
)"
#// qtct
sed -i "/^icon_theme=/c\icon_theme=${gtkIcon}" "${confDir}/qt5ct/qt5ct.conf"
sed -i "/^icon_theme=/c\icon_theme=${gtkIcon}" "${confDir}/qt6ct/qt6ct.conf"
sed -i "/^Theme=/c\Theme=${gtkIcon}" "${confDir}/kdeglobals"
#// gtk3
sed -i "/^gtk-theme-name=/c\gtk-theme-name=${gtkTheme}" $confDir/gtk-3.0/settings.ini
sed -i "/^gtk-icon-theme-name=/c\gtk-icon-theme-name=${gtkIcon}" $confDir/gtk-3.0/settings.ini
#// gtk4
if [ -d /run/current-system/sw/share/themes ] ; then
themeDir=/run/current-system/sw/share/themes
else
themeDir=~/.themes
fi
rm -rf "${confDir}/gtk-4.0"
ln -s "${themeDir}/${gtkTheme}/gtk-4.0" "${confDir}/gtk-4.0"
#// flatpak GTK
if pkg_installed flatpak ; then
if [ "${enableWallDcol}" -eq 0 ] ; then
flatpak --user override --env=GTK_THEME="${gtkTheme}"
flatpak --user override --env=ICON_THEME="${gtkIcon}"
else
flatpak --user override --env=GTK_THEME="Wallbash-Gtk"
flatpak --user override --env=ICON_THEME="${gtkIcon}"
fi
fi
#// wallpaper
"${scrDir}/swwwallpaper.sh" -s "$(readlink "${hydeThemeDir}/wall.set")"

4
scripts/tmux-session-manager Executable file
View File

@@ -0,0 +1,4 @@
#!/usr/bin/env bash
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
exec "$SCRIPT_DIR/tmux-session-manager.sh" "$@"

409
scripts/tmux-session-manager.sh Executable file
View File

@@ -0,0 +1,409 @@
#!/usr/bin/env bash
# Tmux Session Manager - Manage multiple named tmux sessions with persistence
# Usage: tmux-session-manager.sh [session-name] [action]
# Actions: save, restore, list, delete
set -euo pipefail
SESSION_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/tmux/sessions"
RESURRECT_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/tmux/resurrect"
# Create directories if they don't exist
mkdir -p "$SESSION_DIR" "$RESURRECT_DIR"
show_usage() {
cat <<EOF
Tmux Session Manager - Manage multiple named tmux sessions with persistence
Usage: tmux-session-manager [command] [options]
Commands:
list List all saved session configurations
create <name> Create or switch to a named session
save <name> Manually save current session state
restore <name> Restore a specific named session
delete <name> Delete a named session configuration
restore-all Restore all sessions at once
auto-save Automatically save all active sessions (for cron/timer)
Examples:
tmux-session-manager create main # Create/switch to 'main' session
tmux-session-manager save work # Save current session as 'work'
tmux-session-manager restore dev # Restore 'dev' session
tmux-session-manager list # List all sessions
EOF
}
last_snapshot_sessions() {
local last_file="$RESURRECT_DIR/last"
if [ ! -f "$last_file" ]; then
return 0
fi
awk -F '\t' '$1 == "pane" { print $2 }' "$last_file" | sort -u
}
session_path_matches_name() {
local session="$1"
local desired_name="$2"
local desired_basename="$desired_name"
local path=""
if [[ "$desired_name" == _* ]]; then
desired_basename=".${desired_name#_}"
fi
while IFS= read -r path; do
[ -n "$path" ] || continue
if [ "$(basename "$path")" = "$desired_basename" ]; then
return 0
fi
done < <(tmux list-panes -t "=${session}" -F "#{pane_current_path}" 2>/dev/null)
if [ "$desired_name" = "main" ]; then
while IFS= read -r path; do
[ -n "$path" ] || continue
if [ "$path" = "$HOME" ]; then
return 0
fi
done < <(tmux list-panes -t "=${session}" -F "#{pane_current_path}" 2>/dev/null)
fi
return 1
}
run_resurrect_restore() {
local restore_script
restore_script="$(tmux show-options -gv @resurrect-restore-script-path 2>/dev/null || true)"
if [ -z "$restore_script" ]; then
echo "Error: Could not determine resurrect restore script path"
return 1
fi
tmux run-shell "$restore_script"
}
run_resurrect_save() {
local save_script
save_script="$(tmux show-options -gv @resurrect-save-script-path 2>/dev/null || true)"
if [ -z "$save_script" ]; then
echo "Error: Could not determine resurrect save script path"
return 1
fi
tmux run-shell "$save_script quiet"
}
save_session() {
local session_name="$1"
# Get the current session if not specified
if [ -z "$session_name" ]; then
session_name=$(tmux display-message -p '#{session_name}' 2>/dev/null || echo "")
if [ -z "$session_name" ]; then
echo "Error: No active tmux session found"
return 1
fi
fi
# Check if session exists
if ! tmux has-session -t "$session_name" 2>/dev/null; then
echo "Error: Session '$session_name' does not exist"
return 1
fi
# Save session using resurrect script
run_resurrect_save
echo "Saving session '$session_name'..."
sleep 1
# Also create a backup of the session state
local backup_file="$SESSION_DIR/${session_name}.state"
tmux capture-pane -t "$session_name" -p > "$backup_file" || true
echo "Session '$session_name' saved"
}
restore_session() {
local session_name="$1"
local bootstrap_session="__tsm_restore_bootstrap"
local trigger_session=""
local restored=0
local renamed=0
local candidate_session=""
local -a before_sessions=()
local -a after_sessions=()
local -a new_sessions=()
if [ -z "$session_name" ]; then
echo "Error: Session name required"
show_usage
return 1
fi
# Use resurrect to restore the most recent snapshot.
# A target session might not currently exist, so trigger restore from any live session.
echo "Restoring session '$session_name' from latest resurrect save..."
while IFS= read -r session; do
[ -n "$session" ] && before_sessions+=("$session")
done < <(tmux list-sessions -F "#{session_name}" 2>/dev/null || true)
if ! tmux list-sessions >/dev/null 2>&1; then
tmux new-session -d -s "$bootstrap_session"
trigger_session="$bootstrap_session"
else
while IFS= read -r session; do
if [ -n "$session" ]; then
trigger_session="$session"
break
fi
done < <(tmux list-sessions -F "#{session_name}" 2>/dev/null)
fi
if [ -z "$trigger_session" ]; then
echo "Error: Could not find a tmux session to trigger restore"
return 1
fi
run_resurrect_restore
for _ in $(seq 1 20); do
if tmux has-session -t "$session_name" 2>/dev/null; then
restored=1
break
fi
sleep 0.25
done
while IFS= read -r session; do
[ -n "$session" ] && after_sessions+=("$session")
done < <(tmux list-sessions -F "#{session_name}" 2>/dev/null || true)
if [ "$restored" -eq 0 ]; then
for session in "${after_sessions[@]}"; do
local existed=0
for before in "${before_sessions[@]}"; do
if [ "$session" = "$before" ]; then
existed=1
break
fi
done
if [ "$existed" -eq 0 ]; then
new_sessions+=("$session")
fi
done
# Give resurrect a moment to fully materialize pane paths before matching.
for _ in $(seq 1 20); do
candidate_session=""
for session in "${new_sessions[@]}"; do
if session_path_matches_name "$session" "$session_name"; then
candidate_session="$session"
break
fi
done
# If no brand-new session matched, fall back to any current session.
# This handles cases where restore reused existing numeric sessions.
if [ -z "$candidate_session" ]; then
for session in "${after_sessions[@]}"; do
if [ "$session" = "$session_name" ]; then
continue
fi
if session_path_matches_name "$session" "$session_name"; then
candidate_session="$session"
break
fi
done
fi
if [ -n "$candidate_session" ]; then
break
fi
sleep 0.25
done
if [ -z "$candidate_session" ] && [ "${#new_sessions[@]}" -eq 1 ]; then
candidate_session="${new_sessions[0]}"
fi
if [ -n "$candidate_session" ] && ! tmux has-session -t "$session_name" 2>/dev/null; then
tmux rename-session -t "=${candidate_session}" "$session_name"
restored=1
renamed=1
fi
fi
if [ "$trigger_session" = "$bootstrap_session" ] && tmux has-session -t "$bootstrap_session" 2>/dev/null; then
tmux kill-session -t "$bootstrap_session" 2>/dev/null || true
fi
if [ "$restored" -eq 1 ]; then
if [ "$renamed" -eq 1 ]; then
echo "Session '$session_name' restored by renaming '$candidate_session'"
else
echo "Session '$session_name' restored and available"
fi
else
local snapshot_sessions
snapshot_sessions="$(last_snapshot_sessions | tr '\n' ' ' | sed 's/[[:space:]]*$//')"
if [ -n "$snapshot_sessions" ]; then
echo "Restore was triggered, but '$session_name' was not found in the latest snapshot (contains: $snapshot_sessions)"
else
echo "Restore was triggered, but '$session_name' was not found and no snapshot sessions were detected"
fi
return 1
fi
}
create_session() {
local session_name="$1"
if [ -z "$session_name" ]; then
echo "Error: Session name required"
show_usage
return 1
fi
# Check if session already exists
if tmux has-session -t "$session_name" 2>/dev/null; then
echo "Session '$session_name' already exists, attaching..."
tmux attach-session -t "=${session_name}"
else
echo "Creating new session '$session_name'..."
tmux new-session -d -s "$session_name"
tmux send-keys -t "$session_name" "# Session: $session_name" Enter
echo "Session '$session_name' created"
tmux attach-session -t "=${session_name}"
fi
}
list_sessions() {
echo "Available tmux sessions:"
tmux list-sessions -F "#{session_name}: #{session_windows} windows" 2>/dev/null || echo "No tmux sessions found"
echo ""
echo "Session names in latest resurrect snapshot:"
local snapshot_sessions
snapshot_sessions="$(last_snapshot_sessions)"
if [ -n "$snapshot_sessions" ]; then
echo "$snapshot_sessions"
else
echo "No resurrect snapshot found"
fi
echo ""
echo "Saved session labels (local backups):"
if [ -d "$SESSION_DIR" ]; then
ls -1 "$SESSION_DIR" 2>/dev/null | sed 's/.state$//' | sort | uniq || echo "No saved sessions"
else
echo "No saved sessions"
fi
}
delete_session() {
local session_name="$1"
if [ -z "$session_name" ]; then
echo "Error: Session name required"
return 1
fi
# Kill the tmux session if it exists
if tmux has-session -t "$session_name" 2>/dev/null; then
tmux kill-session -t "=${session_name}"
echo "Killed tmux session '$session_name'"
fi
# Remove saved state files
rm -f "$SESSION_DIR/${session_name}.state"
echo "Deleted session configuration '$session_name'"
}
restore_all_sessions() {
local bootstrap_session="__tsm_restore_bootstrap"
local trigger_session=""
echo "Restoring all sessions from latest resurrect save..."
if ! tmux list-sessions >/dev/null 2>&1; then
tmux new-session -d -s "$bootstrap_session"
trigger_session="$bootstrap_session"
else
while IFS= read -r session; do
if [ -n "$session" ]; then
trigger_session="$session"
break
fi
done < <(tmux list-sessions -F "#{session_name}" 2>/dev/null)
fi
if [ -z "$trigger_session" ]; then
echo "Error: Could not find a tmux session to trigger restore"
return 1
fi
run_resurrect_restore
sleep 1
if [ "$trigger_session" = "$bootstrap_session" ] && tmux has-session -t "$bootstrap_session" 2>/dev/null; then
tmux kill-session -t "=${bootstrap_session}" 2>/dev/null || true
fi
echo "Restore triggered for all sessions"
}
auto_save() {
echo "Auto-saving all active tmux sessions..."
while IFS= read -r session; do
save_session "$session" || true
done < <(tmux list-sessions -F "#{session_name}" 2>/dev/null)
echo "All sessions auto-saved"
}
# Main command dispatcher
main() {
local command="${1:-list}"
local arg="${2:-}"
case "$command" in
list)
list_sessions
;;
create)
create_session "$arg"
;;
save)
save_session "$arg"
;;
restore)
restore_session "$arg"
;;
delete)
delete_session "$arg"
;;
restore-all)
restore_all_sessions
;;
auto-save)
auto_save
;;
--help|-h|help)
show_usage
;;
*)
echo "Unknown command: $command"
show_usage
return 1
;;
esac
}
main "$@"

View File

@@ -0,0 +1,22 @@
{ pkgs }:
pkgs.writeShellScriptBin "togglepowermode" ''
# Toggle between performance and power saving mode
config_dir="$HOME/.config/hypr"
power_mode_file="$config_dir/power_mode"
mkdir -p "$config_dir"
# Read current mode or default to balanced
current_mode=$(cat "$power_mode_file" 2>/dev/null || echo "balanced")
if [ "$current_mode" = "powersave" ]; then
# Switch to performance mode
echo "performance" > "$power_mode_file"
echo "Performance Mode"
else
# Switch to powersave mode
echo "powersave" > "$power_mode_file"
echo "Power Saving Mode"
fi
''

View File

@@ -0,0 +1,22 @@
#!/usr/bin/env bash
# Update Hyprland border colors based on pywal colors
# This script reads the pywal colors.json and applies them to Hyprland
COLORS_JSON="$HOME/.cache/wal/colors.json"
if [[ ! -f "$COLORS_JSON" ]]; then
exit 1
fi
# Extract colors from pywal (remove the # prefix)
ACTIVE_COLOR=$(jq -r '.colors.color7' "$COLORS_JSON" | sed 's/#//')
INACTIVE_COLOR=$(jq -r '.colors.color8' "$COLORS_JSON" | sed 's/#//')
# Add alpha channel (ff for fully opaque)
ACTIVE_COLOR="0xff${ACTIVE_COLOR}"
INACTIVE_COLOR="0xff${INACTIVE_COLOR}"
# Apply colors to Hyprland
hyprctl keyword "general:col.active_border" "$ACTIVE_COLOR"
hyprctl keyword "general:col.inactive_border" "$INACTIVE_COLOR"

163
scripts/volumecontrol.sh Executable file
View File

@@ -0,0 +1,163 @@
#!/usr/bin/env bash
# Source global control script
scrDir=$(dirname "$(realpath "$0")")
source "$scrDir/globalcontrol.sh"
# Check if SwayOSD is installed
use_swayosd=false
if command -v swayosd-client >/dev/null 2>&1 && pgrep -x swayosd-server >/dev/null; then
use_swayosd=true
fi
# Define functions
print_usage() {
cat <<EOF
Usage: $(basename "$0") -[device] <action> [step]
Devices/Actions:
-i Input device
-o Output device
-p Player application
-s Select output device
-t Toggle to next output device
Actions:
i Increase volume
d Decrease volume
m Toggle mute
Optional:
step Volume change step (default: 5)
Examples:
$(basename "$0") -o i 5 # Increase output volume by 5
$(basename "$0") -i m # Toggle input mute
$(basename "$0") -p spotify d 10 # Decrease Spotify volume by 10
$(basename "$0") -p '' d 10 # Decrease volume by 10 for all players
EOF
exit 1
}
notify_vol() {
angle=$(( (($vol + 2) / 5) * 5 ))
ico="${icodir}/vol-${angle}.svg"
bar=$(seq -s "." $(($vol / 15)) | sed 's/[0-9]//g')
notify-send -a "t2" -r 91190 -t 800 -i "${ico}" "${vol}${bar}" "${nsink}"
}
notify_mute() {
mute=$(pamixer "${srce}" --get-mute | cat)
[ "${srce}" == "--default-source" ] && dvce="mic" || dvce="speaker"
if [ "${mute}" == "true" ]; then
notify-send -a "t2" -r 91190 -t 800 -i "${icodir}/muted-${dvce}.svg" "muted" "${nsink}"
else
notify-send -a "t2" -r 91190 -t 800 -i "${icodir}/unmuted-${dvce}.svg" "unmuted" "${nsink}"
fi
}
change_volume() {
local action=$1
local step=$2
local device=$3
local delta="-"
local mode="--output-volume"
[ "${action}" = "i" ] && delta="+"
[ "${srce}" = "--default-source" ] && mode="--input-volume"
case $device in
"pamixer")
$use_swayosd && swayosd-client ${mode} "${delta}${step}" && exit 0
pamixer $srce -"$action" "$step"
vol=$(pamixer $srce --get-volume)
;;
"playerctl")
playerctl --player="$srce" volume "$(awk -v step="$step" 'BEGIN {print step/100}')${delta}"
vol=$(playerctl --player="$srce" volume | awk '{ printf "%.0f\n", $0 * 100 }')
;;
esac
notify_vol
}
toggle_mute() {
local device=$1
local mode="--output-volume"
[ "${srce}" = "--default-source" ] && mode="--input-volume"
case $device in
"pamixer")
$use_swayosd && swayosd-client "${mode}" mute-toggle && exit 0
pamixer $srce -t
notify_mute
;;
"playerctl")
local volume_file="/tmp/$(basename "$0")_last_volume_${srce:-all}"
if [ "$(playerctl --player="$srce" volume | awk '{ printf "%.2f", $0 }')" != "0.00" ]; then
playerctl --player="$srce" volume | awk '{ printf "%.2f", $0 }' > "$volume_file"
playerctl --player="$srce" volume 0
else
if [ -f "$volume_file" ]; then
last_volume=$(cat "$volume_file")
playerctl --player="$srce" volume "$last_volume"
else
playerctl --player="$srce" volume 0.5 # Default to 50% if no saved volume
fi
fi
notify_mute
;;
esac
}
select_output() {
local selection=$1
if [ -n "$selection" ]; then
device=$(pactl list sinks | grep -C2 -F "Description: $selection" | grep Name | cut -d: -f2 | xargs)
if pactl set-default-sink "$device"; then
notify-send -t 2000 -r 2 -u low "Activated: $selection"
else
notify-send -t 2000 -r 2 -u critical "Error activating $selection"
fi
else
pactl list sinks | grep -ie "Description:" | awk -F ': ' '{print $2}' | sort
fi
}
toggle_output() {
local default_sink=$(pamixer --get-default-sink | awk -F '"' 'END{print $(NF - 1)}')
mapfile -t sink_array < <(select_output)
local current_index=$(printf '%s\n' "${sink_array[@]}" | grep -n "$default_sink" | cut -d: -f1)
local next_index=$(( (current_index % ${#sink_array[@]}) + 1 ))
local next_sink="${sink_array[next_index-1]}"
select_output "$next_sink"
}
# Main script logic
# Set default variables
icodir="${confDir}/dunst/icons/vol"
step=5
# Parse options
while getopts "iop:st" opt; do
case $opt in
i) device="pamixer"; srce="--default-source"; nsink=$(pamixer --list-sources | awk -F '"' 'END {print $(NF - 1)}') ;;
o) device="pamixer"; srce=""; nsink=$(pamixer --get-default-sink | awk -F '"' 'END{print $(NF - 1)}') ;;
p) device="playerctl"; srce="${OPTARG}"; nsink=$(playerctl --list-all | grep -w "$srce") ;;
s) select_output "$(select_output | rofi -dmenu -config "${confDir}/rofi/notification.rasi")"; exit ;;
t) toggle_output; exit ;;
*) print_usage ;;
esac
done
shift $((OPTIND-1))
# Check if device is set
[ -z "$device" ] && print_usage
# Execute action
case $1 in
i|d) change_volume "$1" "${2:-$step}" "$device" ;;
m) toggle_mute "$device" ;;
*) print_usage ;;
esac

220
scripts/wallbash.sh Executable file
View File

@@ -0,0 +1,220 @@
#!/usr/bin/env bash
#|---/ /+---------------------------------------------+---/ /|#
#|--/ /-| Script to generate color palette from image |--/ /-|#
#|-/ /--| Prasanth Rangan |-/ /--|#
#|/ /---+---------------------------------------------+/ /---|#
#// accent color profile
colorProfile="default"
wallbashCurve="32 50\n42 46\n49 40\n56 39\n64 38\n76 37\n90 33\n94 29\n100 20"
sortMode="auto"
while [ $# -gt 0 ] ; do
case "$1" in
-v|--vibrant) colorProfile="vibrant"
wallbashCurve="18 99\n32 97\n48 95\n55 90\n70 80\n80 70\n88 60\n94 40\n99 24"
;;
-p|--pastel) colorProfile="pastel"
wallbashCurve="10 99\n17 66\n24 49\n39 41\n51 37\n58 34\n72 30\n84 26\n99 22"
;;
-m|--mono) colorProfile="mono"
wallbashCurve="10 0\n17 0\n24 0\n39 0\n51 0\n58 0\n72 0\n84 0\n99 0"
;;
-c|--custom)
shift
if [ -n "${1}" ] && [[ "${1}" =~ ^([0-9]+[[:space:]][0-9]+\\n){8}[0-9]+[[:space:]][0-9]+$ ]] ; then
colorProfile="custom"
wallbashCurve="${1}"
else
echo "Error: Custom color curve format is incorrect ${1}"
exit 1
fi
;;
-d|--dark) sortMode="dark"
colSort=""
;;
-l|--light) sortMode="light"
colSort="-r"
;;
*) break
;;
esac
shift
done
#// set variables
wallbashImg="${1}"
wallbashColors=4
wallbashFuzz=70
wallbashRaw="${2:-"${wallbashImg}"}.mpc"
wallbashOut="${2:-"${wallbashImg}"}.dcol"
wallbashCache="${2:-"${wallbashImg}"}.cache"
#// color modulations
pryDarkBri=116
pryDarkSat=110
pryDarkHue=88
pryLightBri=100
pryLightSat=100
pryLightHue=114
txtDarkBri=188
txtLightBri=16
#// input image validation
if [ -z "${wallbashImg}" ] || [ ! -f "${wallbashImg}" ] ; then
echo "Error: Input file not found!"
exit 1
fi
magick -ping "${wallbashImg}" -format "%t" info: &> /dev/null
if [ $? -ne 0 ] ; then
echo "Error: Unsuppoted image format ${wallbashImg}"
exit 1
fi
echo -e "wallbash ${colorProfile} profile :: ${sortMode} :: Colors ${wallbashColors} :: Fuzzy ${wallbashFuzz} :: \"${wallbashOut}\""
mkdir -p "${cacheDir}/${cacheThm}"
> "${wallbashOut}"
#// define functions
rgb_negative() {
local inCol=$1
local r=${inCol:0:2}
local g=${inCol:2:2}
local b=${inCol:4:2}
local r16=$((16#$r))
local g16=$((16#$g))
local b16=$((16#$b))
r=$(printf "%02X" $((255 - $r16)))
g=$(printf "%02X" $((255 - $g16)))
b=$(printf "%02X" $((255 - $b16)))
echo "${r}${g}${b}"
}
rgba_convert() {
local inCol=$1
local r=${inCol:0:2}
local g=${inCol:2:2}
local b=${inCol:4:2}
local r16=$((16#$r))
local g16=$((16#$g))
local b16=$((16#$b))
printf "rgba(%d,%d,%d,\1341)\n" "$r16" "$g16" "$b16"
}
fx_brightness() {
local inCol="${1}"
local fxb=$(magick "${inCol}" -colorspace gray -format "%[fx:mean]" info:)
if awk -v fxb="${fxb}" 'BEGIN {exit !(fxb < 0.5)}' ; then
return 0 #// echo ":: ${fxb} :: dark :: ${inCol}"
else
return 1 #// echo ":: ${fxb} :: light :: ${inCol}"
fi
}
#// quantize raw primary colors
magick -quiet -regard-warnings "${wallbashImg}"[0] -alpha off +repage "${wallbashRaw}"
readarray -t dcolRaw <<< $(magick "${wallbashRaw}" -depth 8 -fuzz ${wallbashFuzz}% +dither -kmeans ${wallbashColors} -depth 8 -format "%c" histogram:info: | sed -n 's/^[ ]*\(.*\):.*[#]\([0-9a-fA-F]*\) .*$/\1,\2/p' | sort -r -n -k 1 -t ",")
if [ ${#dcolRaw[*]} -lt ${wallbashColors} ] ; then
echo -e "RETRYING :: distinct colors ${#dcolRaw[*]} is less than ${wallbashColors} palette color..."
readarray -t dcolRaw <<< $(magick "${wallbashRaw}" -depth 8 -fuzz ${wallbashFuzz}% +dither -kmeans $((wallbashColors + 2)) -depth 8 -format "%c" histogram:info: | sed -n 's/^[ ]*\(.*\):.*[#]\([0-9a-fA-F]*\) .*$/\1,\2/p' | sort -r -n -k 1 -t ",")
fi
#// sort colors based on image brightness
if [ "${sortMode}" == "auto" ] ; then
if fx_brightness "${wallbashRaw}" ; then
sortMode="dark"
colSort=""
else
sortMode="light"
colSort="-r"
fi
fi
echo "dcol_mode=\"${sortMode}\"" >> "${wallbashOut}"
dcolHex=($(echo -e "${dcolRaw[@]:0:$wallbashColors}" | tr ' ' '\n' | awk -F ',' '{print $2}' | sort ${colSort}))
greyCheck=$(magick "${wallbashRaw}" -colorspace HSL -channel g -separate +channel -format "%[fx:mean]" info:)
if (( $(awk 'BEGIN {print ('"$greyCheck"' < 0.12)}') )); then
wallbashCurve="10 0\n17 0\n24 0\n39 0\n51 0\n58 0\n72 0\n84 0\n99 0"
fi
#// loop for derived colors
for (( i=0; i<${wallbashColors}; i++ )) ; do
#// generate missing primary colors
if [ -z "${dcolHex[i]}" ] ; then
if fx_brightness "xc:#${dcolHex[i - 1]}" ; then
modBri=$pryDarkBri
modSat=$pryDarkSat
modHue=$pryDarkHue
else
modBri=$pryLightBri
modSat=$pryLightSat
modHue=$pryLightHue
fi
echo -e "dcol_pry$((i + 1)) :: regen missing color"
dcol[i]=$(magick xc:"#${dcolHex[i - 1]}" -depth 8 -normalize -modulate ${modBri},${modSat},${modHue} -depth 8 -format "%c" histogram:info: | sed -n 's/^[ ]*\(.*\):.*[#]\([0-9a-fA-F]*\) .*$/\2/p')
fi
echo "dcol_pry$((i + 1))=\"${dcolHex[i]}\"" >> "${wallbashOut}"
echo "dcol_pry$((i + 1))_rgba=\"$( rgba_convert "${dcolHex[i]}" )\"" >> "${wallbashOut}"
#// generate primary text colors
nTxt=$(rgb_negative ${dcolHex[i]})
if fx_brightness "xc:#${dcolHex[i]}" ; then
modBri=$txtDarkBri
else
modBri=$txtLightBri
fi
tcol=$(magick xc:"#${nTxt}" -depth 8 -normalize -modulate ${modBri},10,100 -depth 8 -format "%c" histogram:info: | sed -n 's/^[ ]*\(.*\):.*[#]\([0-9a-fA-F]*\) .*$/\2/p')
echo "dcol_txt$((i + 1))=\"${tcol}\"" >> "${wallbashOut}"
echo "dcol_txt$((i + 1))_rgba=\"$( rgba_convert "${tcol}" )\"" >> "${wallbashOut}"
#// generate accent colors
xHue=$(magick xc:"#${dcolHex[i]}" -colorspace HSB -format "%c" histogram:info: | awk -F '[hsb(,]' '{print $2}')
acnt=1
echo -e "${wallbashCurve}" | sort -n ${colSort} | while read -r xBri xSat
do
acol=$(magick xc:"hsb(${xHue},${xSat}%,${xBri}%)" -depth 8 -format "%c" histogram:info: | sed -n 's/^[ ]*\(.*\):.*[#]\([0-9a-fA-F]*\) .*$/\2/p')
echo "dcol_$((i + 1))xa${acnt}=\"${acol}\"" >> "${wallbashOut}"
echo "dcol_$((i + 1))xa${acnt}_rgba=\"$( rgba_convert "${acol}" )\"" >> "${wallbashOut}"
((acnt++))
done
done
#// cleanup temp cache
rm -f "${wallbashRaw}" "${wallbashCache}"

22
scripts/wallbashcava.sh Executable file
View File

@@ -0,0 +1,22 @@
#!/usr/bin/env sh
scrDir=`dirname "$(realpath "$0")"`
source $scrDir/globalcontrol.sh
cvaDir="${confDir}/cava"
CAVA_CONF="${cvaDir}/config"
WALL_DCOL="${cvaDir}/Wall-Dcol"
KEY_LINE='### HYPRDOTS CAVA: Autogenerated line below for wallbash###'
if pkg_installed cava ; then
sed -i "/${KEY_LINE}/,\$d" "${CAVA_CONF}"
if grep -q "${KEY_LINE}" "${CAVA_CONF}"; then
sed -i "/${KEY_LINE}/r ${WALL_DCOL}" "${CAVA_CONF}"
else
echo "${KEY_LINE}" >> "${CAVA_CONF}"
sed -i "/${KEY_LINE}/r ${WALL_DCOL}" "${CAVA_CONF}"
fi
pkill -USR2 cava
fi

41
scripts/wallbashcode.sh Executable file
View File

@@ -0,0 +1,41 @@
#!/usr/bin/env bash
#// set variables
scrDir="$(dirname "$(realpath "$0")")"
source "${scrDir}/globalcontrol.sh"
readarray -t codeConf < <(find "${confDir}" -mindepth 1 -maxdepth 1 -type d -name "Code*" -o -name "VSCodium*" -o -name "Cursor*" | sort)
readarray -t codeVsix < <(find "$HOME" -mindepth 1 -maxdepth 1 -type d -name ".vscode*" -o -name ".cursor" | sort)
tmpFile="/tmp/$(id -u)$(basename ${0}).tmp"
tgtFile="extensions/undefined_publisher.wallbash-0.0.1/themes/wallbash-color-theme.json"
#// install ext
for i in "${!codeVsix[@]}" ;do
if [ ! -f "${codeVsix[i]}/${tgtFile}" ] ; then
[ -f "${cacheDir}/landing/Code_Wallbash.vsix" ] || curl -L -o "${cacheDir}/landing/Code_Wallbash.vsix" https://github.com/prasanthrangan/hyprdots/raw/main/Source/arcs/Code_Wallbash.vsix
case ${codeVsix[i]} in
*".cursor"*)
echo "[wallbashcode] Cursor IDE: Manual intervention required for extension installation."
echo "[wallbashcode] Read the instructions here: https://www.cursor.com/how-to-install-extension "
;;
*)
pkg_installed code-insiders && code-insiders --install-extension "${cacheDir}/landing/Code_Wallbash.vsix"
pkg_installed code && code --install-extension "${cacheDir}/landing/Code_Wallbash.vsix"
pkg_installed vscodium && vscodium --install-extension "${cacheDir}/landing/Code_Wallbash.vsix"
;;
esac
fi
[ -d "$(dirname "${codeVsix[i]}/${tgtFile}")" ] && cp "${cacheDir}/landing/wallbashcode.json" "${codeVsix[i]}/${tgtFile}"
done
#// apply theme
for i in "${!codeConf[@]}" ; do
[ -d "${codeConf[i]}/User" ] || continue
[ -f "${codeConf[i]}/User/settings.json" ] || echo -e "{\n \"workbench.colorTheme\":\"wallbash\" \n}" > "${codeConf[i]}/User/settings.json"
extTheme="$(jq -r '.["workbench.colorTheme"]' "${codeConf[i]}/User/settings.json")"
if [ "${extTheme}" != "wallbash" ] ; then
jq '.["workbench.colorTheme"] = "wallbash"' "${codeConf[i]}/User/settings.json" > "${tmpFile}" && mv "${tmpFile}" "${codeConf[i]}/User/settings.json"
fi
done

30
scripts/wallbashdiscord.sh Executable file
View File

@@ -0,0 +1,30 @@
#!/usr/bin/env bash
#// source variables
scrDir="$(dirname "$(realpath "$0")")"
source "${scrDir}/globalcontrol.sh"
discord_col="${cacheDir}/landing/discord.css"
declare -a client_list=()
#// List more clients
client_list+=("$HOME/.config/Vencord/settings/quickCss.css")
client_list+=("$HOME/.config/vesktop/settings/quickCss.css")
client_list+=("$HOME/.var/app/dev.vencord.Vesktop/config/vesktop/settings/quickCss.css")
client_list+=("$HOME/.config/WebCord/Themes/theme.css")
client_list+=("$HOME/.var/app/io.github.spacingbat3.webcord/config/WebCord/Themes/theme.css")
client_list+=("$HOME/.var/app/xyz.armcord.ArmCord/config/ArmCord/themes/theme.css")
#// main loop
for client_css in "${client_list[@]}" ; do
eval client_css="${client_css}"
if [[ -d $(dirname "${client_css}") ]] ; then
cp "${discord_col}" "${client_css}"
fi
done

16
scripts/wallbashdunst.sh Executable file
View File

@@ -0,0 +1,16 @@
#!/usr/bin/env bash
# set variables
scrDir=`dirname "$(realpath "$0")"`
source $scrDir/globalcontrol.sh
dstDir="${confDir}/dunst"
# regen conf
export hypr_border
envsubst < "${dstDir}/dunst.conf" > "${dstDir}/dunstrc"
envsubst < "${dstDir}/wallbash.conf" >> "${dstDir}/dunstrc"
killall dunst
dunst &

23
scripts/wallbashqt.sh Executable file
View File

@@ -0,0 +1,23 @@
#!/usr/bin/env bash
# set variables
scrDir=`dirname "$(realpath "$0")"`
source $scrDir/globalcontrol.sh
# sync qt5 and qt6 colors
cp "${confDir}/qt5ct/colors.conf" "${confDir}/qt6ct/colors.conf"
# restart dolphin
a_ws=$(hyprctl -j activeworkspace | jq '.id')
dpid=$(hyprctl -j clients | jq --arg wid "$a_ws" '.[] | select(.workspace.id == ($wid | tonumber)) | select(.class == "org.kde.dolphin") | .pid')
if [ ! -z ${dpid} ] ; then
hyprctl dispatch closewindow pid:${dpid}
hyprctl dispatch exec dolphin &
fi

42
scripts/wallbashspotify.sh Executable file
View File

@@ -0,0 +1,42 @@
#!/usr/bin/env sh
# set variables
scrDir="$(dirname "$(realpath "$0")")"
source "${scrDir}/globalcontrol.sh"
# regen conf
if pkg_installed spotify && pkg_installed spicetify-cli ; then
if [ ! -w /opt/spotify ] || [ ! -w /opt/spotify/Apps ]; then
notify-send -a "Hyprdots" "Permission needed for Wallbash Spotify theme"
pkexec chmod a+wr /opt/spotify
pkexec chmod a+wr /opt/spotify/Apps -R
fi
if [ "$(spicetify config | awk '{if ($1=="color_scheme") print $2}')" != "Wallbash" ] || [[ "${*}" == *"--reset"* ]] ; then
spicetify &> /dev/null
mkdir -p ~/.config/spotify
touch ~/.config/spotify/prefs
sptfyConf=$(spicetify -c)
spotfy_flags='--ozone-platform=wayland'
sed -i -e "/^prefs_path/ s+=.*$+= $HOME/.config/spotify/prefs+g" \
-e "/^spotify_launch_flags/ s+=.*$+= $spotfy_flags+g" "$sptfyConf"
curl -L -o ${cacheDir}/landing/Spotify_Sleek.tar.gz https://github.com/prasanthrangan/hyprdots/raw/main/Source/arcs/Spotify_Sleek.tar.gz
tar -xzf ${cacheDir}/landing/Spotify_Sleek.tar.gz -C ~/.config/spicetify/Themes/
spicetify backup apply
spicetify config current_theme Sleek
spicetify config color_scheme Wallbash
spicetify apply
fi
if pgrep -x spotify > /dev/null ; then
pkill -x spicetify
spicetify -q watch -s &
fi
fi

61
scripts/wallbashtoggle.sh Executable file
View File

@@ -0,0 +1,61 @@
#!/usr/bin/env sh
#// set variables
scrDir="$(dirname "$(realpath "$0")")"
source "${scrDir}/globalcontrol.sh"
TgtScr="$scrDir/globalcontrol.sh"
rofiConf="${confDir}/rofi/wallbash.rasi"
wallbashModes=("theme" "auto" "dark" "light")
#// rofi select mode
rofi_wallbash()
{
[[ "${rofiScale}" =~ ^[0-9]+$ ]] || rofiScale=10
r_scale="configuration {font: \"JetBrainsMono Nerd Font ${rofiScale}\";}"
elem_border=$(( hypr_border * 4 ))
r_override="window{border-radius:${elem_border}px;} element{border-radius:${elem_border}px;}"
rofiSel=$(parallel echo {} ::: "${wallbashModes[@]}" | rofi -dmenu -theme-str "${r_scale}" -theme-str "${r_override}" -config "${rofiConf}" -select "${wallbashModes[${enableWallDcol}]}")
if [ ! -z "${rofiSel}" ] ; then
setMode="$(parallel --link echo {} ::: "${!wallbashModes[@]}" ::: "${wallbashModes[@]}" ::: "${rofiSel}" | awk '{if ($2 == $3) print $1}')"
else
exit 0
fi
}
#// switch mode
step_wallbash()
{
for i in "${!wallbashModes[@]}" ; do
if [ "${enableWallDcol}" == "${i}" ] ; then
if [ "${1}" == "n" ] ; then
setMode=$(( (i + 1) % ${#wallbashModes[@]} ))
elif [ "${1}" == "p" ] ; then
setMode=$(( i - 1 ))
fi
break
fi
done
}
#// apply wallbash mode
case "${1}" in
m|-m|--menu) rofi_wallbash ;;
n|-n|--next) step_wallbash n ;;
p|-p|--prev) step_wallbash p ;;
*) step_wallbash n ;;
esac
export reload_flag=1
[[ "${setMode}" -lt 0 ]] && setMode=$((${#wallbashModes[@]} - 1))
set_conf "enableWallDcol" "${setMode}"
"${scrDir}/themeswitch.sh"
notify-send -a "t1" -i "$HOME/.config/dunst/icons/hyprdots.png" " ${wallbashModes[setMode]} mode"

41
scripts/waybar-cava.sh Normal file
View File

@@ -0,0 +1,41 @@
#!/usr/bin/env bash
set -euo pipefail
bar="▁ ▂ ▃ ▄ ▅ ▆ ▇ █"
dict="s/;//g"
for ((i=0; i<${#bar}; i++)); do
dict+=";s/$i/${bar:$i:1}/g"
done
RUNTIME_DIR="${XDG_RUNTIME_DIR:-/tmp}"
pidfile="$RUNTIME_DIR/waybar-cava.pid"
if [ -f "$pidfile" ]; then
oldpid=$(cat "$pidfile" || true)
if [ -n "$oldpid" ] && kill -0 "$oldpid" 2>/dev/null; then
kill "$oldpid" 2>/dev/null || true
sleep 0.1
fi
fi
echo $$ > "$pidfile"
config_file=$(mktemp "$RUNTIME_DIR/waybar-cava.XXXXXX.conf")
cleanup() { rm -f "$config_file" "$pidfile"; }
trap cleanup EXIT INT TERM
cat >"$config_file" <<EOF
[general]
framerate = 30
bars = 10
[input]
method = pulse
source = auto
[output]
method = raw
raw_target = /dev/stdout
data_format = ascii
ascii_max_range = 7
EOF
exec cava -p "$config_file" | sed -u "$dict"

8
scripts/waybar-toggle.sh Normal file
View File

@@ -0,0 +1,8 @@
#!/usr/bin/env sh
if pgrep -f waybar >/dev/null; then
pkill -f waybar
else
waybar &
fi

130
scripts/waybar_cava.sh Executable file
View File

@@ -0,0 +1,130 @@
#!/usr/bin/env bash
#----- Optimized bars animation without much CPU usage increase --------
#----- Optimized bars animation without much CPU usage increase pt2 --------
# Default values
scrDir="$(dirname "$(realpath "$0")")"
# shellcheck disable=SC1091
source "${scrDir}/globalcontrol.sh"
usage() {
cat <<HELP
Usage: $(basename "$0") [OPTIONS]
Options:
--bar <waybar_cava_bar> Specify the characters to use for the bar animation (default: ▁▂▃▄▅▆▇█).
--width <waybar_cava_width> Specify the width of the bar.
--range <waybar_cava_range> Specify the range of the bar.
--help Display this help message and exit.
--restart Restart the waybar_cava.
--stb <waybar_cava_stbmode> Specify the standby mode for waybar cava (default: 0).
0: clean - totally hides the module
1: blank - makes module expand as spaces
2: full - occupies the module with full bar
3: low - makes the module display the lowest set bar
*: string - displays a string
HELP
exit 1
}
# Parse command line arguments using getopt
if ! ARGS=$(getopt -o "hr" -l "help,bar:,width:,range:,restart,stb:" -n "$0" -- "$@"); then
usage
fi
eval set -- "$ARGS"
while true; do
case "$1" in
--help | -h)
usage
;;
--bar)
waybar_cava_bar="$2"
shift 2
;;
--width)
waybar_cava_width="$2"
shift 2
;;
--range)
waybar_cava_range="$2"
shift 2
;;
--restart) # restart by killing all waybar_cava
pkill -f "cava -p /tmp/bar_cava_config"
exit 0
;;
--stb)
waybar_cava_stbmode="$2"
shift 2
;;
--)
shift
break
;;
*)
usage
;;
esac
done
bar="${waybar_cava_bar:-▁▂▃▄▅▆▇█}"
# // waybar_cava_stbmode - standby mode for waybar cava - default 0
# 0: clean - totally hides the module
# 1: blank - makes module expand as spaces
# 2: full - occupies the module with full bar
# 3: low - makes the module display the lowest set bar
# <string>: - displays a string
case ${waybar_cava_stbmode:-} in
0)
stbBar=''
;; # Clean
1)
stbBar="‎ "
;; # Invisible char
2)
stbBar="${bar: -1}"
;; # Full bar
3)
stbBar="${bar:0:1}"
;; # Lowest bar
*)
asciiBar="${waybar_cava_stbmode:-${bar}}"
;;
esac
# Calculate the length of the bar outside the loop
bar_length=${#bar}
bar_width=${waybar_cava_width:-${bar_length}}
bar_range=${waybar_cava_range:-$((bar_length - 1))}
# Create dictionary to replace char with bar
dict="s/;//g"
stbAscii=$(printf '0%.0s' $(seq 1 "${bar_width}")) # predicts the amount of ancii characters to be used
[ -n "${asciiBar}" ] || asciiBar="${stbAscii//0/${stbBar}}"
dict="$dict;s/${stbAscii}/${asciiBar}/g"
i=0
while [ $i -lt "${bar_length}" ] || [ $i -lt "${bar_width}" ]; do
if [ $i -lt "${bar_length}" ]; then
dict="$dict;s/$i/${bar:$i:1}/g"
fi
((i++))
done
# Create cava config
config_file="/tmp/bar_cava_config"
cat >"$config_file" <<EOF
[general]
bars = ${bar_width}
sleep_timer = 1
[input]
method = pulse
source = auto
[output]
method = raw
raw_target = /dev/stdout
data_format = ascii
ascii_max_range = ${bar_range}
EOF
cava -p "$config_file" | sed -u "${dict}"

148
scripts/wbarconfgen.sh Executable file
View File

@@ -0,0 +1,148 @@
#!/usr/bin/env bash
# read control file and initialize variables
export scrDir="$(dirname "$(realpath "$0")")"
source "${scrDir}/globalcontrol.sh"
waybar_dir="${confDir}/waybar"
modules_dir="$waybar_dir/modules"
conf_file="$waybar_dir/config.jsonc"
conf_ctl="$waybar_dir/config.ctl"
readarray -t read_ctl < $conf_ctl
num_files="${#read_ctl[@]}"
switch=0
# update control file to set next/prev mode
if [ $num_files -gt 1 ]
then
for (( i=0 ; i<$num_files ; i++ ))
do
flag=`echo "${read_ctl[i]}" | cut -d '|' -f 1`
if [ $flag -eq 1 ] && [ "$1" == "n" ] ; then
nextIndex=$(( (i + 1) % $num_files ))
switch=1
break;
elif [ $flag -eq 1 ] && [ "$1" == "p" ] ; then
nextIndex=$(( i - 1 ))
switch=1
break;
fi
done
fi
if [ $switch -eq 1 ] ; then
update_ctl="${read_ctl[nextIndex]}"
reload_flag=1
sed -i "s/^1/0/g" $conf_ctl
awk -F '|' -v cmp="$update_ctl" '{OFS=FS} {if($0==cmp) $1=1; print$0}' $conf_ctl > $waybar_dir/tmp && mv $waybar_dir/tmp $conf_ctl
fi
# overwrite config from header module
export set_sysname=`hostnamectl hostname`
export w_position=`grep '^1|' $conf_ctl | cut -d '|' -f 3`
# setting explicit waybar output
if [ ${#waybar_output[@]} -gt 0 ]; then
w_output=$(printf '"%s", ' "${waybar_output[@]}")
w_output=${w_output%, } # Remove the trailing comma and space
echo "[outputs] $w_output"
fi
export w_output="${w_output:-\"*\"}"
# setting waybar position
case ${w_position} in
left) export hv_pos="width" ; export r_deg=90 ;;
right) export hv_pos="width" ; export r_deg=270 ;;
*) export hv_pos="height" ; export r_deg=0 ;;
esac
export w_height=`grep '^1|' $conf_ctl | cut -d '|' -f 2`
if [ -z $w_height ] ; then
y_monres=`cat /sys/class/drm/*/modes | head -1 | cut -d 'x' -f 2`
export w_height=$(( y_monres*2/100 ))
fi
export i_size=$(( w_height*6/10 ))
if [ $i_size -lt 12 ] ; then
export i_size="12"
fi
export i_theme="$(
{ grep -q "^[[:space:]]*\$ICON[-_]THEME\s*=" "${hydeThemeDir}/hypr.theme" && grep "^[[:space:]]*\$ICON[-_]THEME\s*=" "${hydeThemeDir}/hypr.theme" | cut -d '=' -f2 | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' ;} ||
grep 'gsettings set org.gnome.desktop.interface icon-theme' "${hydeThemeDir}/hypr.theme" | awk -F "'" '{print $((NF - 1))}'
)"
export i_task=$(( w_height*6/10 ))
if [ $i_task -lt 16 ] ; then
export i_task="16"
fi
export i_priv=$(( w_height*6/13 ))
if [ $i_priv -lt 12 ] ; then
export i_priv="12"
fi
envsubst < $modules_dir/header.jsonc > $conf_file
# module generator function
gen_mod()
{
local pos=$1
local col=$2
local mod=""
mod=`grep '^1|' $conf_ctl | cut -d '|' -f ${col}`
mod="${mod//(/"custom/l_end"}"
mod="${mod//)/"custom/r_end"}"
mod="${mod//[/"custom/sl_end"}"
mod="${mod//]/"custom/sr_end"}"
mod="${mod//\{/"custom/rl_end"}"
mod="${mod//\}/"custom/rr_end"}"
mod="${mod// /"\",\""}"
echo -e "\t\"modules-${pos}\": [\"custom/padd\",\"${mod}\",\"custom/padd\"]," >> $conf_file
write_mod=`echo $write_mod $mod`
}
# write positions for modules
echo -e "\n\n// positions generated based on config.ctl //\n" >> $conf_file
gen_mod left 4
gen_mod center 5
gen_mod right 6
# copy modules/*.jsonc to the config
echo -e "\n\n// sourced from modules based on config.ctl //\n" >> $conf_file
echo "$write_mod" | sed 's/","/\n/g ; s/ /\n/g' | awk -F '/' '{print $NF}' | awk -F '#' '{print}' | awk '!x[$0]++' | while read mod_cpy
do
if [ -f $modules_dir/$mod_cpy.jsonc ] ; then
envsubst < $modules_dir/$mod_cpy.jsonc >> $conf_file
fi
done
cat $modules_dir/footer.jsonc >> $conf_file
# generate style
$scrDir/wbarstylegen.sh
# restart waybar
if [ "$reload_flag" == "1" ] ; then
killall waybar
waybar --config ${waybar_dir}/config.jsonc --style ${waybar_dir}/style.css > /dev/null 2>&1 &
fi

118
scripts/wbarstylegen.sh Executable file
View File

@@ -0,0 +1,118 @@
#!/usr/bin/env bash
# detect hypr theme and initialize variables
scrDir=`dirname "$(realpath "$0")"`
source $scrDir/globalcontrol.sh
waybar_dir="${confDir}/waybar"
modules_dir="$waybar_dir/modules"
conf_ctl="$waybar_dir/config.ctl"
in_file="$waybar_dir/modules/style.css"
out_file="$waybar_dir/style.css"
src_file="${confDir}/hypr/themes/theme.conf"
# calculate height from control file or monitor res
b_height=`grep '^1|' $conf_ctl | cut -d '|' -f 2`
if [ -z $b_height ] || [ "$b_height" == "0" ]; then
y_monres=`cat /sys/class/drm/*/modes | head -1 | cut -d 'x' -f 2`
b_height=$(( y_monres*3/100 ))
fi
# calculate values based on height
export b_radius=$(( b_height*70/100 )) # block rad 70% of height (type1)
export c_radius=$(( b_height*25/100 )) # block rad 25% of height {type2}
export t_radius=$(( b_height*25/100 )) # tooltip rad 25% of height
export e_margin=$(( b_height*30/100 )) # block margin 30% of height
export e_paddin=$(( b_height*10/100 )) # block padding 10% of height
export g_margin=$(( b_height*14/100 )) # module margin 14% of height
export g_paddin=$(( b_height*15/100 )) # module padding 15% of height
export w_radius=$(( b_height*30/100 )) # workspace rad 30% of height
export w_margin=$(( b_height*10/100 )) # workspace margin 10% of height
export w_paddin=$(( b_height*10/100 )) # workspace padding 10% of height
export w_padact=$(( b_height*40/100 )) # workspace active padding 40% of height
export s_fontpx=$(( b_height*34/100 )) # font size 34% of height
if [ $b_height -lt 30 ] ; then
export e_paddin=0
fi
if [ $s_fontpx -lt 10 ] ; then
export s_fontpx=10
fi
# adjust values for vert/horz
export w_position=`grep '^1|' $conf_ctl | cut -d '|' -f 3`
case ${w_position} in
top|bottom)
export x1g_margin=${g_margin}
export x2g_margin=0
export x3g_margin=${g_margin}
export x4g_margin=0
export x1rb_radius=0
export x2rb_radius=${b_radius}
export x3rb_radius=${b_radius}
export x4rb_radius=0
export x1lb_radius=${b_radius}
export x2lb_radius=0
export x3lb_radius=0
export x4lb_radius=${b_radius}
export x1rc_radius=0
export x2rc_radius=${c_radius}
export x3rc_radius=${c_radius}
export x4rc_radius=0
export x1lc_radius=${c_radius}
export x2lc_radius=0
export x3lc_radius=0
export x4lc_radius=${c_radius}
export x1="top"
export x2="bottom"
export x3="left"
export x4="right" ;;
left|right)
export x1g_margin=0
export x2g_margin=${g_margin}
export x3g_margin=0
export x4g_margin=${g_margin}
export x1rb_radius=0
export x2rb_radius=0
export x3rb_radius=${b_radius}
export x4rb_radius=${b_radius}
export x1lb_radius=${b_radius}
export x2lb_radius=${b_radius}
export x3lb_radius=0
export x4lb_radius=0
export x1rc_radius=0
export x2rc_radius=${c_radius}
export x3rc_radius=${c_radius}
export x4rc_radius=0
export x1lc_radius=${c_radius}
export x2lc_radius=0
export x3lc_radius=0
export x4lc_radius=${c_radius}
export x1="left"
export x2="right"
export x3="top"
export x4="bottom" ;;
esac
# list modules and generate theme style
export modules_ls=$(grep -m 1 '".*.": {' --exclude="$modules_dir/footer.jsonc" $modules_dir/*.jsonc | cut -d '"' -f 2 | awk -F '/' '{ if($1=="custom") print "#custom-"$NF"," ; else print "#"$NF","}')
envsubst < $in_file > $out_file
# override rounded couners
hypr_border=`awk -F '=' '{if($1~" rounding ") print $2}' $src_file | sed 's/ //g'`
if [ "$hypr_border" == "0" ] ; then
sed -i "/border-radius: /c\ border-radius: 0px;" $out_file
fi

21
scripts/windowpin.sh Executable file
View File

@@ -0,0 +1,21 @@
#!/usr/bin/env bash
# enable float
WinFloat=$(hyprctl -j clients | jq '.[] | select(.focusHistoryID == 0) | .floating')
WinPinned=$(hyprctl -j clients | jq '.[] | select(.focusHistoryID == 0) | .pinned')
if [ "${WinFloat}" == "false" ] && [ "${WinPinned}" == "false" ] ; then
hyprctl dispatch togglefloating active
fi
# toggle pin
hyprctl dispatch pin active
# disable float
WinFloat=$(hyprctl -j clients | jq '.[] | select(.focusHistoryID == 0) | .floating')
WinPinned=$(hyprctl -j clients | jq '.[] | select(.focusHistoryID == 0) | .pinned')
if [ "${WinFloat}" == "true" ] && [ "${WinPinned}" == "false" ] ; then
hyprctl dispatch togglefloating active
fi