我想枚举 X Server 显示连接点,例如DisplayPort-1-7
或HDMI-A-1-1
,同时识别连接到每个连接点的物理监视器(如果有)。
动机:我使用的是 Xubuntu 18.04 (Bionic),xfce 在对接/断开对接时自动配置显示器的效果很差。我使用的是戴尔笔记本电脑,GPU 在对接、取消对接和重新对接时会更改显示器连接的标识符,因此我不能仅使用固定标识符来设置显示器,这使得由arandr
失败。
我的目标是编写一个简单的 Bash/Python 脚本,该脚本可以查看连接的显示器并运行 xrandr 以按照我希望的方式设置显示器。
潜在的工具:
xrandr
为我提供了特定于 X Server 的显示连接点列表,但没有为我提供监视器 ID。hwinfo --monitor
可以列出显示器并解码 EDID 数据以确定其型号名称和序列 ID,但不知道 X Windows 名称。
我还没有找到一种方法来确定哪个物理监视器连接到哪个 X Server 端口。
编辑澄清以下评论:我的目标是从显示器的名称、型号或序列号中识别显示器。然后我可以xrandr
在脚本中使用显示器的标识来设置其分辨率和位置。
答案1
只是好的部分:这是我用于执行此操作的 Python 脚本,需要python-xlib
安装。
到目前为止,我已经找到了一个来源,可以获取 X Server 显示连接列表并同时获取连接到每个服务器的监视器,那就是 X 本身。有多种方法可以从 X 获取此信息,具体取决于您对解析的容忍度与直接从 X 获取数据的能力。
方法一:解析xrandr --verbose
该xrandr --verbose
命令包含将显示连接与监视器进行匹配所需的所有信息。单个显示器连接的输出如下所示:
Screen 0: minimum 320 x 200, current 6400 x 1600, maximum 8192 x 8192
DP-1 disconnected (normal left inverted right x axis y axis)
[extra content removed]
DisplayPort-1-7 connected 1920x1080+0+464 (0x4a) normal (normal left inverted right x axis y axis) 510mm x 287mm
Identifier: 0x224
Timestamp: 6668772
Subpixel: unknown
Gamma: 1.0:1.0:1.0
Brightness: 1.0
Clones:
CRTC: 4
CRTCs: 0 4 5 6 7
Transform: 1.000000 0.000000 0.000000
0.000000 1.000000 0.000000
0.000000 0.000000 1.000000
filter:
EDID:
00ffffffffffff0010ac73404c424241
------[more hex redacted]-------
001155223811000a202020202020007e
GAMMA_LUT_SIZE: 4096
range: (0, -1)
DEGAMMA_LUT_SIZE: 4096
range: (0, -1)
GAMMA_LUT: 0
range: (0, 65535)
CTM: 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 1
DEGAMMA_LUT: 0
range: (0, 65535)
TearFree: auto
supported: off, on, auto
vrr_capable: 0
range: (0, 1)
max bpc: 8
range: (8, 16)
underscan vborder: 0
range: (0, 128)
underscan hborder: 0
range: (0, 128)
underscan: off
supported: off, on, auto
scaling mode: None
supported: None, Full, Center, Full aspect
link-status: Good
supported: Good, Bad
CONNECTOR_ID: 76
supported: 76
non-desktop: 0
range: (0, 1)
1920x1080 (0x4a) 148.500MHz +HSync +VSync *current +preferred
h: width 1920 start 2008 end 2052 total 2200 skew 0 clock 67.50KHz
v: height 1080 start 1084 end 1089 total 1125 clock 60.00Hz
1680x1050 (0x9b) 146.250MHz -HSync +VSync
h: width 1680 start 1784 end 1960 total 2240 skew 0 clock 65.29KHz
v: height 1050 start 1053 end 1059 total 1089 clock 59.95Hz
[extra content removed]
解析此输出并不好:您需要识别代表显示连接与屏幕的线路,并根据是否连接/断开等而有所不同。但是如果您这样做,您可以提取 EDID,转换它为原始字节,并将其传递给诸如parse-edid
.
方法2:Xlib
客户端和EDID解析器
有一个Xlib 的 Python 客户端它具有从每个连接的显示器获取显示连接和相关 EDID 字节所需的工具。同样,有用于解析 EDID 数据的 Python 库,尽管它不是很理想(如下所述)。但是,我制作了一个示例脚本,将这两个项目放在一起以产生我想要的答案:
#!/usr/bin/env python3
import pyedid.edid, pyedid.helpers.registry
import Xlib.display
def get_x_displays():
# Used by PyEDID to fetch manufacturers given their EDID code
registry = pyedid.helpers.registry.Registry.from_web()
# Xlib resources
d = Xlib.display.Display()
root = d.screen().root
resources = root.xrandr_get_screen_resources()._data
outputs = {}
for output in resources['outputs']:
output_info = d.xrandr_get_output_info(output, resources['config_timestamp'])._data
output_name = output_info['name']
props = d.xrandr_list_output_properties(output)
edid_data = None
# Look through the atoms (properties) of each output to see if there's one named 'EDID'
for atom in props._data['atoms']:
atom_name = d.get_atom_name(atom)
if atom_name == 'EDID':
edid_raw = d.xrandr_get_output_property(output, atom, 0, 0, 1000)._data['value']
edid_data = pyedid.edid.Edid(bytes(edid_raw)[:128], registry)
break
outputs[output_name] = edid_data
return outputs
if __name__ == '__main__':
displays = get_x_displays()
for connection, monitor in sorted(displays.items(), key=lambda kv: kv[0]):
print(connection)
print(' ' + ("No connection or empty EDID" if monitor is None else
"{} ({})".format(monitor.name, monitor.serial)))
在我的机器上,这会产生以下输出(序列号被破坏):
DP-1
No connection or empty EDID
DP-2
No connection or empty EDID
DP-3
No connection or empty EDID
DisplayPort-1-3
No connection or empty EDID
DisplayPort-1-4
No connection or empty EDID
DisplayPort-1-5
No connection or empty EDID
DisplayPort-1-6
DELL UP3017 (DDSB553SBDFL)
DisplayPort-1-7
DELL U2312HM (V092DMLS657D)
DisplayPort-1-8
No connection or empty EDID
HDMI-1
No connection or empty EDID
HDMI-A-1-1
No connection or empty EDID
eDP-1
None (0)
eDP-1-1
No connection or empty EDID
PyEDID 库需要制造商的“注册表”,以便它可以填充 EDID 的制造商字段。from_web()
从在线源创建注册表的调用是此脚本中最慢的部分。我创造了该脚本的替代版本通过完全跳过制造商查找,而不是传递原始值来消除该要求。
答案2
你尝试过吗`
$ xrandr --listactivemonitors
Monitors: 2
0: +*DVI-0 1920/521x1080/293+0+0 DVI-0
1: +DVI-1 1920/521x1080/293+0+0 DVI-1
它将其分解为如下表格格式:
[屏幕/显示器]编号:[连接器 + 模式] [连接器]