1111 If that URL should fail, try contacting the author.
1212'''
1313
14- from __future__ import (unicode_literals , absolute_import , division ,
15- print_function )
14+ from __future__ import (unicode_literals , print_function )
1615
1716__version__ = '0.0.8'
1817__author__ = "Mickaël 'Tiger-222' Schoentgen"
@@ -45,11 +44,9 @@ class ScreenshotError(Exception):
4544 from LaunchServices import kUTTypePNG
4645elif system () == 'Linux' :
4746 from os import environ
48- from os .path import expanduser
49- import xml .etree .ElementTree as ET
5047 from ctypes .util import find_library
51- from ctypes import byref , cast , cdll , POINTER , Structure , \
52- c_char_p , c_int , c_int32 , c_uint , c_uint32 , c_ulong , c_void_p
48+ from ctypes import byref , cast , cdll , POINTER , Structure , c_char_p , \
49+ c_int , c_int32 , c_long , c_uint , c_uint32 , c_ulong , c_ushort , c_void_p
5350
5451 class Display (Structure ):
5552 pass
@@ -76,6 +73,22 @@ class XImage(Structure):
7673 ('bits_per_pixel' , c_int ), ('red_mask' , c_ulong ),
7774 ('green_mask' , c_ulong ), ('blue_mask' , c_ulong )]
7875
76+ class XRRModeInfo (Structure ):
77+ pass
78+
79+ class XRRScreenResources (Structure ):
80+ _fields_ = [("timestamp" , c_ulong ), ("configTimestamp" , c_ulong ),
81+ ("ncrtc" , c_int ), ("crtcs" , POINTER (c_long )),
82+ ("noutput" , c_int ), ("outputs" , POINTER (c_long )),
83+ ("nmode" , c_int ), ("modes" , POINTER (XRRModeInfo ))]
84+
85+ class XRRCrtcInfo (Structure ):
86+ _fields_ = [("timestamp" , c_ulong ), ("x" , c_int ), ("y" , c_int ),
87+ ("width" , c_int ), ("height" , c_int ), ("mode" , c_long ),
88+ ("rotation" , c_int ), ("noutput" , c_int ),
89+ ("outputs" , POINTER (c_long )), ("rotations" , c_ushort ),
90+ ("npossible" , c_int ), ("possible" , POINTER (c_long ))]
91+
7992 def b (x ):
8093 return pack (b'<B' , x )
8194elif system () == 'Windows' :
@@ -352,10 +365,15 @@ def init(self):
352365 x11 = find_library ('X11' )
353366 if not x11 :
354367 raise ScreenshotError ('No X11 library found.' )
355-
356368 self .xlib = cdll .LoadLibrary (x11 )
357369 self .debug ('init' , 'xlib' , self .xlib )
358370
371+ xrandr = find_library ('Xrandr' )
372+ if not xrandr :
373+ raise ScreenshotError ('No Xrandr library found.' )
374+ self .xrandr = cdll .LoadLibrary (xrandr )
375+ self .debug ('init' , 'xrandr' , self .xrandr )
376+
359377 self ._set_argtypes ()
360378 self ._set_restypes ()
361379
@@ -398,6 +416,15 @@ def _set_argtypes(self):
398416 self .xlib .XGetPixel .argtypes = [POINTER (XImage ), c_int , c_int ]
399417 self .xlib .XFree .argtypes = [POINTER (XImage )]
400418 self .xlib .XCloseDisplay .argtypes = [POINTER (Display )]
419+ self .xrandr .XRRGetScreenResources .argtypes = [POINTER (Display ),
420+ POINTER (Display )]
421+ self .xrandr .XRRGetCrtcInfo .argtypes = [POINTER (Display ),
422+ POINTER (XRRScreenResources ),
423+ c_long ]
424+ self .xrandr .XRRFreeScreenResources .argtypes = [
425+ POINTER (XRRScreenResources )
426+ ]
427+ self .xrandr .XRRFreeCrtcInfo .argtypes = [POINTER (XRRCrtcInfo )]
401428
402429 def _set_restypes (self ):
403430 ''' Functions return type '''
@@ -406,84 +433,17 @@ def _set_restypes(self):
406433
407434 self .xlib .XOpenDisplay .restype = POINTER (Display )
408435 self .xlib .XDefaultScreen .restype = c_int
409- self .xlib . XDefaultRootWindow .restype = POINTER (XWindowAttributes )
436+ self .xrandr . XRRGetCrtcInfo .restype = POINTER (XRRCrtcInfo )
410437 self .xlib .XGetWindowAttributes .restype = c_int
411438 self .xlib .XAllPlanes .restype = c_ulong
412439 self .xlib .XGetImage .restype = POINTER (XImage )
413440 self .xlib .XGetPixel .restype = c_ulong
414441 self .xlib .XFree .restype = c_void_p
415442 self .xlib .XCloseDisplay .restype = c_void_p
416-
417- def _x11_config (self ):
418- ''' Try to determine display monitors from X11 configuration file:
419- ~/.config/monitors.xml
420- '''
421-
422- self .debug ('_x11_config' )
423-
424- monitors = expanduser ('~/.config/monitors.xml' )
425- if not os .path .isfile (monitors ):
426- self .debug ('ERROR' , 'MSSLinux: _x11_config() failed.' )
427- return
428-
429- tree = ET .parse (monitors )
430- root = tree .getroot ()
431- config = root .findall ('configuration' )[- 1 ]
432- conf = []
433- for output in config .findall ('output' ):
434- name = output .get ('name' )
435- if name != 'default' :
436- x = output .find ('x' )
437- y = output .find ('y' )
438- width = output .find ('width' )
439- height = output .find ('height' )
440- rotation = output .find ('rotation' )
441- if None not in [x , y , width , height ] and name not in conf :
442- conf .append (name )
443- if rotation .text in ['left' , 'right' ]:
444- width , height = height , width
445- yield ({
446- b'left' : int (x .text ),
447- b'top' : int (y .text ),
448- b'width' : int (width .text ),
449- b'height' : int (height .text ),
450- b'rotation' : rotation .text
451- })
452-
453- def _xfce4_config (self ):
454- ''' Try to determine display monitors from XFCE4 configuration file:
455- ~/.config/xfce4/xfconf/xfce-perchannel-xml/displays.xml
456- '''
457-
458- self .debug ('_xfce4_config' )
459-
460- path_ = '~/.config/xfce4/xfconf/xfce-perchannel-xml/displays.xml'
461- monitors = expanduser (path_ )
462- if not os .path .isfile (monitors ):
463- self .debug ('ERROR' , 'MSSLinux: _xfce4_config() failed.' )
464- return
465-
466- rotations = {0 : 'normal' , 90 : 'left' , 270 : 'right' }
467- tree = ET .parse (monitors )
468- root = tree .getroot ()
469- config = root .findall ('property' )[0 ]
470- for output in config .findall ('property' ):
471- name = output .get ('name' )
472- if name != 'default' :
473- active , res , _ , rot , _ , _ , pos = output .findall ('property' )
474- if active .get ('value' ) == 'true' :
475- width , height = res .get ('value' ).split ('x' )
476- rotation = rotations [int (rot .get ('value' ))]
477- if rotation in ['left' , 'right' ]:
478- width , height = height , width
479- posx , posy = pos .findall ('property' )
480- yield ({
481- b'left' : int (posx .get ('value' )),
482- b'top' : int (posy .get ('value' )),
483- b'width' : int (width ),
484- b'height' : int (height ),
485- b'rotation' : rotation
486- })
443+ self .xlib .XDefaultRootWindow .restype = POINTER (XWindowAttributes )
444+ self .xrandr .XRRGetScreenResources .restype = POINTER (XRRScreenResources )
445+ self .xrandr .XRRFreeScreenResources .restype = c_void_p
446+ self .xrandr .XRRFreeCrtcInfo .restype = c_void_p
487447
488448 def enum_display_monitors (self , screen = 0 ):
489449 ''' Get positions of one or more monitors.
@@ -502,12 +462,23 @@ def enum_display_monitors(self, screen=0):
502462 b'height' : int (gwa .height )
503463 })
504464 else :
505- # It is a little more complicated, we have to guess all stuff
506- # from differents XML configuration files.
507- for config in ['x11' , 'xfce4' ]:
508- for mon in getattr (self , '_{}_config' .format (config ))():
509- if mon :
510- yield mon
465+ # Fix for XRRGetScreenResources:
466+ # expected LP_Display instance instead of LP_XWindowAttributes
467+ root = cast (self .root , POINTER (Display ))
468+ mon = self .xrandr .XRRGetScreenResources (self .display , root )
469+ self .debug ('enum_display_monitors' , 'number of monitors' ,
470+ mon .contents .noutput - 1 )
471+ for num in range (mon .contents .noutput - 1 ):
472+ crtc_info = self .xrandr .XRRGetCrtcInfo (self .display , mon ,
473+ mon .contents .crtcs [num ])
474+ yield ({
475+ b'left' : int (crtc_info .contents .x ),
476+ b'top' : int (crtc_info .contents .y ),
477+ b'width' : int (crtc_info .contents .width ),
478+ b'height' : int (crtc_info .contents .height )
479+ })
480+ self .xrandr .XRRFreeCrtcInfo (crtc_info )
481+ self .xrandr .XRRFreeScreenResources (mon )
511482
512483 def get_pixels (self , monitor ):
513484 ''' Retrieve all pixels from a monitor. Pixels have to be RGB.
0 commit comments