jan*_*ver 56 udev acpi multi-monitor monitors
是否有任何当我插上或缩小外部监视器到我的笔记本电脑的DisplayPort的所触发的事件?ACPID 和 UDEV 根本没有反应。
我在英特尔芯片上使用板载图形。这是一个类似的讨论,已经有几年了。
我不想使用轮询,但我需要一些配置,根据显示器是否连接自动设置显示设置。
F. *_*uri 16
注意: 这是在带有 i915 驱动显卡的笔记本电脑上测试的。
注意:插入新屏幕时,不会向主机发送任何事件,即使在我上次编辑后也是如此。所以唯一的办法就是使用轮询。试图使它们尽可能高效......
最后有一个更好的解决方案(通过 ACPI):
仍然没有事件,但 ACPI 似乎比xrandr
查询更有效。(注意:这需要加载 ACPI 内核模块,但不需要 root 权限)。
我的最终解决方案(使用 bash):
isVgaConnected() {
local crtState
read -a < /proc/acpi/video/VID/CRT0/state crtState
test $(( ( ${crtState[1]} >>4 ) ${1:+*-1+1} )) -ne 0
}
Run Code Online (Sandbox Code Playgroud)
现在进行测试:
$ if isVgaConnected; then echo yes; else echo no; fi
yes
Run Code Online (Sandbox Code Playgroud)
它已插入,所以现在我拔掉它:
$ if isVgaConnected; then echo yes; else echo no; fi
no
Run Code Online (Sandbox Code Playgroud)
注意: ${1:+*-1+1}
允许一个布尔参数:如果有东西存在,答案将被反转:( crtState >> 4 ) * -1 + 1
。
和最终脚本:
#!/bin/bash
export crtProcEntry=/proc/acpi/video/VID/CRT0/state
isVgaConnected() {
local crtState
read -a < $crtProcEntry crtState
test $(( ( ${crtState[1]} >>4 ) ${1:+*-1+1} )) -ne 0
}
delay=.1
unset switch
isVgaConnected || switch=not
while :;do
while isVgaConnected $switch;do
sleep $delay
done
if [ "$switch" ];then
unset switch
echo VGA IS connected
# doing something while VGA is connected
else
switch=not
echo VGA is NOT connected.
# doing something else, maybe.
fi
done
Run Code Online (Sandbox Code Playgroud)
警告: 比 轻xrandr
,但延迟小于0.02秒并非不重要,Bash 脚本将进入资源吞噬进程 ( top
)的顶部!
虽然这需要大约 0.001 秒:
$ time read -a </proc/stat crtStat
Run Code Online (Sandbox Code Playgroud)
这需要 ~0.030 秒:
$ read -a < /proc/acpi/video/VID/CRT0/state crtState
Run Code Online (Sandbox Code Playgroud)
这很大!因此,根据您的需要,delay
可以在0.5
和之间合理设置2
。
我终于找到了一些东西,使用这个:
重要免责声明:玩弄/proc
和/sys
条目可能会破坏您的系统!!!所以不要在生产系统上尝试以下操作。
mapfile watchFileList < <(
find /sys /proc -type f 2>/dev/null |
grep -i acpi\\\|i91
)
prompt=("/" "|" '\' '-');
l=0
while :; do
mapfile watchStat < <(
grep -H . ${watchFileList[@]} 2>/dev/null
)
for ((i=0;i<=${#watchStat[@]};i++)); do
[ "${watchStat[i]}" == "${oldStat[i]}" ] || echo ${watchStat[i]}
done
oldStat=("${watchStat[@]}")
sleep .5
printf "\r%s\r" ${prompt[l++]}
[ $l -eq 4 ]&&l=0
done
Run Code Online (Sandbox Code Playgroud)
...在清理不需要的条目后:
for ((i=0;i<=${#watchFileList[@]};i++)); do
[[ "${watchFileList[$i]}" =~ /sys/firmware/acpi/interrupts/sci ]] &&
unset watchFileList[$i] && echo $i
done
Run Code Online (Sandbox Code Playgroud)
我已经能够阅读这个:
/proc/acpi/video/VID/CRT0/state:state: 0x1d
/proc/acpi/video/VID/CRT0/state:state: 0x0d
/proc/acpi/video/VID/CRT0/state:state: 0x1d
Run Code Online (Sandbox Code Playgroud)
当我插入、拔下和重新插入显示器电缆时。
原答案当查询配置(正在运行system/preferences/monitor
或xrandr
)时,显卡会进行一种扫描,因此运行会xrandr -q
为您提供信息,但您必须轮询状态。
我已经扫描了所有日志(内核、守护进程、X 等)并通过/proc
&搜索/sys
,显然似乎没有满足您的要求的东西。
我也试过这个:
export spc50="$(printf "%50s" "")"
watch -n1 '
find /proc/acpi/video -type f |
xargs grep -H . |
sed "s/^\([^:]*):/\1'$spc50'}:/;
s/^\(.\{50\}\) *:/\1 /"'
Run Code Online (Sandbox Code Playgroud)
毕竟,如果您System/Preferences/Monitor
在没有插入或拔出新屏幕的情况下运行,该工具将简单地(通常)出现。但是,如果您之前插入或拔出屏幕,有时您会运行此工具,并且您会看到桌面进行了一种重置或刷新(如果您运行 ,则相同xrandr
)。
这似乎证实了该工具xrandr
通过定期轮询状态(从它运行时开始)来请求(或以相同的方式工作)。
你可以自己试试:
$ for ((i=10;i--;)); do xrandr -q | grep ' connected' | wc -l; sleep 1; done
1
1
1
2
2
2
1
1
1
1
Run Code Online (Sandbox Code Playgroud)
这将显示连接了多少屏幕(显示器),持续 10 秒。
当它运行时,插上和/或拔下你的屏幕/显示器,看看会发生什么。所以你可以创建一个小 Bash 测试函数:
isVgaConnected() {
local xRandr=$(xrandr -q)
[ "$xRandr" == "${xRandr#*VGA1 con}" ] || return 0
return 1
}
Run Code Online (Sandbox Code Playgroud)
这将是可用的,如:
$ if isVgaConnected; then echo yes; fi
Run Code Online (Sandbox Code Playgroud)
但要小心,xrandr
大约需要0.140 秒到 0.200 秒,而插头没有任何变化,并且在之前插入或拔出某些东西时最多需要0.700 秒(注意:它似乎不是资源消耗者)。
为了确保我没有教错东西,我搜索了 Web 和文档,但没有找到关于DBus 和 Screens 的任何信息。
最后,我在两个不同的窗口中运行dbus-monitor --system
(我也一直在玩选项)和我写的小脚本:
$ for ((i=1000;i--;)); do isVgaConnected && echo yes || echo no; sleep .5; done
Run Code Online (Sandbox Code Playgroud)
...再次插入,而不是拔下显示器,很多次。所以现在我可以说:
xrandr -q
以了解监视器是否已插入之外别无他法。但要小心,因为似乎没有其他方法。例如,xrandr
似乎共享此信息,因此我的 GNOME 桌面会xinerama
自动切换到...当我运行xrandr
.
以下几行出现在 udevadm monitor
KERNEL[46578.184280] change /devices/pci0000:00/0000:00:02.0/drm/card0 (drm)
UDEV [46578.195887] change /devices/pci0000:00/0000:00:02.0/drm/card0 (drm)
Run Code Online (Sandbox Code Playgroud)
将显示器连接到 VGA 连接器时。所以可能有办法解决这个问题。
小智 6
对于那些出于某种原因不想走热插拔路线的人,仍然可以使用 inotifywait 在脚本中不轮询:
#!/bin/bash SCREEN_LEFT=DP2 SCREEN_RIGHT=eDP1 START_DELAY=5 renice +19 $$ >/dev/null 睡眠 $START_DELAY OLD_DUAL="虚拟" 而 [1]; 做 DUAL=$(cat /sys/class/drm/card0-DP-2/status) if [ "$OLD_DUAL" != "$DUAL" ]; 然后 if [ "$DUAL" == "connected" ]; 然后 echo '双显示器设置' xrandr --output $SCREEN_LEFT --auto --rotate normal --pos 0x0 --output $SCREEN_RIGHT --auto --rotate normal --below $SCREEN_LEFT 别的 echo '单显示器设置' xrandr --auto 菲 OLD_DUAL="$DUAL" 菲 inotifywait -q -e 关闭 /sys/class/drm/card0-DP-2/status >/dev/null 完毕
它最好从您的 .xsessionrc 中调用,不要忘记结尾 &。使用 xrandr 轮询在我全新的笔记本电脑上出现了严重的可用性问题(鼠标会定期停止)。