在Python中获取显示器数量和分辨率,无需 xrandr 命令行工具
我在使用Ubuntu系统,想要获取连接的显示器数量、它们当前的分辨率,以及如果可能的话,它们之间的位置关系。因为我不太喜欢解析xrandr这个命令行工具的输出,至少在我不需要的时候,我希望能用Python-XLib或者其他类似的Python方法来实现。
这是我显示配置的xrandr输出:
$ xrandr
Screen 0: minimum 320 x 200, current 2960 x 1050, maximum 8192 x 8192
DVI-0 connected 1680x1050+0+0 (normal left inverted right x axis y axis) 473mm x 296mm
1680x1050 60.0*+
[some lines cut]
VGA-0 connected 1280x1024+1680+26 (normal left inverted right x axis y axis) 376mm x 301mm
1280x1024 60.0 + 75.0*
[some more lines cut]
我想用Python以这样的方式获取这些值:
monitors = get_monitors()
print monitors[0].width # out: 1680
print monitors[1].width # out: 1280
print monitors[0].x_position # out: 0
print monitors[1].x_position # out: 1680
在尝试通过Python-XLib(或者其他库,比如pyGTK和pygame)获取信息时,似乎所有的显示器总是被当作一个单一的显示器来处理。例如,这是我到目前为止用XLib得到的结果:
import Xlib
import Xlib.display
display = Xlib.display.Display(':0')
print display.screen_count() # output: 1
root = display.screen().root
print root.get_geometry().width # output: 2960 -> no way to get width of single monitor?
print root.get_geometry().height # output: 1050
但是正如我所说的,我更希望有一种更简洁的方法,而不需要解析命令行的输出。真的没有办法用Python获取(详细的)显示信息,而不需要解析xrandr的输出吗?
5 个回答
1
import Xlib.display
display = Xlib.display.Display()
root = display.screen().root
for m in root.xrandr_get_monitors().monitors:
connector = display.get_atom_name(m.name)
print(f'{connector}, {m.width_in_pixels}x{m.height_in_pixels}, '\
f'x={m.x}, y={m.y}')
对我来说返回的是:
HDMI-0, 1920x1080, x=0, y=1050
DVI-0, 1680x1050, x=1920, y=1050
DVI-1, 1680x1050, x=0, y=0
注意,“display”和“screen”是X11的专业术语,它们和我们日常用语不太一样。“Monitor”通常指的是实际的显示器——不过在X11中,你可以用Xrandr把多个显示器合成一个虚拟显示器……
- X11的显示指的是整个X服务器
- 同一台主机上的不同X11显示 → 可能是不同的用户
- 一个用户所用的所有键盘和鼠标(通常各一个)都属于一个X11显示
- 现在每个X11显示通常只有一个X11屏幕
- 多个X11屏幕的概念其实已经不再流行了
- 想象一下,一个鼠标和键盘被完全不同的输出设备共享
- 不能在X11屏幕之间共享或移动窗口
- 可以在每个X11屏幕上运行不同的窗口管理器
- 或者至少必须运行完全独立的窗口管理器实例
- 这并没有证明非常有用
- 现在的X11屏幕必须包含所有显示器
- 通常是一个大矩形把它们都包起来
- 有一个来自(X11) EWMH规范的桌面术语
- 是否把X11屏幕视为一个桌面取决于窗口管理器
- ……或者它是否认为每个显示器都是一个桌面
- 想要在(X11 EWMH)桌面之间移动窗口的X11应用(“客户端”)可能需要根据不同的窗口管理器采取不同的方法
- 但大多数应用都把全屏或在(X11 EWMH)桌面或显示器上组织窗口的事情留给窗口管理器和用户来处理
5
最新的代码片段。它可以从所有连接的显示器中提取出当前分辨率的所有模式。
from Xlib import display
from Xlib.ext import randr
def find_mode(id, modes):
for mode in modes:
if id == mode.id:
return "{}x{}".format(mode.width, mode.height)
def get_display_info():
d = display.Display(':0')
screen_count = d.screen_count()
default_screen = d.get_default_screen()
result = []
screen = 0
info = d.screen(screen)
window = info.root
res = randr.get_screen_resources(window)
for output in res.outputs:
params = d.xrandr_get_output_info(output, res.config_timestamp)
if not params.crtc:
continue
crtc = d.xrandr_get_crtc_info(params.crtc, res.config_timestamp)
modes = set()
for mode in params.modes:
modes.add(find_mode(mode, res.modes))
result.append({
'name': params.name,
'resolution': "{}x{}".format(crtc.width, crtc.height),
'available_resolutions': list(modes)
})
return result
print(get_display_info())
13
xrandr
是一个可以通过命令行访问 "RandR" X11 扩展的工具。你也可以直接通过 Python-Xlib 来使用这些功能。这里有一个示例(来自 Python-Xlib 自己的代码!)。
为了防止网址再次变化,这里有一段简单的代码,可以帮助我们获取显示模式。我们需要创建一个窗口(窗口的大小等都无所谓):
from __future__ import print_function
from Xlib import X, display
from Xlib.ext import randr
d = display.Display()
s = d.screen()
window = s.root.create_window(0, 0, 1, 1, 1, s.root_depth)
然后我们可以使用这个窗口来查询屏幕资源。例如,按照提问者的例子:
res = randr.get_screen_resources(window)
for mode in res.modes:
w, h = mode.width, mode.height
print("Width: {}, height: {}".format(w, h))
在我的电脑上,我得到:
$ python minimal.py
Xlib.protocol.request.QueryExtension
Width: 1600, height: 900
Width: 1440, height: 900
Width: 1360, height: 768
Width: 1360, height: 768
Width: 1152, height: 864
Width: 1024, height: 768
Width: 800, height: 600
Width: 800, height: 600
Width: 640, height: 480