From 62409836fc855f7987e2873bbabf77f4e64fc66d Mon Sep 17 00:00:00 2001 From: "s0wlz (Matthias Puchstein)" Date: Sun, 1 Mar 2026 16:07:48 +0100 Subject: [PATCH] hypr: add workspace layout toggles with notifications --- dot_config/hypr/hyprland.d/50-layout.conf | 5 + .../hypr/hyprland.d/70-keybinds.conf.tmpl | 7 +- .../bin/executable_hypr-workspace-layout | 100 ++++++++++++++++++ 3 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 dot_local/bin/executable_hypr-workspace-layout diff --git a/dot_config/hypr/hyprland.d/50-layout.conf b/dot_config/hypr/hyprland.d/50-layout.conf index f92fb3d..6f3ebe4 100644 --- a/dot_config/hypr/hyprland.d/50-layout.conf +++ b/dot_config/hypr/hyprland.d/50-layout.conf @@ -13,6 +13,11 @@ master { drop_at_cursor = true } +scrolling { + fullscreen_on_one_column = false + focus_fit_method = 0 +} + # https://wiki.hyprland.org/Configuring/Variables/#misc misc { force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers diff --git a/dot_config/hypr/hyprland.d/70-keybinds.conf.tmpl b/dot_config/hypr/hyprland.d/70-keybinds.conf.tmpl index de83d47..4ed9136 100644 --- a/dot_config/hypr/hyprland.d/70-keybinds.conf.tmpl +++ b/dot_config/hypr/hyprland.d/70-keybinds.conf.tmpl @@ -100,8 +100,11 @@ bind = $mainMod CTRL SHIFT, Tab, layoutmsg, rollnext # Scrolling layout bind = $mainMod, comma, layoutmsg, move -col bind = $mainMod, period, layoutmsg, move +col -bind = $mainMod CTRL, comma, layoutmsg, fit active -bind = $mainMod CTRL, period, layoutmsg, togglefit +bind = $mainMod CTRL, comma, layoutmsg, colresize 0.9 +bind = $mainMod CTRL, period, layoutmsg, fit active +bind = $mainMod CTRL SHIFT, period, layoutmsg, togglefit +bind = $mainMod ALT, comma, exec, hypr-workspace-layout toggle-ms +bind = $mainMod ALT, period, exec, hypr-workspace-layout cycle # MOVE FOCUS with mainMod + vim keys bind = $mainMod, H, movefocus, l diff --git a/dot_local/bin/executable_hypr-workspace-layout b/dot_local/bin/executable_hypr-workspace-layout new file mode 100644 index 0000000..2644439 --- /dev/null +++ b/dot_local/bin/executable_hypr-workspace-layout @@ -0,0 +1,100 @@ +#!/usr/bin/env bash +set -euo pipefail + +mode="${1:-}" +if [[ "$mode" != "toggle-ms" && "$mode" != "cycle" ]]; then + printf 'Usage: %s {toggle-ms|cycle}\n' "${0##*/}" >&2 + exit 2 +fi + +if ! command -v hyprctl >/dev/null 2>&1; then + echo "hyprctl not found" >&2 + exit 1 +fi + +active_json="$(hyprctl -j activeworkspace 2>/dev/null || true)" +if [[ -z "$active_json" ]]; then + echo "failed to query active workspace" >&2 + exit 1 +fi + +active_name="" +active_id="" +if command -v jq >/dev/null 2>&1; then + active_name="$(printf '%s' "$active_json" | jq -r '.name // empty')" + active_id="$(printf '%s' "$active_json" | jq -r '.id // empty')" +else + active_name="$(printf '%s' "$active_json" | sed -n 's/.*"name":"\([^"]*\)".*/\1/p')" + active_id="$(printf '%s' "$active_json" | sed -n 's/.*"id":\([0-9-]\+\).*/\1/p')" +fi + +if [[ -z "$active_name" && -z "$active_id" ]]; then + echo "could not parse active workspace" >&2 + exit 1 +fi + +if [[ -n "$active_name" && ! "$active_name" =~ ^[0-9]+$ ]]; then + ws_selector="name:$active_name" + ws_key="name:$active_name" +else + ws_id="${active_id:-$active_name}" + ws_selector="$ws_id" + ws_key="id:$ws_id" +fi + +state_file="${XDG_RUNTIME_DIR:-/tmp}/hypr-workspace-layout-state" + +get_state() { + local key="$1" + if [[ -f "$state_file" ]]; then + awk -F '\t' -v k="$key" '$1 == k {v = $2} END {print v}' "$state_file" + fi +} + +set_state() { + local key="$1" + local layout="$2" + local tmp + tmp="$(mktemp "${state_file}.XXXXXX")" + + if [[ -f "$state_file" ]]; then + awk -F '\t' -v k="$key" '$1 != k {print $1 "\t" $2}' "$state_file" > "$tmp" + fi + + printf '%s\t%s\n' "$key" "$layout" >> "$tmp" + mv "$tmp" "$state_file" +} + +default_layout="master" +if [[ "$ws_selector" == "name:comms" || "$ws_selector" == "name:steam" ]]; then + default_layout="scrolling" +fi + +current_layout="$(get_state "$ws_key")" +if [[ -z "$current_layout" ]]; then + current_layout="$default_layout" +fi + +if [[ "$mode" == "toggle-ms" ]]; then + if [[ "$current_layout" == "master" ]]; then + next_layout="scrolling" + else + next_layout="master" + fi +else + layouts=(dwindle master scrolling monocle) + next_layout="${layouts[0]}" + + for i in "${!layouts[@]}"; do + if [[ "${layouts[$i]}" == "$current_layout" ]]; then + next_layout="${layouts[$(((i + 1) % ${#layouts[@]}))]}" + break + fi + done +fi + +hyprctl keyword workspace "$ws_selector,layout:$next_layout" >/dev/null +set_state "$ws_key" "$next_layout" + +# Best-effort notification so layout switches are visible immediately. +hyprctl notify -1 1800 "rgb(8bd5ca)" "Layout: ${next_layout} (${ws_selector})" >/dev/null 2>&1 || true