diff options
| author | Craig Jennings <c@cjennings.net> | 2026-01-29 23:06:41 -0600 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-01-29 23:06:41 -0600 |
| commit | c378c2f075845f6a8110be37ca7fbb7fc98721c7 (patch) | |
| tree | ecad884574df40ac80f44cf9001eb201d5362110 | |
| parent | 0da19ea3454ec54b47c31f921c5c9697c10648f9 (diff) | |
feat(hyprland): add pyprland for scratchpads, magnify, and window stashing
Replace native special workspace scratchpads with pyprland to fix issue
where new windows were captured by visible scratchpads. Add magnify on
mod+Z and window stash scripts (mod+O to stash, mod+Alt+O stash others,
mod+Shift+O restore).
| -rwxr-xr-x | archsetup | 1 | ||||
| -rw-r--r-- | dotfiles/hyprland/.config/hypr/hyprland.conf | 64 | ||||
| -rw-r--r-- | dotfiles/hyprland/.config/hypr/pyprland.toml | 48 | ||||
| -rwxr-xr-x | dotfiles/hyprland/.local/bin/stash-others | 12 | ||||
| -rwxr-xr-x | dotfiles/hyprland/.local/bin/stash-restore | 10 | ||||
| -rwxr-xr-x | dotfiles/hyprland/.local/bin/stash-window | 4 |
6 files changed, 93 insertions, 46 deletions
@@ -1405,6 +1405,7 @@ hyprland() { action="Hyprland Utilities" && display "subtitle" "$action" pacman_install cpio # hyprpm (plugin manager) dependency + aur_install pyprland # scratchpads, magnify, expose (fixes special workspace issues) pacman_install waybar # status bar pacman_install fuzzel # app launcher (native Wayland, pinentry support) pacman_install swww # wallpaper daemon diff --git a/dotfiles/hyprland/.config/hypr/hyprland.conf b/dotfiles/hyprland/.config/hypr/hyprland.conf index 9458150..a854e1a 100644 --- a/dotfiles/hyprland/.config/hypr/hyprland.conf +++ b/dotfiles/hyprland/.config/hypr/hyprland.conf @@ -31,6 +31,9 @@ exec-once = gammastep > ~/.local/var/log/gammastep-$(date +%Y-%m-%d-%H%M%S).log exec-once = blueman-applet exec-once = mpd +# Pyprland (scratchpads, magnify, etc.) +exec-once = pypr + # Apps that can start later exec-once = signal-desktop --start-in-tray --ozone-platform=wayland exec-once = protonmail-bridge --no-window @@ -211,11 +214,11 @@ bind = $mod SHIFT, SPACE, togglefloating bind = $mod, I, layoutmsg, addmaster bind = $mod, D, layoutmsg, removemaster -# Focus mode (xtra-dispatchers plugin) -# O = "Only this window" / "bring back Others" / "close Others" -bind = $mod, O, exec, hyprctl dispatch plugin:xtd:throwunfocused 10 -bind = $mod SHIFT, O, exec, focus-restore -bind = $mod CTRL, O, exec, hyprctl dispatch plugin:xtd:closeunfocused +# Stash windows (hide to special workspace) +# O = stash focused / Alt+O = stash others / Shift+O = restore all +bind = $mod, O, exec, stash-window +bind = $mod ALT, O, exec, stash-others +bind = $mod SHIFT, O, exec, stash-restore # Gaps (from DWM) bind = $mod, MINUS, exec, hyprctl keyword general:gaps_out $(( $(hyprctl getoption general:gaps_out -j | jq -r '.custom' | cut -d' ' -f1) - 5 )) && hyprctl keyword general:gaps_in $(( $(hyprctl getoption general:gaps_in -j | jq -r '.custom' | cut -d' ' -f1) - 5 )) @@ -260,48 +263,17 @@ bind = $mod SHIFT, COMMA, movewindow, mon:-1 bind = $mod SHIFT, PERIOD, movewindow, mon:+1 # ============================================================================ -# Scratchpads (from DWM togglescratch) +# Scratchpads (via pyprland) # ============================================================================ -# Using on-created-empty workspace rules - app launches on first toggle, -# subsequent toggles just show/hide the workspace - -# Workspace rules (auto-launch apps when workspace first accessed) -workspace = special:term, on-created-empty:foot --app-id foot-term tmux -workspace = special:audio, on-created-empty:foot --app-id foot-audio pulsemixer -workspace = special:monitor, on-created-empty:foot --app-id foot-monitor monitor-dashboard -workspace = special:music, on-created-empty:foot --app-id foot-music ncmpcpp -workspace = special:network, on-created-empty:foot --app-id foot-network nmtui -# Keybindings (single bind per scratchpad - just toggle visibility) -bind = $mod SHIFT, RETURN, togglespecialworkspace, term -bind = $mod, A, togglespecialworkspace, audio -bind = $mod, M, togglespecialworkspace, monitor -bind = $mod, SLASH, togglespecialworkspace, music - -# Window rules (using app-id/class matching, Hyprland 0.53+ syntax) -# Terminal scratchpad -windowrule = match:class ^(foot-term)$, float on -windowrule = match:class ^(foot-term)$, size (monitor_w*0.6) (monitor_h*0.6) -windowrule = match:class ^(foot-term)$, center on - -# Audio mixer -windowrule = match:class ^(foot-audio)$, float on -windowrule = match:class ^(foot-audio)$, size (monitor_w*0.6) (monitor_h*0.6) -windowrule = match:class ^(foot-audio)$, center on - -# System monitor -windowrule = match:class ^(foot-monitor)$, float on -windowrule = match:class ^(foot-monitor)$, size (monitor_w*0.6) (monitor_h*0.6) -windowrule = match:class ^(foot-monitor)$, center on - -# Music player -windowrule = match:class ^(foot-music)$, float on -windowrule = match:class ^(foot-music)$, size (monitor_w*0.6) (monitor_h*0.6) -windowrule = match:class ^(foot-music)$, center on - -# Network manager -windowrule = match:class ^(foot-network)$, float on -windowrule = match:class ^(foot-network)$, size (monitor_w*0.6) (monitor_h*0.6) -windowrule = match:class ^(foot-network)$, center on +# Configured in ~/.config/hypr/pyprland.toml +# Uses normal workspaces (not special), so new windows won't be captured +bind = $mod SHIFT, RETURN, exec, pypr toggle term +bind = $mod, A, exec, pypr toggle audio +bind = $mod, M, exec, pypr toggle monitor +bind = $mod, SLASH, exec, pypr toggle music + +# Magnify (zoom) +bind = $mod, Z, exec, pypr zoom # Calculator (not a scratchpad, just launches app) bind = $mod, X, exec, qalculate-gtk diff --git a/dotfiles/hyprland/.config/hypr/pyprland.toml b/dotfiles/hyprland/.config/hypr/pyprland.toml new file mode 100644 index 0000000..f946a74 --- /dev/null +++ b/dotfiles/hyprland/.config/hypr/pyprland.toml @@ -0,0 +1,48 @@ +# Pyprland Configuration +# https://hyprland-community.github.io/pyprland/ + +[pyprland] +plugins = [ + "scratchpads", + "magnify", +] + +# ============================================================================ +# Magnify +# ============================================================================ +[magnify] +factor = 2 + +# ============================================================================ +# Scratchpads +# ============================================================================ +# Scratchpads use normal workspaces by default (not special workspaces), +# which prevents newly launched apps from being captured by the scratchpad. + +[scratchpads.term] +command = "foot --app-id foot-term tmux" +class = "foot-term" +size = "60% 60%" +position = "20% 20%" +animation = "fromBottom" + +[scratchpads.audio] +command = "foot --app-id foot-audio pulsemixer" +class = "foot-audio" +size = "60% 60%" +position = "20% 20%" +animation = "fromBottom" + +[scratchpads.monitor] +command = "foot --app-id foot-monitor monitor-dashboard" +class = "foot-monitor" +size = "60% 60%" +position = "20% 20%" +animation = "fromBottom" + +[scratchpads.music] +command = "foot --app-id foot-music ncmpcpp" +class = "foot-music" +size = "60% 60%" +position = "20% 20%" +animation = "fromBottom" diff --git a/dotfiles/hyprland/.local/bin/stash-others b/dotfiles/hyprland/.local/bin/stash-others new file mode 100755 index 0000000..5af6743 --- /dev/null +++ b/dotfiles/hyprland/.local/bin/stash-others @@ -0,0 +1,12 @@ +#!/bin/bash +# Stash all unfocused windows on current workspace to special:stash + +focused=$(hyprctl activewindow -j | jq -r '.address') +workspace=$(hyprctl activewindow -j | jq -r '.workspace.id') + +# Get all windows on current workspace except the focused one +hyprctl clients -j | jq -r --arg focused "$focused" --argjson ws "$workspace" \ + '.[] | select(.workspace.id == $ws and .address != $focused) | .address' | \ +while read -r addr; do + hyprctl dispatch movetoworkspacesilent special:stash,address:"$addr" +done diff --git a/dotfiles/hyprland/.local/bin/stash-restore b/dotfiles/hyprland/.local/bin/stash-restore new file mode 100755 index 0000000..e04945a --- /dev/null +++ b/dotfiles/hyprland/.local/bin/stash-restore @@ -0,0 +1,10 @@ +#!/bin/bash +# Restore all windows from special:stash to current workspace + +workspace=$(hyprctl activeworkspace -j | jq -r '.id') + +# Get all windows in special:stash and move them to current workspace +hyprctl clients -j | jq -r '.[] | select(.workspace.name == "special:stash") | .address' | \ +while read -r addr; do + hyprctl dispatch movetoworkspacesilent "$workspace",address:"$addr" +done diff --git a/dotfiles/hyprland/.local/bin/stash-window b/dotfiles/hyprland/.local/bin/stash-window new file mode 100755 index 0000000..1ffab8c --- /dev/null +++ b/dotfiles/hyprland/.local/bin/stash-window @@ -0,0 +1,4 @@ +#!/bin/bash +# Stash the focused window to a special workspace + +hyprctl dispatch movetoworkspacesilent special:stash |
