hyprland: use builtin previous-workspace toggle

This commit is contained in:
2026-03-31 11:24:50 -07:00
committed by Kat Huang
parent 56cb75e072
commit a95505fc3a
4 changed files with 3 additions and 249 deletions

View File

@@ -444,10 +444,9 @@ bind = $mainMod CTRL, 8, workspace, 8
bind = $mainMod CTRL, 9, movetoworkspacesilent, 9 bind = $mainMod CTRL, 9, movetoworkspacesilent, 9
bind = $mainMod CTRL, 9, workspace, 9 bind = $mainMod CTRL, 9, workspace, 9
# Workspace cycling with monitor-local history and commit-on-release semantics. # Toggle to the previous workspace on the current monitor using Hyprland's
bind = $mainMod, backslash, exec, ~/.config/hypr/scripts/workspace-back.sh cycle # built-in per-monitor workspace history.
bindr = , SUPER_L, exec, ~/.config/hypr/scripts/workspace-back.sh finalize bind = $mainMod, backslash, workspace, previous_per_monitor
bindr = , SUPER_R, exec, ~/.config/hypr/scripts/workspace-back.sh finalize
# Swap current workspace with another (like XMonad's swapWithCurrent) # Swap current workspace with another (like XMonad's swapWithCurrent)
bind = $hyper, 5, exec, ~/.config/hypr/scripts/swap-workspaces.sh 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. # Force a fresh daemon after compositor restarts so hyprscratch doesn't keep a stale socket.
exec-once = systemctl --user restart hyprscratch.service exec-once = systemctl --user restart hyprscratch.service
exec-once = hypridle exec-once = hypridle
exec-once = ~/.config/hypr/scripts/workspace-history.sh
# Clipboard history daemon # Clipboard history daemon
exec-once = wl-paste --type text --watch cliphist store exec-once = wl-paste --type text --watch cliphist store

View File

@@ -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

View File

@@ -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}"
}

View File

@@ -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