diff options
Diffstat (limited to '')
| -rw-r--r-- | src/libgammaman.py | 119 | ||||
| -rw-r--r-- | src/monitor.py | 592 | 
2 files changed, 234 insertions, 477 deletions
| 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 * +import libgammaman +import libgamma -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 +def close_c_bindings(): +    ''' +    Close all C bindings and let them free resources and close connections +    ''' +    libgammaman.close() -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 -''' - -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(): +def set_gamma(*crtcs, screen = 0, display = None, method = None):      ''' -    Close all C bindings and let them free resources and close connections +    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      ''' -    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() +    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,94 +508,63 @@ 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 +    method = libgammaman.get_method(method) +    display_ = libgammaman.get_display(display, method) +    screen_n = display_.partitions_available +    rc = Screens() +    rc.screens = [None] * screen_n -    @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() +    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():      ''' @@ -753,210 +572,29 @@ def list_screens_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 +    return list_screens('drm', None) - -class DRMManager: +def list_screens_quartz():      ''' -    Manager for DRM connections to avoid monitor flicker on unnecessary connections -     -    There should only be one instance of this class +    Retrieve informantion about all screens, outputs and CRTC:s, using Quartz -    @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  :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 __init__(self): -        ''' -        Constructor -        ''' -        self.is_open, self.cards, self.connectors = False, None, None -     -    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() +    @return  :Screens  An instance of a datastructure with the relevant information +    ''' +    return list_screens('w32gdi', None) -drm_manager = DRMManager() -''' -:DRMManager  Manager for DRM connections to avoid monitor flicker on unnecessary connections -''' + +def quartz_restore(): +    ''' +    Restore all CRTC:s' gamma ramps the settings in ColorSync +    ''' +    method = libgammaman.get_method('quartz') +    libgammaman.get_display(None, method).restore() | 
