モニタ接続時にxrandrを自動で実行する

提供: Akionux-wiki
Share/Save/Bookmark
移動先: 案内検索

概要

プライマリモニタとして使っているPC用のモニタと、拡張用にテレビをHDMIで繋いでいるんだけれど、テレビを消すと接続が切れてしまうので、繋ぎ直すのに毎回xrandrとか実行するのが面倒で、udevで接続時に自動でxrandrを実行してもらうようにしたときの記録。 以下、プライマリモニタがHDMI2、テレビがHDMI3で接続されるとする。

環境

  • Slackware 14.2 (x86_64)

参考にしたもの

手順

まず、次のコマンドでデバイスの状態を監視する。

udevadm monitor --environment --udev

これを実行してから、デバイスを抜き差ししてみて、情報を確認する。 モニタを抜き差しすると次のような情報が出てくる。

UDEV  [1212068.086939] change   /devices/pci0000:00/0000:00:02.0/drm/card0 (drm)
ACTION=change
DEVNAME=/dev/dri/card0
DEVPATH=/devices/pci0000:00/0000:00:02.0/drm/card0
DEVTYPE=drm_minor
DISPLAY=:0
HOTPLUG=1
ID_PATH=pci-0000:00:02.0
ID_PATH_TAG=pci-0000_00_02_0
MAJOR=226
MINOR=0
SEQNUM=6352
SUBSYSTEM=drm
TAGS=:udev-acl:
USEC_INITIALIZED=57590
XAUTHORITY=/home/hoge/.Xauthority

udevadm infoを使っても情報を確認可能[1]

udevadm info -a -p $(udevadm info -q path -n /dev/dri/card0)

デバイスの状態が変化したときに実行するシェルスクリプトを作成する。 [2]のスクリプトを改変した。

#!/bin/sh

dmode="$(cat /sys/class/drm/card0-HDMI-A-3/status)"
export DISPLAY=:0
export XAUTHORITY=/home/hoge/.Xauthority

if [ "${dmode}" = disconnected ]; then
  /usr/bin/xrandr --auto
elif [ "${dmode}" = connected ];then
  t=0
  while $(/usr/bin/xrandr | grep "HDMI3 disconnected" &> /dev/null);do
    sleep 1
    t=$((t+1))
    if [ $t -ge 60 ];then 
      break 
    fi 
  done
  /usr/bin/xrandr --output HDMI3 --mode 1920x1080 --left-of HDMI2
else /usr/bin/xrandr --auto
fi

私の環境ではデバイスの状態がconnectedであっても、xrandrでの状態がなぜかしばらくdisconnectedになっているらしく、connectedになるまでsleepするようにしてある (このおかげで1時間くらい嵌った)。 それと、環境変数DISPLAYとXAUTHORITYをexportする必要があることに注意。 このスクリプトを適当な場所に保存し、実行できるようにしておく。

chmod +x /home/hoge/bin/xrandr-hdmi3.sh

次に、udevのルールを作成する。例えば、/etc/udev/rules.d/95-monitor-hotplug.rulesに次のように作る。

KERNEL=="card0", SUBSYSTEM=="drm", ENV{DISPLAY}=":0", ENV{XAUTHORITY}="/home/hoge/.Xauthority", RUN+="/home/hoge/bin/xrandr-hdmi3.sh"

RUN+=...で指定してあるのが先程作ったスクリプト。実行ファイルは絶対パスで指定する必要があるらしい。

デバイスの特定のアクションが起きたときのudevの挙動をテストするには次のように実行する。

udevadm test -a change $(udevadm info -q path -n /dev/dri/card0) 2>&1 

-aオプションでアクションを指定し、続く引数でデバイスパスを指定する。

udevのルールをリロードする。

udevadm control --reload

で、デバイスを繋いでみて確認する。

References