From b27aec4ad5642c2bae9464bccebf1077752063c3 Mon Sep 17 00:00:00 2001 From: Leif Middelschulte Date: Sat, 18 Feb 2012 16:49:07 +0000 Subject: [PATCH] Refactoring e_randr, big time. SVN revision: 68114 --- src/bin/Makefile.am | 7 + src/bin/e_config.c | 68 +- src/bin/e_randr.c | 2423 +--------------------------- src/bin/e_randr.h | 62 +- src/bin/e_randr_11.c | 103 ++ src/bin/e_randr_11_serialization.c | 102 ++ src/bin/e_randr_12.c | 717 ++++++++ src/bin/e_randr_12_crtc.c | 333 ++++ src/bin/e_randr_12_output.c | 233 +++ src/bin/e_randr_12_serialization.c | 594 +++++++ src/bin/e_randr_private.h | 68 + src/bin/e_randr_serialization.c | 74 + 12 files changed, 2358 insertions(+), 2426 deletions(-) create mode 100644 src/bin/e_randr_11.c create mode 100644 src/bin/e_randr_11_serialization.c create mode 100644 src/bin/e_randr_12.c create mode 100644 src/bin/e_randr_12_crtc.c create mode 100644 src/bin/e_randr_12_output.c create mode 100644 src/bin/e_randr_12_serialization.c create mode 100644 src/bin/e_randr_private.h create mode 100644 src/bin/e_randr_serialization.c diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am index 880422ca2..6de49072f 100644 --- a/src/bin/Makefile.am +++ b/src/bin/Makefile.am @@ -276,6 +276,13 @@ e_popup.c \ e_powersave.c \ e_prefix.c \ e_randr.c \ +e_randr_serialization.c \ +e_randr_11.c \ +e_randr_11_serialization.c \ +e_randr_12.c \ +e_randr_12_output.c \ +e_randr_12_crtc.c \ +e_randr_12_serialization.c \ e_remember.c \ e_resist.c \ e_scale.c \ diff --git a/src/bin/e_config.c b/src/bin/e_config.c index 9ed39f08e..99b9e5f79 100644 --- a/src/bin/e_config.c +++ b/src/bin/e_config.c @@ -57,7 +57,7 @@ static E_Config_DD *_e_config_randr_serialized_setup_11_edd = NULL; static E_Config_DD *_e_config_randr_serialized_setup_12_edd = NULL; static E_Config_DD *_e_config_randr_serialized_output_policy_edd = NULL; static E_Config_DD *_e_config_randr_serialized_output_edd = NULL; -static E_Config_DD *_e_config_randr_serialized_mode_info_edd = NULL; +static E_Config_DD *_e_config_randr_mode_info_edd = NULL; static E_Config_DD *_e_config_randr_serialized_crtc_edd = NULL; @@ -555,7 +555,6 @@ e_config_init(void) #define T E_Randr_Serialized_Output_Policy #define D _e_config_randr_serialized_output_policy_edd E_CONFIG_VAL(D, T, name, STR); - E_CONFIG_VAL(D, T, name_length, INT); E_CONFIG_VAL(D, T, policy, INT); _e_config_randr_serialized_output_edd = E_CONFIG_DD_NEW("E_Randr_Serialized_Output", E_Randr_Serialized_Output); @@ -564,15 +563,14 @@ e_config_init(void) #define T E_Randr_Serialized_Output #define D _e_config_randr_serialized_output_edd E_CONFIG_VAL(D, T, name, STR); - E_CONFIG_VAL(D, T, name_length, INT); - E_CONFIG_VAL(D, T, edid_hash.hash, INT); E_CONFIG_VAL(D, T, backlight_level, DOUBLE); - _e_config_randr_serialized_mode_info_edd = E_CONFIG_DD_NEW("E_Randr_Serialized_Mode_Info", Ecore_X_Randr_Mode_Info); + _e_config_randr_mode_info_edd = E_CONFIG_DD_NEW("Ecore_X_Randr_Mode_Info", Ecore_X_Randr_Mode_Info); #undef T #undef D #define T Ecore_X_Randr_Mode_Info -#define D _e_config_randr_serialized_mode_info_edd +#define D _e_config_randr_mode_info_edd + E_CONFIG_VAL(D, T, xid, INT); E_CONFIG_VAL(D, T, width, INT); E_CONFIG_VAL(D, T, height, INT); E_CONFIG_VAL(D, T, dotClock, LL); @@ -592,11 +590,10 @@ e_config_init(void) #undef D #define T E_Randr_Serialized_Crtc #define D _e_config_randr_serialized_crtc_edd - E_CONFIG_LIST(D, T, serialized_outputs, _e_config_randr_serialized_output_edd); - E_CONFIG_SUB(D, T, mode_info, _e_config_randr_serialized_mode_info_edd); + E_CONFIG_LIST(D, T, outputs, _e_config_randr_serialized_output_edd); + E_CONFIG_SUB(D, T, mode_info, _e_config_randr_mode_info_edd); E_CONFIG_VAL(D, T, pos.x, INT); E_CONFIG_VAL(D, T, pos.y, INT); - EET_DATA_DESCRIPTOR_ADD_LIST_STRING(D, T, "Crtc_Possible_Outputs_Names", possible_outputs_names); E_CONFIG_VAL(D, T, orientation, INT); _e_config_randr_serialized_setup_12_edd = E_CONFIG_DD_NEW("E_Randr_Serialized_Setup_12", E_Randr_Serialized_Setup_12); @@ -605,8 +602,8 @@ e_config_init(void) #define T E_Randr_Serialized_Setup_12 #define D _e_config_randr_serialized_setup_12_edd E_CONFIG_VAL(D, T, timestamp, DOUBLE); - E_CONFIG_LIST(D, T, serialized_crtcs, _e_config_randr_serialized_crtc_edd); - E_CONFIG_LIST(D, T, serialized_edid_hashes, _e_config_randr_edid_hash_edd); + E_CONFIG_LIST(D, T, crtcs, _e_config_randr_serialized_crtc_edd); + E_CONFIG_LIST(D, T, edid_hashes, _e_config_randr_edid_hash_edd); _e_config_randr_serialized_setup_edd = E_CONFIG_DD_NEW("E_Randr_Serialized_Setup", E_Randr_Serialized_Setup); #undef T @@ -615,7 +612,7 @@ e_config_init(void) #define D _e_config_randr_serialized_setup_edd E_CONFIG_SUB(D, T, serialized_setup_11, _e_config_randr_serialized_setup_11_edd); E_CONFIG_LIST(D, T, serialized_setups_12, _e_config_randr_serialized_setup_12_edd); - E_CONFIG_LIST(D, T, serialized_outputs_policies, _e_config_randr_serialized_output_policy_edd); + E_CONFIG_LIST(D, T, outputs_policies, _e_config_randr_serialized_output_policy_edd); _e_config_edd = E_CONFIG_DD_NEW("E_Config", E_Config); #undef T @@ -936,7 +933,7 @@ e_config_shutdown(void) E_CONFIG_DD_FREE(_e_config_mime_icon_edd); E_CONFIG_DD_FREE(_e_config_syscon_action_edd); E_CONFIG_DD_FREE(_e_config_env_var_edd); - E_CONFIG_DD_FREE(_e_config_randr_serialized_setup_edd); + //E_CONFIG_DD_FREE(_e_config_randr_serialized_setup_edd); return 1; } @@ -1881,15 +1878,8 @@ _e_config_free(E_Config *ecf) E_Color_Class *cc; E_Path_Dir *epd; E_Remember *rem; - E_Randr_Serialized_Setup_12 *serialized_setup_12; - E_Randr_Serialized_Crtc *serialized_crtc; - E_Randr_Serialized_Output_Policy *serialized_output_policy; - E_Randr_Serialized_Output *serialized_output; - E_Randr_Edid_Hash *edid_hash; - char *output_name; E_Config_Env_Var *evr; - if (!ecf) return; EINA_LIST_FREE(ecf->modules, em) @@ -2039,44 +2029,8 @@ _e_config_free(E_Config *ecf) } if(ecf->randr_serialized_setup) { - free (ecf->randr_serialized_setup->serialized_setup_11); - if (ecf->randr_serialized_setup->serialized_setups_12) - { - EINA_LIST_FREE(ecf->randr_serialized_setup->serialized_setups_12, serialized_setup_12) - { - EINA_LIST_FREE(serialized_setup_12->serialized_crtcs, serialized_crtc) - { - if (!serialized_crtc) continue; - EINA_LIST_FREE(serialized_crtc->serialized_outputs, serialized_output) - { - if (!serialized_output) continue; - free(serialized_output->name); - free(serialized_output); - } - EINA_LIST_FREE(serialized_crtc->possible_outputs_names, output_name) - { - if (output_name) free(output_name); - } - if (serialized_crtc->mode_info.name) - free(serialized_crtc->mode_info.name); - free(serialized_crtc); - } - EINA_LIST_FREE(serialized_setup_12->serialized_edid_hashes, edid_hash) - { - if (edid_hash) free(edid_hash); - } - free(serialized_setup_12); - } - } - EINA_LIST_FREE(ecf->randr_serialized_setup->serialized_outputs_policies, serialized_output_policy) - { - if (!serialized_output_policy) continue; - free(serialized_output_policy->name); - free(serialized_output_policy); - } - free(ecf->randr_serialized_setup); + e_randr_serialized_setup_free(ecf->randr_serialized_setup); } - EINA_LIST_FREE(ecf->env_vars, evr) { if (evr->var) eina_stringshare_del(evr->var); diff --git a/src/bin/e_randr.c b/src/bin/e_randr.c index c6d916433..5f4cada8f 100644 --- a/src/bin/e_randr.c +++ b/src/bin/e_randr.c @@ -2,16 +2,15 @@ * vim:ts=8:sw=3:sts=8:expandtab:cino=>5n-3f0^-2{2 */ #include "e.h" +#include "e_randr_private.h" #define ECORE_X_RANDR_1_1 ((1 << 16) | 1) #define ECORE_X_RANDR_1_2 ((1 << 16) | 2) #define ECORE_X_RANDR_1_3 ((1 << 16) | 3) -#define Ecore_X_Randr_None 0 +#define Ecore_X_Randr_None 0 #define Ecore_X_Randr_Unset -1 -#define POLLINTERVAL 128 - /* * Save mechanism: * Single monitor: @@ -19,940 +18,104 @@ * * Multiple monitors: * - Use the EDID information to make sure we restore the right monitor. + * - Depend on the sequence in which the XIDs are returned provided by the X + * server. This means that relative indexes are used for setup store/restore. * - * TODO: - * -fix output policies above and left */ -//following macro namescheme follows cardinal relation -//1 : M -#define E_RANDR_NO_SCREEN_RET(ret) if (!e_randr_screen_info) \ - return ret -#define E_RANDR_NO_11_RET(ret) if (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_1) || !e_randr_screen_info->rrvd_info.randr_info_11) \ - return ret -#define E_RANDR_NO_12_RET(ret) if (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12) \ - return ret -#define E_RANDR_NO_CRTCS_RET(ret) if (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->crtcs) \ - return ret -#define E_RANDR_NO_OUTPUTS_RET(ret) if (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->outputs) \ - return ret -#define E_RANDR_NO_CRTC_RET(crtc, ret) if (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->crtcs || !crtc) \ - return ret -#define E_RANDR_NO_OUTPUT_RET(output, ret) if (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->outputs || !output) \ - return ret -#define E_RANDR_NO_MODE_RET(mode, ret) if (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->modes || !mode) \ - return ret -#define E_RANDR_NO_CRTC_OUTPUT_RET(crtc, output, ret) if (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->crtcs || !crtc || !e_randr_screen_info->rrvd_info.randr_info_12->outputs || !output) \ - return ret -#define E_RANDR_NO_CRTC_OUTPUT_MODE_RET(crtc, output, mode, ret) if (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->crtcs || !crtc || !e_randr_screen_info->rrvd_info.randr_info_12->outputs || !output || !e_randr_screen_info->rrvd_info.randr_info_12->modes || !mode) \ - return ret +static Eina_Bool _init(void); +static void _shutdown(void); +static void _screen_info_refresh(void); +static Eina_Bool _e_event_config_loaded_cb(void *data, int type, void *e); +static void _try_restore_configuration(void); +static void _event_listeners_add(void); +static void _event_listeners_remove(void); -#define E_RANDR_NO_11 (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_1) || !e_randr_screen_info->rrvd_info.randr_info_11) -#define E_RANDR_NO_12 (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12) -#define E_RANDR_NO_CRTCS (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->crtcs) -#define E_RANDR_NO_OUTPUTS (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->outputs) -#define E_RANDR_NO_MODES (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->modes) -#define E_RANDR_NO_CRTC(crtc) (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->crtcs || !crtc) -#define E_RANDR_NO_OUTPUT(output) (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->outputs || !output) -#define E_RANDR_NO_CRTC_OUTPUT(crtc, output) (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->crtcs || !crtc || !e_randr_screen_info->rrvd_info.randr_info_12->outputs || !output) -#define E_RANDR_NO_CRTC_OUTPUT_MODE(crtc, output, mode) (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->crtcs || !crtc || !e_randr_screen_info->rrvd_info.randr_info_12->outputs || !output || !e_randr_screen_info->rrvd_info.randr_info_12->modes || !mode) - -static Eina_Bool _e_randr_init(void); -static void _e_randr_shutdown(void); -static Eina_Bool _e_randr_screen_info_refresh(void); -static void _e_randr_event_listeners_add(void); -static void _e_randr_event_listeners_remove(void); -static Eina_Bool _e_randr_event_cb(void *data, int type, void *e); -static Eina_Bool _e_event_config_loaded_cb(void *data, int type, void *e); -static Eina_Bool _e_randr_x_poll_cb(void *data __UNUSED__); -static E_Randr_Screen_Info *_e_randr_screen_info_new(void); -static void _e_randr_screen_info_free(E_Randr_Screen_Info *screen_info); -static E_Randr_Screen_Info_11 *_e_randr_screen_info_11_new(void); -static Eina_Bool _e_randr_screen_info_11_set(void); -static void _e_randr_screen_info_11_free(E_Randr_Screen_Info_11 *screen_info_11); -static E_Randr_Screen_Info_12 *_e_randr_screen_info_12_new(void); -static Eina_Bool _e_randr_screen_info_12_set(E_Randr_Screen_Info_12 *screen_info_12); -static void _e_randr_screen_info_12_free(E_Randr_Screen_Info_12 *screen_info_12); -static E_Randr_Output_Info *_e_randr_output_info_new(int nrequested); -static void _e_randr_output_info_free(E_Randr_Output_Info *output_info); -static E_Randr_Crtc_Info *_e_randr_crtc_info_new(int nrequested); -static void _e_randr_crtc_info_free(E_Randr_Crtc_Info *crtc_info); -static Eina_Bool _e_randr_screen_outputs_init(void); -static Eina_Bool _e_randr_screen_crtcs_init(void); - -static Eina_Bool _e_randr_try_restore_11(E_Randr_Screen_Info_11 *si_11); -static Eina_Bool _e_randr_try_restore_12(E_Randr_Screen_Info_12 *si_12); -void _e_randr_restore_12_policies(E_Randr_Screen_Info_12 *si_12); -static Eina_Bool _e_randr_output_modes_add(E_Randr_Output_Info *output_info); -static void _e_randr_notify_crtc_mode_change(E_Randr_Crtc_Info *crtc_info); -static void _e_randr_notify_output_change(E_Randr_Output_Info *output_info); -static Ecore_X_Randr_Mode_Info *_e_randr_mode_info_get(Ecore_X_Randr_Mode mode); -static E_Randr_Crtc_Info *_e_randr_crtc_info_get(Ecore_X_Randr_Crtc crtc); -static E_Randr_Output_Info *_e_randr_output_info_get(Ecore_X_Randr_Output output); -static void _e_randr_output_info_set(E_Randr_Output_Info *output_info); -static void _e_randr_crtc_info_set(E_Randr_Crtc_Info *crtc_info); -static const E_Randr_Crtc_Info *_e_randr_policy_crtc_get(E_Randr_Crtc_Info *but, E_Randr_Crtc_Info *hint, Ecore_X_Randr_Output_Policy policy); -static Ecore_X_Randr_Output *_e_randr_outputs_to_array(Eina_List *outputs_info); -static Eina_Bool _e_randr_try_enable_output(E_Randr_Output_Info *output_info, Eina_Bool force); -static void _e_randr_crtcs_possible_output_update(E_Randr_Output_Info *output_info); -static void _e_randr_crtc_outputs_refs_update(E_Randr_Crtc_Info *crtc_info); -static Eina_Bool _e_randr_crtc_move_policy(E_Randr_Crtc_Info *new_crtc); -//static int _crtcs_size_sort_cb(const void *d1, const void *d2); -static int _outputs_size_sort_cb(const void *d1, const void *d2); -static int _modes_size_sort_cb(const void *d1, const void *d2); -static Eina_List *_e_randr_outputs_common_modes_get(Eina_List *outputs, Ecore_X_Randr_Mode_Info *max_size_mode); -static Ecore_X_Randr_Mode_Info *_e_randr_outputs_common_mode_max_get(Eina_List *outputs, Ecore_X_Randr_Mode_Info *max_size_mode); -static Ecore_X_Randr_Mode_Info *_e_randr_mode_geo_identical_find(Eina_List *modes, Ecore_X_Randr_Mode_Info *mode); -static Eina_Bool _e_randr_crtc_mode_intersects_crtcs(E_Randr_Crtc_Info *crtc_info, Ecore_X_Randr_Mode_Info *mode); -static Eina_Bool _e_randr_crtc_outputs_mode_max_set(E_Randr_Crtc_Info *crtc_info); -static Eina_Bool _e_randr_crtcs_clone_crtc_removed(E_Randr_Crtc_Info *former_clone); -static void _e_randr_screen_primary_output_assign(E_Randr_Output_Info *removed); -static void _e_randr_output_info_hw_info_set(E_Randr_Output_Info *output_info); -static void _e_randr_output_hw_info_free(E_Randr_Output_Info *output_info); -static Eina_Bool _e_randr_outputs_are_clones(E_Randr_Output_Info *output_info, Eina_List *outputs); - -EAPI E_Randr_Screen_Info * e_randr_screen_info = NULL; -static Eina_List *_e_randr_event_handlers = NULL; -static Ecore_Poller *poller = NULL; +EAPI E_Randr_Screen_Info e_randr_screen_info; +static Eina_List *_event_handlers = NULL; EINTERN Eina_Bool e_randr_init(void) { - return _e_randr_init(); + return _init(); } EINTERN int e_randr_shutdown(void) { - _e_randr_shutdown(); + _shutdown(); return 1; } -EAPI Eina_Bool +EAPI void e_randr_screen_info_refresh(void) { - return _e_randr_screen_info_refresh(); + _screen_info_refresh(); } static Eina_Bool -_e_randr_init(void) +_init(void) { - EINA_SAFETY_ON_FALSE_RETURN_VAL(e_randr_screen_info_refresh(), EINA_FALSE); - _e_randr_event_listeners_add(); + e_randr_screen_info_refresh(); + _event_listeners_add(); + + _try_restore_configuration(); + + if (e_randr_screen_info.randr_version >= ECORE_X_RANDR_1_2) + { + _12_policies_restore(); + } + return EINA_TRUE; } static void -_e_randr_shutdown(void) +_shutdown(void) { - _e_randr_screen_info_free(e_randr_screen_info); + if (e_randr_screen_info.randr_version == ECORE_X_RANDR_1_1) + { + _11_screen_info_free(e_randr_screen_info.rrvd_info.randr_info_11); + e_randr_screen_info.rrvd_info.randr_info_11 = NULL; + } + else if (e_randr_screen_info.randr_version >= ECORE_X_RANDR_1_2) + { + _12_screen_info_free(e_randr_screen_info.rrvd_info.randr_info_12); + e_randr_screen_info.rrvd_info.randr_info_12 = NULL; + } + _event_listeners_remove(); } -static Eina_Bool -_e_randr_screen_info_refresh(void) + +/** + * @return EINA_TRUE if info could be refreshed, else EINA_FALSE + */ +static void +_screen_info_refresh(void) { - int n; Ecore_X_Window *roots; Ecore_X_Window root; + int n; - if (e_randr_screen_info) - _e_randr_screen_info_free(e_randr_screen_info); + EINA_SAFETY_ON_FALSE_RETURN(ecore_x_randr_query()); - if (!(roots = ecore_x_window_root_list(&n))) return EINA_FALSE; + if (!(roots = ecore_x_window_root_list(&n))) return; /* first (and only) root window */ root = roots[0]; free(roots); - if (!ecore_x_randr_query()) - goto e_randr_screen_info_refresh_fail; - if (!(e_randr_screen_info = _e_randr_screen_info_new())) - goto e_randr_screen_info_refresh_fail_free_screen; + e_randr_screen_info.randr_version = ecore_x_randr_version_get(); + e_randr_screen_info.root = root; + e_randr_screen_info.rrvd_info.randr_info_11 = NULL; - e_randr_screen_info->randr_version = ecore_x_randr_version_get(); - e_randr_screen_info->root = root; - - if (e_randr_screen_info->randr_version == ECORE_X_RANDR_1_1) + // Value set/retrieval helper functions + if (e_randr_screen_info.randr_version == ECORE_X_RANDR_1_1) { - if (!(e_randr_screen_info->rrvd_info.randr_info_11 = _e_randr_screen_info_11_new())) - goto e_randr_screen_info_refresh_fail_free_screen; - _e_randr_screen_info_11_set(); + _11_screen_info_refresh(); } - else if (e_randr_screen_info->randr_version >= ECORE_X_RANDR_1_2) + else if (e_randr_screen_info.randr_version >= ECORE_X_RANDR_1_2) { - if (!(e_randr_screen_info->rrvd_info.randr_info_12 = _e_randr_screen_info_12_new())) - goto e_randr_screen_info_refresh_fail_free_screen; - _e_randr_screen_info_12_set(e_randr_screen_info->rrvd_info.randr_info_12); - if (!_e_randr_screen_outputs_init() - || !_e_randr_screen_crtcs_init()) - goto e_randr_screen_info_refresh_fail_free_screen; - _e_randr_screen_primary_output_assign(NULL); - //also restore stored policies - _e_randr_restore_12_policies(e_randr_screen_info->rrvd_info.randr_info_12); + _12_screen_info_refresh(); } - else - goto e_randr_screen_info_refresh_fail_free_screen; - - return EINA_TRUE; - -e_randr_screen_info_refresh_fail_free_screen: - if (e_randr_screen_info) - _e_randr_screen_info_free(e_randr_screen_info); -e_randr_screen_info_refresh_fail: - return EINA_FALSE; -} - -/** - * @param nrequeste - * @return Instance of E_Randr_Screen_Info or if memory couldn't be - * allocated NULL. - */ -static E_Randr_Screen_Info * -_e_randr_screen_info_new(void) -{ - E_Randr_Screen_Info *ret = NULL; - E_Randr_Screen_Info default_info = - { - .root = Ecore_X_Randr_Unset, - .randr_version = Ecore_X_Randr_None, - .rrvd_info.randr_info_11 = NULL - }; - - if (!(ret = malloc(sizeof(E_Randr_Screen_Info)))) return NULL; - - memcpy(ret, &default_info, sizeof(default_info)); - - return ret; -} - -/** - * @param screen_info the screen info to free. - */ -static void -_e_randr_screen_info_free(E_Randr_Screen_Info *screen_info) -{ - if ((!screen_info) || !(screen_info->rrvd_info.randr_info_11)) return; - switch (e_randr_screen_info->randr_version) - { - case ECORE_X_RANDR_1_1: - _e_randr_screen_info_11_free(screen_info->rrvd_info.randr_info_11); - break; - - case ECORE_X_RANDR_1_2: - case ECORE_X_RANDR_1_3: - _e_randr_screen_info_12_free(screen_info->rrvd_info.randr_info_12); - break; - } - free(screen_info); - screen_info = NULL; -} - -/** - * @return array of E_Randr_Screen_Info_11 elements, or in case not all could - * be created or parameter 'nrequested'==0, NULL - */ -static E_Randr_Screen_Info_11 * -_e_randr_screen_info_11_new(void) -{ - E_Randr_Screen_Info_11 *ret = NULL; - static const E_Randr_Screen_Info_11 default_info = - { - .sizes = NULL, - .csize_index = Ecore_X_Randr_Unset, - .corientation = Ecore_X_Randr_Unset, - .orientations = Ecore_X_Randr_Unset, - .rates = NULL, - .current_rate = Ecore_X_Randr_Unset - }; - - if (!(ret = malloc(sizeof(E_Randr_Screen_Info_11)))) return NULL; - - ret = memcpy(ret, &default_info, sizeof(default_info)); - - return ret; -} - -/** - * @param screen_info the screen info to be freed. - */ -static void -_e_randr_screen_info_11_free(E_Randr_Screen_Info_11 *screen_info) -{ - if (!screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_1)) - return; - - if (screen_info->sizes) - { - free(eina_list_nth(screen_info->sizes, 0)); - eina_list_free(screen_info->sizes); - screen_info->sizes = NULL; - } - if (screen_info->rates) - { - /* this may be leaking, but at least it will be valid */ - eina_list_free(eina_list_nth(screen_info->rates, 0)); - eina_list_free(screen_info->rates); - screen_info->rates = NULL; - } - free(screen_info); - screen_info = NULL; -} - -/** - * @return array of E_Randr_Screen_Info_12 elements, or in case not all could - * be created or parameter 'nrequested'==0, NULL - */ -static E_Randr_Screen_Info_12 * -_e_randr_screen_info_12_new(void) -{ - E_Randr_Screen_Info_12 *ret = NULL; - static const E_Randr_Screen_Info_12 default_info = - { - .min_size = {Ecore_X_Randr_Unset, Ecore_X_Randr_Unset}, - .max_size = {Ecore_X_Randr_Unset, Ecore_X_Randr_Unset}, - .current_size = {Ecore_X_Randr_Unset, Ecore_X_Randr_Unset}, - .crtcs = NULL, - .outputs = NULL, - .primary_output = NULL, - .alignment = ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE - }; - - if (!(ret = malloc(sizeof(E_Randr_Screen_Info_12)))) return NULL; - ret = memcpy(ret, &default_info, sizeof(default_info)); - - return ret; -} - -static Eina_Bool -_e_randr_screen_info_12_set(E_Randr_Screen_Info_12 *screen_info) -{ - E_RANDR_NO_12_RET(EINA_FALSE); - - ecore_x_randr_screen_size_range_get(e_randr_screen_info->root, - &screen_info->min_size.width, - &screen_info->min_size.height, - &screen_info->max_size.width, - &screen_info->max_size.height); - ecore_x_randr_screen_current_size_get(e_randr_screen_info->root, - &screen_info->current_size.width, - &screen_info->current_size.height, - NULL, NULL); - - return EINA_TRUE; -} - -static Eina_Bool -_e_randr_screen_info_11_set(void) -{ - E_RANDR_NO_11_RET(EINA_FALSE); - - E_Randr_Screen_Info_11 *screen_info_11 = e_randr_screen_info->rrvd_info.randr_info_11; - Ecore_X_Randr_Screen_Size_MM *sizes = NULL; - Ecore_X_Randr_Refresh_Rate *rates = NULL; - Eina_List *rates_list; - int i, j, nsizes, nrates; - - if (!(sizes = ecore_x_randr_screen_primary_output_sizes_get(e_randr_screen_info->root, &nsizes))) - return EINA_FALSE; - for (i = 0; i < nsizes; i++) - if (!(screen_info_11->sizes = eina_list_append(screen_info_11->sizes, &sizes[i]))) - goto _e_randr_screen_info_11_fill_fail_sizes; - ecore_x_randr_screen_primary_output_current_size_get(e_randr_screen_info->root, NULL, NULL, NULL, NULL, &(screen_info_11->csize_index)); - screen_info_11->corientation = ecore_x_randr_screen_primary_output_orientation_get(e_randr_screen_info->root); - screen_info_11->orientations = ecore_x_randr_screen_primary_output_orientations_get(e_randr_screen_info->root); - for (i = 0; i < nsizes; i++) - { - rates_list = NULL; - if (!(rates = ecore_x_randr_screen_primary_output_refresh_rates_get(e_randr_screen_info->root, i, &nrates))) - return EINA_FALSE; - for (j = 0; j < nrates; j++) - if (!(rates_list = eina_list_append(rates_list, &rates[j]))) - goto _e_randr_screen_info_11_fill_fail_rates_list; - if (!(screen_info_11->rates = eina_list_append(screen_info_11->rates, rates_list))) - goto _e_randr_screen_info_11_fill_fail_rates; - } - screen_info_11->current_rate = ecore_x_randr_screen_primary_output_current_refresh_rate_get(e_randr_screen_info->root); - - return EINA_TRUE; - -_e_randr_screen_info_11_fill_fail_rates_list: - eina_list_free(rates_list); -_e_randr_screen_info_11_fill_fail_rates: - free(rates); -_e_randr_screen_info_11_fill_fail_sizes: - free(sizes); - free(screen_info_11); - return EINA_FALSE; -} - -/** - * @param screen_info the screen info to be freed. - */ -static void -_e_randr_screen_info_12_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; - - if (!screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2)) return; - - if (e_randr_screen_info->randr_version >= ECORE_X_RANDR_1_2 && screen_info->crtcs) - { - EINA_LIST_FREE (screen_info->crtcs, crtc_info) - _e_randr_crtc_info_free(crtc_info); - free(eina_list_nth(screen_info->crtcs, 0)); - } - - if (e_randr_screen_info->randr_version >= ECORE_X_RANDR_1_2 && screen_info->outputs) - { - EINA_LIST_FREE (screen_info->outputs, output_info) - _e_randr_output_info_free(output_info); - free(eina_list_nth(screen_info->outputs, 0)); - } - - if (e_randr_screen_info->randr_version >= ECORE_X_RANDR_1_2 && screen_info->modes) - { - EINA_LIST_FREE (screen_info->modes, mode_info) - ecore_x_randr_mode_info_free(mode_info); - } - - _e_randr_event_listeners_remove(); - - free (screen_info); - screen_info = NULL; -} - -/** - * @brief allocates structs with and fills them with default values. The - * returned pointer is allocated as one chunk of data since it won't change. - * @param nrequested number of E_Randr_Crtc_Info to be created - * @return array of E_Randr_Crtc_Info elements, or in case not all could - * be created or parameter 'nrequested'==0, NULL - */ -static E_Randr_Crtc_Info * -_e_randr_crtc_info_new(int nrequested) -{ - E_Randr_Crtc_Info *ret = NULL; - static E_Randr_Crtc_Info default_info = - { - .xid = Ecore_X_Randr_Unset, - .geometry = {Ecore_X_Randr_Unset, Ecore_X_Randr_Unset, Ecore_X_Randr_Unset, Ecore_X_Randr_Unset}, - .panning = {Ecore_X_Randr_Unset, Ecore_X_Randr_Unset, Ecore_X_Randr_Unset, Ecore_X_Randr_Unset}, - .tracking = {Ecore_X_Randr_Unset, Ecore_X_Randr_Unset, Ecore_X_Randr_Unset, Ecore_X_Randr_Unset}, - .border = {Ecore_X_Randr_Unset, Ecore_X_Randr_Unset, Ecore_X_Randr_Unset, Ecore_X_Randr_Unset}, - .current_orientation = ECORE_X_RANDR_ORIENTATION_ROT_0, - .orientations = Ecore_X_Randr_Unset, - .gamma_ramps = NULL, - .gamma_ramp_size = Ecore_X_Randr_Unset, - .outputs = NULL, - .possible_outputs = NULL - }; - - if (!(ret = malloc(sizeof(E_Randr_Crtc_Info) * nrequested))) return NULL; - - while (nrequested > 0) - { - memcpy(&ret[--nrequested], &default_info, sizeof(default_info)); - } - - return ret; -} - -/** - * @param crtc_info the crtc info to be freed. - */ -static void -_e_randr_crtc_info_free(E_Randr_Crtc_Info *crtc_info) -{ - if (!crtc_info) return; - - 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; - } -} - -/** - * @brief allocates structs with and fills them with default values. The - * returned pointer is allocated as one chunk of data since it won't change. - * @param nrequested number of E_Randr_Output_Info to be created - * @return E_Randr_Output_Info element, or it could not be - * created, NULL - */ -static E_Randr_Output_Info * -_e_randr_output_info_new(int nrequested) -{ - E_Randr_Output_Info *ret = NULL; - static E_Randr_Output_Info default_info = - { - .xid = Ecore_X_Randr_Unset, - .name = NULL, - .crtc = NULL, - .possible_crtcs = NULL, - .preferred_modes = NULL, - .max_backlight = Ecore_X_Randr_Unset, - .backlight_level = 0.0, - .edid = NULL, - .edid_length = 0, - .size_mm = {Ecore_X_Randr_Unset, Ecore_X_Randr_Unset}, - .wired_clones = NULL, - .signalformats = Ecore_X_Randr_Unset, - .signalformat = Ecore_X_Randr_Unset, - .connector_number = Ecore_X_Randr_Unset, - .connector_type = Ecore_X_Randr_Unset, - .connection_status = ECORE_X_RANDR_CONNECTION_STATUS_DISCONNECTED, - .subpixel_order = Ecore_X_Randr_Unset, - .compatible_outputs = NULL, - .policy = ECORE_X_RANDR_OUTPUT_POLICY_NONE - }; - - if (!(ret = malloc(sizeof(E_Randr_Output_Info) * nrequested))) return NULL; - - while (nrequested > 0) - { - memcpy(&ret[--nrequested], &default_info, sizeof(default_info)); - } - - return ret; -} - -/* - * removes all traces of an output within the data. - * @param output_info the output info to be freed. - */ -static void -_e_randr_output_info_free(E_Randr_Output_Info *output_info) -{ - Eina_List *iter; - E_Randr_Crtc_Info *crtc_info; - - if (!output_info) return; - if (output_info->name) - { - free(output_info->name); - output_info->name = NULL; - } - _e_randr_output_hw_info_free(output_info); - - EINA_LIST_FOREACH (e_randr_screen_info->rrvd_info.randr_info_12->crtcs, iter, crtc_info) - { - crtc_info->outputs = eina_list_remove(crtc_info->outputs, output_info); - } -} - -static void -_e_randr_output_info_set(E_Randr_Output_Info *output_info) -{ - if (E_RANDR_NO_12 || !output_info) return; - - output_info->name = ecore_x_randr_output_name_get(e_randr_screen_info->root, output_info->xid, &output_info->name_length); - output_info->connection_status = ecore_x_randr_output_connection_status_get(e_randr_screen_info->root, output_info->xid); -} - -/* - * fills a given crtc_info using its xid with - * - geometry data (x,y,w,h) - * - used outputs structs - * - possible outputs structs - * - mode - * - connection status - * - orientation - */ -static void -_e_randr_crtc_info_set(E_Randr_Crtc_Info *crtc_info) -{ - Ecore_X_Randr_Mode mode = 0; - fprintf(stderr, "E_RANDR: Filling CRTC %d (%p)\n", crtc_info->xid, crtc_info); - if (E_RANDR_NO_12 || !crtc_info) return; - - //get references to used and possible E_Randr_Output_Info structs - _e_randr_crtc_outputs_refs_update(crtc_info); - - 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); - mode = ecore_x_randr_crtc_mode_get(e_randr_screen_info->root, crtc_info->xid); - crtc_info->current_mode = _e_randr_mode_info_get(mode); - fprintf(stderr, "E_RANDR:\t CRTC %x apparently is in mode %x, trying to find it in the list of modes..\n", crtc_info->xid, mode); - if (crtc_info->current_mode) - fprintf(stderr, "E_RANDR:\t\t found CRTC %d in mode %d\n", crtc_info->xid, crtc_info->current_mode->xid); - crtc_info->current_orientation = ecore_x_randr_crtc_orientation_get(e_randr_screen_info->root, crtc_info->xid); - if (crtc_info->outputs_common_modes) - { - eina_list_free(crtc_info->outputs_common_modes); - crtc_info->outputs_common_modes = NULL; - } - crtc_info->outputs_common_modes = _e_randr_outputs_common_modes_get(crtc_info->outputs, NULL); -} - -/* - * looks up modes supported by an output and adds them - if they are not already - * known by - to the screen's information struct ant the output_info itself - */ -static Eina_Bool -_e_randr_output_modes_add(E_Randr_Output_Info *output_info) -{ - Ecore_X_Randr_Mode *modes; - Ecore_X_Randr_Mode_Info *mode_info; - int nmodes, npreferred; - Eina_List *iter; - Eina_Bool added_yet = EINA_FALSE; - - if (E_RANDR_NO_12 || !(modes = ecore_x_randr_output_modes_get(e_randr_screen_info->root, output_info->xid, &nmodes, &npreferred))) return EINA_FALSE; - - //In case the monitor does not have any preferred mode at all - if (nmodes > 0 && npreferred == 0) npreferred = 1; - - while (--nmodes >= 0) - { - added_yet = EINA_FALSE; - EINA_LIST_FOREACH (e_randr_screen_info->rrvd_info.randr_info_12->modes, iter, mode_info) - { - if (mode_info && mode_info->xid == modes[nmodes]) - { - added_yet = EINA_TRUE; - break; - } - } - if (!added_yet) - { - mode_info = ecore_x_randr_mode_info_get(e_randr_screen_info->root, modes[nmodes]); - e_randr_screen_info->rrvd_info.randr_info_12->modes = eina_list_prepend(e_randr_screen_info->rrvd_info.randr_info_12->modes, mode_info); - } - output_info->modes = eina_list_prepend(output_info->modes, mode_info); - if (nmodes < npreferred) output_info->preferred_modes = eina_list_prepend(output_info->preferred_modes, mode_info); - } - - free(modes); - return EINA_TRUE; -} - -static Eina_Bool -_e_randr_screen_crtcs_init(void) -{ - Ecore_X_Randr_Crtc *crtcs = NULL; - E_Randr_Crtc_Info *crtcs_info = NULL, *crtc = NULL; - int i, ncrtcs; - - if (E_RANDR_NO_12 || !(crtcs = ecore_x_randr_crtcs_get(e_randr_screen_info->root, &ncrtcs))) return EINA_FALSE; - - if (!(crtcs_info = _e_randr_crtc_info_new(ncrtcs))) goto ecore_x_randr_screen_crtcs_init_fail_free_crtcs; - for (i = 0; i < ncrtcs; i++) - { - fprintf (stderr, "E_RANDR: filling %d/%d (%d)\n", (i + 1), ncrtcs, crtcs[i]); - crtcs_info[i].xid = crtcs[i]; - _e_randr_crtc_info_set(&crtcs_info[i]); - if (!(e_randr_screen_info->rrvd_info.randr_info_12->crtcs = eina_list_append(e_randr_screen_info->rrvd_info.randr_info_12->crtcs, &crtcs_info[i]))) break; - } - if (i == ncrtcs) - { - //successfully initialized crtcs! - free (crtcs); - return EINA_TRUE; - } - EINA_LIST_FREE (e_randr_screen_info->rrvd_info.randr_info_12->crtcs, crtc) - _e_randr_crtc_info_free(crtc); - if (e_randr_screen_info->rrvd_info.randr_info_12->crtcs) - { - free(eina_list_nth(e_randr_screen_info->rrvd_info.randr_info_12->crtcs, 0)); - } - -ecore_x_randr_screen_crtcs_init_fail_free_crtcs: - free(crtcs); - return EINA_FALSE; -} - -static Eina_Bool -_e_randr_screen_outputs_init(void) -{ - Ecore_X_Randr_Output *outputs; - E_Randr_Output_Info *outputs_info = NULL, *output_info = NULL; - int noutputs = 0; - if (E_RANDR_NO_12 || !(outputs = ecore_x_randr_outputs_get(e_randr_screen_info->root, &noutputs))) return EINA_FALSE; - - if (!(outputs_info = _e_randr_output_info_new(noutputs))) goto _e_randr_screen_outputs_init_fail_free_outputs; - while (--noutputs >= 0) - { - outputs_info[noutputs].xid = outputs[noutputs]; - _e_randr_output_info_set(&outputs_info[noutputs]); - if (outputs_info[noutputs].connection_status == ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED) - _e_randr_output_info_hw_info_set(&outputs_info[noutputs]); - - if (!(e_randr_screen_info->rrvd_info.randr_info_12->outputs = eina_list_append(e_randr_screen_info->rrvd_info.randr_info_12->outputs, &outputs_info[noutputs]))) goto _e_randr_screen_outputs_init_fail_free_outputs_list; - } - - free(outputs); - return EINA_TRUE; - -_e_randr_screen_outputs_init_fail_free_outputs_list: - if (e_randr_screen_info->rrvd_info.randr_info_12->outputs) - { - EINA_LIST_FREE (e_randr_screen_info->rrvd_info.randr_info_12->outputs, output_info) - free(output_info); - } -_e_randr_screen_outputs_init_fail_free_outputs: - free(outputs); - return EINA_FALSE; -} - -static Ecore_X_Randr_Mode_Info * -_e_randr_mode_info_get(Ecore_X_Randr_Mode mode) -{ - Eina_List *iter; - Ecore_X_Randr_Mode_Info *mode_info; - - E_RANDR_NO_MODE_RET(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; -} - -static E_Randr_Output_Info * -_e_randr_output_info_get(Ecore_X_Randr_Output output) -{ - Eina_List *iter; - E_Randr_Output_Info *output_info; - - E_RANDR_NO_OUTPUTS_RET(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; -} - -static E_Randr_Crtc_Info * -_e_randr_crtc_info_get(Ecore_X_Randr_Crtc crtc) -{ - Eina_List *iter; - E_Randr_Crtc_Info *crtc_info; - - E_RANDR_NO_CRTCS_RET(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; -} - -static Eina_Bool -_e_randr_event_cb(void *data __UNUSED__, int type, void *ev) -{ - E_Randr_Crtc_Info *crtc_info; - Ecore_X_Randr_Mode_Info *mode_info; - Eina_Bool enabled = EINA_FALSE; - - if (!e_randr_screen_info) return ECORE_CALLBACK_RENEW; - - if (type == ECORE_X_EVENT_RANDR_CRTC_CHANGE) - { - Ecore_X_Event_Randr_Crtc_Change *event = (Ecore_X_Event_Randr_Crtc_Change *)ev; - /* available information: - struct _Ecore_X_Event_Randr_Crtc_Change - { - 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; - }; - */ - crtc_info = _e_randr_crtc_info_get(event->crtc); - if (!crtc_info) return ECORE_CALLBACK_RENEW; - - // Update CRTC's information (Output(s), (Common) Mode(s), etc.) - _e_randr_crtc_info_set(crtc_info); - - // Get mode info of set mode - mode_info = _e_randr_mode_info_get(event->mode); - - fprintf(stderr, "E_RANDR: CRTC %x was set to mode %x.\n", event->crtc, event->mode); - - if (event->mode != Ecore_X_Randr_None) - { - //switched (on) - if(!crtc_info->outputs_common_modes) - fprintf(stderr, "E_RANDR: Though this monitor was switched on, no outputs are known to be connected to CRTC %x. Therefore no common modes available.\n", crtc_info->xid); - if ((crtc_info->current_mode != mode_info)) - { - crtc_info->current_mode = mode_info; - _e_randr_notify_crtc_mode_change(crtc_info); - } - else - crtc_info->current_mode = _e_randr_mode_info_get(event->mode); - crtc_info->current_orientation = event->orientation; - crtc_info->geometry.x = event->geo.x; - crtc_info->geometry.y = event->geo.y; - crtc_info->geometry.w = event->geo.w; - crtc_info->geometry.h = event->geo.h; - //update screensize if necessary - e_randr_screen_info->rrvd_info.randr_info_12->current_size.width = MAX((event->geo.x + event->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((event->geo.y + event->geo.h), e_randr_screen_info->rrvd_info.randr_info_12->current_size.height); - } - else - { - //set the max mode common amongst outputs - _e_randr_crtcs_clone_crtc_removed(crtc_info); - - //disabled - crtc_info->current_orientation = event->orientation; - crtc_info->geometry.x = 0; - crtc_info->geometry.y = 0; - crtc_info->geometry.w = 0; - crtc_info->geometry.h = 0; - crtc_info->current_mode = NULL; - if (crtc_info->outputs) - { - eina_list_free(crtc_info->outputs); - crtc_info->outputs = NULL; - } - - //update screensize of necessary - ecore_x_randr_screen_reset(e_randr_screen_info->root); - ecore_x_randr_screen_current_size_get(e_randr_screen_info->root, &e_randr_screen_info->rrvd_info.randr_info_12->current_size.width, &e_randr_screen_info->rrvd_info.randr_info_12->current_size.height, NULL, NULL); - } - } - else if (type == ECORE_X_EVENT_RANDR_OUTPUT_CHANGE) - { - Ecore_X_Event_Randr_Output_Change *event = ev; - E_Randr_Output_Info *output_info = NULL; - /* available information: - struct _Ecore_X_Event_Randr_Output_Change - { - 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; - }; - */ - fprintf(stderr, "E_RANDR: Output connected!: \n" - "E_RANDR: relative to win: %x\n" - "E_RANDR: output (xid): %x\n" - "E_RANDR: used by crtc (xid): %x\n" - "E_RANDR: mode: %x\n" - "E_RANDR: orientation: %d\n" - "E_RANDR: connection state: %d (connected = %d, disconnected = %d, unknown = %d)\n" - "E_RANDR: subpixel_order: %d\n", - event->win, event->output, event->crtc, event->mode, event->orientation, event->connection, ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED, ECORE_X_RANDR_CONNECTION_STATUS_DISCONNECTED, ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN, event->subpixel_order); - - output_info = _e_randr_output_info_get(event->output); - if (!output_info) return ECORE_CALLBACK_RENEW; - - if ((output_info->crtc = _e_randr_crtc_info_get(event->crtc))) - { - if (!eina_list_data_find(output_info->crtc->outputs, output_info)) - output_info->crtc->outputs = eina_list_append(output_info->crtc->outputs, output_info); - //update the list of common modes for the crtc's connected outputs - if (output_info->crtc->outputs_common_modes) - { - eina_list_free(output_info->crtc->outputs_common_modes); - output_info->crtc->outputs_common_modes = NULL; - } - output_info->crtc->outputs_common_modes = _e_randr_outputs_common_modes_get(output_info->crtc->outputs, NULL); - } - - output_info->connection_status = event->connection; - output_info->subpixel_order = event->subpixel_order; - - if (event->connection == ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED) - { - if (event->crtc) - output_info->crtc = _e_randr_crtc_info_get(event->crtc); - - if (output_info && !output_info->crtc && (event->crtc == Ecore_X_Randr_None) && (event->mode == Ecore_X_Randr_None)) - { - //Monitor was attached! - _e_randr_output_info_hw_info_set(output_info); - //make the crtcs aware of their possibly new output - _e_randr_crtcs_possible_output_update(output_info); - - if (output_info->policy != ECORE_X_RANDR_OUTPUT_POLICY_NONE) - enabled = _e_randr_try_enable_output(output_info, EINA_FALSE); //maybe give a success message? - fprintf(stderr, "E_RANDR: Output %d %s.", output_info->xid, (enabled ? "was enabled sucessfully" : "could not be enabled")); - } - _e_randr_notify_output_change(output_info); - } - else if (event->connection == ECORE_X_RANDR_CONNECTION_STATUS_DISCONNECTED) - { - if (output_info->crtc) - { - //remove output from CRTC - output_info->crtc->outputs = eina_list_remove(output_info->crtc->outputs, output_info); - if (eina_list_count(output_info->crtc->outputs) == 0) - output_info->crtc->outputs = NULL; - - if (output_info->crtc->current_mode) - { - //in case this output was enabled on some CRTC - 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); - //crop the screen of course. - ecore_x_randr_screen_reset(e_randr_screen_info->root); - } - else - _e_randr_crtc_outputs_mode_max_set(output_info->crtc); - } - - //reset assigned CRTC - output_info->crtc = NULL; - if (output_info == e_randr_screen_info->rrvd_info.randr_info_12->primary_output) - _e_randr_screen_primary_output_assign(output_info); - //let's try to get a proper config for the new setup and crop the - //screen afterwards. - /* - if ((restore_info = _e_randr_config_find_suiting_config_12())) - { - //in case we didn't have, init it anyway... - //_e_randr_config_enable_12(restore_info); - } - */ - } - _e_randr_notify_output_change(output_info); - _e_randr_output_hw_info_free(output_info); - } - } - else if (type == ECORE_X_EVENT_RANDR_OUTPUT_PROPERTY_NOTIFY) - { - //Ecore_X_Event_Randr_Output_Property_Notify *event = (Ecore_X_Event_Randr_Output_Property_Notify*) ev; - /* available information: - struct _Ecore_X_Event_Randr_Output_Property_Notify - { - Ecore_X_Window win; - Ecore_X_Randr_Output output; - Ecore_X_Atom property; - Ecore_X_Time time; - Ecore_X_Randr_Property_Change state; - }; - */ - } - e_randr_try_restore_configuration(e_randr_screen_info); - return ECORE_CALLBACK_RENEW; -} - -static Eina_Bool -_e_randr_x_poll_cb(void *data __UNUSED__) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(e_randr_screen_info, ECORE_CALLBACK_CANCEL); - - ecore_x_randr_screen_primary_output_orientations_get(e_randr_screen_info->root); - - return ECORE_CALLBACK_RENEW; } static Eina_Bool @@ -960,1463 +123,45 @@ _e_event_config_loaded_cb(void *data __UNUSED__, int type, void *ev __UNUSED__) { if (type != E_EVENT_CONFIG_LOADED) return EINA_TRUE; - e_randr_try_restore_configuration(e_randr_screen_info); + _try_restore_configuration(); return EINA_FALSE; } -static void -_e_randr_event_listeners_add(void) + static void +_event_listeners_add(void) { - if (E_RANDR_NO_12) return; - ecore_x_randr_events_select(e_randr_screen_info->root, EINA_TRUE); - _e_randr_event_handlers = eina_list_append(_e_randr_event_handlers, ecore_event_handler_add(ECORE_X_EVENT_RANDR_CRTC_CHANGE, _e_randr_event_cb, NULL)); - _e_randr_event_handlers = eina_list_append(_e_randr_event_handlers, ecore_event_handler_add(ECORE_X_EVENT_RANDR_OUTPUT_CHANGE, _e_randr_event_cb, NULL)); - _e_randr_event_handlers = eina_list_append(_e_randr_event_handlers, ecore_event_handler_add(ECORE_X_EVENT_RANDR_OUTPUT_PROPERTY_NOTIFY, _e_randr_event_cb, NULL)); - _e_randr_event_handlers = eina_list_append(_e_randr_event_handlers, ecore_event_handler_add(E_EVENT_CONFIG_LOADED, _e_event_config_loaded_cb, NULL)); - // WORKAROUND problem of X not sending events - poller = ecore_poller_add(ECORE_POLLER_CORE, POLLINTERVAL, _e_randr_x_poll_cb, NULL); + _event_handlers = eina_list_append(_event_handlers, ecore_event_handler_add(E_EVENT_CONFIG_LOADED, _e_event_config_loaded_cb, NULL)); + + if (e_randr_screen_info.randr_version >= ECORE_X_RANDR_1_2) + { + _12_event_listeners_add(); + } } + static void +_try_restore_configuration(void) +{ + if (e_randr_screen_info.randr_version == ECORE_X_RANDR_1_1) + { + _11_try_restore_configuration(); + } + else if (e_randr_screen_info.randr_version >= ECORE_X_RANDR_1_2) + { + _12_try_restore_configuration(); + } +} + +// "Free" helper functions static void -_e_randr_event_listeners_remove(void) +_event_listeners_remove(void) { Ecore_Event_Handler *_event_handler = NULL; - EINA_LIST_FREE (_e_randr_event_handlers, _event_handler) + EINA_LIST_FREE (_event_handlers, _event_handler) ecore_event_handler_del(_event_handler); - ecore_poller_del(poller); - poller = NULL; -} -static void -_e_randr_notify_crtc_mode_change(E_Randr_Crtc_Info *crtc_info) -{ - // E_Notification *n; - // char buff[200]; - // - if (crtc_info->current_mode) + if (e_randr_screen_info.randr_version >= ECORE_X_RANDR_1_2) { - // snprintf(buff, 200, "New resolution is %dx%d. Click here for further information.", crtc_info->current_mode->width, crtc_info->current_mode->height); - // n = e_notification_full_new("RandRR", crtc_info->xid, NULL, "Resolution changed", buff, -1); - // //n = e_notification_full_new("RandRR", id, icon, function, body, timeout); - // e_notification_send(n, NULL, NULL); - // e_notification_unref(n); + _12_event_listeners_remove(); } } - -static void -_e_randr_notify_output_change(E_Randr_Output_Info *output_info) -{ - // E_Notification *n; - // char buff[100]; - if (output_info->connection_status == ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED) - { - // snprintf(buff, 100, "Output %s connected", output_info->name); - // n = e_notification_full_new("RandRR", output_info->xid, NULL, buff, "Click here for further information.", -1); - } - else - { - // snprintf(buff, 100, "Output %s disconnected", output_info->name); - // n = e_notification_full_new("RandRR", output_info->xid, NULL, buff, "Click here to adjust screen setup.", -1); - } - - // //n = e_notification_full_new("RandRR", id, icon, function, body, timeout); - // e_notification_send(n, NULL, NULL); - // e_notification_unref(n); -} - -/* - * 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. - */ -static const E_Randr_Crtc_Info * -_e_randr_policy_crtc_get(E_Randr_Crtc_Info *but, E_Randr_Crtc_Info *hint __UNUSED__, Ecore_X_Randr_Output_Policy policy) -{ - Eina_List *iter, *possible_crtcs = NULL; - E_Randr_Crtc_Info *crtc_info, *ret = NULL; - - E_RANDR_NO_CRTCS_RET(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; -} - -// Setup store functions -Eina_Bool -_e_randr_copy_mode_info(Ecore_X_Randr_Mode_Info *dest, Ecore_X_Randr_Mode_Info *src) -{ - if (!dest || !src) return EINA_FALSE; - - dest->width = src->width; - dest->height = src->height; - dest->dotClock = src->dotClock; - dest->hSyncStart = src->hSyncStart; - dest->hSyncEnd = src->hSyncEnd; - dest->hTotal = src->hTotal; - dest->hSkew = src->hSkew; - dest->vSyncStart = src->vSyncStart; - dest->vSyncEnd = src->vSyncEnd; - dest->vTotal = src->vTotal; - if (src->nameLength > 0) - { - if (!(dest->name = malloc(src->nameLength + 1))) return EINA_FALSE; - if (!strncpy(dest->name, src->name, src->nameLength)) goto _e_randr_copy_mode_info_fail_free_name; - } - dest->nameLength = src->nameLength; - dest->modeFlags = src->modeFlags; - - return EINA_TRUE; - -_e_randr_copy_mode_info_fail_free_name: - free(dest->name); - return EINA_FALSE; -} - -void -_e_randr_free_serialized_mode_info(Ecore_X_Randr_Mode_Info *mode_info) -{ - if (mode_info->name) free(mode_info->name); -} - -Eina_List * -_e_randr_create_outputs_policies_list(Eina_List *outputs) -{ - Eina_List *iter, *list = NULL; - E_Randr_Output_Info *oi; - E_Randr_Serialized_Output_Policy *sop; - - EINA_LIST_FOREACH (outputs, iter, oi) - { - if (!oi->name || (oi->name_length <= 0)) continue; - if (!(sop = E_NEW(E_Randr_Serialized_Output_Policy, 1)) - || !(sop->name = malloc(oi->name_length + 1)) - || !(strncpy(sop->name, oi->name, oi->name_length))) - goto _e_randr_create_outputs_policies_list_fail_free_list; - sop->name_length = oi->name_length; - sop->policy = oi->policy; - if (!(list = eina_list_append(list, sop))) - goto _e_randr_create_outputs_policies_list_fail_free_list; - } - - return list; -_e_randr_create_outputs_policies_list_fail_free_list: - EINA_LIST_FREE (list, sop) - { - if (sop->name) free(sop->name); - free(sop); - } - return NULL; -} - -void -_e_randr_free_serialized_output_policy(E_Randr_Serialized_Output_Policy *sop) -{ - if (!sop) return; - - free(sop->name); - free(sop); -} - -Eina_List * -_e_randr_update_serialized_outputs_policies(E_Randr_Screen_Info_12 *si_12, Eina_List *sops) -{ - /* - * Do not free this mem, since it might be in e_config's teritory - * - E_Randr_Serialized_Output_Policy *sop; - - EINA_LIST_FREE (sops, sop) - { - _e_randr_free_serialized_output_policy(sop); - } - */ - - eina_list_free(sops); - - return _e_randr_create_outputs_policies_list(si_12->outputs); -} - - Eina_List * -_e_randr_create_possible_outputs_names_list(Eina_List *outputs) -{ - Eina_List *iter, *list = NULL; - E_Randr_Output_Info *oi; - char *name; - - if (!outputs) return NULL; - - EINA_LIST_FOREACH (outputs, iter, oi) - { - if (!oi->name || (oi->name_length <= 0)) continue; - if (!(name = malloc(oi->name_length)) - || !strncpy(name, oi->name, oi->name_length) - || !(list = eina_list_append(list, name))) goto _e_randr_create_possible_outputs_names_list_fail_free_list; - } - return list; - -_e_randr_create_possible_outputs_names_list_fail_free_list: - EINA_LIST_FREE (list, name) - { - if (name) free(name); - } - return NULL; -} - -E_Randr_Edid_Hash * -_e_randr_create_edid_hash(E_Randr_Output_Info *output_info) -{ - E_Randr_Edid_Hash *edid_hash; - - if (!output_info || (output_info->edid_hash.hash == 0) || !(edid_hash = malloc(sizeof(E_Randr_Edid_Hash)))) return NULL; - - edid_hash->hash = output_info->edid_hash.hash; - - return edid_hash; -} - -E_Randr_Serialized_Output * -_e_randr_create_serialized_output(E_Randr_Output_Info *output_info) -{ - E_Randr_Serialized_Output *so; - char *name; - - if (!output_info || !output_info->name || (output_info->name_length <= 0) || !(so = malloc(sizeof(E_Randr_Serialized_Output)))) return NULL; - - if (!(name = malloc(output_info->name_length)) - || !strncpy(so->name, output_info->name, output_info->name_length)) - goto _e_randr_create_serialized_outputs_fail_free_so; - so->name_length = output_info->name_length; - so->edid_hash.hash = output_info->edid_hash.hash; - so->backlight_level = output_info->backlight_level; - - return so; - -_e_randr_create_serialized_outputs_fail_free_so: - free(so); - return NULL; -} - -void -_e_randr_free_serialized_output(E_Randr_Serialized_Output *so) -{ - if (so->name) free(so->name); - free(so); -} - -E_Randr_Serialized_Crtc * -_e_randr_create_serialized_crtc(E_Randr_Crtc_Info *crtc_info) -{ - E_Randr_Serialized_Crtc *sc; - E_Randr_Serialized_Output *so; - E_Randr_Output_Info *output_info; - Eina_List *iter; - char *output_name; - - if (!(sc = E_NEW(E_Randr_Serialized_Crtc, 1))) return NULL; - if (!_e_randr_copy_mode_info(&sc->mode_info, crtc_info->current_mode)) goto _e_randr_create_serialized_crtc_free_sc; - if (!(sc->possible_outputs_names = _e_randr_create_possible_outputs_names_list(crtc_info->possible_outputs))) goto _e_randr_create_serialized_crtc_free_mode_sc; - //Create list of serialized outputs - EINA_LIST_FOREACH (crtc_info->outputs, iter, output_info) - { - if (!(so = _e_randr_create_serialized_output(output_info)) - || !(sc->serialized_outputs = eina_list_append(sc->serialized_outputs, so))) goto _e_randr_create_serialized_crtc_free_outputs_list_sc; - } - sc->pos.x = crtc_info->geometry.x; - sc->pos.y = crtc_info->geometry.y; - sc->orientation = crtc_info->current_orientation; - - return sc; - -_e_randr_create_serialized_crtc_free_outputs_list_sc: - EINA_LIST_FREE (sc->possible_outputs_names, output_name) - { - if (output_name) free(output_name); - } - EINA_LIST_FREE (sc->serialized_outputs, so) - { - if (so) _e_randr_free_serialized_output(so); - } -_e_randr_create_serialized_crtc_free_mode_sc: - _e_randr_free_serialized_mode_info(&sc->mode_info); -_e_randr_create_serialized_crtc_free_sc: - E_FREE(sc); - - return NULL; -} - -void -_e_randr_free_serialized_crtc(E_Randr_Serialized_Crtc *sc) -{ - E_Randr_Serialized_Output *so; - char *name; - - EINA_LIST_FREE (sc->serialized_outputs, so) - _e_randr_free_serialized_output(so); - _e_randr_free_serialized_mode_info(&sc->mode_info); - EINA_LIST_FREE (sc->possible_outputs_names, name) - free(name); - free(sc); -} - -E_Randr_Serialized_Setup_11 * -_e_randr_create_serialized_setup_11(E_Randr_Screen_Info_11 *screen_info_11) -{ - E_Randr_Serialized_Setup_11 *ss; - Ecore_X_Randr_Screen_Size_MM *size; - - if (!(ss = malloc(sizeof(*ss)))) return NULL; - if (!(size = (Ecore_X_Randr_Screen_Size_MM *)eina_list_data_get(eina_list_nth(screen_info_11->sizes, screen_info_11->csize_index)))) goto _e_randr_create_serialized_setup_11_failed_free_ss; - ss->size.width = size->width; - ss->size.height = size->height; - ss->refresh_rate = screen_info_11->current_rate; - ss->orientation = screen_info_11->corientation; - - return ss; - -_e_randr_create_serialized_setup_11_failed_free_ss: - free(ss); - return NULL; -} - -E_Randr_Serialized_Setup_11 * -_e_randr_update_serialized_setup_11(E_Randr_Serialized_Setup_11 *ss_11, E_Randr_Screen_Info_11 *si_11) -{ - Ecore_X_Randr_Screen_Size_MM *size; - - if (ss_11) - { - if (!(size = (Ecore_X_Randr_Screen_Size_MM *)eina_list_data_get(eina_list_nth(si_11->sizes, si_11->csize_index)))) return NULL; - if (!memcpy(&ss_11->size, size, sizeof(Ecore_X_Randr_Screen_Size_MM))) - goto _e_randr_update_serialized_setup_11_failed_free_ss; - ss_11->refresh_rate = si_11->current_rate; - ss_11->orientation = si_11->corientation; - } - else - ss_11 = _e_randr_create_serialized_setup_11(si_11); - - return ss_11; - -_e_randr_update_serialized_setup_11_failed_free_ss: - free(ss_11); - return NULL; -} - -E_Randr_Serialized_Setup_12 * -_e_randr_create_serialized_setup_12(E_Randr_Screen_Info_12 *screen_info_12) -{ - E_Randr_Serialized_Setup_12 *ss; - Eina_List *iter; - E_Randr_Crtc_Info *ci; - E_Randr_Output_Info *oi; - E_Randr_Serialized_Crtc *sc; - E_Randr_Edid_Hash *edid_hash; - - if (!(ss = E_NEW(E_Randr_Serialized_Setup_12, 1))) return NULL; - - ss->timestamp = ecore_time_get(); - - //Add CRTCs and their configuration - EINA_LIST_FOREACH (screen_info_12->crtcs, iter, ci) - { - //ignore disabled crtcs for now - if (!ci->current_mode) continue; - - if (!(sc = _e_randr_create_serialized_crtc(ci)) - || !(ss->serialized_crtcs = eina_list_append(ss->serialized_crtcs, sc))) - goto _e_randr_create_serialized_setup_12_failed_free_list_ss; - } - - /* - * Add EDID hashes of connected and enabled - * outputs for easier comparison during - * setup restoration - */ - EINA_LIST_FOREACH (screen_info_12->outputs, iter, oi) - { - if ((oi->connection_status != ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED) || !oi->crtc || !oi->crtc->current_mode) - continue; - if (!(edid_hash = _e_randr_create_edid_hash(oi)) || !(ss->serialized_edid_hashes = eina_list_append(ss->serialized_edid_hashes, edid_hash))) - goto _e_randr_create_serialized_setup_12_failed_free_output_list_crtc_list_ss; - } - - return ss; - -_e_randr_create_serialized_setup_12_failed_free_output_list_crtc_list_ss: - EINA_LIST_FREE (ss->serialized_edid_hashes, edid_hash) - { - if (edid_hash) free(edid_hash); - } -_e_randr_create_serialized_setup_12_failed_free_list_ss: - EINA_LIST_FREE (ss->serialized_crtcs, sc) - { - _e_randr_free_serialized_crtc(sc); - } - free(ss); - return NULL; -} - -E_Randr_Serialized_Setup_12 * -_e_randr_find_matching_serialized_setup(Eina_List *setups_12, E_Randr_Screen_Info_12 *si_12) -{ - E_Randr_Serialized_Setup_12 *ss_12; - Eina_List *setups_iter, *r_iter, *s_iter; - Eina_Bool found = EINA_FALSE; - E_Randr_Edid_Hash *edid_hash; - E_Randr_Output_Info *oi; - - if (!setups_12 || !si_12) return NULL; - - EINA_LIST_FOREACH (setups_12, setups_iter, ss_12) - { - EINA_LIST_FOREACH (si_12->outputs, r_iter, oi) - { - //skip disconnected/-abled monitors - if ((oi->connection_status != ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED) || !oi->crtc || !oi->crtc->current_mode) - continue; - found = EINA_FALSE; - EINA_LIST_FOREACH (ss_12->serialized_edid_hashes, s_iter, edid_hash) - { - if (oi->edid_hash.hash == edid_hash->hash) - { - found = EINA_TRUE; - break; - } - } - if (!found) - break; - } - if (found) - break; - } - if (found) - return ss_12; - - return NULL; -} - -void -_e_randr_free_serialized_setup_12(E_Randr_Serialized_Setup_12 *ss_12) -{ - E_Randr_Serialized_Crtc *sc; - E_Randr_Edid_Hash *edid_hash; - - if (!ss_12) return; - - EINA_LIST_FREE (ss_12->serialized_crtcs, sc) - { - if (!sc) continue; - _e_randr_free_serialized_crtc(sc); - } - EINA_LIST_FREE (ss_12->serialized_edid_hashes, edid_hash) - if (edid_hash) free(edid_hash); - - free(ss_12); -} - -Eina_List * -_e_randr_update_serialized_setup_12(Eina_List *setups_12, E_Randr_Screen_Info_12 *si_12) -{ - E_Randr_Serialized_Setup_12 *ss_12; - - if (setups_12) - { - /* - * try to find the setup with the same monitors - * connected in order to replace it - */ - if ((ss_12 = _e_randr_find_matching_serialized_setup(setups_12, si_12))) - { - //_e_randr_free_serialized_setup_12(ss_12); - setups_12 = eina_list_remove(setups_12, ss_12); - } - } - ss_12 = _e_randr_create_serialized_setup_12(si_12); - setups_12 = eina_list_append(setups_12, ss_12); - - return setups_12; -} - -E_Randr_Serialized_Setup * -_e_randr_create_serialized_setup(E_Randr_Screen_Info *screen_info __UNUSED__) -{ - return E_NEW(E_Randr_Serialized_Setup, 1); -} - -EAPI void -e_randr_store_configuration(E_Randr_Screen_Info *screen_info, E_Randr_Configuration_Store_Modifier modifier) -{ - if (E_RANDR_NO_11) return; - - if (!e_config->randr_serialized_setup) - e_config->randr_serialized_setup = _e_randr_create_serialized_setup(screen_info); - - fprintf(stderr, "E_RANDR: Configuration shall be stored using the following modifier: %d.\n", modifier); - - if (screen_info->randr_version == ECORE_X_RANDR_1_1) - { - if (e_config->randr_serialized_setup->serialized_setup_11) - e_config->randr_serialized_setup->serialized_setup_11 = _e_randr_update_serialized_setup_11(e_config->randr_serialized_setup->serialized_setup_11, screen_info->rrvd_info.randr_info_11); - else - e_config->randr_serialized_setup->serialized_setup_11 = _e_randr_create_serialized_setup_11(screen_info->rrvd_info.randr_info_11); - } - else if (screen_info->randr_version >= ECORE_X_RANDR_1_2) - { - /* - if (modifier & (E_RANDR_CONFIGURATION_STORE_RESOLUTIONS | E_RANDR_CONFIGURATION_STORE_ARRANGEMENT | E_RANDR_CONFIGURATION_STORE_ORIENTATIONS)) - { - if (e_config->randr_serialized_setup->serialized_setups_12) - e_config->randr_serialized_setup->serialized_setups_12 = _e_randr_update_serialized_setup_12(e_config->randr_serialized_setup->serialized_setups_12, screen_info->rrvd_info.randr_info_12); - else - e_config->randr_serialized_setup->serialized_setups_12 = eina_list_append(e_config->randr_serialized_setup->serialized_setups_12, _e_randr_create_serialized_setup_12(screen_info->rrvd_info.randr_info_12)); - } - */ - - if (modifier & E_RANDR_CONFIGURATION_STORE_POLICIES) - { - //update output policies - e_config->randr_serialized_setup->serialized_outputs_policies = _e_randr_update_serialized_outputs_policies(screen_info->rrvd_info.randr_info_12, e_config->randr_serialized_setup->serialized_outputs_policies); - } - } - e_config_save_queue(); -} - -//setup restore functions -EAPI Eina_Bool -e_randr_try_restore_configuration(E_Randr_Screen_Info *si) -{ - if (!e_config || !e_config->randr_serialized_setup) return EINA_FALSE; - - if (si->randr_version == ECORE_X_RANDR_1_1) - return _e_randr_try_restore_11(si->rrvd_info.randr_info_11); - else if (si->randr_version >= ECORE_X_RANDR_1_2) - return _e_randr_try_restore_12(si->rrvd_info.randr_info_12); - - return EINA_FALSE; -} - -Eina_Bool -_e_randr_try_restore_11(E_Randr_Screen_Info_11 *si_11) -{ - Eina_List *iter; - Ecore_X_Randr_Screen_Size_MM *stored_size, *size; - int i = 0; - - if (!e_config->randr_serialized_setup->serialized_setup_11) return EINA_FALSE; - stored_size = &e_config->randr_serialized_setup->serialized_setup_11->size; - EINA_LIST_FOREACH (si_11->sizes, iter, size) - { - if ((stored_size->width == size->width) - && (stored_size->height == size->height) - && (stored_size->width_mm == size->width_mm) - && (stored_size->height_mm == size->height_mm)) - { - return ecore_x_randr_screen_primary_output_size_set(e_randr_screen_info->root, i); - } - i++; - } - - return EINA_FALSE; -} - -E_Randr_Crtc_Info * -_e_randr_find_matching_crtc(Eina_List *crtcs, E_Randr_Serialized_Crtc *sc) -{ - Eina_List *iter, *s_name_iter, *p_output_iter; - E_Randr_Crtc_Info *ci; - E_Randr_Output_Info *oi; - char *s_output_name; - - EINA_LIST_FOREACH (crtcs, iter, ci) - { - if (eina_list_count(ci->possible_outputs) != eina_list_count(sc->possible_outputs_names)) - continue; - EINA_LIST_FOREACH (sc->possible_outputs_names, s_name_iter, s_output_name) - { - EINA_LIST_FOREACH (ci->possible_outputs, p_output_iter, oi) - { - if (oi->name) - { - if (!strncmp(s_output_name, oi->name, oi->name_length)) - return ci; - } - } - } - } - return NULL; -} - -Eina_List * -_e_randr_find_matching_outputs(Eina_List *sois, Eina_List *ois) -{ - Eina_List *r_output_iter, *s_output_iter, *list = NULL; - E_Randr_Output_Info *oi; - E_Randr_Serialized_Output *so; - - EINA_LIST_FOREACH (sois, s_output_iter, so) - { - fprintf(stderr, "E_RANDR: Looking for serialized output %d(hash)\n", so->edid_hash.hash); - EINA_LIST_FOREACH (ois, r_output_iter, oi) - { - fprintf(stderr, "E_RANDR: \tComparing to output %d(hash)\n", oi->edid_hash.hash); - if (so->edid_hash.hash == oi->edid_hash.hash) - { - list = eina_list_append(list, oi); - break; - } - } - } - if (list && (eina_list_count(sois) != eina_list_count(list))) - { - eina_list_free(list); - list = NULL; - } - - return list; -} - -Ecore_X_Randr_Mode_Info * -_e_randr_find_matching_mode_info(Eina_List *modes, Ecore_X_Randr_Mode_Info *mode) -{ - Eina_List *iter; - Ecore_X_Randr_Mode_Info *mi = NULL; - - EINA_LIST_FOREACH (modes, iter, mi) - { - if ((mode->width == mi->width) - && (mode->height == mi->height) - && (mode->dotClock == mi->dotClock) - && (mode->hSyncStart == mi->hSyncStart) - && (mode->hSyncEnd == mi->hSyncEnd) - && (mode->hTotal == mi->hTotal) - && (mode->hSkew == mi->hSkew) - && (mode->vSyncStart == mi->vSyncStart) - && (mode->vSyncEnd == mi->vSyncEnd) - && (mode->vTotal == mi->vTotal) - && (mode->nameLength == mi->nameLength) - && !strncpy(mode->name, mi->name, mode->nameLength) - && (mode->modeFlags == mi->modeFlags)) - return mi; - } - return NULL; -} - -void -_e_randr_restore_12_policies(E_Randr_Screen_Info_12 *si_12) -{ - E_Randr_Output_Info *output; - E_Randr_Serialized_Output_Policy *sop; - Eina_List *iter, *iter2; - - EINA_SAFETY_ON_NULL_RETURN(si_12); - EINA_SAFETY_ON_NULL_RETURN(e_config->randr_serialized_setup); - EINA_SAFETY_ON_NULL_RETURN(e_config->randr_serialized_setup->serialized_outputs_policies); - - // Restore policies - EINA_LIST_FOREACH(si_12->outputs, iter, output) - { - EINA_LIST_FOREACH(e_config->randr_serialized_setup->serialized_outputs_policies, iter2, sop) - { - if (output->name) - { - if (strncmp(sop->name, output->name, sop->name_length) == 0) - { - output->policy = sop->policy; - } - } - } - } -} - -Eina_Bool -_e_randr_try_restore_12(E_Randr_Screen_Info_12 *si_12) -{ - /* - E_Randr_Serialized_Setup_12 *ss_12; - E_Randr_Serialized_Crtc *sc; - E_Randr_Crtc_Info *ci; - Ecore_X_Randr_Output *outputs_array; - Ecore_X_Randr_Mode_Info *mi; - Eina_List *iter; - */ - Eina_Bool ret = EINA_TRUE; - - //Restore policies - _e_randr_restore_12_policies(si_12); - - /* - * step by step. disable entire setup matching for now - if (!(ss_12 = _e_randr_find_matching_serialized_setup(e_config->randr_serialized_setup->serialized_setups_12, si_12))) return EINA_FALSE; - - EINA_LIST_FOREACH (ss_12->serialized_crtcs, iter, sc) - { - ci = _e_randr_find_matching_crtc(si_12->crtcs, sc); - outputs_list = _e_randr_find_matching_outputs(si_12->outputs, sc->serialized_outputs); - outputs_array = _e_randr_outputs_to_array(outputs_list); - if (!(mi = _e_randr_find_matching_mode_info(si_12->modes, &sc->mode_info))) - { - // The serialized mode is no longer available - eina_list_free(outputs_list); - free(outputs_array); - continue; - } - ret &= ecore_x_randr_crtc_mode_set(e_randr_screen_info->root, ci->xid, outputs_array, eina_list_count(outputs_list), mi->xid); - ret &= ecore_x_randr_crtc_pos_set(e_randr_screen_info->root, ci->xid, sc->pos.x, sc->pos.y); - } - */ - return ret; -} - -//Utility functions - static Ecore_X_Randr_Output * -_e_randr_outputs_to_array(Eina_List *outputs_info) -{ - Ecore_X_Randr_Output *ret = NULL; - E_Randr_Output_Info *output_info; - Eina_List *output_iter; - int i = 0; - - if (!outputs_info || !(ret = malloc(sizeof(Ecore_X_Randr_Output) * eina_list_count(outputs_info)))) return NULL; - EINA_LIST_FOREACH (outputs_info, output_iter, output_info) - /* output_info == NULL should _not_ be possible! */ - ret[i++] = output_info ? output_info->xid : Ecore_X_Randr_None; - return ret; -} - -/* - * 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). - */ - static Eina_Bool -_e_randr_try_enable_output(E_Randr_Output_Info *output_info, Eina_Bool force) -{ - if (!output_info) return EINA_FALSE; - else if (output_info->crtc && output_info->crtc->current_mode) - return EINA_TRUE; - - Eina_List *iter, *outputs_list = NULL; - E_Randr_Crtc_Info *crtc_info, *usable_crtc = NULL; - E_Randr_Output_Info *primary_output; - Ecore_X_Randr_Output *outputs; - Ecore_X_Randr_Mode_Info *mode_info; - Eina_Bool ret = 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 && (!crtc_info->current_mode || 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; - - fprintf(stderr, "E_RANDR: Try to enable output %x using policy %d.\n", output_info->xid, output_info->policy); - - //get the CRTC we will refer to, dependend on policy - switch (output_info->policy) - { - case ECORE_X_RANDR_OUTPUT_POLICY_NONE: - return EINA_TRUE; - - case ECORE_X_RANDR_OUTPUT_POLICY_CLONE: - /* - * 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 - * 2a. exact mode or a - * 2b. 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. - */ - 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->modes, primary_output->crtc->current_mode)) - { - /* - * mode currently used by primary output's CRTC is also supported by the new output - */ - if (_e_randr_outputs_are_clones(output_info, primary_output->crtc->outputs)) - { - /* - * 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 = eina_list_clone(primary_output->crtc->outputs); - outputs_list = eina_list_append(outputs_list, output_info); - outputs = _e_randr_outputs_to_array(outputs_list); - 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 - */ - - /* - * 2a. 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); - return 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); - } - } - else - { - /* - * 2b. geometrically identical mode - */ - if (primary_output->crtc && (mode_info = _e_randr_mode_geo_identical_find(output_info->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); - return 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); - } - /* - * 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) - { - if ((mode_info = _e_randr_outputs_common_mode_max_get(outputs_list, primary_output->crtc->current_mode))) - { - fprintf(stderr, "Will try to set mode: %dx%d for primary and clone.\n", 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 = (ret && ecore_x_randr_crtc_mode_set(e_randr_screen_info->root, usable_crtc->xid, &output_info->xid, 1, mode_info->xid)); - ret = (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 - fprintf(stderr, "Couldn't get primary output!\n"); - /* - * 4. FAIL - */ - break; - - default: - if (usable_crtc) - { - //enable and position according to used policies - if (!(mode_info = ((Ecore_X_Randr_Mode_Info *)eina_list_nth(output_info->preferred_modes, 0)))) - { - fprintf(stderr, "E_RANDR: Could not enable output(%x), as it has no preferred (and there for none at all) modes.!\n", output_info->xid); - ret = EINA_FALSE; - break; - } - if ((ret = ecore_x_randr_crtc_mode_set(e_randr_screen_info->root, usable_crtc->xid, &output_info->xid, 1, mode_info->xid))) - { - usable_crtc->geometry.w = mode_info->width; - usable_crtc->geometry.h = mode_info->height; - usable_crtc->geometry.x = 0; - usable_crtc->geometry.y = 0; - usable_crtc->outputs = eina_list_append(usable_crtc->outputs, output_info); - - ret &= _e_randr_crtc_move_policy(usable_crtc); - } - } - } - ecore_x_randr_screen_reset(e_randr_screen_info->root); - return ret; -} - -/* - * updates all crtcs information regarding a new output - */ -static void -_e_randr_crtcs_possible_output_update(E_Randr_Output_Info *output_info) -{ - Eina_List *iter; - E_Randr_Crtc_Info *crtc_info; - Ecore_X_Randr_Output *outputs = NULL; - int noutputs = 0; - - EINA_LIST_FOREACH (e_randr_screen_info->rrvd_info.randr_info_12->crtcs, iter, crtc_info) - { - if (!eina_list_data_find(crtc_info->possible_outputs, output_info)) - { - if ((outputs = ecore_x_randr_crtc_possible_outputs_get(e_randr_screen_info->root, crtc_info->xid, &noutputs))) - { - while (--noutputs >= 0) - { - if (outputs[noutputs] == output_info->xid) - { - crtc_info->possible_outputs = eina_list_append(crtc_info->possible_outputs, output_info); - break; - } - } - free(outputs); - } - } - } -} - -/* - * setup a crtc's current (possible) outputs references - */ -static void -_e_randr_crtc_outputs_refs_update(E_Randr_Crtc_Info *crtc_info) -{ - Ecore_X_Randr_Output *outputs; - E_Randr_Output_Info *output_info; - int i, noutputs; - - EINA_SAFETY_ON_NULL_RETURN(e_randr_screen_info->rrvd_info.randr_info_12->outputs); - - //get references to output_info structs which are related to this CRTC - if ((outputs = ecore_x_randr_crtc_outputs_get(e_randr_screen_info->root, crtc_info->xid, &noutputs))) - { - eina_list_free(crtc_info->outputs); - crtc_info->outputs = NULL; - for (i = 0; i < noutputs; i++) - { - if (!(output_info = _e_randr_output_info_get(outputs[i]))) - { - output_info = _e_randr_output_info_new(1); - output_info->xid = outputs[i]; - _e_randr_output_info_set(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); - } - crtc_info->outputs = eina_list_append(crtc_info->outputs, output_info); - output_info->crtc = crtc_info; - } - free(outputs); - } - //get references to possible output_info structs which are related to this CRTC - if ((outputs = ecore_x_randr_crtc_possible_outputs_get(e_randr_screen_info->root, crtc_info->xid, &noutputs))) - { - eina_list_free(crtc_info->possible_outputs); - crtc_info->possible_outputs = NULL; - for (i = 0; i < noutputs; i++) - { - output_info = _e_randr_output_info_get(outputs[i]); - crtc_info->possible_outputs = eina_list_append(crtc_info->possible_outputs, output_info); - } - free(outputs); - } -} - -/* - * 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. - */ -static Eina_Bool -_e_randr_crtc_move_policy(E_Randr_Crtc_Info *new_crtc) -{ - const E_Randr_Crtc_Info *crtc_rel; - E_Randr_Output_Info *last_output = NULL; - int dx = Ecore_X_Randr_None, dy = Ecore_X_Randr_None; - Eina_Bool ret = EINA_TRUE; - - //use the policy of the new crtc's last output - last_output = (E_Randr_Output_Info *)eina_list_data_get(eina_list_last(new_crtc->outputs)); - if (!last_output) return EINA_FALSE; - //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 = _e_randr_policy_crtc_get(new_crtc, NULL, last_output->policy))) return EINA_TRUE; - - //following is policy dependend. - switch (last_output->policy) - { - 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); - } - 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); - } - break; - - default: - break; - } - ret &= ecore_x_randr_crtc_pos_relative_set(e_randr_screen_info->root, new_crtc->xid, crtc_rel->xid, last_output->policy, e_randr_screen_info->rrvd_info.randr_info_12->alignment); - return ret; -} - -/* - * returns the highest resolution mode common ammongst the given outputs, - * optionally limited by max_size_mode. If none is found, NULL is returned. - */ -static Ecore_X_Randr_Mode_Info * -_e_randr_outputs_common_mode_max_get(Eina_List *outputs, Ecore_X_Randr_Mode_Info *max_size_mode) -{ - Eina_List *all_modes = NULL, *iter, *output_iter, *right; - E_Randr_Output_Info *output_info; - Ecore_X_Randr_Mode_Info *mode_info; - int outputs_mode_found; - - //create a list of all available modes - EINA_LIST_FOREACH (outputs, iter, output_info) - { - right = eina_list_clone(output_info->modes); - all_modes = eina_list_merge(all_modes, right); - } - - if (max_size_mode) - { - //remove all modes that are larger than max_size_mode - EINA_LIST_FOREACH (all_modes, iter, mode_info) - { - if (_modes_size_sort_cb((void *)max_size_mode, (void *)mode_info) < 0) - all_modes = eina_list_remove(all_modes, mode_info); - } - } - - //sort modes by their sizes - all_modes = eina_list_sort(all_modes, eina_list_count(all_modes), _modes_size_sort_cb); - EINA_LIST_REVERSE_FOREACH (all_modes, iter, mode_info) - { - outputs_mode_found = 0; - EINA_LIST_FOREACH (outputs, output_iter, output_info) - { - if (eina_list_data_find(output_info->modes, mode_info)) - outputs_mode_found++; - } - if (outputs_mode_found == (int)eina_list_count(outputs)) - break; - mode_info = NULL; - } - return mode_info; -} - -/* - static int - _crtcs_size_sort_cb(const void *d1, const void *d2) - { - E_Randr_Crtc_Info *crtc1 = ((E_Randr_Crtc_Info*)d1), *crtc2 = ((E_Randr_Crtc_Info*)d2); - - return ((crtc1->geometry.w * crtc1->geometry.h) - (crtc2->geometry.w * crtc2->geometry.h)); - } - */ - -static int -_outputs_size_sort_cb(const void *d1, const void *d2) -{ - E_Randr_Output_Info *output1 = ((E_Randr_Output_Info *)d1), *output2 = ((E_Randr_Output_Info *)d2); - - return (output1 && output1->crtc && output1->crtc->current_mode && output2 && output2->crtc && output2->crtc->current_mode) ? ((output1->crtc->current_mode->width * output1->crtc->current_mode->height) - (output2->crtc->current_mode->width * output2->crtc->current_mode->height)) : 0; -} - -static int -_modes_size_sort_cb(const void *d1, const void *d2) -{ - Ecore_X_Randr_Mode_Info *mode1 = ((Ecore_X_Randr_Mode_Info *)d1), *mode2 = ((Ecore_X_Randr_Mode_Info *)d2); - - return (mode1->width * mode1->height) - (mode2->width * mode2->height); -} - -/* - * returns a mode within a given list of modes that is gemetrically identical. - * If none is found, NULL is returned. - */ -static Ecore_X_Randr_Mode_Info * -_e_randr_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; -} - -/* - * reconfigures a CRTC enabling the highest resolution amongst its outputs, - * without touching any other CRTC currently activated - */ -static Eina_Bool -_e_randr_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 (!_e_randr_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 = _e_randr_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; -} - -/* - * returns EINA_TRUE if given CRTC would intersect with other CRTCs if set to - * given mode - */ -static Eina_Bool -_e_randr_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; -} - -/* - * returns a list of modes common ammongst the given outputs, - * optionally limited by max_size_mode. If none are found, NULL is returned. - */ -static Eina_List * -_e_randr_outputs_common_modes_get(Eina_List *outputs, Ecore_X_Randr_Mode_Info *max_size_mode) -{ - Eina_List *common_modes = NULL, *iter, *output_iter, *right; - E_Randr_Output_Info *output_info; - Ecore_X_Randr_Mode_Info *mode_info; - int outputs_mode_found; - - if (!outputs) return NULL; - - //create a list of all available modes - EINA_LIST_FOREACH (outputs, iter, output_info) - { - right = eina_list_clone(output_info->modes); - common_modes = eina_list_merge(common_modes, right); - } - - if (max_size_mode) - { - //remove all modes that are larger than max_size_mode - EINA_LIST_FOREACH (common_modes, iter, mode_info) - { - if (_modes_size_sort_cb((void *)max_size_mode, (void *)mode_info) < 0) - common_modes = eina_list_remove(common_modes, mode_info); - } - } - - //sort modes desc. by their sizes - for (iter = eina_list_last(common_modes); iter; ) - { - mode_info = iter->data; - iter = iter->prev; - outputs_mode_found = 0; - EINA_LIST_FOREACH (outputs, output_iter, output_info) - { - if (eina_list_data_find(output_info->modes, mode_info)) - outputs_mode_found++; - } - if (outputs_mode_found != (int)eina_list_count(outputs)) - common_modes = eina_list_remove(common_modes, mode_info); - } - return common_modes; -} - -/* - * reconfigure all CRTCs that had a given CRTC as a clone - */ -static Eina_Bool -_e_randr_crtcs_clone_crtc_removed(E_Randr_Crtc_Info *former_clone) -{ - Eina_List *iter; - E_Randr_Crtc_Info *crtc_info; - - if (!former_clone) return EINA_FALSE; - - EINA_LIST_FOREACH (e_randr_screen_info->rrvd_info.randr_info_12->crtcs, iter, crtc_info) - { - if ((crtc_info == former_clone) || ((crtc_info->geometry.w <= 0) || (crtc_info->geometry.h <= 0))) continue; - if ((former_clone->geometry.x == crtc_info->geometry.x) && (former_clone->geometry.y == crtc_info->geometry.y) && (former_clone->geometry.w == crtc_info->geometry.w) && (former_clone->geometry.h == crtc_info->geometry.h)) - { - if (!_e_randr_crtc_outputs_mode_max_set(crtc_info)) return EINA_FALSE; - } - } - - return EINA_TRUE; -} - -static void -_e_randr_screen_primary_output_assign(E_Randr_Output_Info *removed) -{ - Eina_List *iter; - E_Randr_Output_Info *primary_output = NULL, *output_info; - - E_RANDR_NO_OUTPUTS_RET(); - - 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 = _e_randr_output_info_get(ecore_x_randr_primary_output_get(e_randr_screen_info->root)))) - { - primary_output = eina_list_data_get(eina_list_last(e_randr_screen_info->rrvd_info.randr_info_12->outputs)); - - EINA_LIST_FOREACH (e_randr_screen_info->rrvd_info.randr_info_12->outputs, iter, output_info) - { - if (output_info->connection_status == ECORE_X_RANDR_CONNECTION_STATUS_DISCONNECTED || !output_info->crtc || !output_info->crtc->current_mode) continue; - if ((!primary_output->crtc || !primary_output->crtc->current_mode) || _outputs_size_sort_cb(output_info, primary_output) > 0) primary_output = output_info; - } - if (!primary_output->crtc || !primary_output->crtc->current_mode) primary_output = NULL; - } - e_randr_screen_info->rrvd_info.randr_info_12->primary_output = primary_output; -} - -static void -_e_randr_output_info_hw_info_set(E_Randr_Output_Info *output_info) -{ - Ecore_X_Randr_Output *outputs; - Ecore_X_Randr_Crtc *crtcs; - E_Randr_Output_Info *output; - E_Randr_Crtc_Info *crtc; - int i, num; - - _e_randr_output_modes_add(output_info); - output_info->edid = ecore_x_randr_output_edid_get(e_randr_screen_info->root, output_info->xid, &output_info->edid_length); - if (output_info->edid_length > 0) - output_info->edid_hash.hash = eina_hash_superfast((char *)output_info->edid, output_info->edid_length); - - //get the outputs we can use on the same CRTC alongside this one. - if (output_info->clones) - { - eina_list_free(output_info->clones); - output_info->clones = NULL; - } - if ((outputs = ecore_x_randr_output_clones_get(e_randr_screen_info->root, output_info->xid, &num))) - { - for (i = 0; i < num; i++) - { - if ((output = _e_randr_output_info_get(outputs[i]))) - output_info->clones = eina_list_append(output_info->clones, output); - } - free(outputs); - } - - //get the CRTCs which are usable with this output. - if (output_info->possible_crtcs) - { - eina_list_free(output_info->possible_crtcs); - output_info->possible_crtcs = NULL; - } - if ((crtcs = ecore_x_randr_output_possible_crtcs_get(e_randr_screen_info->root, output_info->xid, &num))) - { - for (i = 0; i < num; i++) - { - fprintf(stderr, "E_RANDR: possible CRTC: %d\n", crtcs[i]); - if ((crtc = _e_randr_crtc_info_get(crtcs[i]))) - { - fprintf(stderr, "E_RANDR: \tfound the suiting struct at %p\n", crtc); - output_info->possible_crtcs = eina_list_append(output_info->possible_crtcs, crtc); - } - } - free(crtcs); - } - else - { - fprintf(stderr, "E_RANDR: Output %x does not have a single possible CRTC.\n", output_info->xid); - } -} - -/* - * free the hardware specifig parts of the information - * removes all traces of an output within the data. - * @param output_info the output info to be freed. - */ -static void -_e_randr_output_hw_info_free(E_Randr_Output_Info *output_info) -{ - E_Randr_Crtc_Info *crtc_info; - Eina_List *iter; - if (!output_info) return; - - if (output_info->modes) - { - eina_list_free(output_info->modes); - output_info->modes = NULL; - } - if (output_info->preferred_modes) - { - eina_list_free(output_info->preferred_modes); - output_info->preferred_modes = NULL; - } - if (output_info->edid) - { - free(output_info->edid); - output_info->edid = NULL; - } - if (output_info->wired_clones) - { - eina_list_free(output_info->wired_clones); - output_info->wired_clones = NULL; - } - if (output_info->compatible_outputs) - { - eina_list_free(output_info->compatible_outputs); - output_info->compatible_outputs = NULL; - } - if (output_info->possible_crtcs) - { - eina_list_free(output_info->possible_crtcs); - output_info->possible_crtcs = NULL; - } - if (output_info->clones) - { - eina_list_free(output_info->clones); - output_info->clones = NULL; - } - - EINA_LIST_FOREACH (e_randr_screen_info->rrvd_info.randr_info_12->crtcs, iter, crtc_info) - { - crtc_info->possible_outputs = eina_list_remove(crtc_info->possible_outputs, output_info); - } -} - -/* - * checks whether a given output is a common clone of the given list's outputs - */ -static Eina_Bool -_e_randr_outputs_are_clones(E_Randr_Output_Info *output_info, Eina_List *outputs) -{ - E_Randr_Output_Info *output; - Eina_List *iter; - - if (!outputs || !output_info) return EINA_FALSE; - - EINA_LIST_FOREACH (output_info->clones, iter, output) - { - if (!eina_list_data_find(output_info->clones, output)) - return EINA_FALSE; - } - return EINA_TRUE; -} - diff --git a/src/bin/e_randr.h b/src/bin/e_randr.h index 039ae3cef..f61970262 100644 --- a/src/bin/e_randr.h +++ b/src/bin/e_randr.h @@ -2,6 +2,7 @@ typedef struct _E_Randr_Crtc_Info E_Randr_Crtc_Info; typedef struct _E_Randr_Edid_Hash E_Randr_Edid_Hash; +typedef struct _E_Randr_Monitor_Info E_Randr_Monitor_Info; typedef struct _E_Randr_Output_Info E_Randr_Output_Info; typedef struct _E_Randr_Screen_Info_11 E_Randr_Screen_Info_11; typedef struct _E_Randr_Screen_Info_12 E_Randr_Screen_Info_12; @@ -27,8 +28,7 @@ typedef enum _E_Randr_Configuration_Store_Modifier | E_RANDR_CONFIGURATION_STORE_ORIENTATIONS) } E_Randr_Configuration_Store_Modifier; -EAPI void e_randr_store_configuration(E_Randr_Screen_Info *screen_info, E_Randr_Configuration_Store_Modifier modifier); -EAPI Eina_Bool e_randr_try_restore_configuration(E_Randr_Screen_Info *screen_info); +EAPI void e_randr_store_configuration(E_Randr_Configuration_Store_Modifier modifier); #else #ifndef E_RANDR_H @@ -56,6 +56,18 @@ struct _E_Randr_Edid_Hash int hash; }; +struct _E_Randr_Monitor_Info +{ + Eina_List *modes; + Eina_List *preferred_modes; + Ecore_X_Randr_Screen_Size size_mm; + unsigned char *edid; + unsigned long edid_length; + E_Randr_Edid_Hash edid_hash; + int max_backlight; + double backlight_level; +}; + struct _E_Randr_Output_Info { Ecore_X_ID xid; @@ -69,21 +81,13 @@ struct _E_Randr_Output_Info Ecore_X_Randr_Connector_Type connector_type; Ecore_X_Randr_Connection_Status connection_status; Ecore_X_Randr_Output_Policy policy; + Eina_List *possible_crtcs; + Eina_List *compatibility_list; + Ecore_X_Render_Subpixel_Order subpixel_order; /* * Attached Monitor specific: */ - Eina_List *modes; - Eina_List *preferred_modes; - Eina_List *clones; - Eina_List *possible_crtcs; - Ecore_X_Randr_Screen_Size size_mm; - unsigned char *edid; - unsigned long edid_length; - E_Randr_Edid_Hash edid_hash; - int max_backlight; - double backlight_level; - Ecore_X_Render_Subpixel_Order subpixel_order; - Eina_List *compatible_outputs; + E_Randr_Monitor_Info *monitor; }; struct _E_Randr_Screen_Info_11 @@ -129,41 +133,35 @@ struct _E_Randr_Screen_Info struct _E_Randr_Serialized_Output_Policy { char *name; - int name_length; Ecore_X_Randr_Output_Policy policy; }; struct _E_Randr_Serialized_Output { char *name; - int name_length; - E_Randr_Edid_Hash edid_hash; double backlight_level; }; struct _E_Randr_Serialized_Crtc { + int index; //List of E_Randr_Serialized_Output objects that were used on the same output - Eina_List *serialized_outputs; - //the serialized mode_info misses its xid value - Ecore_X_Randr_Mode_Info mode_info; + Eina_List *outputs; Evas_Coord_Point pos; - //List of all possible outputs' names - //e.g. "LVDS", "CRT-0", "VGA" - Eina_List *possible_outputs_names; Ecore_X_Randr_Orientation orientation; + //the serialized mode_info + Ecore_X_Randr_Mode_Info mode_info; }; struct _E_Randr_Serialized_Setup_12 { double timestamp; //List of E_Randr_Serialized_Crtc objects - Eina_List *serialized_crtcs; + Eina_List *crtcs; /* - * List of E_Randr_Edid_Hash elements of monitors, - * that were enabled, when the setup was stored + * List of E_Randr_Edid_Hash elements of all connected monitors */ - Eina_List *serialized_edid_hashes; + Eina_List *edid_hashes; }; struct _E_Randr_Serialized_Setup_11 @@ -179,14 +177,18 @@ struct _E_Randr_Serialized_Setup //List of E_Randr_Serialized_Setup_12 objects Eina_List *serialized_setups_12; //List of E_Randr_Serialized_Output_Policy objects - Eina_List *serialized_outputs_policies; + Eina_List *outputs_policies; }; EINTERN Eina_Bool e_randr_init(void); -EAPI Eina_Bool e_randr_screen_info_refresh(void); +EAPI void e_randr_screen_info_refresh(void); EINTERN int e_randr_shutdown(void); +EINTERN void e_randr_serialized_setup_free(E_Randr_Serialized_Setup *ss); +EINTERN void e_randr_11_serialized_setup_free(E_Randr_Serialized_Setup_11 *ss_11); +EINTERN void e_randr_12_serialized_setup_free(E_Randr_Serialized_Setup_12 *ss_12); +EINTERN void e_randr_12_serialized_output_policy_free(E_Randr_Serialized_Output_Policy *policy); -EAPI extern E_Randr_Screen_Info *e_randr_screen_info; +EAPI extern E_Randr_Screen_Info e_randr_screen_info; #endif #endif diff --git a/src/bin/e_randr_11.c b/src/bin/e_randr_11.c new file mode 100644 index 000000000..271db4622 --- /dev/null +++ b/src/bin/e_randr_11.c @@ -0,0 +1,103 @@ +#include "e_randr_private.h" +#include "e_randr.h" + +//New helper functions +/** + * @brief allocate and initialize a new E_Randr_Screen_Info_11 element + * @return E_Randr_Screen_Info_11 elements or in case it could + * not be created and properly initialized, NULL + */ +E_Randr_Screen_Info_11 * +_11_screen_info_new(void) +{ + E_Randr_Screen_Info_11 *randr_info_11 = NULL; + Ecore_X_Randr_Screen_Size_MM *sizes = NULL; + Ecore_X_Randr_Refresh_Rate *rates = NULL; + Eina_List *rates_list; + int i, j, nsizes, nrates; + + EINA_SAFETY_ON_TRUE_RETURN_VAL(E_RANDR_11_NO, NULL); + + randr_info_11 = malloc(sizeof(E_Randr_Screen_Info_11)); + + randr_info_11->sizes = NULL; + randr_info_11->csize_index = Ecore_X_Randr_Unset; + randr_info_11->corientation = Ecore_X_Randr_Unset; + randr_info_11->orientations = Ecore_X_Randr_Unset; + randr_info_11->rates = NULL; + randr_info_11->current_rate = Ecore_X_Randr_Unset; + + if (!(sizes = ecore_x_randr_screen_primary_output_sizes_get(e_randr_screen_info.root, &nsizes))) + goto _info_11_new_fail; + for (i = 0; i < nsizes; i++) + if (!(randr_info_11->sizes = eina_list_append(randr_info_11->sizes, &sizes[i]))) + goto _info_11_new_fail_sizes; + ecore_x_randr_screen_primary_output_current_size_get(e_randr_screen_info.root, NULL, NULL, NULL, NULL, &(randr_info_11->csize_index)); + randr_info_11->corientation = ecore_x_randr_screen_primary_output_orientation_get(e_randr_screen_info.root); + randr_info_11->orientations = ecore_x_randr_screen_primary_output_orientations_get(e_randr_screen_info.root); + for (i = 0; i < nsizes; i++) + { + rates_list = NULL; + if (!(rates = ecore_x_randr_screen_primary_output_refresh_rates_get(e_randr_screen_info.root, i, &nrates))) + return EINA_FALSE; + for (j = 0; j < nrates; j++) + if (!(rates_list = eina_list_append(rates_list, &rates[j]))) + goto _info_11_new_fail_rates_list; + if (!(randr_info_11->rates = eina_list_append(randr_info_11->rates, rates_list))) + goto _info_11_new_fail_rates; + } + randr_info_11->current_rate = ecore_x_randr_screen_primary_output_current_refresh_rate_get(e_randr_screen_info.root); + + return randr_info_11; + +_info_11_new_fail_rates_list: + eina_list_free(rates_list); +_info_11_new_fail_rates: + free(rates); +_info_11_new_fail_sizes: + free(sizes); +_info_11_new_fail: + free(randr_info_11); + return NULL; +} + +//Free helper functions +/** + * @param screen_info the screen info to be freed. + */ +void +_11_screen_info_free(E_Randr_Screen_Info_11 *screen_info) +{ + EINA_SAFETY_ON_NULL_RETURN(screen_info); + + if (screen_info->sizes) + { + free(eina_list_nth(screen_info->sizes, 0)); + eina_list_free(screen_info->sizes); + screen_info->sizes = NULL; + } + if (screen_info->rates) + { + /* this may be leaking, but at least it will be valid */ + eina_list_free(eina_list_nth(screen_info->rates, 0)); + eina_list_free(screen_info->rates); + screen_info->rates = NULL; + } + free(screen_info); + screen_info = NULL; +} + +/***************************************************************** + * + * Init. and Shutdown code + * + ***************************************************************** + */ +void +_11_screen_info_refresh(void) +{ + EINA_SAFETY_ON_TRUE_RETURN(E_RANDR_11_NO); + + _11_screen_info_free(e_randr_screen_info.rrvd_info.randr_info_11); + e_randr_screen_info.rrvd_info.randr_info_11 = _11_screen_info_new(); +} diff --git a/src/bin/e_randr_11_serialization.c b/src/bin/e_randr_11_serialization.c new file mode 100644 index 000000000..5512298f5 --- /dev/null +++ b/src/bin/e_randr_11_serialization.c @@ -0,0 +1,102 @@ +#include "e_randr_private.h" +#include "e_randr.h" + +/********************************************************************** + * + * Storage/Restorage of setups + * + ********************************************************************** + */ + +//New helper functions + + E_Randr_Serialized_Setup_11 * +_serialized_setup_11_new(void) +{ + E_Randr_Serialized_Setup_11 *ss; + Ecore_X_Randr_Screen_Size_MM *size; + + ss = malloc(sizeof(*ss)); + + if (!(size = (Ecore_X_Randr_Screen_Size_MM *)eina_list_data_get(eina_list_nth(e_randr_screen_info.rrvd_info.randr_info_11->sizes, e_randr_screen_info.rrvd_info.randr_info_11->csize_index)))) goto _serialized_setup_11_new_failed_free_ss; + ss->size.width = size->width; + ss->size.height = size->height; + ss->refresh_rate = e_randr_screen_info.rrvd_info.randr_info_11->current_rate; + ss->orientation = e_randr_screen_info.rrvd_info.randr_info_11->corientation; + + return ss; + +_serialized_setup_11_new_failed_free_ss: + free(ss); + return NULL; +} + +//Update/value set helper functions + E_Randr_Serialized_Setup_11 * +_serialized_setup_11_update(E_Randr_Serialized_Setup_11 *ss_11) +{ + Ecore_X_Randr_Screen_Size_MM *size; + + if (ss_11) + { + if (!(size = (Ecore_X_Randr_Screen_Size_MM *)eina_list_data_get(eina_list_nth(e_randr_screen_info.rrvd_info.randr_info_11->sizes, e_randr_screen_info.rrvd_info.randr_info_11->csize_index)))) return NULL; + if (!memcpy(&ss_11->size, size, sizeof(Ecore_X_Randr_Screen_Size_MM))) + goto _update_serialized_setup_11_failed_free_ss; + ss_11->refresh_rate = e_randr_screen_info.rrvd_info.randr_info_11->current_rate; + ss_11->orientation = e_randr_screen_info.rrvd_info.randr_info_11->corientation; + } + else + ss_11 = _serialized_setup_11_new(); + + return ss_11; + +_update_serialized_setup_11_failed_free_ss: + free(ss_11); + return NULL; +} + +//Free helper functions + void +_e_randr_serialized_setup_11_free(E_Randr_Serialized_Setup_11 *ss11) +{ + free(ss11); +} + +EINTERN void +e_randr_11_serialized_setup_free(E_Randr_Serialized_Setup_11 *ss_11) +{ + _e_randr_serialized_setup_11_free(ss_11); +} + + Eina_Bool +_11_try_restore_configuration(void) +{ + Ecore_X_Randr_Screen_Size_MM *stored_size, *size; + Eina_List *iter; + int i = 0; + + if (!e_config->randr_serialized_setup->serialized_setup_11) return EINA_FALSE; + stored_size = &e_config->randr_serialized_setup->serialized_setup_11->size; + EINA_LIST_FOREACH(e_randr_screen_info.rrvd_info.randr_info_11->sizes, iter, size) + { + if ((stored_size->width == size->width) + && (stored_size->height == size->height) + && (stored_size->width_mm == size->width_mm) + && (stored_size->height_mm == size->height_mm)) + { + return ecore_x_randr_screen_primary_output_size_set(e_randr_screen_info.root, i); + } + i++; + } + + return EINA_FALSE; +} + + void +_11_store_configuration(E_Randr_Configuration_Store_Modifier modifier) +{ + if (e_config->randr_serialized_setup->serialized_setup_11) + e_config->randr_serialized_setup->serialized_setup_11 = _serialized_setup_11_update(e_config->randr_serialized_setup->serialized_setup_11); + else + e_config->randr_serialized_setup->serialized_setup_11 = _serialized_setup_11_new(); +} diff --git a/src/bin/e_randr_12.c b/src/bin/e_randr_12.c new file mode 100644 index 000000000..f6a50c3ad --- /dev/null +++ b/src/bin/e_randr_12.c @@ -0,0 +1,717 @@ +#include "e.h" +#include "e_randr_private.h" + +#define POLLINTERVAL 128 + +// Set functions for the global e_randr_screen_info struct +static void _screen_primary_output_assign(E_Randr_Output_Info *removed); + +// Init helper functions +static void _outputs_init(void); +static void _crtcs_init(void); +static Eina_Bool _structs_init(void); + +// 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 +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); +static Eina_Bool _try_enable_output(E_Randr_Output_Info *output_info, Eina_Bool force); + +static Ecore_Poller *poller = NULL; +static Eina_List *_event_handlers = NULL; +const static char *_CONNECTION_STATES_STRINGS[] = {"CONNECTED", "DISCONNECTED", "UNKNOWN"}; +const static char *_POLICIES_STRINGS[] = {"ABOVE", "RIGHT", "BELOW", "LEFT", "CLONE", "NONE"}; + +//"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 + */ + static E_Randr_Screen_Info_12 * +_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, + &randr_info_12->min_size.width, + &randr_info_12->min_size.height, + &randr_info_12->max_size.width, + &randr_info_12->max_size.height); + ecore_x_randr_screen_current_size_get(e_randr_screen_info.root, + &randr_info_12->current_size.width, + &randr_info_12->current_size.height, + NULL, NULL); + + return randr_info_12; +} + + static Eina_Bool +_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]); + 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); + } + 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]); + } + + _outputs_init(); + _crtcs_init(); + + return EINA_TRUE; +} + +//Set value / retrieval helper functions + + static void +_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) + _crtc_refs_set(crtc); +} + + static void +_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) + output->monitor = _monitor_info_new(output); + } +} + + static void +_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. + */ + void +_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); + + if (screen_info->crtcs) + { + EINA_LIST_FREE (screen_info->crtcs, crtc_info) + _crtc_info_free(crtc_info); + free(eina_list_nth(screen_info->crtcs, 0)); + } + + if (screen_info->outputs) + { + EINA_LIST_FREE (screen_info->outputs, output_info) + _output_info_free(output_info); + free(eina_list_nth(screen_info->outputs, 0)); + } + + if (screen_info->modes) + { + EINA_LIST_FREE (screen_info->modes, mode_info) + ecore_x_randr_mode_info_free(mode_info); + } + + free (screen_info); +} + +/* + ********************************************* + * + * Getter functions for e_randr_screen_info struct + * + * ******************************************** + */ + Ecore_X_Randr_Mode_Info * +_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; +} + + E_Randr_Output_Info * +_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; +} + + E_Randr_Crtc_Info * +_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; +} + + Eina_Bool +_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; +} +/* + * returns a mode within a given list of modes that is gemetrically identical. + * If none is found, NULL is returned. + */ + static Ecore_X_Randr_Mode_Info * +_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 + * + ***************************************************************** + */ + void +_12_screen_info_refresh(void) +{ + EINA_SAFETY_ON_TRUE_RETURN(e_randr_screen_info.randr_version < ECORE_X_RANDR_1_2); + + _12_screen_info_free(e_randr_screen_info.rrvd_info.randr_info_12); + e_randr_screen_info.rrvd_info.randr_info_12 = _screen_info_12_new(); + _structs_init(); + _screen_primary_output_assign(NULL); +} + +/****************************************************************** + * + * Event code + * + ****************************************************************** + */ + + static Eina_Bool +_x_poll_cb(void *data __UNUSED__) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(e_randr_screen_info.rrvd_info.randr_info_12, ECORE_CALLBACK_CANCEL); + + ecore_x_randr_screen_primary_output_orientations_get(e_randr_screen_info.root); + + return ECORE_CALLBACK_RENEW; +} + + void +_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 + * + */ + static Eina_Bool +_output_change_event_cb(void *data __UNUSED__, int type, void *ev) +{ + Ecore_X_Event_Randr_Output_Change *oce = (Ecore_X_Event_Randr_Output_Change*)ev; + E_Randr_Output_Info *output_info; + E_Randr_Crtc_Info *crtc_info = NULL; + Eina_Bool policy_success = EINA_FALSE; + + EINA_SAFETY_ON_TRUE_RETURN_VAL(E_RANDR_12_NO, ECORE_CALLBACK_CANCEL); + 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; + */ + + EINA_SAFETY_ON_FALSE_RETURN_VAL((output_info = _12_screen_info_output_info_get(oce->output)), ECORE_CALLBACK_RENEW); + + fprintf(stderr, "E_RANDR: Output event: \n" + "\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\n", + oce->win, + oce->output, + oce->crtc, + oce->mode, + oce->orientation, + _CONNECTION_STATES_STRINGS[oce->connection], + oce->subpixel_order); + + 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); + } + + output_info->connection_status = oce->connection; + output_info->subpixel_order = oce->subpixel_order; + + if (output_info->connection_status != oce->connection) + { + _monitor_info_free(output_info->monitor); + output_info->monitor = NULL; + + if (oce->connection == ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED) + { + //New device connected! + output_info->monitor = _monitor_info_new(output_info); + fprintf(stderr, "E_RANDR: Output %d was newly connected.\n", output_info->xid); + + //only try to enable the monitor if there is no serialized setup + if(!_12_try_restore_configuration()) + { + policy_success = _try_enable_output(output_info, EINA_FALSE); //maybe give a success message? + fprintf(stderr, "E_RANDR: Policy \"%s\" was enforced %ssuccesfully.\n", _POLICIES_STRINGS[output_info->policy - 1], (policy_success ? "" : "un")); + } + } + 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; +} + + static Eina_Bool +_crtc_change_event_cb(void *data __UNUSED__, int type, void *ev) +{ + Ecore_X_Event_Randr_Crtc_Change *cce = (Ecore_X_Event_Randr_Crtc_Change*)ev; + E_Randr_Crtc_Info *crtc_info; + + EINA_SAFETY_ON_TRUE_RETURN_VAL(E_RANDR_12_NO, ECORE_CALLBACK_CANCEL); + EINA_SAFETY_ON_TRUE_RETURN_VAL((type != ECORE_X_EVENT_RANDR_CRTC_CHANGE), ECORE_CALLBACK_RENEW); + + /* event information: + 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; + */ + fprintf(stderr, "E_RANDR: CRTC event: \n" + "\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\n", + cce->win, + cce->crtc, + cce->mode, + cce->orientation, + cce->geo.x, + cce->geo.y, + cce->geo.w, + cce->geo.h); + + + 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) + { + _crtc_outputs_refs_set(crtc_info); + crtc_info->outputs_common_modes = _outputs_common_modes_get(crtc_info->outputs, NULL); + } + + //crop the screen + ecore_x_randr_screen_reset(e_randr_screen_info.root); + + return ECORE_CALLBACK_RENEW; +} + + static Eina_Bool +_output_property_change_event_cb(void *data __UNUSED__, int type, void *ev) +{ + Ecore_X_Event_Randr_Output_Property_Notify *opce = (Ecore_X_Event_Randr_Output_Property_Notify*)ev; + E_Randr_Output_Info *output_info; + + EINA_SAFETY_ON_TRUE_RETURN_VAL(E_RANDR_12_NO, ECORE_CALLBACK_CANCEL); + 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; + */ + 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). + */ + static Eina_Bool +_try_enable_output(E_Randr_Output_Info *output_info, Eina_Bool force) +{ + Eina_List *iter, *outputs_list = NULL, *common_modes = NULL; + E_Randr_Crtc_Info *crtc_info, *usable_crtc = NULL; + E_Randr_Output_Info *primary_output; + Ecore_X_Randr_Output *outputs; + Ecore_X_Randr_Mode_Info *mode_info; + Eina_Bool ret = EINA_FALSE; + + 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 + switch (output_info->policy) + { + case ECORE_X_RANDR_OUTPUT_POLICY_NONE: + return EINA_TRUE; + + case ECORE_X_RANDR_OUTPUT_POLICY_CLONE: + /* + * 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 + * 2a. exact mode or a + * 2b. 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 + */ + + /* + * 2a. 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); + return 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); + } + } + else + { + /* + * 2b. 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); + return 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); + } + /* + * 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); + fprintf(stderr, "Will try to set mode: %dx%d for primary and clone.\n", 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 = (ret && ecore_x_randr_crtc_mode_set(e_randr_screen_info.root, usable_crtc->xid, &output_info->xid, 1, mode_info->xid)); + ret = (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 + fprintf(stderr, "E_RANDR: Failed to clone, because of missing or disabled primary output!\n"); + /* + * 4. FAIL + */ + break; + + default: + //enable and position according to used policies + if (!(mode_info = ((Ecore_X_Randr_Mode_Info *)eina_list_data_get(output_info->monitor->preferred_modes)))) + { + fprintf(stderr, "E_RANDR: Could not enable output(%d), as it has no preferred modes (and there for none at all)!\n", output_info->xid); + ret = EINA_FALSE; + break; + } + if ((ret = ecore_x_randr_crtc_mode_set(e_randr_screen_info.root, usable_crtc->xid, &output_info->xid, 1, mode_info->xid))) + { + ret &= _crtc_move_policy(usable_crtc); + } + } + if (ret) + ecore_x_randr_screen_reset(e_randr_screen_info.root); + + return ret; +} + + void +_12_event_listeners_remove(void) +{ + Ecore_Event_Handler *_event_handler = NULL; + + EINA_LIST_FREE (_event_handlers, _event_handler) + ecore_event_handler_del(_event_handler); + ecore_poller_del(poller); + poller = NULL; +} diff --git a/src/bin/e_randr_12_crtc.c b/src/bin/e_randr_12_crtc.c new file mode 100644 index 000000000..17cec0591 --- /dev/null +++ b/src/bin/e_randr_12_crtc.c @@ -0,0 +1,333 @@ +#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; + int noutputs; + + 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) + fprintf(stderr, "E_RANDR: Could not find output struct for output %d.\n", outputs[noutputs]); + crtc_info->outputs = eina_list_append(crtc_info->outputs, output_info); + } + 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; + int npoutputs; + + 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) + fprintf(stderr, "E_RANDR: Could not find output struct for output %d.\n", poutputs[npoutputs]); + crtc_info->possible_outputs = eina_list_append(crtc_info->possible_outputs, output_info); + } + + _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); + + EINA_SAFETY_ON_TRUE_RETURN_VAL((crtc == Ecore_X_Randr_None), crtc_info); + + 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. + */ + const Eina_Bool +_crtc_move_policy(E_Randr_Crtc_Info *new_crtc) +{ + const E_Randr_Crtc_Info *crtc_rel; + E_Randr_Output_Info *first_output = NULL; + int dx = Ecore_X_Randr_None, dy = Ecore_X_Randr_None; + Eina_Bool ret = EINA_TRUE; + + //use the policy of the new crtc's first output + first_output = (E_Randr_Output_Info *)eina_list_data_get(new_crtc->outputs); + if (!first_output) + return EINA_FALSE; + //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(new_crtc, first_output->policy))) + return EINA_TRUE; + + //following is policy dependend. + switch (first_output->policy) + { + 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); + } + 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); + } + break; + + default: + break; + } + ret &= ecore_x_randr_crtc_pos_relative_set(e_randr_screen_info.root, new_crtc->xid, crtc_rel->xid, first_output->policy, e_randr_screen_info.rrvd_info.randr_info_12->alignment); + + 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; +} diff --git a/src/bin/e_randr_12_output.c b/src/bin/e_randr_12_output.c new file mode 100644 index 000000000..49b7b98d7 --- /dev/null +++ b/src/bin/e_randr_12_output.c @@ -0,0 +1,233 @@ +#include "e_randr_private.h" +#include "e_randr.h" + +E_Randr_Monitor_Info *_monitor_info_new(E_Randr_Output_Info *output_info); +static int _modes_size_sort_cb(const void *d1, const void *d2); + +void +_monitor_modes_refs_set(E_Randr_Monitor_Info *mi, Ecore_X_Randr_Output o) +{ + Ecore_X_Randr_Mode *modes = NULL; + Ecore_X_Randr_Mode_Info *mode_info = NULL; + int nmodes, npreferred; + + EINA_SAFETY_ON_NULL_RETURN(mi); + EINA_SAFETY_ON_TRUE_RETURN(o == Ecore_X_Randr_None); + + // Add (preferred) modes + modes = ecore_x_randr_output_modes_get(e_randr_screen_info.root, o, &nmodes, &npreferred); + while (--nmodes >= 0) + { + if (!(mode_info = _12_screen_info_mode_info_get(modes[nmodes]))) + { + //Mode unknown to the global structure, so add it + mode_info = ecore_x_randr_mode_info_get(e_randr_screen_info.root, modes[nmodes]); + 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); + } + mi->modes = eina_list_append(mi->modes, mode_info); + if (nmodes >= npreferred) + mi->preferred_modes = eina_list_append(mi->preferred_modes, mode_info); + } + free(modes); +} + +/** + * @brief Allocates a new E_Randr_Monitor_Info struct and initializes it with + * default values. + * @return E_Randr_Monitor_Info element, or if it could not be + * created, NULL + */ +E_Randr_Monitor_Info * +_monitor_info_new(E_Randr_Output_Info *oi) +{ + E_Randr_Monitor_Info *mi = NULL; + + EINA_SAFETY_ON_NULL_RETURN_VAL(oi, NULL); + + mi = E_NEW(E_Randr_Monitor_Info, 1); + + // Set some default values + mi->modes = NULL; + mi->preferred_modes = NULL; + mi->size_mm.width = Ecore_X_Randr_Unset; + mi->size_mm.height = Ecore_X_Randr_Unset; + mi->edid = NULL; + mi->edid_length = 0; + mi->edid_hash.hash = 0; + mi->max_backlight = Ecore_X_Randr_Unset; + mi->backlight_level = 0.0; + + _monitor_modes_refs_set(mi, oi->xid); + + ecore_x_randr_output_size_mm_get(e_randr_screen_info.root, oi->xid, &mi->size_mm.width, &mi->size_mm.height); + mi->edid = ecore_x_randr_output_edid_get(e_randr_screen_info.root, oi->xid, &mi->edid_length); + if (mi->edid_length > 0) + mi->edid_hash.hash = eina_hash_superfast((char *)mi->edid, mi->edid_length); + + return mi; +} + +/** + * @brief Frees E_Randr_Monitor_Info structure + */ +void +_monitor_info_free(E_Randr_Monitor_Info *monitor_info) +{ + if (!monitor_info) + return; + + eina_list_free(monitor_info->modes); + eina_list_free(monitor_info->preferred_modes); + free(monitor_info->edid); + free(monitor_info); +} + +/** + * @brief allocates a struct and fills it with default values. + * @param output the output the display is queried for. If Ecore_X_Randr_None is + * given, a struct with only the xid will be set + * @return E_Randr_Output_Info element + */ +E_Randr_Output_Info * +_output_info_new(Ecore_X_Randr_Output output) +{ + E_Randr_Output_Info *output_info = NULL; + + EINA_SAFETY_ON_TRUE_RETURN_VAL(E_RANDR_12_NO, NULL); + EINA_SAFETY_ON_TRUE_RETURN_VAL((output == Ecore_X_Randr_None), NULL); + + output_info = malloc(sizeof(E_Randr_Output_Info)); + + output_info->xid = output; + + //Use default values + output_info->crtc = NULL; + output_info->wired_clones = NULL; + output_info->possible_crtcs = NULL; + output_info->signalformats = Ecore_X_Randr_Unset; + output_info->signalformat = Ecore_X_Randr_Unset; + output_info->connector_number = 0; + output_info->connector_type = Ecore_X_Randr_Unset; + output_info->policy = ECORE_X_RANDR_OUTPUT_POLICY_NONE; + output_info->compatibility_list = NULL; + output_info->subpixel_order = Ecore_X_Randr_Unset; + + output_info->name = ecore_x_randr_output_name_get(e_randr_screen_info.root, output_info->xid, &output_info->name_length); + output_info->connection_status = ecore_x_randr_output_connection_status_get(e_randr_screen_info.root, output_info->xid); + + return output_info; +} + +void +_output_info_free(E_Randr_Output_Info *output_info) +{ + EINA_SAFETY_ON_NULL_RETURN(output_info); + + eina_list_free(output_info->wired_clones); + eina_list_free(output_info->possible_crtcs); + eina_list_free(output_info->compatibility_list); + free(output_info->name); + _monitor_info_free(output_info->monitor); + output_info->monitor = NULL; + free(output_info); +} + +void +_output_refs_set(E_Randr_Output_Info *output_info) +{ + Ecore_X_Randr_Crtc crtc, *crtcs = NULL; + E_Randr_Crtc_Info *crtc_info; + int ncrtcs = 0; + + EINA_SAFETY_ON_TRUE_RETURN(E_RANDR_12_NO); + EINA_SAFETY_ON_NULL_RETURN(output_info); + + eina_list_free(output_info->possible_crtcs); + + //Add possible crtcs + crtcs = ecore_x_randr_output_possible_crtcs_get(e_randr_screen_info.root, output_info->xid, &ncrtcs); + while (--ncrtcs >= 0) + { + if (!(crtc_info = _12_screen_info_crtc_info_get(crtcs[ncrtcs]))) + continue; + output_info->possible_crtcs = eina_list_append(output_info->possible_crtcs, crtc_info); + } + free(crtcs); + + crtc = ecore_x_randr_output_crtc_get(e_randr_screen_info.root, output_info->xid); + output_info->crtc = _12_screen_info_crtc_info_get(crtc); + + if (output_info->connection_status == ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED) + output_info->monitor = _monitor_info_new(output_info); + else + output_info->monitor = NULL; +} + + Ecore_X_Randr_Output * +_outputs_to_array(Eina_List *outputs_info) +{ + Ecore_X_Randr_Output *ret = NULL; + E_Randr_Output_Info *output_info; + Eina_List *output_iter; + int i = 0; + + if (!outputs_info || !(ret = malloc(sizeof(Ecore_X_Randr_Output) * eina_list_count(outputs_info)))) return NULL; + EINA_LIST_FOREACH(outputs_info, output_iter, output_info) + /* output_info == NULL should _not_ be possible! */ + ret[i++] = output_info ? output_info->xid : Ecore_X_Randr_None; + return ret; +} + +/* + * returns a list of modes common ammongst the given outputs, + * optionally limited by max_size_mode. If none are found, NULL is returned. + */ +Eina_List +*_outputs_common_modes_get(Eina_List *outputs, Ecore_X_Randr_Mode_Info *max_size_mode) +{ + Eina_List *common_modes = NULL, *mode_iter, *output_iter; + E_Randr_Output_Info *output_info; + Ecore_X_Randr_Mode_Info *mode_info; + + EINA_SAFETY_ON_NULL_RETURN_VAL(outputs, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(e_randr_screen_info.rrvd_info.randr_info_12->modes, NULL); + + //create a list of all common modes + common_modes = eina_list_clone(e_randr_screen_info.rrvd_info.randr_info_12->modes); + common_modes = eina_list_sort(common_modes, 0, _modes_size_sort_cb); + + EINA_LIST_FOREACH(common_modes, mode_iter, mode_info) + { + EINA_LIST_FOREACH(outputs, output_iter, output_info) + { + if (!eina_list_data_find(output_info->monitor->modes, mode_info)) + common_modes = eina_list_remove(common_modes, mode_info); + } + } + + if (max_size_mode) + { + //remove all modes that are larger than max_size_mode + EINA_LIST_FOREACH(common_modes, mode_iter, mode_info) + { + if (_modes_size_sort_cb((void *)max_size_mode, (void *)mode_info) < 0) + common_modes = eina_list_remove(common_modes, mode_info); + } + } + + //sort modes desc. by their sizes + common_modes = eina_list_reverse(common_modes); + + return common_modes; +} + + static int +_modes_size_sort_cb(const void *d1, const void *d2) +{ + Ecore_X_Randr_Mode_Info *mode1 = ((Ecore_X_Randr_Mode_Info *)d1), *mode2 = ((Ecore_X_Randr_Mode_Info *)d2); + + EINA_SAFETY_ON_NULL_RETURN_VAL(d1, 1); + EINA_SAFETY_ON_NULL_RETURN_VAL(d2, -1); + + return (mode1->width * mode1->height) - (mode2->width * mode2->height); +} diff --git a/src/bin/e_randr_12_serialization.c b/src/bin/e_randr_12_serialization.c new file mode 100644 index 000000000..9963bb455 --- /dev/null +++ b/src/bin/e_randr_12_serialization.c @@ -0,0 +1,594 @@ +#include "e_randr_private.h" +#include "e_randr.h" + +#define MODE_STR_LENGTH_MAX 100 + +const static char *_POLICIES_STRINGS[] = {"ABOVE", "RIGHT", "BELOW", "LEFT", "CLONE", "NONE"}; + +static E_Randr_Serialized_Crtc *_serialized_crtc_new(E_Randr_Crtc_Info *crtc_info); +static inline int _sort_by_number_of_edids(const void *d1, const void *d2); +static inline Eina_List *_find_matching_outputs(Eina_List *sois); +static inline E_Randr_Crtc_Info *_find_matching_crtc(E_Randr_Serialized_Crtc *sc); +static inline Ecore_X_Randr_Mode_Info *_find_matching_mode_info(Ecore_X_Randr_Mode_Info *mode); + +/********************************************************************** + * + * Storage/Restorage of setups + * + ********************************************************************** + */ + +/* + * Layout: + * + * Serialized_Setup_12 { + * - timestamp + * - List + * - List + * } + * Serialized_Crtc { + * - index + * - List + * - pos + * - orientation + * - mode + * } + * Serialized_Output { + * - name + * - name_length + * - serialized_edid + * - backlight_level + * } + * Serialized_EDID { + * - edid_hash + * } + * + */ +//"Free" helper functions + + void +_serialized_output_free(E_Randr_Serialized_Output *so) +{ + EINA_SAFETY_ON_NULL_RETURN(so); + + free(so); +} + + void +_serialized_output_policy_free(E_Randr_Serialized_Output_Policy *sop) +{ + EINA_SAFETY_ON_NULL_RETURN(sop); + + free(sop->name); + free(sop); +} + +EINTERN void +e_randr_12_serialized_output_policy_free(E_Randr_Serialized_Output_Policy *policy) +{ + _serialized_output_policy_free(policy); +} + + void +_serialized_mode_info_free(Ecore_X_Randr_Mode_Info *mode_info) +{ + EINA_SAFETY_ON_NULL_RETURN(mode_info); + + free(mode_info->name); +} + + void +_serialized_crtc_free(E_Randr_Serialized_Crtc *sc) +{ + E_Randr_Serialized_Output *so; + + EINA_SAFETY_ON_NULL_RETURN(sc); + + EINA_LIST_FREE (sc->outputs, so) + _serialized_output_free(so); + _serialized_mode_info_free(&sc->mode_info); + free(sc); +} + +//"New" helper functions + +/** + * @brief Seeks given data in the list and returns the index + * of the first element equaling @data + * @param list The list to be examined + * @param data The data to be found + * @return if found, the index of the list node. Else -1. + */ +int +_eina_list_data_index_get(const Eina_List *list, const void *data) +{ + Eina_List *iter; + void *ndata; + int i = 0; + + EINA_LIST_REVERSE_FOREACH(list, iter, ndata) + { + if (ndata == data) + return i; + else + i++; + } + + return -1; +} + +void +_mode_info_clone(Ecore_X_Randr_Mode_Info *dst, const Ecore_X_Randr_Mode_Info *src) +{ + EINA_SAFETY_ON_NULL_RETURN(dst); + + if (!src) + { + dst->xid = Ecore_X_Randr_None; + dst->name = NULL; + return; + } + + dst->xid = src->xid; + dst->width = src->width; + dst->height = src->height; + dst->dotClock = src->dotClock; + dst->hSyncStart = src->hSyncStart; + dst->hSyncEnd = src->hSyncEnd; + dst->hTotal = src->hTotal; + dst->hSkew = src->hSkew; + dst->vSyncStart = src->vSyncStart; + dst->vSyncEnd = src->vSyncEnd; + dst->vTotal = src->vTotal; + if (src->nameLength > 0) + { + dst->name = malloc(src->nameLength + 1); + strncpy(dst->name, src->name, src->nameLength); + } + dst->nameLength = src->nameLength; + dst->modeFlags = src->modeFlags; +} + +E_Randr_Edid_Hash +*_monitor_edid_hash_clone(E_Randr_Monitor_Info *mi) +{ + E_Randr_Edid_Hash *edid_hash; + + EINA_SAFETY_ON_NULL_RETURN_VAL(mi, NULL); + EINA_SAFETY_ON_TRUE_RETURN_VAL((mi->edid_hash.hash == 0), NULL); + edid_hash = malloc(sizeof(E_Randr_Edid_Hash)); + + edid_hash->hash = mi->edid_hash.hash; + + return edid_hash; +} + + Eina_List * +_outputs_policies_list_new(Eina_List *outputs) +{ + E_Randr_Serialized_Output_Policy *sop; + Eina_List *iter, *list = NULL; + E_Randr_Output_Info *oi; + + EINA_SAFETY_ON_NULL_RETURN_VAL(outputs, NULL); + + EINA_LIST_FOREACH(outputs, iter, oi) + { + if (!oi->name) continue; + + sop = E_NEW(E_Randr_Serialized_Output_Policy, 1); + sop->name = malloc(oi->name_length + 1); + strncpy(sop->name, oi->name, oi->name_length); + sop->policy = oi->policy; + list = eina_list_append(list, sop); + } + + return list; +} + + E_Randr_Serialized_Output * +_serialized_output_new(E_Randr_Output_Info *output_info) +{ + E_Randr_Serialized_Output *so; + + EINA_SAFETY_ON_NULL_RETURN_VAL(output_info, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(output_info->name, NULL); + + so = E_NEW(E_Randr_Serialized_Output, 1); + + so->name = malloc(output_info->name_length + 1); + strncpy(so->name, output_info->name, output_info->name_length); + if (output_info->monitor) + { + so->backlight_level = output_info->monitor->backlight_level; + } + else + { + so->backlight_level = Ecore_X_Randr_Unset; + } + + return so; +} + + E_Randr_Serialized_Crtc * +_serialized_crtc_new(E_Randr_Crtc_Info *crtc_info) +{ + E_Randr_Serialized_Crtc *sc = NULL; + E_Randr_Serialized_Output *so = NULL; + E_Randr_Output_Info *output_info = NULL; + Eina_List *iter; + + EINA_SAFETY_ON_NULL_RETURN_VAL(crtc_info, NULL); + + sc = E_NEW(E_Randr_Serialized_Crtc, 1); + + //Get relative index of CRTC + sc->index = _eina_list_data_index_get(e_randr_screen_info.rrvd_info.randr_info_12->crtcs, crtc_info); + //Create list of serialized outputs + EINA_LIST_FOREACH(crtc_info->outputs, iter, output_info) + { + if (!(so = _serialized_output_new(output_info))) + continue; + sc->outputs = eina_list_append(sc->outputs, so); + fprintf(stderr, "E_RANDR:\t Serialized output %s.\n", so->name); + } + sc->pos.x = crtc_info->geometry.x; + sc->pos.y = crtc_info->geometry.y; + sc->orientation = crtc_info->current_orientation; + //Clone mode + _mode_info_clone(&sc->mode_info, crtc_info->current_mode); + + return sc; +} + + E_Randr_Serialized_Setup_12 * +_12_serialized_setup_new(void) +{ + E_Randr_Serialized_Setup_12 *ss = NULL; + Eina_List *iter; + E_Randr_Crtc_Info *ci; + E_Randr_Output_Info *oi; + E_Randr_Serialized_Crtc *sc; + E_Randr_Edid_Hash *edid_hash; + + EINA_SAFETY_ON_TRUE_RETURN_VAL(E_RANDR_12_NO, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(e_randr_screen_info.rrvd_info.randr_info_12->outputs, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(e_randr_screen_info.rrvd_info.randr_info_12->crtcs, NULL); + + ss = E_NEW(E_Randr_Serialized_Setup_12, 1); + + ss->timestamp = ecore_time_get(); + + //Add CRTCs and their configuration + EINA_LIST_FOREACH(e_randr_screen_info.rrvd_info.randr_info_12->crtcs, iter, ci) + { + sc = _serialized_crtc_new(ci); + if (!sc) + continue; + ss->crtcs = eina_list_append(ss->crtcs, sc); + fprintf(stderr, "E_RANDR: Serialized CRTC %d (index %d) in mode %s.\n", ci->xid, sc->index, sc->mode_info.name ? sc->mode_info.name : "(disabled)"); + } + + /* + * Add EDID hashes of connected outputs + * for easier comparison during + * setup restoration + */ + EINA_LIST_FOREACH(e_randr_screen_info.rrvd_info.randr_info_12->outputs, iter, oi) + { + if (oi->connection_status != ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED) + continue; + edid_hash = _monitor_edid_hash_clone(oi->monitor); + ss->edid_hashes = eina_list_append(ss->edid_hashes, edid_hash); + } + + return ss; +} + +//Update (also retrieval) helper functions + + E_Randr_Serialized_Setup_12 * +_matching_serialized_setup_get(Eina_List *setups_12) +{ + E_Randr_Serialized_Setup_12 *ss_12; + Eina_List *setups_iter, *edid_iter; + E_Randr_Edid_Hash *edid_hash; + + EINA_SAFETY_ON_TRUE_RETURN_VAL(E_RANDR_12_NO, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(setups_12, NULL); + + //Sort list of setups by the number of monitors involved + setups_12 = eina_list_sort(setups_12, 0, _sort_by_number_of_edids); + + EINA_LIST_FOREACH(setups_12, setups_iter, ss_12) + { + //1. Make sure: #outputs >= #serialized EDIDs + if (eina_list_count(e_randr_screen_info.rrvd_info.randr_info_12->outputs) < eina_list_count(ss_12->edid_hashes)) + continue; + //2. Compare #CRTCs + if (eina_list_count(e_randr_screen_info.rrvd_info.randr_info_12->crtcs) != eina_list_count(ss_12->crtcs)) + continue; + + //3. Find all serialized EDIDs + EINA_LIST_FOREACH(ss_12->edid_hashes, edid_iter, edid_hash) + { + if (!_12_screen_info_edid_is_available(edid_hash)) + goto _setup_12_skip; + } + + //4. All EDIDs found? Great, let's go! + return ss_12; +_setup_12_skip: + continue; + } + + // None found! + return NULL; +} + + Eina_List * +_outputs_policies_update(Eina_List *sops) +{ + E_Randr_Serialized_Output_Policy *sop; + + EINA_LIST_FREE (sops, sop) + { + _serialized_output_policy_free(sop); + } + + return _outputs_policies_list_new(e_randr_screen_info.rrvd_info.randr_info_12->outputs); +} + + Eina_List * +_12_serialized_setup_update(Eina_List *setups_12) +{ + E_Randr_Serialized_Setup_12 *ss_12; + + if (setups_12) + { + /* + * try to find the setup with the same monitors + * connected in order to replace it + */ + if ((ss_12 = _matching_serialized_setup_get(setups_12))) + { + _12_serialized_setup_free(ss_12); + setups_12 = eina_list_remove(setups_12, ss_12); + } + } + ss_12 = _12_serialized_setup_new(); + setups_12 = eina_list_append(setups_12, ss_12); + + return setups_12; +} + + void +_12_policies_restore(void) +{ + E_Randr_Output_Info *output; + E_Randr_Serialized_Output_Policy *sop; + Eina_List *iter, *iter2; + + EINA_SAFETY_ON_TRUE_RETURN(E_RANDR_12_NO); + EINA_SAFETY_ON_NULL_RETURN(e_config->randr_serialized_setup); + EINA_SAFETY_ON_NULL_RETURN(e_config->randr_serialized_setup->outputs_policies); + + // Restore policies + EINA_LIST_FOREACH(e_randr_screen_info.rrvd_info.randr_info_12->outputs, iter, output) + { + EINA_LIST_FOREACH(e_config->randr_serialized_setup->outputs_policies, iter2, sop) + { + if (!strncmp(sop->name, output->name, output->name_length)) + { + output->policy = sop->policy; + fprintf(stderr, "E_RANDR: Policy \"%s\" for output \"%s\" restored.\n", _POLICIES_STRINGS[sop->policy - 1], output->name); + } + } + } +} + + Eina_Bool +_12_try_restore_configuration(void) +{ + E_Randr_Serialized_Setup_12 *ss_12; + E_Randr_Serialized_Crtc *sc; + E_Randr_Crtc_Info *ci; + Ecore_X_Randr_Output *outputs_array; + E_Randr_Output_Info *output_info; + Ecore_X_Randr_Mode_Info *mi; + Ecore_X_Randr_Mode mode; + Eina_List *iter, *outputs_list, *outputs_iter; + Eina_Bool ret = EINA_TRUE; + + EINA_SAFETY_ON_NULL_RETURN_VAL(e_config, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(e_config->randr_serialized_setup, EINA_FALSE); + + if (!(ss_12 = _matching_serialized_setup_get(e_config->randr_serialized_setup->serialized_setups_12))) + return EINA_FALSE; + + fprintf(stderr, "E_RANDR: Found matching serialized setup.\n"); + EINA_LIST_FOREACH(ss_12->crtcs, iter, sc) + { + ci = _find_matching_crtc(sc); + outputs_list = _find_matching_outputs(sc->outputs); + outputs_array = _outputs_to_array(outputs_list); + fprintf(stderr, "E_RANDR: \tSerialized mode "); + if (sc->mode_info.xid == Ecore_X_Randr_None) + { + fprintf(stderr, "was disabled.\n"); + mode = Ecore_X_Randr_None; + } + else if ((mi = _find_matching_mode_info(&sc->mode_info))) + { + fprintf(stderr, "is now known under the name %s.\n", mi->name); + mode = mi->xid; + } + else + { + // The serialized mode is no longer available + mi->name = malloc(MODE_STR_LENGTH_MAX); + //IMPROVABLE: Use random string, like mktemp for files + snprintf(mi->name, (MODE_STR_LENGTH_MAX - 1), "%ux%u,%lu,%lu", sc->mode_info.width, sc->mode_info.height, sc->mode_info.dotClock, sc->mode_info.modeFlags); + mi = &sc->mode_info; + mode = ecore_x_randr_mode_info_add(e_randr_screen_info.root, mi); + if (mode == Ecore_X_Randr_None) + { + eina_list_free(outputs_list); + free(outputs_array); + continue; + } + EINA_LIST_FOREACH(outputs_list, outputs_iter, output_info) + ecore_x_randr_output_mode_add(output_info->xid, mode); + fprintf(stderr, "was now added to the server manually using the name %s.\n", mi->name); + } + + // DEBUG + fprintf(stderr, "E_RANDR: \tRestoring CRTC %d (index %d) in mode %s.\n", ci->xid, sc->index, (mode == Ecore_X_Randr_None) ? "(disabled)" : mi->name); + fprintf(stderr, "E_RANDR: \t\tUsed outputs:"); + EINA_LIST_FOREACH(outputs_list, outputs_iter, output_info) + fprintf(stderr, " %s", output_info->name); + fprintf(stderr, ".\n"); + // DEBUG END + + ret &= ecore_x_randr_crtc_mode_set(e_randr_screen_info.root, ci->xid, outputs_array, eina_list_count(outputs_list), mode); + eina_list_free(outputs_list); + free(outputs_array); + ret &= ecore_x_randr_crtc_pos_set(e_randr_screen_info.root, ci->xid, sc->pos.x, sc->pos.y); + ret &= ecore_x_randr_crtc_orientation_set(e_randr_screen_info.root, ci->xid, sc->orientation); + } + return ret; +} + + void +_12_serialized_setup_free(E_Randr_Serialized_Setup_12 *ss_12) +{ + E_Randr_Serialized_Crtc *sc; + E_Randr_Edid_Hash *edid_hash; + + if (!ss_12) return; + + EINA_LIST_FREE (ss_12->crtcs, sc) + { + _serialized_crtc_free(sc); + } + EINA_LIST_FREE (ss_12->edid_hashes, edid_hash) + free(edid_hash); + + free(ss_12); +} + +EINTERN void +e_randr_12_serialized_setup_free(E_Randr_Serialized_Setup_12 *ss_12) +{ + _12_serialized_setup_free(ss_12); +} + + void +_12_store_configuration(E_Randr_Configuration_Store_Modifier modifier) +{ + if (modifier & (E_RANDR_CONFIGURATION_STORE_RESOLUTIONS | E_RANDR_CONFIGURATION_STORE_ARRANGEMENT | E_RANDR_CONFIGURATION_STORE_ORIENTATIONS)) + { + e_config->randr_serialized_setup->serialized_setups_12 = _12_serialized_setup_update(e_config->randr_serialized_setup->serialized_setups_12); + } + + if (modifier & E_RANDR_CONFIGURATION_STORE_POLICIES) + { + //update output policies + e_config->randr_serialized_setup->outputs_policies = _outputs_policies_update(e_config->randr_serialized_setup->outputs_policies); + } +} + +//Retrievel functions for the current e_randr_screen_info context + +// Find entities for restoration in current e_randr_screen_info context + static E_Randr_Crtc_Info * +_find_matching_crtc(E_Randr_Serialized_Crtc *sc) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(sc, NULL); + EINA_SAFETY_ON_TRUE_RETURN_VAL(E_RANDR_12_NO, NULL); + + return eina_list_nth(e_randr_screen_info.rrvd_info.randr_info_12->crtcs, sc->index); +} + +/** + * @brief Creates list of E_Randr_Output_Info* elements for list of + * E_Randr_Serialized_Output* objects. + * @param sois list of E_Randr_Serialized_Output* elements + * @return List of E_Randr_Output* elements or NULL, if not all outputs could be + * found or monitors are connected to different outputs + */ + static Eina_List * +_find_matching_outputs(Eina_List *sois) +{ + Eina_List *r_output_iter, *s_output_iter, *list = NULL; + E_Randr_Output_Info *oi; + E_Randr_Serialized_Output *so; + + EINA_LIST_FOREACH(sois, s_output_iter, so) + { + fprintf(stderr, "E_RANDR: \tLooking for serialized output \"%s\"\n", so->name); + EINA_LIST_FOREACH(e_randr_screen_info.rrvd_info.randr_info_12->outputs, r_output_iter, oi) + { + fprintf(stderr, "E_RANDR: \t\tComparing to output \"%s\"\n", oi->name); + if (!strncmp(so->name, oi->name, oi->name_length)) + { + + list = eina_list_append(list, oi); + break; + } + } + } + if (list && (eina_list_count(sois) != eina_list_count(list))) + { + eina_list_free(list); + list = NULL; + } + + return list; +} + + static Ecore_X_Randr_Mode_Info * +_find_matching_mode_info(Ecore_X_Randr_Mode_Info *mode) +{ + Eina_List *iter; + Ecore_X_Randr_Mode_Info *mi = NULL; + + EINA_LIST_FOREACH(e_randr_screen_info.rrvd_info.randr_info_12->modes, iter, mi) + { + if (!strncmp(mode->name, mi->name, mode->nameLength)) + return mi; + } + EINA_LIST_FOREACH(e_randr_screen_info.rrvd_info.randr_info_12->modes, iter, mi) + { +#define EQL(arg) (mi->arg == mode->arg) + if (EQL(width) && + EQL(height) && + EQL(dotClock) && + EQL(hSyncStart) && + EQL(hSyncEnd) && + EQL(hTotal) && + EQL(hSkew) && + EQL(vSyncStart) && + EQL(vSyncEnd) && + EQL(vTotal) && + EQL(modeFlags)) + return mi; +#undef EQL + } + return NULL; +} + + static int +_sort_by_number_of_edids(const void *d1, const void *d2) +{ + const E_Randr_Serialized_Setup_12 *ss1 = (const E_Randr_Serialized_Setup_12*)d1; + const E_Randr_Serialized_Setup_12 *ss2 = (const E_Randr_Serialized_Setup_12*)d1; + + EINA_SAFETY_ON_NULL_RETURN_VAL(ss1, 1); + EINA_SAFETY_ON_NULL_RETURN_VAL(ss2, -1); + + if (eina_list_count(ss2->edid_hashes) > eina_list_count(ss1->edid_hashes)) + return 1; + else + return -1; +} diff --git a/src/bin/e_randr_private.h b/src/bin/e_randr_private.h new file mode 100644 index 000000000..3c63d22b0 --- /dev/null +++ b/src/bin/e_randr_private.h @@ -0,0 +1,68 @@ +#ifdef E_TYPEDEFS + +#else +#ifndef E_RANDR_PRIVATE_H +#define E_RANDR_PRIVATE_H + +#include "e.h" + +#define ECORE_X_RANDR_1_1 ((1 << 16) | 1) +#define ECORE_X_RANDR_1_2 ((1 << 16) | 2) +#define ECORE_X_RANDR_1_3 ((1 << 16) | 3) + +#define Ecore_X_Randr_Unset -1 +#define Ecore_X_Randr_None 0 + +#define E_RANDR_11_NO ((e_randr_screen_info.randr_version < ECORE_X_RANDR_1_1) || !e_randr_screen_info.rrvd_info.randr_info_11) +#define E_RANDR_12_NO ((e_randr_screen_info.randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info.rrvd_info.randr_info_12) +#define E_RANDR_12_NO_CRTCS (E_RANDR_12_NO || !e_randr_screen_info.rrvd_info.randr_info_12->crtcs) +#define E_RANDR_12_NO_CRTC(crtc) (E_RANDR_12_NO || !e_randr_screen_info.rrvd_info.randr_info_12->crtcs || (crtc == Ecore_X_Randr_None)) +#define E_RANDR_12_NO_OUTPUTS (E_RANDR_12_NO || !e_randr_screen_info.rrvd_info.randr_info_12->outputs) +#define E_RANDR_12_NO_OUTPUT(output) (E_RANDR_12_NO || !e_randr_screen_info.rrvd_info.randr_info_12->outputs || (output == Ecore_X_Randr_None)) +#define E_RANDR_12_NO_MODES (E_RANDR_12_NO || !e_randr_screen_info.rrvd_info.randr_info_12->modes) +#define E_RANDR_12_NO_MODE(mode) (E_RANDR_12_NO || !e_randr_screen_info.rrvd_info.randr_info_12->modes || (mode == Ecore_X_Randr_None)) + +// RandRR == 1.1 +E_Randr_Screen_Info_11 *_11_screen_info_new(void); +void _11_screen_info_free(E_Randr_Screen_Info_11 *screen_info_11); +void _11_screen_info_refresh(void); +Eina_Bool _11_try_restore_configuration(void); +void _11_store_configuration(E_Randr_Configuration_Store_Modifier modifier); + +// RandRR >= 1.2 +E_Randr_Screen_Info_12 *_12_screen_info_new(void); +void _12_screen_info_free(E_Randr_Screen_Info_12 *screen_info_12); +void _12_screen_info_refresh(void); +void _12_policies_restore(void); +void _12_event_listeners_add(void); +void _12_event_listeners_remove(void); +// Retrieval functions +Ecore_X_Randr_Mode_Info *_12_screen_info_mode_info_get(const Ecore_X_Randr_Mode mode); +E_Randr_Crtc_Info *_12_screen_info_crtc_info_get(const Ecore_X_Randr_Crtc crtc); +E_Randr_Output_Info *_12_screen_info_output_info_get(const Ecore_X_Randr_Output output); +Eina_Bool _12_screen_info_edid_is_available(const E_Randr_Edid_Hash *hash); +// (Re)store data +E_Randr_Serialized_Setup_12 *_12_serialized_setup_new(void); +void _12_serialized_setup_free(E_Randr_Serialized_Setup_12 *ss_12); +Eina_Bool _12_try_restore_configuration(void); +void _12_store_configuration(E_Randr_Configuration_Store_Modifier modifier); + +// >= 1.2 Substructures helper functions +E_Randr_Monitor_Info *_monitor_info_new(E_Randr_Output_Info *output_info); +void _monitor_info_free(E_Randr_Monitor_Info *monitor_info); +void _monitor_modes_refs_set(E_Randr_Monitor_Info *mi, Ecore_X_Randr_Output output); +E_Randr_Output_Info *_output_info_new(Ecore_X_Randr_Output output); +void _output_info_free(E_Randr_Output_Info *output_info); +void _output_refs_set(E_Randr_Output_Info *output_info); +Ecore_X_Randr_Output *_outputs_to_array(Eina_List *outputs_info); +Eina_List *_outputs_common_modes_get(Eina_List *outputs, Ecore_X_Randr_Mode_Info *max_size_mode); + +E_Randr_Crtc_Info * _crtc_info_new(Ecore_X_Randr_Crtc crtc); +void _crtc_info_free(E_Randr_Crtc_Info *crtc_info); +void _crtc_refs_set(E_Randr_Crtc_Info *crtc_info); +void _crtc_outputs_refs_set(E_Randr_Crtc_Info *crtc_info); +const Eina_Bool _crtc_move_policy(E_Randr_Crtc_Info *new_crtc); +const E_Randr_Crtc_Info *_crtc_according_to_policy_get(E_Randr_Crtc_Info *but, Ecore_X_Randr_Output_Policy policy); + +#endif +#endif diff --git a/src/bin/e_randr_serialization.c b/src/bin/e_randr_serialization.c new file mode 100644 index 000000000..ba5fb9138 --- /dev/null +++ b/src/bin/e_randr_serialization.c @@ -0,0 +1,74 @@ +#include "e_randr_private.h" +#include "e_randr.h" + +#define ECORE_X_RANDR_1_1 ((1 << 16) | 1) +#define ECORE_X_RANDR_1_2 ((1 << 16) | 2) +#define ECORE_X_RANDR_1_3 ((1 << 16) | 3) + +/********************************************************************** + * + * Storage/Restorage of setups + * + ********************************************************************** + */ + + E_Randr_Serialized_Setup * +_new_serialized_setup(void) +{ + return E_NEW(E_Randr_Serialized_Setup, 1); +} + + EAPI void +e_randr_store_configuration(E_Randr_Configuration_Store_Modifier modifier) +{ + if (!e_config->randr_serialized_setup) + e_config->randr_serialized_setup = _new_serialized_setup(); + + fprintf(stderr, "E_RANDR: Configuration shall be stored using the following modifier: %d.\n", modifier); + + if (e_randr_screen_info.randr_version == ECORE_X_RANDR_1_1) + { + _11_store_configuration(modifier); + } + else if (e_randr_screen_info.randr_version >= ECORE_X_RANDR_1_2) + { + _12_store_configuration(modifier); + } + e_config_save_queue(); +} + +Eina_Bool +_try_restore_configuration(void) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(e_config, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(e_config->randr_serialized_setup, EINA_FALSE); + + if (e_randr_screen_info.randr_version == ECORE_X_RANDR_1_1) + return _11_try_restore_configuration(); + else if (e_randr_screen_info.randr_version >= ECORE_X_RANDR_1_2) + return _12_try_restore_configuration(); + + return EINA_FALSE; +} + +EINTERN void e_randr_serialized_setup_free(E_Randr_Serialized_Setup *ss) +{ + E_Randr_Serialized_Setup_12 *serialized_setup_12 = NULL; + E_Randr_Serialized_Output_Policy *serialized_output_policy = NULL; + + EINA_SAFETY_ON_NULL_RETURN(ss); + + e_randr_11_serialized_setup_free(ss->serialized_setup_11); + if (ss->serialized_setups_12) + { + EINA_LIST_FREE(ss->serialized_setups_12, serialized_setup_12) + { + e_randr_12_serialized_setup_free(serialized_setup_12); + } + } + EINA_LIST_FREE(ss->outputs_policies, serialized_output_policy) + { + e_randr_12_serialized_output_policy_free(serialized_output_policy); + } + free(ss); +}