From f24b1e38904f1baf351502bfa630b3b9d7d2e2f1 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Thu, 3 Apr 2014 00:10:43 +0200 Subject: add multi-display support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- TODO | 6 ++- src/blueshift_randr.pyx | 14 ++++--- src/blueshift_randr_c.c | 5 ++- src/blueshift_randr_c.h | 3 +- src/blueshift_vidmode.pyx | 14 ++++--- src/blueshift_vidmode_c.c | 25 +++++++------ src/blueshift_vidmode_c.h | 3 +- src/monitor.py | 93 +++++++++++++++++++++++++---------------------- 8 files changed, 92 insertions(+), 71 deletions(-) diff --git a/TODO b/TODO index fa56580..a1cd619 100644 --- a/TODO +++ b/TODO @@ -2,15 +2,17 @@ High priority: Add support for monitor hotplugging Add models for calculating fade and refresh rate parameters Test with multiple X screens + Test, document and demo multi-display support Medium priority: Add a section in manual for information on which order to apply settings and how it affects the result. + Import multi-screen and multi-display support so that new + connections are not need all the time. Low priority: - Raw ramp applying functions with precalcuated interpolation, polynomial + Raw ramp applying functions with precalcuated polynomial interpolation Add support for temporarily closing DRM connection so that multiple users can run in DRM - Add multi-display support (for example operating on two X displays) Future stuff: Add wayland support (could not find an API for it, but xwayland works) diff --git a/src/blueshift_randr.pyx b/src/blueshift_randr.pyx index f54a5c9..756ea73 100644 --- a/src/blueshift_randr.pyx +++ b/src/blueshift_randr.pyx @@ -19,7 +19,7 @@ cimport cython from libc.stdlib cimport malloc, free -cdef extern int blueshift_randr_open(int use_screen) +cdef extern int blueshift_randr_open(int use_screen, char* display) cdef extern unsigned short int* blueshift_randr_read(int use_crtc) cdef extern int blueshift_randr_apply(unsigned long long int use_crtcs, unsigned short int* r_curve, @@ -40,14 +40,18 @@ if (r_c is NULL) or (g_c is NULL) or (b_c is NULL): -def randr_open(int use_screen): +def randr_open(int use_screen, display): ''' Start stage of colour curve control - @param use_screen The screen to use - @return Zero on success + @param use_screen The screen to use + @param display:str? The display to use, `None` for the current + @return :int Zero on success ''' - return blueshift_randr_open(use_screen) + cdef char* display_ = NULL + if display is not None: + display_ = display + return blueshift_randr_open(use_screen, display_) def randr_read(int use_crtc): diff --git a/src/blueshift_randr_c.c b/src/blueshift_randr_c.c index 6a15715..0c99533 100644 --- a/src/blueshift_randr_c.c +++ b/src/blueshift_randr_c.c @@ -48,9 +48,10 @@ static blueshift_randr_crtc_t* crtcs_end; * Start stage of colour curve control * * @param use_screen The screen to use + * @param display The display to use, `NULL` for the current one * @return Zero on success */ -int blueshift_randr_open(int use_screen) +int blueshift_randr_open(int use_screen, char* display) { blueshift_randr_crtc_t* crtcs_; @@ -69,7 +70,7 @@ int blueshift_randr_open(int use_screen) /* Get X connection */ - connection = xcb_connect(NULL, NULL); + connection = xcb_connect(display, NULL); /* Check RandR protocol version */ diff --git a/src/blueshift_randr_c.h b/src/blueshift_randr_c.h index 5bae1de..db12770 100644 --- a/src/blueshift_randr_c.h +++ b/src/blueshift_randr_c.h @@ -62,9 +62,10 @@ typedef struct blueshift_randr_crtc * Start stage of colour curve control * * @param use_screen The screen to use + * @param display The display to use, `NULL` for the current one * @return Zero on success */ -int blueshift_randr_open(int use_screen); +int blueshift_randr_open(int use_screen, char* display); /** * Gets the current colour curves diff --git a/src/blueshift_vidmode.pyx b/src/blueshift_vidmode.pyx index 7f1810d..e4262d7 100644 --- a/src/blueshift_vidmode.pyx +++ b/src/blueshift_vidmode.pyx @@ -19,7 +19,7 @@ cimport cython from libc.stdlib cimport malloc, free -cdef extern int blueshift_vidmode_open(int use_screen) +cdef extern int blueshift_vidmode_open(int use_screen, char* display) cdef extern int blueshift_vidmode_read(int use_crtc, unsigned short int* r_curve, unsigned short int* g_curve, @@ -46,15 +46,19 @@ if (r_c is NULL) or (g_c is NULL) or (b_c is NULL): -def vidmode_open(int use_screen): +def vidmode_open(int use_screen, display): ''' Start stage of colour curve control - @param use_screen The screen to use - @return :bool Whether call was successful + @param use_screen The screen to use + @param display:str? The display to use, `None` for the current + @return :bool Whether call was successful ''' global vidmode_gamma_size - vidmode_gamma_size = blueshift_vidmode_open(use_screen) + cdef char* display_ = NULL + if display is not None: + display_ = display + vidmode_gamma_size = blueshift_vidmode_open(use_screen, display_) return vidmode_gamma_size > 1 diff --git a/src/blueshift_vidmode_c.c b/src/blueshift_vidmode_c.c index bd5efb5..b6d30f8 100644 --- a/src/blueshift_vidmode_c.c +++ b/src/blueshift_vidmode_c.c @@ -20,7 +20,7 @@ /** * The X server display */ -static Display* display; +static Display* connection; /** * The X screen @@ -38,16 +38,17 @@ static int curve_size; * Start stage of colour curve control * * @param use_screen The screen to use + * @param display The display to use, `NULL` for the current one * @return Zero on error, otherwise the size of colours curves */ -int blueshift_vidmode_open(int use_screen) +int blueshift_vidmode_open(int use_screen, char* display) { int _major, _minor; /* Get X display */ - if ((display = XOpenDisplay(NULL)) == NULL) + if ((connection = XOpenDisplay(display)) == NULL) { fprintf(stderr, "Cannot open X display\n"); return 0; @@ -56,10 +57,10 @@ int blueshift_vidmode_open(int use_screen) /* Check for VidMode extension */ - if (XF86VidModeQueryVersion(display, &_major, &_minor) == 0) + if (XF86VidModeQueryVersion(connection, &_major, &_minor) == 0) { fprintf(stderr, "VidMode version query failed\n"); - XCloseDisplay(display); + XCloseDisplay(connection); return 0; } @@ -67,17 +68,17 @@ int blueshift_vidmode_open(int use_screen) /* Get curve's size on the encoding axis */ screen = use_screen; - if (XF86VidModeGetGammaRampSize(display, screen, &curve_size) == 0) + if (XF86VidModeGetGammaRampSize(connection, screen, &curve_size) == 0) { fprintf(stderr, "VidMode gamma size query failed\n"); - XCloseDisplay(display); + XCloseDisplay(connection); return 0; } if (curve_size <= 1) { fprintf(stderr, "VidMode gamma size query failed, impossible dimension\n"); - XCloseDisplay(display); + XCloseDisplay(connection); return 0; } @@ -100,10 +101,10 @@ int blueshift_vidmode_read(int use_crtc, uint16_t* r_gamma, uint16_t* g_gamma, u /* Read curves */ - if (XF86VidModeGetGammaRamp(display, screen, curve_size, r_gamma, g_gamma, b_gamma) == 0) + if (XF86VidModeGetGammaRamp(connection, screen, curve_size, r_gamma, g_gamma, b_gamma) == 0) { fprintf(stderr, "VidMode gamma query failed\n"); - XCloseDisplay(display); + XCloseDisplay(connection); return 1; } @@ -126,7 +127,7 @@ int blueshift_vidmode_apply(uint64_t use_crtcs, uint16_t* r_curve, uint16_t* g_c /* Apply curves */ - if (XF86VidModeSetGammaRamp(display, screen, curve_size, r_curve, g_curve, b_curve) == 0) + if (XF86VidModeSetGammaRamp(connection, screen, curve_size, r_curve, g_curve, b_curve) == 0) { fprintf(stderr, "VidMode gamma control failed\n"); return 1; @@ -143,6 +144,6 @@ void blueshift_vidmode_close(void) { /* Free remaining resources */ - XCloseDisplay(display); + XCloseDisplay(connection); } diff --git a/src/blueshift_vidmode_c.h b/src/blueshift_vidmode_c.h index c99f841..c94a297 100644 --- a/src/blueshift_vidmode_c.h +++ b/src/blueshift_vidmode_c.h @@ -31,9 +31,10 @@ * Start stage of colour curve control * * @param use_screen The screen to use + * @param display The display to use, `NULL` for the current one * @return Zero on error, otherwise the size of colours curves */ -int blueshift_vidmode_open(int use_screen); +int blueshift_vidmode_open(int use_screen, char* display); /** * Gets the current colour curves diff --git a/src/monitor.py b/src/monitor.py index 2f58999..36f9235 100644 --- a/src/monitor.py +++ b/src/monitor.py @@ -48,12 +48,12 @@ except: randr_opened = None ''' -:int? The index of the, with RandR, opened X screen, if any +:(int, str)? The index of the, with RandR, opened X screen and X display, if any ''' vidmode_opened = None ''' -:int? The index of the, with vidmode, opened X screen, if any +:(int, str)? The index of the, with vidmode, opened X screen and X display, if any ''' @@ -76,61 +76,64 @@ def close_c_bindings(): drm_manager.close() -def randr_get(crtc = 0, screen = 0): +def randr_get(crtc = 0, screen = 0, display = None): ''' Gets the current colour curves using the X11 extension RandR - @param crtc:int The CRTC of the monitor to read from - @param screen:int The screen that the monitor belong to - @return :()→void Function to invoke to apply the curves that was used when this function was invoked + @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 + @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 - if (randr_opened is None) or not (randr_opened == screen): - # Close RandR connection, if any, because its is connected to the wrong screen + # 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) == 0: - randr_opened = screen + if randr_open(screen, display) == 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))) -def vidmode_get(crtc = 0, screen = 0): +def vidmode_get(crtc = 0, screen = 0, display = None): ''' Gets the current colour curves using the X11 extension VidMode - @param crtc:int The CRTC of the monitor to read from - @param screen:int The screen that the monitor belong to - @return :()→void Function to invoke to apply the curves that was used when this function was invoked + @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 + @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 - if (vidmode_opened is None) or not (vidmode_opened == screen): - # Close vidmode connection, if any, because its is connected to the wrong screen + # 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): - vidmode_opened = screen + if vidmode_open(screen, display): + vidmode_opened = (screen, display) else: raise Exception('Cannot open vidmode connection') # Read current curves and create function return ramps_to_function(*(vidmode_read(crtc))) -def drm_get(crtc = 0, screen = 0): +def drm_get(crtc = 0, screen = 0, display = None): ''' Gets the current colour curves using DRM - @param crtc:int The CRTC of the monitor to read from - @param screen:int The graphics card that the monitor belong to, named `screen` 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 + @param crtc:int The CRTC of the monitor to read from + @param screen:int The graphics card to which the monitors belong, named `screen` for compatibility with `randr_get` and `vidmode_get` + @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) @@ -138,12 +141,13 @@ def drm_get(crtc = 0, screen = 0): return ramps_to_function(*(drm_get_gamma_ramps(connection, crtc, i_size))) -def randr(*crtcs, screen = 0): +def randr(*crtcs, screen = 0, display = None): ''' Applies colour curves using the X11 extension RandR - @param crtcs:*int The CRT controllers to use, all are used if none are specified - @param screen:int The screen that the monitors belong to + @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 ''' from blueshift_randr import randr_open, randr_apply, randr_close global randr_opened @@ -152,14 +156,14 @@ def randr(*crtcs, screen = 0): # 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 - if (randr_opened is None) or not (randr_opened == screen): - # Close RandR connection, if any, because its is connected to the wrong screen + # 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) == 0: - randr_opened = screen + if randr_open(screen, display) == 0: + randr_opened = (screen, display) else: raise Exception('Cannot open RandR connection') try: @@ -170,12 +174,13 @@ def randr(*crtcs, screen = 0): pass # Happens on exit by TERM signal -def vidmode(*crtcs, screen = 0): +def vidmode(*crtcs, screen = 0, display = None): ''' Applies colour curves using the X11 extension VidMode - @param crtcs:*int The CRT controllers to use, all are used if none are specified - @param screen:int The screen that the monitors belong to + @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 ''' from blueshift_vidmode import vidmode_open, vidmode_apply, vidmode_close global vidmode_opened @@ -184,14 +189,14 @@ def vidmode(*crtcs, screen = 0): # 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 - if (vidmode_opened is None) or not (vidmode_opened == screen): - # Close vidmode connection, if any, because its is connected to the wrong screen + # 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): - vidmode_opened = screen + if vidmode_open(screen, display): + vidmode_opened = (screen, display) else: raise Exception('Cannot open vidmode connection') try: @@ -202,12 +207,14 @@ def vidmode(*crtcs, screen = 0): pass # Happens on exit by TERM signal -def drm(*crtcs, screen = 0): +def drm(*crtcs, screen = 0, display = None): ''' Applies colour curves using DRM - @param crtcs:*int The CRT controllers to use, all are used if none are specified - @param screen:int The card that the monitors belong to, named `screen` for compatibility with randr_get and vidmode_get + @param crtcs:*int The CRT controllers to use, all are used if none are specified + @param screen:int The graphics card to which the monitors belong, + 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) -- cgit v1.2.3-70-g09d2