Last active
May 3, 2026 15:58
-
-
Save khromalabs/ee2eca3f557d1696e5612b7d15ac813b to your computer and use it in GitHub Desktop.
Auto dim external screen when there's no activity
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # This script will auto-dim an external screen if the mouse is outside the external screen, or if there's no window sitting | |
| # in the external screen. Meant to be polling in the background (every 2 seconds) | |
| # Supports scaling. | |
| # Requires: xdotool, wmctrl, xrandr, ddcutil | |
| # Find your external screen $MONITOR_ID using: `ddcutil detect -t` | |
| DEBUG=0 | |
| MONITOR_ID="1" | |
| function get_bright_last() | |
| { | |
| echo "$(ddcutil getvcp 10 -t --display $MONITOR_ID | tail -1 | awk '{print $4}')" | |
| } | |
| # $1=scaled size $2=physical size | |
| function get_mouse_location_x() | |
| { | |
| eval $(xdotool getmouselocation --shell) | |
| # Scale factors (from 1920x1080 → 2954x1662) | |
| scale_x=$1/$2 | |
| expr="$X/($1/$2)" | |
| number=$(echo "$expr" | bc -l) | |
| printf "%.0f" "$number" 2>/dev/null | |
| } | |
| function echodebug() | |
| { | |
| if [ "$DEBUG" == "1" ]; then | |
| echo "$1" | |
| fi | |
| } | |
| function has_windows_on_external() { | |
| awk_expr='$3 >= ' | |
| awk_expr+=" $laptop_width_full " | |
| awk_expr+=' {print $0}' | |
| window_count=$(wmctrl -lG | awk "$awk_expr" | wc -l) | |
| if [ "$window_count" -gt 1 ]; then | |
| echo 1 | |
| else | |
| echo 0 | |
| fi | |
| } | |
| BRIGHT_LAST="$(get_bright_last)" | |
| echodebug "BRIGHT_LAST: $BRIGHT_LAST" | |
| BRIGHT_MIN="0" | |
| LAST_STATE="none" | |
| LAPTOP_RES="$(xrandr --current | grep '*' | awk '{print $1}' | head -1)" | |
| LAPTOP_RES_FULL="$(xrandr --current | grep 'connected' | awk '{print $4}' | head -1)" | |
| echodebug "LAPTOP_RES: $LAPTOP_RES" | |
| echodebug "LAPTOP_RES_FULL: $LAPTOP_RES_FULL" | |
| IFS='x' read laptop_width laptop_height <<< "$LAPTOP_RES" | |
| IFS='x' read laptop_width_full laptop_height_full <<< "$LAPTOP_RES_FULL" | |
| echodebug "LAPTOP WIDTH: $laptop_width" | |
| echodebug "LAPTOP WIDTH FULL: $laptop_width_full" | |
| mouse_real_x="$(get_mouse_location_x $laptop_width_full $laptop_width)" | |
| trap 'ddcutil setvcp 10 $BRIGHT_LAST --display $MONITOR_ID' EXIT | |
| while true; do | |
| mouse_real_x="$(get_mouse_location_x $laptop_width_full $laptop_width)" | |
| echodebug "mouse_real_x: $mouse_real_x" | |
| echodebug "has_windows_on_external: $(has_windows_on_external $laptop_width_full)" | |
| if [ $mouse_real_x -ge $laptop_width -o $(has_windows_on_external $laptop_width_full) -gt 0 ]; then | |
| current_state="active" | |
| else | |
| current_state="idle" | |
| fi | |
| if [ "$current_state" != "$LAST_STATE" ]; then | |
| if [ "$current_state" == "idle" ]; then | |
| BRIGHT_LAST="$(get_bright_last)" | |
| echodebug "BRIGHT_LAST: $BRIGHT_LAST" | |
| ddcutil setvcp 10 0 --display $MONITOR_ID | |
| else | |
| ddcutil setvcp 10 $BRIGHT_LAST --display $MONITOR_ID | |
| fi | |
| LAST_STATE=$current_state | |
| fi | |
| sleep 2 | |
| done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment