diff options
author | Mattias Andrée <maandree@operamail.com> | 2014-09-07 14:50:15 +0200 |
---|---|---|
committer | Mattias Andrée <maandree@operamail.com> | 2014-09-07 14:50:15 +0200 |
commit | 58fc31358cebb7f713b25608a0bc28fcda2b1958 (patch) | |
tree | 0e528e8d8ffd056fd79266adb33866a8846dcd47 | |
parent | cleanup in preparation for and preparation for use of pylibgamma (diff) | |
download | blueshift-1.90.tar.gz blueshift-1.90.tar.bz2 blueshift-1.90.tar.xz |
use pylibgamma1.90
Signed-off-by: Mattias Andrée <maandree@operamail.com>
Diffstat (limited to '')
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | info/blueshift.texinfo | 31 | ||||
-rw-r--r-- | src/libgammaman.py | 119 | ||||
-rw-r--r-- | src/monitor.py | 602 |
4 files changed, 242 insertions, 513 deletions
@@ -67,7 +67,8 @@ FLAGS = $$($(PKGCONFIG) --cflags $(LIBS)) -std=$(STD) $(WARN) $(OPTIMISE) \ DATAFILES = 2deg 10deg redshift redshift_old # Python source files PYFILES = __main__.py colour.py curve.py monitor.py solar.py icc.py adhoc.py \ - backlight.py blackbody.py aux.py weather.py interpolation.py + backlight.py blackbody.py aux.py weather.py interpolation.py \ + libgammaman.py # Configuration script example files EXAMPLES = comprehensive sleepmode crtc-detection crtc-searching logarithmic \ xmobar xpybar stored-settings current-settings xmonad threaded \ diff --git a/info/blueshift.texinfo b/info/blueshift.texinfo index 89c7bde..d130bb3 100644 --- a/info/blueshift.texinfo +++ b/info/blueshift.texinfo @@ -1640,7 +1640,7 @@ curves) are @code{drm} and @code{drm_get}, respectively. The parameters are exactly the same for the DRM functions as they are for the RandR functions: @code{screen} is still -named @code{screee} instead of @code{card}, +named @code{screen} instead of @code{card}, and @code{display} is still present but has not effect. @@ -1702,21 +1702,6 @@ GDI, except the functions are named @code{quartz} and @code{quartz_get}, respectively. -@c TODO resolve this (Windows and Mac OS X) -Be aware than the following may change -in a future version of Blueshift as support -for Windows and Mac OS X increases. - -Both Windows GDI and Quartz have support -for getting the number of available CRTC:s. -It is however not as full featured as for -RandR and DRM so @code{list_screens} cannot -be used. Instead, use the functions -@code{w32gdi_crtc_count} and -@code{quartz_crtc_count}, respectively. -They take no arguments and return an integer -with the number of available CRTC:s. - Quartz also have support for resetting the adjustment on each and every monitor on the system to this on ColorSync. To perform @@ -1724,20 +1709,6 @@ this action run the function @code{quartz_restore}. It takes no arguments and does not return any value. -Again, the support for Windows and Mac OS X, is -minimal. For now, if you want to use either of -@code{w32gdi_crtc_count}, @code{quartz_crtc_count} -and @code{quartz_restore} before Windows GDI -or Quartz have been used via @code{w32gdi}, -@code{w32gdi_get}, @code{quartz} or @code{quartz_get}, -you will have to initialise them. The easiest -way to do this is to just run @code{w32gdi_get} -or @code{quartz_get}. Another way to do this -is to run @code{w32gdi_open} or @code{quartz_open} -and when done run @code{w32gdi_close} or -@code{quartz_close}. Neither of these functions -take any arguments nor returns any value. - @node Optimising @section Optimising 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() |