From 58fc31358cebb7f713b25608a0bc28fcda2b1958 Mon Sep 17 00:00:00 2001
From: Mattias Andrée <maandree@operamail.com>
Date: Sun, 7 Sep 2014 14:50:15 +0200
Subject: use pylibgamma
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Mattias Andrée <maandree@operamail.com>
---
 src/libgammaman.py | 119 +++++++++++
 src/monitor.py     | 602 +++++++++++------------------------------------------
 2 files changed, 239 insertions(+), 482 deletions(-)
 create mode 100644 src/libgammaman.py

(limited to 'src')

diff --git a/src/libgammaman.py b/src/libgammaman.py
new file mode 100644
index 0000000..fb33907
--- /dev/null
+++ b/src/libgammaman.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python3
+
+# Copyright © 2014  Mattias Andrée (maandree@member.fsf.org)
+# 
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This module is responsible for keeping track of resources for
+# the monitor module.
+
+import libgamma
+
+
+cache = {}
+'''
+Resource cache
+'''
+
+
+def get_method(name):
+    '''
+    Translate an adjustment method name into an ID
+    
+    @param   name:str?  The adjustment method's name
+    @return  :int       The adjustment method's ID
+    '''
+    method = { 'randr'   : libgamma.LIBGAMMA_METHOD_X_RANDR
+             , 'vidmode' : libgamma.LIBGAMMA_METHOD_X_VIDMODE
+             , 'drm'     : libgamma.LIBGAMMA_METHOD_LINUX_DRM
+             , 'w32gdi'  : libgamma.LIBGAMMA_METHOD_W32_GDI
+             , 'quartz'  : libgamma.LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS
+             , 'dummy'   : libgamma.LIBGAMMA_METHOD_DUMMY
+             , None      : None
+             }
+    method = method[name] if name in method else None
+    if name is None:
+        method = libgamma.list_methods(0)[0]
+    elif method is None:
+        raise Exception('Invalid method: %s' % name)
+    elif not libgamma.is_method_available(method):
+        raise Exception('Invalid method: %s' % name)
+    return method
+
+
+def get_display(display, method):
+    '''
+    Get a display
+    
+    @param   display:str?       The display ID
+    @param   method:int         The adjustment method
+    @return  :libgamma.Display  Display object
+    '''
+    if display is None:
+        display = libgamma.method_default_site(method)
+    if method not in cache:
+        cache[method] = {}
+    cache_displays = cache[method]
+    if display not in cache_displays:
+        site = libgamma.Site(method, display)
+        cache_displays[display] = site
+        site.cache_screens = {}
+    return cache_displays[display]
+
+
+def get_screen(screen, display, method):
+    '''
+    Get a screen
+    
+    @param   screen:int        The screen index
+    @param   display:str?      The display ID
+    @param   method:int        The adjustment method
+    @return  :libgamma.Screen  Screen object
+    '''
+    display = get_display(display, method)
+    cache_screens = display.cache_screens
+    if screen not in cache_screens:
+        partition = libgamma.Partition(display, screen)
+        cache_screens[screen] = partition
+        partition.cache_crtcs = {}
+    return cache_screens[screen]
+
+
+def get_crtc(crtc, screen, display, method):
+    '''
+    Get a CRTC
+    
+    @param   crtc:int        The CRTC index
+    @param   screen:int      The screen index
+    @param   display:str?    The display ID
+    @param   method:int      The adjustment method
+    @return  :libgamma.CRTC  CRTC object
+    '''
+    screen = get_screen(screen, display, method)
+    cache_crtcs = screen.cache_crtcs
+    if crtc not in cache_crtcs:
+        monitor = libgamma.CRTC(screen, crtc)
+        cache_crtcs[crtc] = monitor
+        (monitor.info, _) = monitor.information(~0)
+    return cache_crtcs[crtc]
+
+
+def close():
+    '''
+    Release all resources
+    '''
+    global cache
+    del cache
+    cache = {}
+
diff --git a/src/monitor.py b/src/monitor.py
index bfed220..7891370 100644
--- a/src/monitor.py
+++ b/src/monitor.py
@@ -15,6 +15,8 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+# This module is responsible for access to the monitors.
+
 import os
 import sys
 from subprocess import Popen, PIPE
@@ -22,81 +24,60 @@ from subprocess import Popen, PIPE
 from aux import *
 from curve import *
 
-
-LIBEXECDIR = 'bin'
-'''
-:str  Path to executable libraries, '/usr/libexec' is standard
-'''
-
-
-## Load DRM module
-try:
-    from blueshift_drm import *
-except:
-    # Not compiled with DRM support
-    pass
-
-## Load W32 GDI module
-try:
-    from blueshift_w32gdi import *
-except:
-    # Not compiled with W32 GDI support
-    pass
-
-## Load Quartz module
-try:
-    from blueshift_quartz import *
-except:
-    # Not compiled with Quartz support
-    pass
+import libgammaman
+import libgamma
 
 
-randr_opened = None
-'''
-:(int, str)?  The index of the, with RandR, opened X screen and X display, if any
-'''
 
-vidmode_opened = None
-'''
-:(int, str)?  The index of the, with VidMode, opened X screen and X display, if any
-'''
+def close_c_bindings():
+    '''
+    Close all C bindings and let them free resources and close connections
+    '''
+    libgammaman.close()
 
-w32gdi_opened = False
-'''
-:bool  Whether W32 GDI is in use
-'''
 
-quartz_opened = False
-'''
-:bool  Whether Quartz is in use
-'''
+def get_gamma(crtc = 0, screen = 0, display = None, *, method = None):
+    '''
+    Gets the current colour curves
+    
+    @param   crtc:int      The CRTC of the monitor to read from
+    @param   screen:int    The screen to which the monitors belong
+    @param   display:str?  The display to which to connect, `None` for current display
+    @param   method:str?   The adjustment method
+    @return  :()→void      Function to invoke to apply the curves that was used when this function was invoked
+    '''
+    # Get CRTC objet
+    method = libgammaman.get_method(method)
+    crtc = libgammaman.get_crtc(crtc, screen, display, method)
+    # Create gamma ramps
+    ramps = libgamma.GammaRamps(i_size, i_size, i_size)
+    # Get gamma
+    crtc.get_gamma(ramps)
+    return ramps_to_function(ramps.red, ramps.green, ramps.blue)
 
 
-def close_c_bindings():
-    '''
-    Close all C bindings and let them free resources and close connections
+def set_gamma(*crtcs, screen = 0, display = None, method = None):
     '''
-    global randr_opened, vidmode_opened, w32gdi_opened, quartz_opened
-    if randr_opened is not None:
-        # Close RandR connection if open
-        from blueshift_randr import randr_close
-        randr_opened = None
-        randr_close()
-    if vidmode_opened is not None:
-        # Close VidMode connection if open
-        from blueshift_vidmode import vidmode_close
-        vidmode_opened = None
-        vidmode_close()
-    if w32gdi_opened:
-        # Close W32 GDI connection if open
-        w32gdi_opened = False
-        w32gdi_close()
-    if quartz_opened:
-        # Close Quartz connection if open
-        quartz_opened = False
-        quartz_close()
-    # Close DRM connection if open
-    drm_manager.close()
+    Applies colour curves
+    
+    @param  crtcs:*int    The CRT controllers to use, all are used if none are specified
+    @param  screen:int    The screen to which the monitors belong
+    @param  display:str?  The display to which to connect, `None` for current display
+    @param  method:str?   The adjustment method
+    '''
+    for crtc in (0,) if len(crtcs) == 0 else crtcs:
+        # Convert curves to [0, 0xFFFF] integer lists
+        (R_curve, G_curve, B_curve) = translate_to_integers()
+        # Get CRTC objet
+        method = libgammaman.get_method(method)
+        crtc = libgammaman.get_crtc(crtc, screen, display, method)
+        # Create gamma ramps
+        ramps = libgamma.GammaRamps(i_size, i_size, i_size)
+        # Set gamma
+        ramps.red[:] = R_curve
+        ramps.green[:] = G_curve
+        ramps.blue[:] = B_curve
+        crtc.set_gamma(ramps)
 
 
 def randr_get(crtc = 0, screen = 0, display = None):
@@ -108,21 +89,7 @@ def randr_get(crtc = 0, screen = 0, display = None):
     @param   display:str?  The display to which to connect, `None` for current display
     @return  :()→void      Function to invoke to apply the curves that was used when this function was invoked
     '''
-    from blueshift_randr import randr_open, randr_read, randr_close
-    global randr_opened
-    # Open new RandR connection if non is open or one is open to the wrong screen or display
-    if (randr_opened is None) or not (randr_opened == (screen, display)):
-        # Close RandR connection, if any, because its is connected to the wrong screen or display
-        if randr_opened is not None:
-            randr_close()
-        # Open RandR connection
-        if randr_open(screen, display if display is None else display.encode('utf-8')) == 0:
-            randr_opened = (screen, display)
-        else:
-            raise Exception('Cannot open RandR connection')
-    # Read current curves and create function
-    return ramps_to_function(*(randr_read(crtc)))
-
+    return get_gamma(crtc, screen, display, method = 'randr')
 
 def vidmode_get(crtc = 0, screen = 0, display = None):
     '''
@@ -133,21 +100,7 @@ def vidmode_get(crtc = 0, screen = 0, display = None):
     @param   display:str?  The display to which to connect, `None` for current display
     @return  :()→void      Function to invoke to apply the curves that was used when this function was invoked
     '''
-    from blueshift_vidmode import vidmode_open, vidmode_read, vidmode_close
-    global vidmode_opened
-    # Open new VidMode connection if non is open or one is open to the wrong screen or display
-    if (vidmode_opened is None) or not (vidmode_opened == (screen, display)):
-        # Close VidMode connection, if any, because its is connected to the wrong screen or display
-        if vidmode_opened is not None:
-            vidmode_close()
-        # Open VidMode connection
-        if vidmode_open(screen, display if display is None else display.encode('utf-8')):
-            vidmode_opened = (screen, display)
-        else:
-            raise Exception('Cannot open VidMode connection')
-    # Read current curves and create function
-    return ramps_to_function(*(vidmode_read()))
-
+    return get_gamma(crtc, screen, display, method = 'vidmode')
 
 def drm_get(crtc = 0, screen = 0, display = None):
     '''
@@ -158,11 +111,7 @@ def drm_get(crtc = 0, screen = 0, display = None):
     @param   display:str?  Dummy parameter for compatibility with `randr_get` and `vidmode_get`
     @return  :()→void      Function to invoke to apply the curves that was used when this function was invoked
     '''
-    # Get DRM connection, open if necessary
-    connection = drm_manager.open_card(screen)
-    # Read current curves and create function
-    return ramps_to_function(*(drm_get_gamma_ramps(connection, crtc, i_size)))
-
+    return get_gamma(crtc, screen, display, method = 'drm')
 
 def w32gdi_get(crtc = 0, screen = 0, display = None):
     '''
@@ -173,15 +122,7 @@ def w32gdi_get(crtc = 0, screen = 0, display = None):
     @param   display:str?  Dummy parameter for compatibility with `randr_get` and `vidmode_get`
     @return  :()→void      Function to invoke to apply the curves that was used when this function was invoked
     '''
-    global w32gdi_opened
-    # Open W32 GDI connection if necessary
-    if not w32gdi_opened:
-        w32gdi_opened = True
-        if (not w32gdi_open() == 0):
-            raise Exception("Could not open W32 GDI connection")
-    # Read current curves and create function
-    return ramps_to_function(*(w32gdi_read(crtc)))
-
+    return get_gamma(crtc, screen, display, method = 'w32gdi')
 
 def quartz_get(crtc = 0, screen = 0, display = None):
     '''
@@ -192,14 +133,7 @@ def quartz_get(crtc = 0, screen = 0, display = None):
     @param   display:str?  Dummy parameter for compatibility with `randr_get` and `vidmode_get`
     @return  :()→void      Function to invoke to apply the curves that was used when this function was invoked
     '''
-    global quartz_opened
-    # Open Quartz connection if necessary
-    if not quartz_opened:
-        quartz_opened = True
-        if (not quartz_open() == 0):
-            raise Exception("Could not open Quartz connection")
-    # Read current curves and create function
-    return ramps_to_function(*(quartz_read(crtc)))
+    return get_gamma(crtc, screen, display, method = 'quartz')
 
 
 def randr(*crtcs, screen = 0, display = None):
@@ -210,30 +144,7 @@ def randr(*crtcs, screen = 0, display = None):
     @param  screen:int    The screen to which the monitors belong
     @param  display:str?  The display to which to connect, `None` for current display
     '''
-    from blueshift_randr import randr_open, randr_apply, randr_close
-    global randr_opened
-    # Select CRTC:s
-    crtcs = list(crtcs) if len(crtcs) > 0 else [-1]
-    
-    # Convert curves to [0, 0xFFFF] integer lists
-    (R_curve, G_curve, B_curve) = translate_to_integers()
-    # Open new RandR connection if non is open or one is open to the wrong screen or display
-    if (randr_opened is None) or not (randr_opened == (screen, display)):
-        # Close RandR connection, if any, because its is connected to the wrong screen or display
-        if randr_opened is not None:
-            randr_close()
-        # Open RandR connection
-        if randr_open(screen, display if display is None else display.encode('utf-8')) == 0:
-            randr_opened = (screen, display)
-        else:
-            raise Exception('Cannot open RandR connection')
-    try:
-        # Apply adjustments
-        if not randr_apply(crtcs, R_curve, G_curve, B_curve) == 0:
-            raise Exception('Cannot use RandR to apply colour adjustments')
-    except OverflowError:
-        pass # Happens on exit by TERM signal
-
+    set_gamma(*crtcs, screen = screen, display = display, method = 'randr')
 
 def vidmode(*crtcs, screen = 0, display = None):
     '''
@@ -243,27 +154,7 @@ def vidmode(*crtcs, screen = 0, display = None):
     @param  screen:int    The screen to which the monitors belong
     @param  display:str?  The display to which to connect, `None` for current display
     '''
-    from blueshift_vidmode import vidmode_open, vidmode_apply, vidmode_close
-    global vidmode_opened
-    # Convert curves to [0, 0xFFFF] integer lists
-    (R_curve, G_curve, B_curve) = translate_to_integers()
-    # Open new vidmode connection if non is open or one is open to the wrong screen or display
-    if (vidmode_opened is None) or not (vidmode_opened == (screen, display)):
-        # Close vidmode connection, if any, because its is connected to the wrong screen or display
-        if vidmode_opened is not None:
-            vidmode_close()
-        # Open vidmode connection
-        if vidmode_open(screen, display if display is None else display.encode('utf-8')):
-            vidmode_opened = (screen, display)
-        else:
-            raise Exception('Cannot open VidMode connection')
-    try:
-        # Apply adjustments
-        if not vidmode_apply(R_curve, G_curve, B_curve) == 0:
-            raise Exception('Cannot use VidMode to apply colour adjustments')
-    except OverflowError:
-        pass # Happens on exit by TERM signal
-
+    set_gamma(*crtcs, screen = screen, display = display, method = 'vidmode')
 
 def drm(*crtcs, screen = 0, display = None):
     '''
@@ -274,19 +165,7 @@ def drm(*crtcs, screen = 0, display = None):
                           named `screen` for compatibility with `randr` and `vidmode`
     @param  display:str?  Dummy parameter for compatibility with `randr` and `vidmode`
     '''
-    # Get DRM connection, open if necessary
-    connection = drm_manager.open_card(screen)
-    # Convert curves to [0, 0xFFFF] integer lists
-    (R_curve, G_curve, B_curve) = translate_to_integers()
-    try:
-        # Select all CRTC:s if none have been selected
-        if len(crtcs) == 0:
-            crtcs = range(drm_crtc_count(connection))
-        # Apply adjustments
-        drm_set_gamma_ramps(connection, list(crtcs), i_size, R_curve, G_curve, B_curve)
-    except OverflowError:
-        pass # Happens on exit by TERM signal
-
+    set_gamma(*crtcs, screen = screen, display = display, method = 'drm')
 
 def w32gdi(*crtcs, screen = 0, display = None):
     '''
@@ -296,23 +175,7 @@ def w32gdi(*crtcs, screen = 0, display = None):
     @param  screen:int    Dummy parameter for compatibility with `randr`, `vidmode` and `drm`
     @param  display:str?  Dummy parameter for compatibility with `randr` and `vidmode`
     '''
-    global w32gdi_opened
-    # Open W32 GDI connection if necessary
-    if not w32gdi_opened:
-        w32gdi_opened = True
-        if (not w32gdi_open() == 0):
-            raise Exception("Could not open W32 GDI connection")
-    # Convert curves to [0, 0xFFFF] integer lists
-    (R_curve, G_curve, B_curve) = translate_to_integers()
-    try:
-        # Select all CRTC:s if none have been selected
-        if len(crtcs) == 0:
-            crtcs = range(w32gdi_crtc_count())
-        # Apply adjustments
-        w32gdi_apply(list(crtcs), R_curve, G_curve, B_curve)
-    except OverflowError:
-        pass # Happens on exit by TERM signal
-
+    set_gamma(*crtcs, screen = screen, display = display, method = 'w32gdi')
 
 def quartz(*crtcs, screen = 0, display = None):
     '''
@@ -322,20 +185,7 @@ def quartz(*crtcs, screen = 0, display = None):
     @param  screen:int    Dummy parameter for compatibility with `randr`, `vidmode` and `drm`
     @param  display:str?  Dummy parameter for compatibility with `randr` and `vidmode`
     '''
-    global quartz_opened
-    # Open Quartz connection if necessary
-    if not quartz_opened:
-        quartz_opened = True
-        if (not quartz_open() == 0):
-            raise Exception("Could not open Quartz connection")
-    try:
-        # Select all CRTC:s if none have been selected
-        if len(crtcs) == 0:
-            crtcs = range(quartz_crtc_count())
-        # Apply adjustments
-        quartz_apply(list(crtcs), r_curve, g_curve, b_curve)
-    except OverflowError:
-        pass # Happens on exit by TERM signal
+    set_gamma(*crtcs, screen = screen, display = display, method = 'quartz')
 
 
 def print_curves(*crtcs, screen = 0, display = None, compact = False):
@@ -658,305 +508,93 @@ class EDID:
             raise Exception('Incorrect EDID checksum')
 
 
-def list_screens(method = 'randr', display = None):
+def list_screens(method = None, display = None):
     '''
     Retrieve informantion about all screens, outputs and CRTC:s
     
-    @param   method:str    The listing method: 'randr' for RandR (under X),
+    @param   method:str?   The listing method: 'randr' for RandR (under X),
                                                'drm' for DRM (under TTY)
+                                               `None` for automatic
     @param   display:str?  The display to use, `None` for the current one
     @return  :Screens      An instance of a datastructure with the relevant information
     '''
-    if method == 'randr':   return list_screens_randr(display = display)
-    if method == 'drm':     return list_screens_drm()
-    raise Exception('Invalid method: %s' % method)
-
-
-def list_screens_randr(display = None):
-    '''
-    Retrieve informantion about all screens, outputs and CRTC:s, using RandR
-    
-    @param   display:str?  The display to use, `None` for the current one
-    @return  :Screens      An instance of a datastructure with the relevant information
-    '''
-    # Generate command line arguments to execute
-    command = [LIBEXECDIR + os.sep + 'blueshift_idcrtc']
-    if display is not None:
-        command.append(display)
-    # Spawn the executable library blueshift_idcrtc
-    process = Popen(command, stdout = PIPE)
-    # Wait for the child process to exit and gather its output to stdout
-    lines = process.communicate()[0].decode('utf-8', 'error').split('\n')
-    # Ensure that the child process has exited
-    while process.returncode is None:
-        process.wait()
-    # Raise an exception if the child process failed
-    if process.returncode != 0:
-        raise Exception('blueshift_idcrtc exited with value %i' % process.returncode)
-    # Trim the beginning of each line, that is, remove the
-    # indention added for human readablility
-    lines = [line.strip() for line in lines]
-    screens, screen_i, screen, output = None, None, None, None
-    for line in lines:
-        if line.startswith('Screen count: '):
-            # Prepare the screen table when we know how many screens there are
-            screens = [None] * int(line[len('Screen count: '):])
-        elif line.startswith('Screen: '):
-            # Get the index of the next screen
-            screen_i = int(line[len('Screen: '):])
-            # And add it to the table
-            screens[screen_i] = screen = Screen()
-        elif line.startswith('CRTC count: '):
-            # Store the number of CRTC:s
-            screen.crtc_count = int(line[len('CRTC count: '):])
-        elif line.startswith('Output count: '):
-            # Prepare the current screens output table when we know how many outputs it has
-            screen.outputs = [None] * int(line[len('Output count: '):])
-        elif line.startswith('Output: '):
-            # Get the index of the next output
-            output_i = int(line[len('Output: '):])
-            # Create structure for the output
-            output = Output()
+    method = libgammaman.get_method(method)
+    display_ = libgammaman.get_display(display, method)
+    screen_n = display_.partitions_available
+    rc = Screens()
+    rc.screens = [None] * screen_n
+    
+    for screen_i in range(screen_n):
+        screen = libgammaman.get_screen(screen_i, display, method)
+        # And add it to the table
+        rc.screens[screen_i] = s = Screen()
+        # Store the number of CRTC:s
+        s.crtc_count = crtc_n = screen.crtcs_available
+        # Prepare the current screens output table when we know how many outputs it has
+        s.outputs = [None] * crtc_n
+        for crtc_i in range(crtc_n):
+            crtc = libgamma.CRTC(screen, crtc_i)
+            (info, _) = crtc.information(~0)
+            s.outputs[crtc_i] = o = Output()
             # Store the screen index for the output so that it is easy
             # to look it up when iterating over outputs
-            output.screen = screen_i
-            # Store the output in the table
-            screen.outputs[output_i] = output
-        elif line.startswith('Name: '):
+            o.screen = screen_i
             # Store the name of the output
-            output.name = line[len('Name: '):]
-        elif line.startswith('Connection: '):
+            o.name = info.connector_name if info.connector_name_error == 0 else None
             # Store the connection status of the output's connector
-            output.connected = line[len('Connection: '):] == 'connected'
-        elif line.startswith('Size: '):
+            o.connected = info.active if info.active_error == 0 else None
             # Store the physical dimensions of the monitor
-            output.widthmm, output.heightmm = [int(x) for x in line[len('Size: '):].split(' ')]
+            o.widthmm, o.heightmm = info.width_mm, info.height_mm
             # But if it is zero or less it is unknown
-            if (output.widthmm <= 0) or (output.heightmm <= 0):
-                output.widthmm, output.heightmm = None, None
-        elif line.startswith('CRTC: '):
+            if (o.widthmm <= 0) or (o.heightmm <= 0):
+                o.widthmm, o.heightmm = None, None
             # Store the CRTC index of the output
-            output.crtc = int(line[len('CRTC: '):])
-        elif line.startswith('EDID: '):
+            o.crtc = crtc_i
             # Store the output's extended dislay identification data
-            output.edid = line[len('EDID: '):]
-    # Store all screens in a special class that
-    # makes it easier to use them collectively
-    rc = Screens()
-    rc.screens = screens
+            o.edid = None if info.edid is None or not info.edid_error == 0 else libgamma.behex_edid(info.edid)
+    
     return rc
+    
 
 
+def list_screens_randr(display = None):
+    '''
+    Retrieve informantion about all screens, outputs and CRTC:s, using RandR
+    
+    @param   display:str?  The display to use, `None` for the current one
+    @return  :Screens      An instance of a datastructure with the relevant information
+    '''
+    return list_screens('randr', display)
+
 def list_screens_drm():
     '''
     Retrieve informantion about all screens, outputs and CRTC:s, using DRM
     
     @return  :Screens  An instance of a datastructure with the relevant information
     '''
-    ## This method should not use `drm_manager` because we want to be able to find updates
-    # Create instance of class with all the graphics cards so that it is easy
-    # to use them collectively,
-    screens = Screens()
-    # and create the list to fill with graphics cards.
-    screens.screens = []
-    ## When using DRM we will often call graphics cards ‘screens’ as
-    ## to keep consisitence with X extension. In real world use, it is
-    ## usally equivalent, except for the order of the CRTC:s.
-    # For each graphics card, by index:
-    for card in range(drm_card_count()):
-        # Create an instance which makes it easy to use the
-        # graphics cards, such as searching for monitors,
-        screen = Screen()
-        # and append it to the list of graphics cards.
-        screens.screens.append(screen)
-        # Acquire resources for the graphics card,
-        connection = drm_open_card(card)
-        # but just ignore the card on failure.
-        if connection == -1:
-            continue # TODO could this fail if the card is already used by Blueshift?
-        # As our DRM module's API dictates, update the resources
-        drm_update_card(connection)
-        # Store the number of CRTC:s, so that it can
-        # be easily accessed; all connectors do not have a CRTCs,
-        # because they need to have a monitor connected an unused
-        # connectors are also listed.
-        screen.crtc_count = drm_crtc_count(connection)
-        # Create a graphics card local str → int map from the
-        # connector type name of the number of used such connectors
-        # so that we can name the outputs uniquely within the
-        # scope of the card with reason names. These will not be
-        # the same as the named given by RandR or `/sys/class/drm`.
-        used_names = {}
-        # For each connector of the graphics card:
-        for connector in range(drm_connector_count(connection)):
-            # Open a connection to the connector
-            drm_open_connector(connection, connector)
-            # Create an instance of a data structure to store output information inside,
-            output = Output()
-            # and add it to the list of outputs for the graphics card.
-            screen.outputs.append(output)
-            # The connector type name
-            output.name = drm_get_connector_type_name(connection, connector)
-            # and append an index to it and use that as the name of the output.
-            if output.name not in used_names:
-                # Start at zero,
-                used_names[output.name] = 0
-            # and count upwards as the type of connector reoccurs.
-            count = used_names[output.name]
-            used_names[output.name] += 1
-            output.name = '%s-%i' % (output.name, count)
-            # Store the connection status of the connector,
-            # but assume it is disconnected if it is unknown.
-            output.connected = drm_is_connected(connection, connector) == 1
-            if output.connected:
-                # Store the physical dimensions of the monitor
-                output.widthmm = drm_get_width(connection, connector)
-                output.heightmm = drm_get_height(connection, connector)
-                # But if it is zero or less it is unknown
-                if (output.widthmm <= 0) or (output.heightmm <= 0):
-                    output.widthmm, output.heightmm = None, None
-                # Store the output's CRTC index
-                output.crtc = drm_get_crtc(connection, connector)
-                # Store the output's extended display identification data
-                output.edid = drm_get_edid(connection, connector)
-            # Store the graphics card index for the output so that
-            # it is easy to look it up when iterating over outputs
-            output.screen = card
-            # Now that we are done with the connector, close its resources
-            drm_close_connector(connection, connector)
-        # Now that we are done with the graphics card, close its resources
-        drm_close_card(connection)
-    # Mark that the DRM module has been used so that
-    # resource as properly freed. This is the only
-    # time in this function `drm_manager` shall be used.
-    drm_manager.is_open = True
-    return screens
-
-
-class DRMManager:
-    '''
-    Manager for DRM connections to avoid monitor flicker on unnecessary connections
-    
-    There should only be one instance of this class
-    
-    @variable  is_open:bool      Whether the DRM module has been used
-    @variable  cards:list<int>?  Map from card index to connection file descriptors, -1 if not connected
+    return list_screens('drm', None)
+
+def list_screens_quartz():
     '''
+    Retrieve informantion about all screens, outputs and CRTC:s, using Quartz
     
-    def __init__(self):
-        '''
-        Constructor
-        '''
-        self.is_open, self.cards, self.connectors = False, None, None
+    @return  :Screens  An instance of a datastructure with the relevant information
+    '''
+    return list_screens('quartz', None)
+
+def list_screens_w32gdi():
+    '''
+    Retrieve informantion about all screens, outputs and CRTC:s, using Windows GDI
     
-    def open_card(self, card):
-        '''
-        Make sure there is a connection to a specific card
-        
-        @param   card:int  The index of the card
-        @return  :int      -1 on failure, otherwise the identifier for the connection
-        '''
-        # Mark that the DRM module has been used
-        self.is_open = True
-        # Initialise connection map if not already initialised,
-        if self.cards is None:
-            self.cards = [-1] * drm_card_count()
-            # and the graphics card layer of the connector map.
-            self.connectors = [None] * drm_card_count()
-        # If we are not connected to the desired graphics card
-        if self.cards[card] == -1:
-            # connect to it
-            self.cards[card] = drm_open_card(card)
-            # and acquire resources.
-            drm_update_card(self.cards[card])
-        return self.cards[card]
-    
-    def open_connector(self, card, connector):
-        '''
-        Make sure there is a connection to a specific connector
-        
-        @param  card:int       The index of the card with the connector, must already be opened
-        @param  connector:int  The index of the connector
-        '''
-        # The file descriptor of the connection to the graphics card,
-        connection = self.open_card(card)
-        # and initialise the connector map if not alreadt initialised.
-        if self.connectors[card] is None:
-            self.connectors[card] = [False] * drm_connector_count()
-        # Then, if the connector is not already opened,
-        if not self.connectors[card][connector]:
-            # mark it as opened,
-            self.connectors[card][connector] = True
-            # and open it.
-            drm_open_connector(connection, connector)
-    
-    def close_connector(self, card, connector):
-        '''
-        Make sure there is no connection to a specific connector
-        
-        @param  card:int       The index of the card with the connector
-        @param  connector:int  The index of the connector
-        '''
-        # If no graphics card has been opened, do nothing
-        if self.cards is None:  return
-        # Otherwise get the connection to the graphics card,
-        connection = self.cards[card]
-        # but do nothing if is has not been opened.
-        if connection == -1:  return
-        # Neither do anything if no connector has been used.
-        if self.connectors[card] is None:  return
-        # If the connector has been used,
-        if self.connectors[card][connector]:
-            # mark it as unused,
-            self.connectors[card][connector] = False
-            # as close it.
-            drm_close_connector(connection, connector)
-    
-    def close_card(self, card):
-        '''
-        Make sure there is no connection to a specific card
-        
-        @param  card:int  The index of the card
-        '''
-        # Do nothing is no graphics card has been used
-        if self.cards is None:
-            return
-        # Otherwise get the file descriptor of the connection to the card.
-        connection = self.cards[card]
-        # If The graphics card has been used
-        if not connection == -1:
-            # Mark it as unused,
-            self.cards[card] = -1
-            # and close the connection to any opened connector
-            if self.connectors[card] is not None:
-                # by iterating over the connectors
-                for i in range(len(self.connectors[card])):
-                    # and close any opened connector
-                    if self.connectors[card][i]:
-                        drm_close_connector(connection, i)
-                # and then mark all connectors as unused.
-                self.connectors[card] = None
-            # Close the connection to the graphics card
-            drm_close_card(connection)
-    
-    def close(self):
-        '''
-        Close all connections
-        '''
-        # If the DRM module as been used
-        if self.is_open:
-            # Makr it as unused
-            self.is_open = False
-            # And close all connections to the graphics cards and their connectors
-            if self.cards is not None:
-                for card in range(len(self.cards)):
-                    self.close_card(card)
-                self.cards = None
-            # And close finally close the connection to DRM
-            drm_close()
-
-drm_manager = DRMManager()
-'''
-:DRMManager  Manager for DRM connections to avoid monitor flicker on unnecessary connections
-'''
+    @return  :Screens  An instance of a datastructure with the relevant information
+    '''
+    return list_screens('w32gdi', None)
+
+
+def quartz_restore():
+    '''
+    Restore all CRTC:s' gamma ramps the settings in ColorSync
+    '''
+    method = libgammaman.get_method('quartz')
+    libgammaman.get_display(None, method).restore()
 
-- 
cgit v1.2.3-70-g09d2