2021-05-11 02:08:15 -07:00
/**************************************************************
custom_video_xrandr . cpp - Linux XRANDR video management layer
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Switchres Modeline generation engine for emulation
License GPL - 2.0 +
Copyright 2010 - 2021 Chris Kennedy , Antonio Giner ,
Alexandre Wodarczyk , Gil Delescluse
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <stdio.h>
# include <exception>
# include <dlfcn.h>
# include <string.h>
# include "custom_video_xrandr.h"
# include "log.h"
//============================================================
// library functions
//============================================================
# define XRRAddOutputMode p_XRRAddOutputMode
# define XRRConfigCurrentConfiguration p_XRRConfigCurrentConfiguration
# define XRRCreateMode p_XRRCreateMode
# define XRRDeleteOutputMode p_XRRDeleteOutputMode
# define XRRDestroyMode p_XRRDestroyMode
# define XRRFreeCrtcInfo p_XRRFreeCrtcInfo
# define XRRFreeOutputInfo p_XRRFreeOutputInfo
# define XRRFreeScreenConfigInfo p_XRRFreeScreenConfigInfo
# define XRRFreeScreenResources p_XRRFreeScreenResources
# define XRRGetCrtcInfo p_XRRGetCrtcInfo
# define XRRGetOutputInfo p_XRRGetOutputInfo
# define XRRGetScreenInfo p_XRRGetScreenInfo
# define XRRGetScreenResourcesCurrent p_XRRGetScreenResourcesCurrent
# define XRRQueryVersion p_XRRQueryVersion
# define XRRSetCrtcConfig p_XRRSetCrtcConfig
# define XRRSetScreenSize p_XRRSetScreenSize
# define XRRGetScreenSizeRange p_XRRGetScreenSizeRange
# define XCloseDisplay p_XCloseDisplay
# define XGrabServer p_XGrabServer
# define XOpenDisplay p_XOpenDisplay
# define XSync p_XSync
# define XUngrabServer p_XUngrabServer
# define XSetErrorHandler p_XSetErrorHandler
# define XClearWindow p_XClearWindow
# define XFillRectangle p_XFillRectangle
# define XCreateGC p_XCreateGC
//============================================================
// error_handler
// xorg error handler (static)
//============================================================
int xrandr_timing : : ms_xerrors = 0 ;
int xrandr_timing : : ms_xerrors_flag = 0 ;
static int ( * old_error_handler ) ( Display * , XErrorEvent * ) ;
static __typeof__ ( XGetErrorText ) * p_XGetErrorText ;
# define XGetErrorText p_XGetErrorText
static int error_handler ( Display * dpy , XErrorEvent * err )
{
char buf [ 64 ] ;
XGetErrorText ( dpy , err - > error_code , buf , 64 ) ;
buf [ 0 ] = ' \0 ' ;
xrandr_timing : : ms_xerrors | = xrandr_timing : : ms_xerrors_flag ;
old_error_handler ( dpy , err ) ;
log_error ( " XRANDR: <-> (error_handler) [ERROR] %s error code %d flags %02x \n " , buf , err - > error_code , xrandr_timing : : ms_xerrors ) ;
return 0 ;
}
//============================================================
// id for class object (static)
//============================================================
static int s_id = 0 ;
//============================================================
// screen management exclusivity array (static)
//============================================================
static int s_total_managed_screen = 0 ;
static int * sp_shared_screen_manager = NULL ;
//============================================================
// desktop screen positions (static)
//============================================================
static XRRCrtcInfo * sp_desktop_crtc = NULL ;
//============================================================
// xrandr_timing::xrandr_timing
//============================================================
xrandr_timing : : xrandr_timing ( char * device_name , custom_video_settings * vs )
{
m_vs = * vs ;
// Increment id for each new screen
m_id = + + s_id ;
log_verbose ( " XRANDR: <%d> (xrandr_timing) creation (%s) \n " , m_id , device_name ) ;
// Copy screen device name and limit size
if ( ( strlen ( device_name ) + 1 ) > 32 )
{
strncpy ( m_device_name , device_name , 31 ) ;
log_error ( " XRANDR: <%d> (xrandr_timing) [ERROR] the device name is too long it has been trucated to %s \n " , m_id , m_device_name ) ;
}
else
strcpy ( m_device_name , device_name ) ;
if ( m_vs . screen_reordering )
{
if ( m_id = = 1 )
m_enable_screen_reordering = 1 ;
}
else if ( m_vs . screen_compositing )
m_enable_screen_compositing = 1 ;
log_verbose ( " XRANDR: <%d> (xrandr_timing) checking X availability (early stub) \n " , m_id ) ;
m_x11_handle = dlopen ( " libX11.so " , RTLD_NOW ) ;
if ( m_x11_handle )
{
p_XOpenDisplay = ( __typeof__ ( XOpenDisplay ) ) dlsym ( m_x11_handle , " XOpenDisplay " ) ;
if ( p_XOpenDisplay = = NULL )
{
log_error ( " XRANDR: <%d> (xrandr_timing) [ERROR] missing func %s in %s \n " , m_id , " XOpenDisplay " , " X11_LIBRARY " ) ;
2023-03-25 11:57:10 +01:00
throw std : : exception ( ) ;
2021-05-11 02:08:15 -07:00
}
else
{
if ( ! XOpenDisplay ( NULL ) )
{
log_verbose ( " XRANDR: <%d> (xrandr_timing) X server not found \n " , m_id ) ;
2023-03-25 11:57:10 +01:00
throw std : : exception ( ) ;
2021-05-11 02:08:15 -07:00
}
}
}
else
{
log_error ( " XRANDR: <%d> (xrandr_timing) [ERROR] missing %s library \n " , m_id , " X11_LIBRARY " ) ;
2023-03-25 11:57:10 +01:00
throw std : : exception ( ) ;
2021-05-11 02:08:15 -07:00
}
s_total_managed_screen + + ;
}
//============================================================
// xrandr_timing::~xrandr_timing
//============================================================
xrandr_timing : : ~ xrandr_timing ( )
{
s_total_managed_screen - - ;
if ( s_total_managed_screen = = 0 )
{
2023-03-25 11:57:10 +01:00
s_id = 0 ;
2021-05-11 02:08:15 -07:00
if ( sp_desktop_crtc )
delete [ ] sp_desktop_crtc ;
if ( sp_shared_screen_manager )
delete [ ] sp_shared_screen_manager ;
// Restore default desktop background
XClearWindow ( m_pdisplay , m_root ) ;
}
// Free the display
if ( m_pdisplay ! = NULL )
XCloseDisplay ( m_pdisplay ) ;
// close Xrandr library
if ( m_xrandr_handle )
dlclose ( m_xrandr_handle ) ;
// close X11 library
if ( m_x11_handle )
dlclose ( m_x11_handle ) ;
}
//============================================================
// xrandr_timing::init
//============================================================
bool xrandr_timing : : init ( )
{
log_verbose ( " XRANDR: <%d> (init) loading Xrandr library \n " , m_id ) ;
if ( ! m_xrandr_handle )
m_xrandr_handle = dlopen ( " libXrandr.so " , RTLD_NOW ) ;
if ( m_xrandr_handle )
{
p_XRRAddOutputMode = ( __typeof__ ( XRRAddOutputMode ) ) dlsym ( m_xrandr_handle , " XRRAddOutputMode " ) ;
if ( p_XRRAddOutputMode = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s " , m_id , " XRRAddOutputMode " , " XRANDR_LIBRARY " ) ;
return false ;
}
p_XRRConfigCurrentConfiguration = ( __typeof__ ( XRRConfigCurrentConfiguration ) ) dlsym ( m_xrandr_handle , " XRRConfigCurrentConfiguration " ) ;
if ( p_XRRConfigCurrentConfiguration = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s " , m_id , " XRRConfigCurrentConfiguration " , " XRANDR_LIBRARY " ) ;
return false ;
}
p_XRRCreateMode = ( __typeof__ ( XRRCreateMode ) ) dlsym ( m_xrandr_handle , " XRRCreateMode " ) ;
if ( p_XRRCreateMode = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s " , m_id , " XRRCreateMode " , " XRANDR_LIBRARY " ) ;
return false ;
}
p_XRRDeleteOutputMode = ( __typeof__ ( XRRDeleteOutputMode ) ) dlsym ( m_xrandr_handle , " XRRDeleteOutputMode " ) ;
if ( p_XRRDeleteOutputMode = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s " , m_id , " XRRDeleteOutputMode " , " XRANDR_LIBRARY " ) ;
return false ;
}
p_XRRDestroyMode = ( __typeof__ ( XRRDestroyMode ) ) dlsym ( m_xrandr_handle , " XRRDestroyMode " ) ;
if ( p_XRRDestroyMode = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s " , m_id , " XRRDestroyMode " , " XRANDR_LIBRARY " ) ;
return false ;
}
p_XRRFreeCrtcInfo = ( __typeof__ ( XRRFreeCrtcInfo ) ) dlsym ( m_xrandr_handle , " XRRFreeCrtcInfo " ) ;
if ( p_XRRFreeCrtcInfo = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s " , m_id , " XRRFreeCrtcInfo " , " XRANDR_LIBRARY " ) ;
return false ;
}
p_XRRFreeOutputInfo = ( __typeof__ ( XRRFreeOutputInfo ) ) dlsym ( m_xrandr_handle , " XRRFreeOutputInfo " ) ;
if ( p_XRRFreeOutputInfo = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s " , m_id , " XRRFreeOutputInfo " , " XRANDR_LIBRARY " ) ;
return false ;
}
p_XRRFreeScreenConfigInfo = ( __typeof__ ( XRRFreeScreenConfigInfo ) ) dlsym ( m_xrandr_handle , " XRRFreeScreenConfigInfo " ) ;
if ( p_XRRFreeScreenConfigInfo = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s " , m_id , " XRRFreeScreenConfigInfo " , " XRANDR_LIBRARY " ) ;
return false ;
}
p_XRRFreeScreenResources = ( __typeof__ ( XRRFreeScreenResources ) ) dlsym ( m_xrandr_handle , " XRRFreeScreenResources " ) ;
if ( p_XRRFreeScreenResources = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s " , m_id , " XRRFreeScreenResources " , " XRANDR_LIBRARY " ) ;
return false ;
}
p_XRRGetCrtcInfo = ( __typeof__ ( XRRGetCrtcInfo ) ) dlsym ( m_xrandr_handle , " XRRGetCrtcInfo " ) ;
if ( p_XRRGetCrtcInfo = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s " , m_id , " XRRGetCrtcInfo " , " XRANDR_LIBRARY " ) ;
return false ;
}
p_XRRGetOutputInfo = ( __typeof__ ( XRRGetOutputInfo ) ) dlsym ( m_xrandr_handle , " XRRGetOutputInfo " ) ;
if ( p_XRRGetOutputInfo = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s " , m_id , " XRRGetOutputInfo " , " XRANDR_LIBRARY " ) ;
return false ;
}
p_XRRGetScreenInfo = ( __typeof__ ( XRRGetScreenInfo ) ) dlsym ( m_xrandr_handle , " XRRGetScreenInfo " ) ;
if ( p_XRRGetScreenInfo = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s " , m_id , " XRRGetScreenInfo " , " XRANDR_LIBRARY " ) ;
return false ;
}
p_XRRGetScreenResourcesCurrent = ( __typeof__ ( XRRGetScreenResourcesCurrent ) ) dlsym ( m_xrandr_handle , " XRRGetScreenResourcesCurrent " ) ;
if ( p_XRRGetScreenResourcesCurrent = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s " , m_id , " XRRGetScreenResourcesCurrent " , " XRANDR_LIBRARY " ) ;
return false ;
}
p_XRRQueryVersion = ( __typeof__ ( XRRQueryVersion ) ) dlsym ( m_xrandr_handle , " XRRQueryVersion " ) ;
if ( p_XRRQueryVersion = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s " , m_id , " XRRQueryVersion " , " XRANDR_LIBRARY " ) ;
return false ;
}
p_XRRSetCrtcConfig = ( __typeof__ ( XRRSetCrtcConfig ) ) dlsym ( m_xrandr_handle , " XRRSetCrtcConfig " ) ;
if ( p_XRRSetCrtcConfig = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s " , m_id , " XRRSetCrtcConfig " , " XRANDR_LIBRARY " ) ;
return false ;
}
p_XRRSetScreenSize = ( __typeof__ ( XRRSetScreenSize ) ) dlsym ( m_xrandr_handle , " XRRSetScreenSize " ) ;
if ( p_XRRSetScreenSize = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s " , m_id , " XRRSetScreenSize " , " XRANDR_LIBRARY " ) ;
return false ;
}
p_XRRGetScreenSizeRange = ( __typeof__ ( XRRGetScreenSizeRange ) ) dlsym ( m_xrandr_handle , " XRRGetScreenSizeRange " ) ;
if ( p_XRRGetScreenSizeRange = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s " , m_id , " XRRSetScreenSize " , " XRANDR_LIBRARY " ) ;
return false ;
}
}
else
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing %s library \n " , m_id , " XRANDR_LIBRARY " ) ;
return false ;
}
log_verbose ( " XRANDR: <%d> (init) loading X11 library \n " , m_id ) ;
if ( ! m_x11_handle )
m_x11_handle = dlopen ( " libX11.so " , RTLD_NOW ) ;
if ( m_x11_handle )
{
p_XCloseDisplay = ( __typeof__ ( XCloseDisplay ) ) dlsym ( m_x11_handle , " XCloseDisplay " ) ;
if ( p_XCloseDisplay = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s \n " , m_id , " XCloseDisplay " , " X11_LIBRARY " ) ;
return false ;
}
p_XGrabServer = ( __typeof__ ( XGrabServer ) ) dlsym ( m_x11_handle , " XGrabServer " ) ;
if ( p_XGrabServer = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s \n " , m_id , " XGrabServer " , " X11_LIBRARY " ) ;
return false ;
}
p_XOpenDisplay = ( __typeof__ ( XOpenDisplay ) ) dlsym ( m_x11_handle , " XOpenDisplay " ) ;
if ( p_XOpenDisplay = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s \n " , m_id , " XOpenDisplay " , " X11_LIBRARY " ) ;
return false ;
}
p_XSync = ( __typeof__ ( XSync ) ) dlsym ( m_x11_handle , " XSync " ) ;
if ( p_XSync = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s \n " , m_id , " XSync " , " X11_LIBRARY " ) ;
return false ;
}
p_XUngrabServer = ( __typeof__ ( XUngrabServer ) ) dlsym ( m_x11_handle , " XUngrabServer " ) ;
if ( p_XUngrabServer = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s \n " , m_id , " XUngrabServer " , " X11_LIBRARY " ) ;
return false ;
}
p_XSetErrorHandler = ( __typeof__ ( XSetErrorHandler ) ) dlsym ( m_x11_handle , " XSetErrorHandler " ) ;
if ( p_XSetErrorHandler = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s \n " , m_id , " XSetErrorHandler " , " X11_LIBRARY " ) ;
return false ;
}
p_XGetErrorText = ( __typeof__ ( XGetErrorText ) ) dlsym ( m_x11_handle , " XGetErrorText " ) ;
if ( p_XGetErrorText = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s \n " , m_id , " XGetErrorText " , " X11_LIBRARY " ) ;
return false ;
}
p_XClearWindow = ( __typeof__ ( XClearWindow ) ) dlsym ( m_x11_handle , " XClearWindow " ) ;
if ( p_XClearWindow = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s " , m_id , " XClearWindow " , " X11_LIBRARY " ) ;
return false ;
}
p_XFillRectangle = ( __typeof__ ( XFillRectangle ) ) dlsym ( m_x11_handle , " XFillRectangle " ) ;
if ( p_XFillRectangle = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s " , m_id , " XFillRectangle " , " X11_LIBRARY " ) ;
return false ;
}
p_XCreateGC = ( __typeof__ ( XCreateGC ) ) dlsym ( m_x11_handle , " XCreateGC " ) ;
if ( p_XCreateGC = = NULL )
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing func %s in %s " , m_id , " XCreateGC " , " X11_LIBRARY " ) ;
return false ;
}
}
else
{
log_error ( " XRANDR: <%d> (init) [ERROR] missing %s library \n " , m_id , " X11_LIBRARY " ) ;
return false ;
}
// Select current display and root window
// m_pdisplay is global to reduce open/close calls, resource is freed when class is destroyed
if ( ! m_pdisplay )
m_pdisplay = XOpenDisplay ( NULL ) ;
if ( ! m_pdisplay )
{
log_error ( " XRANDR: <%d> (init) [ERROR] failed to connect to the X server \n " , m_id ) ;
return false ;
}
// Display XRANDR version
int major_version , minor_version ;
XRRQueryVersion ( m_pdisplay , & major_version , & minor_version ) ;
log_verbose ( " XRANDR: <%d> (init) version %d.%d \n " , m_id , major_version , minor_version ) ;
if ( major_version < 1 | | ( major_version = = 1 & & minor_version < 2 ) )
{
log_error ( " XRANDR: <%d> (init) [ERROR] Xrandr version 1.2 or above is required \n " , m_id ) ;
return false ;
}
// screen_pos defines screen position, 0 is default first screen position and equivalent to 'auto'
int screen_pos = - 1 ;
bool detected = false ;
// Handle the screen name, "auto", "screen[0-9]" and XRANDR device name
if ( strlen ( m_device_name ) = = 7 & & ! strncmp ( m_device_name , " screen " , 6 ) & & m_device_name [ 6 ] > = ' 0 ' & & m_device_name [ 6 ] < = ' 9 ' )
screen_pos = m_device_name [ 6 ] - ' 0 ' ;
else if ( strlen ( m_device_name ) = = 1 & & m_device_name [ 0 ] > = ' 0 ' & & m_device_name [ 0 ] < = ' 9 ' )
screen_pos = m_device_name [ 0 ] - ' 0 ' ;
if ( ScreenCount ( m_pdisplay ) > 1 )
log_verbose ( " XRANDR: <%d> (init) [WARNING] screen count is %d, unpredictable behavior to be expected \n " , m_id , ScreenCount ( m_pdisplay ) ) ;
for ( int screen = 0 ; ! detected & & screen < ScreenCount ( m_pdisplay ) ; screen + + )
{
log_verbose ( " XRANDR: <%d> (init) check screen number %d \n " , m_id , screen ) ;
m_screen = screen ;
m_root = RootWindow ( m_pdisplay , screen ) ;
XRRScreenResources * resources = XRRGetScreenResourcesCurrent ( m_pdisplay , m_root ) ;
if ( m_id = = 1 )
{
// Prepare the shared screen array
sp_shared_screen_manager = new int [ resources - > noutput ] ;
for ( int o = 0 ; o < resources - > noutput ; o + + )
sp_shared_screen_manager [ o ] = 0 ;
// Save all active crtc positions
sp_desktop_crtc = new XRRCrtcInfo [ resources - > ncrtc ] ;
for ( int c = 0 ; c < resources - > ncrtc ; c + + )
memcpy ( & sp_desktop_crtc [ c ] , XRRGetCrtcInfo ( m_pdisplay , resources , resources - > crtcs [ c ] ) , sizeof ( XRRCrtcInfo ) ) ;
}
// Get default screen rotation from screen configuration
XRRScreenConfiguration * sc = XRRGetScreenInfo ( m_pdisplay , m_root ) ;
XRRConfigCurrentConfiguration ( sc , & m_desktop_rotation ) ;
XRRFreeScreenConfigInfo ( sc ) ;
Rotation current_rotation = 0 ;
int output_position = 0 ;
for ( int o = 0 ; o < resources - > noutput ; o + + )
{
XRROutputInfo * output_info = XRRGetOutputInfo ( m_pdisplay , resources , resources - > outputs [ o ] ) ;
if ( ! output_info )
{
log_error ( " XRANDR: <%d> (init) [ERROR] could not get output 0x%x information \n " , m_id , ( unsigned int ) resources - > outputs [ o ] ) ;
continue ;
}
// Check all connected output
if ( m_desktop_output = = - 1 & & output_info - > connection = = RR_Connected & & output_info - > crtc )
{
if ( ! strcmp ( m_device_name , " auto " ) | | ! strcmp ( m_device_name , output_info - > name ) | | output_position = = screen_pos )
{
// store the output connector
m_desktop_output = o ;
// store screen minium and maximum resolutions
int min_width ;
int max_width ;
int min_height ;
int max_height ;
XRRGetScreenSizeRange ( m_pdisplay , m_root , & min_width , & min_height , & max_width , & max_height ) ;
m_min_width = min_width ;
m_max_width = max_width ;
m_min_height = min_height ;
m_max_height = max_height ;
if ( sp_shared_screen_manager [ m_desktop_output ] = = 0 )
{
sp_shared_screen_manager [ m_desktop_output ] = m_id ;
m_managed = 1 ;
}
// identify the current modeline and rotation
XRRCrtcInfo * crtc_info = XRRGetCrtcInfo ( m_pdisplay , resources , output_info - > crtc ) ;
current_rotation = crtc_info - > rotation ;
for ( int m = 0 ; m < resources - > nmode & & m_desktop_mode . id = = 0 ; m + + )
{
// Get screen mode
if ( crtc_info - > mode = = resources - > modes [ m ] . id )
{
m_desktop_mode = resources - > modes [ m ] ;
m_last_crtc = * crtc_info ;
}
}
XRRFreeCrtcInfo ( crtc_info ) ;
// check screen rotation (left or right)
if ( current_rotation & 0xe )
{
m_crtc_flags = MODE_ROTATED ;
log_verbose ( " XRANDR: <%d> (init) desktop rotation is %s \n " , m_id , ( current_rotation & 0x2 ) ? " left " : ( ( current_rotation & 0x8 ) ? " right " : " inverted " ) ) ;
}
}
output_position + + ;
}
log_verbose ( " XRANDR: <%d> (init) check output connector '%s' active %d crtc %d %s \n " , m_id , output_info - > name , output_info - > connection = = RR_Connected ? 1 : 0 , output_info - > crtc ? 1 : 0 , m_desktop_output = = o ? ( m_managed ? " [SELECTED] " : " [UNMANAGED] " ) : " " ) ;
XRRFreeOutputInfo ( output_info ) ;
}
XRRFreeScreenResources ( resources ) ;
// Check if screen has been detected
detected = m_desktop_output ! = - 1 ;
}
if ( ! detected )
log_error ( " XRANDR: <%d> (init) [ERROR] no screen detected \n " , m_id ) ;
else if ( m_enable_screen_reordering )
{
// Global screen placement
modeline mode = { } ;
mode . type = MODE_DESKTOP ;
set_timing ( & mode , XRANDR_ENABLE_SCREEN_REORDERING ) ;
}
return detected ;
}
//============================================================
// xrandr_timing::update_mode
//============================================================
bool xrandr_timing : : update_mode ( modeline * mode )
{
if ( ! mode )
return false ;
// Handle no screen detected case
if ( m_desktop_output = = - 1 )
{
log_error ( " XRANDR: <%d> (update_mode) [ERROR] no screen detected \n " , m_id ) ;
return false ;
}
if ( ! delete_mode ( mode ) )
{
log_error ( " XRANDR: <%d> (update_mode) [ERROR] delete operation not successful " , m_id ) ;
return false ;
}
if ( ! add_mode ( mode ) )
{
log_error ( " XRANDR: <%d> (update_mode) [ERROR] add operation not successful " , m_id ) ;
return false ;
}
return true ;
}
//============================================================
// xrandr_timing::add_mode
//============================================================
bool xrandr_timing : : add_mode ( modeline * mode )
{
if ( ! mode )
return false ;
// Handle no screen detected case
if ( m_desktop_output = = - 1 )
{
log_error ( " XRANDR: <%d> (add_mode) [ERROR] no screen detected \n " , m_id ) ;
return false ;
}
if ( ! m_managed )
{
log_error ( " XRANDR: <%d> (add_mode) [WARNING] this screen is managed by <%d> \n " , m_id , sp_shared_screen_manager [ m_desktop_output ] ) ;
return false ;
}
// Check if mode is available from the plaftform_data mode id
XRRModeInfo * pxmode = find_mode ( mode ) ;
if ( pxmode ! = NULL )
{
log_error ( " XRANDR: <%d> (add_mode) [WARNING] mode already exist \n " , m_id ) ;
return true ;
}
// Create specific mode name
char name [ 48 ] ;
sprintf ( name , " SR-%d_%dx%d@%.02f%s " , m_id , mode - > hactive , mode - > vactive , mode - > vfreq , mode - > interlace ? " i " : " " ) ;
// Check if mode is available from the SR name (should not be the case, otherwise it means that we recevied twice the same mode request)
pxmode = find_mode_by_name ( name ) ;
if ( pxmode ! = NULL )
{
log_error ( " XRANDR: <%d> (add_mode) [WARNING] mode already exist (duplicate request) \n " , m_id ) ;
mode - > platform_data = pxmode - > id ;
return true ;
}
log_verbose ( " XRANDR: <%d> (add_mode) create mode %s \n " , m_id , name ) ;
// Setup the xrandr mode structure
XRRModeInfo xmode = { } ;
xmode . name = name ;
xmode . nameLength = strlen ( name ) ;
xmode . dotClock = mode - > pclock ;
xmode . width = mode - > hactive ;
xmode . hSyncStart = mode - > hbegin ;
xmode . hSyncEnd = mode - > hend ;
xmode . hTotal = mode - > htotal ;
xmode . height = mode - > vactive ;
xmode . vSyncStart = mode - > vbegin ;
xmode . vSyncEnd = mode - > vend ;
xmode . vTotal = mode - > vtotal ;
xmode . modeFlags = ( mode - > interlace ? RR_Interlace : 0 ) | ( mode - > doublescan ? RR_DoubleScan : 0 ) | ( mode - > hsync ? RR_HSyncPositive : RR_HSyncNegative ) | ( mode - > vsync ? RR_VSyncPositive : RR_VSyncNegative ) ;
xmode . hSkew = 0 ;
mode - > type | = CUSTOM_VIDEO_TIMING_XRANDR ;
// Create the modeline
XSync ( m_pdisplay , False ) ;
ms_xerrors = 0 ;
ms_xerrors_flag = 0x01 ;
old_error_handler = XSetErrorHandler ( error_handler ) ;
RRMode gmid = XRRCreateMode ( m_pdisplay , m_root , & xmode ) ;
XSync ( m_pdisplay , False ) ;
XSetErrorHandler ( old_error_handler ) ;
if ( ms_xerrors & ms_xerrors_flag )
{
log_error ( " XRANDR: <%d> (add_mode) [ERROR] in %s \n " , m_id , " XRRCreateMode " ) ;
return false ;
}
mode - > platform_data = gmid ;
// Add new modeline to primary output
XRRScreenResources * resources = XRRGetScreenResourcesCurrent ( m_pdisplay , m_root ) ;
XSync ( m_pdisplay , False ) ;
ms_xerrors_flag = 0x02 ;
old_error_handler = XSetErrorHandler ( error_handler ) ;
XRRAddOutputMode ( m_pdisplay , resources - > outputs [ m_desktop_output ] , mode - > platform_data ) ;
XSync ( m_pdisplay , False ) ;
XSetErrorHandler ( old_error_handler ) ;
XRRFreeScreenResources ( resources ) ;
if ( ms_xerrors & ms_xerrors_flag )
{
log_error ( " XRANDR: <%d> (add_mode) [ERROR] in %s \n " , m_id , " XRRAddOutputMode " ) ;
// remove unlinked modeline
if ( mode - > platform_data )
{
log_error ( " XRANDR: <%d> (add_mode) [ERROR] remove mode [%04lx] \n " , m_id , mode - > platform_data ) ;
XRRDestroyMode ( m_pdisplay , mode - > platform_data ) ;
mode - > platform_data = 0 ;
}
}
else
log_verbose ( " XRANDR: <%d> (add_mode) mode %04lx %dx%d refresh %.6f added \n " , m_id , mode - > platform_data , mode - > hactive , mode - > vactive , mode - > vfreq ) ;
return ms_xerrors = = 0 ;
}
//============================================================
// xrandr_timing::find_mode_by_name
//============================================================
XRRModeInfo * xrandr_timing : : find_mode_by_name ( char * name )
{
XRRModeInfo * pxmode = NULL ;
XRRScreenResources * resources = XRRGetScreenResourcesCurrent ( m_pdisplay , m_root ) ;
// use SR name to return the mode
for ( int m = 0 ; m < resources - > nmode ; m + + )
{
if ( strcmp ( resources - > modes [ m ] . name , name ) = = 0 )
{
pxmode = & resources - > modes [ m ] ;
break ;
}
}
XRRFreeScreenResources ( resources ) ;
return pxmode ;
}
//============================================================
// xrandr_timing::find_mode
//============================================================
XRRModeInfo * xrandr_timing : : find_mode ( modeline * mode )
{
XRRModeInfo * pxmode = NULL ;
XRRScreenResources * resources = XRRGetScreenResourcesCurrent ( m_pdisplay , m_root ) ;
// use platform_data (mode id) to return the mode
for ( int m = 0 ; m < resources - > nmode ; m + + )
{
if ( mode - > platform_data = = resources - > modes [ m ] . id )
{
pxmode = & resources - > modes [ m ] ;
break ;
}
}
XRRFreeScreenResources ( resources ) ;
return pxmode ;
}
//============================================================
// xrandr_timing::set_timing
//============================================================
bool xrandr_timing : : set_timing ( modeline * mode )
{
if ( m_enable_screen_compositing )
return set_timing ( mode , 0 ) ;
return set_timing ( mode , XRANDR_DISABLE_CRTC_RELOCATION ) ;
}
//============================================================
// xrandr_timing::set_timing
//============================================================
bool xrandr_timing : : set_timing ( modeline * mode , int flags )
{
// Handle no screen detected case
if ( m_desktop_output = = - 1 )
{
log_error ( " XRANDR: <%d> (set_timing) [ERROR] no screen detected \n " , m_id ) ;
return false ;
}
if ( ! m_managed )
{
log_error ( " XRANDR: <%d> (set_timing) [WARNING] this screen is managed by <%d> \n " , m_id , sp_shared_screen_manager [ m_desktop_output ] ) ;
return false ;
}
if ( m_id ! = 1 & & ( flags & XRANDR_ENABLE_SCREEN_REORDERING ) )
flags = XRANDR_DISABLE_CRTC_RELOCATION ; // only master can do global screen preparation
XRRModeInfo * pxmode = NULL ;
if ( mode - > type & MODE_DESKTOP )
pxmode = & m_desktop_mode ;
else
pxmode = find_mode ( mode ) ;
if ( pxmode = = NULL )
{
log_error ( " XRANDR: <%d> (set_timing) [ERROR] mode not found \n " , m_id ) ;
return false ;
}
// Use xrandr to switch to new mode.
XRRScreenResources * resources = XRRGetScreenResourcesCurrent ( m_pdisplay , m_root ) ;
XRROutputInfo * output_info = XRRGetOutputInfo ( m_pdisplay , resources , resources - > outputs [ m_desktop_output ] ) ;
XRRCrtcInfo * crtc_info = XRRGetCrtcInfo ( m_pdisplay , resources , output_info - > crtc ) ;
if ( flags & XRANDR_DISABLE_CRTC_RELOCATION )
log_verbose ( " XRANDR: <%d> (set_timing) DISABLE crtc relocation \n " , m_id ) ;
if ( flags & XRANDR_ENABLE_SCREEN_REORDERING )
log_verbose ( " XRANDR: <%d> (set_timing) GLOBAL desktop screen preparation \n " , m_id ) ;
else if ( m_last_crtc . mode = = crtc_info - > mode & & m_last_crtc . x = = crtc_info - > x & & m_last_crtc . y = = crtc_info - > y & & pxmode - > id = = crtc_info - > mode )
log_verbose ( " XRANDR: <%d> (set_timing) requested mode is already active [%04lx] %ux%u+%d+%d \n " , m_id , crtc_info - > mode , crtc_info - > width , crtc_info - > height , crtc_info - > x , crtc_info - > y ) ;
else if ( m_last_crtc . mode ! = crtc_info - > mode )
{
log_verbose ( " XRANDR: <%d> (set_timing) [WARNING] unexpected active modeline detected (last:[%04lx] now:[%04lx] %ux%u+%d+%d want:[%04lx]) \n " , m_id , m_last_crtc . mode , crtc_info - > mode , crtc_info - > width , crtc_info - > height , crtc_info - > x , crtc_info - > y , pxmode - > id ) ;
* crtc_info = m_last_crtc ;
}
// Grab X server to prevent unwanted interaction from the window manager
XGrabServer ( m_pdisplay ) ;
unsigned int width = m_min_width ;
unsigned int height = m_min_height ;
unsigned int active_crtc = 0 ;
unsigned int reordering_last_y = 0 ;
ms_xerrors = 0 ;
XRRCrtcInfo * global_crtc = new XRRCrtcInfo [ resources - > ncrtc ] ;
XRRCrtcInfo * original_crtc = new XRRCrtcInfo [ resources - > ncrtc ] ;
// caculate necessary screen size and of crtc neighborhood if they have at least one side aligned with the mode changed crtc
for ( int c = 0 ; c < resources - > ncrtc ; c + + )
{
// Prepare crtc references
memcpy ( & original_crtc [ c ] , XRRGetCrtcInfo ( m_pdisplay , resources , resources - > crtcs [ c ] ) , sizeof ( XRRCrtcInfo ) ) ;
memcpy ( & global_crtc [ c ] , XRRGetCrtcInfo ( m_pdisplay , resources , resources - > crtcs [ c ] ) , sizeof ( XRRCrtcInfo ) ) ;
// Original state
XRRCrtcInfo * crtc_info0 = & original_crtc [ c ] ;
// Modified state
XRRCrtcInfo * crtc_info1 = & global_crtc [ c ] ;
// clear timestamp
crtc_info1 - > timestamp = 0 ;
// Skip unused crtc
if ( output_info - > crtc ! = 0 & & crtc_info0 - > mode ! = 0 )
{
if ( flags & XRANDR_ENABLE_SCREEN_REORDERING )
{
// Relocate all crtcs
// Super resolution placement, vertical stacking, reserved XRANDR_REORDERING_MAXIMUM_HEIGHT pixels
crtc_info1 - > x = 0 ;
crtc_info1 - > y = reordering_last_y ;
if ( crtc_info1 - > height > XRANDR_REORDERING_MAXIMUM_HEIGHT )
reordering_last_y + = crtc_info1 - > height ;
else
reordering_last_y + = XRANDR_REORDERING_MAXIMUM_HEIGHT ;
crtc_info1 - > timestamp | = XRANDR_SETMODE_UPDATE_REORDERING ;
active_crtc + + ;
}
// Switchres selected desktop output
else if ( resources - > crtcs [ c ] = = output_info - > crtc )
{
crtc_info1 - > timestamp | = XRANDR_SETMODE_IS_DESKTOP ;
crtc_info1 - > mode = pxmode - > id ;
crtc_info1 - > width = pxmode - > width ;
crtc_info1 - > height = pxmode - > height ;
if ( mode - > type & MODE_DESKTOP )
{
if ( ! m_enable_screen_compositing & & ( crtc_info1 - > x ! = sp_desktop_crtc [ c ] . x | | crtc_info1 - > y ! = sp_desktop_crtc [ c ] . y ) )
{
// Restore original desktop position
crtc_info1 - > x = sp_desktop_crtc [ c ] . x ;
crtc_info1 - > y = sp_desktop_crtc [ c ] . y ;
crtc_info1 - > timestamp | = XRANDR_SETMODE_RESTORE_DESKTOP ;
}
}
else
{
// Use curent position
crtc_info1 - > x = crtc_info - > x ;
crtc_info1 - > y = crtc_info - > y ;
}
if ( crtc_info0 - > mode ! = crtc_info1 - > mode | | crtc_info0 - > width ! = crtc_info1 - > width | | crtc_info0 - > height ! = crtc_info1 - > height | | crtc_info0 - > x ! = crtc_info1 - > x | | crtc_info0 - > y ! = crtc_info1 - > y )
crtc_info1 - > timestamp | = XRANDR_SETMODE_UPDATE_DESKTOP_CRTC ;
}
else if ( mode - > type & MODE_DESKTOP & & m_enable_screen_reordering & & ( crtc_info1 - > x ! = sp_desktop_crtc [ c ] . x | | crtc_info1 - > y ! = sp_desktop_crtc [ c ] . y ) )
{
crtc_info1 - > x = sp_desktop_crtc [ c ] . x ;
crtc_info1 - > y = sp_desktop_crtc [ c ] . y ;
crtc_info1 - > timestamp | = ( XRANDR_SETMODE_RESTORE_DESKTOP | XRANDR_SETMODE_UPDATE_REORDERING ) ;
}
}
}
for ( int c = 0 ; c < resources - > ncrtc ; c + + )
{
// Original state
XRRCrtcInfo * crtc_info0 = & original_crtc [ c ] ;
// Modified state
XRRCrtcInfo * crtc_info1 = & global_crtc [ c ] ;
// Skip unused crtc
if ( output_info - > crtc ! = 0 & & crtc_info0 - > mode ! = 0 )
{
if ( ( flags & XRANDR_DISABLE_CRTC_RELOCATION ) = = 0 & & ( crtc_info1 - > timestamp & XRANDR_SETMODE_IS_DESKTOP ) = = 0 )
{
// relocate crtc impacted by new width
if ( crtc_info1 - > x > = crtc_info - > x + ( int ) crtc_info - > width )
{
crtc_info1 - > x + = pxmode - > width - crtc_info - > width ;
crtc_info1 - > timestamp | = XRANDR_SETMODE_UPDATE_OTHER_CRTC ;
}
// relocate crtc impacted by new height
if ( crtc_info1 - > y > = crtc_info - > y + ( int ) crtc_info - > height )
{
crtc_info1 - > y + = pxmode - > height - crtc_info - > height ;
crtc_info1 - > timestamp | = XRANDR_SETMODE_UPDATE_OTHER_CRTC ;
}
}
// Calculate overall screen size based on crtcs placement
if ( crtc_info1 - > x + crtc_info1 - > width > width )
width = crtc_info1 - > x + crtc_info1 - > width ;
if ( crtc_info1 - > y + crtc_info1 - > height > height )
height = crtc_info1 - > y + crtc_info1 - > height ;
if ( width > m_max_width )
{
log_error ( " XRANDR: <%d> (set_timing) [ERROR] width is above allowed maximum (%d > %d) \n " , m_id , width , m_max_width ) ;
width = m_max_width ;
}
if ( height > m_max_height )
{
log_error ( " XRANDR: <%d> (set_timing) [ERROR] height is above allowed maximum (%d > %d) \n " , m_id , height , m_max_height ) ;
height = m_max_height ;
}
if ( crtc_info1 - > timestamp & XRANDR_SETMODE_UPDATE_MASK )
log_verbose ( " XRANDR: <%d> (set_timing) crtc %d%s [%04lx] %ux%u+%d+%d --> [%04lx] %ux%u+%d+%d flags [%02lx] \n " , m_id , c , crtc_info1 - > timestamp & 1 ? " * " : " " , crtc_info0 - > mode , crtc_info0 - > width , crtc_info0 - > height , crtc_info0 - > x , crtc_info0 - > y , crtc_info1 - > mode , crtc_info1 - > width , crtc_info1 - > height , crtc_info1 - > x , crtc_info1 - > y , crtc_info1 - > timestamp ) ;
else if ( crtc_info1 - > timestamp & XRANDR_SETMODE_INFO_MASK )
log_verbose ( " XRANDR: <%d> (set_timing) crtc %d%s [%04lx] %ux%u+%d+%d flags [%02lx] \n " , m_id , c , crtc_info1 - > timestamp & 1 ? " * " : " " , crtc_info1 - > mode , crtc_info1 - > width , crtc_info1 - > height , crtc_info1 - > x , crtc_info1 - > y , crtc_info1 - > timestamp ) ;
else
log_verbose ( " XRANDR: <%d> (set_timing) crtc %d [%04lx] %ux%u+%d+%d \n " , m_id , c , crtc_info1 - > mode , crtc_info1 - > width , crtc_info1 - > height , crtc_info1 - > x , crtc_info1 - > y ) ;
}
}
// Disable crtc with pending modification
for ( int c = 0 ; c < resources - > ncrtc ; c + + )
{
// Modified state
if ( global_crtc [ c ] . timestamp & XRANDR_SETMODE_UPDATE_MASK )
{
if ( XRRSetCrtcConfig ( m_pdisplay , resources , resources - > crtcs [ c ] , CurrentTime , 0 , 0 , None , RR_Rotate_0 , NULL , 0 ) ! = RRSetConfigSuccess )
{
log_error ( " XRANDR: <%d> (set_timing) [ERROR] when disabling crtc %d \n " , m_id , c ) ;
ms_xerrors_flag = 0x01 ;
ms_xerrors | = ms_xerrors_flag ;
}
}
}
// Set the framebuffer screen size to enable all crtc
if ( ms_xerrors = = 0 )
{
log_verbose ( " XRANDR: <%d> (set_timing) setting screen size to %d x %d \n " , m_id , width , height ) ;
XSync ( m_pdisplay , False ) ;
ms_xerrors_flag = 0x02 ;
old_error_handler = XSetErrorHandler ( error_handler ) ;
XRRSetScreenSize ( m_pdisplay , m_root , width , height , ( int ) ( ( 25.4 * width ) / 96.0 ) , ( int ) ( ( 25.4 * height ) / 96.0 ) ) ;
XSync ( m_pdisplay , False ) ;
XSetErrorHandler ( old_error_handler ) ;
if ( ms_xerrors & ms_xerrors_flag )
log_error ( " XRANDR: <%d> (set_timing) [ERROR] in %s \n " , m_id , " XRRSetScreenSize " ) ;
}
// Refresh all crtc, switch modeline and set new placement
for ( int c = 0 ; c < resources - > ncrtc ; c + + )
{
// Modified state
XRRCrtcInfo * crtc_info1 = & global_crtc [ c ] ;
if ( crtc_info1 - > timestamp & XRANDR_SETMODE_UPDATE_MASK )
{
if ( crtc_info1 - > timestamp & XRANDR_SETMODE_IS_DESKTOP )
XFillRectangle ( m_pdisplay , m_root , XCreateGC ( m_pdisplay , m_root , 0 , 0 ) , crtc_info1 - > x , crtc_info1 - > y , crtc_info1 - > width , crtc_info1 - > height ) ;
// enable crtc with updated parameters
XSync ( m_pdisplay , False ) ;
ms_xerrors_flag = 0x14 ;
old_error_handler = XSetErrorHandler ( error_handler ) ;
XRRSetCrtcConfig ( m_pdisplay , resources , resources - > crtcs [ c ] , CurrentTime , crtc_info1 - > x , crtc_info1 - > y , crtc_info1 - > mode , crtc_info1 - > rotation , crtc_info1 - > outputs , crtc_info1 - > noutput ) ;
XSync ( m_pdisplay , False ) ;
XSetErrorHandler ( old_error_handler ) ;
if ( ms_xerrors & 0x10 )
{
log_error ( " XRANDR: <%d> (set_timing) [ERROR] in %s crtc %d set modeline %04lx \n " , m_id , " XRRSetCrtcConfig " , c , crtc_info1 - > mode ) ;
ms_xerrors & = 0xEF ;
}
}
}
delete [ ] original_crtc ;
delete [ ] global_crtc ;
// Release X server, events can be processed now
XUngrabServer ( m_pdisplay ) ;
if ( ms_xerrors & ms_xerrors_flag )
log_error ( " XRANDR: <%d> (set_timing) [ERROR] in %s \n " , m_id , " XRRSetCrtcConfig " ) ;
// Recall the impacted crtc to settle parameters
XRRFreeCrtcInfo ( crtc_info ) ;
crtc_info = XRRGetCrtcInfo ( m_pdisplay , resources , output_info - > crtc ) ;
// crtc config modeline change fail
if ( crtc_info - > mode = = 0 )
log_error ( " XRANDR: <%d> (set_timing) [ERROR] switching resolution failed, no modeline is set \n " , m_id ) ;
else
// save last crtc
m_last_crtc = * crtc_info ;
XRRFreeCrtcInfo ( crtc_info ) ;
XRRFreeOutputInfo ( output_info ) ;
XRRFreeScreenResources ( resources ) ;
return ( ms_xerrors = = 0 & & crtc_info - > mode ! = 0 ) ;
}
//============================================================
// xrandr_timing::delete_mode
//============================================================
bool xrandr_timing : : delete_mode ( modeline * mode )
{
// Handle no screen detected case
if ( m_desktop_output = = - 1 )
{
log_error ( " XRANDR: <%d> (delete_mode) [ERROR] no screen detected \n " , m_id ) ;
return false ;
}
if ( ! m_managed )
{
log_error ( " XRANDR: <%d> (delete_mode) [WARNING] this screen is managed by <%d> \n " , m_id , sp_shared_screen_manager [ m_desktop_output ] ) ;
return false ;
}
if ( ! mode )
return false ;
XRRScreenResources * resources = XRRGetScreenResourcesCurrent ( m_pdisplay , m_root ) ;
int total_xerrors = 0 ;
// Delete modeline
for ( int m = 0 ; m < resources - > nmode & & mode - > platform_data ! = 0 ; m + + )
{
if ( mode - > platform_data = = resources - > modes [ m ] . id )
{
XRROutputInfo * output_info = XRRGetOutputInfo ( m_pdisplay , resources , resources - > outputs [ m_desktop_output ] ) ;
XRRCrtcInfo * crtc_info = XRRGetCrtcInfo ( m_pdisplay , resources , output_info - > crtc ) ;
if ( resources - > modes [ m ] . id = = crtc_info - > mode )
2023-07-28 01:39:39 +02:00
{
log_verbose ( " XRANDR: <%d> (delete_mode) [WARNING] modeline [%04lx] is currently active, restoring desktop mode first \n " , m_id , resources - > modes [ m ] . id ) ;
modeline desktop_mode = { } ;
desktop_mode . type | = MODE_DESKTOP ;
if ( ! set_timing ( & desktop_mode , 0 ) )
{
log_error ( " XRANDR: <%d> (delete_mode) [ERROR] Could not restore desktop mode \n " , m_id ) ;
return false ;
}
}
2021-05-11 02:08:15 -07:00
XRRFreeCrtcInfo ( crtc_info ) ;
XRRFreeOutputInfo ( output_info ) ;
log_verbose ( " XRANDR: <%d> (delete_mode) remove mode %s \n " , m_id , resources - > modes [ m ] . name ) ;
XSync ( m_pdisplay , False ) ;
ms_xerrors = 0 ;
ms_xerrors_flag = 0x01 ;
old_error_handler = XSetErrorHandler ( error_handler ) ;
XRRDeleteOutputMode ( m_pdisplay , resources - > outputs [ m_desktop_output ] , resources - > modes [ m ] . id ) ;
if ( ms_xerrors & ms_xerrors_flag )
{
log_error ( " XRANDR: <%d> (delete_mode) [ERROR] in %s \n " , m_id , " XRRDeleteOutputMode " ) ;
total_xerrors + + ;
}
ms_xerrors_flag = 0x02 ;
XRRDestroyMode ( m_pdisplay , resources - > modes [ m ] . id ) ;
XSync ( m_pdisplay , False ) ;
XSetErrorHandler ( old_error_handler ) ;
if ( ms_xerrors & ms_xerrors_flag )
{
log_error ( " XRANDR: <%d> (delete_mode) [ERROR] in %s \n " , m_id , " XRRDestroyMode " ) ;
total_xerrors + + ;
}
mode - > platform_data = 0 ;
}
}
XRRFreeScreenResources ( resources ) ;
return total_xerrors = = 0 ;
}
//============================================================
// xrandr_timing::get_timing
//============================================================
bool xrandr_timing : : get_timing ( modeline * mode )
{
// Handle no screen detected case
if ( m_desktop_output = = - 1 )
{
log_error ( " XRANDR: <%d> (get_timing) [ERROR] no screen detected \n " , m_id ) ;
return false ;
}
XRRScreenResources * resources = XRRGetScreenResourcesCurrent ( m_pdisplay , m_root ) ;
XRROutputInfo * output_info = XRRGetOutputInfo ( m_pdisplay , resources , resources - > outputs [ m_desktop_output ] ) ;
// Cycle through the modelines and report them back to the display manager
if ( m_video_modes_position < output_info - > nmode )
{
for ( int m = 0 ; m < resources - > nmode ; m + + )
{
XRRModeInfo * pxmode = & resources - > modes [ m ] ;
if ( pxmode - > id = = output_info - > modes [ m_video_modes_position ] )
{
mode - > platform_data = pxmode - > id ;
mode - > pclock = pxmode - > dotClock ;
mode - > hactive = pxmode - > width ;
mode - > hbegin = pxmode - > hSyncStart ;
mode - > hend = pxmode - > hSyncEnd ;
mode - > htotal = pxmode - > hTotal ;
mode - > vactive = pxmode - > height ;
mode - > vbegin = pxmode - > vSyncStart ;
mode - > vend = pxmode - > vSyncEnd ;
mode - > vtotal = pxmode - > vTotal ;
mode - > interlace = ( pxmode - > modeFlags & RR_Interlace ) ? 1 : 0 ;
mode - > doublescan = ( pxmode - > modeFlags & RR_DoubleScan ) ? 1 : 0 ;
mode - > hsync = ( pxmode - > modeFlags & RR_HSyncPositive ) ? 1 : 0 ;
mode - > vsync = ( pxmode - > modeFlags & RR_VSyncPositive ) ? 1 : 0 ;
mode - > hfreq = mode - > pclock / mode - > htotal ;
mode - > vfreq = mode - > hfreq / mode - > vtotal * ( mode - > interlace ? 2 : 1 ) ;
mode - > refresh = mode - > vfreq ;
mode - > width = pxmode - > width ;
mode - > height = pxmode - > height ;
// Add the rotation flag from the crtc
mode - > type | = m_crtc_flags ;
mode - > type | = CUSTOM_VIDEO_TIMING_XRANDR ;
if ( strncmp ( pxmode - > name , " SR- " , 3 ) = = 0 )
log_verbose ( " XRANDR: <%d> (get_timing) [WARNING] modeline %s detected \n " , m_id , pxmode - > name ) ;
// Add the desktop flag to desktop modeline
if ( m_desktop_mode . id = = pxmode - > id )
mode - > type | = MODE_DESKTOP ;
log_verbose ( " XRANDR: <%d> (get_timing) mode %04lx %dx%d refresh %.6f added \n " , m_id , pxmode - > id , pxmode - > width , pxmode - > height , mode - > vfreq ) ;
}
}
m_video_modes_position + + ;
}
else
{
// Inititalise the position for the modeline list
m_video_modes_position = 0 ;
}
XRRFreeOutputInfo ( output_info ) ;
XRRFreeScreenResources ( resources ) ;
return true ;
}
//============================================================
// xrandr_timing::process_modelist
//============================================================
bool xrandr_timing : : process_modelist ( std : : vector < modeline * > modelist )
{
bool error = false ;
bool result = false ;
for ( auto & mode : modelist )
{
if ( mode - > type & MODE_DELETE )
result = delete_mode ( mode ) ;
else if ( mode - > type & MODE_ADD )
result = add_mode ( mode ) ;
2023-07-28 01:39:39 +02:00
else if ( mode - > type & MODE_UPDATE )
result = update_mode ( mode ) ;
2021-05-11 02:08:15 -07:00
if ( ! result )
{
mode - > type | = MODE_ERROR ;
error = true ;
}
else
// succeed
mode - > type & = ~ MODE_ERROR ;
}
return ! error ;
}