linux-change-hz-on-ac.md
edited
1## Install `displayconfig-mutter` (Fedora)
2```sh
3sudo dnf copr enable eaglesemanation/displayconfig-mutter
4sudo dnf install displayconfig-mutter
5```
6```sh
7displayconfig-mutter list
8```
9should return something along the lines of
10```sh
11┌───────────┬────────┬──────────────┬────────────┬──────────────┬─────────────────────┬─────┬─────┐
12│ Connector │ Vendor │ Product name │ Resolution │ Refresh rate │ Scaling │ VRR │ HDR │
13├───────────┼────────┼──────────────┼────────────┼──────────────┼─────────────────────┼─────┼─────┤
14│ eDP-1 │ CSW │ MNG007ZA1-3 │ 3200x2000 │ 60 │ 166.66666269302368% │ No │ No │
15└───────────┴────────┴──────────────┴────────────┴──────────────┴─────────────────────┴─────┴─────┘
16```
17In this case, my monitor is `eDP-1`.
18
19## Configure your env
20Here, you configure your desired connector (aka, your display), the framerate for when your laptop is unplugged (`LOW_HZ`) and the framerate for when AC is connected (`HIGH_HZ`).
21```sh
22cat > ~/.config/rr-autoswitch.env <<'EOF'
23CONNECTOR=eDP-1
24LOW_HZ=60
25HIGH_HZ=165
26EOF
27```
28
29## Create the service
30```sh
31cat > ~/.local/bin/rr-watch-ac.sh <<'EOF'
32#!/usr/bin/env bash
33set -euo pipefail
34
35# Allow overrides via ~/.config/rr-autoswitch.env
36[ -f "$HOME/.config/rr-autoswitch.env" ] && source "$HOME/.config/rr-autoswitch.env"
37CONNECTOR="${CONNECTOR:-eDP-1}"
38LOW_HZ="${LOW_HZ:-60}"
39HIGH_HZ="${HIGH_HZ:-165}"
40
41apply_rr() {
42 local hz="$1"
43 # Keep current resolution, only change refresh rate
44 displayconfig-mutter set --connector "$CONNECTOR" --refresh-rate "$hz"
45}
46
47on_battery_now() {
48 # returns 0 if on battery, 1 otherwise
49 busctl get-property org.freedesktop.UPower /org/freedesktop/UPower org.freedesktop.UPower OnBattery \
50 | grep -q 'true'
51}
52
53# Apply once at start
54if on_battery_now; then apply_rr "$LOW_HZ"; else apply_rr "$HIGH_HZ"; fi
55
56# React to future changes (UPower PropertiesChanged on /org/freedesktop/UPower)
57dbus-monitor --system "type='signal',sender='org.freedesktop.UPower',\
58interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',\
59path='/org/freedesktop/UPower'" \
60| while read -r line; do
61 if grep -q "OnBattery" <<<"$line"; then
62 # tiny debounce so we read the new state
63 sleep 0.3
64 if on_battery_now; then apply_rr "$LOW_HZ"; else apply_rr "$HIGH_HZ"; fi
65 fi
66 done
67EOF
68```
69```sh
70chmod +x ~/.local/bin/rr-watch-ac.sh
71```
72```sh
73cat > ~/.config/systemd/user/rr-autoswitch.service <<'EOF'
74[Unit]
75Description=Auto-switch monitor refresh rate on AC/battery (Wayland/GNOME)
76After=graphical-session.target
77Wants=graphical-session.target
78
79[Service]
80EnvironmentFile=%h/.config/rr-autoswitch.env
81ExecStart=%h/.local/bin/rr-watch-ac.sh
82Restart=always
83RestartSec=1
84
85[Install]
86WantedBy=default.target
87EOF
88```
89```sh
90systemctl --user daemon-reload
91systemctl --user enable --now rr-autoswitch.service
92```