diff --git a/bin/omarchy-hyprland-monitor-clamshell b/bin/omarchy-hyprland-monitor-clamshell index dc896317..86c893fc 100755 --- a/bin/omarchy-hyprland-monitor-clamshell +++ b/bin/omarchy-hyprland-monitor-clamshell @@ -6,21 +6,70 @@ TOGGLES_DIR="$HOME/.local/state/omarchy/toggles/hypr" CLAMSHELL_FLAG="$TOGGLES_DIR/internal-monitor-clamshell.lua" MANUAL_DISABLE_FLAG="$TOGGLES_DIR/internal-monitor-disable.lua" +SCALE_STATE="$TOGGLES_DIR/internal-monitor-scale" INTERNAL=$(hyprctl monitors all -j | jq -r '.[] | select(.name | contains("eDP")).name' | head -n 1) -read_monitor_scale() { +valid_scale() { + [[ $1 =~ ^[0-9]+([.][0-9]+)?$ ]] +} + +configured_monitor_scale() { local monitor_lua="$HOME/.config/hypr/monitors.lua" - [[ -f $monitor_lua ]] || { echo '"auto"'; return; } + [[ -f $monitor_lua ]] || return 0 local scale scale=$(sed -n 's/^local omarchy_monitor_scale = //p' "$monitor_lua" | head -1) if [[ -z $scale ]]; then scale=$(sed -nE 's/^hl\.monitor\(\{ output = "", mode = "preferred", position = "auto", scale = ([^ ]+) \}\)/\1/p' "$monitor_lua" | head -1) fi - [[ -z $scale ]] && scale='"auto"' echo "$scale" } +current_internal_scale() { + [[ -n $INTERNAL ]] || return 0 + hyprctl monitors all -j | jq -r --arg internal "$INTERNAL" '.[] | select(.name == $internal and .disabled != true) | .scale' | head -1 +} + +store_internal_scale() { + local scale="$1" + valid_scale "$scale" || return 0 + + mkdir -p "$TOGGLES_DIR" + printf '%s\n' "$scale" >"$SCALE_STATE" +} + +remember_internal_scale() { + local scale + scale=$(current_internal_scale) + store_internal_scale "$scale" +} + +read_monitor_scale() { + local scale + scale=$(configured_monitor_scale) + if valid_scale "$scale"; then + echo "$scale" + return + fi + + scale=$(current_internal_scale) + if valid_scale "$scale"; then + store_internal_scale "$scale" + echo "$scale" + return + fi + + if [[ -f $SCALE_STATE ]]; then + scale=$(<"$SCALE_STATE") + if valid_scale "$scale"; then + echo "$scale" + return + fi + fi + + echo 2 +} + enable_internal_output() { [[ -n $INTERNAL ]] || return 0 local scale @@ -48,6 +97,7 @@ enable_internal() { fi [[ -f $MANUAL_DISABLE_FLAG ]] && omarchy-hyprland-monitor-external-active && return 0 + remember_internal_scale enable_internal_output dpms_internal enable } @@ -57,6 +107,7 @@ disable_internal() { [[ -f $MANUAL_DISABLE_FLAG ]] && return 0 mkdir -p "$TOGGLES_DIR" + remember_internal_scale local config config=$(printf 'hl.monitor({ output = "%s", disabled = true })' "$INTERNAL") diff --git a/test/shell.d/monitor-clamshell-scale-test.sh b/test/shell.d/monitor-clamshell-scale-test.sh new file mode 100644 index 00000000..6acc7892 --- /dev/null +++ b/test/shell.d/monitor-clamshell-scale-test.sh @@ -0,0 +1,99 @@ +#!/bin/bash + +set -euo pipefail + +source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh" + +test_tmp=$(mktemp -d) +trap 'rm -rf "$test_tmp"' EXIT + +stub_bin="$test_tmp/bin" +home_dir="$test_tmp/home" +monitor_lua="$home_dir/.config/hypr/monitors.lua" +eval_log="$test_tmp/hyprctl-eval.log" +state_dir="$home_dir/.local/state/omarchy/toggles/hypr" +scale_state="$state_dir/internal-monitor-scale" + +mkdir -p "$stub_bin" "$home_dir/.config/hypr" + +cat >"$stub_bin/hyprctl" <<'SH' +#!/bin/bash + +if [[ $1 == "monitors" && $2 == "all" && $3 == "-j" ]]; then + if [[ ${OMARCHY_TEST_INTERNAL_DISABLED:-false} == "true" ]]; then + printf '[{"name":"eDP-1","disabled":true,"scale":null}]' + else + printf '[{"name":"eDP-1","disabled":false,"scale":%s}]' "${OMARCHY_TEST_INTERNAL_SCALE:-2}" + fi +elif [[ $1 == "eval" ]]; then + printf '%s\n' "$2" >>"$OMARCHY_TEST_HYPRCTL_EVAL_LOG" +elif [[ $1 == "reload" ]]; then + printf 'reload\n' >>"$OMARCHY_TEST_HYPRCTL_EVAL_LOG" +elif [[ $1 == "dispatch" ]]; then + printf 'dispatch %s\n' "$2" >>"$OMARCHY_TEST_HYPRCTL_EVAL_LOG" +else + exit 1 +fi +SH + +cat >"$stub_bin/omarchy-hyprland-monitor-internal" <<'SH' +#!/bin/bash +exit 0 +SH + +cat >"$stub_bin/omarchy-hyprland-monitor-internal-mirror" <<'SH' +#!/bin/bash +exit 0 +SH + +cat >"$stub_bin/omarchy-hyprland-monitor-external-active" <<'SH' +#!/bin/bash +[[ ${OMARCHY_TEST_EXTERNAL_ACTIVE:-false} == "true" ]] +SH + +cat >"$stub_bin/omarchy-hw-clamshell" <<'SH' +#!/bin/bash +[[ ${OMARCHY_TEST_CLAMSHELL:-false} == "true" ]] +SH + +chmod +x "$stub_bin"/* + +write_auto_monitor_config() { + cat >"$monitor_lua" <<'LUA' +local omarchy_gdk_scale = 2 +local omarchy_monitor_scale = "auto" +LUA +} + +run_clamshell() { + HOME="$home_dir" \ + PATH="$stub_bin:$PATH" \ + OMARCHY_TEST_HYPRCTL_EVAL_LOG="$eval_log" \ + OMARCHY_TEST_INTERNAL_SCALE="${OMARCHY_TEST_INTERNAL_SCALE:-2}" \ + OMARCHY_TEST_INTERNAL_DISABLED="${OMARCHY_TEST_INTERNAL_DISABLED:-false}" \ + OMARCHY_TEST_EXTERNAL_ACTIVE="${OMARCHY_TEST_EXTERNAL_ACTIVE:-false}" \ + OMARCHY_TEST_CLAMSHELL="${OMARCHY_TEST_CLAMSHELL:-false}" \ + "$ROOT/bin/omarchy-hyprland-monitor-clamshell" +} + +write_auto_monitor_config +: >"$eval_log" +OMARCHY_TEST_INTERNAL_SCALE=2 run_clamshell +grep -F 'scale = 2' "$eval_log" >/dev/null || fail "clamshell recovery uses current internal scale instead of auto" +! grep -F 'scale = "auto"' "$eval_log" >/dev/null || fail "clamshell recovery does not apply auto scale" +[[ -f $scale_state ]] || fail "clamshell recovery remembers current internal scale" +[[ $(<"$scale_state") == "2" ]] || fail "clamshell recovery remembers current internal scale value" +pass "clamshell recovery uses current internal scale instead of auto" + +write_auto_monitor_config +: >"$eval_log" +OMARCHY_TEST_INTERNAL_SCALE=1.6 OMARCHY_TEST_EXTERNAL_ACTIVE=true OMARCHY_TEST_CLAMSHELL=true run_clamshell +[[ -f $scale_state ]] || fail "clamshell disable remembers internal scale" +[[ $(<"$scale_state") == "1.6" ]] || fail "clamshell disable remembers internal scale value" +pass "clamshell disable remembers internal scale" + +: >"$eval_log" +OMARCHY_TEST_INTERNAL_DISABLED=true run_clamshell +grep -F 'scale = 1.6' "$eval_log" >/dev/null || fail "clamshell recovery uses remembered internal scale" +! grep -F 'scale = "auto"' "$eval_log" >/dev/null || fail "clamshell recovery avoids auto after disabled internal display" +pass "clamshell recovery uses remembered internal scale"