From d88e6fc3b3460ca643ce66398696262fc34a1b97 Mon Sep 17 00:00:00 2001 From: Don Williams Date: Wed, 21 Jan 2026 22:40:49 -0500 Subject: The update scripts were missing `-e` after kitty On branch development Your branch is up to date with 'origin/development'. Changes to be committed: modified: ../hypr/scripts/Distro_update.sh modified: ../hypr/scripts/KooLsDotsUpdate.sh --- config/hypr/scripts/Distro_update.sh | 10 +++++----- config/hypr/scripts/KooLsDotsUpdate.sh | 8 +++++++- 2 files changed, 12 insertions(+), 6 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 -- cgit v1.2.3 From 49509f4c8a961d34246be8b0b77bf06622351d87 Mon Sep 17 00:00:00 2001 From: Don Williams Date: Wed, 21 Jan 2026 22:52:11 -0500 Subject: Added additional check/clean up for WindowRules/Startup in UserConfigs This should prevent duplicated entries and two waybars On branch development Your branch is up to date with 'origin/development'. Changes to be committed: modified: scripts/lib_copy.sh --- scripts/lib_copy.sh | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/scripts/lib_copy.sh b/scripts/lib_copy.sh index fa1231c5..ece7095a 100644 --- a/scripts/lib_copy.sh +++ b/scripts/lib_copy.sh @@ -187,6 +187,88 @@ compose_overlay_from_backup() { fi } +cleanup_duplicate_userconfigs() { + local current_version="$1" + local log="$2" + + if [ -z "$current_version" ]; then + return + fi + if ! version_gte "$current_version" "2.3.18"; then + return + fi + + local HYPR_DIR="$HOME/.config/hypr" + local BASE_DIR="$HYPR_DIR/configs" + local USER_DIR="$HYPR_DIR/UserConfigs" + + local STARTUP_BASE="$BASE_DIR/Startup_Apps.conf" + local STARTUP_USER="$USER_DIR/Startup_Apps.conf" + local WINDOW_BASE="$BASE_DIR/WindowRules.conf" + local WINDOW_USER="$USER_DIR/WindowRules.conf" + + if [ -f "$STARTUP_BASE" ] && [ -f "$STARTUP_USER" ]; then + local tmp_startup + local backup_startup + backup_startup="$STARTUP_USER.backup-dupfix-$(date +%Y%m%d-%H%M%S)" + tmp_startup=$(mktemp) + awk ' + function trim(s){ gsub(/^[ \t]+|[ \t]+$/, "", s); return s } + FNR==NR { + if ($0 ~ /^[ \t]*exec-once[ \t]*=/) { + line=trim($0) + base[line]=1 + } + next + } + { + if ($0 ~ /^[ \t]*exec-once[ \t]*=/) { + line=trim($0) + if (line in base) next + } + print + } + ' "$STARTUP_BASE" "$STARTUP_USER" >"$tmp_startup" + if ! cmp -s "$STARTUP_USER" "$tmp_startup"; then + cp "$STARTUP_USER" "$backup_startup" + mv "$tmp_startup" "$STARTUP_USER" + echo "${NOTE:-[NOTE]} - Removed duplicate Startup_Apps entries matching base config." 2>&1 | tee -a "$log" + else + rm -f "$tmp_startup" + fi + fi + + if [ -f "$WINDOW_BASE" ] && [ -f "$WINDOW_USER" ]; then + local tmp_window + local backup_window + backup_window="$WINDOW_USER.backup-dupfix-$(date +%Y%m%d-%H%M%S)" + tmp_window=$(mktemp) + awk ' + function trim(s){ gsub(/^[ \t]+|[ \t]+$/, "", s); return s } + FNR==NR { + if ($0 ~ /^[ \t]*(windowrule|layerrule)[ \t]*=/) { + line=trim($0) + base[line]=1 + } + next + } + { + if ($0 ~ /^[ \t]*(windowrule|layerrule)[ \t]*=/) { + line=trim($0) + if (line in base) next + } + print + } + ' "$WINDOW_BASE" "$WINDOW_USER" >"$tmp_window" + if ! cmp -s "$WINDOW_USER" "$tmp_window"; then + cp "$WINDOW_USER" "$backup_window" + mv "$tmp_window" "$WINDOW_USER" + echo "${NOTE:-[NOTE]} - Removed duplicate WindowRules entries matching base config." 2>&1 | tee -a "$log" + else + rm -f "$tmp_window" + fi + fi +} restore_user_configs() { local log="$1" local express_mode="$2" @@ -281,6 +363,16 @@ restore_user_configs() { done fi fi + + if [ -n "$CURRENT_VERSION" ]; then + cleanup_duplicate_userconfigs "$CURRENT_VERSION" "$log" + else + local detected_version + detected_version=$(get_installed_dotfiles_version) + if [ -n "$detected_version" ]; then + cleanup_duplicate_userconfigs "$detected_version" "$log" + fi + fi } restore_user_scripts() { -- cgit v1.2.3 From 9dd1f73d832d51972498e775baf992274ef6063c Mon Sep 17 00:00:00 2001 From: Don Williams Date: Thu, 22 Jan 2026 00:35:13 -0500 Subject: Removed stale NVIM config. It's not copied but also not needed On branch development Your branch is up to date with 'origin/development'. Changes to be committed: deleted: config/nvim/init.lua deleted: config/nvim/init.vim.txt deleted: config/nvim/lazy-lock.json deleted: config/nvim/lua/plugins.lua deleted: config/nvim/lua/plugins/alpha.lua deleted: config/nvim/lua/plugins/catppuccin.lua deleted: config/nvim/lua/plugins/lsp-config.lua deleted: config/nvim/lua/plugins/lualine.lua deleted: config/nvim/lua/plugins/neo-tree.lua deleted: config/nvim/lua/plugins/telescope.lua deleted: config/nvim/lua/plugins/treesitter.lua deleted: config/nvim/lua/vim-options.lua --- config/nvim/init.lua | 16 ----- config/nvim/init.vim.txt | 45 -------------- config/nvim/lazy-lock.json | 16 ----- config/nvim/lua/plugins.lua | 2 - config/nvim/lua/plugins/alpha.lua | 105 --------------------------------- config/nvim/lua/plugins/catppuccin.lua | 13 ---- config/nvim/lua/plugins/lsp-config.lua | 25 -------- config/nvim/lua/plugins/lualine.lua | 10 ---- config/nvim/lua/plugins/neo-tree.lua | 12 ---- config/nvim/lua/plugins/telescope.lua | 13 ---- config/nvim/lua/plugins/treesitter.lua | 12 ---- config/nvim/lua/vim-options.lua | 15 ----- 12 files changed, 284 deletions(-) delete mode 100644 config/nvim/init.lua delete mode 100644 config/nvim/init.vim.txt delete mode 100644 config/nvim/lazy-lock.json delete mode 100644 config/nvim/lua/plugins.lua delete mode 100644 config/nvim/lua/plugins/alpha.lua delete mode 100644 config/nvim/lua/plugins/catppuccin.lua delete mode 100644 config/nvim/lua/plugins/lsp-config.lua delete mode 100644 config/nvim/lua/plugins/lualine.lua delete mode 100644 config/nvim/lua/plugins/neo-tree.lua delete mode 100644 config/nvim/lua/plugins/telescope.lua delete mode 100644 config/nvim/lua/plugins/treesitter.lua delete mode 100644 config/nvim/lua/vim-options.lua diff --git a/config/nvim/init.lua b/config/nvim/init.lua deleted file mode 100644 index 861f3aee..00000000 --- a/config/nvim/init.lua +++ /dev/null @@ -1,16 +0,0 @@ -local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" -if not (vim.uv or vim.loop).fs_stat(lazypath) then - vim.fn.system({ - "git", - "clone", - "--filter=blob:none", - "https://github.com/folke/lazy.nvim.git", - "--branch=stable", -- latest stable release - lazypath, - }) -end -vim.opt.rtp:prepend(lazypath) - -require("lazy").setup("plugins") -require("vim-options") - diff --git a/config/nvim/init.vim.txt b/config/nvim/init.vim.txt deleted file mode 100644 index 2388fe28..00000000 --- a/config/nvim/init.vim.txt +++ /dev/null @@ -1,45 +0,0 @@ -" Basic Configurations -" FernuDev Github - https://github.com/Fernu292 - -set number -set mouse=a -syntax enable -set showcmd -set encoding=utf-8 -set showmatch -set relativenumber - -set expandtab -set tabstop=4 -set shiftwidth=0 -set softtabstop=0 -set autoindent -set smarttab - -call plug#begin() - Plug 'nvim-lualine/lualine.nvim' - Plug 'nvim-tree/nvim-web-devicons' - Plug 'navarasu/onedark.nvim' - Plug 'catppuccin/nvim', { 'as': 'catppuccin' } -call plug#end() - -" Calling the Lualine pluggin - -colorscheme onedark - -lua << END -require('lualine').setup { - options = { - icons_enabled = true, - theme = 'material' - } -} - -require('onedark').setup { - style = "dark", - transparent = true, -} - -require('onedark').load() - -END diff --git a/config/nvim/lazy-lock.json b/config/nvim/lazy-lock.json deleted file mode 100644 index b26c6d27..00000000 --- a/config/nvim/lazy-lock.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "alpha-nvim": { "branch": "main", "commit": "41283fb402713fc8b327e60907f74e46166f4cfd" }, - "catppuccin": { "branch": "main", "commit": "894efb557728e532aa98b98029d16907a214ec05" }, - "lazy.nvim": { "branch": "main", "commit": "dea1f687fe6e15eb3098557a69d44231ebcb6cf5" }, - "lualine.nvim": { "branch": "master", "commit": "0a5a66803c7407767b799067986b4dc3036e1983" }, - "mason-lspconfig.nvim": { "branch": "main", "commit": "37a336b653f8594df75c827ed589f1c91d91ff6c" }, - "mason.nvim": { "branch": "main", "commit": "2af3b574b68dc0273c7fb60369f3a48d5a16a857" }, - "neo-tree.nvim": { "branch": "v3.x", "commit": "29f7c215332ba95e470811c380ddbce2cebe2af4" }, - "nui.nvim": { "branch": "main", "commit": "a2bc1e9d0359caa5d11ad967cd1e30e8d4676226" }, - "nvim-lspconfig": { "branch": "master", "commit": "cf97d2485fc3f6d4df1b79a3ea183e24c272215e" }, - "nvim-treesitter": { "branch": "master", "commit": "d4a888ae3cff358cb239643c45b2b38bb60e29c6" }, - "nvim-web-devicons": { "branch": "master", "commit": "c0cfc1738361b5da1cd0a962dd6f774cc444f856" }, - "plenary.nvim": { "branch": "master", "commit": "a3e3bc82a3f95c5ed0d7201546d5d2c19b20d683" }, - "telescope-ui-select.nvim": { "branch": "master", "commit": "6e51d7da30bd139a6950adf2a47fda6df9fa06d2" }, - "telescope.nvim": { "branch": "master", "commit": "a0bbec21143c7bc5f8bb02e0005fa0b982edc026" } -} \ No newline at end of file diff --git a/config/nvim/lua/plugins.lua b/config/nvim/lua/plugins.lua deleted file mode 100644 index a2b4f84d..00000000 --- a/config/nvim/lua/plugins.lua +++ /dev/null @@ -1,2 +0,0 @@ -return {} - diff --git a/config/nvim/lua/plugins/alpha.lua b/config/nvim/lua/plugins/alpha.lua deleted file mode 100644 index a3346f1b..00000000 --- a/config/nvim/lua/plugins/alpha.lua +++ /dev/null @@ -1,105 +0,0 @@ ---- @type LazyPluginSpec -return { - "goolord/alpha-nvim", - event = "VimEnter", - dependencies = { "nvim-tree/nvim-web-devicons" }, - opts = function() - local dashboard = require("alpha.themes.dashboard") - require("alpha.term") - local arttoggle = false - - local logo = { - [[ ]], - [[ ███╗ ██╗███████╗ ██████╗ ██╗ ██╗██╗███╗ ███╗ ]], - [[ ████╗ ██║██╔════╝██╔═══██╗██║ ██║██║████╗ ████║ ]], - [[ ██╔██╗ ██║█████╗ ██║ ██║██║ ██║██║██╔████╔██║ ]], - [[ ██║╚██╗██║██╔══╝ ██║ ██║╚██╗ ██╔╝██║██║╚██╔╝██║ ]], - [[ ██║ ╚████║███████╗╚██████╔╝ ╚████╔╝ ██║██║ ╚═╝ ██║ ]], - [[ ╚═╝ ╚═══╝╚══════╝ ╚═════╝ ╚═══╝ ╚═╝╚═╝ ╚═╝ ]], - [[ ]], - } - - local art = { - -- { name, width, height } - { "tohru", 62, 17 }, - } - - if arttoggle == true then - dashboard.opts.opts.noautocmd = true - dashboard.section.terminal.opts.redraw = true - local path = vim.fn.stdpath("config") .. "/assets/" - -- local random = math.random(1, #art) - local currentart = art[1] - dashboard.section.terminal.command = "cat " .. path .. currentart[1] - - dashboard.section.terminal.width = currentart[2] - dashboard.section.terminal.height = currentart[3] - - dashboard.opts.layout = { - dashboard.section.terminal, - { type = "padding", val = 2 }, - dashboard.section.buttons, - dashboard.section.footer, - } - else - dashboard.section.header.val = logo - end - dashboard.section.buttons.val = { - dashboard.button("f", " " .. "Find files", ":Telescope find_files "), - } - for _, button in ipairs(dashboard.section.buttons.val) do - button.opts.hl = "AlphaButtons" - button.opts.hl_shortcut = "AlphaShortcut" - end - dashboard.section.header.opts.hl = "Function" - dashboard.section.buttons.opts.hl = "Identifier" - dashboard.section.footer.opts.hl = "Function" - dashboard.opts.layout[1].val = 4 - return dashboard - end, - config = function(_, dashboard) - if vim.o.filetype == "lazy" then - vim.cmd.close() - vim.api.nvim_create_autocmd("User", { - pattern = "AlphaReady", - callback = function() - require("lazy").show() - end, - }) - end - require("alpha").setup(dashboard.opts) - vim.api.nvim_create_autocmd("User", { - pattern = "LazyVimStarted", - callback = function() - local v = vim.version() - local dev = "" - if v.prerelease == "dev" then - dev = "-dev+" .. v.build - else - dev = "" - end - local version = v.major .. "." .. v.minor .. "." .. v.patch .. dev - local stats = require("lazy").stats() - local plugins_count = stats.loaded .. "/" .. stats.count - local ms = math.floor(stats.startuptime + 0.5) - local time = vim.fn.strftime("%H:%M:%S") - local date = vim.fn.strftime("%d.%m.%Y") - local line1 = " " .. plugins_count .. " plugins loaded in " .. ms .. "ms" - local line2 = "󰃭 " .. date .. "  " .. time - local line3 = " " .. version - - local line1_width = vim.fn.strdisplaywidth(line1) - local line2Padded = string.rep(" ", (line1_width - vim.fn.strdisplaywidth(line2)) / 2) .. line2 - local line3Padded = string.rep(" ", (line1_width - vim.fn.strdisplaywidth(line3)) / 2) .. line3 - - dashboard.section.footer.val = { - line1, - line2Padded, - line3Padded, - } - pcall(vim.cmd.AlphaRedraw) - end, - }) - end, -} - diff --git a/config/nvim/lua/plugins/catppuccin.lua b/config/nvim/lua/plugins/catppuccin.lua deleted file mode 100644 index 6d05f984..00000000 --- a/config/nvim/lua/plugins/catppuccin.lua +++ /dev/null @@ -1,13 +0,0 @@ -return { - "catppuccin/nvim", - lazy = false, - name = "catppuccin", - priority = 1000, - config = function() - require("catppuccin").setup({ - transparent_background = true, - }) - vim.cmd.colorscheme "catppuccin" - end -} - diff --git a/config/nvim/lua/plugins/lsp-config.lua b/config/nvim/lua/plugins/lsp-config.lua deleted file mode 100644 index f41e7984..00000000 --- a/config/nvim/lua/plugins/lsp-config.lua +++ /dev/null @@ -1,25 +0,0 @@ -return { - { - "williamboman/mason.nvim", - config = function() - require("mason").setup() - end - }, - { - "williamboman/mason-lspconfig.nvim", - config = function() - require("mason-lspconfig").setup({ - ensure_installed = {"lua_ls", "clangd", "cmake", "cssls", "html"} - }) - end - }, - { - "neovim/nvim-lspconfig", - config = function() - local lspconfig = require("lspconfig") - lspconfig.lua_ls.setup({}) - vim.keymap.set('n', 'K', vim.lsp.buf.hover, {}) - end - } -} - diff --git a/config/nvim/lua/plugins/lualine.lua b/config/nvim/lua/plugins/lualine.lua deleted file mode 100644 index bf5923d6..00000000 --- a/config/nvim/lua/plugins/lualine.lua +++ /dev/null @@ -1,10 +0,0 @@ -return { - 'nvim-lualine/lualine.nvim', - config = function() - require('lualine').setup({ - options = { - theme = 'dracula' - } - }) - end -} diff --git a/config/nvim/lua/plugins/neo-tree.lua b/config/nvim/lua/plugins/neo-tree.lua deleted file mode 100644 index da29ce40..00000000 --- a/config/nvim/lua/plugins/neo-tree.lua +++ /dev/null @@ -1,12 +0,0 @@ -return { - "nvim-neo-tree/neo-tree.nvim", - branch = "v3.x", - dependencies = { - "nvim-lua/plenary.nvim", - "nvim-tree/nvim-web-devicons", - "MunifTanjim/nui.nvim", - }, - config = function() - vim.keymap.set('n', '', ':Neotree filesystem reveal left', {}) - end -} diff --git a/config/nvim/lua/plugins/telescope.lua b/config/nvim/lua/plugins/telescope.lua deleted file mode 100644 index 7282f2cb..00000000 --- a/config/nvim/lua/plugins/telescope.lua +++ /dev/null @@ -1,13 +0,0 @@ -return { - { - 'nvim-telescope/telescope.nvim', tag = '0.1.8', - dependencies = { 'nvim-lua/plenary.nvim' }, - config = function() - local builtin = require("telescope.builtin") - vim.keymap.set('n', '', builtin.find_files, {}) - end - }, - { - "nvim-telescope/telescope-ui-select.nvim" - } -} diff --git a/config/nvim/lua/plugins/treesitter.lua b/config/nvim/lua/plugins/treesitter.lua deleted file mode 100644 index 20063418..00000000 --- a/config/nvim/lua/plugins/treesitter.lua +++ /dev/null @@ -1,12 +0,0 @@ -return { - "nvim-treesitter/nvim-treesitter", - build = ":TSUpdate", - config = function() - local configs = require("nvim-treesitter.configs") - configs.setup({ - ensure_installed = {"lua", "c", "javascript"}, - highlight = { enable = true }, - indent = { enable = true } - }) - end -} diff --git a/config/nvim/lua/vim-options.lua b/config/nvim/lua/vim-options.lua deleted file mode 100644 index d28b7e8f..00000000 --- a/config/nvim/lua/vim-options.lua +++ /dev/null @@ -1,15 +0,0 @@ -vim.cmd("set number") -vim.cmd("set mouse=a") -vim.cmd("syntax enable") -vim.cmd("set showcmd") -vim.cmd("set encoding=utf-8") -vim.cmd("set showmatch") -vim.cmd("set relativenumber") -vim.cmd("set expandtab") -vim.cmd("set tabstop=4") -vim.cmd("set shiftwidth=0") -vim.cmd("set softtabstop=0") -vim.cmd("set autoindent") -vim.cmd("set smarttab") -vim.keymap.set('n', '', 'h', {}) -vim.keymap.set('n', '', 'l',{}) -- cgit v1.2.3 From 16ce0ba50456256602019b37df369ac9a7307633 Mon Sep 17 00:00:00 2001 From: tak0dan Date: Thu, 22 Jan 2026 17:32:45 +0100 Subject: Refactor Tak0-Autodispatch.sh with improved logic (#929) --- config/hypr/scripts/Tak0-Autodispatch.sh | 371 +++++++++++++++++++++++++------ 1 file changed, 300 insertions(+), 71 deletions(-) diff --git a/config/hypr/scripts/Tak0-Autodispatch.sh b/config/hypr/scripts/Tak0-Autodispatch.sh index 114a3e8e..0f81a6a3 100755 --- a/config/hypr/scripts/Tak0-Autodispatch.sh +++ b/config/hypr/scripts/Tak0-Autodispatch.sh @@ -1,90 +1,319 @@ #!/usr/bin/env bash -# USAGE / ІНСТРУКЦІЯ: -# 1) Run from terminal: -# ./dispatch.sh -# Example: -# ./dispatch.sh discord 2 # -# 2) Call from Hyprland config (in hyprland.conf file): -# exec-once = /path/to/dispatch.sh +# ───────────────────────────────────────────────────────────────────────────── +# Tak0-Autodispatch.sh +# ───────────────────────────────────────────────────────────────────────────── # -# 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. +# 🇬🇧 ENGLISH +# ----------------------------------------------------------------------------- +# 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 -# Наприклад: -# ./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 +# 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 [rule ...] -- # -# Примітки: -# - Скрипт чекає до ~9 секунд (30 ітерацій по 0.3 сек) поки вікно з'явиться. -# - Використовує hyprctl і jq, тому ці інструменти мають бути встановлені. +# 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 [rule ...] -- +# +# Важливо: +# • Всі rules — тимчасові +# • Глобальна конфігурація Hyprland НЕ псується +# +# ───────────────────────────────────────────────────────────────────────────── +# +# 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 +# ───────────────────────────────────────────────────────────────────────────── +# +# 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_WORKSPACE=$2 -# The target workspace number where the window should be moved. -# Цільовий номер воркспейсу, куди потрібно перемістити вікно. +TARGET_WS="$1" +shift || true + +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 " >> "$LOGFILE" 2>&1 +if [[ "${1-}" == "--" ]]; then + shift +fi + +CMD="$*" + +if [[ -z "$TARGET_WS" || -z "$CMD" ]]; then + echo "Usage: $0 [rule rule ...] -- " >>"$LOGFILE" exit 1 fi -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 -sleep 0.4 - -# Launch the application in the background and disown it. -# Запускаємо аплікацію у фоновому режимі та відв’язуємо від терміналу. -$APP & disown -pid=$! - -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" ' - .[] | 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 +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 +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 + + 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 + +# ───────────────────────────────────────────────────────────────────────────── +# 3️⃣ ULTRA-EARLY GLOBAL CAPTURE (NUCLEAR OPTION) +# ───────────────────────────────────────────────────────────────────────────── +# +# EN: +# Temporarily forces ALL windows (initialClass:.*) +# onto the target workspace. +# +# Protects against ultra-fast helpers: +# • 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 + +# ───────────────────────────────────────────────────────────────────────────── +# 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 +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=$! +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.3 + 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 + +# 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 + + 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 + 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 -- cgit v1.2.3 From ff1e6fb0e529fbae01c75cd7abe00605130a0f96 Mon Sep 17 00:00:00 2001 From: brockar Date: Thu, 22 Jan 2026 20:56:44 -0300 Subject: fix: check current version --- copy.sh | 3 +- scripts/lib_copy.sh | 137 ++++++++++++++++++++++++++++------------------------ 2 files changed, 75 insertions(+), 65 deletions(-) diff --git a/copy.sh b/copy.sh index b061f4ac..d2c507ce 100755 --- a/copy.sh +++ b/copy.sh @@ -167,6 +167,7 @@ while [[ $# -gt 0 ]]; do esac shift done +INSTALLED_VERSION=$(get_installed_dotfiles_version) EXPRESS_SUPPORTED=0 if express_supported; then EXPRESS_SUPPORTED=1 @@ -479,7 +480,7 @@ printf "\n%.0s" {1..1} restore_hypr_assets "$LOG" "$EXPRESS_MODE" printf "\n%.0s" {1..1} -restore_user_configs "$LOG" "$EXPRESS_MODE" +restore_user_configs "$LOG" "$EXPRESS_MODE" "$INSTALLED_VERSION" printf "\n%.0s" {1..1} restore_user_scripts "$LOG" "$EXPRESS_MODE" diff --git a/scripts/lib_copy.sh b/scripts/lib_copy.sh index ece7095a..18fd845a 100644 --- a/scripts/lib_copy.sh +++ b/scripts/lib_copy.sh @@ -12,25 +12,30 @@ copy_phase1() { echo -n "${CAT:-[ACTION]} Do you want to replace ${YELLOW:-}$DIR2${RESET:-} config? (y/n): " read DIR1_CHOICE case "$DIR1_CHOICE" in - [Yy]*) BACKUP_DIR=$(get_backup_dirname) - mv "$DIRPATH" "$DIRPATH-backup-$BACKUP_DIR" 2>&1 | tee -a "$log" - echo -e "${NOTE:-[NOTE]} - Backed up $DIR2 to $DIRPATH-backup-$BACKUP_DIR." 2>&1 | tee -a "$log" - cp -r "config/$DIR2" "$HOME/.config/$DIR2" 2>&1 | tee -a "$log" - echo -e "${OK:-[OK]} - Replaced $DIR2 with new configuration." 2>&1 | tee -a "$log" - if [ "$DIR2" = "rofi" ]; then - if [ -d "$DIRPATH-backup-$BACKUP_DIR/themes" ]; then - for file in "$DIRPATH-backup-$BACKUP_DIR/themes"/*; do - [ -e "$file" ] || continue - cp -n "$file" "$HOME/.config/rofi/themes/" >>"$log" 2>&1 || true - done || true - fi - if [ -f "$DIRPATH-backup-$BACKUP_DIR/0-shared-fonts.rasi" ]; then - cp "$DIRPATH-backup-$BACKUP_DIR/0-shared-fonts.rasi" "$HOME/.config/rofi/0-shared-fonts.rasi" >>"$log" 2>&1 - fi - fi - break ;; - [Nn]*) echo -e "${NOTE:-[NOTE]} - Skipping ${YELLOW:-}$DIR2${RESET:-}" 2>&1 | tee -a "$log"; break ;; - *) echo -e "${WARN:-[WARN]} - Invalid choice. Please enter Y or N." ;; + [Yy]*) + BACKUP_DIR=$(get_backup_dirname) + mv "$DIRPATH" "$DIRPATH-backup-$BACKUP_DIR" 2>&1 | tee -a "$log" + echo -e "${NOTE:-[NOTE]} - Backed up $DIR2 to $DIRPATH-backup-$BACKUP_DIR." 2>&1 | tee -a "$log" + cp -r "config/$DIR2" "$HOME/.config/$DIR2" 2>&1 | tee -a "$log" + echo -e "${OK:-[OK]} - Replaced $DIR2 with new configuration." 2>&1 | tee -a "$log" + if [ "$DIR2" = "rofi" ]; then + if [ -d "$DIRPATH-backup-$BACKUP_DIR/themes" ]; then + for file in "$DIRPATH-backup-$BACKUP_DIR/themes"/*; do + [ -e "$file" ] || continue + cp -n "$file" "$HOME/.config/rofi/themes/" >>"$log" 2>&1 || true + done || true + fi + if [ -f "$DIRPATH-backup-$BACKUP_DIR/0-shared-fonts.rasi" ]; then + cp "$DIRPATH-backup-$BACKUP_DIR/0-shared-fonts.rasi" "$HOME/.config/rofi/0-shared-fonts.rasi" >>"$log" 2>&1 + fi + fi + break + ;; + [Nn]*) + echo -e "${NOTE:-[NOTE]} - Skipping ${YELLOW:-}$DIR2${RESET:-}" 2>&1 | tee -a "$log" + break + ;; + *) echo -e "${WARN:-[WARN]} - Invalid choice. Please enter Y or N." ;; esac done else @@ -49,47 +54,52 @@ copy_waybar() { echo -n "${CAT:-[ACTION]} Do you want to replace ${YELLOW:-}$DIRW${RESET:-} config? (y/n): " read DIR1_CHOICE case "$DIR1_CHOICE" in - [Yy]*) BACKUP_DIR=$(get_backup_dirname) - cp -r "$DIRPATHw" "$DIRPATHw-backup-$BACKUP_DIR" 2>&1 | tee -a "$log" - echo -e "${NOTE:-[NOTE]} - Backed up $DIRW to $DIRPATHw-backup-$BACKUP_DIR." 2>&1 | tee -a "$log" - rm -rf "$DIRPATHw" && cp -r "config/$DIRW" "$DIRPATHw" 2>&1 | tee -a "$log" - for file in "config" "style.css"; do - symlink="$DIRPATHw-backup-$BACKUP_DIR/$file" - target_file="$DIRPATHw/$file" - if [ -L "$symlink" ]; then - symlink_target=$(readlink "$symlink") - if [ -f "$symlink_target" ]; then - rm -f "$target_file" && cp -f "$symlink_target" "$target_file" - fi - fi - done - for dir in "$DIRPATHw-backup-$BACKUP_DIR/configs"/*; do - [ -e "$dir" ] || continue - if [ -d "$dir" ]; then - target_dir="$HOME/.config/waybar/configs/$(basename "$dir")" - [ -d "$target_dir" ] || cp -r "$dir" "$HOME/.config/waybar/configs/" - fi - done - for file in "$DIRPATHw-backup-$BACKUP_DIR/configs"/*; do - [ -e "$file" ] || continue - target_file="$HOME/.config/waybar/configs/$(basename "$file")" - [ -e "$target_file" ] || cp "$file" "$HOME/.config/waybar/configs/" - done || true - for file in "$DIRPATHw-backup-$BACKUP_DIR/style"/*; do - [ -e "$file" ] || continue - if [ -d "$file" ]; then - target_dir="$HOME/.config/waybar/style/$(basename "$file")" - [ -d "$target_dir" ] || cp -r "$file" "$HOME/.config/waybar/style/" - else - target_file="$HOME/.config/waybar/style/$(basename "$file")" - [ -e "$target_file" ] || cp "$file" "$HOME/.config/waybar/style/" - fi - done || true - BACKUP_FILEw="$DIRPATHw-backup-$BACKUP_DIR/UserModules" - [ -f "$BACKUP_FILEw" ] && cp -f "$BACKUP_FILEw" "$DIRPATHw/UserModules" - break ;; - [Nn]*) echo -e "${NOTE:-[NOTE]} - Skipping ${YELLOW:-}$DIRW${RESET:-} config replacement." 2>&1 | tee -a "$log"; break ;; - *) echo -e "${WARN:-[WARN]} - Invalid choice. Please enter Y or N." ;; + [Yy]*) + BACKUP_DIR=$(get_backup_dirname) + cp -r "$DIRPATHw" "$DIRPATHw-backup-$BACKUP_DIR" 2>&1 | tee -a "$log" + echo -e "${NOTE:-[NOTE]} - Backed up $DIRW to $DIRPATHw-backup-$BACKUP_DIR." 2>&1 | tee -a "$log" + rm -rf "$DIRPATHw" && cp -r "config/$DIRW" "$DIRPATHw" 2>&1 | tee -a "$log" + for file in "config" "style.css"; do + symlink="$DIRPATHw-backup-$BACKUP_DIR/$file" + target_file="$DIRPATHw/$file" + if [ -L "$symlink" ]; then + symlink_target=$(readlink "$symlink") + if [ -f "$symlink_target" ]; then + rm -f "$target_file" && cp -f "$symlink_target" "$target_file" + fi + fi + done + for dir in "$DIRPATHw-backup-$BACKUP_DIR/configs"/*; do + [ -e "$dir" ] || continue + if [ -d "$dir" ]; then + target_dir="$HOME/.config/waybar/configs/$(basename "$dir")" + [ -d "$target_dir" ] || cp -r "$dir" "$HOME/.config/waybar/configs/" + fi + done + for file in "$DIRPATHw-backup-$BACKUP_DIR/configs"/*; do + [ -e "$file" ] || continue + target_file="$HOME/.config/waybar/configs/$(basename "$file")" + [ -e "$target_file" ] || cp "$file" "$HOME/.config/waybar/configs/" + done || true + for file in "$DIRPATHw-backup-$BACKUP_DIR/style"/*; do + [ -e "$file" ] || continue + if [ -d "$file" ]; then + target_dir="$HOME/.config/waybar/style/$(basename "$file")" + [ -d "$target_dir" ] || cp -r "$file" "$HOME/.config/waybar/style/" + else + target_file="$HOME/.config/waybar/style/$(basename "$file")" + [ -e "$target_file" ] || cp "$file" "$HOME/.config/waybar/style/" + fi + done || true + BACKUP_FILEw="$DIRPATHw-backup-$BACKUP_DIR/UserModules" + [ -f "$BACKUP_FILEw" ] && cp -f "$BACKUP_FILEw" "$DIRPATHw/UserModules" + break + ;; + [Nn]*) + echo -e "${NOTE:-[NOTE]} - Skipping ${YELLOW:-}$DIRW${RESET:-} config replacement." 2>&1 | tee -a "$log" + break + ;; + *) echo -e "${WARN:-[WARN]} - Invalid choice. Please enter Y or N." ;; esac done else @@ -272,6 +282,7 @@ cleanup_duplicate_userconfigs() { restore_user_configs() { local log="$1" local express_mode="$2" + local old_version="$3" local DIRPATH="$HOME/.config/hypr" local BACKUP_DIR @@ -289,11 +300,9 @@ restore_user_configs() { fi if [ -d "$BACKUP_DIR_PATH" ] && [ "$express_mode" -eq 0 ]; then - local VERSION_FILE - VERSION_FILE=$(find "$DIRPATH" -maxdepth 1 -name "v*.*.*" | head -n 1) local CURRENT_VERSION="999.9.9" - if [ -n "$VERSION_FILE" ]; then - CURRENT_VERSION=$(basename "$VERSION_FILE" | sed 's/^v//') + if [ -n "$old_version" ]; then + CURRENT_VERSION="$old_version" fi local TARGET_VERSION="2.3.19" -- cgit v1.2.3 From 8eae87e4361e33eb75547911da86a850d5504798 Mon Sep 17 00:00:00 2001 From: Don Williams Date: Thu, 22 Jan 2026 18:56:18 -0500 Subject: Added version check up 2.3.19, logging and better code to compare files On branch development Your branch is up to date with 'origin/development'. Changes to be committed: modified: scripts/lib_copy.sh --- scripts/lib_copy.sh | 87 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 69 insertions(+), 18 deletions(-) diff --git a/scripts/lib_copy.sh b/scripts/lib_copy.sh index 18fd845a..ace6f4d7 100644 --- a/scripts/lib_copy.sh +++ b/scripts/lib_copy.sh @@ -204,10 +204,17 @@ cleanup_duplicate_userconfigs() { if [ -z "$current_version" ]; then return fi - if ! version_gte "$current_version" "2.3.18"; then + + # Run de-dupe only for existing installs up to and including v2.3.19. + # For v2.3.20 and newer, the underlying duplication bug is fixed and + # this cleanup is no longer needed (and might mask future issues). + if version_gte "$current_version" "2.3.20"; then + echo "${INFO:-[INFO]} Skipping UserConfigs duplicate cleanup for detected version v$current_version (>= 2.3.20)." 2>&1 | tee -a "$log" return fi + echo "${INFO:-[INFO]} Running UserConfigs duplicate cleanup for detected version v$current_version (<= 2.3.19)." 2>&1 | tee -a "$log" + local HYPR_DIR="$HOME/.config/hypr" local BASE_DIR="$HYPR_DIR/configs" local USER_DIR="$HYPR_DIR/UserConfigs" @@ -216,7 +223,11 @@ cleanup_duplicate_userconfigs() { local STARTUP_USER="$USER_DIR/Startup_Apps.conf" local WINDOW_BASE="$BASE_DIR/WindowRules.conf" local WINDOW_USER="$USER_DIR/WindowRules.conf" + local KEYBINDS_BASE="$BASE_DIR/Keybinds.conf" + local KEYBINDS_USER="$USER_DIR/UserKeybinds.conf" + # Startup_Apps: strip exec-once lines from UserConfigs that are exact + # duplicates of the base Startup_Apps.conf. if [ -f "$STARTUP_BASE" ] && [ -f "$STARTUP_USER" ]; then local tmp_startup local backup_startup @@ -248,6 +259,8 @@ cleanup_duplicate_userconfigs() { fi fi + # WindowRules: strip windowrule/layerrule lines from UserConfigs that + # are exact duplicates of the base WindowRules.conf. if [ -f "$WINDOW_BASE" ] && [ -f "$WINDOW_USER" ]; then local tmp_window local backup_window @@ -278,6 +291,41 @@ cleanup_duplicate_userconfigs() { rm -f "$tmp_window" fi fi + + # Keybinds: strip bind* lines from UserKeybinds.conf that are exact + # duplicates of the base Keybinds.conf. Comments and unbinds are kept. + if [ -f "$KEYBINDS_BASE" ] && [ -f "$KEYBINDS_USER" ]; then + local tmp_keybinds + local backup_keybinds + backup_keybinds="$KEYBINDS_USER.backup-dupfix-$(date +%Y%m%d-%H%M%S)" + tmp_keybinds=$(mktemp) + awk ' + function trim(s){ gsub(/^[ \t]+|[ \t]+$/, "", s); return s } + FNR==NR { + # Match any Hyprland bind variant: bindd, bindmd, bindld, binded, + # bindlnd, bindeld, etc. + if ($0 ~ /^[ \t]*bind[a-z]*[ \t]*=/) { + line=trim($0) + base[line]=1 + } + next + } + { + if ($0 ~ /^[ \t]*bind[a-z]*[ \t]*=/) { + line=trim($0) + if (line in base) next + } + print + } + ' "$KEYBINDS_BASE" "$KEYBINDS_USER" >"$tmp_keybinds" + if ! cmp -s "$KEYBINDS_USER" "$tmp_keybinds"; then + cp "$KEYBINDS_USER" "$backup_keybinds" + mv "$tmp_keybinds" "$KEYBINDS_USER" + echo "${NOTE:-[NOTE]} - Removed duplicate UserKeybinds entries matching base Keybinds.conf." 2>&1 | tee -a "$log" + else + rm -f "$tmp_keybinds" + fi + fi } restore_user_configs() { local log="$1" @@ -294,12 +342,17 @@ restore_user_configs() { exit 1 fi + # In express mode we still want to run the de-dupe logic, but we skip + # the interactive restoration prompts so the workflow stays non-blocking. + local SKIP_RESTORE_PROMPTS=0 if [ -d "$BACKUP_DIR_PATH" ] && [ "$express_mode" -eq 1 ]; then echo "${NOTE:-[NOTE]} Express mode: skipping UserConfigs restoration prompts." 2>&1 | tee -a "$log" - return + SKIP_RESTORE_PROMPTS=1 fi - if [ -d "$BACKUP_DIR_PATH" ] && [ "$express_mode" -eq 0 ]; then + if [ -d "$BACKUP_DIR_PATH" ] && [ "$SKIP_RESTORE_PROMPTS" -eq 0 ]; then + local VERSION_FILE + VERSION_FILE=$(find "$DIRPATH" -maxdepth 1 -name "v*.*.*" | head -n 1) local CURRENT_VERSION="999.9.9" if [ -n "$old_version" ]; then CURRENT_VERSION="$old_version" @@ -308,13 +361,13 @@ restore_user_configs() { local TARGET_VERSION="2.3.19" echo -e "${NOTE:-[NOTE]} Restoring previous ${MAGENTA:-}User-Configs${RESET:-}... " 2>&1 | tee -a "$log" - printf "${WARNING:-}\ - █▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀█\n\ - NOTES for RESTORING PREVIOUS CONFIGS\n\ - █▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄█\n\n\ - The 'UserConfigs' directory is for all your personal settings.\n\ - Files in this directory will override the default configurations,\n\ - so your customizations are not lost when you update.\n\ + printf "${WARNING:-}\\ + █▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀█\\n\\ + NOTES for RESTORING PREVIOUS CONFIGS\\n\\ + █▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄█\\n\\n\\ + The 'UserConfigs' directory is for all your personal settings.\\n\\ + Files in this directory will override the default configurations,\\n\\ + so your customizations are not lost when you update.\\n\\ " >&2 if version_gte "$CURRENT_VERSION" "$TARGET_VERSION"; then @@ -373,14 +426,12 @@ restore_user_configs() { fi fi - if [ -n "$CURRENT_VERSION" ]; then - cleanup_duplicate_userconfigs "$CURRENT_VERSION" "$log" - else - local detected_version - detected_version=$(get_installed_dotfiles_version) - if [ -n "$detected_version" ]; then - cleanup_duplicate_userconfigs "$detected_version" "$log" - fi + # Always run de-dupe based on the installed dotfiles version so that + # express mode and standard mode behave consistently. + local detected_version + detected_version=$(get_installed_dotfiles_version) + if [ -n "$detected_version" ]; then + cleanup_duplicate_userconfigs "$detected_version" "$log" fi } -- cgit v1.2.3 From a64c7f7f3ecfe188af8723a10d18a1c0ce6d2665 Mon Sep 17 00:00:00 2001 From: Don Williams Date: Thu, 22 Jan 2026 19:04:18 -0500 Subject: Moved version to v2.3.20 On branch development Your branch is ahead of 'origin/development' by 1 commit. (use "git push" to publish your local commits) Changes to be committed: modified: CHANGELOG.md modified: config/hypr/configs/ENVariables.conf renamed: config/hypr/v2.3.19 -> config/hypr/v2.3.20 --- CHANGELOG.md | 10 ++++++++++ config/hypr/configs/ENVariables.conf | 2 +- config/hypr/v2.3.19 | 5 ----- config/hypr/v2.3.20 | 5 +++++ 4 files changed, 16 insertions(+), 6 deletions(-) delete mode 100644 config/hypr/v2.3.19 create mode 100644 config/hypr/v2.3.20 diff --git a/CHANGELOG.md b/CHANGELOG.md index c3e8ca96..c733649f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog — JAK's Hyprland Dotfiles +## v2.3.20 + +- Bugfix release +- Fixed issue with express-update + - It bypassed the code to remove duplicates in system vs. user + - Now checks for dups in version <= 2.3.19 + - Improved the checking code for better matching system vs. User + - Merged `tak0dan` update to `Tak0-Autodispatch.sh` script + - Removed stale `nvim` config. It was never copied but not needed + ## v2.3.19 - 2026-01-20 diff --git a/config/hypr/configs/ENVariables.conf b/config/hypr/configs/ENVariables.conf index 2421199c..6be44e9b 100644 --- a/config/hypr/configs/ENVariables.conf +++ b/config/hypr/configs/ENVariables.conf @@ -5,7 +5,7 @@ # environment-variables # Current Version of JakooLit Dotfiles: -env = DOTS_VERSION,2.3.19 +env = DOTS_VERSION,2.3.20 ### Toolkit Backend Variables ### env = GDK_BACKEND,wayland,x11,* diff --git a/config/hypr/v2.3.19 b/config/hypr/v2.3.19 deleted file mode 100644 index 31b3414d..00000000 --- a/config/hypr/v2.3.19 +++ /dev/null @@ -1,5 +0,0 @@ -### https://github.com/JaKooLit ### -## https://github.com/JaKooLit/Hyprland-Dots -## This is to have a reference of which version would be - -## note that this will always be higher than the released versions \ No newline at end of file diff --git a/config/hypr/v2.3.20 b/config/hypr/v2.3.20 new file mode 100644 index 00000000..31b3414d --- /dev/null +++ b/config/hypr/v2.3.20 @@ -0,0 +1,5 @@ +### https://github.com/JaKooLit ### +## https://github.com/JaKooLit/Hyprland-Dots +## This is to have a reference of which version would be + +## note that this will always be higher than the released versions \ No newline at end of file -- cgit v1.2.3 From c6a85140d2578a7d3ea009cb8074049c98c8da4e Mon Sep 17 00:00:00 2001 From: Don Williams Date: Thu, 22 Jan 2026 19:10:39 -0500 Subject: Added version check to update helper to make sure dedupe is run On branch development Your branch is ahead of 'origin/development' by 2 commits. (use "git push" to publish your local commits) Changes to be committed: modified: scripts/lib_update.sh --- scripts/lib_update.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/scripts/lib_update.sh b/scripts/lib_update.sh index 0a70dff0..be0b8a0a 100644 --- a/scripts/lib_update.sh +++ b/scripts/lib_update.sh @@ -77,6 +77,20 @@ run_repo_update() { echo " Pull status : $( [ $pull_status -eq 0 ] && echo success || echo failure )" | tee -a "$log_file" echo "----------------------------------------" | tee -a "$log_file" + # Also run the UserConfigs duplicate cleanup for existing installs, + # using the same version gating as the main copy workflow (<= v2.3.19). + if declare -f get_installed_dotfiles_version >/dev/null 2>&1 \ + && declare -f cleanup_duplicate_userconfigs >/dev/null 2>&1; then + local installed_version + installed_version=$(get_installed_dotfiles_version) + if [ -n "$installed_version" ]; then + echo "${INFO:-[INFO]} Checking for duplicate UserConfigs entries after repo update (detected v$installed_version)..." | tee -a "$log_file" + cleanup_duplicate_userconfigs "$installed_version" "$log_file" + else + echo "${NOTE:-[NOTE]} Skipping UserConfigs duplicate cleanup; installed version could not be detected." | tee -a "$log_file" + fi + fi + read -n1 -s -r -p "Press any key to return to the main menu..." echo -- cgit v1.2.3 From 2088bdc2b5ef8c2823e6f2e4997871818417672e Mon Sep 17 00:00:00 2001 From: Don Williams Date: Thu, 22 Jan 2026 19:23:58 -0500 Subject: fix: UserConfigs dedupe handling for express/update --- copy.sh | 13 +++++++++---- scripts/lib_copy.sh | 11 ++++++++--- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/copy.sh b/copy.sh index d2c507ce..90dc1b83 100755 --- a/copy.sh +++ b/copy.sh @@ -410,7 +410,12 @@ if command -v ags >/dev/null 2>&1; then fi fi -printf "\n%.0s" {1..1} +printf "\\n%.0s" {1..1} + +# Capture installed dotfiles version at the start of the workflow so we +# can apply cleanup rules based on the pre-upgrade state, even if a newer +# version marker is copied in later. +INSTALLED_VERSION_AT_START="$(get_installed_dotfiles_version || true)" # quickshell (ags alternative) # Check if quickshell is installed @@ -478,10 +483,10 @@ fi printf "\n%.0s" {1..1} restore_hypr_assets "$LOG" "$EXPRESS_MODE" -printf "\n%.0s" {1..1} +printf "\\n%.0s" {1..1} -restore_user_configs "$LOG" "$EXPRESS_MODE" "$INSTALLED_VERSION" -printf "\n%.0s" {1..1} +restore_user_configs "$LOG" "$EXPRESS_MODE" "$INSTALLED_VERSION_AT_START" +printf "\\n%.0s" {1..1} restore_user_scripts "$LOG" "$EXPRESS_MODE" printf "\n%.0s" {1..1} diff --git a/scripts/lib_copy.sh b/scripts/lib_copy.sh index ace6f4d7..331c6906 100644 --- a/scripts/lib_copy.sh +++ b/scripts/lib_copy.sh @@ -427,9 +427,14 @@ restore_user_configs() { fi # Always run de-dupe based on the installed dotfiles version so that - # express mode and standard mode behave consistently. - local detected_version - detected_version=$(get_installed_dotfiles_version) + # express mode and standard mode behave consistently. Prefer the + # pre-upgrade version (old_version) if provided so we still clean up + # legacy duplicates when upgrading to a newer release that no longer + # needs the fix. + local detected_version="$old_version" + if [ -z "$detected_version" ]; then + detected_version=$(get_installed_dotfiles_version) + fi if [ -n "$detected_version" ]; then cleanup_duplicate_userconfigs "$detected_version" "$log" fi -- cgit v1.2.3 From dff3fc2eabbb329e2013ccd4cc65a328ea712373 Mon Sep 17 00:00:00 2001 From: brockar Date: Fri, 23 Jan 2026 16:06:00 -0300 Subject: fix: remove non-english comments --- config/hypr/UserScripts/Tak0-Autodispatch.sh | 62 ++----- config/hypr/scripts/Tak0-Autodispatch.sh | 228 ++++++++------------------ config/hypr/scripts/Tak0-Per-Window-Switch.sh | 6 - 3 files changed, 86 insertions(+), 210 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 # 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 -# Наприклад: -# ./dispatch.sh discord 2 -# -# 2) Виклик з конфігурації Hyprland (у файлі hyprland.conf): -# exec-once = /path/to/dispatch.sh -# -# Логи зберігаються у файлі 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 " >> "$LOGFILE" 2>&1 - exit 1 + echo "Usage: $0 " >>"$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 [rule ...] -- -# -# Важливо: -# • Всі 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 [rule rule ...] -- " >>"$LOGFILE" - exit 1 + echo "Usage: $0 [rule rule ...] -- " >>"$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' /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 - - 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 + 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[@]}" + 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" -- cgit v1.2.3