diff options
| author | Martin Guzman <55927935+brockar@users.noreply.github.com> | 2025-11-22 13:42:39 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-11-22 13:42:39 -0300 |
| commit | bcfd5e7c2b67f0a62b1ceeb62d20b0a80ca55a70 (patch) | |
| tree | e87f649fe0c9d8f382b8f465d1468b6495fb5886 | |
| parent | c862835221decf03b6640bb43e4044861cceaa04 (diff) | |
| parent | 1351220a092414ae593bc006e3a3ebc09523198d (diff) | |
Merge pull request #871 from JaKooLit/development
[Bug] Change to waybar sleep timers was too long, slowed down waybar start/refressh
87 files changed, 3589 insertions, 1056 deletions
@@ -1,3 +1,43 @@ WARP.md .warp.md result + +# Python artifacts +__pycache__/ +*.py[cod] +*.pyo +*.pyd +*.so +*.egg +*.egg-info/ +.eggs/ +dist/ +build/ +eggs/ +pip-wheel-metadata/ + +# Virtual environments +.venv/ +venv/ +env/ +ENV/ +.env + +# Testing and coverage +.pytest_cache/ +.coverage +.cache/ +.tox/ +htmlcov/ + +# Type checking and linting +.mypy_cache/ +.pytype/ +.flake8 +.ruff_cache/ + +# IDE and editor directories +.idea/ +.vscode/ +*.swp +*.swo diff --git a/CHANGELOG.md b/CHANGELOG.md index cd0effc4..f6623708 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,19 +1,46 @@ # Changelog — JAK's Hyprland Dotfiles +## v2.3.18 — 2025-11-05 + +- Keybinds: initialize SUPER+J/K at login to match the default layout (master or dwindle). + - Adds scripts/KeybindsLayoutInit.sh and wires it to Startup_Apps so J/K and O (togglesplit) are correct on first session. + - ChangeLayout.sh continues to rebind dynamically when layouts are toggled. + - Credits: [Suresh Thagunna](https://github.com/suresh466) for identifying the mismatch and proposing an auto-alignment approach. +- Startup config sourcing: load vendor Startup_Apps and WindowRules first, then user overlays, restoring baseline autostarts while keeping user additions. +- Quick Settings: “Edit Startup Apps” opens the full vendor defaults for clarity. + ## October 2025 +### ⌨️ Keybinds + +- Convert Hyprland keybinds to description form (`bindd`, `bindld`, `binded`, + `bindmd`, `bindlnd`) in `config/hypr/...`. +- Add concise descriptions for each keybind; keep the name "powermenu". +- Update `config/hypr/scripts/KeyBinds.sh` to parse and display descriptions + as: MODS+KEY — DESCRIPTION — DISPATCHER [PARAMS]. + ### 🐛 Fixes +- Updated `/bin/bash` to `/usr/bin/env bash` - Correct `windowrule` syntax error. - Ensure wallpaper selector applies wallpaper to SDDM. - Update theme colors when a new wallpaper is selected. +### 🖥️ Jak dotfiles version now in `fastfetch` output. + ### 🌦️ Weather.py +Key Changes: + +- 2nd Weather.py Update by prabinpanta0 - ♻️ Substantial rewrite. -- ✅ Launches properly in Waybar. -- 📍 Improved location detection; overridable variables exposed. -- 🌐 Switched to Open-Meteo for weather data with fallback providers. +- ✨ New unified weather entrypoint (weatherWrap.sh) + - With Python-first execution +- 🔒 Automatic weather updates before screen lock +- 🚀 Weather cache initialization at session startup +- 🛡️ Enhanced error handling and fallback mechanisms +- 📍 Automatic location detection via IP geolocation +- 🎨 Improved weather condition mapping and JSON output ### 🖥️ Support for debian and ubuntu installs @@ -34,6 +61,7 @@ ### 👥 Contributors +- [prabinpanta0](https://github.com/prabinpanta0) - [CharlyMH](https://github.com/CharlyMH) - [ndeekshith](https://github.com/ndeekshith) - [SherLock707](https://github.com/SherLock707) diff --git a/CHANGES-v2.3.18.md b/CHANGES-v2.3.18.md new file mode 100644 index 00000000..29eb7c41 --- /dev/null +++ b/CHANGES-v2.3.18.md @@ -0,0 +1,72 @@ +# CHANGES: Hyprland-Dots v2.3.18 + +## FIXES: + +- Fixed: Overview Toggle keyind SUPER + A now properly detects QuickShell + - If QS fails, or not installed AGS will be started instead +- Fixed: Super J/K cycle next/prev weren't working in both master / dwindle +- Fixed: Weather.py one-off run +- Removed: Hyprsunt from status group. + - Credit: Alberson Miranda +- Added: more application icons for waybars +- Weather.py basically rewritten to improve look and functionality + - Credit: Prabin Panta + - The Jak team also heavily contributed to the rewrite +- Fixed: Waybar + - Changing the waybar config `SUPERALT + B` would sometimes need to be done twice + - Cause: options were incorrect annotated with "👉 ${name}" +- Fixed: `GameMode.sh` to function consistently +- Updated: `WalllustSwww.sh` wallpaper path +- Corrected: Typo in Show Open Apps +- GameMode.sh / Refresh.sh + - Enabling / Disabling repeatedly would result in multiple waybars + - Added additional `sleep` commands in `GameMode.sh` and `Refresh.sh` + - Resolves [Issue 870](https://github.com/JaKooLit/Hyprland-Dots/issues/870) + +## CHANGES: + +- Changed: Hyprland Packages from SID + - No longer built from source + - Hyprland Version @ v0.51.1 + - If/When SID it updated, updates will be done as normal process +- Lock screen: + - Clock now horizontal and smaller + - Adjust spacing margines of the various fields + - Small changes to color variabbles Trying to balance colors + - Fixed both 1080 and 2K+ configurations +- `UserConfigs/Startup_App.conf` is now sourced in `hyprland.conf` + - It was being sourced twice +- Some scripts weren't executable + - `scripts/Battery.sh` + - `scripts/ComposeHyprConfigs.sh` + - `scripts/OverviewToggle.sh` + - `scripts/sddm_wallpaper.sh` +- Updated: SWWW to v0.11.2 + - Fixes numerous issues + - Portrait monitors especially + - SWWW isn't being maintained In future will switch to AWWWW +- Added: A message before installing wallpapers that some are AI generated or enhanced +- Changed: `/usr/bin/bash` to `/usr/bin/evn bash` for better portability +- Adjusted: Small change to `DropDownterminal.sh` + - Increased top margin % to center it more + - Widened it. + - These options are settable in the script. + +## FEATURES: + +- Hyprsunet retains last state on/off + - Credit: Alberson Miranda +- Fastfetch now displays the version of the Jak Dotfiles +- ChangeLayout.sh + - Dynamically binds SUPER J/K based on current layout + - Previously only worked in Master Layout + - Credit: Suresh Thagunna + - Along with that KeybindsLayoutInit script reads current default layout + - Then it adjusts the SUPER J/K keybindings appropriately +- RofiBeats dynamic music system added +- Binds now include descriptions. + - Switched from `bind` to `bindd` + - Improves usability of keybind search +- Add new laptop gesture for zoom system. + +Thanks to everyone that contributed, or reported issues. diff --git a/Distro-Hyprland.sh b/Distro-Hyprland.sh index ff88325f..99a1fc34 100755 --- a/Distro-Hyprland.sh +++ b/Distro-Hyprland.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # https://github.com/JaKooLit # Script design to clone the Distro-Hyprland install scripts diff --git a/config/fastfetch/config-compact.jsonc b/config/fastfetch/config-compact.jsonc index fc2c4884..962b6bb3 100644 --- a/config/fastfetch/config-compact.jsonc +++ b/config/fastfetch/config-compact.jsonc @@ -21,16 +21,22 @@ { "type": "custom", "format": " ─────────────────────────── " - }, + }, { "type": "kernel", "key": " ", "keyColor": "yellow" }, { + "type": "custom", + "key": " ", + "format": "JaKooLit: {$DOTS_VERSION}", + "keyColor": "blue" + }, + { "type": "wm", "key": " ", - "keyColor": "blue" + "keyColor": "magenta" }, { "type": "shell", @@ -69,6 +75,6 @@ "type": "custom", "format": " \u001b[31m \u001b[32m \u001b[33m \u001b[34m \u001b[35m \u001b[36m \u001b[37m \u001b[90m " }, - "break", + "break" ] } diff --git a/config/fastfetch/config-pokemon.jsonc b/config/fastfetch/config-pokemon.jsonc index 2b4522f4..0435033c 100644 --- a/config/fastfetch/config-pokemon.jsonc +++ b/config/fastfetch/config-pokemon.jsonc @@ -27,9 +27,15 @@ "keyColor": "yellow" }, { + "type": "custom", + "key": " ", + "keyColor": "blue", + "format": "JaKooLit Version: {$DOTS_VERSION}" + }, + { "type": "wm", "key": " ", - "keyColor": "blue" + "keyColor": "magenta" }, { "type": "shell", @@ -68,6 +74,6 @@ "type": "custom", "format": " \u001b[31m \u001b[32m \u001b[33m \u001b[34m \u001b[35m \u001b[36m \u001b[37m \u001b[90m " }, - "break", + "break" ] } diff --git a/config/fastfetch/config-v2.jsonc b/config/fastfetch/config-v2.jsonc index 59509fe7..6d20c695 100644 --- a/config/fastfetch/config-v2.jsonc +++ b/config/fastfetch/config-v2.jsonc @@ -20,95 +20,101 @@ { "type": "os", "key": " DISTRO", - "keyColor": "31", + "keyColor": "31" }, { "type": "kernel", "key": " ├ ", - "keyColor": "31", + "keyColor": "31" + }, + { + "type": "custom", + "key": " ├ ", + "format": "JaKooLit Version: {$DOTS_VERSION}", + "keyColor": "31" }, { "type": "packages", "key": " ├ ", - "keyColor": "31", + "keyColor": "31" }, { "type": "shell", "key": " └ ", - "keyColor": "31", + "keyColor": "31" }, "break", { "type": "wm", "key": " DE/WM", - "keyColor": "32", + "keyColor": "32" }, { "type": "wmtheme", "key": " ├ ", - "keyColor": "32", + "keyColor": "32" }, { "type": "icons", "key": " ├ ", - "keyColor": "32", + "keyColor": "32" }, { "type": "cursor", "key": " ├ ", - "keyColor": "32", + "keyColor": "32" }, { "type": "terminal", "key": " ├ ", - "keyColor": "32", + "keyColor": "32" }, { "type": "terminalfont", "key": " └ ", - "keyColor": "32", + "keyColor": "32" }, "break", { "type": "host", "format": "{2}", "key": " SYSTEM", - "keyColor": "33", + "keyColor": "33" }, { "type": "cpu", "format": "{1} ({3}) @ {7} GHz", "key": " ├ ", - "keyColor": "33", + "keyColor": "33" }, { "type": "gpu", "format": "{2}", "key": " ├ ", - "keyColor": "33", + "keyColor": "33" }, { "type": "memory", "key": " ├ ", - "keyColor": "33", + "keyColor": "33" }, { "type": "swap", "key": " ├ ", - "keyColor": "33", + "keyColor": "33" }, { "type": "disk", "key": " ├ ", - "keyColor": "33", + "keyColor": "33" }, { "type": "display", "key": " └ ", "compactType": "original-with-refresh-rate", - "keyColor": "33", + "keyColor": "33" }, "break", - "break", + "break" ] } diff --git a/config/fastfetch/config.jsonc b/config/fastfetch/config.jsonc index e3f8c3c6..dce06d78 100644 --- a/config/fastfetch/config.jsonc +++ b/config/fastfetch/config.jsonc @@ -17,10 +17,17 @@ "key": " DISTRO", "keyColor": "yellow" }, + { "type": "kernel", "key": "│ ├", "keyColor": "yellow" + }, + { + "type": "custom", + "key": "│ ├", + "format": "JaKooLit Version: {$DOTS_VERSION}", + "keyColor": "yellow" }, { "type": "packages", @@ -50,12 +57,12 @@ { "type": "cursor", "key": "│ ├", - "keyColor": "blue", + "keyColor": "blue" }, { "type": "terminalfont", "key": "│ ├", - "keyColor": "blue", + "keyColor": "blue" }, { "type": "terminal", @@ -124,6 +131,6 @@ "type": "custom", "format": "\u001b[90m \u001b[31m \u001b[32m \u001b[33m \u001b[34m \u001b[35m \u001b[36m \u001b[37m \u001b[38m \u001b[39m \u001b[39m \u001b[38m \u001b[37m \u001b[36m \u001b[35m \u001b[34m \u001b[33m \u001b[32m \u001b[31m \u001b[90m " }, - "break", + "break" ] } diff --git a/config/hypr/UserConfigs/ENVariables.conf b/config/hypr/UserConfigs/ENVariables.conf index f24cc306..4e736dc3 100644 --- a/config/hypr/UserConfigs/ENVariables.conf +++ b/config/hypr/UserConfigs/ENVariables.conf @@ -4,6 +4,9 @@ # Set your defaults editor through ENV in ~/.config/hypr/UserConfigs/01-UserDefaults.conf # environment-variables +# Current Version of JakooLit Dotfiles: +env = DOTS_VERSION,2.3.18 + # Toolkit Backend Variables env = GDK_BACKEND,wayland,x11,* env = QT_QPA_PLATFORM,wayland;xcb diff --git a/config/hypr/UserConfigs/UserKeybinds.conf b/config/hypr/UserConfigs/UserKeybinds.conf index 338bf0d1..17711559 100644 --- a/config/hypr/UserConfigs/UserKeybinds.conf +++ b/config/hypr/UserConfigs/UserKeybinds.conf @@ -16,67 +16,68 @@ source= $UserConfigs/01-UserDefaults.conf # common shortcuts #bindr = $mainMod, $mainMod_L, exec, pkill rofi || rofi -show drun -modi drun,filebrowser,run,window # Super Key to Launch rofi menu -bind = $mainMod, D, exec, pkill rofi || true && rofi -show drun -modi drun,filebrowser,run,window # Main Menu (APP Launcher) -bind = $mainMod, B, exec, xdg-open "https://" # default browser -#bind = $mainMod, A, exec, pkill rofi || true && ags -t 'overview' # desktop overview (if installed) -#bind = $mainMod, A, global, quickshell:overviewToggle # desktop overview (if installed) -bind = $mainMod, Return, exec, $term #terminal -bind = $mainMod, E, exec, $files #file manager +bindd = $mainMod, D, app launcher, exec, pkill rofi || true && rofi -show drun -modi drun,filebrowser,run,window +bindd = $mainMod, B, open default browser, exec, xdg-open "https://" +bindd = $mainMod, A, desktop overview, exec, $scriptsDir/OverviewToggle.sh # toggles quickshell or ags overview (tries QS first, falls back to AGS) +#bindd = $mainMod, A, ags overview, exec, pkill rofi || true && ags -t 'overview' # desktop overview (if installed) +#bindd = $mainMod, A, Quickshell overview, global, quickshell:overviewToggle # desktop overview (if installed) +bindd = $mainMod, Return, Open terminal, exec, $term +bindd = $mainMod, E, file manager, exec, $files # FEATURES / EXTRAS -bind = $mainMod, H, exec, $scriptsDir/KeyHints.sh # help / cheat sheet -bind = $mainMod ALT, R, exec, $scriptsDir/Refresh.sh # Refresh waybar, swaync, rofi -bind = $mainMod ALT, E, exec, $scriptsDir/RofiEmoji.sh # emoji menu -bind = $mainMod, S, exec, $scriptsDir/RofiSearch.sh # Google search using rofi -bind = $mainMod CTRL, S, exec, rofi -show window # list/switch apps using rofi -bind = $mainMod ALT, O, exec, $scriptsDir/ChangeBlur.sh # Toggle blur settings -bind = $mainMod SHIFT, G, exec, $scriptsDir/GameMode.sh # Toggle animations ON/OFF -bind = $mainMod ALT, L, exec, $scriptsDir/ChangeLayout.sh # Toggle Master or Dwindle Layout -bind = $mainMod ALT, V, exec, $scriptsDir/ClipManager.sh # Clipboard Manager -bind = $mainMod CTRL, R, exec, $scriptsDir/RofiThemeSelector.sh # KooL Rofi Menu Theme Selector -bind = $mainMod CTRL SHIFT, R, exec, pkill rofi || true && $scriptsDir/RofiThemeSelector-modified.sh # modified Rofi Theme Selector +bindd = $mainMod, H, help / cheat sheet, exec, $scriptsDir/KeyHints.sh +bindd = $mainMod ALT, R, refresh bar and menus, exec, $scriptsDir/Refresh.sh +bindd = $mainMod ALT, E, emoji menu, exec, $scriptsDir/RofiEmoji.sh +bindd = $mainMod, S, web search, exec, $scriptsDir/RofiSearch.sh +bindd = $mainMod CTRL, S, window switcher, exec, rofi -show window +bindd = $mainMod ALT, O, toggle blur, exec, $scriptsDir/ChangeBlur.sh +bindd = $mainMod SHIFT, G, toggle game mode, exec, $scriptsDir/GameMode.sh +bindd = $mainMod ALT, L, toggle master/dwindle layout, exec, $scriptsDir/ChangeLayout.sh +bindd = $mainMod ALT, V, clipboard manager, exec, $scriptsDir/ClipManager.sh +bindd = $mainMod CTRL, R, rofi theme selector, exec, $scriptsDir/RofiThemeSelector.sh +bindd = $mainMod CTRL SHIFT, R, rofi theme selector (modified), exec, pkill rofi || true && $scriptsDir/RofiThemeSelector-modified.sh -bind = $mainMod SHIFT, F, fullscreen # whole full screen -bind = $mainMod CTRL, F, fullscreen, 1 # fake full screen -bind = $mainMod, SPACE, togglefloating, #Float Mode -bind = $mainMod ALT, SPACE, exec, hyprctl dispatch workspaceopt allfloat #All Float Mode -bind = $mainMod SHIFT, Return, exec, $scriptsDir/Dropterminal.sh $term # Dropdown terminal +bindd = $mainMod SHIFT, F, fullscreen, fullscreen +bindd = $mainMod CTRL, F, maximize window, fullscreen, 1 +bindd = $mainMod, SPACE, Float current window, togglefloating, +bindd = $mainMod ALT, SPACE, Float all windows, exec, hyprctl dispatch workspaceopt allfloat +bindd = $mainMod SHIFT, Return, DropDown terminal, exec, $scriptsDir/Dropterminal.sh $term # Desktop zooming or magnifier -bind = $mainMod ALT, mouse_down, exec, hyprctl keyword cursor:zoom_factor "$(hyprctl getoption cursor:zoom_factor | awk 'NR==1 {factor = $2; if (factor < 1) {factor = 1}; print factor * 2.0}')" -bind = $mainMod ALT, mouse_up, exec, hyprctl keyword cursor:zoom_factor "$(hyprctl getoption cursor:zoom_factor | awk 'NR==1 {factor = $2; if (factor < 1) {factor = 1}; print factor / 2.0}')" +bindd = $mainMod ALT, mouse_down, zoom in, exec, hyprctl keyword cursor:zoom_factor "$(hyprctl getoption cursor:zoom_factor | awk 'NR==1 {factor = $2; if (factor < 1) {factor = 1}; print factor * 2.0}')" +bindd = $mainMod ALT, mouse_up, zoom out, exec, hyprctl keyword cursor:zoom_factor "$(hyprctl getoption cursor:zoom_factor | awk 'NR==1 {factor = $2; if (factor < 1) {factor = 1}; print factor / 2.0}')" ## NOTES for ja (Hyprland version 0.39 (Ubuntu 24.04)) #bind = $mainMod ALT, mouse_down, exec, hyprctl keyword misc:cursor_zoom_factor "$(hyprctl getoption misc:cursor_zoom_factor | awk 'NR==1 {factor = $2; if (factor < 1) {factor = 1}; print factor * 2.0}')" #bind = $mainMod ALT, mouse_up, exec, hyprctl keyword misc:cursor_zoom_factor "$(hyprctl getoption misc:cursor_zoom_factor | awk 'NR==1 {factor = $2; if (factor < 1) {factor = 1}; print factor / 2.0}')" # Waybar / Bar related -bind = $mainMod CTRL ALT, B, exec, pkill -SIGUSR1 waybar # Toggle hide/show waybar -bind = $mainMod CTRL, B, exec, $scriptsDir/WaybarStyles.sh # Waybar Styles Menu -bind = $mainMod ALT, B, exec, $scriptsDir/WaybarLayout.sh # Waybar Layout Menu +bindd = $mainMod CTRL ALT, B, toggle waybar on/off, exec, pkill -SIGUSR1 waybar +bindd = $mainMod CTRL, B, waybar styles menu, exec, $scriptsDir/WaybarStyles.sh +bindd = $mainMod ALT, B, waybar layout menu, exec, $scriptsDir/WaybarLayout.sh # Night light toggle (Hyprsunset) -bind = $mainMod, N, exec, $scriptsDir/Hyprsunset.sh toggle +bindd = $mainMod, N, toggle night light, exec, $scriptsDir/Hyprsunset.sh toggle # FEATURES / EXTRAS (UserScripts) -bind = $mainMod SHIFT, M, exec, $UserScripts/RofiBeats.sh # online music using rofi -bind = $mainMod, W, exec, $UserScripts/WallpaperSelect.sh # Select wallpaper to apply -bind = $mainMod SHIFT, W, exec, $UserScripts/WallpaperEffects.sh # Wallpaper Effects by imagemagick -bind = CTRL ALT, W, exec, $UserScripts/WallpaperRandom.sh # Random wallpapers -bind = $mainMod CTRL, O, exec, hyprctl setprop active opaque toggle # disable opacity on active window -bind = $mainMod SHIFT, K, exec, $scriptsDir/KeyBinds.sh # search keybinds via rofi -bind = $mainMod SHIFT, A, exec, $scriptsDir/Animations.sh #hyprland animations menu -bind = $mainMod SHIFT, O, exec, $UserScripts/ZshChangeTheme.sh # Change oh-my-zsh theme -bindln = ALT_L, SHIFT_L, exec, $scriptsDir/SwitchKeyboardLayout.sh # Change keyboard layout globally -bindln = SHIFT_L, ALT_L, exec, $scriptsDir/Tak0-Per-Window-Switch.sh # Change keyboard layout locally for each window -bind = $mainMod ALT, C, exec, $UserScripts/RofiCalc.sh # calculator (qalculate) +bindd = $mainMod SHIFT, M, online music, exec, $UserScripts/RofiBeats.sh +bindd = $mainMod, W, select wallpaper, exec, $UserScripts/WallpaperSelect.sh +bindd = $mainMod SHIFT, W, wallpaper effects, exec, $UserScripts/WallpaperEffects.sh +bindd = CTRL ALT, W, random wallpaper, exec, $UserScripts/WallpaperRandom.sh +bindd = $mainMod CTRL, O, toggle active window opacity, exec, hyprctl setprop active opaque toggle +bindd = $mainMod SHIFT, K, search keybinds, exec, $scriptsDir/KeyBinds.sh +bindd = $mainMod SHIFT, A, animations menu, exec, $scriptsDir/Animations.sh +bindd = $mainMod SHIFT, O, change oh-my-zsh theme, exec, $UserScripts/ZshChangeTheme.sh +bindlnd = ALT_L, SHIFT_L, switch keyboard layout globally, exec, $scriptsDir/SwitchKeyboardLayout.sh +bindlnd = SHIFT_L, ALT_L, switch keyboard layout per-window, exec, $scriptsDir/Tak0-Per-Window-Switch.sh +bindd = $mainMod ALT, C, calculator, exec, $UserScripts/RofiCalc.sh # Move current workspaces to monitors (left right up or down) -bind = $mainMod CTRL, F9, movecurrentworkspacetomonitor, l #move current workspace to LEFT monitor -bind = $mainMod CTRL, F10, movecurrentworkspacetomonitor, r #move current workspace to RIGHT monitor -bind = $mainMod CTRL, F11, movecurrentworkspacetomonitor, u #move current workspace to UP monitor -bind = $mainMod CTRL, F12, movecurrentworkspacetomonitor, d #move current workspace to DOWN monitor +bindd = $mainMod CTRL, F9, move workspace to left monitor, movecurrentworkspacetomonitor, l +bindd = $mainMod CTRL, F10, move workspace to right monitor, movecurrentworkspacetomonitor, r +bindd = $mainMod CTRL, F11, move workspace to up monitor, movecurrentworkspacetomonitor, u +bindd = $mainMod CTRL, F12, move workspace to down monitor, movecurrentworkspacetomonitor, d # For passthrough keyboard into a VM diff --git a/config/hypr/UserConfigs/UserSettings.conf b/config/hypr/UserConfigs/UserSettings.conf index f81ccc6a..4802e79a 100644 --- a/config/hypr/UserConfigs/UserSettings.conf +++ b/config/hypr/UserConfigs/UserSettings.conf @@ -73,6 +73,8 @@ gestures { workspace_swipe_create_new = true workspace_swipe_forever = true #workspace_swipe_use_r = true #uncomment if wanted a forever create a new workspace with swipe right + gesture = 3, up, dispatcher, exec, hyprctl keyword cursor:zoom_factor "$(hyprctl getoption cursor:zoom_factor | awk 'NR==1 {factor = $2; if (factor < 1) {factor = 1}; print factor * 1.5}')" + gesture = 3, down, dispatcher, exec, hyprctl keyword cursor:zoom_factor "$(hyprctl getoption cursor:zoom_factor | awk 'NR==1 {factor = $2; if (factor < 1) {factor = 1}; print factor / 1.5}')" } misc { diff --git a/config/hypr/UserConfigs/WindowRules-v3.conf b/config/hypr/UserConfigs/WindowRules-v3.conf new file mode 100644 index 00000000..f093faf6 --- /dev/null +++ b/config/hypr/UserConfigs/WindowRules-v3.conf @@ -0,0 +1,671 @@ +# /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ # +# For window rules and layerrules +# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more + +# NOTES: This is only for Hyprland > 0.52 + +# note for ja: This should NOT be implemented on Debian and Ubuntu + +# windowrule - tags - add apps under appropriate tag to use the same settings +# browser tags +# notif tags +# KooL settings tag +# terminal tags +# email tags +# project tags +# screenshare tags +# IM tags +# game tags +# gamestore tags +# file-manager tags +# wallpaper tags +# multimedia tags +# multimedia-video tags +# settings tags +# viewer tags +# Some special override rules + +# POSITION +# windowrule = center,floating:1 # warning, it cause even the menu to float and center. +#windowrule = move 72% 7%,title:^(Firefox)$ + +# windowrule to avoid idle for fullscreen apps +#windowrule = idleinhibit fullscreen, class:^(*)$ +#windowrule = idleinhibit fullscreen, title:^(*)$ + +# windowrule move to workspace +#windowrule = workspace 1, tag:email* +#windowrule = workspace 2, tag:browser* +#windowrule = workspace 3, class:^([Tt]hunar)$ +#windowrule = workspace 3, tag:projects* +#windowrule = workspace 5, tag:gamestore* +#windowrule = workspace 7, tag:im* +#windowrule = workspace 8, tag:games* + +# windowrule move to workspace (silent) +#windowrule = workspace 4 silent, tag:screenshare* +#windowrule = workspace 6 silent, class:^(virt-manager)$ +#windowrule = workspace 6 silent, class:^(.virt-manager-wrapped)$ +#windowrule = workspace 9 silent, tag:multimedia* +# +# FLOAT +#windowrule = float, class:^([Ww]hatsapp-for-linux|ZapZap|com.rtosta.zapzap)$ +#windowrule = float, title:^(Firefox)$ + +# windowrule - ######### float popups and dialogue ####### + + +# OPACITY + +# SIZE + +#windowrule = size 25% 25%, title:^(Picture-in-Picture)$ +#windowrule = size 25% 25%, title:^(Firefox)$ + +# PINNING +#windowrule = pin,title:^(Firefox)$ + +# windowrule - extras + +# BLUR & FULLSCREEN + + +#This not gonna take the focus to the window that appears when hovering over some of the parts of the IntelliJ Products + +#This will gonna make the VS Code bluer like other apps + +#windowrule = bordercolor rgb(EE4B55) rgb(880808), fullscreen:1 +#windowrule = bordercolor rgb(282737) rgb(1E1D2D), floating:1 +#windowrule = opacity 0.8 0.8, pinned:1 + +# LAYER RULES + +#layerrule = ignorealpha 0.5, tag:notif* + +#layerrule = ignorezero, class:^([Rr]ofi)$ +#layerrule = blur, class:^([Rr]ofi)$ +#layerrule = unset,class:^([Rr]ofi)$ +#layerrule = ignorezero, <rofi> + +#layerrule = ignorezero, overview +#layerrule = blur, overview + +# --- Auto-generated window rules --- +windowrule { + name = windowrule-1 + match:class = ^([Ff]irefox|org.mozilla.firefox|[Ff]irefox-esr|[Ff]irefox-bin)$ + tag = +browser +} + +windowrule { + name = windowrule-2 + match:class = ^([Gg]oogle-chrome(-beta|-dev|-unstable)?)$ + tag = +browser +} + +windowrule { + name = windowrule-3 + match:class = ^(chrome-.+-Default)$ # Chrome PWAs + tag = +browser +} + +windowrule { + name = windowrule-4 + match:class = ^([Cc]hromium)$ + tag = +browser +} + +windowrule { + name = windowrule-5 + match:class = ^([Mm]icrosoft-edge(-stable|-beta|-dev|-unstable))$ + tag = +browser +} + +windowrule { + name = windowrule-6 + match:class = ^(Brave-browser(-beta|-dev|-unstable)?)$ + tag = +browser +} + +windowrule { + name = windowrule-7 + match:class = ^([Tt]horium-browser|[Cc]achy-browser)$ + tag = +browser +} + +windowrule { + name = windowrule-8 + match:class = ^(zen-alpha|zen)$ + tag = +browser +} + +windowrule { + name = windowrule-9 + match:class = ^(swaync-control-center|swaync-notification-window|swaync-client|class)$ + tag = +notif +} + +windowrule { + name = windowrule-10 + match:title = ^(KooL Quick Cheat Sheet)$ + tag = +KooL_Cheat +} + +windowrule { + name = windowrule-11 + match:title = ^(KooL Hyprland Settings)$ + tag = +KooL_Settings +} + +windowrule { + name = windowrule-12 + match:class = ^(nwg-displays|nwg-look)$ + tag = +KooL-Settings +} + +windowrule { + name = windowrule-13 + match:class = ^(Alacritty|kitty|kitty-dropterm)$ + tag = +terminal +} + +windowrule { + name = windowrule-14 + match:class = ^([Tt]hunderbird|org.gnome.Evolution)$ + tag = +email +} + +windowrule { + name = windowrule-15 + match:class = ^(eu.betterbird.Betterbird)$ + tag = +email +} + +windowrule { + name = windowrule-16 + match:class = ^(codium|codium-url-handler|VSCodium)$ + tag = +projects +} + +windowrule { + name = windowrule-17 + match:class = ^(VSCode|code-url-handler)$ + tag = +projects +} + +windowrule { + name = windowrule-18 + match:class = ^(jetbrains-.+)$ # JetBrains IDEs + tag = +projects +} + +windowrule { + name = windowrule-19 + match:class = ^(com.obsproject.Studio)$ + tag = +screenshare +} + +windowrule { + name = windowrule-20 + match:class = ^([Dd]iscord|[Ww]ebCord|[Vv]esktop)$ + tag = +im +} + +windowrule { + name = windowrule-21 + match:class = ^([Ff]erdium)$ + center = on + float = on + size = 60% = 70% + tag = +im +} + +windowrule { + name = windowrule-22 + match:class = ^([Ww]hatsapp-for-linux)$ + tag = +im +} + +windowrule { + name = windowrule-23 + match:class = ^(ZapZap|com.rtosta.zapzap)$ + tag = +im +} + +windowrule { + name = windowrule-24 + match:class = ^(org.telegram.desktop|io.github.tdesktop_x64.TDesktop)$ + tag = +im +} + +windowrule { + name = windowrule-25 + match:class = ^(teams-for-linux)$ + tag = +im +} + +windowrule { + name = windowrule-26 + match:class = ^(im.riot.Riot|Element)$ # Element Matrix client + tag = +im +} + +windowrule { + name = windowrule-27 + match:class = ^(gamescope)$ + tag = +games +} + +windowrule { + name = windowrule-28 + match:class = ^(steam_app_\d+)$ + tag = +games +} + +windowrule { + name = windowrule-29 + match:class = ^([Ss]team)$ + tag = +gamestore +} + +windowrule { + name = windowrule-30 + match:title = ^([Ll]utris)$ + tag = +gamestore +} + +windowrule { + name = windowrule-31 + match:class = ^(com.heroicgameslauncher.hgl)$ + tag = +gamestore +} + +windowrule { + name = windowrule-32 + match:class = ^([Tt]hunar|org.gnome.Nautilus|[Pp]cmanfm-qt)$ + tag = +file-manager +} + +windowrule { + name = windowrule-33 + match:class = ^(app.drey.Warp)$ + tag = +file-manager +} + +windowrule { + name = windowrule-34 + match:class = ^([Ww]aytrogen)$ + tag = +wallpaper +} + +windowrule { + name = windowrule-35 + match:class = ^([Aa]udacious)$ + tag = +multimedia +} + +windowrule { + name = windowrule-36 + match:class = ^([Mm]pv|vlc)$ + tag = +multimedia_video +} + +windowrule { + name = windowrule-37 + match:title = ^(ROG Control)$ + center = on + tag = +settings +} + +windowrule { + name = windowrule-38 + match:class = ^(wihotspot(-gui)?)$ # wifi hotspot + tag = +settings +} + +windowrule { + name = windowrule-39 + match:class = ^([Bb]aobab|org.gnome.[Bb]aobab)$ # Disk usage analyzer + tag = +settings +} + +windowrule { + name = windowrule-40 + match:class = ^(gnome-disks|wihotspot(-gui)?)$ + tag = +settings +} + +windowrule { + name = windowrule-41 + match:title = (Kvantum Manager) + tag = +settings +} + +windowrule { + name = windowrule-42 + match:class = ^(file-roller|org.gnome.FileRoller)$ # archive manager + tag = +settings +} + +windowrule { + name = windowrule-43 + match:class = ^(nm-applet|nm-connection-editor|blueman-manager)$ + tag = +settings +} + +windowrule { + name = windowrule-44 + match:class = ^(pavucontrol|org.pulseaudio.pavucontrol|com.saivert.pwvucontrol)$ + center = on + tag = +settings +} + +windowrule { + name = windowrule-45 + match:class = ^(qt5ct|qt6ct|[Yy]ad)$ + tag = +settings +} + +windowrule { + name = windowrule-46 + match:class = (xdg-desktop-portal-gtk) + tag = +settings +} + +windowrule { + name = windowrule-47 + match:class = ^(org.kde.polkit-kde-authentication-agent-1)$ + tag = +settings +} + +windowrule { + name = windowrule-48 + match:class = ^([Rr]ofi)$ + tag = +settings +} + +windowrule { + name = windowrule-49 + match:class = ^(gnome-system-monitor|org.gnome.SystemMonitor|io.missioncenter.MissionCenter)$ # system monitor + tag = +viewer +} + +windowrule { + name = windowrule-50 + match:class = ^(evince)$ # document viewer + tag = +viewer +} + +windowrule { + name = windowrule-51 + match:class = ^(eog|org.gnome.Loupe)$ # image viewer + tag = +viewer +} + +windowrule { + name = windowrule-52 + match:tag = multimedia_video* + no_blur = on + opacity = 1.0 +} + +windowrule { + name = windowrule-53 + match:tag = KooL_Cheat* + center = on + float = on + size = 65% = 90% +} + +windowrule { + name = windowrule-54 + match:class = ([Tt]hunar) + match:title = negative:(.*[Tt]hunar.*) + center = on + float = on +} + +windowrule { + name = windowrule-55 + match:tag = KooL-Settings* + center = on + float = on +} + +windowrule { + name = windowrule-56 + match:title = ^(Keybindings)$ + center = on +} + +windowrule { + name = windowrule-57 + match:class = ^([Ww]hatsapp-for-linux|ZapZap|com.rtosta.zapzap)$ + center = on + size = 60% = 70% +} + +windowrule { + name = windowrule-58 + match:title = ^(Picture-in-Picture)$ + float = on + move = 72% = 7% + opacity = 0.95 = 0.75 + pin = 0 +} + +windowrule { + name = windowrule-59 + match:fullscreen = 1 + idle_inhibit = fullscreen +} + +windowrule { + name = windowrule-60 + match:tag = wallpaper* + float = on + opacity = 0.9 = 0.7 + size = 70% = 70% +} + +windowrule { + name = windowrule-61 + match:tag = settings* + float = on + opacity = 0.8 = 0.7 + size = 70% = 70% +} + +windowrule { + name = windowrule-62 + match:tag = viewer* + float = on + opacity = 0.82 = 0.75 +} + +windowrule { + name = windowrule-63 + match:class = ([Zz]oom|onedriver|onedriver-launcher)$ + float = on +} + +windowrule { + name = windowrule-64 + match:class = (org.gnome.Calculator) + match:title = (Calculator) + float = on +} + +windowrule { + name = windowrule-65 + match:class = ^(mpv|com.github.rafostar.Clapper)$ + float = on +} + +windowrule { + name = windowrule-66 + match:class = ^([Qq]alculate-gtk)$ + float = on +} + +windowrule { + name = windowrule-67 + match:title = ^(Authentication Required)$ + center = on + float = on +} + +windowrule { + name = windowrule-68 + match:class = (codium|codium-url-handler|VSCodium) + match:title = negative:(.*codium.*|.*VSCodium.*) + float = on +} + +windowrule { + name = windowrule-69 + match:class = ^(com.heroicgameslauncher.hgl)$ + match:title = negative:(Heroic Games Launcher) + float = on +} + +windowrule { + name = windowrule-70 + match:class = ^([Ss]team)$ + match:title = negative:^([Ss]team)$ + float = on +} + +windowrule { + name = windowrule-71 + match:title = ^(Add Folder to Workspace)$ + center = on + float = on + size = 70% = 60% +} + +windowrule { + name = windowrule-72 + match:title = ^(Save As)$ + center = on + float = on + size = 70% = 60% +} + +windowrule { + name = windowrule-73 + match:initial_title = (Open Files) + float = on + size = 70% = 60% +} + +windowrule { + name = windowrule-74 + match:title = ^(SDDM Background)$ #KooL's Dots YAD for setting SDDM background + center = on + float = on + size = 16% = 12% +} + +windowrule { + name = windowrule-75 + match:tag = browser* + opacity = 0.99 = 0.8 +} + +windowrule { + name = windowrule-76 + match:tag = projects* + opacity = 0.9 = 0.8 +} + +windowrule { + name = windowrule-77 + match:tag = im* + opacity = 0.94 = 0.86 +} + +windowrule { + name = windowrule-78 + match:tag = multimedia* + opacity = 0.94 = 0.86 +} + +windowrule { + name = windowrule-79 + match:tag = file-manager* + opacity = 0.9 = 0.8 +} + +windowrule { + name = windowrule-80 + match:tag = terminal* + opacity = 0.9 = 0.7 +} + +windowrule { + name = windowrule-81 + match:class = ^(gedit|org.gnome.TextEditor|mousepad)$ + opacity = 0.8 = 0.7 +} + +windowrule { + name = windowrule-82 + match:class = ^(deluge)$ + opacity = 0.9 = 0.8 +} + +windowrule { + name = windowrule-83 + match:class = ^(seahorse)$ # gnome-keyring gui + opacity = 0.9 = 0.8 +} + +windowrule { + name = windowrule-84 + match:class = ^(code)$ + opacity = 0.8 + opacity = 0.9 +} + +windowrule { + name = windowrule-85 + match:tag = games* + fullscreen = 0 + no_blur = on +} + +windowrule { + name = windowrule-86 + match:class = ^(jetbrains-*) + no_initial_focus = on +} + +windowrule { + name = windowrule-87 + match:title = ^(wind.*)$ + no_initial_focus = on +} + +# --- Auto-generated layer rules --- +layerrule { + name = layerrule-1 + match:namespace = rofi + blur = on + ignore_alpha = 0 +} + +layerrule { + name = layerrule-2 + match:namespace = notifications + blur = on + ignore_alpha = 0 +} + +layerrule { + name = layerrule-3 + match:namespace = quickshell:overview + blur = on + ignore_alpha = 0 + ignore_alpha = 0.5 +} diff --git a/config/hypr/UserConfigs/WindowRules.conf b/config/hypr/UserConfigs/WindowRules.conf index d6959dc4..2c24dafc 100644 --- a/config/hypr/UserConfigs/WindowRules.conf +++ b/config/hypr/UserConfigs/WindowRules.conf @@ -113,20 +113,20 @@ windowrule = move 72% 7%,title:^(Picture-in-Picture)$ windowrule = idleinhibit fullscreen, fullscreen:1 # windowrule move to workspace -windowrule = workspace 1, tag:email* -windowrule = workspace 2, tag:browser* +#windowrule = workspace 1, tag:email* +#windowrule = workspace 2, tag:browser* #windowrule = workspace 3, class:^([Tt]hunar)$ #windowrule = workspace 3, tag:projects* -windowrule = workspace 5, tag:gamestore* -windowrule = workspace 7, tag:im* -windowrule = workspace 8, tag:games* +#windowrule = workspace 5, tag:gamestore* +#windowrule = workspace 7, tag:im* +#windowrule = workspace 8, tag:games* # windowrule move to workspace (silent) -windowrule = workspace 4 silent, tag:screenshare* -windowrule = workspace 6 silent, class:^(virt-manager)$ -windowrule = workspace 6 silent, class:^(.virt-manager-wrapped)$ -windowrule = workspace 9 silent, tag:multimedia* - +#windowrule = workspace 4 silent, tag:screenshare* +#windowrule = workspace 6 silent, class:^(virt-manager)$ +#windowrule = workspace 6 silent, class:^(.virt-manager-wrapped)$ +#windowrule = workspace 9 silent, tag:multimedia* +# # FLOAT windowrule = float, tag:KooL_Cheat* windowrule = float, tag:wallpaper* @@ -167,12 +167,12 @@ windowrule = size 16% 12%, title:^(SDDM Background)$ #KooL's Dots YAD for settin # END of float popups and dialogue ####### # OPACITY -windowrule = opacity 0.9 0.7, tag:browser* +windowrule = opacity 0.99 0.8, tag:browser* windowrule = opacity 0.9 0.8, tag:projects* windowrule = opacity 0.94 0.86, tag:im* windowrule = opacity 0.94 0.86, tag:multimedia* windowrule = opacity 0.9 0.8, tag:file-manager* -windowrule = opacity 0.8 0.7, tag:terminal* +windowrule = opacity 0.9 0.7, tag:terminal* windowrule = opacity 0.8 0.7, tag:settings* windowrule = opacity 0.82 0.75, tag:viewer* windowrule = opacity 0.9 0.7, tag:wallpaper* diff --git a/config/hypr/UserScripts/RainbowBorders.sh b/config/hypr/UserScripts/RainbowBorders.sh index cc1419fb..0a7fd721 100755 --- a/config/hypr/UserScripts/RainbowBorders.sh +++ b/config/hypr/UserScripts/RainbowBorders.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # for rainbow borders animation diff --git a/config/hypr/UserScripts/RofiBeats.sh b/config/hypr/UserScripts/RofiBeats.sh index 1cddce09..a002a518 100755 --- a/config/hypr/UserScripts/RofiBeats.sh +++ b/config/hypr/UserScripts/RofiBeats.sh @@ -1,35 +1,39 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## -# For Rofi Beats to play online Music or Locally saved media files +# RofiBeats - unified, dynamic UI (add, remove, manage, play) -# Variables mDIR="$HOME/Music/" iDIR="$HOME/.config/swaync/icons" rofi_theme="$HOME/.config/rofi/config-rofi-Beats.rasi" -rofi_theme_1="$HOME/.config/rofi/config-rofi-Beats-menu.rasi" +rofi_theme_menu="$HOME/.config/rofi/config-rofi-Beats-menu.rasi" +music_list="$HOME/.config/rofi/online_music.list" -# Online Stations. Edit as required -declare -A online_music=( - ["FM - Easy Rock 96.3 📻🎶"]="https://radio-stations-philippines.com/easy-rock" - ["FM - Easy Rock - Baguio 91.9 📻🎶"]="https://radio-stations-philippines.com/easy-rock-baguio" - ["FM - Love Radio 90.7 📻🎶"]="https://radio-stations-philippines.com/love" - ["FM - WRock - CEBU 96.3 📻🎶"]="https://onlineradio.ph/126-96-3-wrock.html" - ["FM - Fresh Philippines 📻🎶"]="https://onlineradio.ph/553-fresh-fm.html" - ["Radio - Lofi Girl 🎧🎶"]="https://play.streamafrica.net/lofiradio" - ["Radio - Chillhop 🎧🎶"]="http://stream.zeno.fm/fyn8eh3h5f8uv" - ["Radio - Ibiza Global 🎧🎶"]="https://filtermusic.net/ibiza-global" - ["Radio - Metal Music 🎧🎶"]="https://tunein.com/radio/mETaLmuSicRaDio-s119867/" - ["YT - Wish 107.5 YT Pinoy HipHop 📻🎶"]="https://youtube.com/playlist?list=PLkrzfEDjeYJnmgMYwCKid4XIFqUKBVWEs&si=vahW_noh4UDJ5d37" - ["YT - Youtube Top 100 Songs Global 📹🎶"]="https://youtube.com/playlist?list=PL4fGSI1pDJn6puJdseH2Rt9sMvt9E2M4i&si=5jsyfqcoUXBCSLeu" - ["YT - Wish 107.5 YT Wishclusives 📹🎶"]="https://youtube.com/playlist?list=PLkrzfEDjeYJn5B22H9HOWP3Kxxs-DkPSM&si=d_Ld2OKhGvpH48WO" - ["YT - Relaxing Piano Music 🎹🎶"]="https://youtu.be/6H7hXzjFoVU?si=nZTPREC9lnK1JJUG" - ["YT - Youtube Remix 📹🎶"]="https://youtube.com/playlist?list=PLeqTkIUlrZXlSNn3tcXAa-zbo95j0iN-0" - ["YT - Korean Drama OST 📹🎶"]="https://youtube.com/playlist?list=PLUge_o9AIFp4HuA-A3e3ZqENh63LuRRlQ" - ["YT - lofi hip hop radio beats 📹🎶"]="https://www.youtube.com/live/jfKfPfyJRdk?si=PnJIA9ErQIAw6-qd" - ["YT - Relaxing Piano Jazz Music 🎹🎶"]="https://youtu.be/85UEqRat6E4?si=jXQL1Yp2VP_G6NSn" -) +mkdir -p "$(dirname "$music_list")" +[[ -f "$music_list" ]] || touch "$music_list" -# Populate local_music array with files from music directory and subdirectories +# Send notification +notification() { + notify-send -u normal -i "$iDIR/music.png" "$@" +} + +# Check if mpv is currently playing +music_playing() { pgrep -x "mpv" >/dev/null; } + +# Stop all mpv processes except mpvpaper +stop_music() { + mpv_pids=$(pgrep -x mpv) + if [ -n "$mpv_pids" ]; then + mpvpaper_pid=$(ps aux | grep -- 'unique-wallpaper-process' | grep -v 'grep' | awk '{print $2}') + for pid in $mpv_pids; do + if ! echo "$mpvpaper_pid" | grep -q "$pid"; then + kill -9 $pid || true + fi + done + notification "Music stopped" + fi +} + +# Populate local music file list populate_local_music() { local_music=() filenames=() @@ -39,115 +43,94 @@ populate_local_music() { done < <(find -L "$mDIR" -type f \( -iname "*.mp3" -o -iname "*.flac" -o -iname "*.wav" -o -iname "*.ogg" -o -iname "*.mp4" \)) } -# Function for displaying notifications -notification() { - notify-send -u normal -i "$iDIR/music.png" "Now Playing:" "$@" -} - -# Main function for playing local music +# Play selected local music file play_local_music() { populate_local_music - - # Prompt the user to select a song - choice=$(printf "%s\n" "${filenames[@]}" | rofi -i -dmenu -config $rofi_theme) - - if [ -z "$choice" ]; then - exit 1 - fi - - # Find the corresponding file path based on user's choice and set that to play the song then continue on the list - for (( i=0; i<"${#filenames[@]}"; ++i )); do + choice=$(printf "%s\n" "${filenames[@]}" | rofi -i -dmenu -config "$rofi_theme" \ + -theme-str 'entry { placeholder: "🎵 Choose Local Music"; }') + [[ -z "$choice" ]] && exit 1 + for ((i = 0; i < "${#filenames[@]}"; ++i)); do if [ "${filenames[$i]}" = "$choice" ]; then - - if music_playing; then - stop_music - fi - notification "$choice" - mpv --playlist-start="$i" --loop-playlist --vid=no "${local_music[@]}" - + music_playing && stop_music + notification "Now Playing:" "$choice" + mpv --no-video --playlist-start="$i" --loop-playlist "${local_music[@]}" break fi done } -# Main function for shuffling local music +# Shuffle and play all local music shuffle_local_music() { - if music_playing; then - stop_music - fi + music_playing && stop_music notification "Shuffle Play local music" - - # Play music in $mDIR on shuffle - mpv --shuffle --loop-playlist --vid=no "$mDIR" + mpv --no-video --shuffle --loop-playlist "$mDIR" } -# Main function for playing online music +# Play selected online music play_online_music() { - choice=$(for online in "${!online_music[@]}"; do - echo "$online" - done | sort | rofi -i -dmenu -config "$rofi_theme") - - if [ -z "$choice" ]; then - exit 1 + if [ ! -s "$music_list" ]; then + notify-send -u low -i "$iDIR/music.png" "No online music found" "Add some with Manage Music" + exit 0 fi - - link="${online_music[$choice]}" - - if music_playing; then - stop_music - fi - notification "$choice" - - # Play the selected online music using mpv - mpv --shuffle --vid=no "$link" -} - -# Function to check if music is already playing -music_playing() { - pgrep -x "mpv" > /dev/null + choice=$(awk -F'|' '{print $1}' "$music_list" | sort | rofi -i -dmenu -config "$rofi_theme" \ + -theme-str 'entry { placeholder: "🌐 Choose Online Station"; }') + [[ -z "$choice" ]] && exit 1 + link=$(awk -F'|' -v name="$choice" '$1 == name {print $2; exit}' "$music_list") + [[ -z "$link" ]] && { + notify-send -u low -i "$iDIR/music.png" "URL not found for" "$choice" + exit 1 + } + music_playing && stop_music + notification "Now Playing:" "$choice" + mpv --no-video --shuffle "$link" } -# Function to stop music and kill mpv processes -stop_music() { - mpv_pids=$(pgrep -x mpv) +# Manage online music list (add, remove, view) +manage_music() { + sub_choice=$(printf "Add Music\nRemove Music\nView List" | rofi -dmenu \ + -config "$rofi_theme_menu" \ + -theme-str 'entry { placeholder: "🛠️ Manage Music List"; }') - if [ -n "$mpv_pids" ]; then - # Get the PID of the mpv process used by mpvpaper (using the unique argument added) - mpvpaper_pid=$(ps aux | grep -- 'unique-wallpaper-process' | grep -v 'grep' | awk '{print $2}') - - for pid in $mpv_pids; do - if ! echo "$mpvpaper_pid" | grep -q "$pid"; then - kill -9 $pid || true - fi - done - notify-send -u low -i "$iDIR/music.png" "Music stopped" || true - fi + case "$sub_choice" in + "Add Music") + name=$(rofi -dmenu -lines 0 -config "$rofi_theme_menu" \ + -theme-str 'entry { placeholder: "🎼 Enter Music Title"; }') + [[ -z "$name" ]] && return + url=$(rofi -dmenu -lines 0 -config "$rofi_theme_menu" \ + -theme-str 'entry { placeholder: "🔗 Enter Music URL"; }') + [[ -z "$url" ]] && return + echo "$name|$url" >>"$music_list" + notification "Added" "$name" + ;; + "Remove Music") + entry=$(awk -F'|' '{print $1}' "$music_list" | rofi -dmenu -config "$rofi_theme_menu" \ + -theme-str 'entry { placeholder: "🗑️ Select Music to Remove"; }') + [[ -z "$entry" ]] && return + grep -vF "$entry" "$music_list" >"$music_list.tmp" && mv "$music_list.tmp" "$music_list" + notification "Removed" "$entry" + ;; + "View List") + # Show only titles, not URLs + awk -F'|' '{print $1}' "$music_list" | rofi -dmenu -config "$rofi_theme_menu" \ + -theme-str 'entry { placeholder: "📜 Online Music List"; }' >/dev/null + ;; + esac } +# Main menu user_choice=$(printf "%s\n" \ "Play from Online Stations" \ "Play from Music directory" \ "Shuffle Play from Music directory" \ "Stop RofiBeats" \ - | rofi -dmenu -config $rofi_theme_1) - -echo "User choice: $user_choice" + "Manage Music List" | + rofi -dmenu -config "$rofi_theme_menu" \ + -theme-str 'entry { placeholder: "🎧 RofiBeats Menu"; }') case "$user_choice" in - "Play from Online Stations") - play_online_music - ;; - "Play from Music directory") - play_local_music - ;; - "Shuffle Play from Music directory") - shuffle_local_music - ;; - "Stop RofiBeats") - if music_playing; then - stop_music - fi - ;; - *) - ;; +"Play from Online Stations") play_online_music ;; +"Play from Music directory") play_local_music ;; +"Shuffle Play from Music directory") shuffle_local_music ;; +"Stop RofiBeats") music_playing && stop_music ;; +"Manage Music List") manage_music ;; esac diff --git a/config/hypr/UserScripts/RofiCalc.sh b/config/hypr/UserScripts/RofiCalc.sh index 4b3b8b69..b72d5f3e 100755 --- a/config/hypr/UserScripts/RofiCalc.sh +++ b/config/hypr/UserScripts/RofiCalc.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ # /* Calculator (using qalculate) and rofi */ # /* Submitted by: https://github.com/JosephArmas */ diff --git a/config/hypr/UserScripts/Tak0-Autodispatch.sh b/config/hypr/UserScripts/Tak0-Autodispatch.sh index a1f72129..114a3e8e 100755 --- a/config/hypr/UserScripts/Tak0-Autodispatch.sh +++ b/config/hypr/UserScripts/Tak0-Autodispatch.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # USAGE / ІНСТРУКЦІЯ: # 1) Run from terminal: # ./dispatch.sh <application_command> <target_workspace_number> diff --git a/config/hypr/UserScripts/WallpaperAutoChange.sh b/config/hypr/UserScripts/WallpaperAutoChange.sh index a6d2cedd..6d8e8735 100755 --- a/config/hypr/UserScripts/WallpaperAutoChange.sh +++ b/config/hypr/UserScripts/WallpaperAutoChange.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # source https://wiki.archlinux.org/title/Hyprland#Using_a_script_to_change_wallpaper_every_X_minutes diff --git a/config/hypr/UserScripts/WallpaperEffects.sh b/config/hypr/UserScripts/WallpaperEffects.sh index ac8fc0e8..89577efa 100755 --- a/config/hypr/UserScripts/WallpaperEffects.sh +++ b/config/hypr/UserScripts/WallpaperEffects.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ # # Wallpaper Effects using ImageMagick (SUPER SHIFT W) diff --git a/config/hypr/UserScripts/WallpaperRandom.sh b/config/hypr/UserScripts/WallpaperRandom.sh index 79396508..654d4bd3 100755 --- a/config/hypr/UserScripts/WallpaperRandom.sh +++ b/config/hypr/UserScripts/WallpaperRandom.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # Script for Random Wallpaper ( CTRL ALT W) diff --git a/config/hypr/UserScripts/WallpaperSelect.sh b/config/hypr/UserScripts/WallpaperSelect.sh index 466832ba..9e51125f 100755 --- a/config/hypr/UserScripts/WallpaperSelect.sh +++ b/config/hypr/UserScripts/WallpaperSelect.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ # This script for selecting wallpapers (SUPER W) diff --git a/config/hypr/UserScripts/Weather.py b/config/hypr/UserScripts/Weather.py index ca1d5281..a6483777 100755 --- a/config/hypr/UserScripts/Weather.py +++ b/config/hypr/UserScripts/Weather.py @@ -3,21 +3,48 @@ # Rewritten to use Open-Meteo APIs (worldwide, no API key) for robust weather data. # Outputs Waybar-compatible JSON and a simple text cache. +from __future__ import annotations + import json import os import sys import time import html -from typing import Any, Dict, List, Optional, Tuple - +from pathlib import Path +from typing import Any, Dict, List, Optional, Tuple, TypeVar, Union, cast +from typing import NamedTuple import requests +from dataclasses import dataclass + +@dataclass +class Location: + lat: float + lon: float + place: Optional[str] = None + + +@dataclass +class WeatherData: + temp_str: str + feels_str: str + icon: str + status: str + min_max: str + wind_text: str + humidity_text: str + visibility_text: str + aqi_text: str + hourly_precip: str + is_day: int + code: int + # =============== Configuration =============== # You can configure behavior via environment variables OR the constants below. # Examples (zsh): # # One-off run # # WEATHER_UNITS can be "metric" or "imperial" -# WEATHER_UNITS=imperial WEATHER_PLACE="Concord, NH" python3 /home/dwilliams/Projects/Weather.py +# WEATHER_UNITS=imperial WEATHER_PLACE="Concord, NH" python3 ~/.config/hypr/UserScripts/Weather.py # # # Persist in current shell session # export WEATHER_UNITS=imperial @@ -27,10 +54,10 @@ import requests # export WEATHER_TOOLTIP_MARKUP=1 # 1 to enable Pango markup, 0 to disable # export WEATHER_LOC_ICON="📍" # or "*" for ASCII-only # -CACHE_DIR = os.path.expanduser("~/.cache") -API_CACHE_PATH = os.path.join(CACHE_DIR, "open_meteo_cache.json") -SIMPLE_TEXT_CACHE_PATH = os.path.join(CACHE_DIR, ".weather_cache") -CACHE_TTL_SECONDS = int(os.getenv("WEATHER_CACHE_TTL", "600")) # default 10 minutes +CACHE_DIR: Path = Path.home() / ".cache" +API_CACHE_PATH: Path = CACHE_DIR / "open_meteo_cache.json" +SIMPLE_TEXT_CACHE_PATH: Path = CACHE_DIR / ".weather_cache" +CACHE_TTL_SECONDS = int(os.getenv("WEATHER_CACHE_TTL", "300")) # default 5 minutes # Units: metric or imperial (default metric) UNITS = os.getenv("WEATHER_UNITS", "metric").strip().lower() # metric|imperial @@ -38,16 +65,17 @@ UNITS = os.getenv("WEATHER_UNITS", "metric").strip().lower() # metric|imperial # Optional manual coordinates ENV_LAT = os.getenv("WEATHER_LAT") ENV_LON = os.getenv("WEATHER_LON") -# Optional manual place override for tooltip +# Optional manual place override for tooltip (and optional forward geocoding) ENV_PLACE = os.getenv("WEATHER_PLACE") -# Manual place name set inside this file. If set (non-empty), this takes top priority. +# Manual place name set inside this file. If set (non-empty), this takes top priority for display +# and, if coordinates are not provided, will be used to geocode latitude/longitude. # Example: MANUAL_PLACE = "Concord, NH, US" -MANUAL_PLACE: Optional[str] = None +MANUAL_PLACE: Optional[str] = "" #Set your city HERE # Location icon in tooltip (default to a standard emoji to avoid missing glyphs) LOC_ICON = os.getenv("WEATHER_LOC_ICON", "📍") # Enable/disable Pango markup in tooltip (1/0, true/false) -TOOLTIP_MARKUP = os.getenv("WEATHER_TOOLTIP_MARKUP", "1").lower() not in ("0", "false", "no") +TOOLTIP_MARKUP = os.getenv("WEATHER_TOOLTIP_MARKUP", "0").lower() in ("1", "true", "yes") # Optional debug logging to stderr (set WEATHER_DEBUG=1 to enable) DEBUG = os.getenv("WEATHER_DEBUG", "0").lower() not in ("0", "false", "no") @@ -138,19 +166,68 @@ def log_debug(msg: str) -> None: def ensure_cache_dir() -> None: try: - os.makedirs(CACHE_DIR, exist_ok=True) + # CACHE_DIR is a Path + CACHE_DIR.mkdir(parents=True, exist_ok=True) except Exception as e: print(f"Error creating cache dir: {e}", file=sys.stderr) +def _coerce_numeric(value: Any, to_int: bool) -> Optional[Union[int, float]]: + if to_int: + if isinstance(value, int): + return value + if isinstance(value, (float, str)): + try: + return int(float(value)) + except (ValueError, TypeError): + return None + return None + else: + if isinstance(value, float): + return value + if isinstance(value, int): + return float(value) + if isinstance(value, str): + try: + return float(value) + except (ValueError, TypeError): + return None + return None + + +def coerce_int(value: Any) -> Optional[int]: + return cast(Optional[int], _coerce_numeric(value, True)) + + +def coerce_float(value: Any) -> Optional[float]: + return cast(Optional[float], _coerce_numeric(value, False)) + + +def coerce_number(value: Any) -> Union[int, float, None]: + if isinstance(value, (int, float)): + return value + if isinstance(value, str): + try: + # Parse to float, then return int if it has no fractional part + f = float(value) + return int(f) if f.is_integer() else f + except (ValueError, TypeError): + return None + return None + + def read_api_cache() -> Optional[Dict[str, Any]]: try: - if not os.path.exists(API_CACHE_PATH): + if not API_CACHE_PATH.exists(): return None - with open(API_CACHE_PATH, "r", encoding="utf-8") as f: + with API_CACHE_PATH.open("r", encoding="utf-8") as f: data = json.load(f) - if (time.time() - data.get("timestamp", 0)) <= CACHE_TTL_SECONDS: - return data + # Use ensure_dict for safety + data_dict = ensure_dict(data) + timestamp_val = data_dict.get("timestamp", 0) + timestamp = coerce_float(timestamp_val) or 0 + if (time.time() - timestamp) <= CACHE_TTL_SECONDS: + return data_dict return None except Exception as e: print(f"Error reading cache: {e}", file=sys.stderr) @@ -161,7 +238,7 @@ def write_api_cache(payload: Dict[str, Any]) -> None: try: ensure_cache_dir() payload["timestamp"] = time.time() - with open(API_CACHE_PATH, "w", encoding="utf-8") as f: + with API_CACHE_PATH.open("w", encoding="utf-8") as f: json.dump(payload, f) except Exception as e: print(f"Error writing API cache: {e}", file=sys.stderr) @@ -170,34 +247,42 @@ def write_api_cache(payload: Dict[str, Any]) -> None: def write_simple_text_cache(text: str) -> None: try: ensure_cache_dir() - with open(SIMPLE_TEXT_CACHE_PATH, "w", encoding="utf-8") as f: + with SIMPLE_TEXT_CACHE_PATH.open("w", encoding="utf-8") as f: f.write(text) except Exception as e: print(f"Error writing simple cache: {e}", file=sys.stderr) -def get_coords() -> Tuple[float, float]: - # 1) Explicit env +def get_coords_from_env() -> Optional[Tuple[float, float]]: if ENV_LAT and ENV_LON: try: return float(ENV_LAT), float(ENV_LON) except ValueError: print("Invalid WEATHER_LAT/WEATHER_LON; falling back to IP geolocation", file=sys.stderr) + return None + - # 2) Try cached coordinates from last successful forecast +def get_coords_from_cache() -> Optional[Tuple[float, float]]: try: cached = read_api_cache() - if cached and isinstance(cached, dict): - fc = cached.get("forecast") or {} - lat = fc.get("latitude") - lon = fc.get("longitude") - if isinstance(lat, (int, float)) and isinstance(lon, (int, float)): - return float(lat), float(lon) + if cached: + fc = ensure_dict(cached.get("forecast")) + lat_raw = safe_get(fc, "latitude") + lon_raw = safe_get(fc, "longitude") + lat = coerce_float(lat_raw) + lon = coerce_float(lon_raw) + if lat is None: + log_debug(f"Unexpected type for cached latitude: {type(lat_raw)}") + if lon is None: + log_debug(f"Unexpected type for cached longitude: {type(lon_raw)}") + if lat is not None and lon is not None: + return lat, lon except Exception as e: print(f"Reading cached coords failed: {e}", file=sys.stderr) + return None - # 3) IP-based geolocation with multiple providers (prefer ipwho.is, ipapi.co; ipinfo.io as fallback) - # ipwho.is + +def get_coords_from_ipwho() -> Optional[Tuple[float, float]]: try: resp = SESSION.get("https://ipwho.is/", timeout=TIMEOUT) resp.raise_for_status() @@ -209,8 +294,10 @@ def get_coords() -> Tuple[float, float]: return float(lat), float(lon) except Exception as e: print(f"ipwho.is failed: {e}", file=sys.stderr) + return None - # ipapi.co + +def get_coords_from_ipapi() -> Optional[Tuple[float, float]]: try: resp = SESSION.get("https://ipapi.co/json", timeout=TIMEOUT) resp.raise_for_status() @@ -221,8 +308,10 @@ def get_coords() -> Tuple[float, float]: return float(lat), float(lon) except Exception as e: print(f"ipapi.co failed: {e}", file=sys.stderr) + return None + - # ipinfo.io (fallback) +def get_coords_from_ipinfo() -> Optional[Tuple[float, float]]: try: resp = SESSION.get("https://ipinfo.io/json", timeout=TIMEOUT) resp.raise_for_status() @@ -233,8 +322,68 @@ def get_coords() -> Tuple[float, float]: return float(lat_s), float(lon_s) except Exception as e: print(f"ipinfo.io failed: {e}", file=sys.stderr) + return None + - # 4) Last resort +def get_coords_from_place_name(name: str) -> Optional[Tuple[float, float]]: + """Forward geocode a place name to coordinates using Open-Meteo Geocoding API. + + Returns (lat, lon) if found, else None. + """ + try: + base = "https://geocoding-api.open-meteo.com/v1/search" + params: Dict[str, Union[str, float]] = { + "name": name, + "count": 1, + "language": os.getenv("WEATHER_LANG", "en"), + "format": "json", + } + resp = SESSION.get(base, params=params, timeout=TIMEOUT) + resp.raise_for_status() + data = ensure_dict(resp.json()) + results = ensure_list(data.get("results")) + if results: + p = ensure_dict(results[0]) + lat = coerce_float(p.get("latitude")) + lon = coerce_float(p.get("longitude")) + if lat is not None and lon is not None: + return float(lat), float(lon) + except Exception as e: + print(f"Place geocoding failed: {e}", file=sys.stderr) + return None + + +def get_coords() -> Tuple[float, float]: + # 1) Forward geocode from MANUAL_PLACE first (highest priority) + if MANUAL_PLACE: + place_name = MANUAL_PLACE.strip() + coords = get_coords_from_place_name(place_name) + if coords: + return coords + + # 2) Explicit env coordinates + coords = get_coords_from_env() + if coords: + return coords + + # 3) Forward geocode from ENV_PLACE + if ENV_PLACE: + place_name = ENV_PLACE.strip() + coords = get_coords_from_place_name(place_name) + if coords: + return coords + + # 4) Try cached coordinates + coords = get_coords_from_cache() + if coords: + return coords + + # 5) IP-based geolocation + coords = get_coords_from_ipwho() or get_coords_from_ipapi() or get_coords_from_ipinfo() + if coords: + return coords + + # 6) Last resort print("IP geolocation failed: no providers succeeded", file=sys.stderr) return 0.0, 0.0 @@ -272,7 +421,7 @@ def format_visibility(meters: Optional[float]) -> str: def fetch_open_meteo(lat: float, lon: float) -> Dict[str, Any]: base = "https://api.open-meteo.com/v1/forecast" - params = { + params: Dict[str, Union[str, float]] = { "latitude": lat, "longitude": lon, "current": "temperature_2m,apparent_temperature,relative_humidity_2m,wind_speed_10m,wind_direction_10m,weather_code,visibility,precipitation,pressure_msl,is_day", @@ -289,7 +438,7 @@ def fetch_open_meteo(lat: float, lon: float) -> Dict[str, Any]: def fetch_aqi(lat: float, lon: float) -> Optional[Dict[str, Any]]: try: base = "https://air-quality-api.open-meteo.com/v1/air-quality" - params = { + params: Dict[str, Union[str, float]] = { "latitude": lat, "longitude": lon, "current": "european_aqi", @@ -303,37 +452,54 @@ def fetch_aqi(lat: float, lon: float) -> Optional[Dict[str, Any]]: return None -def fetch_place(lat: float, lon: float) -> Optional[str]: - """Reverse geocode lat/lon to an approximate place. Tries Nominatim first, then Open-Meteo.""" - lang = os.getenv("WEATHER_LANG", "en") +def extract_place_parts_nominatim(data_dict: JSONDict) -> List[str]: + address = ensure_dict(data_dict.get("address")) + candidates = [data_dict.get("name"), address.get("city"), address.get("town"), address.get("village"), address.get("hamlet")] + name = cast(Optional[str], next((c for c in candidates if c is not None), None)) + admin1 = cast(Optional[str], address.get("state")) + country = cast(Optional[str], address.get("country")) + parts: List[str] = [] + if name is not None: + parts.append(name) + if admin1 is not None: + parts.append(admin1) + if country is not None: + parts.append(country) + return parts - # 1) Nominatim (OpenStreetMap) + +def extract_place_parts_open_meteo(p: JSONDict) -> List[str]: + name = cast(Optional[str], p.get("name")) + admin1 = cast(Optional[str], p.get("admin1")) + country = cast(Optional[str], p.get("country")) + parts: List[str] = [] + if name is not None: + parts.append(name) + if admin1 is not None: + parts.append(admin1) + if country is not None: + parts.append(country) + return parts + + +def reverse_geocode(base: str, params: Dict[str, Union[str, float]], headers: Optional[Dict[str, str]] = None) -> Optional[str]: try: - base = "https://nominatim.openstreetmap.org/reverse" - params = { - "lat": lat, - "lon": lon, - "format": "jsonv2", - "accept-language": lang, - } - headers = {"User-Agent": UA + " Weather.py/1.0"} resp = SESSION.get(base, params=params, headers=headers, timeout=TIMEOUT) resp.raise_for_status() data = resp.json() - address = data.get("address", {}) - name = data.get("name") or address.get("city") or address.get("town") or address.get("village") or address.get("hamlet") - admin1 = address.get("state") - country = address.get("country") - parts = [part for part in [name, admin1, country] if part] + data_dict = ensure_dict(data) + parts = extract_place_parts_nominatim(data_dict) if parts: return ", ".join(parts) except Exception as e: - log_debug(f"Reverse geocoding (Nominatim) failed: {e}") + log_debug(f"Reverse geocoding failed: {e}") + return None - # 2) Open-Meteo reverse (fallback) + +def reverse_geocode_open_meteo(lat: float, lon: float, lang: str) -> Optional[str]: try: base = "https://geocoding-api.open-meteo.com/v1/reverse" - params = { + params: Dict[str, Union[str, float]] = { "latitude": lat, "longitude": lon, "language": lang, @@ -342,48 +508,117 @@ def fetch_place(lat: float, lon: float) -> Optional[str]: resp = SESSION.get(base, params=params, timeout=TIMEOUT) resp.raise_for_status() data = resp.json() - results = data.get("results") or [] + data_dict = ensure_dict(data) + results = ensure_list(data_dict.get("results")) if results: - p = results[0] - name = p.get("name") - admin1 = p.get("admin1") - country = p.get("country") - parts = [part for part in [name, admin1, country] if part] + p = ensure_dict(results[0]) + parts = extract_place_parts_open_meteo(p) if parts: return ", ".join(parts) except Exception as e: log_debug(f"Reverse geocoding (Open-Meteo) failed: {e}") - return None +def fetch_place(lat: float, lon: float) -> Optional[str]: + """Reverse geocode lat/lon to an approximate place. Tries Nominatim first, then Open-Meteo.""" + lang = os.getenv("WEATHER_LANG", "en") + + # 1) Nominatim (OpenStreetMap) + base = "https://nominatim.openstreetmap.org/reverse" + params: Dict[str, Union[str, float]] = { + "lat": lat, + "lon": lon, + "format": "jsonv2", + "accept-language": lang, + } + headers = {"User-Agent": UA + " Weather.py/1.0"} + place = reverse_geocode(base, params, headers) + if place: + return place + + # 2) Open-Meteo reverse (fallback) + return reverse_geocode_open_meteo(lat, lon, lang) + + # =============== Build Output =============== -def safe_get(dct: Dict[str, Any], *keys, default=None): - cur: Any = dct - for k in keys: +_T = TypeVar("_T") + +JSONValue = Union[str, int, float, bool, None, "JSONDict", "JSONList"] +JSONDict = Dict[str, JSONValue] +JSONList = List[JSONValue] + + +def ensure_dict(value: Any) -> JSONDict: + """Return a JSON-like dict when the incoming value looks like one.""" + if isinstance(value, dict): + return cast(JSONDict, value) + # Warn about unexpected type to catch API shape mismatches + val_repr = repr(value) if value is not None else "None" + if len(val_repr) > 100: + val_repr = val_repr[:100] + "..." + print(f"Warning: ensure_dict received {type(value).__name__} instead of dict: {val_repr}", file=sys.stderr) + return cast(JSONDict, {}) + + +def ensure_list(value: Any) -> JSONList: + """Return a JSON-like list when the incoming value looks like one.""" + if isinstance(value, list): + return cast(JSONList, value) + # Warn about unexpected type to catch API shape mismatches + val_repr = repr(value) if value is not None else "None" + if len(val_repr) > 100: + val_repr = val_repr[:100] + "..." + print(f"Warning: ensure_list received {type(value).__name__} instead of list: {val_repr}", file=sys.stderr) + return cast(JSONList, []) + + +def safe_get( + obj: JSONValue | None, + *keys: Union[str, int], + default: _T | None = None, +) -> _T | JSONValue | None: + """Safely traverse nested dict/list structures. + + Keys may be strings (for mapping lookups) or ints (for list indices). + Returns ``default`` if any lookup fails. + """ + + cur: JSONValue | None = obj + for key in keys: if isinstance(cur, dict): - if k not in cur: + if not isinstance(key, str) or key not in cur: return default - cur = cur[k] + cur = cur[key] elif isinstance(cur, list): - try: - cur = cur[k] # type: ignore[index] - except Exception: + if not isinstance(key, int) or key < 0 or key >= len(cur): return default + cur = cur[key] else: return default - return cur + return cast(_T | JSONValue | None, cur) + + +def get_precipitation_probabilities(forecast: JSONDict) -> List[Optional[float]]: + probs_raw = safe_get(forecast, "hourly", "precipitation_probability") + probs_raw_list = ensure_list(probs_raw) + return [coerce_float(p) if p is not None else None for p in probs_raw_list] + + +def find_current_index(times: List[str], cur_time: Optional[str]) -> int: + if cur_time is not None and cur_time in times: + return times.index(cur_time) + return 0 -def build_hourly_precip(forecast: Dict[str, Any]) -> str: +def build_hourly_precip(forecast: JSONDict) -> str: try: - times: List[str] = safe_get(forecast, "hourly", "time", default=[]) or [] - probs: List[Optional[float]] = safe_get( - forecast, "hourly", "precipitation_probability", default=[] - ) or [] - cur_time: Optional[str] = safe_get(forecast, "current", "time") - idx = times.index(cur_time) if cur_time in times else 0 + times_raw = safe_get(forecast, "hourly", "time") + times: List[str] = cast(List[str], ensure_list(times_raw)) + probs = get_precipitation_probabilities(forecast) + cur_time: Optional[str] = cast(Optional[str], safe_get(forecast, "current", "time")) + idx = find_current_index(times, cur_time) window = probs[idx : idx + 6] if not window: return "" @@ -393,152 +628,308 @@ def build_hourly_precip(forecast: Dict[str, Any]) -> str: return "" -def build_output(lat: float, lon: float, forecast: Dict[str, Any], aqi: Optional[Dict[str, Any]], place: Optional[str] = None) -> Tuple[Dict[str, Any], str]: - cur = forecast.get("current", {}) - cur_units = forecast.get("current_units", {}) - daily = forecast.get("daily", {}) - daily_units = forecast.get("daily_units", {}) +def build_weather_strings(cur: JSONDict, cur_units: JSONDict, daily: JSONDict, daily_units: JSONDict, temp_unit: str) -> Tuple[str, str, int, int, str, str, str]: + temp_val = coerce_float(cur.get("temperature_2m")) + temp_unit_str = cast(str, cur_units.get("temperature_2m", "")) + temp_str = f"{int(round(temp_val))}{temp_unit_str}" if temp_val is not None else "N/A" - temp_val = cur.get("temperature_2m") - temp_unit = cur_units.get("temperature_2m", "") - temp_str = f"{int(round(temp_val))}{temp_unit}" if isinstance(temp_val, (int, float)) else "N/A" + feels_val = coerce_float(cur.get("apparent_temperature")) + feels_unit = cast(str, cur_units.get("apparent_temperature", "")) + feels_str = f"Feels like {int(round(feels_val))}{feels_unit}" if feels_val is not None else "" - feels_val = cur.get("apparent_temperature") - feels_unit = cur_units.get("apparent_temperature", "") - feels_str = f"Feels like {int(round(feels_val))}{feels_unit}" if isinstance(feels_val, (int, float)) else "" - - is_day = int(cur.get("is_day", 1) or 1) - code = int(cur.get("weather_code", -1) or -1) + is_day_val = cur.get("is_day") + is_day_int = coerce_int(is_day_val) + is_day = is_day_int if is_day_int is not None else 1 + weather_code_val = cur.get("weather_code") + code_int = coerce_int(weather_code_val) + code = code_int if code_int is not None else -1 icon = wmo_to_icon(code, is_day) status = wmo_to_status(code) - # min/max today (index 0) - tmin_val = safe_get(daily, "temperature_2m_min", 0) - tmax_val = safe_get(daily, "temperature_2m_max", 0) - dtemp_unit = daily_units.get("temperature_2m_min", temp_unit) - tmin_str = f"{int(round(tmin_val))}{dtemp_unit}" if isinstance(tmin_val, (int, float)) else "" - tmax_str = f"{int(round(tmax_val))}{dtemp_unit}" if isinstance(tmax_val, (int, float)) else "" + tmin_val = coerce_float(safe_get(daily, "temperature_2m_min", 0)) + tmax_val = coerce_float(safe_get(daily, "temperature_2m_max", 0)) + dtemp_unit = cast(str, daily_units.get("temperature_2m_min", temp_unit)) + tmin_str = f"{int(round(tmin_val))}{dtemp_unit}" if tmin_val is not None else "" + tmax_str = f"{int(round(tmax_val))}{dtemp_unit}" if tmax_val is not None else "" min_max = f" {tmin_str}\t\t {tmax_str}" if tmin_str and tmax_str else "" - wind_val = cur.get("wind_speed_10m") - wind_unit = cur_units.get("wind_speed_10m", "") - wind_text = f" {int(round(wind_val))}{wind_unit}" if isinstance(wind_val, (int, float)) else "" + return temp_str, feels_str, is_day, code, icon, status, min_max - hum_val = cur.get("relative_humidity_2m") - humidity_text = f" {int(hum_val)}%" if isinstance(hum_val, (int, float)) else "" - vis_val = cur.get("visibility") - visibility_text = f" {format_visibility(vis_val)}" if isinstance(vis_val, (int, float)) else "" +def build_weather_details(cur: JSONDict, cur_units: JSONDict) -> Tuple[str, str, str]: + wind_val_raw = cur.get("wind_speed_10m") + wind_val = coerce_float(wind_val_raw) + wind_unit = cast(str, cur_units.get("wind_speed_10m", "")) + if wind_val is None: + log_debug(f"Unexpected type for wind_speed_10m: {type(wind_val_raw)}") + wind_text = f" {int(round(wind_val))}{wind_unit}" if wind_val is not None else "" - aqi_val = safe_get(aqi or {}, "current", "european_aqi") - aqi_text = f"AQI {int(aqi_val)}" if isinstance(aqi_val, (int, float)) else "AQI N/A" + hum_val_raw = cur.get("relative_humidity_2m") + hum_val = coerce_float(hum_val_raw) + if hum_val is None: + log_debug(f"Unexpected type for relative_humidity_2m: {type(hum_val_raw)}") + humidity_text = f" {int(hum_val)}%" if hum_val is not None else "" - hourly_precip = build_hourly_precip(forecast) - prediction = f"\n\n{hourly_precip}" if hourly_precip else "" + vis_val_raw = cur.get("visibility") + vis_val = coerce_float(vis_val_raw) + if vis_val is None: + log_debug(f"Unexpected type for visibility: {type(vis_val_raw)}") + visibility_text = f" {format_visibility(vis_val)}" if vis_val is not None else "" - # Build place string (priority: MANUAL_PLACE > ENV_PLACE > reverse geocode > lat,lon) - place_str = (MANUAL_PLACE or ENV_PLACE or place or f"{lat:.3f}, {lon:.3f}") - location_text = f"{LOC_ICON} {place_str}" + return wind_text, humidity_text, visibility_text + + +def build_aqi_info(aqi: Optional[Dict[str, Any]]) -> str: + aqi_dict = ensure_dict(aqi) + aqi_val_raw = safe_get(aqi_dict, "current", "european_aqi") + aqi_val = coerce_float(aqi_val_raw) + if aqi_val is None: + log_debug(f"Unexpected type for european_aqi: {type(aqi_val_raw)}") + return f"AQI {int(aqi_val)}" if aqi_val is not None else "AQI N/A" + + +def build_place_str(lat: float, lon: float, place: Optional[str]) -> str: + effective_place = MANUAL_PLACE or ENV_PLACE or place + if effective_place: + return f"{effective_place} ({lat:.3f}, {lon:.3f})" + return f"{lat:.3f}, {lon:.3f}" + + + + +class TooltipParams(NamedTuple): + temp_str: str + icon: str + status: str + location_text: str + feels_str: str + min_max: str + wind_text: str + humidity_text: str + visibility_text: str + aqi_text: str + hourly_precip: str - # Build tooltip (markup or plain) + +def build_tooltip_markup(params: TooltipParams) -> str: + return str.format( + "\t\t{}\t\t\n{}\n{}\n{}\n{}\n\n{}\n{}\n{}{}", + f'<span size="xx-large">{esc(params.temp_str)}</span>', + f"<big> {params.icon}</big>", + f"<b>{esc(params.status)}</b>", + esc(params.location_text), + f"<small>{esc(params.feels_str)}</small>" if params.feels_str else "", + f"<b>{esc(params.min_max)}</b>" if params.min_max else "", + f"{esc(params.wind_text)}\t{esc(params.humidity_text)}", + f"{esc(params.visibility_text)}\t{esc(params.aqi_text)}", + f"<i> {esc(params.hourly_precip)}</i>" if params.hourly_precip else "", + ) + + +def build_tooltip_plain(params: TooltipParams) -> str: + lines = [ + f"{params.icon} {params.temp_str}", + params.status, + params.location_text, + ] + if params.feels_str: + lines.append(params.feels_str) + if params.min_max: + lines.append(params.min_max) + combined_wind = f"{params.wind_text} {params.humidity_text}".strip() + if combined_wind: + lines.append(combined_wind) + combined_visibility = f"{params.visibility_text} {params.aqi_text}".strip() + if combined_visibility: + lines.append(combined_visibility) + if params.hourly_precip: + lines.append(params.hourly_precip) + return "\n".join([ln for ln in lines if ln]) + + +def build_tooltip_text(params: TooltipParams) -> str: if TOOLTIP_MARKUP: - # Escape dynamic text to avoid breaking Pango markup - tooltip_text = str.format( - "\t\t{}\t\t\n{}\n{}\n{}\n{}\n\n{}\n{}\n{}{}", - f'<span size="xx-large">{esc(temp_str)}</span>', - f"<big> {icon}</big>", - f"<b>{esc(status)}</b>", - esc(location_text), - f"<small>{esc(feels_str)}</small>" if feels_str else "", - f"<b>{esc(min_max)}</b>" if min_max else "", - f"{esc(wind_text)}\t{esc(humidity_text)}", - f"{esc(visibility_text)}\t{esc(aqi_text)}", - f"<i> {esc(prediction)}</i>" if prediction else "", - ) + return build_tooltip_markup(params) else: - lines = [ - f"{icon} {temp_str}", - status, - location_text, - ] - if feels_str: - lines.append(feels_str) - if min_max: - lines.append(min_max) - lines.append(f"{wind_text} {humidity_text}".strip()) - lines.append(f"{visibility_text} {aqi_text}".strip()) - if prediction: - lines.append(hourly_precip) - tooltip_text = "\n".join([ln for ln in lines if ln]) + return build_tooltip_plain(params) + + +def gather_weather_data(forecast: Optional[Dict[str, Any]], aqi: Optional[Dict[str, Any]]) -> WeatherData: + forecast_dict = ensure_dict(forecast) + cur = ensure_dict(forecast_dict.get("current")) + cur_units = ensure_dict(forecast_dict.get("current_units")) + daily = ensure_dict(forecast_dict.get("daily")) + daily_units = ensure_dict(forecast_dict.get("daily_units")) + + temp_str, feels_str, is_day, code, icon, status, min_max = build_weather_strings(cur, cur_units, daily, daily_units, cast(str, cur_units.get("temperature_2m", ""))) + wind_text, humidity_text, visibility_text = build_weather_details(cur, cur_units) + aqi_text = build_aqi_info(aqi) + hourly_precip = build_hourly_precip(forecast_dict) + + return WeatherData( + temp_str=temp_str, + feels_str=feels_str, + icon=icon, + status=status, + min_max=min_max, + wind_text=wind_text, + humidity_text=humidity_text, + visibility_text=visibility_text, + aqi_text=aqi_text, + hourly_precip=hourly_precip, + is_day=is_day, + code=code, + ) + + +def build_output(loc: Location, forecast: Optional[Dict[str, Any]], aqi: Optional[Dict[str, Any]]) -> Tuple[Dict[str, str], str]: + data = gather_weather_data(forecast, aqi) + + place_str = build_place_str(loc.lat, loc.lon, loc.place) + location_text = f"{LOC_ICON} {place_str}" + + tooltip_text = build_tooltip_text( + TooltipParams( + data.temp_str, data.icon, data.status, location_text, data.feels_str, data.min_max, + data.wind_text, data.humidity_text, data.visibility_text, data.aqi_text, data.hourly_precip + ) + ) - out_data = { - "text": f"{icon} {temp_str}", - "alt": status, + out_data: Dict[str, Any] = { + "text": f"{data.icon} {data.temp_str}", + "alt": data.status, "tooltip": tooltip_text, - "class": f"wmo-{code} {'day' if is_day else 'night'}", + "class": f"wmo-{data.code} {'day' if data.is_day else 'night'}", } simple_weather = ( - f"{icon} {status}\n" - + f" {temp_str} ({feels_str})\n" - + (f"{wind_text} \n" if wind_text else "") - + (f"{humidity_text} \n" if humidity_text else "") - + f"{visibility_text} {aqi_text}\n" + f"{place_str}\n" + f"{data.icon} {data.status}\n" + + f" {data.temp_str} ({data.feels_str})\n" + + (f" {data.wind_text} \n" if data.wind_text else "") + + (f" {data.humidity_text} \n" if data.humidity_text else "") + + f" {data.visibility_text} {data.aqi_text}\n" ) return out_data, simple_weather -def main() -> None: - lat, lon = get_coords() - - # Try cache first +def try_cached_weather(lat: float, lon: float) -> Optional[Tuple[Dict[str, str], str]]: cached = read_api_cache() - if cached and isinstance(cached, dict): - forecast = cached.get("forecast") - aqi = cached.get("aqi") - cached_place = cached.get("place") if isinstance(cached.get("place"), str) else None - place_effective = MANUAL_PLACE or ENV_PLACE or cached_place + if cached: + forecast = cast(Optional[Dict[str, Any]], cached.get("forecast")) + aqi = cast(Optional[Dict[str, Any]], cached.get("aqi")) + place_val = cached.get("place") + cached_place = place_val if isinstance(place_val, str) else None + # Ensure the cached forecast corresponds to the requested lat/lon + fc = ensure_dict(cached.get("forecast")) + c_lat = coerce_float(safe_get(fc, "latitude")) + c_lon = coerce_float(safe_get(fc, "longitude")) + if c_lat is not None and c_lon is not None: + if abs(c_lat - lat) > 0.1 or abs(c_lon - lon) > 0.1: + return None # force fresh fetch for new location try: - out, simple = build_output(lat, lon, forecast, aqi, place_effective) - print(json.dumps(out, ensure_ascii=False)) - write_simple_text_cache(simple) - return + return build_output(Location(lat, lon, cached_place), forecast, aqi) except Exception as e: print(f"Cached data build failed, refetching: {e}", file=sys.stderr) + return None - # Fetch fresh + +def fetch_fresh_weather(lat: float, lon: float) -> Optional[Tuple[Dict[str, str], str]]: try: forecast = fetch_open_meteo(lat, lon) aqi = fetch_aqi(lat, lon) - # Use manual/env place if provided; otherwise reverse geocode - place_effective = MANUAL_PLACE or ENV_PLACE or fetch_place(lat, lon) - write_api_cache({"forecast": forecast, "aqi": aqi, "place": place_effective}) - out, simple = build_output(lat, lon, forecast, aqi, place_effective) - print(json.dumps(out, ensure_ascii=False)) - write_simple_text_cache(simple) + # If MANUAL_PLACE is set, don't reverse geocode - use the manual place instead + place = MANUAL_PLACE if MANUAL_PLACE else fetch_place(lat, lon) + write_api_cache({"forecast": forecast, "aqi": aqi, "place": place}) + return build_output(Location(lat, lon, place), forecast, aqi) except Exception as e: print(f"Open-Meteo fetch failed: {e}", file=sys.stderr) - # Last resort: try stale cache without TTL - try: - if os.path.exists(API_CACHE_PATH): - with open(API_CACHE_PATH, "r", encoding="utf-8") as f: - stale = json.load(f) - out, simple = build_output(lat, lon, stale.get("forecast", {}), stale.get("aqi"), stale.get("place") if isinstance(stale.get("place"), str) else None) - print(json.dumps(out, ensure_ascii=False)) - write_simple_text_cache(simple) - return - except Exception as e2: - print(f"Failed to use stale cache: {e2}", file=sys.stderr) - # Fallback minimal output - fallback = { - "text": f"{WEATHER_ICONS['default']} N/A", - "alt": "Unavailable", - "tooltip": "Weather unavailable", - "class": "unavailable", - } - print(json.dumps(fallback, ensure_ascii=False)) + return None + + +def try_stale_weather(lat: float, lon: float) -> Optional[Tuple[Dict[str, str], str]]: + try: + if API_CACHE_PATH.exists(): + with API_CACHE_PATH.open("r", encoding="utf-8") as f: + stale = json.load(f) + stale_dict = ensure_dict(stale) + place_val = stale_dict.get("place") + place = place_val if isinstance(place_val, str) else None + forecast = cast(Optional[Dict[str, Any]], stale_dict.get("forecast")) + aqi = cast(Optional[Dict[str, Any]], stale_dict.get("aqi")) + return build_output(Location(lat, lon, place), forecast, aqi) + except Exception as e2: + print(f"Failed to use stale cache: {e2}", file=sys.stderr) + return None + + +def main() -> None: + lat, lon = get_coords() + + # Try cache first + result = try_cached_weather(lat, lon) + if result: + out, simple = result + print(json.dumps(out, ensure_ascii=False)) + write_simple_text_cache(simple) + return + + # Fetch fresh + result = fetch_fresh_weather(lat, lon) + if result: + out, simple = result + print(json.dumps(out, ensure_ascii=False)) + write_simple_text_cache(simple) + return + + # Last resort: try stale cache + result = try_stale_weather(lat, lon) + if result: + out, simple = result + print(json.dumps(out, ensure_ascii=False)) + write_simple_text_cache(simple) + return + + # Fallback minimal output + fallback = { + "text": f"{WEATHER_ICONS['default']} N/A", + "alt": "Unavailable", + "tooltip": "Weather unavailable", + "class": "unavailable", + } + print(json.dumps(fallback, ensure_ascii=False)) + + +def test_coerce_functions(): + """Manual testing for coerce functions.""" + # Test coerce_int + assert coerce_int(5) == 5 + assert coerce_int(5.5) == 5 + assert coerce_int("5") == 5 + assert coerce_int("5.7") == 5 + assert coerce_int("abc") is None + assert coerce_int(None) is None + + # Test coerce_float + assert coerce_float(5.5) == 5.5 + assert coerce_float(5) == 5.0 + assert coerce_float("5.5") == 5.5 + assert coerce_float("abc") is None + assert coerce_float(None) is None + + # Test coerce_number + assert coerce_number(5) == 5 + assert coerce_number(5.5) == 5.5 + assert coerce_number("5") == 5 + assert coerce_number("5.5") == 5.5 + assert coerce_number("abc") is None + + print("All coerce function tests passed.", file=sys.stderr) if __name__ == "__main__": - main() + if len(sys.argv) > 1 and sys.argv[1] == "--test": + test_coerce_functions() + else: + main() diff --git a/config/hypr/UserScripts/Weather.sh b/config/hypr/UserScripts/Weather.sh index 9bdaff4a..ac9abc13 100755 --- a/config/hypr/UserScripts/Weather.sh +++ b/config/hypr/UserScripts/Weather.sh @@ -1,18 +1,42 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # weather info from wttr. https://github.com/chubin/wttr.in # Remember to add city -city= +city="" + + +# if city is blank, use https://ipapi.co/json to get location from IP +if [ -z "$city" ]; then + city=$(curl -fsS https://ipapi.co/json | grep city | cut -f4 -d'"') +fi + + +# URL-encode city for safe use in URLs +encoded_city="$city" +if command -v python3 >/dev/null 2>&1; then + encoded_city=$(python3 -c 'import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1]))' "$city") +elif command -v jq >/dev/null 2>&1; then + encoded_city=$(printf '%s' "$city" | jq -sRr @uri) +else + # Minimal fallback: encode a few common special characters + encoded_city=$(printf '%s' "$city" | sed -e 's/ /%20/g' -e 's/&/%26/g' -e 's/?/%3F/g' -e 's/#/%23/g') +fi + + cachedir="$HOME/.cache/rbn" -cachefile=${0##*/}-$1 +# Include city and arg in cache key so changing city invalidates old cache +cache_key="${city}_${1}" +# Sanitize cache key to avoid problematic characters in filename +safe_key=$(printf '%s' "$cache_key" | tr -c '[:alnum:]_-' '_') +cachefile=${0##*/}-$safe_key -if [ ! -d $cachedir ]; then - mkdir -p $cachedir +if [ ! -d "$cachedir" ]; then + mkdir -p "$cachedir" fi -if [ ! -f $cachedir/$cachefile ]; then - touch $cachedir/$cachefile +if [ ! -f "$cachedir/$cachefile" ]; then + touch "$cachedir/$cachefile" fi # Save current IFS @@ -20,25 +44,88 @@ SAVEIFS=$IFS # Change IFS to new line. IFS=$'\n' -cacheage=$(($(date +%s) - $(stat -c '%Y' "$cachedir/$cachefile"))) -if [ $cacheage -gt 1740 ] || [ ! -s $cachedir/$cachefile ]; then - data=($(curl -s https://en.wttr.in/"$city"$1\?0qnT 2>&1)) - echo ${data[0]} | cut -f1 -d, > $cachedir/$cachefile - echo ${data[1]} | sed -E 's/^.{15}//' >> $cachedir/$cachefile - echo ${data[2]} | sed -E 's/^.{15}//' >> $cachedir/$cachefile +file="$cachedir/$cachefile" +# Portable file mtime retrieval (GNU/BSD): +# - GNU: stat -c %Y <file> +# - BSD/macOS: stat -f %m <file> +mtime=$(stat -c %Y "$file" 2>/dev/null || stat -f %m "$file" 2>/dev/null || echo 0) +now=$(date +%s) +cacheage=$(( now - mtime )) +if [ $cacheage -gt 1740 ] || [ ! -s "$cachedir/$cachefile" ]; then + # Prefer structured format for reliable parsing (3 lines: location, condition, temperature) + mapfile -t sdata < <(curl -fsS "https://wttr.in/${encoded_city}?format=%25l%0A%25C%0A%25t&lang=en" 2>/dev/null || true) + if [ ${#sdata[@]} -ge 3 ]; then + printf "%s\n" "${sdata[0]}" > "$cachedir/$cachefile" + printf "%s\n" "${sdata[1]}" >> "$cachedir/$cachefile" + printf "%s\n" "${sdata[2]}" >> "$cachedir/$cachefile" + else + # Try fetching each field separately if combined format is flaky + loc=$(curl -fsS "https://wttr.in/${encoded_city}?format=%25l&lang=en" 2>/dev/null || true) + cond_only=$(curl -fsS "https://wttr.in/${encoded_city}?format=%25C&lang=en" 2>/dev/null || true) + temp_only=$(curl -fsS "https://wttr.in/${encoded_city}?format=%25t" 2>/dev/null || true) + if [ -n "$loc" ] && [ -n "$cond_only" ] && [ -n "$temp_only" ]; then + printf "%s\n" "$loc" > "$cachedir/$cachefile" + printf "%s\n" "$cond_only" >> "$cachedir/$cachefile" + printf "%s\n" "$temp_only" >> "$cachedir/$cachefile" + else + # Fallback: try ASCII output and extract best-effort fields + url="https://en.wttr.in/${encoded_city}?1" + mapfile -t data < <(curl -fsS "$url" 2>/dev/null || true) + if [ ${#data[@]} -ge 3 ] && ! echo "${data[0]}" | grep -qi 'not found\|unknown location'; then + loc=$(echo "${data[0]}" | sed -E 's/^.*: *//') + # Attempt to pull condition and temperature hints from nearby lines + cond=$(echo "${data[2]}" | sed -E 's/^.{0,15}//; s/^\s+//') + temp=$(printf "%s\n" "${data[@]}" | grep -Eo '\+?-?[0-9]+(\([^)]+\))? ?°?[CF]' | head -n1) + # Only write if we have at least location and something else meaningful + if [ -n "$loc" ] && { [ -n "$cond" ] || [ -n "$temp" ]; }; then + printf "%s\n" "$loc" > "$cachedir/$cachefile" + printf "%s\n" "${cond:-Unknown}" >> "$cachedir/$cachefile" + printf "%s\n" "${temp:-N/A}" >> "$cachedir/$cachefile" + fi + fi + fi + fi fi -weather=($(cat $cachedir/$cachefile)) +# Read cache robustly (line-wise) +mapfile -t weather < "$cachedir/$cachefile" + +# If cache is still empty or invalid, emit a single error JSON and exit to avoid double-prints +if [ ${#weather[@]} -lt 3 ] || ! echo "${weather[2]}" | grep -qE '[-+0-9].*°'; then + # Last-chance: try live structured fetch and populate cache and runtime weather + mapfile -t sdata < <(curl -fsS "https://wttr.in/${encoded_city}?format=%25l%0A%25C%0A%25t&lang=en" 2>/dev/null || true) + if [ ${#sdata[@]} -ge 3 ]; then + weather=("${sdata[@]}") + printf "%s\n" "${sdata[0]}" > "$cachedir/$cachefile" + printf "%s\n" "${sdata[1]}" >> "$cachedir/$cachefile" + printf "%s\n" "${sdata[2]}" >> "$cachedir/$cachefile" + else + loc=$(curl -fsS "https://wttr.in/${encoded_city}?format=%25l&lang=en" 2>/dev/null || true) + cond_only=$(curl -fsS "https://wttr.in/${encoded_city}?format=%25C&lang=en" 2>/dev/null || true) + temp_only=$(curl -fsS "https://wttr.in/${encoded_city}?format=%25t" 2>/dev/null || true) + if [ -n "$loc" ] && [ -n "$cond_only" ] && [ -n "$temp_only" ]; then + weather=("$loc" "$cond_only" "$temp_only") + printf "%s\n" "$loc" > "$cachedir/$cachefile" + printf "%s\n" "$cond_only" >> "$cachedir/$cachefile" + printf "%s\n" "$temp_only" >> "$cachedir/$cachefile" + else + echo -e "{\"text\":\"\uf06a\", \"alt\":\"\", \"tooltip\":\": \"}" + exit 1 + fi + fi +fi # Restore IFSClear IFS=$SAVEIFS -temperature=$(echo ${weather[2]} | sed -E 's/([[:digit:]]+)\.\./\1 to /g') +temperature=$(echo "${weather[2]}" | sed -E 's/([[:digit:]]+)\.\./\1 to /g') #echo ${weather[1]##*,} # https://fontawesome.com/icons?s=solid&c=weather -case $(echo ${weather[1]##*,} | tr '[:upper:]' '[:lower:]') in +# Normalize condition string for matching +cond_key=$(echo "${weather[1]##*,}" | tr '[:upper:]' '[:lower:]' | sed -E 's/^\s+//; s/\s+$//') +case "$cond_key" in "clear" | "sunny") condition="" ;; @@ -54,7 +141,7 @@ case $(echo ${weather[1]##*,} | tr '[:upper:]' '[:lower:]') in "fog" | "freezing fog") condition="" ;; -"patchy rain possible" | "patchy light drizzle" | "light drizzle" | "patchy light rain" | "light rain" | "light rain shower" | "mist" | "rain") +"patchy rain possible" | "patchy light drizzle" | "light drizzle" | "patchy light rain" | "light rain" | "light rain shower" | "mist" | "rain" | "patchy rain nearby") condition="" ;; "moderate rain at times" | "moderate rain" | "heavy rain at times" | "heavy rain" | "moderate or heavy rain shower" | "torrential rain shower" | "rain shower") @@ -74,14 +161,49 @@ case $(echo ${weather[1]##*,} | tr '[:upper:]' '[:lower:]') in ;; *) condition="" - echo -e "{\"text\":\""$condition"\", \"alt\":\""${weather[0]}"\", \"tooltip\":\""${weather[0]}: $temperature ${weather[1]}"\"}" ;; esac +# If still unknown, try substring heuristics to pick a reasonable icon +if [ "$condition" = "" ]; then + if echo "$cond_key" | grep -q "rain\|drizzle\|shower"; then + condition="" + elif echo "$cond_key" | grep -q "heavy rain\|torrential"; then + condition="" + elif echo "$cond_key" | grep -q "snow"; then + condition="" + elif echo "$cond_key" | grep -q "sleet\|freezing\|ice"; then + condition="" + elif echo "$cond_key" | grep -q "thunder"; then + condition="" + elif echo "$cond_key" | grep -q "overcast"; then + condition="" + elif echo "$cond_key" | grep -q "cloud"; then + condition="" + elif echo "$cond_key" | grep -q "sunny\|clear"; then + condition="" + fi +fi + #echo $temp $condition -echo -e "{\"text\":\""$temperature $condition"\", \"alt\":\""${weather[0]}"\", \"tooltip\":\""${weather[0]}: $temperature ${weather[1]}"\"}" +# Ensure temperature has a value; if empty, keep whatever is in weather[2] or N/A +if [ -z "$temperature" ]; then + temperature="${weather[2]:-N/A}" +fi + +cond_disp=$(echo "${weather[1]}" | sed -E 's/^\s+//; s/\s+$//') + +# Escape strings for safe JSON embedding (escape backslashes and double quotes) +json_escape() { + printf '%s' "$1" | sed -e 's/\\/\\\\/g' -e 's/\"/\\\"/g' +} + +text_json=$(json_escape "$temperature $condition") +alt_json=$(json_escape "${weather[0]}") +tooltip_json=$(json_escape "${weather[0]}: $temperature $cond_disp") -cached_weather=" $temperature \n$condition ${weather[1]}" +printf '{"text":"%s", "alt":"%s", "tooltip":"%s"}\n' "$text_json" "$alt_json" "$tooltip_json" -echo -e $cached_weather > "$HOME/.cache/.weather_cache"
\ No newline at end of file +# Write a two-line cache with an actual newline between lines +printf ' %s \n%s %s\n' "$temperature" "$condition" "${weather[1]}" > "$HOME/.cache/.weather_cache"
\ No newline at end of file diff --git a/config/hypr/UserScripts/WeatherWrap.sh b/config/hypr/UserScripts/WeatherWrap.sh new file mode 100755 index 00000000..10c125dc --- /dev/null +++ b/config/hypr/UserScripts/WeatherWrap.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## +# Weather entrypoint: prefer Python (Open‑Meteo), fallback to legacy Bash (wttr.in) + +SCRIPT_DIR="$(dirname "$0")" +PY_SCRIPT="$SCRIPT_DIR/Weather.py" +BASH_FALLBACK="$SCRIPT_DIR/Weather.sh" + +run_fallback() { + if [ -f "$BASH_FALLBACK" ]; then + # Invoke via bash to avoid requiring +x and ensure consistent shell + bash "$BASH_FALLBACK" "$@" + return $? + else + echo "Weather fallback not found: $BASH_FALLBACK" >&2 + return 127 + fi +} + +if command -v python3 >/dev/null 2>&1; then + python3 "$PY_SCRIPT" "$@" + exit_code=$? + if [ "$exit_code" -eq 0 ]; then + exit 0 + fi + echo "Weather.py failed with code $exit_code — falling back to Weather.sh" >&2 + run_fallback "$@" + exit $? +else + echo "python3 not found in PATH — falling back to Weather.sh" >&2 + run_fallback "$@" + exit $? +fi
\ No newline at end of file diff --git a/config/hypr/UserScripts/ZshChangeTheme.sh b/config/hypr/UserScripts/ZshChangeTheme.sh index cffaf5cb..690f0f13 100755 --- a/config/hypr/UserScripts/ZshChangeTheme.sh +++ b/config/hypr/UserScripts/ZshChangeTheme.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # Script for Oh my ZSH theme ( CTRL SHIFT O) diff --git a/config/hypr/configs/Keybinds.conf b/config/hypr/configs/Keybinds.conf index c2ba9681..fbe3bfe5 100644 --- a/config/hypr/configs/Keybinds.conf +++ b/config/hypr/configs/Keybinds.conf @@ -8,142 +8,144 @@ $scriptsDir = $HOME/.config/hypr/scripts $UserConfigs = $HOME/.config/hypr/UserConfigs $UserScripts = $HOME/.config/hypr/UserScripts -bind = CTRL ALT, Delete, exec, hyprctl dispatch exit 0 # exit Hyprland -bind = $mainMod, Q, killactive, # close active (not kill) -bind = $mainMod SHIFT, Q, exec, $scriptsDir/KillActiveProcess.sh # Kill active process -bind = CTRL ALT, L, exec, $scriptsDir/LockScreen.sh # screen lock -bind = CTRL ALT, P, exec, $scriptsDir/Wlogout.sh # power menu -bind = $mainMod SHIFT, N, exec, swaync-client -t -sw # swayNC notification panel -bind = $mainMod SHIFT, E, exec, $scriptsDir/Kool_Quick_Settings.sh # Settings Menu KooL Hyprland Settings +bindd = CTRL ALT, Delete, exit Hyprland, exec, hyprctl dispatch exit 0 +bindd = $mainMod, Q, close active window, killactive, +bindd = $mainMod SHIFT, Q, Terminate active process, exec, $scriptsDir/KillActiveProcess.sh +bindd = CTRL ALT, L, lock screen, exec, $scriptsDir/LockScreen.sh +bindd = CTRL ALT, P, powermenu, exec, $scriptsDir/Wlogout.sh +bindd = $mainMod SHIFT, N, notification panel, exec, swaync-client -t -sw +bindd = $mainMod SHIFT, E, Quick settings menu, exec, $scriptsDir/Kool_Quick_Settings.sh # Master Layout -bind = $mainMod CTRL, D, layoutmsg, removemaster -bind = $mainMod, I, layoutmsg, addmaster -bind = $mainMod, J, layoutmsg, cyclenext -bind = $mainMod, K, layoutmsg, cycleprev -bind = $mainMod CTRL, Return, layoutmsg, swapwithmaster +bindd = $mainMod CTRL, D, remove master, layoutmsg, removemaster +bindd = $mainMod, I, add master, layoutmsg, addmaster +# NOTE: J/K bindings are set dynamically by scripts/KeybindsLayoutInit.sh and scripts/ChangeLayout.sh +# (we intentionally do not bind them statically here to avoid conflicts across layouts) +# bindd = $mainMod, J, cycle next, layoutmsg, cyclenext +# bindd = $mainMod, K, cycle previous, layoutmsg, cycleprev +bindd = $mainMod CTRL, Return, swap with master, layoutmsg, swapwithmaster # Dwindle Layout -bind = $mainMod SHIFT, I, togglesplit # only works on dwindle layout -bind = $mainMod, P, pseudo, # dwindle +bindd = $mainMod SHIFT, I, toggle split (dwindle), togglesplit +bindd = $mainMod, P, toggle pseudo (dwindle), pseudo, # Works on either layout (Master or Dwindle) -bind = $mainMod, M, exec, hyprctl dispatch splitratio 0.3 +bindd = $mainMod, M, set split ratio 0.3, exec, hyprctl dispatch splitratio 0.3 # group -bind = $mainMod, G, togglegroup # toggle group -bind = $mainMod CTRL, tab, changegroupactive # change focus to another window +bindd = $mainMod, G, toggle group, togglegroup +bindd = $mainMod CTRL, tab, change active in group, changegroupactive - # Cycle windows if floating bring to top -bind = ALT, tab, cyclenext -bind = ALT, tab, bringactivetotop +# Cycle windows; if floating bring to top +bindd = ALT, tab, cycle next window, cyclenext +bindd = ALT, tab, bring active to top, bringactivetotop # Special Keys / Hot Keys -bindel = , xf86audioraisevolume, exec, $scriptsDir/Volume.sh --inc # volume up -bindel = , xf86audiolowervolume, exec, $scriptsDir/Volume.sh --dec # volume down -bindl = , xf86AudioMicMute, exec, $scriptsDir/Volume.sh --toggle-mic # mic mute -bindl = , xf86audiomute, exec, $scriptsDir/Volume.sh --toggle # mute -bindl = , xf86Sleep, exec, systemctl suspend # sleep button -bindl = , xf86Rfkill, exec, $scriptsDir/AirplaneMode.sh # Airplane mode +bindeld = , xf86audioraisevolume, volume up, exec, $scriptsDir/Volume.sh --inc +bindeld = , xf86audiolowervolume, volume down, exec, $scriptsDir/Volume.sh --dec +bindld = , xf86AudioMicMute, toggle mic mute, exec, $scriptsDir/Volume.sh --toggle-mic +bindld = , xf86audiomute, toggle mute, exec, $scriptsDir/Volume.sh --toggle +bindld = , xf86Sleep, sleep, exec, systemctl suspend +bindld = , xf86Rfkill, airplane mode, exec, $scriptsDir/AirplaneMode.sh # media controls using keyboards -bindl = , xf86AudioPlayPause, exec, $scriptsDir/MediaCtrl.sh --pause -bindl = , xf86AudioPause, exec, $scriptsDir/MediaCtrl.sh --pause -bindl = , xf86AudioPlay, exec, $scriptsDir/MediaCtrl.sh --pause -bindl = , xf86AudioNext, exec, $scriptsDir/MediaCtrl.sh --nxt -bindl = , xf86AudioPrev, exec, $scriptsDir/MediaCtrl.sh --prv -bindl = , xf86audiostop, exec, $scriptsDir/MediaCtrl.sh --stop +bindld = , xf86AudioPlayPause, play/pause, exec, $scriptsDir/MediaCtrl.sh --pause +bindld = , xf86AudioPause, pause, exec, $scriptsDir/MediaCtrl.sh --pause +bindld = , xf86AudioPlay, play, exec, $scriptsDir/MediaCtrl.sh --pause +bindld = , xf86AudioNext, next track, exec, $scriptsDir/MediaCtrl.sh --nxt +bindld = , xf86AudioPrev, previous track, exec, $scriptsDir/MediaCtrl.sh --prv +bindld = , xf86audiostop, stop, exec, $scriptsDir/MediaCtrl.sh --stop # Screenshot keybindings NOTE: You may need to press Fn key as well -bind = $mainMod, Print, exec, $scriptsDir/ScreenShot.sh --now # screenshot -bind = $mainMod SHIFT, Print, exec, $scriptsDir/ScreenShot.sh --area # screenshot (area) -bind = $mainMod CTRL, Print, exec, $scriptsDir/ScreenShot.sh --in5 # screenshot (5 secs delay) -bind = $mainMod CTRL SHIFT, Print, exec, $scriptsDir/ScreenShot.sh --in10 # screenshot (10 secs delay) -bind = ALT, Print, exec, $scriptsDir/ScreenShot.sh --active # screenshot (active window only) +bindd = $mainMod, Print, screenshot now, exec, $scriptsDir/ScreenShot.sh --now +bindd = $mainMod SHIFT, Print, screenshot (area), exec, $scriptsDir/ScreenShot.sh --area +bindd = $mainMod CTRL, Print, screenshot in 5s, exec, $scriptsDir/ScreenShot.sh --in5 +bindd = $mainMod CTRL SHIFT, Print, screenshot in 10s, exec, $scriptsDir/ScreenShot.sh --in10 +bindd = ALT, Print, screenshot active window, exec, $scriptsDir/ScreenShot.sh --active # screenshot with swappy (another screenshot tool) -bind = $mainMod SHIFT, S, exec, $scriptsDir/ScreenShot.sh --swappy #screenshot (swappy) +bindd = $mainMod SHIFT, S, screenshot (swappy), exec, $scriptsDir/ScreenShot.sh --swappy # Resize windows -binde = $mainMod SHIFT, left, resizeactive,-50 0 -binde = $mainMod SHIFT, right, resizeactive,50 0 -binde = $mainMod SHIFT, up, resizeactive,0 -50 -binde = $mainMod SHIFT, down, resizeactive,0 50 +binded = $mainMod SHIFT, left, resize left (-50), resizeactive, -50 0 +binded = $mainMod SHIFT, right, resize right (+50), resizeactive, 50 0 +binded = $mainMod SHIFT, up, resize up (-50), resizeactive, 0 -50 +binded = $mainMod SHIFT, down, resize down (+50), resizeactive, 0 50 # Move windows -bind = $mainMod CTRL, left, movewindow, l -bind = $mainMod CTRL, right, movewindow, r -bind = $mainMod CTRL, up, movewindow, u -bind = $mainMod CTRL, down, movewindow, d +bindd = $mainMod CTRL, left, move window left, movewindow, l +bindd = $mainMod CTRL, right, move window right, movewindow, r +bindd = $mainMod CTRL, up, move window up, movewindow, u +bindd = $mainMod CTRL, down, move window down, movewindow, d # Swap windows -bind = $mainMod ALT, left, swapwindow, l -bind = $mainMod ALT, right, swapwindow, r -bind = $mainMod ALT, up, swapwindow, u -bind = $mainMod ALT, down, swapwindow, d +bindd = $mainMod ALT, left, swap window left, swapwindow, l +bindd = $mainMod ALT, right, swap window right, swapwindow, r +bindd = $mainMod ALT, up, swap window up, swapwindow, u +bindd = $mainMod ALT, down, swap window down, swapwindow, d # Move focus with mainMod + arrow keys -bind = $mainMod, left, movefocus, l -bind = $mainMod, right, movefocus, r -bind = $mainMod, up, movefocus, u -bind = $mainMod, down, movefocus, d +bindd = $mainMod, left, focus left, movefocus, l +bindd = $mainMod, right, focus right, movefocus, r +bindd = $mainMod, up, focus up, movefocus, u +bindd = $mainMod, down, focus down, movefocus, d # Workspaces related -bind = $mainMod, tab, workspace, m+1 -bind = $mainMod SHIFT, tab, workspace, m-1 +bindd = $mainMod, tab, next workspace, workspace, m+1 +bindd = $mainMod SHIFT, tab, previous workspace, workspace, m-1 # Special workspace -bind = $mainMod SHIFT, U, movetoworkspace, special -bind = $mainMod, U, togglespecialworkspace, +bindd = $mainMod SHIFT, U, move to special workspace, movetoworkspace, special +bindd = $mainMod, U, toggle special workspace, togglespecialworkspace, # The following mappings use the key codes to better support various keyboard layouts # 1 is code:10, 2 is code 11, etc # Switch workspaces with mainMod + [0-9] -bind = $mainMod, code:10, workspace, 1 # NOTE: code:10 = key 1 -bind = $mainMod, code:11, workspace, 2 # NOTE: code:11 = key 2 -bind = $mainMod, code:12, workspace, 3 # NOTE: code:12 = key 3 -bind = $mainMod, code:13, workspace, 4 # NOTE: code:13 = key 4 -bind = $mainMod, code:14, workspace, 5 # NOTE: code:14 = key 5 -bind = $mainMod, code:15, workspace, 6 # NOTE: code:15 = key 6 -bind = $mainMod, code:16, workspace, 7 # NOTE: code:16 = key 7 -bind = $mainMod, code:17, workspace, 8 # NOTE: code:17 = key 8 -bind = $mainMod, code:18, workspace, 9 # NOTE: code:18 = key 9 -bind = $mainMod, code:19, workspace, 10 # NOTE: code:19 = key 0 +bindd = $mainMod, code:10, workspace 1, workspace, 1 # NOTE: code:10 = key 1 +bindd = $mainMod, code:11, workspace 2, workspace, 2 # NOTE: code:11 = key 2 +bindd = $mainMod, code:12, workspace 3, workspace, 3 # NOTE: code:12 = key 3 +bindd = $mainMod, code:13, workspace 4, workspace, 4 # NOTE: code:13 = key 4 +bindd = $mainMod, code:14, workspace 5, workspace, 5 # NOTE: code:14 = key 5 +bindd = $mainMod, code:15, workspace 6, workspace, 6 # NOTE: code:15 = key 6 +bindd = $mainMod, code:16, workspace 7, workspace, 7 # NOTE: code:16 = key 7 +bindd = $mainMod, code:17, workspace 8, workspace, 8 # NOTE: code:17 = key 8 +bindd = $mainMod, code:18, workspace 9, workspace, 9 # NOTE: code:18 = key 9 +bindd = $mainMod, code:19, workspace 10, workspace, 10 # NOTE: code:19 = key 0 # Move active window and follow to workspace mainMod + SHIFT [0-9] -bind = $mainMod SHIFT, code:10, movetoworkspace, 1 # NOTE: code:10 = key 1 -bind = $mainMod SHIFT, code:11, movetoworkspace, 2 # NOTE: code:11 = key 2 -bind = $mainMod SHIFT, code:12, movetoworkspace, 3 # NOTE: code:12 = key 3 -bind = $mainMod SHIFT, code:13, movetoworkspace, 4 # NOTE: code:13 = key 4 -bind = $mainMod SHIFT, code:14, movetoworkspace, 5 # NOTE: code:14 = key 5 -bind = $mainMod SHIFT, code:15, movetoworkspace, 6 # NOTE: code:15 = key 6 -bind = $mainMod SHIFT, code:16, movetoworkspace, 7 # NOTE: code:16 = key 7 -bind = $mainMod SHIFT, code:17, movetoworkspace, 8 # NOTE: code:17 = key 8 -bind = $mainMod SHIFT, code:18, movetoworkspace, 9 # NOTE: code:18 = key 9 -bind = $mainMod SHIFT, code:19, movetoworkspace, 10 # NOTE: code:19 = key 0 -bind = $mainMod SHIFT, bracketleft, movetoworkspace, -1 # brackets [ -bind = $mainMod SHIFT, bracketright, movetoworkspace, +1 # brackets ] +bindd = $mainMod SHIFT, code:10, move to workspace 1, movetoworkspace, 1 # NOTE: code:10 = key 1 +bindd = $mainMod SHIFT, code:11, move to workspace 2, movetoworkspace, 2 # NOTE: code:11 = key 2 +bindd = $mainMod SHIFT, code:12, move to workspace 3, movetoworkspace, 3 # NOTE: code:12 = key 3 +bindd = $mainMod SHIFT, code:13, move to workspace 4, movetoworkspace, 4 # NOTE: code:13 = key 4 +bindd = $mainMod SHIFT, code:14, move to workspace 5, movetoworkspace, 5 # NOTE: code:14 = key 5 +bindd = $mainMod SHIFT, code:15, move to workspace 6, movetoworkspace, 6 # NOTE: code:15 = key 6 +bindd = $mainMod SHIFT, code:16, move to workspace 7, movetoworkspace, 7 # NOTE: code:16 = key 7 +bindd = $mainMod SHIFT, code:17, move to workspace 8, movetoworkspace, 8 # NOTE: code:17 = key 8 +bindd = $mainMod SHIFT, code:18, move to workspace 9, movetoworkspace, 9 # NOTE: code:18 = key 9 +bindd = $mainMod SHIFT, code:19, move to workspace 10, movetoworkspace, 10 # NOTE: code:19 = key 0 +bindd = $mainMod SHIFT, bracketleft, move to previous workspace, movetoworkspace, -1 # brackets [ +bindd = $mainMod SHIFT, bracketright, move to next workspace, movetoworkspace, +1 # brackets ] # Move active window to a workspace silently mainMod + CTRL [0-9] -bind = $mainMod CTRL, code:10, movetoworkspacesilent, 1 # NOTE: code:10 = key 1 -bind = $mainMod CTRL, code:11, movetoworkspacesilent, 2 # NOTE: code:11 = key 2 -bind = $mainMod CTRL, code:12, movetoworkspacesilent, 3 # NOTE: code:12 = key 3 -bind = $mainMod CTRL, code:13, movetoworkspacesilent, 4 # NOTE: code:13 = key 4 -bind = $mainMod CTRL, code:14, movetoworkspacesilent, 5 # NOTE: code:14 = key 5 -bind = $mainMod CTRL, code:15, movetoworkspacesilent, 6 # NOTE: code:15 = key 6 -bind = $mainMod CTRL, code:16, movetoworkspacesilent, 7 # NOTE: code:16 = key 7 -bind = $mainMod CTRL, code:17, movetoworkspacesilent, 8 # NOTE: code:17 = key 8 -bind = $mainMod CTRL, code:18, movetoworkspacesilent, 9 # NOTE: code:18 = key 9 -bind = $mainMod CTRL, code:19, movetoworkspacesilent, 10 # NOTE: code:19 = key 0 -bind = $mainMod CTRL, bracketleft, movetoworkspacesilent, -1 # brackets [ -bind = $mainMod CTRL, bracketright, movetoworkspacesilent, +1 # brackets ] +bindd = $mainMod CTRL, code:10, move silently to workspace 1, movetoworkspacesilent, 1 # NOTE: code:10 = key 1 +bindd = $mainMod CTRL, code:11, move silently to workspace 2, movetoworkspacesilent, 2 # NOTE: code:11 = key 2 +bindd = $mainMod CTRL, code:12, move silently to workspace 3, movetoworkspacesilent, 3 # NOTE: code:12 = key 3 +bindd = $mainMod CTRL, code:13, move silently to workspace 4, movetoworkspacesilent, 4 # NOTE: code:13 = key 4 +bindd = $mainMod CTRL, code:14, move silently to workspace 5, movetoworkspacesilent, 5 # NOTE: code:14 = key 5 +bindd = $mainMod CTRL, code:15, move silently to workspace 6, movetoworkspacesilent, 6 # NOTE: code:15 = key 6 +bindd = $mainMod CTRL, code:16, move silently to workspace 7, movetoworkspacesilent, 7 # NOTE: code:16 = key 7 +bindd = $mainMod CTRL, code:17, move silently to workspace 8, movetoworkspacesilent, 8 # NOTE: code:17 = key 8 +bindd = $mainMod CTRL, code:18, move silently to workspace 9, movetoworkspacesilent, 9 # NOTE: code:18 = key 9 +bindd = $mainMod CTRL, code:19, move silently to workspace 10, movetoworkspacesilent, 10 # NOTE: code:19 = key 0 +bindd = $mainMod CTRL, bracketleft, move silently to previous workspace, movetoworkspacesilent, -1 # brackets [ +bindd = $mainMod CTRL, bracketright, move silently to next workspace, movetoworkspacesilent, +1 # brackets ] # Scroll through existing workspaces with mainMod + scroll -bind = $mainMod, mouse_down, workspace, e+1 -bind = $mainMod, mouse_up, workspace, e-1 -bind = $mainMod, period, workspace, e+1 -bind = $mainMod, comma, workspace, e-1 +bindd = $mainMod, mouse_down, next workspace, workspace, e+1 +bindd = $mainMod, mouse_up, previous workspace, workspace, e-1 +bindd = $mainMod, period, next workspace, workspace, e+1 +bindd = $mainMod, comma, previous workspace, workspace, e-1 # Move/resize windows with mainMod + LMB/RMB and dragging -bindm = $mainMod, mouse:272, movewindow # NOTE: mouse:272 = left click -bindm = $mainMod, mouse:273, resizewindow # NOTE: mouse:272 = right click
\ No newline at end of file +bindmd = $mainMod, mouse:272, move window, movewindow # NOTE: mouse:272 = left click +bindmd = $mainMod, mouse:273, resize window, resizewindow # NOTE: mouse:272 = right click diff --git a/config/hypr/UserConfigs/Startup_Apps.conf b/config/hypr/configs/Startup_Apps.conf index 7b668b77..c1670595 100644 --- a/config/hypr/UserConfigs/Startup_Apps.conf +++ b/config/hypr/configs/Startup_Apps.conf @@ -1,5 +1,5 @@ # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ # -# Commands and Apps to be executed at launch +# Commands and Apps to be executed at launch (vendor defaults) $scriptsDir = $HOME/.config/hypr/scripts $UserScripts = $HOME/.config/hypr/UserScripts @@ -19,6 +19,7 @@ exec-once = swww-daemon --format xrgb # Startup exec-once = dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP exec-once = systemctl --user import-environment WAYLAND_DISPLAY XDG_CURRENT_DESKTOP +exec-once = $scriptsDir/KeybindsLayoutInit.sh # Initialize Drop Down terminal - See Bug#810 https://github.com/JaKooLit/Hyprland-Dots/issues/810#issuecomment-3351947644 exec-once = $HOME/.config/hypr/scripts/Dropterminal.sh kitty & @@ -29,6 +30,7 @@ exec-once = $scriptsDir/Polkit.sh # starup apps exec-once = nm-applet --indicator +exec-once = nm-tray # For ubuntu exec-once = swaync #exec-once = ags #exec-once = blueman-applet @@ -46,6 +48,8 @@ exec-once = $UserScripts/RainbowBorders.sh # Starting hypridle to start hyprlock exec-once = hypridle +# Resume Hyprsunset if state is "on" from previous session +exec-once = $scriptsDir/Hyprsunset.sh init # Here are list of features available but disabled by default # exec-once = swww-daemon --format xrgb && swww img $HOME/Pictures/wallpapers/mecha-nostalgia.png # persistent wallpaper @@ -54,4 +58,4 @@ exec-once = hypridle #exec-once = $scriptsDir/Polkit-NixOS.sh # xdg-desktop-portal-hyprland (should be auto starting. However, you can force to start) -#exec-once = $scriptsDir/PortalHyprland.sh +#exec-once = $scriptsDir/PortalHyprland.sh
\ No newline at end of file diff --git a/config/hypr/configs/WindowRules-config-v3.conf b/config/hypr/configs/WindowRules-config-v3.conf new file mode 100644 index 00000000..b54c6a85 --- /dev/null +++ b/config/hypr/configs/WindowRules-config-v3.conf @@ -0,0 +1,690 @@ +# /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ # +# Vendor defaults for window rules and layerrules +# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more + +# NOTES: This is only for Hyprland > 0.48 + +# note for ja: This should NOT be implemented on Debian and Ubuntu + +# windowrule - tags - add apps under appropriate tag to use the same settings +# browser tags + +# notif tags + +# KooL settings tag + +# terminal tags + +# email tags + +# project tags + +# screenshare tags + +# IM tags + +# game tags + +# gamestore tags + +# file-manager tags + +# wallpaper tags + +# multimedia tags + +# multimedia-video tags + +# settings tags + +# viewer tags + +# Some special override rules + +# POSITION +# windowrule = center,floating:1 # warning, it cause even the menu to float and center. +#windowrule = move 72% 7%,title:^(Firefox)$ + +# windowrule to avoid idle for fullscreen apps +#windowrule = idleinhibit fullscreen, class:^(*)$ +#windowrule = idleinhibit fullscreen, title:^(*)$ + +# windowrule move to workspace +#windowrule = workspace 1, tag:email* +#windowrule = workspace 2, tag:browser* +#windowrule = workspace 3, class:^([Tt]hunar)$ +#windowrule = workspace 3, tag:projects* +#windowrule = workspace 5, tag:gamestore* +#windowrule = workspace 7, tag:im* +#windowrule = workspace 8, tag:games* + +# windowrule move to workspace (silent) +#windowrule = workspace 4 silent, tag:screenshare* +#windowrule = workspace 6 silent, class:^(virt-manager)$ +#windowrule = workspace 6 silent, class:^(.virt-manager-wrapped)$ +#windowrule = workspace 9 silent, tag:multimedia* +# +# FLOAT +#windowrule = float, class:^([Ww]hatsapp-for-linux|ZapZap|com.rtosta.zapzap)$ +#windowrule = float, title:^(Firefox)$ + +# windowrule - ######### float popups and dialogue ####### + + + + +# END of float popups and dialogue ####### + +# OPACITY + +# SIZE + +#windowrule = size 25% 25%, title:^(Picture-in-Picture)$ +#windowrule = size 25% 25%, title:^(Firefox)$ + +# PINNING +#windowrule = pin,title:^(Firefox)$ + +# windowrule - extras + +# BLUR & FULLSCREEN + + +#This not gonna take the focus to the window that appears when hovering over some of the parts of the IntelliJ Products + +#This will gonna make the VS Code bluer like other apps + +#windowrule = bordercolor rgb(EE4B55) rgb(880808), fullscreen:1 +#windowrule = bordercolor rgb(282737) rgb(1E1D2D), floating:1 +#windowrule = opacity 0.8 0.8, pinned:1 + +# LAYER RULES + +#layerrule = ignorealpha 0.5, tag:notif* + +#layerrule = ignorezero, class:^([Rr]ofi)$ +#layerrule = blur, class:^([Rr]ofi)$ +#layerrule = unset,class:^([Rr]ofi)$ +#layerrule = ignorezero, <rofi> + +#layerrule = ignorezero, overview +#layerrule = blur, overview +# --- Auto-generated window rules --- +windowrule { + name = windowrule-1 + match:class = ^([Ff]irefox|org.mozilla.firefox|[Ff]irefox-esr|[Ff]irefox-bin)$ + tag = +browser +} + +windowrule { + name = windowrule-2 + match:class = ^([Gg]oogle-chrome(-beta|-dev|-unstable)?)$ + tag = +browser +} + +windowrule { + name = windowrule-3 + match:class = ^(chrome-.+-Default)$ # Chrome PWAs + tag = +browser +} + +windowrule { + name = windowrule-4 + match:class = ^([Cc]hromium)$ + tag = +browser +} + +windowrule { + name = windowrule-5 + match:class = ^([Mm]icrosoft-edge(-stable|-beta|-dev|-unstable))$ + tag = +browser +} + +windowrule { + name = windowrule-6 + match:class = ^(Brave-browser(-beta|-dev|-unstable)?)$ + tag = +browser +} + +windowrule { + name = windowrule-7 + match:class = ^([Tt]horium-browser|[Cc]achy-browser)$ + tag = +browser +} + +windowrule { + name = windowrule-8 + match:class = ^(zen-alpha|zen)$ + tag = +browser +} + +windowrule { + name = windowrule-9 + match:class = ^(swaync-control-center|swaync-notification-window|swaync-client|class)$ + tag = +notif +} + +windowrule { + name = windowrule-10 + match:title = ^(KooL Quick Cheat Sheet)$ + tag = +KooL_Cheat +} + +windowrule { + name = windowrule-11 + match:title = ^(KooL Hyprland Settings)$ + tag = +KooL_Settings +} + +windowrule { + name = windowrule-12 + match:class = ^(nwg-displays|nwg-look)$ + tag = +KooL-Settings +} + +windowrule { + name = windowrule-13 + match:class = ^(Alacritty|kitty|kitty-dropterm)$ + tag = +terminal +} + +windowrule { + name = windowrule-14 + match:class = ^([Tt]hunderbird|org.gnome.Evolution)$ + tag = +email +} + +windowrule { + name = windowrule-15 + match:class = ^(eu.betterbird.Betterbird)$ + tag = +email +} + +windowrule { + name = windowrule-16 + match:class = ^(codium|codium-url-handler|VSCodium)$ + tag = +projects +} + +windowrule { + name = windowrule-17 + match:class = ^(VSCode|code-url-handler)$ + tag = +projects +} + +windowrule { + name = windowrule-18 + match:class = ^(jetbrains-.+)$ # JetBrains IDEs + tag = +projects +} + +windowrule { + name = windowrule-19 + match:class = ^(com.obsproject.Studio)$ + tag = +screenshare +} + +windowrule { + name = windowrule-20 + match:class = ^([Dd]iscord|[Ww]ebCord|[Vv]esktop)$ + tag = +im +} + +windowrule { + name = windowrule-21 + match:class = ^([Ff]erdium)$ + center = on + float = on + size = 60% = 70% + tag = +im +} + +windowrule { + name = windowrule-22 + match:class = ^([Ww]hatsapp-for-linux)$ + tag = +im +} + +windowrule { + name = windowrule-23 + match:class = ^(ZapZap|com.rtosta.zapzap)$ + tag = +im +} + +windowrule { + name = windowrule-24 + match:class = ^(org.telegram.desktop|io.github.tdesktop_x64.TDesktop)$ + tag = +im +} + +windowrule { + name = windowrule-25 + match:class = ^(teams-for-linux)$ + tag = +im +} + +windowrule { + name = windowrule-26 + match:class = ^(im.riot.Riot|Element)$ # Element Matrix client + tag = +im +} + +windowrule { + name = windowrule-27 + match:class = ^(gamescope)$ + tag = +games +} + +windowrule { + name = windowrule-28 + match:class = ^(steam_app_\d+)$ + tag = +games +} + +windowrule { + name = windowrule-29 + match:class = ^([Ss]team)$ + tag = +gamestore +} + +windowrule { + name = windowrule-30 + match:title = ^([Ll]utris)$ + tag = +gamestore +} + +windowrule { + name = windowrule-31 + match:class = ^(com.heroicgameslauncher.hgl)$ + tag = +gamestore +} + +windowrule { + name = windowrule-32 + match:class = ^([Tt]hunar|org.gnome.Nautilus|[Pp]cmanfm-qt)$ + tag = +file-manager +} + +windowrule { + name = windowrule-33 + match:class = ^(app.drey.Warp)$ + tag = +file-manager +} + +windowrule { + name = windowrule-34 + match:class = ^([Ww]aytrogen)$ + tag = +wallpaper +} + +windowrule { + name = windowrule-35 + match:class = ^([Aa]udacious)$ + tag = +multimedia +} + +windowrule { + name = windowrule-36 + match:class = ^([Mm]pv|vlc)$ + tag = +multimedia_video +} + +windowrule { + name = windowrule-37 + match:title = ^(ROG Control)$ + center = on + tag = +settings +} + +windowrule { + name = windowrule-38 + match:class = ^(wihotspot(-gui)?)$ # wifi hotspot + tag = +settings +} + +windowrule { + name = windowrule-39 + match:class = ^([Bb]aobab|org.gnome.[Bb]aobab)$ # Disk usage analyzer + tag = +settings +} + +windowrule { + name = windowrule-40 + match:class = ^(gnome-disks|wihotspot(-gui)?)$ + tag = +settings +} + +windowrule { + name = windowrule-41 + match:title = (Kvantum Manager) + tag = +settings +} + +windowrule { + name = windowrule-42 + match:class = ^(file-roller|org.gnome.FileRoller)$ # archive manager + tag = +settings +} + +windowrule { + name = windowrule-43 + match:class = ^(nm-applet|nm-connection-editor|blueman-manager)$ + tag = +settings +} + +windowrule { + name = windowrule-44 + match:class = ^(pavucontrol|org.pulseaudio.pavucontrol|com.saivert.pwvucontrol)$ + center = on + tag = +settings +} + +windowrule { + name = windowrule-45 + match:class = ^(qt5ct|qt6ct|[Yy]ad)$ + tag = +settings +} + +windowrule { + name = windowrule-46 + match:class = (xdg-desktop-portal-gtk) + tag = +settings +} + +windowrule { + name = windowrule-47 + match:class = ^(org.kde.polkit-kde-authentication-agent-1)$ + tag = +settings +} + +windowrule { + name = windowrule-48 + match:class = ^([Rr]ofi)$ + tag = +settings +} + +windowrule { + name = windowrule-49 + match:class = ^(gnome-system-monitor|org.gnome.SystemMonitor|io.missioncenter.MissionCenter)$ # system monitor + tag = +viewer +} + +windowrule { + name = windowrule-50 + match:class = ^(evince)$ # document viewer + tag = +viewer +} + +windowrule { + name = windowrule-51 + match:class = ^(eog|org.gnome.Loupe)$ # image viewer + tag = +viewer +} + +windowrule { + name = windowrule-52 + match:tag = multimedia_video* + no_blur = on + opacity = 1.0 +} + +windowrule { + name = windowrule-53 + match:tag = KooL_Cheat* + center = on + float = on + size = 65% = 90% +} + +windowrule { + name = windowrule-54 + match:class = ([Tt]hunar) + match:title = negative:(.*[Tt]hunar.*) + center = on + float = on +} + +windowrule { + name = windowrule-55 + match:tag = KooL-Settings* + center = on + float = on +} + +windowrule { + name = windowrule-56 + match:title = ^(Keybindings)$ + center = on +} + +windowrule { + name = windowrule-57 + match:class = ^([Ww]hatsapp-for-linux|ZapZap|com.rtosta.zapzap)$ + center = on + size = 60% = 70% +} + +windowrule { + name = windowrule-58 + match:title = ^(Picture-in-Picture)$ + float = on + move = 72% = 7% + opacity = 0.95 = 0.75 + pin = 0 +} + +windowrule { + name = windowrule-59 + match:fullscreen = 1 + idle_inhibit = fullscreen +} + +windowrule { + name = windowrule-60 + match:tag = wallpaper* + float = on + opacity = 0.9 = 0.7 + size = 70% = 70% +} + +windowrule { + name = windowrule-61 + match:tag = settings* + float = on + opacity = 0.8 = 0.7 + size = 70% = 70% +} + +windowrule { + name = windowrule-62 + match:tag = viewer* + float = on + opacity = 0.82 = 0.75 +} + +windowrule { + name = windowrule-63 + match:class = ([Zz]oom|onedriver|onedriver-launcher)$ + float = on +} + +windowrule { + name = windowrule-64 + match:class = (org.gnome.Calculator) + match:title = (Calculator) + float = on +} + +windowrule { + name = windowrule-65 + match:class = ^(mpv|com.github.rafostar.Clapper)$ + float = on +} + +windowrule { + name = windowrule-66 + match:class = ^([Qq]alculate-gtk)$ + float = on +} + +windowrule { + name = windowrule-67 + match:title = ^(Authentication Required)$ + center = on + float = on +} + +windowrule { + name = windowrule-68 + match:class = (codium|codium-url-handler|VSCodium) + match:title = negative:(.*codium.*|.*VSCodium.*) + float = on +} + +windowrule { + name = windowrule-69 + match:class = ^(com.heroicgameslauncher.hgl)$ + match:title = negative:(Heroic Games Launcher) + float = on +} + +windowrule { + name = windowrule-70 + match:class = ^([Ss]team)$ + match:title = negative:^([Ss]team)$ + float = on +} + +windowrule { + name = windowrule-71 + match:title = ^(Add Folder to Workspace)$ + center = on + float = on + size = 70% = 60% +} + +windowrule { + name = windowrule-72 + match:title = ^(Save As)$ + center = on + float = on + size = 70% = 60% +} + +windowrule { + name = windowrule-73 + match:initial_title = (Open Files) + float = on + size = 70% = 60% +} + +windowrule { + name = windowrule-74 + match:title = ^(SDDM Background)$ #KooL's Dots YAD for setting SDDM background + center = on + float = on + size = 16% = 12% +} + +windowrule { + name = windowrule-75 + match:tag = browser* + opacity = 0.99 = 0.8 +} + +windowrule { + name = windowrule-76 + match:tag = projects* + opacity = 0.9 = 0.8 +} + +windowrule { + name = windowrule-77 + match:tag = im* + opacity = 0.94 = 0.86 +} + +windowrule { + name = windowrule-78 + match:tag = multimedia* + opacity = 0.94 = 0.86 +} + +windowrule { + name = windowrule-79 + match:tag = file-manager* + opacity = 0.9 = 0.8 +} + +windowrule { + name = windowrule-80 + match:tag = terminal* + opacity = 0.9 = 0.7 +} + +windowrule { + name = windowrule-81 + match:class = ^(gedit|org.gnome.TextEditor|mousepad)$ + opacity = 0.8 = 0.7 +} + +windowrule { + name = windowrule-82 + match:class = ^(deluge)$ + opacity = 0.9 = 0.8 +} + +windowrule { + name = windowrule-83 + match:class = ^(seahorse)$ # gnome-keyring gui + opacity = 0.9 = 0.8 +} + +windowrule { + name = windowrule-84 + match:class = ^(code)$ + opacity = 0.8 + opacity = 0.9 +} + +windowrule { + name = windowrule-85 + match:tag = games* + fullscreen = 0 + no_blur = on +} + +windowrule { + name = windowrule-86 + match:class = ^(jetbrains-*) + no_initial_focus = on +} + +windowrule { + name = windowrule-87 + match:title = ^(wind.*)$ + no_initial_focus = on +} + +# --- Auto-generated layer rules --- +layerrule { + name = layerrule-1 + match:namespace = rofi + blur = on + ignore_alpha = 0 +} + +layerrule { + name = layerrule-2 + match:namespace = notifications + blur = on + ignore_alpha = 0 +} + +layerrule { + name = layerrule-3 + match:namespace = quickshell:overview + blur = on + ignore_alpha = 0 + ignore_alpha = 0.5 +} diff --git a/config/hypr/configs/WindowRules.conf b/config/hypr/configs/WindowRules.conf new file mode 100644 index 00000000..f02c5d29 --- /dev/null +++ b/config/hypr/configs/WindowRules.conf @@ -0,0 +1,235 @@ +# /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ # +# Vendor defaults for window rules and layerrules +# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more + +# NOTES: This is only for Hyprland > 0.48 + +# note for ja: This should NOT be implemented on Debian and Ubuntu + +# windowrule - tags - add apps under appropriate tag to use the same settings +# browser tags +windowrule = tag +browser, class:^([Ff]irefox|org.mozilla.firefox|[Ff]irefox-esr|[Ff]irefox-bin)$ +windowrule = tag +browser, class:^([Gg]oogle-chrome(-beta|-dev|-unstable)?)$ +windowrule = tag +browser, class:^(chrome-.+-Default)$ # Chrome PWAs +windowrule = tag +browser, class:^([Cc]hromium)$ +windowrule = tag +browser, class:^([Mm]icrosoft-edge(-stable|-beta|-dev|-unstable))$ +windowrule = tag +browser, class:^(Brave-browser(-beta|-dev|-unstable)?)$ +windowrule = tag +browser, class:^([Tt]horium-browser|[Cc]achy-browser)$ +windowrule = tag +browser, class:^(zen-alpha|zen)$ + +# notif tags +windowrule = tag +notif, class:^(swaync-control-center|swaync-notification-window|swaync-client|class)$ + +# KooL settings tag +windowrule = tag +KooL_Cheat, title:^(KooL Quick Cheat Sheet)$ +windowrule = tag +KooL_Settings, title:^(KooL Hyprland Settings)$ +windowrule = tag +KooL-Settings, class:^(nwg-displays|nwg-look)$ + +# terminal tags +windowrule = tag +terminal, class:^(Alacritty|kitty|kitty-dropterm)$ + +# email tags +windowrule = tag +email, class:^([Tt]hunderbird|org.gnome.Evolution)$ +windowrule = tag +email, class:^(eu.betterbird.Betterbird)$ + +# project tags +windowrule = tag +projects, class:^(codium|codium-url-handler|VSCodium)$ +windowrule = tag +projects, class:^(VSCode|code-url-handler)$ +windowrule = tag +projects, class:^(jetbrains-.+)$ # JetBrains IDEs + +# screenshare tags +windowrule = tag +screenshare, class:^(com.obsproject.Studio)$ + +# IM tags +windowrule = tag +im, class:^([Dd]iscord|[Ww]ebCord|[Vv]esktop)$ +windowrule = tag +im, class:^([Ff]erdium)$ +windowrule = tag +im, class:^([Ww]hatsapp-for-linux)$ +windowrule = tag +im, class:^(ZapZap|com.rtosta.zapzap)$ +windowrule = tag +im, class:^(org.telegram.desktop|io.github.tdesktop_x64.TDesktop)$ +windowrule = tag +im, class:^(teams-for-linux)$ +windowrule = tag +im, class:^(im.riot.Riot|Element)$ # Element Matrix client + +# game tags +windowrule = tag +games, class:^(gamescope)$ +windowrule = tag +games, class:^(steam_app_\d+)$ + +# gamestore tags +windowrule = tag +gamestore, class:^([Ss]team)$ +windowrule = tag +gamestore, title:^([Ll]utris)$ +windowrule = tag +gamestore, class:^(com.heroicgameslauncher.hgl)$ + +# file-manager tags +windowrule = tag +file-manager, class:^([Tt]hunar|org.gnome.Nautilus|[Pp]cmanfm-qt)$ +windowrule = tag +file-manager, class:^(app.drey.Warp)$ + +# wallpaper tags +windowrule = tag +wallpaper, class:^([Ww]aytrogen)$ + +# multimedia tags +windowrule = tag +multimedia, class:^([Aa]udacious)$ + +# multimedia-video tags +windowrule = tag +multimedia_video, class:^([Mm]pv|vlc)$ + +# settings tags +windowrule = tag +settings, title:^(ROG Control)$ +windowrule = tag +settings, class:^(wihotspot(-gui)?)$ # wifi hotspot +windowrule = tag +settings, class:^([Bb]aobab|org.gnome.[Bb]aobab)$ # Disk usage analyzer +windowrule = tag +settings, class:^(gnome-disks|wihotspot(-gui)?)$ +windowrule = tag +settings, title:(Kvantum Manager) +windowrule = tag +settings, class:^(file-roller|org.gnome.FileRoller)$ # archive manager +windowrule = tag +settings, class:^(nm-applet|nm-connection-editor|blueman-manager)$ +windowrule = tag +settings, class:^(pavucontrol|org.pulseaudio.pavucontrol|com.saivert.pwvucontrol)$ +windowrule = tag +settings, class:^(qt5ct|qt6ct|[Yy]ad)$ +windowrule = tag +settings, class:(xdg-desktop-portal-gtk) +windowrule = tag +settings, class:^(org.kde.polkit-kde-authentication-agent-1)$ +windowrule = tag +settings, class:^([Rr]ofi)$ + +# viewer tags +windowrule = tag +viewer, class:^(gnome-system-monitor|org.gnome.SystemMonitor|io.missioncenter.MissionCenter)$ # system monitor +windowrule = tag +viewer, class:^(evince)$ # document viewer +windowrule = tag +viewer, class:^(eog|org.gnome.Loupe)$ # image viewer + +# Some special override rules +windowrule = noblur, tag:multimedia_video* +windowrule = opacity 1.0, tag:multimedia_video* + +# POSITION +# windowrule = center,floating:1 # warning, it cause even the menu to float and center. +windowrule = center, tag:KooL_Cheat* +windowrule = center, class:([Tt]hunar), title:negative:(.*[Tt]hunar.*) +windowrule = center, title:^(ROG Control)$ +windowrule = center, tag:KooL-Settings* +windowrule = center, title:^(Keybindings)$ +windowrule = center, class:^(pavucontrol|org.pulseaudio.pavucontrol|com.saivert.pwvucontrol)$ +windowrule = center, class:^([Ww]hatsapp-for-linux|ZapZap|com.rtosta.zapzap)$ +windowrule = center, class:^([Ff]erdium)$ +windowrule = move 72% 7%,title:^(Picture-in-Picture)$ +#windowrule = move 72% 7%,title:^(Firefox)$ + +# windowrule to avoid idle for fullscreen apps +#windowrule = idleinhibit fullscreen, class:^(*)$ +#windowrule = idleinhibit fullscreen, title:^(*)$ +windowrule = idleinhibit fullscreen, fullscreen:1 + +# windowrule move to workspace +#windowrule = workspace 1, tag:email* +#windowrule = workspace 2, tag:browser* +#windowrule = workspace 3, class:^([Tt]hunar)$ +#windowrule = workspace 3, tag:projects* +#windowrule = workspace 5, tag:gamestore* +#windowrule = workspace 7, tag:im* +#windowrule = workspace 8, tag:games* + +# windowrule move to workspace (silent) +#windowrule = workspace 4 silent, tag:screenshare* +#windowrule = workspace 6 silent, class:^(virt-manager)$ +#windowrule = workspace 6 silent, class:^(.virt-manager-wrapped)$ +#windowrule = workspace 9 silent, tag:multimedia* +# +# FLOAT +windowrule = float, tag:KooL_Cheat* +windowrule = float, tag:wallpaper* +windowrule = float, tag:settings* +windowrule = float, tag:viewer* +windowrule = float, tag:KooL-Settings* +windowrule = float, class:([Zz]oom|onedriver|onedriver-launcher)$ +windowrule = float, class:(org.gnome.Calculator), title:(Calculator) +windowrule = float, class:^(mpv|com.github.rafostar.Clapper)$ +windowrule = float, class:^([Qq]alculate-gtk)$ +#windowrule = float, class:^([Ww]hatsapp-for-linux|ZapZap|com.rtosta.zapzap)$ +windowrule = float, class:^([Ff]erdium)$ +windowrule = float, title:^(Picture-in-Picture)$ +#windowrule = float, title:^(Firefox)$ + +# windowrule - ######### float popups and dialogue ####### +windowrule = float, title:^(Authentication Required)$ +windowrule = center, title:^(Authentication Required)$ +windowrule = float, class:(codium|codium-url-handler|VSCodium), title:negative:(.*codium.*|.*VSCodium.*) +windowrule = float, class:^(com.heroicgameslauncher.hgl)$, title:negative:(Heroic Games Launcher) +windowrule = float, class:^([Ss]team)$, title:negative:^([Ss]team)$ +windowrule = float, class:([Tt]hunar), title:negative:(.*[Tt]hunar.*) + +windowrule = float, title:^(Add Folder to Workspace)$ +windowrule = size 70% 60%, title:^(Add Folder to Workspace)$ +windowrule = center, title:^(Add Folder to Workspace)$ + +windowrule = float, title:^(Save As)$ +windowrule = size 70% 60%, title:^(Save As)$ +windowrule = center, title:^(Save As)$ + +windowrule = float, initialTitle:(Open Files) +windowrule = size 70% 60%, initialTitle:(Open Files) + +windowrule = float, title:^(SDDM Background)$ #KooL's Dots YAD for setting SDDM background +windowrule = center, title:^(SDDM Background)$ #KooL's Dots YAD for setting SDDM background +windowrule = size 16% 12%, title:^(SDDM Background)$ #KooL's Dots YAD for setting SDDM background +# END of float popups and dialogue ####### + +# OPACITY +windowrule = opacity 0.99 0.8, tag:browser* +windowrule = opacity 0.9 0.8, tag:projects* +windowrule = opacity 0.94 0.86, tag:im* +windowrule = opacity 0.94 0.86, tag:multimedia* +windowrule = opacity 0.9 0.8, tag:file-manager* +windowrule = opacity 0.9 0.7, tag:terminal* +windowrule = opacity 0.8 0.7, tag:settings* +windowrule = opacity 0.82 0.75, tag:viewer* +windowrule = opacity 0.9 0.7, tag:wallpaper* +windowrule = opacity 0.8 0.7, class:^(gedit|org.gnome.TextEditor|mousepad)$ +windowrule = opacity 0.9 0.8, class:^(deluge)$ +windowrule = opacity 0.9 0.8, class:^(seahorse)$ # gnome-keyring gui +windowrule = opacity 0.95 0.75, title:^(Picture-in-Picture)$ +windowrule = opacity 0.9,class:^(code)$ + +# SIZE +windowrule = size 65% 90%, tag:KooL_Cheat* +windowrule = size 70% 70%, tag:wallpaper* +windowrule = size 70% 70%, tag:settings* +windowrule = size 60% 70%, class:^([Ww]hatsapp-for-linux|ZapZap|com.rtosta.zapzap)$ +windowrule = size 60% 70%, class:^([Ff]erdium)$ + +#windowrule = size 25% 25%, title:^(Picture-in-Picture)$ +#windowrule = size 25% 25%, title:^(Firefox)$ + +# PINNING +windowrule = pin, title:^(Picture-in-Picture)$ +#windowrule = pin,title:^(Firefox)$ + +# windowrule - extras +windowrule = keepaspectratio, title:^(Picture-in-Picture)$ + +# BLUR & FULLSCREEN +windowrule = noblur, tag:games* +windowrule = fullscreen, tag:games* + + +#This not gonna take the focus to the window that appears when hovering over some of the parts of the IntelliJ Products +windowrule = noinitialfocus, class:^(jetbrains-*) +windowrule = noinitialfocus, title:^(wind.*)$ + +#This will gonna make the VS Code bluer like other apps +windowrule = opacity 0.8,class:^(code)$ + +#windowrule = bordercolor rgb(EE4B55) rgb(880808), fullscreen:1 +#windowrule = bordercolor rgb(282737) rgb(1E1D2D), floating:1 +#windowrule = opacity 0.8 0.8, pinned:1 + +# LAYER RULES +layerrule = blur, rofi +layerrule = ignorezero, rofi +layerrule = blur, notifications +layerrule = ignorezero, notifications +layerrule = blur, quickshell:overview +layerrule = ignorezero, quickshell:overview +layerrule = ignorealpha 0.5, quickshell:overview + +#layerrule = ignorealpha 0.5, tag:notif* + +#layerrule = ignorezero, class:^([Rr]ofi)$ +#layerrule = blur, class:^([Rr]ofi)$ +#layerrule = unset,class:^([Rr]ofi)$ +#layerrule = ignorezero, <rofi> + +#layerrule = ignorezero, overview +#layerrule = blur, overview
\ No newline at end of file diff --git a/config/hypr/hyprland.conf b/config/hypr/hyprland.conf index 71f243e7..f509a76d 100644 --- a/config/hypr/hyprland.conf +++ b/config/hypr/hyprland.conf @@ -9,35 +9,30 @@ exec-once = $HOME/.config/hypr/initial-boot.sh # Sourcing external config files $configs = $HOME/.config/hypr/configs # Default Configs directory path - -source=$configs/Keybinds.conf # Pre-configured keybinds - # ## This is where you want to start tinkering $UserConfigs = $HOME/.config/hypr/UserConfigs # User Configs directory path -source= $UserConfigs/Startup_Apps.conf # put your start-up packages on this file +source=$configs/Keybinds.conf # Pre-configured keybinds -source= $UserConfigs/ENVariables.conf # Environment variables to load +# Load vendor defaults, then user additions/overrides +source= $configs/Startup_Apps.conf +source= $UserConfigs/Startup_Apps.conf -#source= $UserConfigs/Monitors.conf # Its all about your monitor config (old dots) will remove on push to main -#source= $UserConfigs/WorkspaceRules.conf # Hyprland workspaces (old dots) will remove on push to main +source= $UserConfigs/ENVariables.conf # Environment variables to load source= $UserConfigs/Laptops.conf # For laptop related - source= $UserConfigs/LaptopDisplay.conf # Laptop display related. You need to read the comment on this file -source= $UserConfigs/WindowRules.conf # all about Hyprland Window Rules and Layer Rules +# Load vendor defaults, then user additions +source= $configs/WindowRules.conf # all about Hyprland Window Rules and Layer Rules (defaults) +source= $UserConfigs/WindowRules.conf # Window Rules and Layer Rules user configs source= $UserConfigs/UserDecorations.conf # Decorations config file - source= $UserConfigs/UserAnimations.conf # Animation config file - source= $UserConfigs/UserKeybinds.conf # Put your own keybinds here - source= $UserConfigs/UserSettings.conf # Main Hyprland Settings. - source= $UserConfigs/01-UserDefaults.conf # settings for User defaults apps # nwg-displays source= $HOME/.config/hypr/monitors.conf -source= $HOME/.config/hypr/workspaces.conf
\ No newline at end of file +source= $HOME/.config/hypr/workspaces.conf diff --git a/config/hypr/hyprlock-1080p.conf b/config/hypr/hyprlock-1080p.conf index 14f2f35e..4251ac68 100644 --- a/config/hypr/hyprlock-1080p.conf +++ b/config/hypr/hyprlock-1080p.conf @@ -37,9 +37,9 @@ label { monitor = text = cmd[update:18000000] echo "<b> "$(date +'%A, %-d %B')" </b>" color = $color13 - font_size = 16 + font_size = 48 font_family = Victor Mono Bold Italic - position = 0, -120 + position = 0, -60 halign = center valign = center } @@ -47,42 +47,42 @@ label { # Hour-Time label { monitor = - text = cmd[update:1000] echo "$(date +"%H")" -# text = cmd[update:1000] echo "$(date +"%I")" #AM/PM +# text = cmd[update:1000] echo "$(date +"%H")" + text = cmd[update:1000] echo "$(date +"%I:%M %p")" #AM/PM #color = rgba(255, 185, 0, .8) - color = $color13 - font_size = 200 + color = $color8 + font_size = 130 font_family = JetBrainsMono Nerd Font ExtraBold - position = 0, -60 + position = 0, -250 halign = center valign = top } # Minute-Time -label { - monitor = - text = cmd[update:1000] echo "$(date +"%M")" - #color = rgba(15, 10, 222, .8) - color = $color12 - font_size = 200 - font_family = JetBrainsMono Nerd Font ExtraBold - position = 0, -340 - halign = center - valign = top -} +# label { +# monitor = +# text = cmd[update:1000] echo "$(date +"%M")" +# #color = rgba(15, 10, 222, .8) +# color = $color12 +# font_size = 150 +# font_family = JetBrainsMono Nerd Font ExtraBold +# position = 0, -340 +# halign = center + # valign = top +# } # Seconds-Time -label { - monitor = - text = cmd[update:1000] echo "$(date +"%S")" +#label { +# monitor = +## text = cmd[update:1000] echo "$(date +"%S")" # text = cmd[update:1000] echo "$(date +"%S %p")" #AM/PM - color = $color11 - font_size = 35 - font_family = JetBrainsMono Nerd Font ExtraBold - position = 0, -350 - halign = center - valign = top -} +# color = $color11 +# font_size = 32 +# font_family = JetBrainsMono Nerd Font ExtraBold +# position = 0, -350 +# halign = center +# valign = top +#} # Put a picture of choice here. Default is the current wallpaper #image { @@ -103,10 +103,10 @@ label { label { monitor = text = $USER - color = $color13 - font_size = 24 + color = $color9 + font_size = 36 font_family = Victor Mono Bold Oblique - position = 0, 220 + position = 0, 275 halign = center valign = bottom } @@ -114,12 +114,12 @@ label { # INPUT FIELD input-field { monitor = - size = 200, 60 + size = 230, 70 outline_thickness = 2 dots_size = 0.2 # Scale of input-field height, 0.2 - 0.8 dots_spacing = 0.2 # Scale of dots' absolute size, 0.0 - 1.0 dots_center = true - outer_color = $color11 + outer_color = $color8 inner_color = rgba(255, 255, 255, 0.1) capslock_color = rgb(255,255,255) font_color = $color13 @@ -136,8 +136,8 @@ input-field { label { monitor = text = $LAYOUT - color = $color13 - font_size = 10 + color = $color8 + font_size = 14 font_family = Victor Mono Bold Oblique position = 0, 70 halign = center @@ -148,8 +148,8 @@ label { label { monitor = text = cmd[update:60000] echo "<b> "$(uptime -p || $Scripts/UptimeNixOS.sh)" </b>" - color = $color13 - font_size = 16 + color = $color8 + font_size = 24 font_family = Victor Mono Bold Oblique position = 0, 0 halign = right @@ -160,7 +160,7 @@ label { label { monitor = text = cmd[update:1000] echo "<b> "$($Scripts/Battery.sh)" </b>" - color = $color13 + color = $color8 font_size = 16 font_family = Victor Mono Bold Oblique position = 0, 30 @@ -174,8 +174,8 @@ label { label { monitor = text = cmd[update:3600000] [ -f "$HOME/.cache/.weather_cache" ] && cat "$HOME/.cache/.weather_cache" - color = $color13 - font_size = 16 + color = $color8 + font_size = 14 font_family = Victor Mono Bold Oblique position = 50, 0 halign = left diff --git a/config/hypr/hyprlock.conf b/config/hypr/hyprlock.conf index b67bba51..f359357f 100644 --- a/config/hypr/hyprlock.conf +++ b/config/hypr/hyprlock.conf @@ -37,52 +37,52 @@ label { monitor = text = cmd[update:18000000] echo "<b> "$(date +'%A, %-d %B')" </b>" color = $color13 - font_size = 18 + font_size = 64 font_family = Victor Mono Bold Italic - position = 0, -120 + position = 0, -20 halign = center valign = center } -# Hour-Time +# Hour-Time (single horizontal time like 1080p variant) label { monitor = - text = cmd[update:1000] echo "$(date +"%H")" -# text = cmd[update:1000] echo "$(date +"%I")" #AM/PM +# text = cmd[update:1000] echo "$(date +"%H:%M")" # 24h option + text = cmd[update:1000] echo "$(date +"%I:%M %p")" # AM/PM #color = rgba(255, 185, 0, .8) - color = $color13 - font_size = 240 + color = $color8 + font_size = 173 font_family = JetBrainsMono Nerd Font ExtraBold - position = 0, -100 + position = 0, -133 halign = center valign = top } -# Minute-Time -label { - monitor = - text = cmd[update:1000] echo "$(date +"%M")" - #color = rgba(15, 10, 222, .8) - color = $color12 - font_size = 240 - font_family = JetBrainsMono Nerd Font ExtraBold - position = 0, -450 - halign = center - valign = top -} +# Minute-Time (disabled; kept for reference) +# label { +# monitor = +# text = cmd[update:1000] echo "$(date +"%M")" +# #color = rgba(15, 10, 222, .8) +# color = $color12 +# font_size = 240 +# font_family = JetBrainsMono Nerd Font ExtraBold +# position = 0, -450 +# halign = center +# valign = top +# } -# Seconds-Time -label { - monitor = - text = cmd[update:1000] echo "$(date +"%S")" -# text = cmd[update:1000] echo "$(date +"%S %p")" #AM/PM - color = $color11 - font_size = 50 - font_family = JetBrainsMono Nerd Font ExtraBold - position = 0, -450 - halign = center - valign = top -} +# Seconds-Time (disabled; kept for reference) +# label { +# monitor = +# text = cmd[update:1000] echo "$(date +"%S")" +# # text = cmd[update:1000] echo "$(date +"%S %p")" #AM/PM +# color = $color11 +# font_size = 50 +# font_family = JetBrainsMono Nerd Font ExtraBold +# position = 0, -450 +# halign = center +# valign = top +# } # Put a picture of choice here. Default is the current wallpaper #image { @@ -103,10 +103,10 @@ label { label { monitor = text = $USER - color = $color13 - font_size = 24 + color = $color9 + font_size = 48 font_family = Victor Mono Bold Oblique - position = 0, 280 + position = 0, 300 halign = center valign = bottom } @@ -114,33 +114,32 @@ label { # INPUT FIELD input-field { monitor = - size = 300, 60 + size = 306, 93 outline_thickness = 2 dots_size = 0.2 # Scale of input-field height, 0.2 - 0.8 dots_spacing = 0.2 # Scale of dots' absolute size, 0.0 - 1.0 dots_center = true - outer_color = $color11 + outer_color = $color8 inner_color = rgba(255, 255, 255, 0.1) + capslock_color = rgb(255,255,255) font_color = $color13 - capslock_color = rgb(255,255,255) fade_on_empty = false font_family = Victor Mono Bold Oblique placeholder_text = <i><span foreground="##ffffff99">🔒 Type Password</span></i> hide_input = false - position = 0, 120 + position = 0, 100 halign = center valign = bottom } - # Keyboard LAYOUT label { monitor = text = $LAYOUT - color = $color13 - font_size = 12 + color = $color8 + font_size = 19 font_family = Victor Mono Bold Oblique - position = 0, 80 + position = 0, 53 halign = center valign = bottom } @@ -149,8 +148,8 @@ label { label { monitor = text = cmd[update:60000] echo "<b> "$(uptime -p || $Scripts/UptimeNixOS.sh)" </b>" - color = $color13 - font_size = 18 + color = $color8 + font_size = 32 font_family = Victor Mono Bold Oblique position = 0, 0 halign = right @@ -161,10 +160,10 @@ label { label { monitor = text = cmd[update:1000] echo "<b> "$($Scripts/Battery.sh)" </b>" - color = $color13 - font_size = 18 + color = $color8 + font_size = 21 font_family = Victor Mono Bold Oblique - position = 0, 30 + position = 0, 40 halign = right valign = bottom } @@ -175,8 +174,8 @@ label { label { monitor = text = cmd[update:3600000] [ -f "$HOME/.cache/.weather_cache" ] && cat "$HOME/.cache/.weather_cache" - color = $color13 - font_size = 18 + color = $color8 + font_size = 19 font_family = Victor Mono Bold Oblique position = 50, 0 halign = left diff --git a/config/hypr/initial-boot.sh b/config/hypr/initial-boot.sh index 5b49cb6d..1313f104 100755 --- a/config/hypr/initial-boot.sh +++ b/config/hypr/initial-boot.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ # # A bash script designed to run only once dotfiles installed diff --git a/config/hypr/scripts/AirplaneMode.sh b/config/hypr/scripts/AirplaneMode.sh index 4379935d..548b9d6b 100755 --- a/config/hypr/scripts/AirplaneMode.sh +++ b/config/hypr/scripts/AirplaneMode.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # Airplane Mode. Turning on or off all wifi using rfkill. diff --git a/config/hypr/scripts/Animations.sh b/config/hypr/scripts/Animations.sh index 477e5cd3..4bbe050f 100755 --- a/config/hypr/scripts/Animations.sh +++ b/config/hypr/scripts/Animations.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # For applying Animations from different users diff --git a/config/hypr/scripts/Battery.sh b/config/hypr/scripts/Battery.sh index d7830058..2baed6ca 100644..100755 --- a/config/hypr/scripts/Battery.sh +++ b/config/hypr/scripts/Battery.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash for i in {0..3}; do if [ -f /sys/class/power_supply/BAT$i/capacity ]; then diff --git a/config/hypr/scripts/Brightness.sh b/config/hypr/scripts/Brightness.sh index 63fd02f3..ce443ef2 100755 --- a/config/hypr/scripts/Brightness.sh +++ b/config/hypr/scripts/Brightness.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # Script for Monitor backlights (if supported) using brightnessctl diff --git a/config/hypr/scripts/BrightnessKbd.sh b/config/hypr/scripts/BrightnessKbd.sh index 24737b73..93e09d86 100755 --- a/config/hypr/scripts/BrightnessKbd.sh +++ b/config/hypr/scripts/BrightnessKbd.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # Script for keyboard backlights (if supported) using brightnessctl diff --git a/config/hypr/scripts/ChangeBlur.sh b/config/hypr/scripts/ChangeBlur.sh index 895987a4..0060285b 100755 --- a/config/hypr/scripts/ChangeBlur.sh +++ b/config/hypr/scripts/ChangeBlur.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # Script for changing blurs on the fly diff --git a/config/hypr/scripts/ChangeLayout.sh b/config/hypr/scripts/ChangeLayout.sh index b083fcdc..e2436b79 100755 --- a/config/hypr/scripts/ChangeLayout.sh +++ b/config/hypr/scripts/ChangeLayout.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # for changing Hyprland Layouts (Master or Dwindle) on the fly @@ -9,20 +9,14 @@ LAYOUT=$(hyprctl -j getoption general:layout | jq '.str' | sed 's/"//g') case $LAYOUT in "master") hyprctl keyword general:layout dwindle - hyprctl keyword unbind SUPER,J - hyprctl keyword unbind SUPER,K - hyprctl keyword bind SUPER,J,cyclenext - hyprctl keyword bind SUPER,K,cyclenext,prev + # SUPER+J/K are global and managed by KeybindsLayoutInit.sh; only manage SUPER+O here hyprctl keyword bind SUPER,O,togglesplit notify-send -e -u low -i "$notif" " Dwindle Layout" ;; "dwindle") hyprctl keyword general:layout master - hyprctl keyword unbind SUPER,J - hyprctl keyword unbind SUPER,K + # Drop togglesplit binding on SUPER+O when switching back to master hyprctl keyword unbind SUPER,O - hyprctl keyword bind SUPER,J,layoutmsg,cyclenext - hyprctl keyword bind SUPER,K,layoutmsg,cycleprev notify-send -e -u low -i "$notif" " Master Layout" ;; *) ;; diff --git a/config/hypr/scripts/ClipManager.sh b/config/hypr/scripts/ClipManager.sh index 9937b6f4..3ba5d91a 100755 --- a/config/hypr/scripts/ClipManager.sh +++ b/config/hypr/scripts/ClipManager.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # Clipboard Manager. This script uses cliphist, rofi, and wl-copy. diff --git a/config/hypr/scripts/DarkLight.sh b/config/hypr/scripts/DarkLight.sh index 1bc1602f..e473efb2 100755 --- a/config/hypr/scripts/DarkLight.sh +++ b/config/hypr/scripts/DarkLight.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash ## /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # For Dark and Light switching # Note: Scripts are looking for keywords Light or Dark except for wallpapers as the are in a separate directories diff --git a/config/hypr/scripts/Distro_update.sh b/config/hypr/scripts/Distro_update.sh index b0b1446b..2b3376e3 100755 --- a/config/hypr/scripts/Distro_update.sh +++ b/config/hypr/scripts/Distro_update.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # Simple bash script to check and will try to update your system diff --git a/config/hypr/scripts/Dropterminal.sh b/config/hypr/scripts/Dropterminal.sh index 4833545c..9b2eeecb 100755 --- a/config/hypr/scripts/Dropterminal.sh +++ b/config/hypr/scripts/Dropterminal.sh @@ -1,9 +1,9 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # # Made and brought to by Kiran George # /* -- ✨ https://github.com/SherLock707 ✨ -- */ ## -# Dropdown Terminal +# Dropdown Terminal # Usage: ./Dropdown.sh [-d] <terminal_command> # Example: ./Dropdown.sh foot # ./Dropdown.sh -d foot (with debug output) @@ -15,186 +15,186 @@ SPECIAL_WS="special:scratchpad" ADDR_FILE="/tmp/dropdown_terminal_addr" # Dropdown size and position configuration (percentages) -WIDTH_PERCENT=50 # Width as percentage of screen width -HEIGHT_PERCENT=50 # Height as percentage of screen height -Y_PERCENT=5 # Y position as percentage from top (X is auto-centered) +WIDTH_PERCENT=65 # Width as percentage of screen width +HEIGHT_PERCENT=65 # Height as percentage of screen height +Y_PERCENT=10 # Y position as percentage from top (X is auto-centered) # Animation settings -ANIMATION_DURATION=100 # milliseconds +ANIMATION_DURATION=100 # milliseconds SLIDE_STEPS=5 -SLIDE_DELAY=5 # milliseconds between steps +SLIDE_DELAY=5 # milliseconds between steps # Parse arguments if [ "$1" = "-d" ]; then - DEBUG=true - shift + DEBUG=true + shift fi TERMINAL_CMD="$1" # Debug echo function debug_echo() { - if [ "$DEBUG" = true ]; then - echo "$@" - fi + if [ "$DEBUG" = true ]; then + echo "$@" + fi } # Validate input if [ -z "$TERMINAL_CMD" ]; then - echo "Missing terminal command. Usage: $0 [-d] <terminal_command>" - echo "Examples:" - echo " $0 foot" - echo " $0 -d foot (with debug output)" - echo " $0 'kitty -e zsh'" - echo " $0 'alacritty --working-directory /home/user'" - echo "" - echo "Edit the script to modify size and position:" - echo " WIDTH_PERCENT - Width as percentage of screen (default: 50)" - echo " HEIGHT_PERCENT - Height as percentage of screen (default: 50)" - echo " Y_PERCENT - Y position from top as percentage (default: 5)" - echo " Note: X position is automatically centered" - exit 1 + echo "Missing terminal command. Usage: $0 [-d] <terminal_command>" + echo "Examples:" + echo " $0 foot" + echo " $0 -d foot (with debug output)" + echo " $0 'kitty -e zsh'" + echo " $0 'alacritty --working-directory /home/user'" + echo "" + echo "Edit the script to modify size and position:" + echo " WIDTH_PERCENT - Width as percentage of screen (default: 50)" + echo " HEIGHT_PERCENT - Height as percentage of screen (default: 50)" + echo " Y_PERCENT - Y position from top as percentage (default: 5)" + echo " Note: X position is automatically centered" + exit 1 fi # Function to get window geometry get_window_geometry() { - local addr="$1" - hyprctl clients -j | jq -r --arg ADDR "$addr" '.[] | select(.address == $ADDR) | "\(.at[0]) \(.at[1]) \(.size[0]) \(.size[1])"' + local addr="$1" + hyprctl clients -j | jq -r --arg ADDR "$addr" '.[] | select(.address == $ADDR) | "\(.at[0]) \(.at[1]) \(.size[0]) \(.size[1])"' } # Function to animate window slide down (show) animate_slide_down() { - local addr="$1" - local target_x="$2" - local target_y="$3" - local width="$4" - local height="$5" - - debug_echo "Animating slide down for window $addr to position $target_x,$target_y" - - # Start position (above screen) - local start_y=$((target_y - height - 50)) - - # Calculate step size - local step_y=$(((target_y - start_y) / SLIDE_STEPS)) - - # Move window to start position instantly (off-screen) - hyprctl dispatch movewindowpixel "exact $target_x $start_y,address:$addr" >/dev/null 2>&1 - sleep 0.05 - - # Animate slide down - for i in $(seq 1 $SLIDE_STEPS); do - local current_y=$((start_y + (step_y * i))) - hyprctl dispatch movewindowpixel "exact $target_x $current_y,address:$addr" >/dev/null 2>&1 - sleep 0.03 - done - - # Ensure final position is exact - hyprctl dispatch movewindowpixel "exact $target_x $target_y,address:$addr" >/dev/null 2>&1 + local addr="$1" + local target_x="$2" + local target_y="$3" + local width="$4" + local height="$5" + + debug_echo "Animating slide down for window $addr to position $target_x,$target_y" + + # Start position (above screen) + local start_y=$((target_y - height - 50)) + + # Calculate step size + local step_y=$(((target_y - start_y) / SLIDE_STEPS)) + + # Move window to start position instantly (off-screen) + hyprctl dispatch movewindowpixel "exact $target_x $start_y,address:$addr" >/dev/null 2>&1 + sleep 0.05 + + # Animate slide down + for i in $(seq 1 $SLIDE_STEPS); do + local current_y=$((start_y + (step_y * i))) + hyprctl dispatch movewindowpixel "exact $target_x $current_y,address:$addr" >/dev/null 2>&1 + sleep 0.03 + done + + # Ensure final position is exact + hyprctl dispatch movewindowpixel "exact $target_x $target_y,address:$addr" >/dev/null 2>&1 } # Function to animate window slide up (hide) animate_slide_up() { - local addr="$1" - local start_x="$2" - local start_y="$3" - local width="$4" - local height="$5" - - debug_echo "Animating slide up for window $addr from position $start_x,$start_y" - - # End position (above screen) - local end_y=$((start_y - height - 50)) - - # Calculate step size - local step_y=$(((start_y - end_y) / SLIDE_STEPS)) - - # Animate slide up - for i in $(seq 1 $SLIDE_STEPS); do - local current_y=$((start_y - (step_y * i))) - hyprctl dispatch movewindowpixel "exact $start_x $current_y,address:$addr" >/dev/null 2>&1 - sleep 0.03 - done - - debug_echo "Slide up animation completed" + local addr="$1" + local start_x="$2" + local start_y="$3" + local width="$4" + local height="$5" + + debug_echo "Animating slide up for window $addr from position $start_x,$start_y" + + # End position (above screen) + local end_y=$((start_y - height - 50)) + + # Calculate step size + local step_y=$(((start_y - end_y) / SLIDE_STEPS)) + + # Animate slide up + for i in $(seq 1 $SLIDE_STEPS); do + local current_y=$((start_y - (step_y * i))) + hyprctl dispatch movewindowpixel "exact $start_x $current_y,address:$addr" >/dev/null 2>&1 + sleep 0.03 + done + + debug_echo "Slide up animation completed" } # Function to get monitor info including scale and name of focused monitor get_monitor_info() { - local monitor_data=$(hyprctl monitors -j | jq -r '.[] | select(.focused == true) | "\(.x) \(.y) \(.width) \(.height) \(.scale) \(.name)"') - if [ -z "$monitor_data" ] || [[ "$monitor_data" =~ ^null ]]; then - debug_echo "Error: Could not get focused monitor information" - return 1 - fi - echo "$monitor_data" + local monitor_data=$(hyprctl monitors -j | jq -r '.[] | select(.focused == true) | "\(.x) \(.y) \(.width) \(.height) \(.scale) \(.name)"') + if [ -z "$monitor_data" ] || [[ "$monitor_data" =~ ^null ]]; then + debug_echo "Error: Could not get focused monitor information" + return 1 + fi + echo "$monitor_data" } # Function to calculate dropdown position with proper scaling and centering calculate_dropdown_position() { - local monitor_info=$(get_monitor_info) - - if [ $? -ne 0 ] || [ -z "$monitor_info" ]; then - debug_echo "Error: Failed to get monitor info, using fallback values" - echo "100 100 800 600 fallback-monitor" - return 1 - fi - - local mon_x=$(echo $monitor_info | cut -d' ' -f1) - local mon_y=$(echo $monitor_info | cut -d' ' -f2) - local mon_width=$(echo $monitor_info | cut -d' ' -f3) - local mon_height=$(echo $monitor_info | cut -d' ' -f4) - local mon_scale=$(echo $monitor_info | cut -d' ' -f5) - local mon_name=$(echo $monitor_info | cut -d' ' -f6) - - debug_echo "Monitor info: x=$mon_x, y=$mon_y, width=$mon_width, height=$mon_height, scale=$mon_scale" - - # Validate scale value and provide fallback - if [ -z "$mon_scale" ] || [ "$mon_scale" = "null" ] || [ "$mon_scale" = "0" ]; then - debug_echo "Invalid scale value, using 1.0 as fallback" - mon_scale="1.0" - fi - - # Calculate logical dimensions by dividing physical dimensions by scale - local logical_width logical_height - if command -v bc >/dev/null 2>&1; then - # Use bc for precise floating point calculation - logical_width=$(echo "scale=0; $mon_width / $mon_scale" | bc | cut -d'.' -f1) - logical_height=$(echo "scale=0; $mon_height / $mon_scale" | bc | cut -d'.' -f1) - else - # Fallback to integer math (multiply by 100 for precision, then divide) - local scale_int=$(echo "$mon_scale" | sed 's/\.//' | sed 's/^0*//') - if [ -z "$scale_int" ]; then scale_int=100; fi - - logical_width=$(((mon_width * 100) / scale_int)) - logical_height=$(((mon_height * 100) / scale_int)) - fi - - # Ensure we have valid integer values - if ! [[ "$logical_width" =~ ^-?[0-9]+$ ]]; then logical_width=$mon_width; fi - if ! [[ "$logical_height" =~ ^-?[0-9]+$ ]]; then logical_height=$mon_height; fi - - debug_echo "Physical resolution: ${mon_width}x${mon_height}" - debug_echo "Logical resolution: ${logical_width}x${logical_height} (physical ÷ scale)" - - # Calculate window dimensions based on LOGICAL space percentages - local width=$((logical_width * WIDTH_PERCENT / 100)) - local height=$((logical_height * HEIGHT_PERCENT / 100)) - - # Calculate Y position from top based on percentage of LOGICAL height - local y_offset=$((logical_height * Y_PERCENT / 100)) - - # Calculate centered X position in LOGICAL space - local x_offset=$(((logical_width - width) / 2)) - - # Apply monitor offset to get final positions in logical coordinates - local final_x=$((mon_x + x_offset)) - local final_y=$((mon_y + y_offset)) - - debug_echo "Window size: ${width}x${height} (logical pixels)" - debug_echo "Final position: x=$final_x, y=$final_y (logical coordinates)" - debug_echo "Hyprland will scale these to physical coordinates automatically" - - echo "$final_x $final_y $width $height $mon_name" + local monitor_info=$(get_monitor_info) + + if [ $? -ne 0 ] || [ -z "$monitor_info" ]; then + debug_echo "Error: Failed to get monitor info, using fallback values" + echo "100 100 800 600 fallback-monitor" + return 1 + fi + + local mon_x=$(echo $monitor_info | cut -d' ' -f1) + local mon_y=$(echo $monitor_info | cut -d' ' -f2) + local mon_width=$(echo $monitor_info | cut -d' ' -f3) + local mon_height=$(echo $monitor_info | cut -d' ' -f4) + local mon_scale=$(echo $monitor_info | cut -d' ' -f5) + local mon_name=$(echo $monitor_info | cut -d' ' -f6) + + debug_echo "Monitor info: x=$mon_x, y=$mon_y, width=$mon_width, height=$mon_height, scale=$mon_scale" + + # Validate scale value and provide fallback + if [ -z "$mon_scale" ] || [ "$mon_scale" = "null" ] || [ "$mon_scale" = "0" ]; then + debug_echo "Invalid scale value, using 1.0 as fallback" + mon_scale="1.0" + fi + + # Calculate logical dimensions by dividing physical dimensions by scale + local logical_width logical_height + if command -v bc >/dev/null 2>&1; then + # Use bc for precise floating point calculation + logical_width=$(echo "scale=0; $mon_width / $mon_scale" | bc | cut -d'.' -f1) + logical_height=$(echo "scale=0; $mon_height / $mon_scale" | bc | cut -d'.' -f1) + else + # Fallback to integer math (multiply by 100 for precision, then divide) + local scale_int=$(echo "$mon_scale" | sed 's/\.//' | sed 's/^0*//') + if [ -z "$scale_int" ]; then scale_int=100; fi + + logical_width=$(((mon_width * 100) / scale_int)) + logical_height=$(((mon_height * 100) / scale_int)) + fi + + # Ensure we have valid integer values + if ! [[ "$logical_width" =~ ^-?[0-9]+$ ]]; then logical_width=$mon_width; fi + if ! [[ "$logical_height" =~ ^-?[0-9]+$ ]]; then logical_height=$mon_height; fi + + debug_echo "Physical resolution: ${mon_width}x${mon_height}" + debug_echo "Logical resolution: ${logical_width}x${logical_height} (physical ÷ scale)" + + # Calculate window dimensions based on LOGICAL space percentages + local width=$((logical_width * WIDTH_PERCENT / 100)) + local height=$((logical_height * HEIGHT_PERCENT / 100)) + + # Calculate Y position from top based on percentage of LOGICAL height + local y_offset=$((logical_height * Y_PERCENT / 100)) + + # Calculate centered X position in LOGICAL space + local x_offset=$(((logical_width - width) / 2)) + + # Apply monitor offset to get final positions in logical coordinates + local final_x=$((mon_x + x_offset)) + local final_y=$((mon_y + y_offset)) + + debug_echo "Window size: ${width}x${height} (logical pixels)" + debug_echo "Final position: x=$final_x, y=$final_y (logical coordinates)" + debug_echo "Hyprland will scale these to physical coordinates automatically" + + echo "$final_x $final_y $width $height $mon_name" } # Get the current workspace @@ -202,179 +202,179 @@ CURRENT_WS=$(hyprctl activeworkspace -j | jq -r '.id') # Function to get stored terminal address get_terminal_address() { - if [ -f "$ADDR_FILE" ] && [ -s "$ADDR_FILE" ]; then - cut -d' ' -f1 "$ADDR_FILE" - fi + if [ -f "$ADDR_FILE" ] && [ -s "$ADDR_FILE" ]; then + cut -d' ' -f1 "$ADDR_FILE" + fi } # Function to get stored monitor name get_terminal_monitor() { - if [ -f "$ADDR_FILE" ] && [ -s "$ADDR_FILE" ]; then - cut -d' ' -f2- "$ADDR_FILE" - fi + if [ -f "$ADDR_FILE" ] && [ -s "$ADDR_FILE" ]; then + cut -d' ' -f2- "$ADDR_FILE" + fi } # Function to check if terminal exists terminal_exists() { - local addr=$(get_terminal_address) - if [ -n "$addr" ]; then - hyprctl clients -j | jq -e --arg ADDR "$addr" 'any(.[]; .address == $ADDR)' >/dev/null 2>&1 - else - return 1 - fi + local addr=$(get_terminal_address) + if [ -n "$addr" ]; then + hyprctl clients -j | jq -e --arg ADDR "$addr" 'any(.[]; .address == $ADDR)' >/dev/null 2>&1 + else + return 1 + fi } # Function to check if terminal is in special workspace terminal_in_special() { - local addr=$(get_terminal_address) - if [ -n "$addr" ]; then - hyprctl clients -j | jq -e --arg ADDR "$addr" 'any(.[]; .address == $ADDR and .workspace.name == "special:scratchpad")' >/dev/null 2>&1 - else - return 1 - fi + local addr=$(get_terminal_address) + if [ -n "$addr" ]; then + hyprctl clients -j | jq -e --arg ADDR "$addr" 'any(.[]; .address == $ADDR and .workspace.name == "special:scratchpad")' >/dev/null 2>&1 + else + return 1 + fi } # Function to spawn terminal and capture its address spawn_terminal() { - debug_echo "Creating new dropdown terminal with command: $TERMINAL_CMD" - - # Calculate dropdown position for later use - local pos_info=$(calculate_dropdown_position) - if [ $? -ne 0 ]; then - debug_echo "Warning: Using fallback positioning" - fi - - local target_x=$(echo $pos_info | cut -d' ' -f1) - local target_y=$(echo $pos_info | cut -d' ' -f2) - local width=$(echo $pos_info | cut -d' ' -f3) - local height=$(echo $pos_info | cut -d' ' -f4) - local monitor_name=$(echo $pos_info | cut -d' ' -f5) - - debug_echo "Target position: ${target_x},${target_y}, size: ${width}x${height}" - - # Get window count before spawning - local windows_before=$(hyprctl clients -j) - local count_before=$(echo "$windows_before" | jq 'length') - - # Launch terminal directly in special workspace to avoid visible spawn - hyprctl dispatch exec "[float; size $width $height; workspace special:scratchpad silent] $TERMINAL_CMD" - - # Wait for window to appear - sleep 0.1 - - # Get windows after spawning - local windows_after=$(hyprctl clients -j) - local count_after=$(echo "$windows_after" | jq 'length') - - local new_addr="" - - if [ "$count_after" -gt "$count_before" ]; then - # Find the new window by comparing before/after lists - new_addr=$(comm -13 \ - <(echo "$windows_before" | jq -r '.[].address' | sort) \ - <(echo "$windows_after" | jq -r '.[].address' | sort) \ - | head -1) - fi - - # Fallback: try to find by the most recently mapped window - if [ -z "$new_addr" ] || [ "$new_addr" = "null" ]; then - new_addr=$(hyprctl clients -j | jq -r 'sort_by(.focusHistoryID) | .[-1] | .address') - fi - - if [ -n "$new_addr" ] && [ "$new_addr" != "null" ]; then - # Store the address and monitor name - echo "$new_addr $monitor_name" > "$ADDR_FILE" - debug_echo "Terminal created with address: $new_addr in special workspace on monitor $monitor_name" - - # Small delay to ensure it's properly in special workspace - sleep 0.2 - - # Now bring it back with the same animation as subsequent shows - # Use movetoworkspacesilent to avoid affecting workspace history - hyprctl dispatch movetoworkspacesilent "$CURRENT_WS,address:$new_addr" - hyprctl dispatch pin "address:$new_addr" - animate_slide_down "$new_addr" "$target_x" "$target_y" "$width" "$height" - - return 0 - fi - - debug_echo "Failed to get terminal address" - return 1 + debug_echo "Creating new dropdown terminal with command: $TERMINAL_CMD" + + # Calculate dropdown position for later use + local pos_info=$(calculate_dropdown_position) + if [ $? -ne 0 ]; then + debug_echo "Warning: Using fallback positioning" + fi + + local target_x=$(echo $pos_info | cut -d' ' -f1) + local target_y=$(echo $pos_info | cut -d' ' -f2) + local width=$(echo $pos_info | cut -d' ' -f3) + local height=$(echo $pos_info | cut -d' ' -f4) + local monitor_name=$(echo $pos_info | cut -d' ' -f5) + + debug_echo "Target position: ${target_x},${target_y}, size: ${width}x${height}" + + # Get window count before spawning + local windows_before=$(hyprctl clients -j) + local count_before=$(echo "$windows_before" | jq 'length') + + # Launch terminal directly in special workspace to avoid visible spawn + hyprctl dispatch exec "[float; size $width $height; workspace special:scratchpad silent] $TERMINAL_CMD" + + # Wait for window to appear + sleep 0.1 + + # Get windows after spawning + local windows_after=$(hyprctl clients -j) + local count_after=$(echo "$windows_after" | jq 'length') + + local new_addr="" + + if [ "$count_after" -gt "$count_before" ]; then + # Find the new window by comparing before/after lists + new_addr=$(comm -13 \ + <(echo "$windows_before" | jq -r '.[].address' | sort) \ + <(echo "$windows_after" | jq -r '.[].address' | sort) | + head -1) + fi + + # Fallback: try to find by the most recently mapped window + if [ -z "$new_addr" ] || [ "$new_addr" = "null" ]; then + new_addr=$(hyprctl clients -j | jq -r 'sort_by(.focusHistoryID) | .[-1] | .address') + fi + + if [ -n "$new_addr" ] && [ "$new_addr" != "null" ]; then + # Store the address and monitor name + echo "$new_addr $monitor_name" >"$ADDR_FILE" + debug_echo "Terminal created with address: $new_addr in special workspace on monitor $monitor_name" + + # Small delay to ensure it's properly in special workspace + sleep 0.2 + + # Now bring it back with the same animation as subsequent shows + # Use movetoworkspacesilent to avoid affecting workspace history + hyprctl dispatch movetoworkspacesilent "$CURRENT_WS,address:$new_addr" + hyprctl dispatch pin "address:$new_addr" + animate_slide_down "$new_addr" "$target_x" "$target_y" "$width" "$height" + + return 0 + fi + + debug_echo "Failed to get terminal address" + return 1 } # Main logic if terminal_exists; then - TERMINAL_ADDR=$(get_terminal_address) - debug_echo "Found existing terminal: $TERMINAL_ADDR" - focused_monitor=$(get_monitor_info | awk '{print $6}') - dropdown_monitor=$(get_terminal_monitor) - if [ "$focused_monitor" != "$dropdown_monitor" ]; then - debug_echo "Monitor focus changed: moving dropdown to $focused_monitor" - # Calculate new position for focused monitor - pos_info=$(calculate_dropdown_position) - target_x=$(echo $pos_info | cut -d' ' -f1) - target_y=$(echo $pos_info | cut -d' ' -f2) - width=$(echo $pos_info | cut -d' ' -f3) - height=$(echo $pos_info | cut -d' ' -f4) - monitor_name=$(echo $pos_info | cut -d' ' -f5) - # Move and resize window - hyprctl dispatch movewindowpixel "exact $target_x $target_y,address:$TERMINAL_ADDR" - hyprctl dispatch resizewindowpixel "exact $width $height,address:$TERMINAL_ADDR" - # Update ADDR_FILE - echo "$TERMINAL_ADDR $monitor_name" > "$ADDR_FILE" - fi + TERMINAL_ADDR=$(get_terminal_address) + debug_echo "Found existing terminal: $TERMINAL_ADDR" + focused_monitor=$(get_monitor_info | awk '{print $6}') + dropdown_monitor=$(get_terminal_monitor) + if [ "$focused_monitor" != "$dropdown_monitor" ]; then + debug_echo "Monitor focus changed: moving dropdown to $focused_monitor" + # Calculate new position for focused monitor + pos_info=$(calculate_dropdown_position) + target_x=$(echo $pos_info | cut -d' ' -f1) + target_y=$(echo $pos_info | cut -d' ' -f2) + width=$(echo $pos_info | cut -d' ' -f3) + height=$(echo $pos_info | cut -d' ' -f4) + monitor_name=$(echo $pos_info | cut -d' ' -f5) + # Move and resize window + hyprctl dispatch movewindowpixel "exact $target_x $target_y,address:$TERMINAL_ADDR" + hyprctl dispatch resizewindowpixel "exact $width $height,address:$TERMINAL_ADDR" + # Update ADDR_FILE + echo "$TERMINAL_ADDR $monitor_name" >"$ADDR_FILE" + fi - if terminal_in_special; then - debug_echo "Bringing terminal from scratchpad with slide down animation" - - # Calculate target position - pos_info=$(calculate_dropdown_position) - target_x=$(echo $pos_info | cut -d' ' -f1) - target_y=$(echo $pos_info | cut -d' ' -f2) - width=$(echo $pos_info | cut -d' ' -f3) - height=$(echo $pos_info | cut -d' ' -f4) - - # Use movetoworkspacesilent to avoid affecting workspace history - hyprctl dispatch movetoworkspacesilent "$CURRENT_WS,address:$TERMINAL_ADDR" - hyprctl dispatch pin "address:$TERMINAL_ADDR" - - # Set size and animate slide down - hyprctl dispatch resizewindowpixel "exact $width $height,address:$TERMINAL_ADDR" - animate_slide_down "$TERMINAL_ADDR" "$target_x" "$target_y" "$width" "$height" - - hyprctl dispatch focuswindow "address:$TERMINAL_ADDR" + if terminal_in_special; then + debug_echo "Bringing terminal from scratchpad with slide down animation" + + # Calculate target position + pos_info=$(calculate_dropdown_position) + target_x=$(echo $pos_info | cut -d' ' -f1) + target_y=$(echo $pos_info | cut -d' ' -f2) + width=$(echo $pos_info | cut -d' ' -f3) + height=$(echo $pos_info | cut -d' ' -f4) + + # Use movetoworkspacesilent to avoid affecting workspace history + hyprctl dispatch movetoworkspacesilent "$CURRENT_WS,address:$TERMINAL_ADDR" + hyprctl dispatch pin "address:$TERMINAL_ADDR" + + # Set size and animate slide down + hyprctl dispatch resizewindowpixel "exact $width $height,address:$TERMINAL_ADDR" + animate_slide_down "$TERMINAL_ADDR" "$target_x" "$target_y" "$width" "$height" + + hyprctl dispatch focuswindow "address:$TERMINAL_ADDR" + else + debug_echo "Hiding terminal to scratchpad with slide up animation" + + # Get current geometry for animation + geometry=$(get_window_geometry "$TERMINAL_ADDR") + if [ -n "$geometry" ]; then + curr_x=$(echo $geometry | cut -d' ' -f1) + curr_y=$(echo $geometry | cut -d' ' -f2) + curr_width=$(echo $geometry | cut -d' ' -f3) + curr_height=$(echo $geometry | cut -d' ' -f4) + + debug_echo "Current geometry: ${curr_x},${curr_y} ${curr_width}x${curr_height}" + + # Animate slide up first + animate_slide_up "$TERMINAL_ADDR" "$curr_x" "$curr_y" "$curr_width" "$curr_height" + + # Small delay then move to special workspace and unpin + sleep 0.1 + hyprctl dispatch pin "address:$TERMINAL_ADDR" # Unpin (toggle) + hyprctl dispatch movetoworkspacesilent "$SPECIAL_WS,address:$TERMINAL_ADDR" else - debug_echo "Hiding terminal to scratchpad with slide up animation" - - # Get current geometry for animation - geometry=$(get_window_geometry "$TERMINAL_ADDR") - if [ -n "$geometry" ]; then - curr_x=$(echo $geometry | cut -d' ' -f1) - curr_y=$(echo $geometry | cut -d' ' -f2) - curr_width=$(echo $geometry | cut -d' ' -f3) - curr_height=$(echo $geometry | cut -d' ' -f4) - - debug_echo "Current geometry: ${curr_x},${curr_y} ${curr_width}x${curr_height}" - - # Animate slide up first - animate_slide_up "$TERMINAL_ADDR" "$curr_x" "$curr_y" "$curr_width" "$curr_height" - - # Small delay then move to special workspace and unpin - sleep 0.1 - hyprctl dispatch pin "address:$TERMINAL_ADDR" # Unpin (toggle) - hyprctl dispatch movetoworkspacesilent "$SPECIAL_WS,address:$TERMINAL_ADDR" - else - debug_echo "Could not get window geometry, moving to scratchpad without animation" - hyprctl dispatch pin "address:$TERMINAL_ADDR" - hyprctl dispatch movetoworkspacesilent "$SPECIAL_WS,address:$TERMINAL_ADDR" - fi + debug_echo "Could not get window geometry, moving to scratchpad without animation" + hyprctl dispatch pin "address:$TERMINAL_ADDR" + hyprctl dispatch movetoworkspacesilent "$SPECIAL_WS,address:$TERMINAL_ADDR" fi + fi else - debug_echo "No existing terminal found, creating new one" - if spawn_terminal; then - TERMINAL_ADDR=$(get_terminal_address) - if [ -n "$TERMINAL_ADDR" ]; then - hyprctl dispatch focuswindow "address:$TERMINAL_ADDR" - fi + debug_echo "No existing terminal found, creating new one" + if spawn_terminal; then + TERMINAL_ADDR=$(get_terminal_address) + if [ -n "$TERMINAL_ADDR" ]; then + hyprctl dispatch focuswindow "address:$TERMINAL_ADDR" fi + fi fi diff --git a/config/hypr/scripts/GameMode.sh b/config/hypr/scripts/GameMode.sh index 7a39da3d..59cf7372 100755 --- a/config/hypr/scripts/GameMode.sh +++ b/config/hypr/scripts/GameMode.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # Game Mode. Turning off all animations @@ -20,6 +20,7 @@ if [ "$HYPRGAMEMODE" = 1 ] ; then hyprctl keyword "windowrule opacity 1 override 1 override 1 override, ^(.*)$" swww kill notify-send -e -u low -i "$notif" " Gamemode:" " enabled" + sleep 0.1 exit else swww-daemon --format xrgb && swww img "$HOME/.config/rofi/.current_wallpaper" & diff --git a/config/hypr/scripts/Hypridle.sh b/config/hypr/scripts/Hypridle.sh index 56176716..6acff434 100755 --- a/config/hypr/scripts/Hypridle.sh +++ b/config/hypr/scripts/Hypridle.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # This is for custom version of waybar idle_inhibitor which activates / deactivates hypridle instead diff --git a/config/hypr/scripts/Hyprsunset.sh b/config/hypr/scripts/Hyprsunset.sh index c7c4b395..4a2b52f4 100755 --- a/config/hypr/scripts/Hyprsunset.sh +++ b/config/hypr/scripts/Hyprsunset.sh @@ -8,12 +8,12 @@ set -euo pipefail # - On: sunset icon if available, otherwise a blue sun # # Customize via env vars: -# HYPERSUNSET_TEMP default 4500 (K) -# HYPERSUNSET_ICON_MODE sunset|blue (default: sunset) +# HYPRSUNSET_TEMP default 4500 (K) +# HYPRSUNSET_ICON_MODE sunset|blue (default: sunset) STATE_FILE="$HOME/.cache/.hyprsunset_state" -TARGET_TEMP="${HYPERSUNSET_TEMP:-4500}" -ICON_MODE="${HYPERSUNSET_ICON_MODE:-sunset}" +TARGET_TEMP="${HYPRSUNSET_TEMP:-4500}" +ICON_MODE="${HYPRSUNSET_ICON_MODE:-sunset}" ensure_state() { [[ -f "$STATE_FILE" ]] || echo "off" > "$STATE_FILE" @@ -92,8 +92,20 @@ cmd_status() { printf '{"text":"%s","class":"%s","tooltip":"%s"}\n' "$txt" "$cls" "$tip" } +cmd_init() { + ensure_state + state="$(cat "$STATE_FILE" || echo off)" + + if [[ "$state" == "on" ]]; then + if command -v hyprsunset >/dev/null 2>&1; then + nohup hyprsunset -t "$TARGET_TEMP" >/dev/null 2>&1 & + fi + fi +} + case "${1:-}" in toggle) cmd_toggle ;; status) cmd_status ;; - *) echo "usage: $0 [toggle|status]" >&2; exit 2 ;; + init) cmd_init ;; + *) echo "usage: $0 [toggle|status|init]" >&2; exit 2 ;; esac diff --git a/config/hypr/scripts/KeyBinds.sh b/config/hypr/scripts/KeyBinds.sh index 9c6b5ab7..46953cc5 100755 --- a/config/hypr/scripts/KeyBinds.sh +++ b/config/hypr/scripts/KeyBinds.sh @@ -1,6 +1,6 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## -# searchable enabled keybinds using rofi +# searchable enabled keybinds using rofi (supports bindd descriptions) # kill yad to not interfere with this binds pkill yad || true @@ -17,23 +17,66 @@ laptop_conf="$HOME/.config/hypr/UserConfigs/Laptops.conf" rofi_theme="$HOME/.config/rofi/config-keybinds.rasi" msg='☣️ NOTE ☣️: Clicking with Mouse or Pressing ENTER will have NO function' -# combine the contents of the keybinds files and filter for keybinds -keybinds=$(cat "$keybinds_conf" "$user_keybinds_conf" | grep -E '^bind') +# collect raw bind lines (strip end-of-line comments) from available files +files=("$keybinds_conf" "$user_keybinds_conf") +[[ -f "$laptop_conf" ]] && files+=("$laptop_conf") -# check if laptop.conf exists and add its keybinds if present -if [[ -f "$laptop_conf" ]]; then - laptop_binds=$(grep -E '^bind' "$laptop_conf") - keybinds+=$'\n'"$laptop_binds" -fi +raw_keybinds=$(cat "${files[@]}" 2>/dev/null \ + | grep -E '^[[:space:]]*bind' \ + | sed -E 's/[[:space:]]+#.*$//') # check for any keybinds to display -if [[ -z "$keybinds" ]]; then +if [[ -z "$raw_keybinds" ]]; then echo "no keybinds found." exit 1 fi -# replace $mainmod with super in the displayed keybinds for rofi -display_keybinds=$(echo "$keybinds" | sed 's/\$mainMod/SUPER/g') +# transform into a readable list: MODS+KEY — DESCRIPTION — DISPATCHER [PARAMS] +display_keybinds=$(echo "$raw_keybinds" | awk -F'=' ' + function trim(s){ gsub(/^[ \t]+|[ \t]+$/,"",s); return s } + /^[[:space:]]*bind/ { + binder=$1; gsub(/[ \t]/, "", binder); + hasdesc = (index(binder, "d")>0); + + rhs=$2; rhs=trim(rhs); + n=split(rhs, a, /[ \t]*,[ \t]*/); + + mods=trim(a[1]); key=(n>=2?trim(a[2]):""); + desc=""; dispatcher=""; params=""; + + if (hasdesc) { + desc=(n>=3?trim(a[3]):""); + dispatcher=(n>=4?trim(a[4]):""); + start=5; + } else { + dispatcher=(n>=3?trim(a[3]):""); + start=4; + } + + for(i=start;i<=n;i++){ if(length(a[i])){ p=trim(a[i]); if(p!="") params = (params?params", ":"") p } } + + gsub(/\$mainMod/,"SUPER",mods); + gsub(/[ \t]+/,"+",mods); + + combo = (mods && key) ? mods "+" key : (key?key:mods); + + if (desc != "") { + if (dispatcher != "" && params != "") + print combo, " — ", desc, " — ", dispatcher, " ", params; + else if (dispatcher != "") + print combo, " — ", desc, " — ", dispatcher; + else + print combo, " — ", desc; + } else { + if (dispatcher != "" && params != "") + print combo, " — ", dispatcher, " ", params; + else if (dispatcher != "") + print combo, " — ", dispatcher; + else + print combo; + } + } +') -# use rofi to display the keybinds with the modified content -echo "$display_keybinds" | rofi -dmenu -i -config "$rofi_theme" -mesg "$msg"
\ No newline at end of file +# use rofi to display the keybinds +printf '%s\n' "$display_keybinds" | rofi -dmenu -i -config "$rofi_theme" -mesg "$msg" diff --git a/config/hypr/scripts/KeyHints.sh b/config/hypr/scripts/KeyHints.sh index 7917ae3a..8a478039 100755 --- a/config/hypr/scripts/KeyHints.sh +++ b/config/hypr/scripts/KeyHints.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # GDK BACKEND. Change to either wayland or x11 if having issues diff --git a/config/hypr/scripts/KeybindsLayoutInit.sh b/config/hypr/scripts/KeybindsLayoutInit.sh new file mode 100755 index 00000000..0a53eaaf --- /dev/null +++ b/config/hypr/scripts/KeybindsLayoutInit.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +# /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## +# Initialize J/K keybinds so they always cycle windows globally (no layout-specific behavior) +# This avoids double-actions when layouts change. + +set -euo pipefail + +# Always reset and bind SUPER+J/K the same way on startup +hyprctl keyword unbind SUPER,J || true +hyprctl keyword unbind SUPER,K || true + +# Cycle windows globally: J = next, K = previous +hyprctl keyword bind SUPER,J,cyclenext +hyprctl keyword bind SUPER,K,cyclenext,prev diff --git a/config/hypr/scripts/KillActiveProcess.sh b/config/hypr/scripts/KillActiveProcess.sh index bee146d7..2bc108f2 100755 --- a/config/hypr/scripts/KillActiveProcess.sh +++ b/config/hypr/scripts/KillActiveProcess.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # Copied from Discord post. Thanks to @Zorg diff --git a/config/hypr/scripts/Kitty_themes.sh b/config/hypr/scripts/Kitty_themes.sh index 48bfa99f..55da7e44 100755 --- a/config/hypr/scripts/Kitty_themes.sh +++ b/config/hypr/scripts/Kitty_themes.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ # # Kitty Themes Source https://github.com/dexpota/kitty-themes # diff --git a/config/hypr/scripts/KooLsDotsUpdate.sh b/config/hypr/scripts/KooLsDotsUpdate.sh index f4b8814a..51277ab1 100755 --- a/config/hypr/scripts/KooLsDotsUpdate.sh +++ b/config/hypr/scripts/KooLsDotsUpdate.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # simple bash script to check if update is available by comparing local version and github version diff --git a/config/hypr/scripts/Kool_Quick_Settings.sh b/config/hypr/scripts/Kool_Quick_Settings.sh index e43749bf..16742492 100755 --- a/config/hypr/scripts/Kool_Quick_Settings.sh +++ b/config/hypr/scripts/Kool_Quick_Settings.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # Rofi menu for KooL Hyprland Quick Settings (SUPER SHIFT E) @@ -55,10 +55,10 @@ main() { case "$choice" in "view/edit User Defaults") file="$UserConfigs/01-UserDefaults.conf" ;; "view/edit ENV variables") file="$UserConfigs/ENVariables.conf" ;; - "view/edit Window Rules") file="$UserConfigs/WindowRules.conf" ;; + "view/edit Window Rules") file="$configs/WindowRules.conf" ;; "view/edit User Keybinds") file="$UserConfigs/UserKeybinds.conf" ;; "view/edit User Settings") file="$UserConfigs/UserSettings.conf" ;; - "view/edit Startup Apps") file="$UserConfigs/Startup_Apps.conf" ;; + "view/edit Startup Apps") file="$configs/Startup_Apps.conf" ;; "view/edit Decorations") file="$UserConfigs/UserDecorations.conf" ;; "view/edit Animations") file="$UserConfigs/UserAnimations.conf" ;; "view/edit Laptop Keybinds") file="$UserConfigs/Laptops.conf" ;; diff --git a/config/hypr/scripts/LockScreen.sh b/config/hypr/scripts/LockScreen.sh index 5e799181..d58f5c21 100755 --- a/config/hypr/scripts/LockScreen.sh +++ b/config/hypr/scripts/LockScreen.sh @@ -1,7 +1,11 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # For Hyprlock -#pidof hyprlock || hyprlock -q +#pidof hyprlock || hyprlock -q + +# Ensure weather cache is up-to-date before locking (Waybar/lockscreen readers) +bash "$HOME/.config/hypr/UserScripts/WeatherWrap.sh" >/dev/null 2>&1 + +loginctl lock-session -loginctl lock-session
\ No newline at end of file diff --git a/config/hypr/scripts/MediaCtrl.sh b/config/hypr/scripts/MediaCtrl.sh index 000c3ade..9dc3571d 100755 --- a/config/hypr/scripts/MediaCtrl.sh +++ b/config/hypr/scripts/MediaCtrl.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # Playerctl diff --git a/config/hypr/scripts/MonitorProfiles.sh b/config/hypr/scripts/MonitorProfiles.sh index 67316c09..1176a46a 100755 --- a/config/hypr/scripts/MonitorProfiles.sh +++ b/config/hypr/scripts/MonitorProfiles.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # For applying Pre-configured Monitor Profiles diff --git a/config/hypr/scripts/OverviewToggle.sh b/config/hypr/scripts/OverviewToggle.sh new file mode 100755 index 00000000..2737234c --- /dev/null +++ b/config/hypr/scripts/OverviewToggle.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ # +# Overview toggle wrapper - tries Quickshell first, falls back to AGS + +set -euo pipefail + +# 1) Try Quickshell via Hyprland global dispatch (works if QS is running and listening) +# Only attempt this if a Quickshell process is running; otherwise Hyprland will +# still return success for the dispatch and we'll never fall back to AGS. +if pgrep -x quickshell >/dev/null 2>&1; then + if hyprctl dispatch global quickshell:overviewToggle >/dev/null 2>&1; then + exit 0 + fi +fi + +# If QS isn't running, but the CLI exists, try starting it and retry once +if command -v qs >/dev/null 2>&1; then + qs >/dev/null 2>&1 & + sleep 0.6 + if hyprctl dispatch global quickshell:overviewToggle >/dev/null 2>&1; then + exit 0 + fi +fi + +# 2) Fall back to AGS template +if command -v ags >/dev/null 2>&1; then + pkill rofi || true + if ags -t 'overview' >/dev/null 2>&1; then + exit 0 + fi + # If it failed, try starting AGS daemon then call the template + ags >/dev/null 2>&1 & + sleep 0.6 + if ags -t 'overview' >/dev/null 2>&1; then + exit 0 + fi +fi + +# If we get here, neither worked +notify-send "Overview" "Neither Quickshell nor AGS is available" -u low 2>/dev/null || true +exit 1 diff --git a/config/hypr/scripts/Polkit-NixOS.sh b/config/hypr/scripts/Polkit-NixOS.sh index 51675eff..28642d19 100755 --- a/config/hypr/scripts/Polkit-NixOS.sh +++ b/config/hypr/scripts/Polkit-NixOS.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # For NixOS starting of polkit-gnome. Dec 2023, the settings stated in NixOS wiki does not work so have to manual start it diff --git a/config/hypr/scripts/Polkit.sh b/config/hypr/scripts/Polkit.sh index dcea7653..1af8fd1b 100755 --- a/config/hypr/scripts/Polkit.sh +++ b/config/hypr/scripts/Polkit.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # This script starts the first available Polkit agent from a list of possible locations diff --git a/config/hypr/scripts/PortalHyprland.sh b/config/hypr/scripts/PortalHyprland.sh index 9bdf4b8c..21cb7db4 100755 --- a/config/hypr/scripts/PortalHyprland.sh +++ b/config/hypr/scripts/PortalHyprland.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # For manually starting xdg-desktop-portal-hyprland diff --git a/config/hypr/scripts/Refresh.sh b/config/hypr/scripts/Refresh.sh index 719c368d..76757aa4 100755 --- a/config/hypr/scripts/Refresh.sh +++ b/config/hypr/scripts/Refresh.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # Scripts for refreshing ags, waybar, rofi, swaync, wallust @@ -7,23 +7,25 @@ UserScripts=$HOME/.config/hypr/UserScripts # Define file_exists function file_exists() { - if [ -e "$1" ]; then - return 0 # File exists - else - return 1 # File does not exist - fi + if [ -e "$1" ]; then + return 0 # File exists + else + return 1 # File does not exist + fi } # Kill already running processes _ps=(waybar rofi swaync ags) for _prs in "${_ps[@]}"; do - if pidof "${_prs}" >/dev/null; then - pkill "${_prs}" - fi + if pidof "${_prs}" >/dev/null; then + pkill "${_prs}" + fi done # added since wallust sometimes not applying -killall -SIGUSR2 waybar +killall -SIGUSR2 waybar +# Added sleep for GameMode causing multiple waybar +sleep 0.1 # quit ags & relaunch ags #ags -q && ags & @@ -33,23 +35,24 @@ killall -SIGUSR2 waybar # some process to kill for pid in $(pidof waybar rofi swaync ags swaybg); do - kill -SIGUSR1 "$pid" + kill -SIGUSR1 "$pid" + sleep 0.1 done #Restart waybar -sleep 1 +sleep 0.1 waybar & # relaunch swaync -sleep 0.5 -swaync > /dev/null 2>&1 & +sleep 0.3 +swaync >/dev/null 2>&1 & # reload swaync swaync-client --reload-config # Relaunching rainbow borders if the script exists sleep 1 if file_exists "${UserScripts}/RainbowBorders.sh"; then - ${UserScripts}/RainbowBorders.sh & + ${UserScripts}/RainbowBorders.sh & fi -exit 0
\ No newline at end of file +exit 0 diff --git a/config/hypr/scripts/RefreshNoWaybar.sh b/config/hypr/scripts/RefreshNoWaybar.sh index 8454124e..54c760bd 100755 --- a/config/hypr/scripts/RefreshNoWaybar.sh +++ b/config/hypr/scripts/RefreshNoWaybar.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # Modified version of Refresh.sh but waybar wont refresh diff --git a/config/hypr/scripts/RofiEmoji.sh b/config/hypr/scripts/RofiEmoji.sh index 4570831e..7e3ef0f3 100755 --- a/config/hypr/scripts/RofiEmoji.sh +++ b/config/hypr/scripts/RofiEmoji.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # Variables diff --git a/config/hypr/scripts/RofiSearch.sh b/config/hypr/scripts/RofiSearch.sh index 4218bed3..8ef12c46 100755 --- a/config/hypr/scripts/RofiSearch.sh +++ b/config/hypr/scripts/RofiSearch.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # For Searching via web browsers diff --git a/config/hypr/scripts/RofiThemeSelector-modified.sh b/config/hypr/scripts/RofiThemeSelector-modified.sh index 2cfc2d24..d6a353c0 100755 --- a/config/hypr/scripts/RofiThemeSelector-modified.sh +++ b/config/hypr/scripts/RofiThemeSelector-modified.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # A modified version of Rofi-Theme-Selector, concentrating only on ~/.local and also, applying only 10 @themes in ~/.config/rofi/config.rasi # as opposed to continous adding of //@theme diff --git a/config/hypr/scripts/RofiThemeSelector.sh b/config/hypr/scripts/RofiThemeSelector.sh index 8b2fcb71..b7236e8f 100755 --- a/config/hypr/scripts/RofiThemeSelector.sh +++ b/config/hypr/scripts/RofiThemeSelector.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ # # Rofi Themes - Script to preview and apply themes by live-reloading the config. diff --git a/config/hypr/scripts/ScreenShot.sh b/config/hypr/scripts/ScreenShot.sh index 0a37c7e4..0ef70964 100755 --- a/config/hypr/scripts/ScreenShot.sh +++ b/config/hypr/scripts/ScreenShot.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # Screenshots scripts diff --git a/config/hypr/scripts/Sounds.sh b/config/hypr/scripts/Sounds.sh index 8b2cc76e..b372d714 100755 --- a/config/hypr/scripts/Sounds.sh +++ b/config/hypr/scripts/Sounds.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # This script is used to play system sounds. # Script is used by Volume.Sh and ScreenShots.sh diff --git a/config/hypr/scripts/SwitchKeyboardLayout.sh b/config/hypr/scripts/SwitchKeyboardLayout.sh index f505fa6c..18a9517e 100755 --- a/config/hypr/scripts/SwitchKeyboardLayout.sh +++ b/config/hypr/scripts/SwitchKeyboardLayout.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # This is for changing kb_layouts. Set kb_layouts in $settings_file diff --git a/config/hypr/scripts/Tak0-Autodispatch.sh b/config/hypr/scripts/Tak0-Autodispatch.sh index a1f72129..114a3e8e 100755 --- a/config/hypr/scripts/Tak0-Autodispatch.sh +++ b/config/hypr/scripts/Tak0-Autodispatch.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # USAGE / ІНСТРУКЦІЯ: # 1) Run from terminal: # ./dispatch.sh <application_command> <target_workspace_number> diff --git a/config/hypr/scripts/TouchPad.sh b/config/hypr/scripts/TouchPad.sh index 8509d79f..030c36de 100755 --- a/config/hypr/scripts/TouchPad.sh +++ b/config/hypr/scripts/TouchPad.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # For disabling touchpad. # Edit the Touchpad_Device on ~/.config/hypr/UserConfigs/Laptops.conf according to your system diff --git a/config/hypr/scripts/Volume.sh b/config/hypr/scripts/Volume.sh index 8efdb55c..4c82f543 100755 --- a/config/hypr/scripts/Volume.sh +++ b/config/hypr/scripts/Volume.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # Scripts for volume controls for audio and mic diff --git a/config/hypr/scripts/WallustSwww.sh b/config/hypr/scripts/WallustSwww.sh index 5e0148ee..657f41ab 100755 --- a/config/hypr/scripts/WallustSwww.sh +++ b/config/hypr/scripts/WallustSwww.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # Wallust: derive colors from the current wallpaper and update templates # Usage: WallustSwww.sh [absolute_path_to_wallpaper] diff --git a/config/hypr/scripts/WaybarLayout.sh b/config/hypr/scripts/WaybarLayout.sh index b4d9c493..d3725a91 100755 --- a/config/hypr/scripts/WaybarLayout.sh +++ b/config/hypr/scripts/WaybarLayout.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # Script for waybar layout or configs @@ -50,7 +50,7 @@ main() { [[ -z "$choice" ]] && { echo "No option selected. Exiting."; exit 0; } # Strip marker before applying - choice=${choice# $MARKER} + choice=${choice#"$MARKER "} case "$choice" in "no panel") diff --git a/config/hypr/scripts/WaybarScripts.sh b/config/hypr/scripts/WaybarScripts.sh index 7b3aaba2..d2205c42 100755 --- a/config/hypr/scripts/WaybarScripts.sh +++ b/config/hypr/scripts/WaybarScripts.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ # # This file used on waybar modules sourcing defaults set in $HOME/.config/hypr/UserConfigs/01-UserDefaults.conf diff --git a/config/hypr/scripts/WaybarStyles.sh b/config/hypr/scripts/WaybarStyles.sh index a439f8eb..8ebfed92 100755 --- a/config/hypr/scripts/WaybarStyles.sh +++ b/config/hypr/scripts/WaybarStyles.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # Script for waybar styles @@ -51,7 +51,7 @@ main() { [[ -z "$choice" ]] && { echo "No option selected. Exiting."; exit 0; } # remove annotation and apply - choice=${choice# $MARKER} + choice=${choice#"$MARKER "} apply_style "$choice" } diff --git a/config/hypr/scripts/Wlogout.sh b/config/hypr/scripts/Wlogout.sh index f552b83d..8879858c 100755 --- a/config/hypr/scripts/Wlogout.sh +++ b/config/hypr/scripts/Wlogout.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## # wlogout (Power, Screen Lock, Suspend, etc) diff --git a/config/hypr/scripts/sddm_wallpaper.sh b/config/hypr/scripts/sddm_wallpaper.sh index 9487188c..9dca2f72 100644..100755 --- a/config/hypr/scripts/sddm_wallpaper.sh +++ b/config/hypr/scripts/sddm_wallpaper.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ # SDDM Wallpaper and Wallust Colors Setter diff --git a/config/hypr/v2.3.17 b/config/hypr/v2.3.18 index 31b3414d..31b3414d 100644 --- a/config/hypr/v2.3.17 +++ b/config/hypr/v2.3.18 diff --git a/config/rofi/online_music.list b/config/rofi/online_music.list new file mode 100644 index 00000000..bb21b9d4 --- /dev/null +++ b/config/rofi/online_music.list @@ -0,0 +1,17 @@ +FM - Easy Rock 96.3 📻🎶|https://radio-stations-philippines.com/easy-rock +FM - Easy Rock - Baguio 91.9 📻🎶|https://radio-stations-philippines.com/easy-rock-baguio +FM - Love Radio 90.7 📻🎶|https://radio-stations-philippines.com/love +FM - WRock - CEBU 96.3 📻🎶|https://onlineradio.ph/126-96-3-wrock.html +FM - Fresh Philippines 📻🎶|https://onlineradio.ph/553-fresh-fm.html +Radio - Lofi Girl 🎧🎶|https://play.streamafrica.net/lofiradio +Radio - Chillhop 🎧🎶|http://stream.zeno.fm/fyn8eh3h5f8uv +Radio - Ibiza Global 🎧🎶|https://filtermusic.net/ibiza-global +Radio - Metal Music 🎧🎶|https://tunein.com/radio/mETaLmuSicRaDio-s119867/ +YT - Wish 107.5 YT Pinoy HipHop 📻🎶|https://youtube.com/playlist?list=PLkrzfEDjeYJnmgMYwCKid4XIFqUKBVWEs&si=vahW_noh4UDJ5d37 +YT - Youtube Top 100 Songs Global 📹🎶|https://youtube.com/playlist?list=PL4fGSI1pDJn6puJdseH2Rt9sMvt9E2M4i&si=5jsyfqcoUXBCSLeu +YT - Wish 107.5 YT Wishclusives 📹🎶|https://youtube.com/playlist?list=PLkrzfEDjeYJn5B22H9HOWP3Kxxs-DkPSM&si=d_Ld2OKhGvpH48WO +YT - Relaxing Piano Music 🎹🎶|https://youtu.be/6H7hXzjFoVU?si=nZTPREC9lnK1JJUG +YT - Youtube Remix 📹🎶|https://youtube.com/playlist?list=PLeqTkIUlrZXlSNn3tcXAa-zbo95j0iN-0 +YT - Korean Drama OST 📹🎶|https://youtube.com/playlist?list=PLUge_o9AIFp4HuA-A3e3ZqENh63LuRRlQ +YT - lofi hip hop radio beats 📹🎶|https://www.youtube.com/live/jfKfPfyJRdk?si=PnJIA9ErQIAw6-qd +YT - Relaxing Piano Jazz Music 🎹🎶|https://youtu.be/85UEqRat6E4?si=jXQL1Yp2VP_G6NSn diff --git a/config/waybar/ModulesCustom b/config/waybar/ModulesCustom index 146ec275..f4c871f7 100644 --- a/config/waybar/ModulesCustom +++ b/config/waybar/ModulesCustom @@ -11,8 +11,9 @@ "format-alt-click": "click", "interval": 3600, "return-type": "json", - "exec": "$HOME/.config/hypr/UserScripts/Weather.py", + //"exec": "$HOME/.config/hypr/UserScripts/Weather.py", //"exec": "$HOME/.config/hypr/UserScripts/Weather.sh", + "exec": "$HOME/.config/hypr/UserScripts/WeatherWrap.sh", //"exec-if": "ping wttr.in -c1", "tooltip": true, }, @@ -286,4 +287,4 @@ "format": "", "tooltip": false } -}
\ No newline at end of file +} diff --git a/config/waybar/ModulesGroups b/config/waybar/ModulesGroups index 8d4453a2..30e47f16 100644 --- a/config/waybar/ModulesGroups +++ b/config/waybar/ModulesGroups @@ -89,7 +89,6 @@ }, "modules": [ "custom/power", - "custom/nightlight", "custom/lock", "keyboard-state", "custom/keyboard", @@ -132,7 +131,6 @@ }, "modules": [ "custom/power", - "custom/nightlight", "custom/lock", "custom/logout", "custom/reboot" diff --git a/config/waybar/ModulesWorkspaces b/config/waybar/ModulesWorkspaces index 82a82869..5bdccb91 100644 --- a/config/waybar/ModulesWorkspaces +++ b/config/waybar/ModulesWorkspaces @@ -194,23 +194,25 @@ "class<tor browser>": " ", "class<firefox-developer-edition>": "🦊 ", - "class<kitty|konsole>": " ", + "class<kitty|konsole|[Aa]lacritty>": " ", "class<kitty-dropterm>": " ", "class<com.mitchellh.ghostty>": " ", "class<org.wezfurlong.wezterm>": " ", + "class<Warp|warp|dev.warp.Warp|warp-terminal>": " ", "class<[Tt]hunderbird|[Tt]hunderbird-esr>": " ", "class<eu.betterbird.Betterbird>": " ", "title<.*gmail.*>": " ", "class<[Tt]elegram-desktop|org.telegram.desktop|io.github.tdesktop_x64.TDesktop>": " ", - "class<discord|[Ww]ebcord|Vesktop>": " ", + "class<discord|discord-canary|[Ww]ebcord|[Vv]esktop|com.discordapp.Discord|dev.vencord.Vesktop>": " ", + "class<[Ss]ignal|signal-desktop|org.signal.Signal>": " ", + "title<.*Signal.*>": " ", "title<.*whatsapp.*>": " ", "title<.*zapzap.*>": " ", "title<.*messenger.*>": " ", "title<.*facebook.*>": " ", - "title<.*reddit.*>": " ", - + "title<.*Discord.*>": " ", "title<.*ChatGPT.*>": " ", "title<.*deepseek.*>": " ", @@ -224,17 +226,20 @@ "title<.*Picture-in-Picture.*>": " ", "title<.*youtube.*>": " ", "class<vlc>": " ", + "class<[Kk]denlive|org.kde.kdenlive>": "🎬 ", + "title<.*Kdenlive.*>": "🎬 ", "title<.*cmus.*>": " ", "class<[Ss]potify>": " ", "class<Plex>": " ", "class<virt-manager>": " ", "class<.virt-manager-wrapped>": " ", + "class<remote-viewer|virt-viewer>": " ", "class<virtualbox manager>": "💽 ", "title<virtualbox>": "💽 ", - "class<remmina>": "🖥️ ", + "class<remmina|org.remmina.Remmina>": "🖥️ ", - "class<VSCode|code-url-handler|code-oss|codium|codium-url-handler|VSCodium>": " ", + "class<VSCode|code|code-url-handler|code-oss|codium|codium-url-handler|VSCodium>": " ", "class<dev.zed.Zed>": "", "class<codeblocks>": " ", "title<.*github.*>": " ", @@ -253,6 +258,7 @@ "class<polkit-gnome-authentication-agent-1>": " ", "class<nwg-look>": " ", + "class<nwg-displays>": " ", "class<[Pp]avucontrol|org.pulseaudio.pavucontrol>": " ", "class<steam>": " ", "class<thunar|nemo>": " ", @@ -263,6 +269,29 @@ "class<org.pipewire.Helvum>": "", "class<localsend>":"", "class<PrusaSlicer|UltiMaker-Cura|OrcaSlicer>": "", + + "class<io.github.kolunmi.Bazaar>": " ", + "title<^Bazaar$>": " ", + + "class<com.gabm.satty>": " ", + "title<^satty$>": " ", + + "class<[Bb]ox[Bb]uddy|io.github.dvlv.boxbuddy|io.github.dvlv.BoxBuddy>": " ", + "title<.*BoxBuddy.*>": " ", + + "title<Hyprland Keybinds>": " ", + "title<Niri Keybinds>": " ", + "title<BSPWM Keybinds>": " ", + "title<DWM Keybinds>": " ", + "title<Emacs Leader Keybinds>": " ", + "title<Kitty Configuration>": " ", + "title<WezTerm Configuration>": " ", + "title<Yazi Configuration>": " ", + "title<Cheatsheets Viewer>": " ", + "title<Documentation Viewer>": " ", + "title<^Wallpapers$>": " ", + "title<^Video Wallpapers$>": " ", + "title<^qs-wlogout$>": " ", } }, }
\ No newline at end of file @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ # clear @@ -38,25 +38,25 @@ print_color() { # Check /etc/os-release for Ubuntu or Debian and warn about Hyprland version requirement if grep -iqE '^(ID_LIKE|ID)=.*(ubuntu|debian)' /etc/os-release >/dev/null 2>&1; then printf "\n%.0s" {1..1} - print_color $WARNING "\nThese Dotfiles are only supported on Hyprland 0.51.1 or greater. Do not install on older revisions.\n" + print_color $WARNING "\nThese Dotfiles are only supported on Hyprland v0.50 or greater. Do not install on older versions of Hyprland.\n" while true; do echo -n "${CAT} Do you want to continue anyway? (y/N): " read _continue _continue=$(echo "${_continue}" | tr '[:upper:]' '[:lower:]') case "${_continue}" in - y|yes) - echo "${NOTE} Proceeding on Ubuntu/Debian by user confirmation." - break - ;; - n|no|"") - printf "\n%.0s" {1..1} - echo "${INFO} Aborting per user choice. No changes made." - printf "\n%.0s" {1..1} - exit 1 - ;; - *) - echo "${WARN} Please answer 'y' or 'n'." - ;; + y | yes) + echo "${NOTE} Proceeding on Ubuntu/Debian by user confirmation." + break + ;; + n | no | "") + printf "\n%.0s" {1..1} + echo "${INFO} Aborting per user choice. No changes made." + printf "\n%.0s" {1..1} + exit 1 + ;; + *) + echo "${WARN} Please answer 'y' or 'n'." + ;; esac done fi @@ -111,8 +111,17 @@ fi # Proper Polkit for NixOS if hostnamectl | grep -q 'Operating System: NixOS'; then echo "${INFO} NixOS Distro Detected. Setting up proper env's and configs." 2>&1 | tee -a "$LOG" || true - sed -i -E '/^#?exec-once = \$scriptsDir\/Polkit-NixOS\.sh/s/^#//' config/hypr/UserConfigs/Startup_Apps.conf - sed -i '/^exec-once = \$scriptsDir\/Polkit\.sh$/ s/^#*/#/' config/hypr/UserConfigs/Startup_Apps.conf + # Ensure NixOS polkit is enabled via overlay and default polkit is disabled via disable list + OVERLAY_SA="config/hypr/UserConfigs/Startup_Apps.conf" + DISABLE_SA="config/hypr/UserConfigs/Startup_Apps.disable" + mkdir -p "$(dirname "$OVERLAY_SA")" + touch "$OVERLAY_SA" "$DISABLE_SA" + if ! grep -qx 'exec-once = $scriptsDir/Polkit-NixOS.sh' "$OVERLAY_SA"; then + echo 'exec-once = $scriptsDir/Polkit-NixOS.sh' >>"$OVERLAY_SA" + fi + if ! grep -qx '\$scriptsDir/Polkit.sh' "$DISABLE_SA"; then + echo '$scriptsDir/Polkit.sh' >>"$DISABLE_SA" + fi fi # activating hyprcursor on env by checking if the directory ~/.icons/Bibata-Modern-Ice/hyprcursors exists @@ -236,40 +245,53 @@ done # Check if asusctl is installed and add rog-control-center on Startup if command -v asusctl >/dev/null 2>&1; then - sed -i '/^\s*#exec-once = rog-control-center/s/^#//' config/hypr/UserConfigs/Startup_Apps.conf + OVERLAY_SA="config/hypr/UserConfigs/Startup_Apps.conf" + mkdir -p "$(dirname "$OVERLAY_SA")" + touch "$OVERLAY_SA" + grep -qx 'exec-once = rog-control-center' "$OVERLAY_SA" || echo 'exec-once = rog-control-center' >>"$OVERLAY_SA" fi # Check if blueman-applet is installed and add blueman-applet on Startup if command -v blueman-applet >/dev/null 2>&1; then - sed -i '/^\s*#exec-once = blueman-applet/s/^#//' config/hypr/UserConfigs/Startup_Apps.conf + OVERLAY_SA="config/hypr/UserConfigs/Startup_Apps.conf" + mkdir -p "$(dirname "$OVERLAY_SA")" + touch "$OVERLAY_SA" + grep -qx 'exec-once = blueman-applet' "$OVERLAY_SA" || echo 'exec-once = blueman-applet' >>"$OVERLAY_SA" fi -# Check if ags is installed edit ags behaviour on configs +# Check if ags is installed and enable it if command -v ags >/dev/null 2>&1; then - sed -i '/^\s*#exec-once = ags/s/^#//' config/hypr/UserConfigs/Startup_Apps.conf + echo "${INFO} AGS detected - enabling in startup and refresh scripts" 2>&1 | tee -a "$LOG" + OVERLAY_SA="config/hypr/UserConfigs/Startup_Apps.conf" + mkdir -p "$(dirname "$OVERLAY_SA")" + touch "$OVERLAY_SA" + grep -qx 'exec-once = ags' "$OVERLAY_SA" || echo 'exec-once = ags' >>"$OVERLAY_SA" sed -i '/#ags -q && ags &/s/^#//' config/hypr/scripts/RefreshNoWaybar.sh sed -i '/#ags -q && ags &/s/^#//' config/hypr/scripts/Refresh.sh - - # Uncomment the ags overview keybind - sed -i '/^#bind = \$mainMod, A, exec, pkill rofi || true && ags -t '\''overview'\''/s/^#//' config/hypr/UserConfigs/UserKeybinds.conf - - # Comment the quickshell line if not already commented - sed -i '/^\s*bind\s*=\s*\$mainMod,\s*A,\s*global,\s*quickshell:overviewToggle/{s/^\s*/#/}' config/hypr/UserConfigs/UserKeybinds.conf fi -# Check if quickshell is installed; edit quickshell behaviour on configs +# Check if quickshell is installed and enable it if command -v qs >/dev/null 2>&1; then - sed -i '/^\s*#exec-once = qs/s/^#//' config/hypr/UserConfigs/Startup_Apps.conf + echo "${INFO} Quickshell detected - enabling in startup and refresh scripts" 2>&1 | tee -a "$LOG" + OVERLAY_SA="config/hypr/UserConfigs/Startup_Apps.conf" + mkdir -p "$(dirname "$OVERLAY_SA")" + touch "$OVERLAY_SA" + grep -qx 'exec-once = qs' "$OVERLAY_SA" || echo 'exec-once = qs' >>"$OVERLAY_SA" sed -i '/#pkill qs && qs &/s/^#//' config/hypr/scripts/RefreshNoWaybar.sh sed -i '/#pkill qs && qs &/s/^#//' config/hypr/scripts/Refresh.sh +fi - # Uncomment the quickshell keybind line - sed -i "/^#bind = \$mainMod, A, global, quickshell:overviewToggle/s/^#//" config/hypr/UserConfigs/UserKeybinds.conf - - # Ensure the ags overview keybind is commented - sed -i "/^\s*bind\s*=\s*\\\$mainMod,\s*A,\s*exec,\s*pkill rofi\s*||\s*true\s*&&\s*ags\s*-t\s*'overview'/{s/^\s*/#/}" config/hypr/UserConfigs/UserKeybinds.conf +# Ensure layout-aware keybinds init runs on startup (adds to user overlay so it survives composes) +OVERLAY_SA="config/hypr/UserConfigs/Startup_Apps.conf" +mkdir -p "$(dirname "$OVERLAY_SA")" +if ! grep -qx 'exec-once = \$scriptsDir/KeybindsLayoutInit.sh' "$OVERLAY_SA"; then + echo 'exec-once = $scriptsDir/KeybindsLayoutInit.sh' >>"$OVERLAY_SA" + echo "${INFO} Added KeybindsLayoutInit.sh to user Startup_Apps overlay" 2>&1 | tee -a "$LOG" fi +# Note: The SUPER+A keybind now uses OverviewToggle.sh which automatically +# tries quickshell first and falls back to AGS, so both can be installed + printf "\n%.0s" {1..1} # Checking if neovim or vim is installed and offer user if they want to make as default editor @@ -392,11 +414,19 @@ while true; do sed -i 's#^\(\s*\)\("format": "{:%a %d | %H:%M}",\) #\1//\2#g' config/waybar/Modules 2>&1 | tee -a "$LOG" # for hyprlock - sed -i 's/^\s*text = cmd\[update:1000\] echo "\$(date +"%H")"/# &/' config/hypr/hyprlock.conf 2>&1 | tee -a "$LOG" - sed -i 's/^\(\s*\)# *text = cmd\[update:1000\] echo "\$(date +"%I")" #AM\/PM/\1 text = cmd\[update:1000\] echo "\$(date +"%I")" #AM\/PM/' config/hypr/hyprlock.conf 2>&1 | tee -a "$LOG" + HYPRLOCK_FILE="config/hypr/hyprlock.conf" + if [ ! -f "$HYPRLOCK_FILE" ] && [ -f "config/hypr/hyprlock-1080p.conf" ]; then + HYPRLOCK_FILE="config/hypr/hyprlock-1080p.conf" + fi + if [ -f "$HYPRLOCK_FILE" ]; then + sed -i 's/^\s*text = cmd\[update:1000\] echo "\$(date +"%H")"/# &/' "$HYPRLOCK_FILE" 2>&1 | tee -a "$LOG" + sed -i 's/^\(\s*\)# *text = cmd\[update:1000\] echo "\$(date +"%I")" #AM\/PM/\1 text = cmd\[update:1000\] echo "\$(date +"%I")" #AM\/PM/' "$HYPRLOCK_FILE" 2>&1 | tee -a "$LOG" - sed -i 's/^\s*text = cmd\[update:1000\] echo "\$(date +"%S")"/# &/' config/hypr/hyprlock.conf 2>&1 | tee -a "$LOG" - sed -i 's/^\(\s*\)# *text = cmd\[update:1000\] echo "\$(date +"%S %p")" #AM\/PM/\1 text = cmd\[update:1000\] echo "\$(date +"%S %p")" #AM\/PM/' config/hypr/hyprlock.conf 2>&1 | tee -a "$LOG" + sed -i 's/^\s*text = cmd\[update:1000\] echo "\$(date +"%S")"/# &/' "$HYPRLOCK_FILE" 2>&1 | tee -a "$LOG" + sed -i 's/^\(\s*\)# *text = cmd\[update:1000\] echo "\$(date +"%S %p")" #AM\/PM/\1 text = cmd\[update:1000\] echo "\$(date +"%S %p")" #AM\/PM/' "$HYPRLOCK_FILE" 2>&1 | tee -a "$LOG" + else + echo "${WARN} hyprlock template not found; skipping 12H lock format edits" 2>&1 | tee -a "$LOG" + fi echo "${OK} 12H format set on waybar clocks succesfully." 2>&1 | tee -a "$LOG" @@ -814,6 +844,41 @@ FILES_TO_RESTORE=( "WindowRules.conf" ) +# Helper to extract overlay (additions) and optional disables from a previous user file compared to vendor base +compose_overlay_from_backup() { + local type="$1" # startup|windowrules + local base_file="$2" + local old_user_file="$3" + local new_user_file="$4" + local disable_file="$5" + + mkdir -p "$(dirname "$new_user_file")" + : >"$new_user_file" + : >"$disable_file" + + if [ "$type" = "startup" ]; then + # additions: exec-once lines present in old user but not in base + grep -E '^\s*exec-once\s*=' "$old_user_file" | sed -E 's/^\s+//;s/\s+$//' | sort -u >"$old_user_file.tmp.exec" + grep -E '^\s*exec-once\s*=' "$base_file" | sed -E 's/^\s+//;s/\s+$//' | sort -u >"$base_file.tmp.exec" + comm -23 "$old_user_file.tmp.exec" "$base_file.tmp.exec" >"$new_user_file" + # treat commented exec-once in old user as disables + grep -E '^\s*#\s*exec-once\s*=' "$old_user_file" \ + | sed -E 's/^\s*#\s*exec-once\s*=\s*//' \ + | sed -E 's/^\s+//;s/\s+$//' \ + | grep -Ev '^\$scriptsDir/KeybindsLayoutInit\.sh$' \ + | sort -u >"$disable_file" + rm -f "$old_user_file.tmp.exec" "$base_file.tmp.exec" + elif [ "$type" = "windowrules" ]; then + # additions + grep -E '^(windowrule|layerrule)\s*=' "$old_user_file" | sed -E 's/^\s+//;s/\s+$//' | sort -u >"$old_user_file.tmp.rules" + grep -E '^(windowrule|layerrule)\s*=' "$base_file" | sed -E 's/^\s+//;s/\s+$//' | sort -u >"$base_file.tmp.rules" + comm -23 "$old_user_file.tmp.rules" "$base_file.tmp.rules" >"$new_user_file" + # disables: lines commented in old user + grep -E '^\s*#\s*(windowrule|layerrule)\s*=' "$old_user_file" | sed -E 's/^\s*#\s*//' | sed -E 's/^\s+//;s/\s+$//' | sort -u >"$disable_file" + rm -f "$old_user_file.tmp.rules" "$base_file.tmp.rules" + fi +} + DIRPATH="$HOME/.config/$DIRH" BACKUP_DIR=$(get_backup_dirname) BACKUP_DIR_PATH="$DIRPATH-backup-$BACKUP_DIR/UserConfigs" @@ -830,14 +895,27 @@ if [ -d "$BACKUP_DIR_PATH" ]; then NOTES for RESTORING PREVIOUS CONFIGS █▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄█ - If you decide to restore your old configs, make sure to - handle the updates or changes manually !!! + We now auto-migrate Startup_Apps and WindowRules by extracting + your additions into overlay files and optional disable lists. + This keeps new defaults while preserving your custom changes. " echo -e "${MAGENTA}Kindly Visit and check KooL's Hyprland-Dots GitHub page for the history of commits.${RESET}" for FILE_NAME in "${FILES_TO_RESTORE[@]}"; do BACKUP_FILE="$BACKUP_DIR_PATH/$FILE_NAME" if [ -f "$BACKUP_FILE" ]; then + # Special handling for Startup_Apps.conf and WindowRules.conf + if [ "$FILE_NAME" = "Startup_Apps.conf" ]; then + compose_overlay_from_backup "startup" "$DIRPATH/configs/Startup_Apps.conf" "$BACKUP_FILE" "$DIRPATH/UserConfigs/Startup_Apps.conf" "$DIRPATH/UserConfigs/Startup_Apps.disable" + echo "${OK} - Migrated overlay for ${YELLOW}$FILE_NAME${RESET}" 2>&1 | tee -a "$LOG" + continue + fi + if [ "$FILE_NAME" = "WindowRules.conf" ]; then + compose_overlay_from_backup "windowrules" "$DIRPATH/configs/WindowRules.conf" "$BACKUP_FILE" "$DIRPATH/UserConfigs/WindowRules.conf" "$DIRPATH/UserConfigs/WindowRules.disable" + echo "${OK} - Migrated overlay for ${YELLOW}$FILE_NAME${RESET}" 2>&1 | tee -a "$LOG" + continue + fi + printf "\n${INFO} Found ${YELLOW}$FILE_NAME${RESET} in hypr backup...\n" echo -n "${CAT} Do you want to restore ${YELLOW}$FILE_NAME${RESET} from backup? (y/N): " read file_restore @@ -855,6 +933,7 @@ if [ -d "$BACKUP_DIR_PATH" ]; then done fi + printf "\n%.0s" {1..1} # Restoring previous UserScripts @@ -1023,6 +1102,7 @@ printf "\n%.0s" {1..1} echo "${MAGENTA}By default only a few wallpapers are copied${RESET}..." while true; do + echo "${NOTE} A number of these wallpapers are AI generated or enhanced. Select (N/n) if this is an issue for you. " echo -n "${CAT} Would you like to download additional wallpapers? ${WARN} This is 1GB in size (y/n): " read WALL @@ -1131,4 +1211,3 @@ printf "${INFO} However, it is ${MAGENTA}HIGHLY SUGGESTED${RESET} to logout and printf "\n%.0s" {1..1} printf "${SKY_BLUE}Thank you${RESET} for using ${MAGENTA}KooL's Hyprland Configuration${RESET}... ${YELLOW}ENJOY!!!${RESET}" printf "\n%.0s" {1..3} - @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ # # For downloading dots from releases @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ # # for Semi-Manual upgrading your system. # NOTE: requires rsync @@ -196,7 +196,8 @@ if version_gt "$latest_version" "$stored_version"; then chmod +x "$HOME/.config/hypr/scripts/"* 2>&1 | tee -a "$LOG" chmod +x "$HOME/.config/hypr/UserScripts/"* 2>&1 | tee -a "$LOG" # Set executable for initial-boot.sh - chmod +x "$HOME/.config/hypr/initial-boot.sh" 2>&1 | tee -a "$LOG" + chmod +x "$HOME/.config/hypr/initial-boot.sh" 2>&1 | tee -a "$LOG" + else echo "$MAGENTA Upgrade declined. No files or directories changed" 2>&1 | tee -a "$LOG" fi |
