1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
|
#!/usr/bin/env python3
# https://en.wikipedia.org/wiki/Extended_Display_Identification_Data
# TODO: This is a real mess, it's a transition from the setup-desktop.sh shell
# script to something a little more flexible. But it mostly doesn't work
# yet and is just subbing in for parse-edid.
# TODO: List screens if none are known
# TODO: Zooming
# xrandr --output eDP-1 --mode 2880x1620 --panning 2880x1620
#bigmodes=( 3840x2160 3200x1800 )
#modes=( 2560x1440 2048x1152 1920x1080 1600x900 1368x768
# 1360x768 1280x720 1024x576 960x540 864x486
# 720x405 640x360 )
import re
import os
import sys
import struct
from collections import namedtuple
from subprocess import check_output, call
BUILTIN_DISPLAY_RESOLUTIONS = [
"1600x900", "1920x1080", "2048x1152", "2880x1620"]
BEST_RESOLUTION = BUILTIN_DISPLAY_RESOLUTIONS[2]
DRM_PATH = "/sys/class/drm"
EDID_MAGIC = b'\x00\xff\xff\xff\xff\xff\xff\x00'
EDID_14 = b'\x01\x04'
UNSPEC_TEXT = 0xFE
SERIAL = 0xFF
NAME = 0xFC
MonitorData = namedtuple(
"MonitorData", ("card", "port", "name", "serial", "text"))
def parse_xrandr_query():
monitors = {}
monitor = None
for line in check_output(("xrandr", "-q")).split(b"\n"):
line = line.decode("us-ascii")
if " connected " in line:
monitor = line.split(" ")[0]
monitors[monitor] = []
elif monitor and line.startswith(" "):
monitors[monitor].append(line.strip().split(" ")[0])
return monitors
def parse_card_port(p):
card, port = p.split("/")[-1].split("-", 1)
return int(card[len("card"):]), port
def parse_descriptor(card, port, md):
name, serial, text = None, None, None
for i in range(54, 108, 18):
d = md[i:i+18]
dtype, data = d[3], d[5:]
prep = lambda dd: dd.decode("us-ascii", errors="ignore").strip()
if dtype == UNSPEC_TEXT:
text = prep(data)
elif dtype == SERIAL:
serial = prep(data)
elif dtype == NAME:
name = prep(data)
return MonitorData(card, port, name, serial, text)
def parse_edid(data, path):
if data[0:8] != EDID_MAGIC:
raise Exception("Not EDID")
if data[18:20] != EDID_14:
raise Exception("Not EDID 1.4")
card, port = parse_card_port(path)
return parse_descriptor(card, port, data)
def get_monitor_edid(path):
edid = os.path.join(path, "edid")
if not os.path.exists(edid):
raise Exception("No card with that name {!r}".format(path))
with open(edid, "rb") as fp:
data = fp.read()
return parse_edid(data, path)
def enumerate_monitors():
monitors = []
for path in os.listdir(DRM_PATH):
if not re.match("^card\d+-", path):
continue
drm_path = os.path.join(DRM_PATH, path)
monitors.append(get_monitor_edid(drm_path))
return monitors
def script_main(args):
all_resolutions = parse_xrandr_query() # Do first to refresh /sys
all_monitors = enumerate_monitors()
for monitor in all_monitors:
resolutions = all_resolutions[monitor.port]
# 27" Dell monitors
if monitor == "DELL U2715H":
call(["xrandr",
"--output", "DP-1","--auto",
"--output", "DP-2", "--auto", "--right-of", "DP-1",
"--output", "eDP-1", "--off"])
break
elif monitor == "AMX_HDMI1_A2":
call(["xrandr",
"--output", "eDP-1", "--mode", BEST_RESOLUTION,
"--output", monitor.card, "--auto", "--right-of", "eDP-1"])
break
elif monitor == "DELL U3415W":
call(["xrandr",
"--output", "eDP-1", "--mode", BEST_RESOLUTION,
"--output", monitor.card, "--mode", "3440x1440",
"--right-of", "eDP-1"])
break
elif monitor == "CS-CODECPLUS":
call(["xrandr",
"--output", "eDP-1", "--mode", BEST_RESOLUTION,
"--output", monitor.card, "--auto", "--right-of", "eDP-1"])
break
else:
call(["xrandr",
"--output", "eDP-1", "--mode", BEST_RESOLUTION,
"--output", "DP-1", "--off",
"--output", "DP-2", "--off"])
break
def main(args):
print(get_monitor_edid(args[1]).name)
if __name__ == "__main__":
#sys.exit(main(sys.argv))
sys.stdin.mode = "rb"
print(parse_edid(sys.stdin.buffer.read(), "/card1-eDP-1").text)
|