From a95505fc3ad3f6a4007fdbc3f6df53304859fcda Mon Sep 17 00:00:00 2001 From: Ivan Malison Date: Tue, 31 Mar 2026 11:24:50 -0700 Subject: [PATCH] hyprland: use builtin previous-workspace toggle --- dotfiles/config/hypr/hyprland.conf | 8 +- .../config/hypr/scripts/workspace-back.sh | 71 ---------- .../hypr/scripts/workspace-history-common.sh | 127 ------------------ .../config/hypr/scripts/workspace-history.sh | 46 ------- 4 files changed, 3 insertions(+), 249 deletions(-) delete mode 100755 dotfiles/config/hypr/scripts/workspace-back.sh delete mode 100644 dotfiles/config/hypr/scripts/workspace-history-common.sh delete mode 100755 dotfiles/config/hypr/scripts/workspace-history.sh diff --git a/dotfiles/config/hypr/hyprland.conf b/dotfiles/config/hypr/hyprland.conf index 28312bc5..f6044d55 100644 --- a/dotfiles/config/hypr/hyprland.conf +++ b/dotfiles/config/hypr/hyprland.conf @@ -444,10 +444,9 @@ bind = $mainMod CTRL, 8, workspace, 8 bind = $mainMod CTRL, 9, movetoworkspacesilent, 9 bind = $mainMod CTRL, 9, workspace, 9 -# Workspace cycling with monitor-local history and commit-on-release semantics. -bind = $mainMod, backslash, exec, ~/.config/hypr/scripts/workspace-back.sh cycle -bindr = , SUPER_L, exec, ~/.config/hypr/scripts/workspace-back.sh finalize -bindr = , SUPER_R, exec, ~/.config/hypr/scripts/workspace-back.sh finalize +# Toggle to the previous workspace on the current monitor using Hyprland's +# built-in per-monitor workspace history. +bind = $mainMod, backslash, workspace, previous_per_monitor # Swap current workspace with another (like XMonad's swapWithCurrent) bind = $hyper, 5, exec, ~/.config/hypr/scripts/swap-workspaces.sh @@ -556,7 +555,6 @@ exec-once = sh -lc 'export IMALISON_SESSION_TYPE=wayland; dbus-update-activation # Force a fresh daemon after compositor restarts so hyprscratch doesn't keep a stale socket. exec-once = systemctl --user restart hyprscratch.service exec-once = hypridle -exec-once = ~/.config/hypr/scripts/workspace-history.sh # Clipboard history daemon exec-once = wl-paste --type text --watch cliphist store diff --git a/dotfiles/config/hypr/scripts/workspace-back.sh b/dotfiles/config/hypr/scripts/workspace-back.sh deleted file mode 100755 index 1e51a1c3..00000000 --- a/dotfiles/config/hypr/scripts/workspace-back.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=workspace-history-common.sh -# shellcheck source-path=SCRIPTDIR -source "${script_dir}/workspace-history-common.sh" - -action="${1:-cycle}" - -exec 9>"${lock_file}" -flock 9 - -state="$(wh_load_state)" -monitors_json="$(wh_monitors_json)" -state="$(wh_refresh_state_json "${state}" "${monitors_json}")" - -focused_monitor="$( - jq -r '.[] | select(.focused == true) | .name // empty' <<<"${monitors_json}" | head -n 1 -)" - -if [[ -z "${focused_monitor}" ]]; then - wh_save_state "${state}" - exit 0 -fi - -current_workspace="$(jq -r --arg monitor "${focused_monitor}" '.monitorCurrent[$monitor] // empty' <<<"${state}")" - -case "${action}" in -cycle) - next_workspace="$( - jq -r \ - --arg monitor "${focused_monitor}" \ - --arg current "${current_workspace}" \ - ' - (.monitorHistory[$monitor] // []) as $history - | if ($history | length) < 2 then - "" - else - ($history | index($current)) as $idx - | if $idx == null then - "" - else - $history[(($idx + 1) % ($history | length))] - end - end - ' <<<"${state}" - )" - - if [[ -z "${next_workspace}" || "${next_workspace}" == "${current_workspace}" ]]; then - wh_save_state "${state}" - exit 0 - fi - - state="$( - jq -c \ - --arg monitor "${focused_monitor}" \ - '.cycle = {"active": true, "monitor": $monitor}' <<<"${state}" - )" - wh_save_state "${state}" - hyprctl dispatch workspace "${next_workspace}" >/dev/null 2>&1 || true - ;; -finalize) - state="$(wh_finalize_cycle_json "${state}")" - wh_save_state "${state}" - ;; -*) - printf 'Unknown action: %s\n' "${action}" >&2 - exit 1 - ;; -esac diff --git a/dotfiles/config/hypr/scripts/workspace-history-common.sh b/dotfiles/config/hypr/scripts/workspace-history-common.sh deleted file mode 100644 index f3f9e1d5..00000000 --- a/dotfiles/config/hypr/scripts/workspace-history-common.sh +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/env bash - -max_ws="${HYPR_MAX_WORKSPACE:-9}" - -runtime_dir="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}" -state_dir="${HYPR_WORKSPACE_STATE_DIR:-${runtime_dir}/hypr}" -state_file="${state_dir}/workspace-history.json" -# shellcheck disable=SC2034 # Sourced by sibling scripts that coordinate updates. -lock_file="${state_dir}/workspace-history.lock" - -mkdir -p "${state_dir}" - -wh_default_state() { - cat <<'EOF' -{"monitorCurrent":{},"monitorHistory":{},"cycle":{"active":false}} -EOF -} - -wh_load_state() { - local state - if [[ -s "${state_file}" ]] && state="$(jq -c '.' "${state_file}" 2>/dev/null)"; then - printf '%s\n' "${state}" - return - fi - - wh_default_state -} - -wh_save_state() { - local state="$1" - local tmp_file - - tmp_file="$(mktemp "${state_file}.XXXXXX")" - printf '%s\n' "${state}" >"${tmp_file}" - mv "${tmp_file}" "${state_file}" -} - -wh_normalize_workspace() { - local ws_id="${1:-}" - local ws_name="${2:-}" - - if [[ -n "${ws_name}" && "${ws_name}" != "null" && "${ws_name}" != special:* ]]; then - printf '%s\n' "${ws_name}" - return - fi - - if [[ -z "${ws_id}" || "${ws_id}" == "null" || "${ws_id}" =~ ^- ]]; then - return - fi - - if [[ "${ws_id}" =~ ^[0-9]+$ ]] && ((ws_id >= 1 && ws_id <= max_ws)); then - printf '%s\n' "${ws_id}" - fi -} - -wh_monitors_json() { - hyprctl -j monitors 2>/dev/null || printf '[]\n' -} - -wh_refresh_state_json() { - local state="$1" - local monitors_json="$2" - local row - local monitor - local ws_id - local ws_name - local workspace - - while IFS= read -r row; do - [[ -z "${row}" ]] && continue - - monitor="$(jq -r '.name // empty' <<<"${row}")" - ws_id="$(jq -r '.activeWorkspace.id // empty' <<<"${row}")" - ws_name="$(jq -r '.activeWorkspace.name // empty' <<<"${row}")" - workspace="$(wh_normalize_workspace "${ws_id}" "${ws_name}")" - - [[ -z "${monitor}" || -z "${workspace}" ]] && continue - - state="$( - jq -c \ - --arg monitor "${monitor}" \ - --arg workspace "${workspace}" \ - ' - .monitorCurrent[$monitor] = $workspace - | if .cycle.active == true and .cycle.monitor == $monitor then - . - else - .monitorHistory[$monitor] = - ([$workspace] + ((.monitorHistory[$monitor] // []) | map(select(. != $workspace)))) - end - ' <<<"${state}" - )" - done < <(jq -c '.[]' <<<"${monitors_json}") - - printf '%s\n' "${state}" -} - -wh_finalize_cycle_json() { - local state="$1" - local monitor - local current - - if [[ "$(jq -r '.cycle.active // false' <<<"${state}")" != "true" ]]; then - printf '%s\n' "${state}" - return - fi - - monitor="$(jq -r '.cycle.monitor // empty' <<<"${state}")" - current="$(jq -r --arg monitor "${monitor}" '.monitorCurrent[$monitor] // empty' <<<"${state}")" - - if [[ -n "${monitor}" && -n "${current}" ]]; then - state="$( - jq -c \ - --arg monitor "${monitor}" \ - --arg current "${current}" \ - ' - .monitorHistory[$monitor] = - ([$current] + ((.monitorHistory[$monitor] // []) | map(select(. != $current)))) - | .cycle = {"active": false} - ' <<<"${state}" - )" - else - state="$(jq -c '.cycle = {"active": false}' <<<"${state}")" - fi - - printf '%s\n' "${state}" -} diff --git a/dotfiles/config/hypr/scripts/workspace-history.sh b/dotfiles/config/hypr/scripts/workspace-history.sh deleted file mode 100755 index 77ab43e0..00000000 --- a/dotfiles/config/hypr/scripts/workspace-history.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=workspace-history-common.sh -# shellcheck source-path=SCRIPTDIR -source "${script_dir}/workspace-history-common.sh" - -runtime_dir="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}" -sig="${HYPRLAND_INSTANCE_SIGNATURE:-}" -if [[ -z "$sig" ]]; then - exit 0 -fi - -sock="${runtime_dir}/hypr/${sig}/.socket2.sock" - -with_history_lock() { - exec 9>"${lock_file}" - flock 9 - "$@" -} - -refresh_history_state() { - local state - local monitors_json - - state="$(wh_load_state)" - monitors_json="$(wh_monitors_json)" - state="$(wh_refresh_state_json "${state}" "${monitors_json}")" - wh_save_state "${state}" -} - -with_history_lock refresh_history_state - -# Wait for the event socket to be ready. -while [[ ! -S "${sock}" ]]; do - sleep 0.2 -done - -nc -U "${sock}" | while read -r line; do - case "${line}" in - workspace*">>"*) - with_history_lock refresh_history_state - ;; - esac -done