diff options
Diffstat (limited to 'config/hypr')
| -rwxr-xr-x | config/hypr/UserScripts/Tak0-Autodispatch.sh | 62 | ||||
| -rwxr-xr-x | config/hypr/scripts/Tak0-Autodispatch.sh | 226 | ||||
| -rwxr-xr-x | config/hypr/scripts/Tak0-Per-Window-Switch.sh | 6 |
3 files changed, 85 insertions, 209 deletions
diff --git a/config/hypr/UserScripts/Tak0-Autodispatch.sh b/config/hypr/UserScripts/Tak0-Autodispatch.sh index 114a3e8e..48c22515 100755 --- a/config/hypr/UserScripts/Tak0-Autodispatch.sh +++ b/config/hypr/UserScripts/Tak0-Autodispatch.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# USAGE / ІНСТРУКЦІЯ: +# USAGE: # 1) Run from terminal: # ./dispatch.sh <application_command> <target_workspace_number> # Example: @@ -14,77 +14,49 @@ # 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. -# -# USAGE / ІНСТРУКЦІЯ: -# 1) Запуск з терміналу: -# ./dispatch.sh <application_command> <target_workspace_number> -# Наприклад: -# ./dispatch.sh discord 2 -# -# 2) Виклик з конфігурації Hyprland (у файлі hyprland.conf): -# exec-once = /path/to/dispatch.sh <application_command> <target_workspace_number> -# -# Логи зберігаються у файлі dispatch.log поруч зі скриптом. -# Якщо вікно не з'явилось або неправильно диспатчилось — інформація там. -# -# Примітки: -# - Скрипт чекає до ~9 секунд (30 ітерацій по 0.3 сек) поки вікно з'явиться. -# - Використовує hyprctl і jq, тому ці інструменти мають бути встановлені. 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. -# Команда для запуску аплікації або клас вікна для пошуку. TARGET_WORKSPACE=$2 # The target workspace number where the window should be moved. -# Цільовий номер воркспейсу, куди потрібно перемістити вікно. # 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 + echo "Usage: $0 <application_command> <target_workspace_number>" >>"$LOGFILE" 2>&1 + exit 1 fi -echo "Starting dispatch of '$APP' to workspace $TARGET_WORKSPACE at $(date)" >> "$LOGFILE" +echo "Starting dispatch of '$APP' to workspace $TARGET_WORKSPACE at $(date)" >>"$LOGFILE" # Starting the dispatch process and logging the event. -# Початок процесу диспатчу, запис у лог. - # Avoid early workspace focus issues by switching workspace first. -# Уникаємо проблем з раннім фокусом, спочатку переключаємо воркспейс. -hyprctl dispatch workspace "$TARGET_WORKSPACE" >> "$LOGFILE" 2>&1 +hyprctl dispatch workspace "$TARGET_WORKSPACE" >>"$LOGFILE" 2>&1 sleep 0.4 # Launch the application in the background and disown it. -# Запускаємо аплікацію у фоновому режимі та відв’язуємо від терміналу. -$APP & disown +$APP & +disown pid=$! -echo "Launched '$APP' with PID $pid" >> "$LOGFILE" +echo "Launched '$APP' with PID $pid" >>"$LOGFILE" # Log the launched process ID. -# Лог процесу запуску з PID. - # 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" ' + win=$(hyprctl clients -j | jq -r --arg APP "$APP" ' .[] | select(.class | test($APP;"i")) | .address' 2>>"$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 - fi - sleep 0.3 + 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 + fi + sleep 0.3 done -echo "ERROR: Window for '$APP' was NOT found or dispatched properly to workspace $TARGET_WORKSPACE at $(date)" >> "$LOGFILE" +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 diff --git a/config/hypr/scripts/Tak0-Autodispatch.sh b/config/hypr/scripts/Tak0-Autodispatch.sh index 0f81a6a3..6ed7ec13 100755 --- a/config/hypr/scripts/Tak0-Autodispatch.sh +++ b/config/hypr/scripts/Tak0-Autodispatch.sh @@ -1,11 +1,8 @@ #!/usr/bin/env bash -# + # ───────────────────────────────────────────────────────────────────────────── # Tak0-Autodispatch.sh # ───────────────────────────────────────────────────────────────────────────── -# -# 🇬🇧 ENGLISH -# ----------------------------------------------------------------------------- # This script is an "authoritative spawn dispatcher" for Hyprland. # # Its purpose is to FORCE all windows belonging to a single application launch @@ -29,41 +26,11 @@ # Important notes: # • All window rules are TEMPORARY # • No permanent pollution of Hyprland configuration -# -# ----------------------------------------------------------------------------- -# 🇺🇦 УКРАЇНСЬКА -# ----------------------------------------------------------------------------- -# Цей скрипт — це "авторитарний диспетчер запуску" для Hyprland. -# -# Його задача — ГАРАНТОВАНО відправити ВСІ вікна одного запуску програми -# (основне вікно + helper-и + Electron / Steam дочірні процеси) -# на вказаний workspace. -# -# Скрипту байдуже на: -# • race conditions -# • затримки створення вікон -# • відʼєднані helper-процеси -# • Electron / Chromium / Steam безумство -# -# Типові сценарії використання: -# • Запуск Steam / Discord / браузерів без витоку вікон -# • Заборона спавну на поточному workspace -# • Контроль програм, які ігнорують static windowrules -# -# Запуск: -# ./Tak0-Autodispatch.sh <workspace> [rule ...] -- <command> -# -# Важливо: -# • Всі rules — тимчасові -# • Глобальна конфігурація Hyprland НЕ псується -# # ───────────────────────────────────────────────────────────────────────────── -# -# REQUIREMENTS / ВИМОГИ: +# REQUIREMENTS: # - hyprctl → runtime control of Hyprland # - jq → JSON client parsing # - pgrep/ps → process tree inspection -# set -u @@ -72,38 +39,29 @@ LOGFILE="$(dirname "$0")/dispatch.log" # ───────────────────────────────────────────────────────────────────────────── # 0️⃣ ARGUMENT PARSING # ───────────────────────────────────────────────────────────────────────────── -# -# EN: # $1 → target workspace # Next args → optional capture rules (windowrulev2 syntax) # "--" → argument separator # After "--" → command to execute (verbatim) -# -# UA: -# $1 → цільовий workspace -# Далі → capture rules (сумісні з windowrulev2) -# "--" → роздільник аргументів -# Після "--" → команда запуску (як є) -# TARGET_WS="$1" shift || true CAPTURE_RULES=() while [[ "${1-}" != "--" && -n "${1-}" ]]; do - CAPTURE_RULES+=("$1") - shift || break + CAPTURE_RULES+=("$1") + shift || break done if [[ "${1-}" == "--" ]]; then - shift + shift fi CMD="$*" if [[ -z "$TARGET_WS" || -z "$CMD" ]]; then - echo "Usage: $0 <workspace> [rule rule ...] -- <command>" >>"$LOGFILE" - exit 1 + echo "Usage: $0 <workspace> [rule rule ...] -- <command>" >>"$LOGFILE" + exit 1 fi echo "=== Deploy '$CMD' → WS $TARGET_WS @ $(date) ===" >>"$LOGFILE" @@ -111,43 +69,28 @@ echo "=== Deploy '$CMD' → WS $TARGET_WS @ $(date) ===" >>"$LOGFILE" # ───────────────────────────────────────────────────────────────────────────── # 1️⃣ HYPRLAND READINESS GATE # ───────────────────────────────────────────────────────────────────────────── -# -# EN: # Hyprland may not be fully initialized during early autostart. # hyprctl silently fails if called too early. -# -# UA: -# Під час раннього автозапуску Hyprland може бути ще не готовий. -# hyprctl у такому випадку тихо фейлиться. -# for _ in {1..50}; do - hyprctl -j monitors >/dev/null 2>&1 && break - sleep 0.1 + hyprctl -j monitors >/dev/null 2>&1 && break + sleep 0.1 done # ───────────────────────────────────────────────────────────────────────────── # 2️⃣ CLEANUP GUARANTEE # ───────────────────────────────────────────────────────────────────────────── -# -# EN: # Ensures that ALL temporary rules are removed # even on crash, SIGTERM, or user interruption. -# -# UA: -# Гарантує прибирання ВСІХ тимчасових правил -# навіть у разі крешу, SIGTERM або Ctrl+C. -# cleanup() { - echo "Cleanup: removing temporary capture rules and initialWorkspace at $(date)" >>"$LOGFILE" - - hyprctl keyword windowrulev2 "unset, initialClass:.*" >>"$LOGFILE" 2>&1 || true + echo "Cleanup: removing temporary capture rules and initialWorkspace at $(date)" >>"$LOGFILE" - for RULE in "${CAPTURE_RULES[@]}"; do - echo "Cleanup: removing temporary capture rule: $RULE" >>"$LOGFILE" - hyprctl keyword windowrulev2 "unset, $RULE" >>"$LOGFILE" 2>&1 || true - done + 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 @@ -155,8 +98,6 @@ trap cleanup EXIT INT TERM ERR # ───────────────────────────────────────────────────────────────────────────── # 3️⃣ ULTRA-EARLY GLOBAL CAPTURE (NUCLEAR OPTION) # ───────────────────────────────────────────────────────────────────────────── -# -# EN: # Temporarily forces ALL windows (initialClass:.*) # onto the target workspace. # @@ -164,51 +105,30 @@ trap cleanup EXIT INT TERM ERR # • gpu-process # • renderer # • steamwebhelper -# -# UA: -# Тимчасово заганяє АБСОЛЮТНО всі вікна -# на цільовий workspace. -# -# Рятує від ультрашвидких helper-ів. -# echo "Applying temporary initialWorkspace capture (initialClass:.*)" >>"$LOGFILE" hyprctl keyword windowrulev2 \ - "initialWorkspace $TARGET_WS silent, initialClass:.*" \ - >>"$LOGFILE" 2>&1 || true + "initialWorkspace $TARGET_WS silent, initialClass:.*" \ + >>"$LOGFILE" 2>&1 || true # ───────────────────────────────────────────────────────────────────────────── # 3️⃣.1 OPTIONAL CLASS-BASED PRE-CAPTURE # ───────────────────────────────────────────────────────────────────────────── -# -# EN: # Additional precision rules. # Useful for Electron / Steam multi-process hell. -# -# UA: -# Додаткові class-based правила. -# Підвищують точність для Electron / Steam. -# 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 + echo "Applying temporary capture rule: $RULE" >>"$LOGFILE" + hyprctl keyword windowrulev2 \ + "initialWorkspace $TARGET_WS silent, $RULE" \ + >>"$LOGFILE" 2>&1 || true done # ───────────────────────────────────────────────────────────────────────────── # 4️⃣ APPLICATION LAUNCH # ───────────────────────────────────────────────────────────────────────────── -# -# EN: # bash -c allows aliases, env vars, wrappers. # ROOT_PID is the root of process lineage. -# -# UA: -# bash -c дозволяє aliases, env vars та wrappers. -# ROOT_PID — корінь дерева процесів. -# bash -c "$CMD" & ROOT_PID=$! @@ -217,102 +137,92 @@ echo "Root PID: $ROOT_PID" >>"$LOGFILE" # 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 + 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]}")" + read -r -a __toks <<<"$CMD" + APP_NAME="$(basename "${__toks[0]}")" fi echo "App gate name: $APP_NAME" >>"$LOGFILE" sleep 1.5 -# Release the nuclear option ASAP +#!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) # ───────────────────────────────────────────────────────────────────────────── -# -# EN: # This loop: # • scans ALL Hyprland clients # • matches PID lineage # • matches detached helpers # • matches class rules -# -# UA: -# Цей цикл: -# • читає ВСІ клієнти Hyprland -# • звіряє PID дерево -# • ловить відʼєднані helper-и -# • застосовує class fallback -# get_descendants() { - local root="$1" - local all=("$root") - local changed=1 + 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 + 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[@]}" + 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"* ]] + 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 ((SECONDS < END_TIME)); do + PIDS="$(get_descendants "$ROOT_PID")" - while IFS=$'\t' read -r PID ADDR CLASS; do - MATCH=0 + while IFS=$'\t' read -r PID ADDR CLASS; do + MATCH=0 - for TPID in $PIDS; do - [[ "$PID" == "$TPID" ]] && MATCH=1 && break - done + for TPID in $PIDS; do + [[ "$PID" == "$TPID" ]] && MATCH=1 && break + done - pid_matches_app "$PID" && MATCH=1 + pid_matches_app "$PID" && MATCH=1 - for RULE in "${CAPTURE_RULES[@]}"; do - if [[ "$RULE" =~ class:\^\((.*)\)\$ ]]; then - [[ "$CLASS" =~ ${BASH_REMATCH[1]} ]] && MATCH=1 - fi - done + 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 - done < <(hyprctl clients -j | jq -r '.[] | [.pid, .address, .class] | @tsv') + 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 + done < <(hyprctl clients -j | jq -r '.[] | [.pid, .address, .class] | @tsv') - sleep 0.01 + sleep 0.01 done echo "=== Deploy finished: '$CMD' ===" >>"$LOGFILE" 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" |
