2012-02-18 08:49:07 -08:00
# include "e_randr_private.h"
# include "e_randr.h"
// E_Randr_Crtc_Info helper functions
static Eina_Bool _crtc_mode_intersects_crtcs ( E_Randr_Crtc_Info * crtc_info , Ecore_X_Randr_Mode_Info * mode ) ;
static Eina_Bool _crtc_outputs_mode_max_set ( E_Randr_Crtc_Info * crtc_info ) ;
void
_crtc_outputs_refs_set ( E_Randr_Crtc_Info * crtc_info )
{
E_Randr_Output_Info * output_info = NULL ;
Ecore_X_Randr_Output * outputs = NULL ;
2012-02-21 14:05:07 -08:00
int noutputs = 0 ;
2012-02-18 08:49:07 -08:00
EINA_SAFETY_ON_NULL_RETURN ( crtc_info ) ;
outputs = ecore_x_randr_crtc_outputs_get ( e_randr_screen_info . root , crtc_info - > xid , & noutputs ) ;
while ( - - noutputs > = 0 )
{
output_info = _12_screen_info_output_info_get ( outputs [ noutputs ] ) ;
if ( ! output_info )
2012-02-21 15:53:00 -08:00
{
fprintf ( stderr , " E_RANDR: Could not find output struct for output %d. \n " , outputs [ noutputs ] ) ;
continue ;
}
2012-02-18 08:49:07 -08:00
crtc_info - > outputs = eina_list_append ( crtc_info - > outputs , output_info ) ;
}
2012-02-21 14:05:07 -08:00
free ( outputs ) ;
2012-02-18 08:49:07 -08:00
crtc_info - > outputs_common_modes = _outputs_common_modes_get ( crtc_info - > outputs , NULL ) ;
}
void
_crtc_refs_set ( E_Randr_Crtc_Info * crtc_info )
{
Ecore_X_Randr_Mode mode = Ecore_X_Randr_None ;
Ecore_X_Randr_Mode_Info * mode_info = NULL ;
Ecore_X_Randr_Output * poutputs = NULL ;
E_Randr_Output_Info * output_info = NULL ;
2012-02-21 14:05:07 -08:00
int npoutputs = 0 ;
2012-02-18 08:49:07 -08:00
EINA_SAFETY_ON_NULL_RETURN ( crtc_info ) ;
mode = ecore_x_randr_crtc_mode_get ( e_randr_screen_info . root , crtc_info - > xid ) ;
if ( ! ( mode_info = _12_screen_info_mode_info_get ( mode ) ) )
{
//Mode unknown to the global structure, so add it
mode_info = ecore_x_randr_mode_info_get ( e_randr_screen_info . root , mode ) ;
e_randr_screen_info . rrvd_info . randr_info_12 - > modes = eina_list_append ( e_randr_screen_info . rrvd_info . randr_info_12 - > modes , mode_info ) ;
}
crtc_info - > current_mode = mode_info ;
poutputs = ecore_x_randr_crtc_possible_outputs_get ( e_randr_screen_info . root , crtc_info - > xid , & npoutputs ) ;
while ( - - npoutputs > = 0 )
{
output_info = _12_screen_info_output_info_get ( poutputs [ npoutputs ] ) ;
if ( ! output_info )
2012-02-21 11:58:51 -08:00
{
fprintf ( stderr , " E_RANDR: Could not find output struct for output %d. \n " , poutputs [ npoutputs ] ) ;
continue ;
}
2012-02-18 08:49:07 -08:00
crtc_info - > possible_outputs = eina_list_append ( crtc_info - > possible_outputs , output_info ) ;
}
2012-02-21 14:05:07 -08:00
free ( poutputs ) ;
2012-02-18 08:49:07 -08:00
_crtc_outputs_refs_set ( crtc_info ) ;
}
/**
* @ brief Allocate and init with values .
* @ param crtc the crtc the display is queried for . If Ecore_X_Randr_None is
* given , a struct with only the xid will be set
* @ return E_Randr_Crtc_Info element
*/
E_Randr_Crtc_Info *
_crtc_info_new ( Ecore_X_Randr_Crtc crtc )
{
E_Randr_Crtc_Info * crtc_info = NULL ;
EINA_SAFETY_ON_TRUE_RETURN_VAL ( E_RANDR_12_NO , NULL ) ;
crtc_info = E_NEW ( E_Randr_Crtc_Info , 1 ) ;
crtc_info - > xid = crtc ;
crtc_info - > panning . x = Ecore_X_Randr_Unset ;
crtc_info - > panning . y = Ecore_X_Randr_Unset ;
crtc_info - > panning . w = Ecore_X_Randr_Unset ;
crtc_info - > panning . h = Ecore_X_Randr_Unset ;
crtc_info - > tracking . x = Ecore_X_Randr_Unset ;
crtc_info - > tracking . y = Ecore_X_Randr_Unset ;
crtc_info - > tracking . w = Ecore_X_Randr_Unset ;
crtc_info - > tracking . h = Ecore_X_Randr_Unset ;
crtc_info - > border . x = Ecore_X_Randr_Unset ;
crtc_info - > border . y = Ecore_X_Randr_Unset ;
crtc_info - > border . w = Ecore_X_Randr_Unset ;
crtc_info - > border . h = Ecore_X_Randr_Unset ;
crtc_info - > gamma_ramps = NULL ;
crtc_info - > gamma_ramp_size = Ecore_X_Randr_Unset ;
crtc_info - > outputs = NULL ;
crtc_info - > possible_outputs = NULL ;
crtc_info - > outputs_common_modes = NULL ;
crtc_info - > current_mode = NULL ;
ecore_x_randr_crtc_geometry_get ( e_randr_screen_info . root , crtc_info - > xid , & crtc_info - > geometry . x , & crtc_info - > geometry . y , & crtc_info - > geometry . w , & crtc_info - > geometry . h ) ;
crtc_info - > current_orientation = ecore_x_randr_crtc_orientation_get ( e_randr_screen_info . root , crtc_info - > xid ) ;
crtc_info - > orientations = ecore_x_randr_crtc_orientations_get ( e_randr_screen_info . root , crtc_info - > xid ) ;
return crtc_info ;
}
/**
* @ param crtc_info the crtc info to be freed .
*/
void
_crtc_info_free ( E_Randr_Crtc_Info * crtc_info )
{
EINA_SAFETY_ON_NULL_RETURN ( crtc_info ) ;
if ( crtc_info - > gamma_ramps ) free ( crtc_info - > gamma_ramps ) ;
if ( crtc_info - > outputs )
{
eina_list_free ( crtc_info - > outputs ) ;
crtc_info - > outputs = NULL ;
}
if ( crtc_info - > possible_outputs )
{
eina_list_free ( crtc_info - > possible_outputs ) ;
crtc_info - > possible_outputs = NULL ;
}
}
/*
* returns EINA_TRUE if given CRTC would intersect with other CRTCs if set to
* given mode
*/
static Eina_Bool
_crtc_mode_intersects_crtcs ( E_Randr_Crtc_Info * crtc_info , Ecore_X_Randr_Mode_Info * mode )
{
Eina_List * iter ;
E_Randr_Crtc_Info * tmp ;
EINA_LIST_FOREACH ( e_randr_screen_info . rrvd_info . randr_info_12 - > crtcs , iter , tmp )
{
if ( ( tmp = = crtc_info ) | |
( ( tmp - > geometry . w < = 0 ) | | ( tmp - > geometry . h < = 0 ) ) )
continue ;
if ( E_INTERSECTS ( crtc_info - > geometry . x , crtc_info - > geometry . y ,
mode - > width , mode - > height , tmp - > geometry . x ,
tmp - > geometry . y , tmp - > geometry . w , tmp - > geometry . h )
& & ( ( crtc_info - > geometry . x ! = tmp - > geometry . x ) & &
( crtc_info - > geometry . y ! = tmp - > geometry . y ) ) )
return EINA_TRUE ;
}
return EINA_FALSE ;
}
/*
* reconfigures a CRTC enabling the highest resolution amongst its outputs ,
* without touching any other CRTC currently activated
*/
static Eina_Bool
_crtc_outputs_mode_max_set ( E_Randr_Crtc_Info * crtc_info )
{
Ecore_X_Randr_Mode_Info * mode_info ;
Eina_List * iter ;
Eina_Bool ret = EINA_TRUE ;
Ecore_X_Randr_Output * outputs ;
if ( ! crtc_info | | ! crtc_info - > outputs | | ! crtc_info - > outputs_common_modes ) return EINA_FALSE ;
EINA_LIST_REVERSE_FOREACH ( crtc_info - > outputs_common_modes , iter , mode_info )
{
if ( ! _crtc_mode_intersects_crtcs ( crtc_info , mode_info ) )
break ;
}
if ( ! mode_info )
{
//eina_list_free(crtc_info->outputs_common_modes);
return EINA_FALSE ;
}
if ( ( outputs = _outputs_to_array ( crtc_info - > outputs ) ) )
{
ret = ecore_x_randr_crtc_mode_set ( e_randr_screen_info . root , crtc_info - > xid , outputs , eina_list_count ( crtc_info - > outputs ) , mode_info - > xid ) ;
free ( outputs ) ;
}
//eina_list_free(crtc_info->outputs_common_modes);
//crtc_info->outputs_common_modes = NULL;
ecore_x_randr_screen_reset ( e_randr_screen_info . root ) ;
return ret ;
}
/*
* reconfigure screen setup according to policy . This is only required if all
* CRTCs ' positions might be affected by the another screens ' movement . This includes ' virtual ' moves ,
* which means that e . g . when a crtc should be placed at a position < 0 , all
* other crtcs are accordingly moved instead , so the result is the same .
*/
2012-02-18 23:36:01 -08:00
Eina_Bool
2012-02-20 11:14:26 -08:00
_crtc_move_policy ( E_Randr_Crtc_Info * new_crtc , Ecore_X_Randr_Output_Policy policy )
2012-02-18 08:49:07 -08:00
{
const E_Randr_Crtc_Info * crtc_rel ;
int dx = Ecore_X_Randr_None , dy = Ecore_X_Randr_None ;
Eina_Bool ret = EINA_TRUE ;
2012-02-20 11:14:26 -08:00
EINA_SAFETY_ON_NULL_RETURN_VAL ( new_crtc , EINA_FALSE ) ;
2012-02-18 08:49:07 -08:00
//get the crtc we will place our's relative to. If it's NULL, this is the
//only output attached, work done.
2012-02-20 11:14:26 -08:00
if ( ! ( crtc_rel = _crtc_according_to_policy_get ( new_crtc , policy ) ) )
{
fprintf ( stderr , " E_RANDR: Moving CRTC %d, there is no other CRTC to move this one relative to. \n " , new_crtc - > xid ) ;
return EINA_TRUE ;
}
2012-02-18 08:49:07 -08:00
2012-02-20 11:14:26 -08:00
fprintf ( stderr , " E_RANDR: Moved CRTC %d has geometry (x,y,wxh): %d, %d, %dx%d. \n " , new_crtc - > xid , new_crtc - > geometry . x , new_crtc - > geometry . y , new_crtc - > geometry . w , new_crtc - > geometry . h ) ;
2012-02-18 08:49:07 -08:00
//following is policy dependend.
2012-02-20 11:14:26 -08:00
switch ( policy )
2012-02-18 08:49:07 -08:00
{
case ECORE_X_RANDR_OUTPUT_POLICY_ABOVE :
dy = ( crtc_rel - > geometry . y - new_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 ,
& new_crtc - > xid ,
1 ,
dx ,
dy ) ;
2012-02-20 11:14:26 -08:00
fprintf ( stderr , " E_RANDR: Moving all CRTCs but %d, by %dx%d delta. \n " , new_crtc - > xid , dx , dy ) ;
2012-02-18 08:49:07 -08:00
}
break ;
case ECORE_X_RANDR_OUTPUT_POLICY_LEFT :
dx = ( crtc_rel - > geometry . x - new_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 ,
& new_crtc - > xid ,
1 ,
dx ,
dy ) ;
2012-02-20 11:14:26 -08:00
fprintf ( stderr , " E_RANDR: Moving all CRTCs but %d, by %dx%d delta. \n " , new_crtc - > xid , dx , dy ) ;
2012-02-18 08:49:07 -08:00
}
break ;
default :
break ;
}
2012-02-20 11:14:26 -08:00
ret & = ecore_x_randr_crtc_pos_relative_set ( e_randr_screen_info . root , new_crtc - > xid , crtc_rel - > xid , policy , e_randr_screen_info . rrvd_info . randr_info_12 - > alignment ) ;
2012-02-18 08:49:07 -08:00
return ret ;
}
/*
* this retrieves a CRTC depending on a policy .
* Note that this is enlightenment specific ! Enlightenment doesn ' t ' allow ' zones
* to overlap . Thus we always use the output with the most extreme position
* instead of trying to fill gaps like tetris . Though this could be done by
* simply implementing another policy .
*
* Simply put : get the
* - right
* - left
* - top
* - bottom
* most CRTC and return it .
*/
const E_Randr_Crtc_Info *
_crtc_according_to_policy_get ( E_Randr_Crtc_Info * but , Ecore_X_Randr_Output_Policy policy )
{
Eina_List * iter , * possible_crtcs = NULL ;
E_Randr_Crtc_Info * crtc_info , * ret = NULL ;
EINA_SAFETY_ON_TRUE_RETURN_VAL ( E_RANDR_12_NO_CRTCS , NULL ) ;
//get any crtc that besides 'but' to start with
possible_crtcs = eina_list_clone ( e_randr_screen_info . rrvd_info . randr_info_12 - > crtcs ) ;
possible_crtcs = eina_list_remove ( possible_crtcs , but ) ;
if ( ( eina_list_count ( possible_crtcs ) = = 0 ) & & ( policy ! = ECORE_X_RANDR_OUTPUT_POLICY_CLONE ) )
{
eina_list_free ( possible_crtcs ) ;
return NULL ;
}
// get an initial value for ret
ret = ( E_Randr_Crtc_Info * ) eina_list_data_get ( eina_list_last ( possible_crtcs ) ) ;
switch ( policy )
{
case ECORE_X_RANDR_OUTPUT_POLICY_ABOVE :
EINA_LIST_FOREACH ( e_randr_screen_info . rrvd_info . randr_info_12 - > crtcs , iter , crtc_info )
{
if ( crtc_info - > geometry . y < ret - > geometry . y )
ret = crtc_info ;
}
break ;
case ECORE_X_RANDR_OUTPUT_POLICY_RIGHT :
EINA_LIST_FOREACH ( e_randr_screen_info . rrvd_info . randr_info_12 - > crtcs , iter , crtc_info )
{
if ( ( crtc_info - > geometry . x + crtc_info - > geometry . w ) >
( ret - > geometry . x + ret - > geometry . w ) )
ret = crtc_info ;
}
break ;
case ECORE_X_RANDR_OUTPUT_POLICY_BELOW :
EINA_LIST_FOREACH ( e_randr_screen_info . rrvd_info . randr_info_12 - > crtcs , iter , crtc_info )
{
if ( ( crtc_info - > geometry . y + crtc_info - > geometry . h ) >
( ret - > geometry . y + ret - > geometry . h ) )
ret = crtc_info ;
}
break ;
case ECORE_X_RANDR_OUTPUT_POLICY_LEFT :
EINA_LIST_FOREACH ( e_randr_screen_info . rrvd_info . randr_info_12 - > crtcs , iter , crtc_info )
{
if ( crtc_info - > geometry . x < ret - > geometry . x )
ret = crtc_info ;
}
break ;
case ECORE_X_RANDR_OUTPUT_POLICY_CLONE :
ret = ( e_randr_screen_info . rrvd_info . randr_info_12 - > primary_output ) ? e_randr_screen_info . rrvd_info . randr_info_12 - > primary_output - > crtc : NULL ;
break ;
default :
break ;
}
eina_list_free ( possible_crtcs ) ;
return ret ;
}