diff options
| author | Pinapelz <yukais@pinapelz.com> | 2026-07-10 11:21:24 -0700 |
|---|---|---|
| committer | Pinapelz <yukais@pinapelz.com> | 2026-07-10 11:21:24 -0700 |
| commit | 24de2a31a52d17b6f7214197bdbfeab7428742dd (patch) | |
| tree | f7736c4712d5a394525a3da2f2b4294e81ba9540 /config/hypr/scripts/ChangeLayout.sh | |
| parent | 861bf5be200bfcf2440fec4cda911d29ec18493f (diff) | |
| parent | bca86bbec4757cec1f6f5bdea2ed210542f10fae (diff) | |
Merge remote-tracking branch 'upstream'
Diffstat (limited to 'config/hypr/scripts/ChangeLayout.sh')
| -rwxr-xr-x | config/hypr/scripts/ChangeLayout.sh | 229 |
1 files changed, 162 insertions, 67 deletions
diff --git a/config/hypr/scripts/ChangeLayout.sh b/config/hypr/scripts/ChangeLayout.sh index 3c81bcbe..4e241e85 100755 --- a/config/hypr/scripts/ChangeLayout.sh +++ b/config/hypr/scripts/ChangeLayout.sh @@ -5,36 +5,168 @@ # License: GNU GPLv3 # SPDX-License-Identifier: GPL-3.0-or-later # ================================================== -# for changing Hyprland Layouts (master, dwindle, scrolling, monocle) on the fly - -notif="$HOME/.config/swaync/images/ja.png" +# Switch Hyprland layouts per active monitor/workspace. +# This avoids global layout mutations and keeps workspace-specific rules intact. +notif="${XDG_CONFIG_HOME:-$HOME/.config}/swaync/images/ja.png" +persist_layout_script="${XDG_CONFIG_HOME:-$HOME/.config}/hypr/scripts/PersistWorkspaceLayout.sh" layouts=(master dwindle scrolling monocle) quiet_mode=0 +normalize_layout() { + case "$1" in + master | dwindle | scrolling | monocle) + printf '%s\n' "$1" + ;; + *) + printf '\n' + ;; + esac +} + +wait_for_layout() { + local target="$1" + local actual="" + local attempt + + for attempt in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do + actual="$(get_layout)" + if [[ "$actual" == "$target" ]]; then + printf '%s\n' "$actual" + return 0 + fi + sleep 0.03 + done + + printf '%s\n' "$actual" + return 1 +} + +persist_current_workspace_layout() { + local target_layout="$1" + + if [[ ! -x "$persist_layout_script" ]]; then + return 0 + fi + + "$persist_layout_script" --quiet --layout "$target_layout" >/dev/null 2>&1 || true +} + +get_active_workspace_json() { + hyprctl -j activeworkspace 2>/dev/null || printf '{}' +} + get_layout() { - hyprctl -j getoption general:layout | jq -r '.str' + local ws_json layout + + ws_json="$(get_active_workspace_json)" + layout="$(jq -r '.tiledLayout // .tiled_layout // .layout // empty' <<<"$ws_json" 2>/dev/null || true)" + layout="$(normalize_layout "$layout")" + + if [[ -z "$layout" ]]; then + layout="$(hyprctl -j getoption general:layout 2>/dev/null | jq -r '.str // empty' 2>/dev/null || true)" + layout="$(normalize_layout "$layout")" + fi + + if [[ -z "$layout" ]]; then + layout="dwindle" + fi + + printf '%s\n' "$layout" } -set_hypr_layout() { +get_workspace_selector() { + local ws_json="$1" + local ws_id ws_name + + ws_id="$(jq -r '.id // empty' <<<"$ws_json" 2>/dev/null || true)" + ws_name="$(jq -r '.name // empty' <<<"$ws_json" 2>/dev/null || true)" + + if [[ "$ws_id" =~ ^[0-9]+$ ]] && ((ws_id > 0)); then + printf '%s\n' "$ws_id" + return 0 + fi + + if [[ -n "$ws_name" && "$ws_name" != "null" ]]; then + if [[ "$ws_name" == name:* || "$ws_name" == special:* ]]; then + printf '%s\n' "$ws_name" + else + printf 'name:%s\n' "$ws_name" + fi + return 0 + fi + + return 1 +} + +get_workspace_label() { + local ws_json="$1" + local ws_name ws_id + + ws_name="$(jq -r '.name // empty' <<<"$ws_json" 2>/dev/null || true)" + ws_id="$(jq -r '.id // empty' <<<"$ws_json" 2>/dev/null || true)" + + if [[ -n "$ws_name" && "$ws_name" != "null" ]]; then + printf '%s\n' "$ws_name" + return + fi + + if [[ -n "$ws_id" && "$ws_id" != "null" ]]; then + printf '%s\n' "$ws_id" + return + fi + + printf 'current\n' +} + +get_monitor_name() { + local ws_json="$1" + jq -r '.monitor // empty' <<<"$ws_json" 2>/dev/null || true +} + +escape_lua_string() { + local value="$1" + value="${value//\\/\\\\}" + value="${value//\"/\\\"}" + printf '%s' "$value" +} + +is_ok_output() { + local output="$1" + local normalized + + normalized="$(printf '%s\n' "$output" | tr -d '\r' | sed '/^[[:space:]]*$/d')" + [[ -z "$normalized" || "$normalized" == "ok" ]] +} + +set_workspace_layout_rule() { local target="$1" - local output + local ws_json workspace_selector monitor_name output + local ws_escaped monitor_escaped target_escaped + + ws_json="$(get_active_workspace_json)" + workspace_selector="$(get_workspace_selector "$ws_json" || true)" + monitor_name="$(get_monitor_name "$ws_json")" - output="$(hyprctl keyword general:layout "$target" 2>&1)" + if [[ -z "$workspace_selector" || -z "$monitor_name" ]]; then + echo "Unable to resolve active workspace context" >&2 + return 1 + fi + + output="$(hyprctl keyword workspace "${workspace_selector}, monitor:${monitor_name}, layout:${target}" 2>&1 || true)" if grep -q "keyword can't work with non-legacy parsers" <<<"$output"; then - output="$(hyprctl eval "hl.config({ general = { layout = \"${target}\" } })" 2>&1)" + ws_escaped="$(escape_lua_string "$workspace_selector")" + monitor_escaped="$(escape_lua_string "$monitor_name")" + target_escaped="$(escape_lua_string "$target")" + output="$(hyprctl eval "hl.workspace_rule({ workspace = \"${ws_escaped}\", monitor = \"${monitor_escaped}\", layout = \"${target_escaped}\" })" 2>&1 || true)" fi - if ! grep -q "^ok$" <<<"$output"; then + if ! is_ok_output "$output"; then echo "$output" >&2 return 1 fi } -hypr_keyword() { - hyprctl keyword "$@" >/dev/null 2>&1 || true -} - next_layout() { local current="$1" local i @@ -49,65 +181,24 @@ next_layout() { set_layout() { local target="$1" + local ws_json workspace_label monitor_name actual - if ! set_hypr_layout "$target"; then + ws_json="$(get_active_workspace_json)" + workspace_label="$(get_workspace_label "$ws_json")" + monitor_name="$(get_monitor_name "$ws_json")" + + if ! set_workspace_layout_rule "$target"; then if [[ "$quiet_mode" -eq 0 ]]; then notify-send -e -u critical -i "$notif" " Layout switch failed: $target" fi return 1 fi - hypr_keyword unbind SUPER,j - hypr_keyword unbind SUPER,k - hypr_keyword bind SUPER,j,cyclenext - hypr_keyword bind SUPER,k,cyclenext,prev - hypr_keyword unbind SUPER,left - hypr_keyword unbind SUPER,right - hypr_keyword unbind SUPER,up - hypr_keyword unbind SUPER,down - hypr_keyword unbind SUPER,O - - case "$target" in - "dwindle") - hypr_keyword bind SUPER,left,cyclenext,prev - hypr_keyword bind SUPER,up,cyclenext,prev - hypr_keyword bind SUPER,right,cyclenext - hypr_keyword bind SUPER,down,cyclenext - hypr_keyword bind SUPER,O,layoutmsg,togglesplit - ;; - "scrolling") - hypr_keyword bind SUPER,left,cyclenext,prev - hypr_keyword bind SUPER,up,cyclenext,prev - hypr_keyword bind SUPER,right,cyclenext - hypr_keyword bind SUPER,down,cyclenext - ;; - "monocle") - hypr_keyword bind SUPER,left,layoutmsg,cycleprev - hypr_keyword bind SUPER,up,layoutmsg,cycleprev - hypr_keyword bind SUPER,right,layoutmsg,cyclenext - hypr_keyword bind SUPER,down,layoutmsg,cyclenext - ;; - "master") - hypr_keyword bind SUPER,left,movefocus,l - hypr_keyword bind SUPER,right,movefocus,r - hypr_keyword bind SUPER,up,movefocus,u - hypr_keyword bind SUPER,down,movefocus,d - ;; - *) - hypr_keyword bind SUPER,left,movefocus,l - hypr_keyword bind SUPER,right,movefocus,r - hypr_keyword bind SUPER,up,movefocus,u - hypr_keyword bind SUPER,down,movefocus,d - echo "Unknown layout: $target" >&2 - return 1 - ;; - esac - - local actual - actual="$(get_layout)" + actual="$(wait_for_layout "$target")" if [[ "$actual" == "$target" ]]; then + persist_current_workspace_layout "$target" if [[ "$quiet_mode" -eq 0 ]]; then - notify-send -e -u low -i "$notif" " ${actual^} Layout" + notify-send -e -u low -i "$notif" " ${actual^} Layout ยท WS ${workspace_label}${monitor_name:+ @ ${monitor_name}}" fi else if [[ "$quiet_mode" -eq 0 ]]; then @@ -127,16 +218,20 @@ arg="${1:-toggle}" case "$arg" in init) - set_layout "$current" + # No startup keybind rebinding required anymore. + exit 0 + ;; +current | status | get) + printf '%s\n' "$current" ;; -toggle|next) +toggle | next) set_layout "$(next_layout "$current")" ;; -master|dwindle|scrolling|monocle) +master | dwindle | scrolling | monocle) set_layout "$arg" ;; *) - echo "Usage: $(basename "$0") [--quiet|--no-notify] [toggle|next|init|master|dwindle|scrolling|monocle]" >&2 + echo "Usage: $(basename "$0") [--quiet|--no-notify] [toggle|next|init|current|master|dwindle|scrolling|monocle]" >&2 exit 1 ;; esac |
