summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@operamail.com>2014-09-07 14:50:15 +0200
committerMattias Andrée <maandree@operamail.com>2014-09-07 14:50:15 +0200
commit58fc31358cebb7f713b25608a0bc28fcda2b1958 (patch)
tree0e528e8d8ffd056fd79266adb33866a8846dcd47
parentcleanup in preparation for and preparation for use of pylibgamma (diff)
downloadblueshift-58fc31358cebb7f713b25608a0bc28fcda2b1958.tar.gz
blueshift-58fc31358cebb7f713b25608a0bc28fcda2b1958.tar.bz2
blueshift-58fc31358cebb7f713b25608a0bc28fcda2b1958.tar.xz
use pylibgamma1.90
Signed-off-by: Mattias Andrée <maandree@operamail.com>
Diffstat (limited to '')
-rw-r--r--Makefile3
-rw-r--r--info/blueshift.texinfo31
-rw-r--r--src/libgammaman.py119
-rw-r--r--src/monitor.py602
4 files changed, 242 insertions, 513 deletions
diff --git a/Makefile b/Makefile
index b59cbfc..ff51c92 100644
--- a/Makefile
+++ b/Makefile
@@ -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()