diff --git a/bin/omarchy-brightness-display b/bin/omarchy-brightness-display index a6a1e8304bf..56045554926 100755 --- a/bin/omarchy-brightness-display +++ b/bin/omarchy-brightness-display @@ -35,12 +35,38 @@ monitor_is_internal() { [[ $monitor =~ ^(eDP|LVDS|DSI)- ]] } +# Hyprland monitor names are DRM connector names, so a backlight the kernel registers on an external +# connector (e.g. a display whose brightness the GPU driver controls) belongs to this monitor. It wins +# over the Apple and DDC fallbacks, which go through slower side channels. Internal panels keep +# omarchy-hw-display's heuristic: GPU drivers also register on the eDP connector a backlight that +# may not be the one driving the panel (gmux on dual-GPU Macs). +# Only a connected connector counts: another card can expose a connector with the same name. +connector_backlight() { + local subsystem + + if [[ -z $monitor ]] || monitor_is_internal; then + return 1 + fi + + for subsystem in "${OMARCHY_DRM_PATH:-/sys/class/drm}"/card*-"$monitor"/*/subsystem; do + if [[ $(<"${subsystem%/*/subsystem}/status") == "connected" && $(readlink "$subsystem") == */class/backlight ]]; then + subsystem="${subsystem%/subsystem}" + printf '%s\n' "${subsystem##*/}" + return 0 + fi + done + + return 1 +} + +device="$(connector_backlight)" + use_apple_display() { - omarchy-hyprland-monitor-focused-apple "$monitor" + [[ -z $device ]] && omarchy-hyprland-monitor-focused-apple "$monitor" } use_ddc_display() { - [[ -n $monitor ]] && ! monitor_is_internal + [[ -z $device && -n $monitor ]] && ! monitor_is_internal } if (( $# == 0 )); then @@ -52,7 +78,7 @@ if (( $# == 0 )); then exit fi - device="$(omarchy-hw-display)" || exit 1 + [[ -n $device ]] || device="$(omarchy-hw-display)" || exit 1 backlight_brightness "$device" exit fi @@ -86,8 +112,8 @@ elif use_ddc_display; then brightness="$(omarchy-brightness-display-ddc "$monitor" "$step")" || exit 1 (( no_osd )) || omarchy-osd -i brightness -p "$brightness" else - # Current device highlighted - device="$(omarchy-hw-display)" || exit 1 + # The focused connector's backlight, else the most likely panel backlight + [[ -n $device ]] || device="$(omarchy-hw-display)" || exit 1 # Current brightness percentage current=$(backlight_brightness "$device") || exit 1 diff --git a/test/shell.d/brightness-display-test.sh b/test/shell.d/brightness-display-test.sh index 3e41c511ae0..ce5b162d054 100755 --- a/test/shell.d/brightness-display-test.sh +++ b/test/shell.d/brightness-display-test.sh @@ -10,11 +10,38 @@ trap 'rm -rf "$test_tmp"' EXIT mock_bin="$test_tmp/bin" call_log="$test_tmp/calls" runtime_dir="$test_tmp/runtime" +drm_dir="$test_tmp/drm" mkdir -p "$mock_bin" "$runtime_dir" +# DP-3 has a kernel backlight registered on its connector, as external displays that support it do. +# DP-1's connector only has a non-backlight child. eDP-1's connector has a GPU backlight, as i915 +# registers, which must not override omarchy-hw-display's pick for the internal panel. card1 has a +# disconnected DP-3 of its own with a backlight, which must not be mistaken for the focused DP-3. +mkdir -p "$drm_dir/card2-DP-3/apple-DP-3-bl" "$drm_dir/card2-DP-1/power" "$drm_dir/card0-eDP-1/intel_backlight" \ + "$drm_dir/card1-DP-3/other-DP-3-bl" +ln -s ../../../../class/backlight "$drm_dir/card2-DP-3/apple-DP-3-bl/subsystem" +ln -s ../../../../class/backlight "$drm_dir/card0-eDP-1/intel_backlight/subsystem" +ln -s ../../../../bus/platform "$drm_dir/card2-DP-1/power/subsystem" +ln -s ../../../../class/backlight "$drm_dir/card1-DP-3/other-DP-3-bl/subsystem" +for connector in card2-DP-3 card2-DP-1 card0-eDP-1; do + printf 'connected\n' >"$drm_dir/$connector/status" +done +printf 'disconnected\n' >"$drm_dir/card1-DP-3/status" + cat >"$mock_bin/omarchy-hyprland-monitor-focused-apple" <<'SH' #!/bin/bash -exit 1 +printf 'omarchy-hyprland-monitor-focused-apple %s\n' "$*" >>"$CALL_LOG" +[[ ${APPLE_DISPLAY:-0} == "1" ]] +SH + +cat >"$mock_bin/omarchy-brightness-display-apple" <<'SH' +#!/bin/bash +printf 'omarchy-brightness-display-apple %s\n' "$*" >>"$CALL_LOG" +SH + +cat >"$mock_bin/omarchy-osd" <<'SH' +#!/bin/bash +printf 'omarchy-osd %s\n' "$*" >>"$CALL_LOG" SH cat >"$mock_bin/omarchy-hyprland-monitor-focused" <<'SH' @@ -54,7 +81,7 @@ SH chmod +x "$mock_bin"/* run_brightness() { - CALL_LOG="$call_log" XDG_RUNTIME_DIR="$runtime_dir" PATH="$mock_bin:$ROOT/bin:$PATH" \ + CALL_LOG="$call_log" XDG_RUNTIME_DIR="$runtime_dir" OMARCHY_DRM_PATH="$drm_dir" PATH="$mock_bin:$ROOT/bin:$PATH" \ "$ROOT/bin/omarchy-brightness-display" "$@" } @@ -129,6 +156,36 @@ grep -F 'ddcutil --bus 7 --skip-ddc-checks --noverify setvcp 10 5' "$call_log" > fail "external low brightness writes the one-percent target" pass "external low brightness uses a one-percent step" +: >"$call_log" +brightness=$(APPLE_DISPLAY=1 run_brightness --monitor DP-3) +[[ $brightness == "40" ]] || fail "connector backlight reports brightness" "actual: $brightness" +grep -F 'brightnessctl -d apple-DP-3-bl -m' "$call_log" >/dev/null || \ + fail "connector backlight is queried through brightnessctl" +pass "connector backlight reports brightness" + +: >"$call_log" +APPLE_DISPLAY=1 run_brightness --monitor DP-3 +5% +grep -Fx 'brightnessctl -d apple-DP-3-bl set 45%' "$call_log" >/dev/null || \ + fail "connector backlight steps through brightnessctl" "$(cat "$call_log")" +grep -Fx 'omarchy-osd -i brightness -p 40' "$call_log" >/dev/null || \ + fail "connector backlight shows the OSD" +if grep -E 'omarchy-brightness-display-apple|omarchy-hyprland-monitor-focused-apple|ddcutil' "$call_log"; then + fail "connector backlight skips the Apple and DDC backends" +fi +pass "connector backlight wins over the Apple and DDC backends" + +: >"$call_log" +FOCUSED_MONITOR=DP-3 run_brightness --no-osd 1%- +grep -Fx 'brightnessctl -d apple-DP-3-bl set 1%-' "$call_log" >/dev/null || \ + fail "focused monitor's connector backlight takes precise steps" "$(cat "$call_log")" +pass "focused monitor's connector backlight takes precise steps" + +: >"$call_log" +APPLE_DISPLAY=1 run_brightness --no-osd --monitor DP-1 +5% +grep -Fx 'omarchy-brightness-display-apple --no-osd +5%' "$call_log" >/dev/null || \ + fail "Apple display without a connector backlight keeps asdcontrol" "$(cat "$call_log")" +pass "Apple display without a connector backlight keeps asdcontrol" + cat >"$mock_bin/hyprctl" <<'SH' #!/bin/bash printf '%s\n' '[