Merge ~pieq/checkbox-support:remove-xrandr-contrib into checkbox-support:master

Proposed by Pierre Equoy
Status: Merged
Approved by: Sylvain Pineau
Approved revision: 544e95491f3752cea8fd600d8c28e29427b23dca
Merged at revision: 682b5fa8c4ee4c885ecb5585c06d731cd308a472
Proposed branch: ~pieq/checkbox-support:remove-xrandr-contrib
Merge into: checkbox-support:master
Diff against target: 1075 lines (+0/-1064)
1 file modified
dev/null (+0/-1064)
Reviewer Review Type Date Requested Status
Sylvain Pineau (community) Approve
Review via email: mp+424147@code.launchpad.net

Description of the change

Following the changes made for lp:1968943, this commit removes an unused package from checkbox_support.contrib.

Please check https://code.launchpad.net/~pieq/plainbox-provider-checkbox/+git/plainbox-provider-checkbox/+merge/424146 for additional information.

To post a comment you must log in.
Revision history for this message
Sylvain Pineau (sylvain-pineau) wrote :

+1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/checkbox_support/contrib/__init__.py b/checkbox_support/contrib/__init__.py
0deleted file mode 1006440deleted file mode 100644
index e69de29..0000000
--- a/checkbox_support/contrib/__init__.py
+++ /dev/null
diff --git a/checkbox_support/contrib/xrandr.py b/checkbox_support/contrib/xrandr.py
1deleted file mode 1006441deleted file mode 100644
index 91fd173..0000000
--- a/checkbox_support/contrib/xrandr.py
+++ /dev/null
@@ -1,1064 +0,0 @@
1# Python-XRandR provides a high level API for the XRandR extension of the
2# X.org server. XRandR allows to configure resolution, refresh rate, rotation
3# of the screen and multiple outputs of graphics cards.
4#
5# Copyright 2014 © Canonical Ltd.
6# Copyright 2007 © Sebastian Heinlein <sebastian.heinlein@web.de>
7# Copyright 2007 © Michael Vogt <mvo@ubuntu.com>
8# Copyright 2007 © Canonical Ltd.
9#
10# In many aspects it follows the design of the xrand tool of the X.org, which
11# comes with the following copyright:
12#
13# Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
14# Copyright © 2002 Hewlett Packard Company, Inc.
15# Copyright © 2006 Intel Corporation
16#
17# And can be downloaded here:
18#
19# git://anongit.freedesktop.org/git/xorg/app/xrandr
20#
21# This library is free software; you can redistribute it and/or
22# modify it under the terms of the GNU Lesser General Public
23# License as published by the Free Software Foundation; either
24# version 2.1 of the License, or any later version.
25#
26# This library is distributed in the hope that it will be useful,
27# but WITHOUT ANY WARRANTY; without even the implied warranty of
28# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
29# Lesser General Public License for more details.
30#
31# You should have received a copy of the GNU Lesser General Public
32# License along with this library; if not, write to the Free Software
33# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
34# MA 02110-1301 USA
35
36from ctypes import (
37 POINTER,
38 Structure,
39 byref,
40 c_char_p,
41 c_void_p,
42 c_int,
43 c_long,
44 c_ulong,
45 c_ushort,
46 cdll,
47)
48import os
49
50RR_ROTATE_0 = 1
51RR_ROTATE_90 = 2
52RR_ROTATE_180 = 4
53RR_ROTATE_270 = 8
54RR_REFLECT_X = 16
55RR_REFLECT_Y = 32
56
57RR_CONNECTED = 0
58RR_DISCONNECTED = 1
59RR_UNKOWN_CONNECTION = 2
60
61RR_BAD_OUTPUT = 0
62RR_BAD_CRTC = 1
63RR_BAD_MODE = 2
64
65RR_SET_CONFIG_SUCCESS = 0
66RR_SET_CONFIG_INVALID_CONFIG_TIME = 1
67RR_SET_CONFIG_INVALID_TIME = 2
68RR_SET_CONFIG_FAILED = 3
69
70# Flags to keep track of changes
71CHANGES_NONE = 0
72CHANGES_CRTC = 1
73CHANGES_MODE = 2
74CHANGES_RELATION = 4
75CHANGES_POSITION = 8
76CHANGES_ROTATION = 16
77CHANGES_REFLECTION = 32
78CHANGES_AUTOMATIC = 64
79CHANGES_REFRESH = 128
80CHANGES_PROPERTY = 256
81
82# Relation information
83RELATION_ABOVE = 0
84RELATION_BELOW = 1
85RELATION_RIGHT_OF = 2
86RELATION_LEFT_OF = 3
87RELATION_SAME_AS = 4
88
89# some fundamental datatypes
90RRCrtc = c_long
91RROutput = c_long
92RRMode = c_long
93Connection = c_ushort
94SubpixelOrder = c_ushort
95Time = c_ulong
96Rotation = c_ushort
97Status = c_int
98
99# load the libs
100xlib = cdll.LoadLibrary('libX11.so.6')
101rr = cdll.LoadLibrary('libXrandr.so.2')
102
103
104# query resources
105class _XRRModeInfo(Structure):
106 _fields_ = [
107 ("id", RRMode), # XID is c_long
108 ("width", c_int),
109 ("height", c_int),
110 ("dotClock", c_long),
111 ("hSyncStart", c_int),
112 ("hSyncEnd", c_int),
113 ("hTotal", c_int),
114 ("hSkew", c_int),
115 ("vSyncStart", c_int),
116 ("vSyncEnd", c_int),
117 ("vTotal", c_int),
118 ("name", c_char_p),
119 ("nameLength", c_int),
120 ("modeFlags", c_long),
121 ]
122
123
124class _XRRScreenSize(Structure):
125 _fields_ = [
126 ("width", c_int),
127 ("height", c_int),
128 ("mwidth", c_int),
129 ("mheight", c_int)
130 ]
131
132
133class _XRRCrtcInfo(Structure):
134 _fields_ = [
135 ("timestamp", Time),
136 ("x", c_int),
137 ("y", c_int),
138 ("width", c_int),
139 ("height", c_int),
140 ("mode", RRMode),
141 ("rotation", c_int),
142 ("noutput", c_int),
143 ("outputs", POINTER(RROutput)),
144 ("rotations", Rotation),
145 ("npossible", c_int),
146 ("possible", POINTER(RROutput)),
147 ]
148
149
150class _XRRScreenResources(Structure):
151 _fields_ = [
152 ("timestamp", Time),
153 ("configTimestamp", Time),
154 ("ncrtc", c_int),
155 ("crtcs", POINTER(RRCrtc)),
156 ("noutput", c_int),
157 ("outputs", POINTER(RROutput)),
158 ("nmode", c_int),
159 ("modes", POINTER(_XRRModeInfo)),
160 ]
161
162
163class RRError(Exception):
164 """Base exception class of the module"""
165 pass
166
167
168class UnsupportedRRError(RRError):
169 """Raised if the required XRandR extension version is not available"""
170 def __init__(self, required, current):
171 self.required = required
172 self.current = current
173
174
175# XRRGetOutputInfo
176class _XRROutputInfo(Structure):
177 _fields_ = [
178 ("timestamp", Time),
179 ("crtc", c_int),
180 ("name", c_char_p),
181 ("nameLen", c_int),
182 ("mm_width", c_ulong),
183 ("mm_height", c_ulong),
184 ("connection", Connection),
185 ("subpixel_order", SubpixelOrder),
186 ("ncrtc", c_int),
187 ("crtcs", POINTER(RRCrtc)),
188 ("nclone", c_int),
189 ("clones", POINTER(RROutput)),
190 ("nmode", c_int),
191 ("npreferred", c_int),
192 ("modes", POINTER(RRMode))
193 ]
194
195
196class _XRRCrtcGamma(Structure):
197 _fields_ = [
198 ('size', c_int),
199 ('red', POINTER(c_ushort)),
200 ('green', POINTER(c_ushort)),
201 ('blue', POINTER(c_ushort)),
202 ]
203
204
205def _array_conv(array, type, conv=lambda x: x):
206 length = len(array)
207 res = (type * length)()
208 for i in range(length):
209 res[i] = conv(array[i])
210 return res
211
212
213class Output(object):
214 """The output is a reference to a supported output jacket of the graphics
215 card. Outputs are attached to a hardware pipe to be used. Furthermore
216 they can be a clone of another output or show a subset of the screen"""
217 def __init__(self, info, id, screen):
218 """Initializes an output instance"""
219 self._info = info
220 self.id = id
221 self._screen = screen
222 # Store changes later here
223 self._mode = None
224 self._crtc = None
225 self._rotation = RR_ROTATE_0
226 self._relation = None
227 self._relation_offset = 0
228 self._relative_to = None
229 self._position = None
230 self._reflection = None
231 self._automatic = None
232 self._rate = None
233 self._changes = CHANGES_NONE
234 self._x = 0
235 self._y = 0
236
237 self.name = self._info.contents.name
238
239 def __del__(self):
240 """Frees the internal reference to the output info if the output gets
241 removed"""
242 rr.XRRFreeOutputInfo(self._info)
243
244 def get_physical_width(self):
245 """Returns the display width reported by the connected output device"""
246 return self._info.contents.mm_width
247
248 def get_physical_height(self):
249 """
250 Returns the display height reported by the connected output device
251 """
252 return self._info.contents.mm_height
253
254 def get_crtc(self):
255 """Returns the xid of the hardware pipe to which the output is
256 attached. If the output is disabled it will return 0"""
257 return self._info.contents.crtc
258
259 def get_crtcs(self):
260 """Returns the xids of the hardware pipes to which the output could
261 be attached"""
262 crtcs = []
263 for i in range(self._info.contents.ncrtc):
264 for crtc in self._screen.crtcs:
265 if crtc.xid == self._info.contents.crtcs[i]:
266 crtcs.append(crtc)
267 return crtcs
268
269 def get_available_rotations(self):
270 """Returns a binary flag of the supported rotations of the output or
271 0 if the output is disabled"""
272 rotations = RR_ROTATE_0
273 found = False
274 if self.is_active():
275 # Get the rotations supported by all crtcs to make assigning
276 # crtcs easier. Furthermore there don't seem to be so many
277 # cards which show another behavior
278 for crtc in self.get_crtcs():
279 # Set rotations to the value of the first found crtc and
280 # then create a subset only for all other crtcs
281 if not found:
282 rotations = crtc.get_available_rotations()
283 found = True
284 else:
285 rotations = rotations & crtc.get_available_rotations()
286 return rotations
287
288 def get_available_modes(self):
289 """Returns the list of supported mode lines (resolution, refresh rate)
290 that are supported by the connected device"""
291 modes = []
292 for m in range(self._info.contents.nmode):
293 output_modes = self._info.contents.modes
294 for s in range(self._screen._resources.contents.nmode):
295 screen_modes = self._screen._resources.contents.modes
296 if screen_modes[s].id == output_modes[m]:
297 modes.append(screen_modes[s])
298 return modes
299
300 def get_preferred_mode(self):
301 """Returns an index that refers to the list of available modes and
302 points to the preferred mode of the connected device"""
303 return self._info.contents.npreferred
304
305 def is_active(self):
306 """Returns True if the output is attached to a hardware pipe, is
307 enabled"""
308 return self._info.contents.crtc != 0
309
310 def is_connected(self):
311 """Return True if a device is detected at the output"""
312 if self._info.contents.connection in (RR_CONNECTED,
313 RR_UNKOWN_CONNECTION):
314 return True
315 return False
316
317 def disable(self):
318 """Disables the output"""
319 if not self.is_active():
320 return
321 self._mode = None
322 self._crtc._outputs.remove(self)
323 self._crtc = None
324 self._changes = self._changes | CHANGES_CRTC | CHANGES_MODE
325
326 def set_to_mode(self, mode):
327 modes = self.get_available_modes()
328 if mode in range(len(modes)):
329 self._mode = modes[mode].id
330 return
331 raise RRError("Mode is not available")
332
333 def set_to_preferred_mode(self):
334 modes = self.get_available_modes()
335 mode = modes[self.get_preferred_mode()]
336 if mode is not None:
337 self._mode = mode.id
338 return
339 raise RRError("Preferred mode is not available")
340
341 def get_clones(self):
342 """Returns the xids of the outputs which can be clones of the output"""
343 clones = []
344 for i in range(self._info.contents.nclone):
345 id = self._info.contents.clones[i]
346 o = self._screen.get_output_by_id(id)
347 clones.append(o)
348 return clones
349
350 def set_relation(self, relative, relation, offset=0):
351 """Sets the position of the output in relation to the given one"""
352 rel = self._screen.get_output_by_name(relative)
353 if rel and relation in (RELATION_LEFT_OF, RELATION_RIGHT_OF,
354 RELATION_ABOVE, RELATION_BELOW,
355 RELATION_SAME_AS):
356 self._relation = relation
357 self._relative_to = rel
358 self._relation_offset = offset
359 self._changes = self._changes | CHANGES_RELATION
360 else:
361 raise RRError("The given relative output or relation is not "
362 "available")
363
364 def has_changed(self, changes=None):
365 """Checks if the output has changed: Either for a specific change or
366 generally"""
367 if changes:
368 return self._changes & changes
369 else:
370 return self._changes != CHANGES_NONE
371
372
373class Crtc(object):
374 """The crtc is a reference to a hardware pipe that is provided by the
375 graphics device. Outputs can be attached to crtcs"""
376
377 def __init__(self, info, xid, screen):
378 """Initializes the hardware pipe object"""
379 self._info = info
380 self.xid = xid
381 self._screen = screen
382 self._outputs = []
383
384 def __del__(self):
385 """Frees the reference to the rendering pipe if the instance gets
386 removed"""
387 rr.XRRFreeCrtcInfo(self._info)
388
389 def get_xid(self):
390 """Returns the internal id of the crtc from the X server"""
391 return self.xid
392
393 def get_available_rotations(self):
394 """Returns a binary flag that contains the supported rotations of the
395 hardware pipe"""
396 return self._info.contents.rotations
397
398 def set_config(self, x, y, mode, outputs, rotation=RR_ROTATE_0):
399 """Configures the render pipe with the given mode and outputs. X and y
400 set the position of the crtc output in the screen"""
401 rr.XRRSetCrtcConfig(self._screen._display,
402 self._screen._resources,
403 self.xid,
404 self._screen.get_timestamp(),
405 c_int(x), c_int(y),
406 mode,
407 rotation,
408 _array_conv(outputs, RROutput, lambda x: x.id),
409 len(outputs))
410
411 def apply_changes(self):
412 """Applies the stored changes"""
413 if len(self._outputs) > 0:
414 output = self._outputs[0]
415 self.set_config(output._x, output._y, output._mode,
416 self._outputs, output._rotation)
417 else:
418 self.disable()
419
420 def disable(self):
421 """Turns off all outputs on the crtc"""
422 rr.XRRSetCrtcConfig(self._screen._display,
423 self._screen._resources,
424 self.xid,
425 self._screen.get_timestamp(),
426 0, 0,
427 None,
428 RR_ROTATE_0,
429 0, 0)
430
431 #FIXME: support gamma settings
432 """
433 def get_gamma_size(self):
434 return rr.XRRGetCrtcGammaSize(self._screen._display, self.id)
435 def get_gamma(self):
436 result = rr.XRRGetCrtcGamma(self._screen._display, self.id)
437 return _from_gamma(result)
438 def set_gamma(self, gamma):
439 g = _to_gamma(gamma)
440 rr.XRRSetCrtcGamma(self._screen._display, self.id, g)
441 rr.XRRFreeGamma(g)
442 gamma = property(get_gamma, set_gamma)"""
443
444 def load_outputs(self):
445 """Get the currently assigned outputs"""
446 outputs = []
447 for i in range(self._info.contents.noutput):
448 id = self._info.contents.outputs[i]
449 o = self._screen.get_output_by_id(id)
450 outputs.append(o)
451 self._outputs = outputs
452
453 def get_outputs(self):
454 """Returns the list of attached outputs"""
455 return self._outputs
456
457 def add_output(self, output):
458 """Adds the specified output to the crtc"""
459 output._crtc = self
460 self._outputs.append(output)
461
462 def supports_output(self, output):
463 """Check if the output can be used by the crtc.
464 See check_crtc_for_output in xrandr.c"""
465 if not self.xid in [c.xid for c in output.get_crtcs()]:
466 return False
467 if len(self._outputs):
468 for other in self._outputs:
469 if other == output:
470 continue
471 if other._x != output._x:
472 return False
473 if other._y != output._y:
474 return False
475 if other._mode != output._mode:
476 return False
477 if other._rotation != output._rotation:
478 return False
479 #FIXME: pick_crtc is still missing
480 elif self._info.contents.noutput > 0:
481 if self._info.contents.x != output._x:
482 return False
483 if self._info.contents.y != output._y:
484 return False
485 if self._info.contents.mode_info != output._mode:
486 return False
487 if self._info.rotation != output._rotation:
488 return False
489 return True
490
491 def supports_rotation(self, rotation):
492 """Check if the given rotation is supported by the crtc"""
493 rotations = self._info.contents.rotations
494 dir = rotation & (RR_ROTATE_0 | RR_ROTATE_90 | RR_ROTATE_180 |
495 RR_ROTATE_270)
496 reflect = rotation & (RR_REFLECT_X | RR_REFLECT_Y)
497 if (((rotations & dir) != 0) and ((rotations & reflect) == reflect)):
498 return True
499 return False
500
501 def has_changed(self):
502 """Check if there are any new outputs assigned to the crtc or any
503 outputs with a changed mode or position"""
504 if len(self._outputs) != self._info.contents.noutput:
505 return True
506 for i in range(self._info.contents.noutput):
507 id = self._info.contents.outputs[i]
508 output = self._screen.get_output_by_id(id)
509 if not output in self._outputs:
510 return True
511 if output.has_changed():
512 return True
513 return False
514
515
516class Screen(object):
517 def __init__(self, dpy, screen=-1):
518 """Initializes the screen"""
519 # Some sane default values
520 self.outputs = {}
521 self.crtcs = []
522 self._width = 0
523 self._height = 0
524 self._width_max = 0
525 self._height_max = 0
526 self._width_min = 0
527 self._height_min = 0
528 self._width_mm = 0
529 self._height_mm = 0
530
531 self._display = dpy
532 if not -1 <= screen < xlib.XScreenCount(dpy):
533 raise RRError("The chosen screen is not available", screen)
534 elif screen == -1:
535 self._screen = xlib.XDefaultScreen(dpy)
536 else:
537 self._screen = screen
538 self._root = xlib.XDefaultRootWindow(self._display, self._screen)
539 self._id = rr.XRRRootToScreen(self._display, self._root)
540
541 self._load_resources()
542 self._load_config()
543 (self._width, self._height,
544 self._width_mm, self._height_mm) = self.get_size()
545 if XRANDR_VERSION >= (1, 2):
546 self._load_screen_size_range()
547 self._load_crtcs()
548 self._load_outputs()
549
550 # Store XRandR 1.0 changes here
551 self._rate = self.get_current_rate()
552 self._rotation = self.get_current_rotation()
553 self._size_index = self.get_current_size_index()
554
555 def __del__(self):
556 """Free the reference to the interal screen config if the screen
557 gets removed"""
558 rr.XRRFreeScreenConfigInfo(self._config)
559
560 def _load_config(self):
561 """Loads the screen configuration. Only needed privately by the
562 the bindings"""
563 class XRRScreenConfiguration(Structure):
564 " private to Xrandr "
565 pass
566 gsi = rr.XRRGetScreenInfo
567 gsi.restype = POINTER(XRRScreenConfiguration)
568 self._config = gsi(self._display, self._root)
569
570 def _load_screen_size_range(self):
571 """Detects the dimensionios of the screen"""
572 minWidth = c_int()
573 minHeight = c_int()
574 maxWidth = c_int()
575 maxHeight = c_int()
576 res = rr.XRRGetScreenSizeRange(self._display, self._root,
577 byref(minWidth), byref(minHeight),
578 byref(maxWidth), byref(maxHeight))
579 if res:
580 self._width_max = maxWidth.value
581 self._width_min = minWidth.value
582 self._height_max = maxHeight.value
583 self._height_min = minHeight.value
584
585 def _load_resources(self):
586 """Loads the screen resources. Only needed privately for the
587 bindings"""
588 gsr = rr.XRRGetScreenResources
589 gsr.restype = POINTER(_XRRScreenResources)
590 self._resources = gsr(self._display, self._root)
591
592 def _load_crtcs(self):
593 """Loads the available XRandR 1.2 crtcs (hardware pipes) of
594 the screen"""
595 gci = rr.XRRGetCrtcInfo
596 gci.restype = POINTER(_XRRCrtcInfo)
597 c = self._resources.contents.crtcs
598 for i in range(self._resources.contents.ncrtc):
599 xrrcrtcinfo = gci(self._display, self._resources, c[i])
600 self.crtcs.append(Crtc(xrrcrtcinfo, c[i], self))
601
602 def _load_outputs(self):
603 """Loads the available XRandR 1.2 outputs of the screen"""
604 goi = rr.XRRGetOutputInfo
605 goi.restype = POINTER(_XRROutputInfo)
606 o = self._resources.contents.outputs
607 for i in range(self._resources.contents.noutput):
608 xrroutputinfo = goi(self._display, self._resources, o[i])
609 output = Output(xrroutputinfo, o[i], self)
610 self.outputs[xrroutputinfo.contents.name] = output
611 # Store the mode of the crtc in the output instance
612 crtc = self.get_crtc_by_xid(output.get_crtc())
613 if crtc:
614 output._mode = crtc._info.contents.mode
615 crtc.add_output(output)
616
617 def get_size(self):
618 """Returns the current pixel and physical size of the screen"""
619 width = xlib.XDisplayWidth(self._display, self._screen)
620 width_mm = xlib.XDisplayWidthMM(self._display, self._screen)
621 height = xlib.XDisplayHeight(self._display, self._screen)
622 height_mm = xlib.XDisplayHeightMM(self._display, self._screen)
623 return width, height, width_mm, height_mm
624
625 def get_timestamp(self):
626 """Creates a X timestamp that must be used when applying changes, since
627 they can be delayed"""
628 config_timestamp = Time()
629 rr.XRRTimes.restpye = c_ulong
630 return rr.XRRTimes(self._display, self._id, byref(config_timestamp))
631
632 def get_crtc_by_xid(self, xid):
633 """Returns the crtc with the given xid or None"""
634 for crtc in self.crtcs:
635 if crtc.xid == xid:
636 return crtc
637 return None
638
639 def get_current_rate(self):
640 """Returns the currently used refresh rate"""
641 _check_required_version((1, 0))
642 xccr = rr.XRRConfigCurrentRate
643 xccr.restype = c_int
644 return xccr(self._config)
645
646 def get_available_rates_for_size_index(self, size_index):
647 """Returns the refresh rates that are supported by the screen for
648 the given resolution. See get_available_sizes for the resolution to
649 which size_index points"""
650 _check_required_version((1, 0))
651 rates = []
652 nrates = c_int()
653 rr.XRRConfigRates.restype = POINTER(c_ushort)
654 _rates = rr.XRRConfigRates(self._config, size_index, byref(nrates))
655 for r in range(nrates.value):
656 rates.append(_rates[r])
657 return rates
658
659 def get_current_rotation(self):
660 """Returns the currently used rotation. Can be RR_ROTATE_0,
661 RR_ROTATE_90, RR_ROTATE_180 or RR_ROTATE_270"""
662 _check_required_version((1, 0))
663 current = c_ushort()
664 rr.XRRConfigRotations(self._config, byref(current))
665 return current.value
666
667 def get_available_rotations(self):
668 """Returns a binary flag that holds the available resolutions"""
669 _check_required_version((1, 0))
670 current = c_ushort()
671 rotations = rr.XRRConfigRotations(self._config, byref(current))
672 return rotations
673
674 def get_current_size_index(self):
675 """Returns the position of the currently used resolution size in the
676 list of available resolutions. See get_available_sizes"""
677 _check_required_version((1, 0))
678 rotation = c_ushort()
679 size = rr.XRRConfigCurrentConfiguration(self._config,
680 byref(rotation))
681 return size
682
683 def get_available_sizes(self):
684 """Returns the available resolution sizes of the screen. The size
685 index points to the corresponding resolution of this list"""
686 _check_required_version((1, 0))
687 sizes = []
688 nsizes = c_int()
689 xcs = rr.XRRConfigSizes
690 xcs.restype = POINTER(_XRRScreenSize)
691 _sizes = xcs(self._config, byref(nsizes))
692 for r in range(nsizes.value):
693 sizes.append(_sizes[r])
694 return sizes
695
696 def set_config(self, size_index, rate, rotation):
697 """Configures the screen with the given resolution at the given size
698 index, rotation and refresh rate. To get in effect call
699 Screen.apply_config()"""
700 _check_required_version((1, 0))
701 self.set_size_index(size_index)
702 self.set_refresh_rate(rate)
703 self.set_rotation(rotation)
704
705 def set_size_index(self, index):
706 """Sets the reoslution of the screen. To get in effect call
707 Screen.apply_config()"""
708 if index in range(len(self.get_available_sizes())):
709 self._size_index = index
710 else:
711 raise RRError("There isn't any size associated "
712 "to the index {}".format(index))
713
714 def set_rotation(self, rotation):
715 """Sets the rotation of the screen. To get in effect call
716 Screen.apply_config()"""
717 if self.get_available_rotations() & rotation:
718 self._rotation = rotation
719 else:
720 raise RRError("The chosen rotation is not supported")
721
722 def set_refresh_rate(self, rate):
723 """Sets the refresh rate of the screen. To get in effect call
724 Screen.apply_config()"""
725 if rate in self.get_available_rates_for_size_index(self._size_index):
726 self._rate = rate
727 else:
728 raise RRError(
729 "The chosen refresh rate {0} is not supported".format(rate))
730
731 def get_mode_by_xid(self, xid):
732 """Returns the mode of the given xid"""
733 screen_modes = self._resources.contents.modes
734 for s in range(self._resources.contents.nmode):
735 if screen_modes[s].id == xid:
736 return screen_modes[s]
737 return None
738
739 def get_output_by_name(self, name):
740 """Returns the output of the screen with the given name or None"""
741 if name in self.outputs:
742 return self.outputs[name]
743 else:
744 return None
745
746 def get_output_by_id(self, id):
747 """Returns the output of the screen with the given xid or None"""
748 for o in list(self.outputs.values()):
749 if o.id == id:
750 return o
751 return None
752
753 def print_info(self, verbose=False):
754 """Prints some information about the detected screen and its outputs"""
755 _check_required_version((1, 0))
756 print((
757 "Screen {0}: minimum {1} x {2}, current {3} x {4},"
758 " maximum {5} x {6}"
759 ).format(self._screen, self._width_min, self._height_min, self._width,
760 self._height, self._width_max, self._height_max))
761 print(" {0}mm x {0}mm".format(self._width_mm,
762 self._height_mm))
763 print("Crtcs: {0}".format(len(self.crtcs)))
764 if verbose:
765 print("Modes ({0}):".format(self._resources.contents.nmode))
766 modes = self._resources.contents.modes
767 for i in range(self._resources.contents.nmode):
768 print(" {0} - {1}x{2}".format(
769 modes[i].name, modes[i].width, modes[i].height))
770 i = 0
771 print("Sizes @ Refresh Rates:")
772 for s in self.get_available_sizes():
773 print(" [{0}] {1} x {2} @ {3}".format(
774 i, s.width, s.height,
775 self.get_available_rates_for_size_index(i)))
776 i += 1
777 print("Rotations:")
778 rots = self.get_available_rotations()
779 if rots & RR_ROTATE_0:
780 print("normal")
781 if rots & RR_ROTATE_90:
782 print("right")
783 if rots & RR_ROTATE_180:
784 print("inverted")
785 if rots & RR_ROTATE_270:
786 print("left")
787 print("")
788 print("Outputs:")
789 for o in list(self.outputs.keys()):
790 output = self.outputs[o]
791 print(" %s" % o)
792 if output.is_connected():
793 print("(%smm x %smm)" % (output.get_physical_width(),
794 output.get_physical_height()))
795 modes = output.get_available_modes()
796 print(" Modes:")
797 for m in range(len(modes)):
798 mode = modes[m]
799 refresh = mode.dotClock / (mode.hTotal * mode.vTotal)
800 print(" [%s] %s x %s @ %s" % (m,
801 mode.width,
802 mode.height,
803 refresh))
804 if mode.id == output._mode:
805 print("*")
806 if m == output.get_preferred_mode():
807 print("(preferred)")
808 print("")
809 print(" Rotations:")
810 rots = output.get_available_rotations()
811 if rots & RR_ROTATE_0:
812 print("normal")
813 if rots & RR_ROTATE_90:
814 print("right")
815 if rots & RR_ROTATE_180:
816 print("inverted")
817 if rots & RR_ROTATE_270:
818 print("left")
819 print("")
820 else:
821 print("(not connected)")
822 if verbose:
823 print(" Core properties:")
824 for (f, t) in output._info.contents._fields_:
825 print(" %s: %s" % (
826 f, getattr(output._info.contents, f)))
827
828 def get_outputs(self):
829 """Returns the outputs of the screen"""
830 _check_required_version((1, 2))
831 return list(self.outputs.values())
832
833 def get_output_names(self):
834 _check_required_version((1, 2))
835 return list(self.outputs.keys())
836
837 def set_size(self, width, height, width_mm, height_mm):
838 """Apply the given pixel and physical size to the screen"""
839 _check_required_version((1, 2))
840 # Check if we really need to apply the changes
841 if (width, height, width_mm, height_mm) == self.get_size():
842 return
843 rr.XRRSetScreenSize(self._display, self._root,
844 c_int(width), c_int(height),
845 c_int(width_mm), c_int(height_mm))
846
847 def apply_output_config(self):
848 """Used for instantly applying RandR 1.2 changes"""
849 _check_required_version((1, 2))
850 self._arrange_outputs()
851 self._calculate_size()
852 self.set_size(self._width, self._height,
853 self._width_mm, self._height_mm)
854
855 # Assign all active outputs to crtcs
856 for output in list(self.outputs.values()):
857 if not output._mode or output._crtc:
858 continue
859 for crtc in output.get_crtcs():
860 if crtc and crtc.supports_output(output):
861 crtc.add_output(output)
862 output._changes = output._changes | CHANGES_CRTC
863 break
864 if not output._crtc:
865 #FIXME: Take a look at the pick_crtc code in xrandr.c
866 raise RRError("There is no matching crtc for the output")
867
868 # Apply stored changes of crtcs
869 for crtc in self.crtcs:
870 if crtc.has_changed():
871 crtc.apply_changes()
872
873 def apply_config(self):
874 """Used for instantly applying RandR 1.0 changes"""
875 _check_required_version((1, 0))
876 status = rr.XRRSetScreenConfigAndRate(self._display,
877 self._config,
878 self._root,
879 self._size_index,
880 self._rotation,
881 self._rate,
882 self.get_timestamp())
883 return status
884
885 def _arrange_outputs(self):
886 """Arrange all output positions according to their relative position"""
887 for output in self.get_outputs():
888 # Skip not changed and not used outputs
889 if not output.has_changed(CHANGES_RELATION) or \
890 output._mode is None:
891 continue
892 relative = output._relative_to
893 mode = self.get_mode_by_xid(output._mode)
894 mode_relative = self.get_mode_by_xid(relative._mode)
895 if not relative or not relative._mode:
896 output._x = 0
897 output._y = 0
898 output._changes = output._changes | CHANGES_POSITION
899 if output._relation == RELATION_LEFT_OF:
900 output._y = relative._y + output._relation_offset
901 output._x = relative._x - get_mode_width(
902 mode, output._rotation)
903 elif output._relation == RELATION_RIGHT_OF:
904 output._y = relative._y + output._relation_offset
905 output._x = relative._x + get_mode_width(mode_relative,
906 output._rotation)
907 elif output._relation == RELATION_ABOVE:
908 output._y = relative._y - get_mode_height(mode,
909 output._rotation)
910 output._x = relative._x + output._relation_offset
911 elif output._relation == RELATION_BELOW:
912 output._y = relative._y + get_mode_height(mode_relative,
913 output._rotation)
914 output._x = relative._x + output._relation_offset
915 elif output._relation == RELATION_SAME_AS:
916 output._y = relative._y + output._relation_offset
917 output._x = relative._x + output._relation_offset
918 output._changes = output._changes | CHANGES_POSITION
919 # Normalize the postions so to the upper left cornor of all outputs
920 # is at 0,0
921 min_x = 32768
922 min_y = 32768
923 for output in self.get_outputs():
924 if output._mode is None:
925 continue
926 if output._x < min_x:
927 min_x = output._x
928 if output._y < min_y:
929 min_y = output._y
930 for output in self.get_outputs():
931 if output._mode is None:
932 continue
933 output._x -= min_x
934 output._y -= min_y
935 output._changes = output._changes | CHANGES_POSITION
936
937 def _calculate_size(self):
938 """Recalculate the pixel and physical size of the screen so that
939 it covers all outputs"""
940 width = self._width
941 height = self._height
942 for output in self.get_outputs():
943 if not output._mode:
944 continue
945 mode = self.get_mode_by_xid(output._mode)
946 x = output._x
947 y = output._y
948 w = get_mode_width(mode, output._rotation)
949 h = get_mode_height(mode, output._rotation)
950 if x + w > width:
951 width = x + w
952 if y + h > height:
953 height = y + h
954 if width > self._width_max or height > self._height_max:
955 raise RRError("The required size is not supported",
956 (width, height), (self._width_max, self._width_min))
957 else:
958 if height < self._height_min:
959 self._fb_height = self._height_min
960 else:
961 self._height = height
962 if width < self._width_min:
963 self._width = self._width_min
964 else:
965 self._width = width
966 #FIXME: Physical size is missing
967
968
969def get_current_display():
970 """Returns the currently used display"""
971 display_url = os.getenv("DISPLAY")
972 if display_url is None:
973 raise SystemExit("DISPLAY environment variable is not defined!")
974 open_display = xlib.XOpenDisplay
975 # Set .argtypes and .restype, to ensure proper
976 # type check and conversion
977 open_display.restype = c_void_p
978 open_display.argtypes = [c_char_p]
979 # XOpenDisplay accepts a char*, but
980 # display_url is a unicode string therefore
981 # we convert it to a bytes string
982 dpy = open_display(display_url.encode('utf-8'))
983 return dpy
984
985
986def get_current_screen():
987 """Returns the currently used screen"""
988 screen = Screen(get_current_display())
989 return screen
990
991
992def get_screen_of_display(display, count):
993 """Returns the screen of the given display"""
994 dpy = xlib.XOpenDisplay(display)
995 return Screen(dpy, count)
996
997
998def get_version():
999 """Returns a tuple containing the major and minor version of the xrandr
1000 extension or None if the extension is not available"""
1001 major = c_int()
1002 minor = c_int()
1003 res = rr.XRRQueryVersion(get_current_display(),
1004 byref(major), byref(minor))
1005 if res:
1006 return (major.value, minor.value)
1007 return None
1008
1009
1010def has_extension():
1011 """Returns True if the xrandr extension is available"""
1012 if XRANDR_VERSION:
1013 return True
1014 return False
1015
1016
1017def _to_gamma(gamma):
1018 g = rr.XRRAllocGamma(len(gamma[0]))
1019 for i in range(gamma[0]):
1020 g.red[i] = gamma[0][i]
1021 g.green[i] = gamma[1][i]
1022 g.blue[i] = gamma[2][i]
1023 return g
1024
1025
1026def _from_gamma(g):
1027 gamma = ([], [], [])
1028 for i in range(g.size):
1029 gamma[0].append(g.red[i])
1030 gamma[1].append(g.green[i])
1031 gamma[2].append(g.blue[i])
1032 rr.XRRFreeGamma(g)
1033
1034
1035def _check_required_version(version):
1036 """Raises an exception if the given or a later version of xrandr is not
1037 available"""
1038 if XRANDR_VERSION is None or XRANDR_VERSION < version:
1039 raise UnsupportedRRError(version, XRANDR_VERSION)
1040
1041
1042def get_mode_height(mode, rotation):
1043 """Return the height of the given mode taking the rotation into account"""
1044 if rotation & (RR_ROTATE_0 | RR_ROTATE_180):
1045 return mode.height
1046 elif rotation & (RR_ROTATE_90 | RR_ROTATE_270):
1047 return mode.width
1048 else:
1049 return 0
1050
1051
1052def get_mode_width(mode, rotation):
1053 """Return the width of the given mode taking the rotation into account"""
1054 if rotation & (RR_ROTATE_0 | RR_ROTATE_180):
1055 return mode.width
1056 elif rotation & (RR_ROTATE_90 | RR_ROTATE_270):
1057 return mode.height
1058 else:
1059 return 0
1060
1061
1062XRANDR_VERSION = get_version()
1063
1064# vim:ts=4:sw=4:et

Subscribers

People subscribed via source and target branches