diff options
| author | Martin Guzman <55927935+brockar@users.noreply.github.com> | 2026-01-24 19:45:52 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-01-24 19:45:52 -0300 |
| commit | 6b9ef5fb2219ccbb3d42adb4b691c466991efc9f (patch) | |
| tree | 74b141beda34510f7c44d5e82d2c6ed54c6bfbac /config/hypr/scripts | |
| parent | 035724daaf362eac452a781e20144cf893ed274f (diff) | |
| parent | d2fbf319bc3b09e4345dea390b85d328eb0318c0 (diff) | |
Merge pull request #931 from JaKooLit/development
Development to main: Fix upgrade bug
Diffstat (limited to 'config/hypr/scripts')
| -rwxr-xr-x | config/hypr/scripts/Distro_update.sh | 10 | ||||
| -rwxr-xr-x | config/hypr/scripts/KooLsDotsUpdate.sh | 8 | ||||
| -rwxr-xr-x | config/hypr/scripts/Tak0-Autodispatch.sh | 277 | ||||
| -rwxr-xr-x | config/hypr/scripts/Tak0-Per-Window-Switch.sh | 6 |
4 files changed, 220 insertions, 81 deletions
diff --git a/config/hypr/scripts/Distro_update.sh b/config/hypr/scripts/Distro_update.sh index 917f303b..164de7ec 100755 --- a/config/hypr/scripts/Distro_update.sh +++ b/config/hypr/scripts/Distro_update.sh @@ -15,23 +15,23 @@ fi if command -v paru &> /dev/null || command -v yay &> /dev/null; then # Arch-based if command -v paru &> /dev/null; then - kitty -T update paru -Syu + kitty -T update -e paru -Syu notify-send -i "$iDIR/ja.png" -u low 'Arch-based system' 'has been updated.' else - kitty -T update yay -Syu + kitty -T update -e yay -Syu notify-send -i "$iDIR/ja.png" -u low 'Arch-based system' 'has been updated.' fi elif command -v dnf &> /dev/null; then # Fedora-based - kitty -T update sudo dnf update --refresh -y + kitty -T update -e sudo dnf update --refresh -y notify-send -i "$iDIR/ja.png" -u low 'Fedora system' 'has been updated.' elif command -v apt &> /dev/null; then # Debian-based (Debian, Ubuntu, etc.) - kitty -T update bash -c "sudo apt update && sudo apt upgrade -y" + kitty -T update -e bash -c "sudo apt update && sudo apt upgrade -y" notify-send -i "$iDIR/ja.png" -u low 'Debian/Ubuntu system' 'has been updated.' elif command -v zypper &> /dev/null; then # openSUSE-based - kitty -T update sudo zypper dup -y + kitty -T update -e sudo zypper dup -y notify-send -i "$iDIR/ja.png" -u low 'openSUSE system' 'has been updated.' else # Unsupported distro diff --git a/config/hypr/scripts/KooLsDotsUpdate.sh b/config/hypr/scripts/KooLsDotsUpdate.sh index a49f5430..006d66ed 100755 --- a/config/hypr/scripts/KooLsDotsUpdate.sh +++ b/config/hypr/scripts/KooLsDotsUpdate.sh @@ -17,12 +17,18 @@ fi # GitHub URL - KooL's dots branch="main" github_url="https://github.com/JaKooLit/Hyprland-Dots/tree/$branch/config/hypr/" +# Check for required tools (curl) +if ! command -v curl &> /dev/null; then + notify-send -i "$iDIR/error.png" "Need curl:" "curl not found. Please install curl." + exit 1 +fi # Fetch the version from GitHub URL - KooL's dots -github_version=$(curl -s "$github_url" | grep -o 'v[0-9]\+\.[0-9]\+\.[0-9]\+' | sort -V | tail -n 1 | sed 's/v//') +github_version=$(curl -fsSL -A "Mozilla/5.0" "$github_url" | grep -o 'v[0-9]\+\.[0-9]\+\.[0-9]\+' | sort -V | tail -n 1 | sed 's/v//') # Cant find GitHub URL - KooL's dots version if [ -z "$github_version" ]; then + notify-send -i "$iDIR/error.png" 'KooL Hyprland:' "Unable to determine GitHub version." exit 1 fi diff --git a/config/hypr/scripts/Tak0-Autodispatch.sh b/config/hypr/scripts/Tak0-Autodispatch.sh index 114a3e8e..6ed7ec13 100755 --- a/config/hypr/scripts/Tak0-Autodispatch.sh +++ b/config/hypr/scripts/Tak0-Autodispatch.sh @@ -1,90 +1,229 @@ #!/usr/bin/env bash -# USAGE / ІНСТРУКЦІЯ: -# 1) Run from terminal: -# ./dispatch.sh <application_command> <target_workspace_number> -# Example: -# ./dispatch.sh discord 2 -# -# 2) Call from Hyprland config (in hyprland.conf file): -# exec-once = /path/to/dispatch.sh <application_command> <target_workspace_number> -# -# Logs are saved in dispatch.log file next to the script. -# If the window doesn't appear or is dispatched incorrectly — info will be there. + +# ───────────────────────────────────────────────────────────────────────────── +# Tak0-Autodispatch.sh +# ───────────────────────────────────────────────────────────────────────────── +# This script is an "authoritative spawn dispatcher" for Hyprland. # -# Notes: -# - Script waits about ~9 seconds (30 iterations of 0.3 sec) for window to appear. -# - Uses hyprctl and jq, so these tools must be installed. +# Its purpose is to FORCE all windows belonging to a single application launch +# (main window + helpers + Electron / Steam child processes) +# onto a specific workspace. # -# USAGE / ІНСТРУКЦІЯ: -# 1) Запуск з терміналу: -# ./dispatch.sh <application_command> <target_workspace_number> -# Наприклад: -# ./dispatch.sh discord 2 +# It explicitly ignores: +# • spawn race conditions +# • delayed window creation +# • detached helper processes +# • Electron / Chromium / Steam madness # -# 2) Виклик з конфігурації Hyprland (у файлі hyprland.conf): -# exec-once = /path/to/dispatch.sh <application_command> <target_workspace_number> +# Typical use cases: +# • Launch Steam / Discord / browsers without window leakage +# • Prevent apps from spawning on the currently focused workspace +# • Control applications that completely ignore static windowrules # -# Логи зберігаються у файлі dispatch.log поруч зі скриптом. -# Якщо вікно не з'явилось або неправильно диспатчилось — інформація там. +# Invocation: +# ./Tak0-Autodispatch.sh <workspace> [rule ...] -- <command> # -# Примітки: -# - Скрипт чекає до ~9 секунд (30 ітерацій по 0.3 сек) поки вікно з'явиться. -# - Використовує hyprctl і jq, тому ці інструменти мають бути встановлені. +# Important notes: +# • All window rules are TEMPORARY +# • No permanent pollution of Hyprland configuration +# ───────────────────────────────────────────────────────────────────────────── +# REQUIREMENTS: +# - hyprctl → runtime control of Hyprland +# - jq → JSON client parsing +# - pgrep/ps → process tree inspection + +set -u LOGFILE="$(dirname "$0")/dispatch.log" -# Log file path located next to the script. -# Файл логів розташований поруч зі скриптом. -APP=$1 -# The application command or window class to launch or match. -# Команда для запуску аплікації або клас вікна для пошуку. +# ───────────────────────────────────────────────────────────────────────────── +# 0️⃣ ARGUMENT PARSING +# ───────────────────────────────────────────────────────────────────────────── +# $1 → target workspace +# Next args → optional capture rules (windowrulev2 syntax) +# "--" → argument separator +# After "--" → command to execute (verbatim) + +TARGET_WS="$1" +shift || true -TARGET_WORKSPACE=$2 -# The target workspace number where the window should be moved. -# Цільовий номер воркспейсу, куди потрібно перемістити вікно. +CAPTURE_RULES=() +while [[ "${1-}" != "--" && -n "${1-}" ]]; do + CAPTURE_RULES+=("$1") + shift || break +done -# Check if required arguments are provided. -# Перевірка наявності необхідних параметрів. -if [[ -z "$APP" || -z "$TARGET_WORKSPACE" ]]; then - echo "Usage: $0 <application_command> <target_workspace_number>" >> "$LOGFILE" 2>&1 - exit 1 +if [[ "${1-}" == "--" ]]; then + shift fi -echo "Starting dispatch of '$APP' to workspace $TARGET_WORKSPACE at $(date)" >> "$LOGFILE" -# Starting the dispatch process and logging the event. -# Початок процесу диспатчу, запис у лог. +CMD="$*" + +if [[ -z "$TARGET_WS" || -z "$CMD" ]]; then + echo "Usage: $0 <workspace> [rule rule ...] -- <command>" >>"$LOGFILE" + exit 1 +fi + +echo "=== Deploy '$CMD' → WS $TARGET_WS @ $(date) ===" >>"$LOGFILE" + +# ───────────────────────────────────────────────────────────────────────────── +# 1️⃣ HYPRLAND READINESS GATE +# ───────────────────────────────────────────────────────────────────────────── +# Hyprland may not be fully initialized during early autostart. +# hyprctl silently fails if called too early. -# Avoid early workspace focus issues by switching workspace first. -# Уникаємо проблем з раннім фокусом, спочатку переключаємо воркспейс. -hyprctl dispatch workspace "$TARGET_WORKSPACE" >> "$LOGFILE" 2>&1 -sleep 0.4 +for _ in {1..50}; do + hyprctl -j monitors >/dev/null 2>&1 && break + sleep 0.1 +done + +# ───────────────────────────────────────────────────────────────────────────── +# 2️⃣ CLEANUP GUARANTEE +# ───────────────────────────────────────────────────────────────────────────── +# Ensures that ALL temporary rules are removed +# even on crash, SIGTERM, or user interruption. + +cleanup() { + echo "Cleanup: removing temporary capture rules and initialWorkspace at $(date)" >>"$LOGFILE" + + hyprctl keyword windowrulev2 "unset, initialClass:.*" >>"$LOGFILE" 2>&1 || true + for RULE in "${CAPTURE_RULES[@]}"; do + echo "Cleanup: removing temporary capture rule: $RULE" >>"$LOGFILE" + hyprctl keyword windowrulev2 "unset, $RULE" >>"$LOGFILE" 2>&1 || true + done +} + +trap cleanup EXIT INT TERM ERR -# Launch the application in the background and disown it. -# Запускаємо аплікацію у фоновому режимі та відв’язуємо від терміналу. -$APP & disown -pid=$! +# ───────────────────────────────────────────────────────────────────────────── +# 3️⃣ ULTRA-EARLY GLOBAL CAPTURE (NUCLEAR OPTION) +# ───────────────────────────────────────────────────────────────────────────── +# Temporarily forces ALL windows (initialClass:.*) +# onto the target workspace. +# +# Protects against ultra-fast helpers: +# • gpu-process +# • renderer +# • steamwebhelper + +echo "Applying temporary initialWorkspace capture (initialClass:.*)" >>"$LOGFILE" +hyprctl keyword windowrulev2 \ + "initialWorkspace $TARGET_WS silent, initialClass:.*" \ + >>"$LOGFILE" 2>&1 || true + +# ───────────────────────────────────────────────────────────────────────────── +# 3️⃣.1 OPTIONAL CLASS-BASED PRE-CAPTURE +# ───────────────────────────────────────────────────────────────────────────── +# Additional precision rules. +# Useful for Electron / Steam multi-process hell. + +for RULE in "${CAPTURE_RULES[@]}"; do + echo "Applying temporary capture rule: $RULE" >>"$LOGFILE" + hyprctl keyword windowrulev2 \ + "initialWorkspace $TARGET_WS silent, $RULE" \ + >>"$LOGFILE" 2>&1 || true +done -echo "Launched '$APP' with PID $pid" >> "$LOGFILE" -# Log the launched process ID. -# Лог процесу запуску з PID. +# ───────────────────────────────────────────────────────────────────────────── +# 4️⃣ APPLICATION LAUNCH +# ───────────────────────────────────────────────────────────────────────────── +# bash -c allows aliases, env vars, wrappers. +# ROOT_PID is the root of process lineage. -# Wait for the application window to appear (matching window class). -# Чекаємо появи вікна аплікації (за класом вікна). -for i in {1..30}; do - win=$(hyprctl clients -j | jq -r --arg APP "$APP" ' - .[] | select(.class | test($APP;"i")) | .address' 2>>"$LOGFILE") +bash -c "$CMD" & +ROOT_PID=$! +echo "Root PID: $ROOT_PID" >>"$LOGFILE" - if [[ -n "$win" ]]; then - echo "Found window $win for app '$APP', moving to workspace $TARGET_WORKSPACE" >> "$LOGFILE" - # Move the window to the target workspace. - # Переміщаємо вікно на цільовий воркспейс. - hyprctl dispatch movetoworkspace "$TARGET_WORKSPACE,address:$win" >> "$LOGFILE" 2>&1 - exit 0 +# Resolve canonical process name +APP_NAME="" +for _ in {1..20}; do + if [[ -r "/proc/$ROOT_PID/comm" ]]; then + APP_NAME="$(tr -d '\0' </proc/$ROOT_PID/comm 2>/dev/null || true)" + break + fi + sleep 0.05 +done + +if [[ -z "$APP_NAME" ]]; then + read -r -a __toks <<<"$CMD" + APP_NAME="$(basename "${__toks[0]}")" +fi + +echo "App gate name: $APP_NAME" >>"$LOGFILE" + +sleep 1.5 + +#!TO-DO: Release the nuclear option ASAP +echo "Releasing ultra-early wide capture" >>"$LOGFILE" +hyprctl keyword windowrulev2 "unset, initialClass:.*" >>"$LOGFILE" 2>&1 || true + +# ───────────────────────────────────────────────────────────────────────────── +# 5️⃣ SUPERVISION LOOP (AUTHORITATIVE PHASE) +# ───────────────────────────────────────────────────────────────────────────── +# This loop: +# • scans ALL Hyprland clients +# • matches PID lineage +# • matches detached helpers +# • matches class rules + +get_descendants() { + local root="$1" + local all=("$root") + local changed=1 + + while ((changed)); do + changed=0 + for p in "${all[@]}"; do + for c in $(pgrep -P "$p" 2>/dev/null || true); do + if [[ ! " ${all[*]} " =~ " $c " ]]; then + all+=("$c") + changed=1 + fi + done + done + done + + echo "${all[@]}" +} + +pid_matches_app() { + local pid="$1" + local comm + comm="$(ps -p "$pid" -o comm= 2>/dev/null)" || return 1 + [[ "$comm" == "$APP_NAME" || "$comm" == "$APP_NAME"* ]] +} + +END_TIME=$((SECONDS + 20)) +declare -A SEEN + +while ((SECONDS < END_TIME)); do + PIDS="$(get_descendants "$ROOT_PID")" + + while IFS=$'\t' read -r PID ADDR CLASS; do + MATCH=0 + + for TPID in $PIDS; do + [[ "$PID" == "$TPID" ]] && MATCH=1 && break + done + + pid_matches_app "$PID" && MATCH=1 + + for RULE in "${CAPTURE_RULES[@]}"; do + if [[ "$RULE" =~ class:\^\((.*)\)\$ ]]; then + [[ "$CLASS" =~ ${BASH_REMATCH[1]} ]] && MATCH=1 + fi + done + + if ((MATCH)) && [[ -z "${SEEN[$ADDR]-}" ]]; then + echo "Placing window $ADDR (pid $PID, class $CLASS) → WS $TARGET_WS" >>"$LOGFILE" + hyprctl dispatch movetoworkspacesilent \ + "$TARGET_WS,address:$ADDR" >>"$LOGFILE" 2>&1 || true + SEEN[$ADDR]=1 fi - sleep 0.3 + done < <(hyprctl clients -j | jq -r '.[] | [.pid, .address, .class] | @tsv') + + sleep 0.01 done -echo "ERROR: Window for '$APP' was NOT found or dispatched properly to workspace $TARGET_WORKSPACE at $(date)" >> "$LOGFILE" -# Log error if window was not found or dispatched correctly. -# Запис помилки, якщо вікно не знайдено або неправильно диспатчено. -exit 1 +echo "=== Deploy finished: '$CMD' ===" >>"$LOGFILE" +exit 0 diff --git a/config/hypr/scripts/Tak0-Per-Window-Switch.sh b/config/hypr/scripts/Tak0-Per-Window-Switch.sh index 7cec89a6..d652f0f7 100755 --- a/config/hypr/scripts/Tak0-Per-Window-Switch.sh +++ b/config/hypr/scripts/Tak0-Per-Window-Switch.sh @@ -1,16 +1,10 @@ ################################################################## -# # -# # # TAK_0'S Per-Window-Switch # # # -# # -# # # Just a little script that I made to switch keyboard layouts # # per-window instead of global switching for the more # # smooth and comfortable workflow. # -# # ################################################################## - # This is for changing kb_layouts. Set kb_layouts in MAP_FILE="$HOME/.cache/kb_layout_per_window" |
