2012-02-18 08:49:07 -08:00
# include "e.h"
# include "e_randr_private.h"
# define POLLINTERVAL 128
// Set functions for the global e_randr_screen_info struct
2012-08-28 05:41:17 -07:00
static void _screen_primary_output_assign ( E_Randr_Output_Info * removed ) ;
2012-02-18 08:49:07 -08:00
// Init helper functions
2012-08-28 05:41:17 -07:00
static void _outputs_init ( void ) ;
static void _crtcs_init ( void ) ;
static Eina_Bool _structs_init ( void ) ;
2012-02-18 08:49:07 -08:00
// Retrieval helper functions
static Ecore_X_Randr_Mode_Info * _mode_geo_identical_find ( Eina_List * modes , Ecore_X_Randr_Mode_Info * mode ) ;
// Event helper functions
2012-08-28 05:41:17 -07:00
static Eina_Bool _x_poll_cb ( void * data __UNUSED__ ) ;
static Eina_Bool _crtc_change_event_cb ( void * data , int type , void * e ) ;
static Eina_Bool _output_change_event_cb ( void * data , int type , void * e ) ;
static Eina_Bool _output_property_change_event_cb ( void * data , int type , void * e ) ;
2012-02-18 08:49:07 -08:00
static Ecore_Poller * poller = NULL ;
static Eina_List * _event_handlers = NULL ;
2012-02-18 23:36:01 -08:00
static const char * _CONNECTION_STATES_STRINGS [ ] = { " CONNECTED " , " DISCONNECTED " , " UNKNOWN " } ;
static const char * _POLICIES_STRINGS [ ] = { " ABOVE " , " RIGHT " , " BELOW " , " LEFT " , " CLONE " , " NONE " } ;
2012-02-18 08:49:07 -08:00
//"New" helper functions
/**
* @ return array of E_Randr_Screen_Info_12 elements , or in case not all could
* be created or parameter ' nrequested ' = = 0 , NULL
*/
2012-03-08 03:37:54 -08:00
static E_Randr_Screen_Info_12 *
2012-02-18 08:49:07 -08:00
_screen_info_12_new ( void )
{
E_Randr_Screen_Info_12 * randr_info_12 = NULL ;
EINA_SAFETY_ON_TRUE_RETURN_VAL ( ( e_randr_screen_info . randr_version < ECORE_X_RANDR_1_2 ) , NULL ) ;
randr_info_12 = E_NEW ( E_Randr_Screen_Info_12 , 1 ) ;
randr_info_12 - > min_size . width = Ecore_X_Randr_Unset ;
randr_info_12 - > min_size . height = Ecore_X_Randr_Unset ;
randr_info_12 - > max_size . width = Ecore_X_Randr_Unset ;
randr_info_12 - > max_size . height = Ecore_X_Randr_Unset ;
randr_info_12 - > current_size . width = Ecore_X_Randr_Unset ;
randr_info_12 - > current_size . height = Ecore_X_Randr_Unset ;
randr_info_12 - > crtcs = NULL ;
randr_info_12 - > outputs = NULL ;
randr_info_12 - > modes = NULL ;
randr_info_12 - > primary_output = NULL ;
randr_info_12 - > alignment = ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE ;
ecore_x_randr_screen_size_range_get ( e_randr_screen_info . root ,
2012-08-28 05:41:17 -07:00
& randr_info_12 - > min_size . width ,
& randr_info_12 - > min_size . height ,
& randr_info_12 - > max_size . width ,
& randr_info_12 - > max_size . height ) ;
2012-02-18 08:49:07 -08:00
ecore_x_randr_screen_current_size_get ( e_randr_screen_info . root ,
2012-08-28 05:41:17 -07:00
& randr_info_12 - > current_size . width ,
& randr_info_12 - > current_size . height ,
NULL , NULL ) ;
2012-02-18 08:49:07 -08:00
return randr_info_12 ;
}
2012-03-08 03:37:54 -08:00
static Eina_Bool
2012-02-18 08:49:07 -08:00
_structs_init ( void )
{
//Output stuff
Ecore_X_Randr_Output * outputs ;
E_Randr_Output_Info * output_info = NULL ;
int noutputs = 0 ;
//CRTC stuff
Ecore_X_Randr_Crtc * crtcs = NULL ;
E_Randr_Crtc_Info * crtc_info = NULL ;
int ncrtcs = 0 ;
//Modes stuff
Ecore_X_Randr_Mode_Info * * modes = NULL ;
int nmodes = 0 ;
EINA_SAFETY_ON_TRUE_RETURN_VAL ( E_RANDR_12_NO , EINA_FALSE ) ;
outputs = ecore_x_randr_outputs_get ( e_randr_screen_info . root , & noutputs ) ;
if ( noutputs = = 0 ) return EINA_FALSE ;
while ( - - noutputs > = 0 )
{
output_info = _output_info_new ( outputs [ noutputs ] ) ;
2012-02-18 23:36:01 -08:00
if ( output_info )
e_randr_screen_info . rrvd_info . randr_info_12 - > outputs = eina_list_append ( e_randr_screen_info . rrvd_info . randr_info_12 - > outputs , output_info ) ;
2012-02-18 08:49:07 -08:00
}
free ( outputs ) ;
crtcs = ecore_x_randr_crtcs_get ( e_randr_screen_info . root , & ncrtcs ) ;
if ( ncrtcs = = 0 ) return EINA_FALSE ;
while ( - - ncrtcs > = 0 )
{
crtc_info = _crtc_info_new ( crtcs [ ncrtcs ] ) ;
e_randr_screen_info . rrvd_info . randr_info_12 - > crtcs = eina_list_append ( e_randr_screen_info . rrvd_info . randr_info_12 - > crtcs , crtc_info ) ;
}
free ( crtcs ) ;
modes = ecore_x_randr_modes_info_get ( e_randr_screen_info . root , & nmodes ) ;
if ( nmodes = = 0 ) return EINA_FALSE ;
while ( - - nmodes > = 0 )
{
e_randr_screen_info . rrvd_info . randr_info_12 - > modes = eina_list_append ( e_randr_screen_info . rrvd_info . randr_info_12 - > modes , modes [ nmodes ] ) ;
}
2012-06-13 00:15:27 -07:00
free ( modes ) ;
2012-02-18 08:49:07 -08:00
_outputs_init ( ) ;
_crtcs_init ( ) ;
return EINA_TRUE ;
}
//Set value / retrieval helper functions
2012-03-08 03:37:54 -08:00
static void
2012-02-18 08:49:07 -08:00
_crtcs_init ( void )
{
E_Randr_Crtc_Info * crtc = NULL ;
Eina_List * iter ;
EINA_SAFETY_ON_TRUE_RETURN ( E_RANDR_12_NO ) ;
EINA_LIST_FOREACH ( e_randr_screen_info . rrvd_info . randr_info_12 - > crtcs , iter , crtc )
2012-08-28 05:41:17 -07:00
_crtc_refs_set ( crtc ) ;
2012-02-18 08:49:07 -08:00
}
2012-03-08 03:37:54 -08:00
static void
2012-02-18 08:49:07 -08:00
_outputs_init ( void )
{
E_Randr_Output_Info * output = NULL ;
Eina_List * iter ;
EINA_SAFETY_ON_TRUE_RETURN ( E_RANDR_12_NO ) ;
EINA_LIST_FOREACH ( e_randr_screen_info . rrvd_info . randr_info_12 - > outputs , iter , output )
{
_output_refs_set ( output ) ;
if ( output - > connection_status = = ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED )
2012-06-13 00:40:43 -07:00
{
_monitor_info_free ( output - > monitor ) ;
output - > monitor = _monitor_info_new ( output ) ;
}
2012-02-18 08:49:07 -08:00
}
}
2012-03-08 03:37:54 -08:00
static void
2012-02-18 08:49:07 -08:00
_screen_primary_output_assign ( E_Randr_Output_Info * removed )
{
Eina_List * iter ;
E_Randr_Output_Info * primary_output = NULL , * output_info ;
EINA_SAFETY_ON_TRUE_RETURN ( E_RANDR_12_NO_OUTPUTS ) ;
if ( e_randr_screen_info . rrvd_info . randr_info_12 - > primary_output & & ( removed ! = e_randr_screen_info . rrvd_info . randr_info_12 - > primary_output ) ) return ;
if ( ! ( primary_output = _12_screen_info_output_info_get ( ecore_x_randr_primary_output_get ( e_randr_screen_info . root ) ) ) )
{
EINA_LIST_FOREACH ( e_randr_screen_info . rrvd_info . randr_info_12 - > outputs , iter , output_info )
{
if ( ! output_info | | ( output_info - > connection_status ! = ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED ) | | ! output_info - > crtc | | ! output_info - > crtc - > current_mode ) continue ;
primary_output = output_info ;
break ;
}
}
e_randr_screen_info . rrvd_info . randr_info_12 - > primary_output = primary_output ;
}
//"Free" helper functions
/**
* @ param screen_info the screen info to be freed .
*/
2012-03-08 03:37:54 -08:00
void
2012-02-18 08:49:07 -08:00
_12_screen_info_free ( E_Randr_Screen_Info_12 * screen_info )
{
Ecore_X_Randr_Mode_Info * mode_info ;
E_Randr_Crtc_Info * crtc_info ;
E_Randr_Output_Info * output_info ;
EINA_SAFETY_ON_NULL_RETURN ( screen_info ) ;
EINA_SAFETY_ON_TRUE_RETURN ( E_RANDR_12_NO ) ;
2012-08-28 06:26:51 -07:00
EINA_LIST_FREE ( screen_info - > crtcs , crtc_info )
_crtc_info_free ( crtc_info ) ;
2012-02-18 08:49:07 -08:00
2012-08-28 06:26:51 -07:00
EINA_LIST_FREE ( screen_info - > outputs , output_info )
_output_info_free ( output_info ) ;
2012-02-18 08:49:07 -08:00
2012-08-28 06:26:51 -07:00
EINA_LIST_FREE ( screen_info - > modes , mode_info )
ecore_x_randr_mode_info_free ( mode_info ) ;
2012-02-18 08:49:07 -08:00
2012-08-28 05:41:17 -07:00
free ( screen_info ) ;
2012-02-18 08:49:07 -08:00
}
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Getter functions for e_randr_screen_info struct
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
2012-03-08 03:37:54 -08:00
Ecore_X_Randr_Mode_Info *
2012-02-18 08:49:07 -08:00
_12_screen_info_mode_info_get ( const Ecore_X_Randr_Mode mode )
{
Eina_List * iter ;
Ecore_X_Randr_Mode_Info * mode_info ;
EINA_SAFETY_ON_TRUE_RETURN_VAL ( E_RANDR_12_NO_MODE ( mode ) , NULL ) ;
EINA_LIST_FOREACH ( e_randr_screen_info . rrvd_info . randr_info_12 - > modes , iter , mode_info )
{
if ( mode_info & & ( mode_info - > xid = = mode ) ) return mode_info ;
}
return NULL ;
}
2012-03-08 03:37:54 -08:00
E_Randr_Output_Info *
2012-02-18 08:49:07 -08:00
_12_screen_info_output_info_get ( const Ecore_X_Randr_Output output )
{
Eina_List * iter ;
E_Randr_Output_Info * output_info ;
EINA_SAFETY_ON_TRUE_RETURN_VAL ( E_RANDR_12_NO_OUTPUTS , NULL ) ;
EINA_LIST_FOREACH ( e_randr_screen_info . rrvd_info . randr_info_12 - > outputs , iter , output_info )
{
if ( output_info & & ( output_info - > xid = = output ) ) return output_info ;
}
return NULL ;
}
2012-03-08 03:37:54 -08:00
E_Randr_Crtc_Info *
2012-02-18 08:49:07 -08:00
_12_screen_info_crtc_info_get ( const Ecore_X_Randr_Crtc crtc )
{
Eina_List * iter ;
E_Randr_Crtc_Info * crtc_info ;
EINA_SAFETY_ON_TRUE_RETURN_VAL ( E_RANDR_12_NO_CRTCS , NULL ) ;
EINA_LIST_FOREACH ( e_randr_screen_info . rrvd_info . randr_info_12 - > crtcs , iter , crtc_info )
{
if ( crtc_info & & ( crtc_info - > xid = = crtc ) ) return crtc_info ;
}
return NULL ;
}
2012-03-08 03:37:54 -08:00
Eina_Bool
2012-02-18 08:49:07 -08:00
_12_screen_info_edid_is_available ( const E_Randr_Edid_Hash * hash )
{
Eina_List * iter ;
E_Randr_Output_Info * output_info ;
EINA_SAFETY_ON_TRUE_RETURN_VAL ( E_RANDR_12_NO_OUTPUTS , EINA_FALSE ) ;
EINA_SAFETY_ON_NULL_RETURN_VAL ( hash , EINA_FALSE ) ;
EINA_LIST_FOREACH ( e_randr_screen_info . rrvd_info . randr_info_12 - > outputs , iter , output_info )
{
if ( ! output_info | | ! output_info - > monitor )
continue ;
if ( output_info - > monitor - > edid_hash . hash = = hash - > hash )
return EINA_TRUE ;
}
return EINA_FALSE ;
}
2012-08-28 05:41:17 -07:00
2012-02-18 08:49:07 -08:00
/*
* returns a mode within a given list of modes that is gemetrically identical .
* If none is found , NULL is returned .
*/
2012-03-08 03:37:54 -08:00
static Ecore_X_Randr_Mode_Info *
2012-02-18 08:49:07 -08:00
_mode_geo_identical_find ( Eina_List * modes , Ecore_X_Randr_Mode_Info * mode )
{
Eina_List * iter ;
Ecore_X_Randr_Mode_Info * mode_info ;
EINA_LIST_FOREACH ( modes , iter , mode_info )
{
if ( ( mode_info - > width = = mode - > width ) & & ( mode_info - > height = = mode - > height ) )
return mode_info ;
}
return NULL ;
}
/*****************************************************************
*
* Init . and Shutdown code
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
2012-03-08 03:37:54 -08:00
Eina_Bool
2012-02-18 08:49:07 -08:00
_12_screen_info_refresh ( void )
{
2012-02-21 16:02:58 -08:00
EINA_SAFETY_ON_TRUE_RETURN_VAL ( ( e_randr_screen_info . randr_version < ECORE_X_RANDR_1_2 ) , EINA_FALSE ) ;
2012-02-18 08:49:07 -08:00
2012-02-21 00:17:32 -08:00
if ( e_randr_screen_info . rrvd_info . randr_info_12 )
_12_screen_info_free ( e_randr_screen_info . rrvd_info . randr_info_12 ) ;
2012-02-21 15:53:00 -08:00
if ( ! ( e_randr_screen_info . rrvd_info . randr_info_12 = _screen_info_12_new ( ) ) | |
2012-08-28 05:41:17 -07:00
! _structs_init ( ) )
2012-02-21 15:53:00 -08:00
return EINA_FALSE ;
2012-02-18 08:49:07 -08:00
_screen_primary_output_assign ( NULL ) ;
2012-02-21 16:02:58 -08:00
return EINA_TRUE ;
2012-02-18 08:49:07 -08:00
}
/******************************************************************
*
* Event code
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
2012-03-08 03:37:54 -08:00
static Eina_Bool
2012-02-18 08:49:07 -08:00
_x_poll_cb ( void * data __UNUSED__ )
{
2012-10-10 02:42:05 -07:00
if ( ! e_randr_screen_info . rrvd_info . randr_info_12 )
{
poller = NULL ;
return ECORE_CALLBACK_CANCEL ;
}
2012-02-18 08:49:07 -08:00
ecore_x_randr_screen_primary_output_orientations_get ( e_randr_screen_info . root ) ;
return ECORE_CALLBACK_RENEW ;
}
2012-03-08 03:37:54 -08:00
void
2012-02-18 08:49:07 -08:00
_12_event_listeners_add ( void )
{
EINA_SAFETY_ON_TRUE_RETURN ( E_RANDR_12_NO ) ;
ecore_x_randr_events_select ( e_randr_screen_info . root , EINA_TRUE ) ;
_event_handlers = eina_list_append ( _event_handlers , ecore_event_handler_add ( ECORE_X_EVENT_RANDR_CRTC_CHANGE , _crtc_change_event_cb , NULL ) ) ;
_event_handlers = eina_list_append ( _event_handlers , ecore_event_handler_add ( ECORE_X_EVENT_RANDR_OUTPUT_CHANGE , _output_change_event_cb , NULL ) ) ;
_event_handlers = eina_list_append ( _event_handlers , ecore_event_handler_add ( ECORE_X_EVENT_RANDR_OUTPUT_PROPERTY_NOTIFY , _output_property_change_event_cb , NULL ) ) ;
// WORKAROUND problem of X not sending events
poller = ecore_poller_add ( ECORE_POLLER_CORE , POLLINTERVAL , _x_poll_cb , NULL ) ;
}
/* Usually events are triggered in the following order.
* ( Dis ) connect Display Scenario :
* 1. ) ECORE_X_EVENT_OUTPUT_CHANGE //Triggered, when a display is connected to an
* output
* 2. ) ECORE_X_EVENT_CRTC_CHANGE //Triggered when the CRTC mode is changed (eg.
* enabled by e . g . e_randr or xrandr )
* 3. ) ECORE_X_EVENT_OUTPUT_CHANGE //Triggered for each output changed by the
* preceeding enabling .
*
* When the mode of a CRTC is changed only events 2 and 3 are triggered
*
*/
2012-03-08 03:37:54 -08:00
static Eina_Bool
2012-02-18 08:49:07 -08:00
_output_change_event_cb ( void * data __UNUSED__ , int type , void * ev )
{
2012-08-28 05:41:17 -07:00
Ecore_X_Event_Randr_Output_Change * oce = ( Ecore_X_Event_Randr_Output_Change * ) ev ;
2012-02-20 11:14:22 -08:00
E_Randr_Output_Info * output_info = NULL ;
2012-02-18 08:49:07 -08:00
E_Randr_Crtc_Info * crtc_info = NULL ;
2012-02-20 11:14:22 -08:00
Eina_Bool policy_success = EINA_FALSE , con_state_changed = EINA_FALSE ;
2012-02-18 08:49:07 -08:00
2012-10-10 02:42:05 -07:00
EINA_SAFETY_ON_TRUE_RETURN_VAL ( E_RANDR_12_NO , ECORE_CALLBACK_RENEW ) ;
2012-02-18 08:49:07 -08:00
EINA_SAFETY_ON_TRUE_RETURN_VAL ( ( type ! = ECORE_X_EVENT_RANDR_OUTPUT_CHANGE ) , ECORE_CALLBACK_RENEW ) ;
/* event information:
Ecore_X_Window win ;
Ecore_X_Randr_Output output ;
Ecore_X_Randr_Crtc crtc ;
Ecore_X_Randr_Mode mode ;
Ecore_X_Randr_Orientation orientation ;
Ecore_X_Randr_Connection_Status connection ;
Ecore_X_Render_Subpixel_Order subpixel_order ;
2012-08-28 05:41:17 -07:00
*/
2012-02-18 08:49:07 -08:00
EINA_SAFETY_ON_FALSE_RETURN_VAL ( ( output_info = _12_screen_info_output_info_get ( oce - > output ) ) , ECORE_CALLBACK_RENEW ) ;
2012-06-14 06:42:02 -07:00
DBG ( " E_RANDR: Output event: \n "
2012-08-28 05:41:17 -07:00
" \t \t : relative to win: %d \n "
" \t \t : output (xid): %d \n "
" \t \t : used by crtc (xid): %d \n "
" \t \t : mode: %d \n "
" \t \t : orientation: %d \n "
" \t \t : connection state: %s \n "
" \t \t : subpixel_order: %d " ,
oce - > win ,
oce - > output ,
oce - > crtc ,
oce - > mode ,
oce - > orientation ,
_CONNECTION_STATES_STRINGS [ oce - > connection ] ,
oce - > subpixel_order ) ;
2012-02-18 08:49:07 -08:00
crtc_info = _12_screen_info_crtc_info_get ( oce - > crtc ) ;
//WORKAROUND
//Reason: Missing events, when an output is moved from one CRTC to
// another
if ( output_info - > crtc & & ( crtc_info ! = output_info - > crtc ) )
output_info - > crtc - > outputs = eina_list_remove ( output_info - > crtc - > outputs , output_info ) ;
//END WORKAROUND
output_info - > crtc = crtc_info ;
//Update mode references in case a mode was added manually
if ( output_info - > monitor )
{
eina_list_free ( output_info - > monitor - > modes ) ;
output_info - > monitor - > modes = NULL ;
eina_list_free ( output_info - > monitor - > preferred_modes ) ;
output_info - > monitor - > preferred_modes = NULL ;
_monitor_modes_refs_set ( output_info - > monitor , output_info - > xid ) ;
2012-03-13 12:58:06 -07:00
//Also update common modes of the used CRTC
if ( crtc_info & & crtc_info - > current_mode )
{
eina_list_free ( crtc_info - > outputs ) ;
crtc_info - > outputs = NULL ;
eina_list_free ( crtc_info - > outputs_common_modes ) ;
crtc_info - > outputs_common_modes = NULL ;
_crtc_outputs_refs_set ( crtc_info ) ;
}
2012-02-18 08:49:07 -08:00
}
2012-02-20 11:14:22 -08:00
con_state_changed = ( Eina_Bool ) ( output_info - > connection_status ! = oce - > connection ) ;
2012-02-18 08:49:07 -08:00
output_info - > connection_status = oce - > connection ;
output_info - > subpixel_order = oce - > subpixel_order ;
2012-02-20 11:14:22 -08:00
if ( con_state_changed )
2012-02-18 08:49:07 -08:00
{
2012-08-28 05:41:17 -07:00
_monitor_info_free ( output_info - > monitor ) ;
output_info - > monitor = NULL ;
2012-02-18 08:49:07 -08:00
if ( oce - > connection = = ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED )
{
//New device connected!
output_info - > monitor = _monitor_info_new ( output_info ) ;
2012-06-14 06:42:02 -07:00
INF ( " E_RANDR: Output %d was newly connected. " , output_info - > xid ) ;
2012-02-18 08:49:07 -08:00
//only try to enable the monitor if there is no serialized setup
2012-08-28 05:41:17 -07:00
if ( ! _12_try_restore_configuration ( ) )
2012-02-18 08:49:07 -08:00
{
2012-05-30 12:16:58 -07:00
policy_success = e_randr_12_try_enable_output ( output_info , output_info - > policy , EINA_FALSE ) ; //maybe give a success message?
2012-06-14 06:42:02 -07:00
INF ( " E_RANDR: Policy \" %s \" was enforced %ssuccesfully. " , _POLICIES_STRINGS [ output_info - > policy - 1 ] , ( policy_success ? " " : " un " ) ) ;
2012-02-18 08:49:07 -08:00
}
}
else
{
//connection_state is 'unknown' or 'disconnected': treat as disconnected!
if ( output_info - > crtc )
{
output_info - > crtc - > outputs = eina_list_remove ( output_info - > crtc - > outputs , output_info ) ;
//in case this output was the last one connected on a CRTC,
//disable it again
if ( eina_list_count ( output_info - > crtc - > outputs ) = = 0 )
{
//in case it was the only output running on this CRTC, disable
//it.
ecore_x_randr_crtc_mode_set ( e_randr_screen_info . root , output_info - > crtc - > xid , NULL , Ecore_X_Randr_None , Ecore_X_Randr_None ) ;
}
}
//retry to find a suiting serialized setup for the remaining
//connected monitors
_12_try_restore_configuration ( ) ;
}
}
return ECORE_CALLBACK_RENEW ;
}
2012-03-08 03:37:54 -08:00
static Eina_Bool
2012-02-18 08:49:07 -08:00
_crtc_change_event_cb ( void * data __UNUSED__ , int type , void * ev )
{
2012-08-28 05:41:17 -07:00
Ecore_X_Event_Randr_Crtc_Change * cce = ( Ecore_X_Event_Randr_Crtc_Change * ) ev ;
2012-02-18 08:49:07 -08:00
E_Randr_Crtc_Info * crtc_info ;
2012-10-10 02:42:05 -07:00
EINA_SAFETY_ON_TRUE_RETURN_VAL ( E_RANDR_12_NO , ECORE_CALLBACK_RENEW ) ;
2012-02-18 08:49:07 -08:00
EINA_SAFETY_ON_TRUE_RETURN_VAL ( ( type ! = ECORE_X_EVENT_RANDR_CRTC_CHANGE ) , ECORE_CALLBACK_RENEW ) ;
/* event information:
2012-08-28 05:41:17 -07:00
Ecore_X_Window win ;
Ecore_X_Randr_Crtc crtc ;
Ecore_X_Randr_Mode mode ;
Ecore_X_Randr_Orientation orientation ;
int x ;
int y ;
int width ;
int height ;
*/
2012-06-14 06:42:02 -07:00
DBG ( " E_RANDR: CRTC event: \n "
2012-08-28 05:41:17 -07:00
" \t \t : relative to win: %d \n "
" \t \t : crtc (xid): %d \n "
" \t \t : mode (xid): %d \n "
" \t \t : orientation: %d \n "
" \t \t : x: %d \n "
" \t \t : y: %d \n "
" \t \t : width: %d \n "
" \t \t : height: %d " ,
cce - > win ,
cce - > crtc ,
cce - > mode ,
cce - > orientation ,
cce - > geo . x ,
cce - > geo . y ,
cce - > geo . w ,
cce - > geo . h ) ;
2012-02-18 08:49:07 -08:00
crtc_info = _12_screen_info_crtc_info_get ( cce - > crtc ) ;
EINA_SAFETY_ON_NULL_RETURN_VAL ( crtc_info , ECORE_CALLBACK_RENEW ) ;
crtc_info - > current_mode = _12_screen_info_mode_info_get ( cce - > mode ) ;
crtc_info - > current_orientation = cce - > orientation ;
crtc_info - > geometry . x = cce - > geo . x ;
crtc_info - > geometry . y = cce - > geo . y ;
crtc_info - > geometry . w = cce - > geo . w ;
crtc_info - > geometry . h = cce - > geo . h ;
//update screensize if necessary
e_randr_screen_info . rrvd_info . randr_info_12 - > current_size . width = MAX ( ( cce - > geo . x + cce - > geo . w ) , e_randr_screen_info . rrvd_info . randr_info_12 - > current_size . width ) ;
e_randr_screen_info . rrvd_info . randr_info_12 - > current_size . height = MAX ( ( cce - > geo . y + cce - > geo . h ) , e_randr_screen_info . rrvd_info . randr_info_12 - > current_size . height ) ;
//update output data
eina_list_free ( crtc_info - > outputs ) ;
crtc_info - > outputs = NULL ;
eina_list_free ( crtc_info - > outputs_common_modes ) ;
crtc_info - > outputs_common_modes = NULL ;
//if still enabled, update references to outputs
if ( crtc_info - > current_mode )
{
2012-03-13 12:58:06 -07:00
eina_list_free ( crtc_info - > outputs ) ;
crtc_info - > outputs = NULL ;
eina_list_free ( crtc_info - > outputs_common_modes ) ;
crtc_info - > outputs_common_modes = NULL ;
2012-02-18 08:49:07 -08:00
_crtc_outputs_refs_set ( crtc_info ) ;
}
//crop the screen
ecore_x_randr_screen_reset ( e_randr_screen_info . root ) ;
return ECORE_CALLBACK_RENEW ;
}
2012-03-08 03:37:54 -08:00
static Eina_Bool
2012-02-18 08:49:07 -08:00
_output_property_change_event_cb ( void * data __UNUSED__ , int type , void * ev )
{
2012-08-28 05:41:17 -07:00
Ecore_X_Event_Randr_Output_Property_Notify * opce = ( Ecore_X_Event_Randr_Output_Property_Notify * ) ev ;
2012-02-18 08:49:07 -08:00
E_Randr_Output_Info * output_info ;
2012-10-10 02:42:05 -07:00
EINA_SAFETY_ON_TRUE_RETURN_VAL ( E_RANDR_12_NO , ECORE_CALLBACK_RENEW ) ;
2012-02-18 08:49:07 -08:00
EINA_SAFETY_ON_TRUE_RETURN_VAL ( ( type ! = ECORE_X_EVENT_RANDR_OUTPUT_PROPERTY_NOTIFY ) , ECORE_CALLBACK_RENEW ) ;
/* event information:
Ecore_X_Window win ;
Ecore_X_Randr_Output output ;
Ecore_X_Atom property ;
Ecore_X_Time time ;
Ecore_X_Randr_Property_Change state ;
2012-08-28 05:41:17 -07:00
*/
2012-02-18 08:49:07 -08:00
EINA_SAFETY_ON_FALSE_RETURN_VAL ( ( output_info = _12_screen_info_output_info_get ( opce - > output ) ) , ECORE_CALLBACK_RENEW ) ;
return ECORE_CALLBACK_RENEW ;
}
/*
* Try to enable this output on an unoccupied CRTC . ' Force ' in this context
* means , that if there are only occupied CRTCs , we disable another output to
* enable this one . If not forced we will - if we don ' t find an unoccupied CRTC
* - try to share the output of a CRTC with other outputs already using it
* ( clone ) .
*/
2012-05-30 12:16:58 -07:00
EINTERN Eina_Bool
e_randr_12_try_enable_output ( E_Randr_Output_Info * output_info , Ecore_X_Randr_Output_Policy policy , Eina_Bool force )
2012-02-18 08:49:07 -08:00
{
Eina_List * iter , * outputs_list = NULL , * common_modes = NULL ;
2012-02-22 07:42:07 -08:00
E_Randr_Crtc_Info * crtc_info = NULL , * usable_crtc = NULL ;
const E_Randr_Crtc_Info * crtc_rel = NULL ;
2012-02-18 08:49:07 -08:00
E_Randr_Output_Info * primary_output ;
Ecore_X_Randr_Output * outputs ;
Ecore_X_Randr_Mode_Info * mode_info ;
2012-02-22 07:42:07 -08:00
int dx = Ecore_X_Randr_None , dy = Ecore_X_Randr_None ;
Eina_Bool ret = EINA_TRUE ;
2012-02-18 08:49:07 -08:00
EINA_SAFETY_ON_NULL_RETURN_VAL ( output_info , EINA_FALSE ) ;
EINA_SAFETY_ON_TRUE_RETURN_VAL ( ( output_info - > crtc & & output_info - > crtc - > current_mode ) , EINA_FALSE ) ;
/*
* Try to find a usable crtc for this output . Either unused or forced .
*/
EINA_LIST_FOREACH ( output_info - > possible_crtcs , iter , crtc_info )
{
if ( ! crtc_info - > current_mode | | ! crtc_info - > outputs | | force )
{
usable_crtc = crtc_info ;
break ;
}
}
/*
* apparently we don ' t have a CRTC to make use of the device
*/
if ( ! usable_crtc )
return EINA_FALSE ;
//get the CRTC we will refer to, dependend on policy
2012-05-30 12:16:58 -07:00
switch ( policy )
2012-02-18 08:49:07 -08:00
{
case ECORE_X_RANDR_OUTPUT_POLICY_NONE :
2012-08-28 05:41:17 -07:00
return EINA_TRUE ;
2012-02-18 08:49:07 -08:00
2012-05-30 12:16:58 -07:00
case ECORE_X_RANDR_OUTPUT_POLICY_ASK :
2012-08-28 05:41:17 -07:00
e_randr_12_ask_dialog_new ( output_info ) ;
return EINA_TRUE ; //This is a bit incorrect (dialog feedback is async), but probably not worth a lock.
2012-05-30 12:16:58 -07:00
2012-02-18 08:49:07 -08:00
case ECORE_X_RANDR_OUTPUT_POLICY_CLONE :
2012-08-28 05:41:17 -07:00
/*
* Order of approaches to enable a clone ( of the primary output ) :
*
* 0. Get Primary output from Server
* 1. Try to add new Output to primary output ' s CRTC , using the mode used
* by the primary output
* 2. Try to enable clone in the same
* 2 a . exact mode or a
* 2 b . geometrically identical mode
* 3. Find a most high resolution mode in common to enable on primary output ' s CRTC and the new
* output ' s CRTC
* 4. fail .
*/
//Assign new output, if necessary
_screen_primary_output_assign ( output_info ) ;
if ( ( primary_output = e_randr_screen_info . rrvd_info . randr_info_12 - > primary_output ) )
{
if ( primary_output - > crtc & & primary_output - > crtc - > current_mode & & eina_list_data_find ( output_info - > monitor - > modes , primary_output - > crtc - > current_mode ) )
{
/*
* mode currently used by primary output ' s CRTC is also supported by the new output
*/
if ( eina_list_data_find ( primary_output - > crtc - > possible_outputs , output_info ) & & eina_list_data_find ( output_info - > monitor - > modes , primary_output - > crtc - > current_mode ) )
{
/*
* 1. Try to add new Output to primary output ' s CRTC , using the mode used
* by the primary output
* TODO : check with compatibility list in RandRR > = 1.3
* if available
*
* The new output is also usable by the primary output ' s
* CRTC . Try to enable this output together with the already
* enabled outputs on the CRTC in already used mode .
*/
outputs_list = primary_output - > crtc - > outputs ;
outputs_list = eina_list_append ( outputs_list , output_info ) ;
outputs = _outputs_to_array ( outputs_list ) ;
primary_output - > crtc - > outputs = NULL ;
ret & = ecore_x_randr_crtc_mode_set ( e_randr_screen_info . root , primary_output - > crtc - > xid , outputs , eina_list_count ( outputs_list ) , primary_output - > crtc - > current_mode - > xid ) ;
free ( outputs ) ;
eina_list_free ( outputs_list ) ;
return ret ;
}
else
{
/*
* 2. Try to enable clone in the same
*/
/*
* 2 a . exact mode .
*/
ret & = ecore_x_randr_crtc_mode_set ( e_randr_screen_info . root , usable_crtc - > xid , & output_info - > xid , 1 , primary_output - > crtc - > current_mode - > xid ) ;
ret & = ecore_x_randr_crtc_pos_relative_set ( e_randr_screen_info . root , usable_crtc - > xid , primary_output - > crtc - > xid , ECORE_X_RANDR_OUTPUT_POLICY_CLONE , e_randr_screen_info . rrvd_info . randr_info_12 - > alignment ) ;
return ret ;
}
}
else
{
/*
* 2 b . geometrically identical mode
*/
if ( primary_output - > crtc & & ( mode_info = _mode_geo_identical_find ( output_info - > monitor - > modes , primary_output - > crtc - > current_mode ) ) )
{
ret & = ecore_x_randr_crtc_mode_set ( e_randr_screen_info . root , usable_crtc - > xid , & output_info - > xid , 1 , mode_info - > xid ) ;
ret & = ecore_x_randr_crtc_pos_relative_set ( e_randr_screen_info . root , usable_crtc - > xid , primary_output - > crtc - > xid , ECORE_X_RANDR_OUTPUT_POLICY_CLONE , e_randr_screen_info . rrvd_info . randr_info_12 - > alignment ) ;
return ret ;
}
/*
* 3. Find the highest resolution mode common to enable on primary output ' s CRTC and the new one .
*/
if ( ( ( outputs_list = eina_list_append ( outputs_list , primary_output ) ) & & ( outputs_list = eina_list_append ( outputs_list , output_info ) ) ) )
{
if ( primary_output - > crtc )
{
common_modes = _outputs_common_modes_get ( outputs_list , primary_output - > crtc - > current_mode ) ;
if ( ( mode_info = eina_list_nth ( common_modes , 0 ) ) )
{
eina_list_free ( common_modes ) ;
INF ( " Will try to set mode: %dx%d for primary and clone. " , mode_info - > width , mode_info - > height ) ;
ret & = ecore_x_randr_crtc_mode_set ( e_randr_screen_info . root , primary_output - > crtc - > xid , ( ( Ecore_X_Randr_Output * ) Ecore_X_Randr_Unset ) , Ecore_X_Randr_Unset , mode_info - > xid ) ;
ret & = ecore_x_randr_crtc_mode_set ( e_randr_screen_info . root , usable_crtc - > xid , & output_info - > xid , 1 , mode_info - > xid ) ;
ret & = ecore_x_randr_crtc_pos_relative_set ( e_randr_screen_info . root , usable_crtc - > xid , primary_output - > crtc - > xid , ECORE_X_RANDR_OUTPUT_POLICY_CLONE , e_randr_screen_info . rrvd_info . randr_info_12 - > alignment ) ;
}
}
eina_list_free ( outputs_list ) ;
}
}
}
else
ERR ( " E_RANDR: Failed to clone, because of missing or disabled primary output! " ) ;
/*
* 4. FAIL
*/
break ;
2012-02-18 08:49:07 -08:00
default :
2012-08-28 05:41:17 -07:00
//enable and position according to used policies
if ( ! ( mode_info = ( ( Ecore_X_Randr_Mode_Info * ) eina_list_data_get ( output_info - > monitor - > preferred_modes ) ) ) )
{
ERR ( " E_RANDR: Could not enable output(%d), as it has no preferred modes (and there for none at all)! " , output_info - > xid ) ;
ret = EINA_FALSE ;
break ;
}
//get the crtc we will place our's relative to. If it's NULL, this is the
//only output attached, work done.
if ( ! ( crtc_rel = _crtc_according_to_policy_get ( usable_crtc , policy ) ) )
{
INF ( " E_RANDR: CRTC %d enabled. No other CRTC had to be moved. " , usable_crtc - > xid ) ;
ret & = ecore_x_randr_crtc_mode_set ( e_randr_screen_info . root , usable_crtc - > xid , & output_info - > xid , 1 , mode_info - > xid ) ;
return ret ;
}
//Calculate new CRTC's position according to policy
switch ( policy )
{
case ECORE_X_RANDR_OUTPUT_POLICY_ABOVE :
usable_crtc - > geometry . x = crtc_rel - > geometry . x ;
usable_crtc - > geometry . y = 0 ;
break ;
case ECORE_X_RANDR_OUTPUT_POLICY_RIGHT :
usable_crtc - > geometry . x = ( crtc_rel - > geometry . x + crtc_rel - > geometry . w ) ;
usable_crtc - > geometry . y = crtc_rel - > geometry . y ;
break ;
case ECORE_X_RANDR_OUTPUT_POLICY_BELOW :
usable_crtc - > geometry . x = crtc_rel - > geometry . x ;
usable_crtc - > geometry . y = ( crtc_rel - > geometry . y + crtc_rel - > geometry . h ) ;
break ;
case ECORE_X_RANDR_OUTPUT_POLICY_LEFT :
usable_crtc - > geometry . y = crtc_rel - > geometry . y ;
usable_crtc - > geometry . x = 0 ;
break ;
default :
usable_crtc - > geometry . y = 0 ;
usable_crtc - > geometry . x = 0 ;
}
if ( ( ret & = ecore_x_randr_crtc_settings_set ( e_randr_screen_info . root , usable_crtc - > xid , & output_info - > xid , 1 , usable_crtc - > geometry . x , usable_crtc - > geometry . y , mode_info - > xid , ECORE_X_RANDR_ORIENTATION_ROT_0 ) ) )
{
//WORKAROUND
//Reason: the CRTC event, that'd bring the new info about the set
//mode is arriving too late here.
usable_crtc - > current_mode = mode_info ;
usable_crtc - > geometry . w = mode_info - > width ;
usable_crtc - > geometry . h = mode_info - > height ;
//WORKAROUND END
INF ( " E_RANDR: Moved CRTC %d has geometry (x,y,wxh): %d, %d, %dx%d. " , usable_crtc - > xid , usable_crtc - > geometry . x , usable_crtc - > geometry . y , usable_crtc - > geometry . w , usable_crtc - > geometry . h ) ;
//following is policy dependend.
switch ( policy )
{
case ECORE_X_RANDR_OUTPUT_POLICY_ABOVE :
dy = ( crtc_rel - > geometry . y - usable_crtc - > geometry . h ) ;
if ( dy < 0 )
{
//virtual move (move other CRTCs as nessesary)
dy = - dy ;
ret & = ecore_x_randr_move_all_crtcs_but ( e_randr_screen_info . root ,
& usable_crtc - > xid ,
1 ,
dx ,
dy ) ;
INF ( " E_RANDR: Moving all CRTCs but %d, by %dx%d delta. " , usable_crtc - > xid , dx , dy ) ;
}
break ;
case ECORE_X_RANDR_OUTPUT_POLICY_LEFT :
dx = ( crtc_rel - > geometry . x - usable_crtc - > geometry . w ) ;
if ( dx < 0 )
{
//virtual move (move other CRTCs as nessesary)
dx = - dx ;
ret & = ecore_x_randr_move_all_crtcs_but ( e_randr_screen_info . root ,
& usable_crtc - > xid ,
1 ,
dx ,
dy ) ;
INF ( " E_RANDR: Moving all CRTCs but %d, by %dx%d delta. " , usable_crtc - > xid , dx , dy ) ;
}
break ;
default :
break ;
}
}
2012-02-18 08:49:07 -08:00
}
2012-02-22 07:42:07 -08:00
2012-02-18 08:49:07 -08:00
if ( ret )
ecore_x_randr_screen_reset ( e_randr_screen_info . root ) ;
return ret ;
}
2012-03-08 03:37:54 -08:00
void
2012-02-18 08:49:07 -08:00
_12_event_listeners_remove ( void )
{
Ecore_Event_Handler * _event_handler = NULL ;
2012-08-28 05:41:17 -07:00
EINA_LIST_FREE ( _event_handlers , _event_handler )
ecore_event_handler_del ( _event_handler ) ;
2012-02-18 08:49:07 -08:00
ecore_poller_del ( poller ) ;
poller = NULL ;
}
2012-08-28 05:41:17 -07:00