diff --git a/configure.ac b/configure.ac index b93bda440..e9865bd1d 100644 --- a/configure.ac +++ b/configure.ac @@ -745,6 +745,7 @@ AC_E_OPTIONAL_MODULE([comp], true) AC_E_OPTIONAL_MODULE([shot], true) AC_E_OPTIONAL_MODULE([backlight], true) AC_E_OPTIONAL_MODULE([tasks], true) +AC_E_OPTIONAL_MODULE([conf_randr], true) SUSPEND="" HIBERNATE="" @@ -843,6 +844,8 @@ src/modules/conf_interaction/Makefile src/modules/conf_interaction/module.desktop src/modules/msgbus/Makefile src/modules/msgbus/module.desktop +src/modules/conf_randr/Makefile +src/modules/conf_randr/module.desktop src/modules/gadman/Makefile src/modules/gadman/module.desktop src/modules/mixer/Makefile diff --git a/src/bin/e_config.c b/src/bin/e_config.c index c08a01830..edf43c9c5 100644 --- a/src/bin/e_config.c +++ b/src/bin/e_config.c @@ -6,23 +6,9 @@ #define DEF_MENUCLICK 0.25 #endif -typedef enum _Eet_Union -{ - EET_SCREEN_INFO_11 = (int)((1 << 16) | 1), - EET_SCREEN_INFO_12 = (int)((1 << 16) | 2), - EET_SCREEN_INFO_13 = (int)((1 << 16) | 3), - EET_UNKNOWN -} Eet_Union; - -struct { - Eet_Union u; - const char *name; -} eet_mapping[] = { - { EET_SCREEN_INFO_11, "E_Config_Screen_11" }, - { EET_SCREEN_INFO_12, "E_Config_Screen_12" }, - { EET_SCREEN_INFO_12, "E_Config_Screen_13" }, - { EET_UNKNOWN, NULL } -}; +#define RANDR_SERIALIZED_SETUP_11 ((int)((1 << 16) | 1)) +#define RANDR_SERIALIZED_SETUP_12 ((int)((1 << 16) | 2)) +#define RANDR_SERIALIZED_SETUP_13 ((int)((1 << 16) | 3)) EAPI E_Config *e_config = NULL; @@ -34,8 +20,6 @@ static void _e_config_free(E_Config *cfg); static Eina_Bool _e_config_cb_timer(void *data); static int _e_config_eet_close_handle(Eet_File *ef, char *file); static void _e_config_acpi_bindings_add(void); -static const char * _eet_union_type_get(const void *data, Eina_Bool *unknow); -static Eina_Bool _eet_union_type_set(const char *type, void *data, Eina_Bool unknow); /* local subsystem globals */ static int _e_config_save_block = 0; @@ -65,15 +49,16 @@ static E_Config_DD *_e_config_shelf_desk_edd = NULL; static E_Config_DD *_e_config_mime_icon_edd = NULL; static E_Config_DD *_e_config_syscon_action_edd = NULL; static E_Config_DD *_e_config_env_var_edd = NULL; -static E_Config_DD *_e_config_screen_size_edd = NULL; -static E_Config_DD *_e_config_screen_size_mm_edd = NULL; -static E_Config_DD *_e_config_eina_rectangle_edd = NULL; -static E_Config_DD *_e_config_screen_info_edd = NULL; -static E_Config_DD *_e_config_screen_restore_info_11_edd = NULL; -static E_Config_DD *_e_config_screen_restore_info_12_edd = NULL; -static E_Config_DD *_e_config_screen_output_edid_hash_edd = NULL; -static E_Config_DD *_e_config_screen_output_restore_info_edd = NULL; -static E_Config_DD *_e_config_screen_crtc_restore_info_edd = NULL; +static E_Config_DD *_e_config_randr_size_edd = NULL; +static E_Config_DD *_e_config_randr_size_mm_edd = NULL; +static E_Config_DD *_e_config_randr_edid_hash_edd = NULL; +static E_Config_DD *_e_config_randr_serialized_setup_edd = NULL; +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_serialized_crtc_edd = NULL; EAPI int E_EVENT_CONFIG_ICON_THEME = 0; @@ -526,107 +511,109 @@ e_config_init(void) E_CONFIG_VAL(D, T, val, STR); E_CONFIG_VAL(D, T, unset, UCHAR); - _e_config_screen_size_edd = E_CONFIG_DD_NEW("Ecore_X_Randr_Screen_Size", Ecore_X_Randr_Screen_Size); + _e_config_randr_size_edd = E_CONFIG_DD_NEW("Ecore_X_Randr_Screen_Size", Ecore_X_Randr_Screen_Size); #undef T #undef D #define T Ecore_X_Randr_Screen_Size -#define D _e_config_screen_size_edd +#define D _e_config_randr_size_edd E_CONFIG_VAL(D, T, width, INT); E_CONFIG_VAL(D, T, height, INT); E_CONFIG_VAL(D, T, width, INT); E_CONFIG_VAL(D, T, height, INT); - _e_config_screen_size_mm_edd = E_CONFIG_DD_NEW("Ecore_X_Randr_Screen_Size_MM", Ecore_X_Randr_Screen_Size_MM); + _e_config_randr_size_mm_edd = E_CONFIG_DD_NEW("Ecore_X_Randr_Screen_Size_MM", Ecore_X_Randr_Screen_Size_MM); #undef T #undef D #define T Ecore_X_Randr_Screen_Size_MM -#define D _e_config_screen_size_mm_edd +#define D _e_config_randr_size_mm_edd E_CONFIG_VAL(D, T, width, INT); E_CONFIG_VAL(D, T, height, INT); E_CONFIG_VAL(D, T, width_mm, INT); E_CONFIG_VAL(D, T, height_mm, INT); - _e_config_screen_restore_info_11_edd = E_CONFIG_DD_NEW("E_Randr_Screen_Restore_Info_11", E_Randr_Screen_Restore_Info_11); + _e_config_randr_edid_hash_edd = E_CONFIG_DD_NEW("E_Randr_Edid_Hash", E_Randr_Edid_Hash); #undef T #undef D -#define T E_Randr_Screen_Restore_Info_11 -#define D _e_config_screen_restore_info_11_edd - E_CONFIG_SUB(D, T, size, _e_config_screen_size_edd); +#define T E_Randr_Edid_Hash +#define D _e_config_randr_edid_hash_edd + E_CONFIG_VAL(D, T, hash, INT); + + _e_config_randr_serialized_setup_11_edd = E_CONFIG_DD_NEW("E_Randr_Serialized_Setup_11", E_Randr_Serialized_Setup_11); +#undef T +#undef D +#define T E_Randr_Serialized_Setup_11 +#define D _e_config_randr_serialized_setup_11_edd + E_CONFIG_SUB(D, T, size, _e_config_randr_size_edd); E_CONFIG_VAL(D, T, orientation, INT); E_CONFIG_VAL(D, T, refresh_rate, SHORT); - _e_config_eina_rectangle_edd = E_CONFIG_DD_NEW("Eina_Rectangle", Eina_Rectangle); + _e_config_randr_serialized_output_policy_edd = E_CONFIG_DD_NEW("E_Randr_Serialized_Output_Policy", E_Randr_Serialized_Output_Policy); #undef T #undef D -#define T Eina_Rectangle -#define D _e_config_eina_rectangle_edd - E_CONFIG_VAL(D, T, x, INT); - E_CONFIG_VAL(D, T, y, INT); - E_CONFIG_VAL(D, T, w, INT); - E_CONFIG_VAL(D, T, h, INT); +#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_screen_output_edid_hash_edd = E_CONFIG_DD_NEW("E_Randr_Output_Edid_Hash", E_Randr_Output_Edid_Hash); + _e_config_randr_serialized_output_edd = E_CONFIG_DD_NEW("E_Randr_Serialized_Output", E_Randr_Serialized_Output); #undef T #undef D -#define T E_Randr_Output_Edid_Hash -#define D _e_config_screen_output_edid_hash_edd - E_CONFIG_VAL(D, T, hash, INT); - - // FIXME: need to totally re-do this randr config stuff - remove the - // union stuff. do this differently to not use unions really. not - // intended for how it is used here really. - _e_config_screen_output_restore_info_edd = E_CONFIG_DD_NEW("E_Randr_Output_Restore_Info", E_Randr_Output_Restore_Info); -#undef T -#undef D -#define T E_Randr_Output_Restore_Info -#define D _e_config_screen_output_restore_info_edd - E_CONFIG_SUB(D, T, edid_hash, _e_config_screen_output_edid_hash_edd); +#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_SUB(D, T, edid_hash, _e_config_randr_edid_hash_edd); E_CONFIG_VAL(D, T, backlight_level, DOUBLE); - _e_config_screen_crtc_restore_info_edd = E_CONFIG_DD_NEW("E_Randr_Crtc_Restore_Info", E_Randr_Crtc_Restore_Info); + _e_config_randr_serialized_mode_info_edd = E_CONFIG_DD_NEW("E_Randr_Serialized_Mode_Info", Ecore_X_Randr_Mode_Info); #undef T #undef D -#define T E_Randr_Crtc_Restore_Info -#define D _e_config_screen_crtc_restore_info_edd - E_CONFIG_SUB(D, T, geometry, _e_config_eina_rectangle_edd); - E_CONFIG_LIST(D, T, outputs, _e_config_screen_output_restore_info_edd); +#define T Ecore_X_Randr_Mode_Info +#define D _e_config_randr_serialized_mode_info_edd + E_CONFIG_VAL(D, T, width, INT); + E_CONFIG_VAL(D, T, height, INT); + E_CONFIG_VAL(D, T, dotClock, LL); + E_CONFIG_VAL(D, T, hSyncStart, INT); + E_CONFIG_VAL(D, T, hSyncEnd, INT); + E_CONFIG_VAL(D, T, hTotal, INT); + E_CONFIG_VAL(D, T, hSkew, INT); + E_CONFIG_VAL(D, T, vSyncStart, INT); + E_CONFIG_VAL(D, T, vSyncEnd, INT); + E_CONFIG_VAL(D, T, vTotal, INT); + E_CONFIG_VAL(D, T, name, STR); + E_CONFIG_VAL(D, T, nameLength, INT); + E_CONFIG_VAL(D, T, modeFlags, LL); + + _e_config_randr_serialized_crtc_edd = E_CONFIG_DD_NEW("E_Randr_Serialized_Crtc", E_Randr_Serialized_Crtc); +#undef T +#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_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_screen_restore_info_12_edd = E_CONFIG_DD_NEW("E_Randr_Screen_Restore_Info_12", E_Randr_Screen_Restore_Info_12); + _e_config_randr_serialized_setup_12_edd = E_CONFIG_DD_NEW("E_Randr_Serialized_Setup_12", E_Randr_Serialized_Setup_12); #undef T #undef D -#define T E_Randr_Screen_Restore_Info_12 -#define D _e_config_screen_restore_info_12_edd - E_CONFIG_LIST(D, T, crtcs, _e_config_screen_crtc_restore_info_edd); - E_CONFIG_LIST(D, T, outputs_edid_hashes, _e_config_screen_output_edid_hash_edd); - E_CONFIG_VAL(D, T, noutputs, INT); - E_CONFIG_VAL(D, T, output_policy, INT); - E_CONFIG_VAL(D, T, alignment, INT); +#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_randr_serialized_setup_edd = E_CONFIG_DD_NEW("E_Randr_Serialized_Setup", E_Randr_Serialized_Setup); #undef T #undef D -#define T E_Randr_Screen_Restore_Info -#define D _e_config_screen_info_edd - Eet_Data_Descriptor_Class eddc; - Eet_Data_Descriptor *unified, *edd_11_info, *edd_12_info; - EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, T); - D = eet_data_descriptor_stream_new(&eddc); - eddc.version = EET_DATA_DESCRIPTOR_CLASS_VERSION; - eddc.func.type_get = _eet_union_type_get; - eddc.func.type_set = _eet_union_type_set; - //virtual types to work around EET's inability to differentiate when it - //comes to pointers (a->b) vs. values (a.b) in union mappings - edd_11_info = E_CONFIG_DD_NEW("E_Randr_Screen_Restore_Info_11_Struct", E_Randr_Screen_Restore_Info_11); - E_CONFIG_SUB(edd_11_info, E_Randr_Screen_Restore_Info_Union, restore_info_11, _e_config_screen_restore_info_11_edd); - edd_12_info = E_CONFIG_DD_NEW("E_Randr_Screen_Restore_Info_12_Struct", E_Randr_Screen_Restore_Info_12); - E_CONFIG_LIST(edd_12_info, E_Randr_Screen_Restore_Info_Union, restore_info_12, _e_config_screen_restore_info_12_edd); - unified = eet_data_descriptor_stream_new(&eddc); - EET_DATA_DESCRIPTOR_ADD_MAPPING(unified, "E_Config_Screen_11", edd_11_info); - EET_DATA_DESCRIPTOR_ADD_MAPPING(unified, "E_Config_Screen_12", edd_12_info); - EET_DATA_DESCRIPTOR_ADD_MAPPING(unified, "E_Config_Screen_13", edd_12_info); -// DISABLE! crashie crashie long time -// EET_DATA_DESCRIPTOR_ADD_UNION(D, T, "E_Randr_Screen_Restore_Info_Union", rrvd_restore_info, randr_version, unified); - E_CONFIG_VAL(D, T, randr_version, INT); +#define T E_Randr_Serialized_Setup +#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_edd = E_CONFIG_DD_NEW("E_Config", E_Config); #undef T @@ -787,7 +774,8 @@ e_config_init(void) E_CONFIG_VAL(D, T, desklock_ask_presentation, UCHAR); E_CONFIG_VAL(D, T, desklock_ask_presentation_timeout, DOUBLE); - E_CONFIG_LIST(D, T, screen_info, _e_config_screen_info_edd); + //randr specifics + E_CONFIG_SUB(D, T, randr_serialized_setup, _e_config_randr_serialized_setup_edd); E_CONFIG_VAL(D, T, screensaver_enable, INT); E_CONFIG_VAL(D, T, screensaver_timeout, INT); @@ -959,7 +947,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_screen_info_edd); + E_CONFIG_DD_FREE(_e_config_randr_serialized_setup_edd); return 1; } @@ -1920,10 +1908,13 @@ _e_config_free(E_Config *ecf) E_Color_Class *cc; E_Path_Dir *epd; E_Remember *rem; - E_Randr_Screen_Restore_Info *screen_info; - E_Randr_Crtc_Restore_Info *crtc_info; - E_Randr_Output_Info *output_info; - E_Randr_Screen_Restore_Info_12 *restore_info_12; + E_Randr_Serialized_Setup *serialized_setup; + 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; @@ -2074,37 +2065,50 @@ _e_config_free(E_Config *ecf) if (sca->icon) eina_stringshare_del(sca->icon); E_FREE(sca); } - if (ecf->screen_info) + if(ecf->randr_serialized_setup) { - EINA_LIST_FREE(ecf->screen_info, screen_info) - { - switch (screen_info->randr_version) - { - case EET_SCREEN_INFO_11: - free(screen_info->rrvd_restore_info.restore_info_11); - break; - case EET_SCREEN_INFO_12: - case EET_SCREEN_INFO_13: - EINA_LIST_FREE(screen_info->rrvd_restore_info.restore_info_12, restore_info_12) - { - EINA_LIST_FREE(restore_info_12->crtcs, crtc_info) - { - EINA_LIST_FREE(crtc_info->outputs, output_info) - { - free(output_info->name); - free(output_info->edid); - free (output_info); - } - free (crtc_info); - } - free(restore_info_12); - } - eina_list_free(screen_info->rrvd_restore_info.restore_info_12); - break; - } - free(screen_info); - } + if(ecf->randr_serialized_setup->serialized_setup_11) + free(serialized_setup->serialized_setup_11); + else 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) + { + if (serialized_output->name) free(serialized_output); + 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) continue; + if (serialized_output_policy->name) + free(serialized_output_policy->name); + free(serialized_output_policy); + } + free(ecf->randr_serialized_setup); } + EINA_LIST_FREE(ecf->env_vars, evr) { if (evr->var) eina_stringshare_del(evr->var); @@ -2121,14 +2125,14 @@ _e_config_free(E_Config *ecf) E_FREE(ecf); } -static Eina_Bool + static Eina_Bool _e_config_cb_timer(void *data) { e_util_dialog_show(_("Settings Upgraded"), "%s", (char *)data); return 0; } -static int + static int _e_config_eet_close_handle(Eet_File *ef, char *file) { Eet_Error err; @@ -2138,16 +2142,16 @@ _e_config_eet_close_handle(Eet_File *ef, char *file) switch (err) { case EET_ERROR_NONE: - /* all good - no error */ - break; + /* all good - no error */ + break; case EET_ERROR_BAD_OBJECT: - erstr = _("The EET file handle is bad."); - break; + erstr = _("The EET file handle is bad."); + break; case EET_ERROR_EMPTY: - erstr = _("The file data is empty."); - break; + erstr = _("The file data is empty."); + break; case EET_ERROR_NOT_WRITABLE: - erstr = _("The file is not writable. Perhaps the disk is read-only
or you lost permissions to your files."); + erstr = _("The file is not writable. Perhaps the disk is read-only
or you lost permissions to your files."); break; case EET_ERROR_OUT_OF_MEMORY: erstr = _("Memory ran out while preparing the write.
Please free up memory."); @@ -2285,36 +2289,3 @@ _e_config_acpi_bindings_add(void) bind->params = eina_stringshare_add("now"); e_config->acpi_bindings = eina_list_append(e_config->acpi_bindings, bind); } - -static const char * -_eet_union_type_get(const void *data, Eina_Bool *unknow) -{ - const Eet_Union *u = data; - int i; - - if (unknow) *unknow = EINA_FALSE; - for (i = 0; eet_mapping[i].name; ++i) - if (*u == eet_mapping[i].u) - return eet_mapping[i].name; - - if (unknow) *unknow = EINA_TRUE; - return NULL; -} - -static Eina_Bool -_eet_union_type_set(const char *type, void *data, Eina_Bool unknow) -{ - Eet_Union *u = data; - int i; - - if (unknow) return EINA_FALSE; - - for (i = 0; eet_mapping[i].name; ++i) - if (strcmp(eet_mapping[i].name, type) == 0) - { - *u = eet_mapping[i].u; - return EINA_TRUE; - } - - return EINA_FALSE; -} diff --git a/src/bin/e_config.h b/src/bin/e_config.h index 123843b2f..e793cb733 100644 --- a/src/bin/e_config.h +++ b/src/bin/e_config.h @@ -33,7 +33,7 @@ typedef struct _E_Event_Config_Icon_Theme E_Event_Config_Icon_Theme; /* increment this whenever a new set of config values are added but the users * config doesn't need to be wiped - simply new values need to be put in */ -#define E_CONFIG_FILE_GENERATION 0x0145 +#define E_CONFIG_FILE_GENERATION 0x0146 #define E_CONFIG_FILE_VERSION ((E_CONFIG_FILE_EPOCH << 16) | E_CONFIG_FILE_GENERATION) #define E_EVAS_ENGINE_DEFAULT 0 @@ -250,7 +250,7 @@ struct _E_Config int mouse_accel_denominator; // GUI int mouse_accel_threshold; // GUI - Eina_List *screen_info; // GUI + E_Randr_Serialized_Setup *randr_serialized_setup; // GUI int border_raise_on_mouse_action; // GUI int border_raise_on_focus; // GUI diff --git a/src/bin/e_randr.c b/src/bin/e_randr.c index bb64ecf14..4b8cc7660 100644 --- a/src/bin/e_randr.c +++ b/src/bin/e_randr.c @@ -11,6 +11,13 @@ #define Ecore_X_Randr_Unset -1 /* + * Save mechanism: + * Single monitor: + * - Save monitor using the resolution + * + * Multiple monitors: + * - Use the EDID information to make sure we restore the right monitor. + * * TODO: * -fix output policies above and left */ @@ -57,6 +64,11 @@ 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); +EAPI void e_randr_store_configuration(E_Randr_Screen_Info *screen_info); +EAPI Eina_Bool e_randr_try_restore_configuration(E_Randr_Screen_Info *screen_info); 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); @@ -66,12 +78,8 @@ 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 Eina_Bool _e_randr_outputs_connected(Eina_List *outputs_info); static Ecore_X_Randr_Output *_e_randr_outputs_to_array(Eina_List *outputs_info); -//static int _e_randr_config_find_suiting_config_11(E_Randr_Screen_Restore_Info_11** restore_info); -static E_Randr_Screen_Restore_Info_12 * _e_randr_config_find_suiting_config_12(void); -//static Eina_Bool _e_randr_config_enable_11(int size_index, Ecore_X_Randr_Refresh_Rate refresh_rate, Ecore_X_Randr_Orientation orientation); -//static Eina_Bool _e_randr_config_enable_12(const E_Randr_Screen_Restore_Info_12 *restore_info); +static E_Randr_Serialized_Setup_12 * _e_randr_config_find_suiting_config_12(void); 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); @@ -90,7 +98,7 @@ 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); -E_Randr_Screen_Info *e_randr_screen_info = NULL; +EAPI E_Randr_Screen_Info *e_randr_screen_info = NULL; static Eina_List *_e_randr_event_handlers = NULL; EINTERN Eina_Bool @@ -270,7 +278,6 @@ _e_randr_screen_info_12_new(void) .crtcs = NULL, .outputs = NULL, .primary_output = NULL, - .output_policy = ECORE_X_RANDR_OUTPUT_POLICY_NONE, .alignment = ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE }; @@ -459,7 +466,8 @@ _e_randr_output_info_new(int nrequested) .connector_type = Ecore_X_Randr_Unset, .connection_status = ECORE_X_RANDR_CONNECTION_STATUS_DISCONNECTED, .subpixel_order= Ecore_X_Randr_Unset, - .compatible_outputs = NULL + .compatible_outputs = NULL, + .policy = ECORE_X_RANDR_OUTPUT_POLICY_NONE }; if (!(ret = malloc(sizeof(E_Randr_Output_Info) * nrequested))) return NULL; @@ -760,7 +768,7 @@ _e_randr_event_cb(void *data __UNUSED__, int type, void *ev) else if (type == ECORE_X_EVENT_RANDR_OUTPUT_CHANGE) { Ecore_X_Event_Randr_Output_Change *event = ev; - const E_Randr_Screen_Restore_Info_12 *restore_info; + const E_Randr_Serialized_Setup_12 *restore_info; E_Randr_Output_Info* output_info = NULL; /* available information: struct _Ecore_X_Event_Randr_Output_Change @@ -807,11 +815,13 @@ _e_randr_event_cb(void *data __UNUSED__, int type, void *ev) _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 ((restore_info = _e_randr_config_find_suiting_config_12())) //maybe we have a suiting configuration //_e_randr_config_enable_12(restore_info); ; else + */ enabled = _e_randr_try_enable_output(output_info, EINA_FALSE); //maybe give a success message? } _e_randr_notify_output_change(output_info); @@ -841,11 +851,13 @@ _e_randr_event_cb(void *data __UNUSED__, int type, void *ev) _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); @@ -865,6 +877,7 @@ _e_randr_event_cb(void *data __UNUSED__, int type, void *ev) }; */ } + e_randr_try_restore_configuration(e_randr_screen_info); on_exit: return ECORE_CALLBACK_RENEW; } @@ -999,146 +1012,602 @@ _e_randr_policy_crtc_get(E_Randr_Crtc_Info *but, E_Randr_Crtc_Info *hint __UNUSE return ret; } -/* -static Eina_Bool -_e_randr_outputs_connected(Eina_List *outputs_info) +// Setup store functions + Eina_Bool +_e_randr_copy_mode_info(Ecore_X_Randr_Mode_Info *dest, Ecore_X_Randr_Mode_Info *src) { - Eina_List *iter; - E_Randr_Output_Info *output_info; - EINA_LIST_FOREACH(outputs_info, iter, output_info) - if (output_info->connection_status == ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED) return EINA_TRUE; - return EINA_FALSE; -} + if (!dest || !src) return EINA_FALSE; -static Eina_Bool -_e_randr_config_enable_11(int size_index, Ecore_X_Randr_Refresh_Rate refresh_rate, Ecore_X_Randr_Orientation orientation) -{ - E_Randr_Screen_Info_11 *current_info_11; - - if (E_RANDR_NO_11 || (size_index < 0) || (refresh_rate < 0) || - (orientation < 0)) return EINA_FALSE; - - if (!ecore_x_randr_screen_primary_output_size_set(e_randr_screen_info->root, size_index) - || !ecore_x_randr_screen_primary_output_orientation_set(e_randr_screen_info->root, orientation) - || !ecore_x_randr_screen_primary_output_refresh_rate_set(e_randr_screen_info->root, size_index, refresh_rate)) return EINA_FALSE; - - //TODO: move this to the screen event later. - current_info_11 = e_randr_screen_info->rrvd_info.randr_info_11; - - current_info_11->csize_index = size_index; - current_info_11->corientation = orientation; - current_info_11->current_rate = refresh_rate; + 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; -} -static Eina_Bool -_e_randr_config_enable_12(const E_Randr_Screen_Restore_Info_12 *restore_info __UNUSED__) -{ - if (E_RANDR_NO_12 || !restore_info) return EINA_FALSE; - E_Randr_Screen_Info_12 *current_info_12; - E_Randr_Screen_Restore_Info_12 *restore_info_12 = NULL; - E_Randr_Crtc_Restore_Info *crtc_restore_info = NULL; - E_Randr_Crtc_Info *crtc_info; - E_Randr_Output_Info *output_info; - Eina_List *crtc_restore_iter; - - current_info_12 = (e_randr_screen_info->rrvd_info).randr_info_12; - EINA_LIST_FOREACH(restore_info_12->crtcs, crtc_restore_iter, crtc_restore_info) - { - ; - } - current_info_12->alignment = restore_info_12->alignment; - current_info_12->output_policy = restore_info_12->output_policy; - return EINA_TRUE; +_e_randr_copy_mode_info_fail_free_name: + free(dest->name); return EINA_FALSE; } -static int -_e_randr_config_find_suiting_config_11(E_Randr_Screen_Restore_Info_11 **restore_info) + void +_e_randr_free_serialized_mode_info(Ecore_X_Randr_Mode_Info *mode_info) { - E_RANDR_NO_11_RET(Ecore_X_Randr_None); - Eina_List *cfg_screen_restore_info_iter; - E_Randr_Screen_Restore_Info *screen_restore_info; - - E_Randr_Screen_Restore_Info_11 *restore_info_11; - Ecore_X_Randr_Screen_Size_MM *sizes; - Ecore_X_Randr_Refresh_Rate *rates = NULL; - int i = 0, j = 0, nsizes = 0, nrates = 0; - - EINA_LIST_FOREACH(e_config->screen_info, cfg_screen_restore_info_iter, screen_restore_info) - { - // 'screen_restore_info' should _never_ be NULL, since this functions shouldn't be called due to randr init failing. - if (!screen_restore_info) continue; - if (screen_restore_info->randr_version != ECORE_X_RANDR_1_1) continue; - restore_info_11 = screen_restore_info->rrvd_restore_info.restore_info_11; - if((sizes = ecore_x_randr_screen_primary_output_sizes_get(e_randr_screen_info->root, &nsizes))) - { - for (i = 0; i < nsizes; i++) - { - if ((restore_info_11->size.width == sizes[i].width) - && (restore_info_11->size.height == sizes[i].height)) - { - if ((rates = ecore_x_randr_screen_primary_output_refresh_rates_get(e_randr_screen_info->root, i, &nrates))) - { - for (j = 0; j < nrates; j++) - if (rates[j] == restore_info_11->refresh_rate) - { - if (restore_info) *restore_info = restore_info_11; - free(rates); - free(sizes); - return i; - } - free(rates); - } - } - } - if (sizes) free(sizes); - } - } - return Ecore_X_Randr_Unset; + if (mode_info->name) free(mode_info->name); } -*/ -/** - * @Brief find configuration with the most hardware currently available - */ -static E_Randr_Screen_Restore_Info_12 * -_e_randr_config_find_suiting_config_12(void) + Eina_List +*_e_randr_create_outputs_policies_list(Eina_List *outputs) { - //TODO: write geometry based loading - /* - Eina_List *cfg_screen_restore_info_iter; - E_Randr_Screen_Restore_Info *screen_restore_info; + Eina_List *iter, *list = NULL; + E_Randr_Output_Info *oi; + E_Randr_Serialized_Output_Policy *sop; + char *name; - E_Randr_Screen_Info_12 *current_info_12; - E_Randr_Screen_Restore_Info_12 *restore_info_12, *most_matches = NULL; - E_Randr_Output_Info *output_info; - E_Randr_Crtc_Restore_Info *crtc_restore_info; - Ecore_X_Randr_Output *outputs_xids; - Ecore_X_Randr_Crtc *crtcs_xids; - Eina_List *restore_info_12_iter, *output_iter, *restore_crtcs_iter; + 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; + } - if (e_randr_screen_info && e_config && e_config->screen_info) - { - - EINA_LIST_FOREACH(e_config->screen_info, cfg_screen_restore_info_iter, screen_restore_info) - { - if (screen_restore_info->randr_version < ECORE_X_RANDR_1_2) continue; - - //HINT: use eina_list_clone and a sort callback to find proper - //crtcs and outputs - - //current_info_12 = e_randr_screen_info->rrvd_info.randr_info_12; - } - - } - */ + 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; } -static Ecore_X_Randr_Output * +void +_e_randr_free_serialized_output_policy(E_Randr_Serialized_Output_Policy *sop) +{ + if (!sop) return; + if (sop->name) free(sop->name); + free(sop); +} + + Eina_List +*_e_randr_update_serialized_outputs_policies(E_Randr_Screen_Info_12 *si_12, Eina_List *sops) +{ + E_Randr_Serialized_Output_Policy *sop; + + EINA_LIST_FREE(sops, sop) + { + _e_randr_free_serialized_output_policy(sop); + } + + 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; + size_t len; + + 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); +} + + 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); + } +_e_randr_create_serialized_setup_12_failed_free_ss: + free(ss); +} + +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; + E_Randr_Serialized_Output *so; + E_Randr_Output_Info *oi; + E_Randr_Edid_Hash *edid_hash; + + 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); + } + 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) +{ + E_Randr_Serialized_Setup *ss; + E_Randr_Serialized_Setup_12 *ss_12; + + if (!(ss = E_NEW(E_Randr_Serialized_Setup, 1))) return NULL; + if ((screen_info->randr_version == ECORE_X_RANDR_1_1) && !(ss->serialized_setup_11 = _e_randr_create_serialized_setup_11(screen_info->rrvd_info.randr_info_11))) goto _e_randr_create_serialized_setup_failed_free_ss; + if ((screen_info->randr_version >= ECORE_X_RANDR_1_2)) + { + if (!(ss_12 = _e_randr_create_serialized_setup_12(screen_info->rrvd_info.randr_info_12)) + || !(ss->serialized_setups_12 = eina_list_append(ss->serialized_setups_12, ss_12))) + goto _e_randr_create_serialized_setup_failed_free_ss; + } + + return ss; + +_e_randr_create_serialized_setup_failed_free_ss: + free(ss); +} + + EAPI void +e_randr_store_configuration(E_Randr_Screen_Info *screen_info) +{ + if (E_RANDR_NO_11) return; + + if (!e_config->randr_serialized_setup) + { + e_config->randr_serialized_setup = _e_randr_create_serialized_setup(screen_info); + e_config_save_queue(); + return; + } + + if (screen_info->randr_version == ECORE_X_RANDR_1_1) + { + 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 if (screen_info->randr_version >= ECORE_X_RANDR_1_2) + { + 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); + + //Also, 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) +{ + E_Manager *man; + 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)) + { + man = e_manager_current_get(); + return ecore_x_randr_screen_primary_output_size_set(man->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_Bool name_found; + + 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) + { + name_found = EINA_FALSE; + EINA_LIST_FOREACH(ci->possible_outputs, p_output_iter, oi) + { + if (!strncmp(s_output_name, oi->name, oi->name_length)) + { + name_found = EINA_TRUE; + break; + } + } + if (!name_found) + break; + } + if (name_found) + break; + } + if (name_found) + return ci; + else + 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) + { + EINA_LIST_FOREACH(ois, r_output_iter, oi) + { + 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; +} + + 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, *outputs_list; + Eina_Bool ret = EINA_TRUE; + E_Manager *man; + + if(!(ss_12 = _e_randr_find_matching_serialized_setup(e_config->randr_serialized_setup->serialized_setups_12, si_12))) return EINA_FALSE; + + man = e_manager_current_get(); + + 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); + mi = _e_randr_find_matching_mode_info(si_12->modes, &sc->mode_info); + ret &= ecore_x_randr_crtc_mode_set(man->root, ci->xid, outputs_array, eina_list_count(outputs_list), mi->xid); + ret &= ecore_x_randr_crtc_pos_set(man->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; @@ -1148,7 +1617,7 @@ _e_randr_outputs_to_array(Eina_List *outputs_info) 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! */ + /* output_info == NULL should _not_ be possible! */ ret[i++] = output_info ? output_info->xid : Ecore_X_Randr_None; return ret; } @@ -1191,7 +1660,7 @@ _e_randr_try_enable_output(E_Randr_Output_Info *output_info, Eina_Bool force) if (!usable_crtc) return EINA_FALSE; //get the CRTC we will refer to, dependend on policy - switch (e_randr_screen_info->rrvd_info.randr_info_12->output_policy) + switch (output_info->policy) { case ECORE_X_RANDR_OUTPUT_POLICY_NONE: return EINA_TRUE; @@ -1386,15 +1855,19 @@ 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, e_randr_screen_info->rrvd_info.randr_info_12->output_policy))) return EINA_TRUE; + if(!(crtc_rel = _e_randr_policy_crtc_get(new_crtc, NULL, last_output->policy))) return EINA_TRUE; //following is policy dependend. - switch (e_randr_screen_info->rrvd_info.randr_info_12->output_policy) + switch (last_output->policy) { case ECORE_X_RANDR_OUTPUT_POLICY_ABOVE: dy = (crtc_rel->geometry.y - new_crtc->geometry.h); @@ -1425,7 +1898,7 @@ _e_randr_crtc_move_policy(E_Randr_Crtc_Info *new_crtc) default: break; } - ret &= ecore_x_randr_crtc_pos_relative_set(e_randr_screen_info->root, new_crtc->xid, crtc_rel->xid, e_randr_screen_info->rrvd_info.randr_info_12->output_policy, e_randr_screen_info->rrvd_info.randr_info_12->alignment); + 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; } @@ -1686,6 +2159,8 @@ _e_randr_output_info_hw_info_set(E_Randr_Output_Info *output_info) _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(output_info->edid, output_info->edid_length); //get the outputs we can use on the same CRTC alongside this one. if ((outputs = ecore_x_randr_output_clones_get(e_randr_screen_info->root, output_info->xid, &num))) { @@ -1711,6 +2186,10 @@ _e_randr_output_info_hw_info_set(E_Randr_Output_Info *output_info) } free(crtcs); } + else + { + fprintf(stderr, "E_RANDR: Output %x does not have a single possible CRTC.\n", output_info->xid); + } } /* diff --git a/src/bin/e_randr.h b/src/bin/e_randr.h index 448fc8901..7f04d0283 100644 --- a/src/bin/e_randr.h +++ b/src/bin/e_randr.h @@ -1,24 +1,26 @@ #ifdef E_TYPEDEFS typedef struct _E_Randr_Crtc_Info E_Randr_Crtc_Info; +typedef struct _E_Randr_Edid_Hash E_Randr_Edid_Hash; 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; typedef union _E_Randr_Screen_RRVD_Info E_Randr_Screen_RRVD_Info; typedef struct _E_Randr_Screen_Info E_Randr_Screen_Info; -typedef struct _E_Randr_Output_Edid_Hash E_Randr_Output_Edid_Hash; -typedef struct _E_Randr_Output_Restore_Info E_Randr_Output_Restore_Info; -typedef struct _E_Randr_Crtc_Restore_Info E_Randr_Crtc_Restore_Info; -typedef struct _E_Randr_Screen_Restore_Info_11 E_Randr_Screen_Restore_Info_11; -typedef struct _E_Randr_Screen_Restore_Info_12 E_Randr_Screen_Restore_Info_12; -typedef union _E_Randr_Screen_Restore_Info_Union E_Randr_Screen_Restore_Info_Union; -typedef struct _E_Randr_Screen_Restore_Info E_Randr_Screen_Restore_Info; +typedef struct _E_Randr_Serialized_Output_Policy E_Randr_Serialized_Output_Policy; +typedef struct _E_Randr_Serialized_Output E_Randr_Serialized_Output; +typedef struct _E_Randr_Serialized_Crtc E_Randr_Serialized_Crtc; +typedef struct _E_Randr_Serialized_Setup_11 E_Randr_Serialized_Setup_11; +typedef struct _E_Randr_Serialized_Setup_12 E_Randr_Serialized_Setup_12; +typedef struct _E_Randr_Serialized_Setup E_Randr_Serialized_Setup; + +EAPI void e_randr_store_configuration(E_Randr_Screen_Info *screen_info); #else #ifndef E_RANDR_H #define E_RANDR_H -struct _E_Randr_Crtc_Info +struct _E_Randr_Crtc_Info { Ecore_X_ID xid; Eina_Rectangle geometry; @@ -35,7 +37,12 @@ struct _E_Randr_Crtc_Info Ecore_X_Randr_Mode_Info *current_mode; }; -struct _E_Randr_Output_Info +struct _E_Randr_Edid_Hash +{ + int hash; +}; + +struct _E_Randr_Output_Info { Ecore_X_ID xid; char *name; @@ -47,6 +54,7 @@ struct _E_Randr_Output_Info int connector_number; Ecore_X_Randr_Connector_Type connector_type; Ecore_X_Randr_Connection_Status connection_status; + Ecore_X_Randr_Output_Policy policy; /* * Attached Monitor specific: */ @@ -57,6 +65,7 @@ struct _E_Randr_Output_Info 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; @@ -75,7 +84,7 @@ struct _E_Randr_Screen_Info_11 Ecore_X_Randr_Refresh_Rate current_rate; }; -struct _E_Randr_Screen_Info_12 +struct _E_Randr_Screen_Info_12 { Ecore_X_Randr_Screen_Size min_size; Ecore_X_Randr_Screen_Size max_size; @@ -84,18 +93,17 @@ struct _E_Randr_Screen_Info_12 Eina_List *crtcs; Eina_List *outputs; E_Randr_Output_Info *primary_output; - Ecore_X_Randr_Output_Policy output_policy; Ecore_X_Randr_Relative_Alignment alignment; }; //RRVD == RandR(R) Version Depended -union _E_Randr_Screen_RRVD_Info +union _E_Randr_Screen_RRVD_Info { E_Randr_Screen_Info_11 *randr_info_11; E_Randr_Screen_Info_12 *randr_info_12; }; -struct _E_Randr_Screen_Info +struct _E_Randr_Screen_Info { Ecore_X_Window root; int randr_version; @@ -103,56 +111,67 @@ struct _E_Randr_Screen_Info }; //Following stuff is just for configuration purposes -struct _E_Randr_Output_Edid_Hash { - int hash; + +struct _E_Randr_Serialized_Output_Policy +{ + char *name; + int name_length; + Ecore_X_Randr_Output_Policy policy; }; -struct _E_Randr_Output_Restore_Info +struct _E_Randr_Serialized_Output { - E_Randr_Output_Edid_Hash edid_hash; + char *name; + int name_length; + E_Randr_Edid_Hash edid_hash; double backlight_level; }; -struct _E_Randr_Crtc_Restore_Info +struct _E_Randr_Serialized_Crtc { - Eina_Rectangle geometry; + //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; + 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; - //list of the outputs; - Eina_List *outputs; }; -struct _E_Randr_Screen_Restore_Info_11 +struct _E_Randr_Serialized_Setup_12 { - Ecore_X_Randr_Screen_Size size; + double timestamp; + //List of E_Randr_Serialized_Crtc objects + Eina_List *serialized_crtcs; + /* + * List of E_Randr_Edid_Hash elements of monitors, + * that were enabled, when the setup was stored + */ + Eina_List *serialized_edid_hashes; +}; + +struct _E_Randr_Serialized_Setup_11 +{ + Ecore_X_Randr_Screen_Size_MM size; Ecore_X_Randr_Refresh_Rate refresh_rate; Ecore_X_Randr_Orientation orientation; }; -struct _E_Randr_Screen_Restore_Info_12 +struct _E_Randr_Serialized_Setup { - Eina_List *outputs_edid_hashes; - int noutputs; - Eina_List *crtcs; - Ecore_X_Randr_Output_Policy output_policy; - Ecore_X_Randr_Relative_Alignment alignment; -}; - -union _E_Randr_Screen_Restore_Info_Union -{ - E_Randr_Screen_Restore_Info_11 *restore_info_11; - Eina_List *restore_info_12; -}; - -struct _E_Randr_Screen_Restore_Info -{ - int randr_version; - E_Randr_Screen_Restore_Info_Union rrvd_restore_info; + E_Randr_Serialized_Setup_11 *serialized_setup_11; + //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; }; EINTERN Eina_Bool e_randr_init(void); EINTERN int e_randr_shutdown(void); -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/modules/Makefile.am b/src/modules/Makefile.am index 7eadd76a1..56498e786 100644 --- a/src/modules/Makefile.am +++ b/src/modules/Makefile.am @@ -126,6 +126,10 @@ if USE_MODULE_CONF_INTERACTION SUBDIRS += conf_interaction endif +if USE_MODULE_CONF_RANDR +SUBDIRS += conf_randr +endif + if USE_MODULE_GADMAN SUBDIRS += gadman endif diff --git a/src/modules/conf_display/e_int_config_display.c b/src/modules/conf_display/e_int_config_display.c index 27b62844b..6733c9429 100644 --- a/src/modules/conf_display/e_int_config_display.c +++ b/src/modules/conf_display/e_int_config_display.c @@ -23,8 +23,6 @@ static int _sort_resolutions (const void *d1, const void *d2); typedef struct _Resolution Resolution; typedef struct _SureBox SureBox; -static E_Randr_Screen_Restore_Info_11 *e_screen_config_11 = NULL; - struct _Resolution { int id; @@ -96,13 +94,8 @@ _surebox_dialog_cb_yes(void *data, E_Dialog *dia) ecore_x_randr_screen_primary_output_current_size_get(man->root, &c_size.width, &c_size.height, NULL, NULL, NULL); c_rate = ecore_x_randr_screen_primary_output_current_refresh_rate_get(man->root); - if (e_screen_config_11) - { - e_screen_config_11->size.width = c_size.width; - e_screen_config_11->size.height = c_size.height; - e_screen_config_11->refresh_rate = c_rate; - e_config_save_queue(); - } + e_randr_store_configuration(e_randr_screen_info); + _fill_data(sb->cfdata); _load_resolutions(sb->cfdata); /* No need to load rates as the currently selected resolution has not been @@ -242,7 +235,6 @@ static void _fill_data(E_Config_Dialog_Data *cfdata) { E_Manager *man; - E_Randr_Screen_Restore_Info *restore_info; Eina_List *iter; int rots; @@ -250,36 +242,6 @@ _fill_data(E_Config_Dialog_Data *cfdata) ecore_x_randr_screen_primary_output_current_size_get(man->root, &cfdata->orig_size.width, &cfdata->orig_size.height, NULL, NULL, &cfdata->orig_size_index); cfdata->orig_rate = ecore_x_randr_screen_primary_output_current_refresh_rate_get(man->root); - EINA_LIST_FOREACH(e_config->screen_info, iter, restore_info) - { - if (restore_info->randr_version == RANDR_11) - { - e_screen_config_11 = restore_info->rrvd_restore_info.restore_info_11; - break; - } - } - - if(!e_screen_config_11) - { - if ((restore_info = E_NEW(E_Randr_Screen_Restore_Info, 1))) - { - restore_info->randr_version = RANDR_11; - if ((e_screen_config_11 = E_NEW(E_Randr_Screen_Restore_Info_11, 1))) - { - restore_info->rrvd_restore_info.restore_info_11 = e_screen_config_11; - if (!(e_config->screen_info = eina_list_append(e_config->screen_info, restore_info))) - { - free(e_screen_config_11); - free(restore_info); - } - } - else - { - free (restore_info); - } - } - } - rots = ecore_x_randr_screen_primary_output_orientations_get(man->root); if ((rots) && (rots != ECORE_X_RANDR_ORIENTATION_ROT_0)) { @@ -352,7 +314,6 @@ _basic_check_changed(E_Config_Dialog *cfd __UNUSED__, E_Config_Dialog_Data *cfda rt = eina_list_nth(res->rates, r); if (!rt) return 0; - if (!e_screen_config_11) return EINA_FALSE; return ((res->size.width != cfdata->orig_size.width) || (res->size.height != cfdata->orig_size.height) || (cfdata->has_rates && (*rt != cfdata->orig_rate)) || @@ -414,14 +375,7 @@ _basic_apply_data(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata) (cfdata->orientation | cfdata->flip)); cfdata->orig_orientation = cfdata->orientation; cfdata->orig_flip = cfdata->flip; - if (e_screen_config_11) - e_screen_config_11->orientation = (cfdata->orientation | cfdata->flip); } - else - if (e_screen_config_11) - e_screen_config_11->orientation = 0; - - e_config_save_queue(); return 1; } diff --git a/src/modules/conf_randr/Makefile.am b/src/modules/conf_randr/Makefile.am new file mode 100644 index 000000000..f54929fda --- /dev/null +++ b/src/modules/conf_randr/Makefile.am @@ -0,0 +1,51 @@ +MAINTAINERCLEANFILES = Makefile.in module.desktop +MODULE = conf_randr + +EDJE_CC = @edje_cc@ +EDJE_FLAGS = -v \ + -id $(top_srcdir)/src/modules/$(MODULE)/images \ + @EDJE_DEF@ + +# data files for the module +filesdir = $(libdir)/enlightenment/modules/$(MODULE) +files_DATA = \ + e-module-$(MODULE).edj \ + module.desktop + +EXTRA_DIST = \ + e-module-$(MODULE).edc \ + module.desktop.in + +# the module .so file +INCLUDES = -I. \ + -I$(top_srcdir) \ + -I$(top_srcdir)/src/modules/$(MODULE) \ + -I$(top_srcdir)/src/bin \ + -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/modules \ + @e_cflags@ +pkgdir = $(libdir)/enlightenment/modules/$(MODULE)/$(MODULE_ARCH) +pkg_LTLIBRARIES = module.la +module_la_SOURCES = e_mod_main.c \ + e_mod_main.h \ + e_int_config_randr_orientation.c \ + e_int_config_randr_resolutions.c \ + e_int_config_randr_arrangement.c \ + e_int_config_randr_policies.c \ + e_int_config_randr.c \ + e_int_config_randr.h + +module_la_LIBADD = @e_libs@ @dlopen_libs@ +module_la_LDFLAGS = -module -avoid-version +module_la_DEPENDENCIES = $(top_builddir)/config.h + +e-module-$(MODULE).edj: Makefile $(EXTRA_DIST) + $(EDJE_CC) $(EDJE_FLAGS) \ + $(top_srcdir)/src/modules/$(MODULE)/e-module-$(MODULE).edc \ + $(top_builddir)/src/modules/$(MODULE)/e-module-$(MODULE).edj + +clean-local: + rm -f *.edj + +uninstall: + rm -rf $(DESTDIR)$(libdir)/enlightenment/modules/$(MODULE) diff --git a/src/modules/conf_randr/e-module-conf_randr.edc b/src/modules/conf_randr/e-module-conf_randr.edc new file mode 100644 index 000000000..61f2e219f --- /dev/null +++ b/src/modules/conf_randr/e-module-conf_randr.edc @@ -0,0 +1,945 @@ +#define BORDERSIZE 1 +#define SUGGESTION_TIMEOUT 2.5 + +images { + image: "icon.png" COMP; + image: "video-display.svg" COMP; + image: "display.png" COMP; + image: "display-glass-shine.png" COMP; +} + +collections { + + // The icon used in the settings dialog + group { + name: "icon"; + parts { + part { + name: "image"; + mouse_events: 0; + description { + state: "default" 0.0; + aspect: 1.0 1.0; + aspect_preference: BOTH; + image.normal: "icon.png"; + } + } + } + } + + /**********************************************/ + /*********Subdialog - Arrangement**************/ + /**********************************************/ + + //The graphical representation of a single monitor, including its decorations + group { + name: "e/conf/randr/dialog/subdialog/arrangement/output"; + + styles { + style { + name: "display_name_text"; + base: "font=Sans:style=Bold font_size=10 text_class=tb_plain align=center valign=center color=#fff style=soft_shadow shadow_color=#0000001f wrap=word"; + tag: "br" "\n"; + tag: "hilight" "+ font=Sans:style=Bold text_class=tb_light"; + } + } + + + parts { + + part { + name: "display"; + type: IMAGE; + mouse_events: 0; + + description { + state: "default" 0.0; + image.normal: "display.png"; + rel1.relative: 0.0 0.0; + rel2.relative: 1.0 1.0; + } + } + + part { + name: "e.swallow.content"; + type: SWALLOW; // background of CRTC's zone + + description { + state: "default" 0.0; + aspect_preference: BOTH; + color: 255 255 255 255; + rel1 { + to: "display"; + relative: 0.047379 0.049303; + } + rel2 { + to: "display"; + //relative: 0.97 0.657804; + relative: 0.975 0.66; + } + } + + description { + state: "disabled" 0.0; + inherit: "default" 0.0; + color: 255 255 255 128; + } + } + + part { + name: "output_selected_frame_clip"; + type: RECT; + mouse_events: 0; + + description { + state: "default" 0.0; + color: 255 255 255 0; + + rel1.relative: 0.0 0.0; + rel2.relative: 1.0 1.0; + } + description { + state: "selected" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + } + } + + part { + name: "output_selected_frame_border_top"; + type: RECT; + clip_to: "output_selected_frame_clip"; + mouse_events: 0; + + description { + state: "default" 0.0; + color: 128 128 128 255; + min: 0 2; + fixed: 0 1; + align: 0.5 0.0; + + rel1 { + to: "output_selected_frame_clip"; + relative: 0.0 0.0; + } + rel2 { + to: "output_selected_frame_clip"; + relative: 1.0 0.0; + offset: 0 BORDERSIZE; + } + } + } + + part { + name: "output_selected_frame_border_right"; + type: RECT; + clip_to: "output_selected_frame_clip"; + mouse_events: 0; + + description { + state: "default" 0.0; + color: 128 128 128 255; + min: 1 0; + fixed: 1 0; + align: 1.0 0.5; + + rel1 { + to_x: "output_selected_frame_clip"; + to_y: "output_selected_frame_border_top"; + relative: 1.0 1.0; + offset: (-BORDERSIZE-1) 0; + } + rel2 { + to_x: "output_selected_frame_clip"; + to_y: "output_selected_frame_border_bottom"; + relative: 1.0 0.0; + } + } + } + + part { + name: "output_selected_frame_border_bottom"; + type: RECT; + clip_to: "output_selected_frame_clip"; + mouse_events: 0; + + description { + state: "default" 0.0; + color: 128 128 128 255; + min: 0 2; + fixed: 0 1; + align: 0.5 1.0; + + rel1 { + to: "output_selected_frame_clip"; + relative: 0.0 1.0; + offset: 0 (-BORDERSIZE-1); + } + rel2 { + to: "output_selected_frame_clip"; + relative: 1.0 1.0; + } + } + } + + part { + name: "output_selected_frame_border_left"; + type: RECT; + clip_to: "output_selected_frame_clip"; + mouse_events: 0; + + description { + state: "default" 0.0; + color: 128 128 128 255; + min: 1 0; + fixed: 1 0; + align: 0.0 0.5; + + rel1 { + to_x: "output_selected_frame_clip"; + to_y: "output_selected_frame_border_top"; + relative: 0.0 1.0; + } + rel2 { + to_x: "output_selected_frame_clip"; + to_y: "output_selected_frame_border_bottom"; + relative: 0.0 0.0; + offset: BORDERSIZE 0; + } + } + } + + part { + name: "output_selected_frm_inside"; + type: RECT; + clip_to: "output_selected_frame_clip"; + mouse_events: 0; + + description { + state: "default" 0.0; + color: 255 255 255 120; + + rel1 { + to: "output_selected_frame_clip"; + offset: BORDERSIZE BORDERSIZE; + } + rel2 { + to: "output_selected_frame_clip"; + offset: -BORDERSIZE -BORDERSIZE; + } + } + } + + part { + name: "output_txt_bg"; + type: RECT; + //clip_to: "output_txt_clip"; + mouse_events: 0; + + description { + state: "default" 0.0; + color: 255 255 255 128; + align: 0.5 0.5; + + rel1 { + to: "output_txt"; + relative: 0.0 0.0; + offset: -5 -5; + } + rel2 { + to: "output_txt"; + relative: 1.0 1.0; + offset: 5 5; + } + } + description { + state: "selected" 0.0; + inherit: "default" 0.0; + color: 0 0 0 255; + } + } + + part { + name: "output_txt"; + type: TEXTBLOCK; + //clip_to: "output_txt_clip"; + mouse_events: 0; + + description { + align: 0.5 0.5; + state: "default" 0.0; + color: 0 0 0 255; + // define part coordinates: + //rel1.to: "output_txt_clip"; + //rel2.to: "output_txt_clip"; + rel1.to: "e.swallow.content"; + rel2.to: "e.swallow.content"; + + text { + style: "display_name_text"; + text: "output name"; + min: 1.0 1.0; + max: 1.0 1.0; + } + } + description { + state: "selected" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + } + } + + part { + name: "selected_toggle_on"; + type: RECT; + mouse_events: 1; + + description { + state: "default" 0.0; + color: 0 0 0 0; + visible: 1; + + rel1 { + to: "e.swallow.content"; + relative: 0.0 0.0; + } + rel2 { + to: "e.swallow.content"; + relative: 1.0 1.0; + } + } + + description { + state: "disable" 0.0; + inherit: "default" 0.0; + visible: 0; + } + } + + part { + name: "selected_toggle_off"; + type: RECT; + mouse_events: 1; + + description { + state: "default" 0.0; + color: 0 0 0 0; + visible: 0; + + rel1 { + to: "selected_toggle_on"; + relative: 0.0 0.0; + } + rel2 { + to: "selected_toggle_on"; + relative: 1.0 1.0; + } + } + + description { + state: "disable" 0.0; + inherit: "default" 0.0; + visible: 1; + } + } + + part { + name: "display-glass-shine"; + type: IMAGE; + + description { + state: "default" 0.0; + image.normal: "display-glass-shine.png"; + } + } + + programs { + program { + name: "highlight"; + signal: "mouse,down,1"; + source: "selected_toggle_on"; + + action: STATE_SET "selected" 0.0; + transition: LINEAR 0.1; + //target: "e.swallow.content"; + //target: "output_selected_clip"; + target: "output_txt"; + target: "output_txt_bg"; + target: "output_selected_frame_clip"; + } + + program { + name: "normal"; + signal: "mouse,clicked,1"; + source: "selected_toggle_off"; + + action: STATE_SET "default" 0.0; + transition: LINEAR 0.1; + //target: "e.swallow.content"; + //target: "output_selected_clip"; + target: "output_txt"; + target: "output_txt_bg"; + target: "output_selected_frame_clip"; + } + + program { + name: "selected_toggle_off_on"; + signal: "mouse,clicked,1"; + source: "selected_toggle_on"; + action: STATE_SET "disable" 1.0; + target: "selected_toggle_on"; + target: "selected_toggle_off"; + } + + program { + name: "selected_toggle_on_off"; + signal: "mouse,clicked,1"; + source: "selected_toggle_off"; + action: STATE_SET "default" 1.0; + target: "selected_toggle_on"; + target: "selected_toggle_off"; + } + + program { + name: "emit_highlight"; + signal: "select"; + source: "e"; + after: "highlight"; + } + + program { + name: "emit_normal"; + signal: "deselect"; + source: "e"; + after: "normal"; + } + + program { + name: "disable"; + signal: "disabled"; + source: "e"; + action: STATE_SET "disabled" 0.0; + target: "e.swallow.content"; + } + + program { + name: "enable"; + signal: "enabled"; + source: "e"; + action: STATE_SET "default" 0.0; + target: "e.swallow.content"; + } + + program { + name: "init"; + after: "normal"; + } + } + } + } + + //This group describes the look of the suggestion entity used, when a monitor + //representation is dragged. Its size matches the size of the monitor + //dragged. + group{ + name: "e/conf/randr/dialog/subdialog/arrangement/suggestion"; + data { + item: "distance_min" "20"; + } + + /* + script { + public fade_out_timer_id = 0; + + public suggestion_fade_out () + { + cancel_timer(get_int(fade_out_timer_id)); + run_program(PROGRAM:"hide"); + } + } + */ + + parts { + part { + name: "shape_clip"; + type: RECT; + description { + state: "default" 0.0; + color: 255 255 255 0; + rel1.relative: 0.0 0.0; + rel2.relative: 1.0 1.0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + } + } + part { + name: "shape"; + type: RECT; + mouse_events: 0; + clip_to: "shape_clip"; + description { + state: "default" 0.0; + color: 0 0 0 100; + rel1.to: "shape_clip"; + rel2.to: "shape_clip"; + } + } + } + programs { + program { + name: "show_transition"; + signal: "show"; + source: "e"; + action: STATE_SET "visible" 0.0; + target: "shape_clip"; + transition: LINEAR 0.2; + } + /* + program { + name: "set_timeout"; + signal: "show"; + source: "e"; + script { + new i = timer(SUGGESTION_TIMEOUT, "suggestion_fade_out", 0); + set_int(fade_out_timer_id, i); + } + } + */ + program { + name: "hide"; + signal: "hide"; + source: "e"; + action: STATE_SET "default" 0.0; + target: "shape_clip"; + transition: LINEAR 0.2; + } + } + } + + /**********************************************/ + /************Subdialog - Policies**************/ + /**********************************************/ + group{ + name: "e/conf/randr/dialog/subdialog/policies"; + parts { + part { + name: "current_displays_setup/clipper"; + type: RECT; + mouse_events: 0; + description { + state: "default" 0.0; + color: 0 0 0 0; + rel1.relative: 0.25 0.25; + rel2.relative: 0.75 0.75; + } + description { + state: "above" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + rel1.relative: 0.25 0.5; + rel2.relative: 0.75 1.0; + } + description { + state: "right" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + rel1.relative: 0.0 0.25; + rel2.relative: 0.5 0.75; + } + description { + state: "below" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + rel1.relative: 0.25 0.0; + rel2.relative: 0.75 0.5; + } + description { + state: "left" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + rel1.relative: 0.5 0.25; + rel2.relative: 1.0 0.75; + } + description { + state: "clone" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + } + description { + state: "none" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + } + } + part { + name: "current_displays_setup.swallow.content"; + type: SWALLOW; + clip_to: "current_displays_setup/clipper"; + description { + state: "default" 0.0; + rel1.to: "current_displays_setup/clipper"; + rel2.to: "current_displays_setup/clipper"; + } + } + part { + name: "new_display/clipper"; + type: RECT; + mouse_events: 0; + description { + state: "default" 0.0; + color: 0 0 0 0; + rel1.relative: 0.25 0.25; + rel2.relative: 0.75 0.75; + } + description { + state: "above" 0.0; + inherit: "default" 0.0; + color: 0 0 0 0; + rel1.relative: 0.25 0.0; + rel2.relative: 0.75 0.5; + } + description { + state: "above_visible" 0.0; + inherit: "above" 0.0; + color: 255 255 255 255; + } + description { + state: "right" 0.0; + inherit: "default" 0.0; + color: 0 0 0 0; + rel1.relative: 0.5 0.25; + rel2.relative: 1.0 0.75; + } + description { + state: "right_visible" 0.0; + inherit: "right" 0.0; + color: 255 255 255 255; + } + description { + state: "below" 0.0; + inherit: "default" 0.0; + color: 0 0 0 0; + rel1.relative: 0.25 0.5; + rel2.relative: 0.75 1.0; + } + description { + state: "below_visible" 0.0; + inherit: "below" 0.0; + color: 255 255 255 255; + } + description { + state: "left" 0.0; + inherit: "default" 0.0; + color: 0 0 0 0; + rel1.relative: 0.0 0.25; + rel2.relative: 0.5 0.75; + } + description { + state: "left_visible" 0.0; + inherit: "left" 0.0; + color: 255 255 255 255; + } + description { + state: "clone" 0.0; + inherit: "default" 0.0; + color: 0 0 0 0; + } + description { + state: "clone_visible" 0.0; + inherit: "clone" 0.0; + color: 255 255 255 255; + } + description { + state: "none" 0.0; + inherit: "default" 0.0; + color: 0 0 0 0; + } + description { + state: "none_visible" 0.0; + inherit: "none" 0.0; + color: 255 255 255 255; + } + } + part { + name: "new_display.swallow.content"; + type: SWALLOW; + clip_to: "new_display/clipper"; + description { + state: "default" 0.0; + rel1.to: "new_display/clipper"; + rel2.to: "new_display/clipper"; + } + } + } + /* + * The signals emitted to the UI are encoded as their corresponding value + * in Ecore_X + * + * Policy = Signal emitted + * ECORE_X_RANDR_OUTPUT_POLICY_ABOVE = 1 + * ECORE_X_RANDR_OUTPUT_POLICY_RIGHT = 2 + * ECORE_X_RANDR_OUTPUT_POLICY_BELOW = 3 + * ECORE_X_RANDR_OUTPUT_POLICY_LEFT = 4 + * ECORE_X_RANDR_OUTPUT_POLICY_CLONE = 5 + * ECORE_X_RANDR_OUTPUT_POLICY_NONE = 6 + */ + programs { + program { + name: "new_display_hide"; + signal: "conf,randr,dialog,policies,*"; + source: "e"; + action: STATE_SET "default" 0.0; + target: "new_display/clipper"; + } + program { + name: "current_displays_setup_clipper_above"; + signal: "conf,randr,dialog,policies,1"; + source: "e"; + action: STATE_SET "above" 0.0; + target: "current_displays_setup/clipper"; + target: "new_display/clipper"; + after: "new_display_above_visible_set"; + transition: LINEAR 0.5; + } + program { + name: "new_display_above_visible_set"; + action: STATE_SET "above_visible" 0.0; + target: "new_display/clipper"; + transition: LINEAR 0.5; + } + program { + name: "current_displays_setup_clipper_right"; + signal: "conf,randr,dialog,policies,2"; + source: "e"; + action: STATE_SET "right" 0.0; + target: "current_displays_setup/clipper"; + target: "new_display/clipper"; + after: "new_display_right_visible_set"; + transition: LINEAR 0.5; + } + program { + name: "new_display_right_visible_set"; + action: STATE_SET "right_visible" 0.0; + target: "new_display/clipper"; + transition: LINEAR 0.5; + } + program { + name: "current_displays_setup_clipper_below"; + signal: "conf,randr,dialog,policies,3"; + source: "e"; + action: STATE_SET "below" 0.0; + target: "current_displays_setup/clipper"; + target: "new_display/clipper"; + after: "new_display_below_visible_set"; + transition: LINEAR 0.5; + } + program { + name: "new_display_below_visible_set"; + action: STATE_SET "below_visible" 0.0; + target: "new_display/clipper"; + transition: LINEAR 0.5; + } + program { + name: "current_displays_setup_clipper_left"; + signal: "conf,randr,dialog,policies,4"; + source: "e"; + action: STATE_SET "left" 0.0; + target: "current_displays_setup/clipper"; + target: "new_display/clipper"; + after: "new_display_left_visible_set"; + transition: LINEAR 0.5; + } + program { + name: "new_display_left_visible_set"; + action: STATE_SET "left_visible" 0.0; + target: "new_display/clipper"; + transition: LINEAR 0.5; + } + program { + name: "current_displays_setup_clipper_clone"; + signal: "conf,randr,dialog,policies,5"; + source: "e"; + action: STATE_SET "clone" 0.0; + target: "current_displays_setup/clipper"; + target: "new_display/clipper"; + after: "new_display_clone_visible_set"; + transition: LINEAR 0.5; + } + program { + name: "new_display_clone_visible_set"; + action: STATE_SET "clone_visible" 0.0; + target: "new_display/clipper"; + transition: LINEAR 0.5; + } + program { + name: "current_displays_setup_clipper_none"; + signal: "conf,randr,dialog,policies,6"; + source: "e"; + action: STATE_SET "none" 0.0; + target: "current_displays_setup/clipper"; + target: "new_display/clipper"; + //after: "new_display_none_visible_set"; + transition: LINEAR 0.5; + } + /* + * following is an analog program for none, but we don't want to show + * it anyway. + program { + name: "new_display_none_visible_set"; + action: STATE_SET "none_visible" 0.0; + target: "new_display/clipper"; + transition: LINEAR 0.5; + } + */ + } + } + + // Text objects for rotation and reflection + group { + name: "e/conf/randr/dialog/subdialog/orientation"; + + parts { + part { + name: "clip"; + type: RECT; + mouse_events: 0; + description { + state: "default" 0.0; + rel1.relative: 0.0 0.0; + rel2.relative: 1.0 1.0; + } + } + part { + name: "display"; + clip_to: "clip"; + mouse_events: 0; + description { + state: "default" 0.0; + aspect: 1.0 1.0; + aspect_preference: BOTH; + image.normal: "video-display.svg"; + } + } + part { + name: "orientation_text"; + clip_to: "clip"; + type: TEXT; + mouse_events: 0; + scale: 1; + description { + state: "default" 0.0; + rel1.relative: 0.0 0.0; + rel2.relative: 1.0 0.8; + color: 0 0 0 255; + text { + //Maybe use some default theme label text style later + text: "Orientation"; + font: "Sans:style=Bold"; + /* Use the Bold style + * of the Sans font from + * fontconfig */ + size: 10; + /* size in pixels - 10 */ + min: 0 1; + /* the text will not determine minimum horizontal + * size but WILL determine minimal vertical size + * (thus 0 1 - horiz then vert flags) */ + /* align text to top-left of the region + * given */ + text_class: "title_bar"; + /* text class - so font and size + * can be changed by users */ + } + map { + on: 1; + rotation { + x: 0.0; + y: 0.0; + z: 0.0; + } + } + } + description { + state: "rotate" 0.90; + inherit: "default" 0.0; + map.rotation.z: 270.0; + } + description { + state: "rotate" 0.180; + inherit: "default" 0.0; + map.rotation.z: 180.0; + } + description { + state: "rotate" 0.270; + inherit: "default" 0.0; + map.rotation.z: 90.0; + } + description { + state: "reflect_horizontal" 0.0; + inherit: "default" 0.0; + map.rotation.y: 180.0; + } + description { + state: "reflect_vertical" 0.0; + inherit: "default" 0.0; + map.rotation.x: 180.0; + } + } + } + programs { + program { + name: "rot0"; + signal: "conf,randr,dialog,orientation,current,1"; + source: "e"; + action: STATE_SET "default" 0.0; + target: "orientation_text"; + transition: LINEAR 0.5; + } + program { + name: "rot90"; + signal: "conf,randr,dialog,orientation,current,2"; + source: "e"; + action: STATE_SET "rotate" 0.90; + target: "orientation_text"; + transition: LINEAR 0.5; + } + program { + name: "rot180"; + signal: "conf,randr,dialog,orientation,current,4"; + source: "e"; + action: STATE_SET "rotate" 0.180; + target: "orientation_text"; + transition: LINEAR 0.5; + } + program { + name: "rot270"; + signal: "conf,randr,dialog,orientation,current,8"; + source: "e"; + action: STATE_SET "rotate" 0.270; + target: "orientation_text"; + transition: LINEAR 0.5; + } + program { + name: "ref_x"; + signal: "conf,randr,dialog,orientation,current,16"; + source: "e"; + action: STATE_SET "reflect_horizontal" 0.0; + target: "orientation_text"; + transition: LINEAR 0.5; + } + program { + name: "ref_y"; + signal: "conf,randr,dialog,orientation,current,32"; + source: "e"; + action: STATE_SET "reflect_vertical" 0.0; + target: "orientation_text"; + transition: LINEAR 0.5; + } + } + + } + +} diff --git a/src/modules/conf_randr/e_int_config_randr.c b/src/modules/conf_randr/e_int_config_randr.c new file mode 100644 index 000000000..3a525e708 --- /dev/null +++ b/src/modules/conf_randr/e_int_config_randr.c @@ -0,0 +1,424 @@ +#include "e_int_config_randr.h" +#include "e_widget_toolbook.h" +#include "e.h" +#include "e_randr.h" + +/* + * BUGS: + * - ethumb sometimes returns garbage objects leading to a segv + * + * TODO: + * - write 1.2 per monitor configuration + * - write Smart object, so crtcs representations can be properly freed (events, + * etc.) + * + * IMPROVABLE: + * See comments starting with 'IMPROVABLE' + */ +#ifndef ECORE_X_RANDR_1_2 +#define ECORE_X_RANDR_1_2 ((1 << 16) | 2) +#endif +#ifndef ECORE_X_RANDR_1_3 +#define ECORE_X_RANDR_1_3 ((1 << 16) | 3) +#endif + + +#ifdef Ecore_X_Randr_None +#undef Ecore_X_Randr_None +#define Ecore_X_Randr_None 0 +#else +#define Ecore_X_Randr_None 0 +#endif +#ifdef Ecore_X_Randr_Unset +#undef Ecore_X_Randr_Unset +#define Ecore_X_Randr_Unset -1 +#else +#define Ecore_X_Randr_Unset -1 +#endif + +#define THEME_FILENAME "/e-module-conf_randr.edj" +#define TOOLBAR_ICONSIZE 16 + +static void *create_data (E_Config_Dialog *cfd); +static void free_cfdata (E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); +static int basic_check_changed (E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); +static int basic_apply_data (E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); +static Evas_Object *basic_create_widgets (E_Config_Dialog *cfd, Evas *evas, E_Config_Dialog_Data *cfdata); +static Eina_Bool _deferred_noxrandr_error (void *data); +static Eina_Bool _deferred_norates_error (void *data); + +// Functions for the arrangement subdialog interaction +extern Eina_Bool e_config_randr_dialog_subdialog_arrangement_create_data (E_Config_Dialog_Data *cfdata); +extern Evas_Object *e_config_randr_dialog_subdialog_arrangement_basic_create_widgets (Evas *canvas); +extern Eina_Bool e_config_randr_dialog_subdialog_arrangement_basic_check_changed (E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); +extern Eina_Bool e_config_randr_dialog_subdialog_arrangement_basic_apply_data (E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); +extern void e_config_randr_dialog_subdialog_arrangement_free_data (E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); +extern void e_config_randr_dialog_subdialog_arrangement_keep_changes (E_Config_Dialog_Data *cfdata); +extern void e_config_randr_dialog_subdialog_arrangement_discard_changes (E_Config_Dialog_Data *cfdata); + +// Functions for the policies subdialog interaction +extern Eina_Bool e_config_randr_dialog_subdialog_policies_create_data (E_Config_Dialog_Data *cfdata); +extern Evas_Object *e_config_randr_dialog_subdialog_policies_basic_create_widgets (Evas *canvas); +extern Eina_Bool e_config_randr_dialog_subdialog_policies_basic_check_changed (E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); +extern Eina_Bool e_config_randr_dialog_subdialog_policies_basic_apply_data (E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); +extern void e_config_randr_dialog_subdialog_policies_keep_changes (E_Config_Dialog_Data *cfdata); +extern void e_config_randr_dialog_subdialog_policies_discard_changes (E_Config_Dialog_Data *cfdata); + +// Functions for the resolutions subdialog interaction +extern Eina_Bool e_config_randr_dialog_subdialog_resolutions_create_data (E_Config_Dialog_Data *cfdata); +extern Evas_Object *e_config_randr_dialog_subdialog_resolutions_basic_create_widgets (Evas *canvas); +extern Eina_Bool e_config_randr_dialog_subdialog_resolutions_basic_check_changed (E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); +extern Eina_Bool e_config_randr_dialog_subdialog_resolutions_basic_apply_data (E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); +extern void e_config_randr_dialog_subdialog_resolutions_update_list (Evas *canvas, Evas_Object *crtc); +extern void e_config_randr_dialog_subdialog_resolutions_keep_changes (E_Config_Dialog_Data *cfdata); +extern void e_config_randr_dialog_subdialog_resolutions_discard_changes (E_Config_Dialog_Data *cfdata); + +// Functions for the orientation subdialog interaction +extern Eina_Bool e_config_randr_dialog_subdialog_orientation_create_data (E_Config_Dialog_Data *cfdata); +extern Evas_Object *e_config_randr_dialog_subdialog_orientation_basic_create_widgets (Evas *canvas); +extern Eina_Bool e_config_randr_dialog_subdialog_orientation_basic_check_changed (E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); +extern Eina_Bool e_config_randr_dialog_subdialog_orientation_basic_apply_data (E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); +extern void e_config_randr_dialog_subdialog_orientation_update_radio_buttons (Evas_Object *crtc); +extern void e_config_randr_dialog_subdialog_orientation_update_edje (Evas_Object *crtc); +extern void e_config_randr_dialog_subdialog_orientation_keep_changes (E_Config_Dialog_Data *cfdata); +extern void e_config_randr_dialog_subdialog_orientation_discard_changes (E_Config_Dialog_Data *cfdata); + +/* actual module specifics */ +E_Config_Dialog_Data *e_config_runtime_info = NULL; +extern E_Module *conf_randr_module; +char _theme_file_path[PATH_MAX]; + + E_Config_Randr_Dialog_Output_Dialog_Data * +_e_config_randr_dialog_output_dialog_data_new(E_Randr_Crtc_Info *crtc_info, E_Randr_Output_Info *output_info) +{ + E_Config_Randr_Dialog_Output_Dialog_Data *dialog_data; + + if ((!crtc_info && !output_info) || !(dialog_data = E_NEW(E_Config_Randr_Dialog_Output_Dialog_Data, 1))) return NULL; + if (crtc_info) + { + //already enabled screen + dialog_data->crtc = crtc_info; + } + else if (output_info) + { + //disabled monitor + dialog_data->output = output_info; + } + return dialog_data; + +_e_conf_randr_dialog_create_output_data_failed: + free(dialog_data); + return NULL; +} + + + static void * +create_data(E_Config_Dialog *cfd) +{ + Eina_List *iter; + E_Randr_Output_Info *output_info; + E_Config_Randr_Dialog_Output_Dialog_Data *odd; + + // Prove we got all things to get going + EINA_SAFETY_ON_TRUE_RETURN_VAL(!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2), NULL); + EINA_SAFETY_ON_TRUE_RETURN_VAL(!(e_config_runtime_info = E_NEW(E_Config_Dialog_Data, 1)), NULL); + + e_config_runtime_info->cfd = cfd; + + //Compose theme's file path and name + snprintf(_theme_file_path, sizeof(_theme_file_path), "%s%s", conf_randr_module->dir, THEME_FILENAME); + + e_config_runtime_info->manager = e_manager_current_get(); + EINA_LIST_FOREACH(e_randr_screen_info->rrvd_info.randr_info_12->outputs, iter, output_info) + { + //Create basic data struct for every connected output. + //Data would have to be recreated if a monitor is connected while dialog + //is open. + if (output_info->connection_status != ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED) + continue; + if ((odd = _e_config_randr_dialog_output_dialog_data_new(output_info->crtc, output_info))) + EINA_SAFETY_ON_FALSE_GOTO((e_config_runtime_info->output_dialog_data_list = eina_list_append(e_config_runtime_info->output_dialog_data_list, odd)), _e_conf_randr_create_data_failed_free_data); + } + + fprintf(stderr, "CONF_RANDR: Added %d output data structs.\n", eina_list_count(e_config_runtime_info->output_dialog_data_list)); + //FIXME: Properly (stack-like) free data when creation fails + EINA_SAFETY_ON_FALSE_GOTO(e_config_randr_dialog_subdialog_arrangement_create_data(e_config_runtime_info), _e_conf_randr_create_data_failed_free_data); + EINA_SAFETY_ON_FALSE_GOTO(e_config_randr_dialog_subdialog_resolutions_create_data(e_config_runtime_info), _e_conf_randr_create_data_failed_free_data); + EINA_SAFETY_ON_FALSE_GOTO(e_config_randr_dialog_subdialog_policies_create_data(e_config_runtime_info), _e_conf_randr_create_data_failed_free_data); + EINA_SAFETY_ON_FALSE_GOTO(e_config_randr_dialog_subdialog_orientation_create_data(e_config_runtime_info), _e_conf_randr_create_data_failed_free_data); + + return e_config_runtime_info; + +_e_conf_randr_create_data_failed_free_data: + free(e_config_runtime_info); + return NULL; +} + + static void +free_cfdata(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata) +{ + EINA_SAFETY_ON_TRUE_RETURN(!e_randr_screen_info); + e_config_randr_dialog_subdialog_arrangement_free_data(cfd, cfdata); + + if (cfdata) free(cfdata); + cfdata = NULL; +} + + static Eina_Bool +_e_conf_randr_confirmation_dialog_timer_cb(void *data) +{ + E_Config_Randr_Dialog_Confirmation_Dialog_Data *cdd = (E_Config_Randr_Dialog_Confirmation_Dialog_Data*)data; + char buf[4096]; + + if (!cdd) return ECORE_CALLBACK_CANCEL; + + --cdd->countdown; + + if (cdd->countdown > 0) + { + snprintf(buf, sizeof(buf), + _("Does this look OK? Click Keep if it does, or Restore if not.
" + "If you do not press a button, the previous settings will be restored in %d seconds."), cdd->countdown); + } + else + { + snprintf(buf, sizeof(buf), + _("Does this look OK? Click Keep if it does, or Restore if not.
" + "If you do not press a button, the previous settings will be restored IMMEDIATELY.")); + } + + e_dialog_text_set(cdd->dialog, buf); + + return (cdd->countdown > 0) ? ECORE_CALLBACK_RENEW : ECORE_CALLBACK_CANCEL; +} + + static void +_e_conf_randr_confirmation_dialog_delete_cb(E_Win *win) +{ + E_Dialog *dia; + E_Config_Randr_Dialog_Confirmation_Dialog_Data *cd; + E_Config_Dialog *cfd; + + dia = win->data; + cd = dia->data; + cd->cfdata->gui.confirmation_dialog = NULL; + cfd = cd->cfdata->cfd; + if (cd->timer) ecore_timer_del(cd->timer); + cd->timer = NULL; + free(cd); + e_object_del(E_OBJECT(dia)); + e_object_unref(E_OBJECT(cfd)); +} + + static void +_e_conf_randr_confirmation_dialog_keep_cb(void *data, E_Dialog *dia) +{ + E_Config_Randr_Dialog_Confirmation_Dialog_Data *cdd = (E_Config_Randr_Dialog_Confirmation_Dialog_Data*)data; + + if (!cdd) return; + + e_config_randr_dialog_subdialog_arrangement_keep_changes(cdd->cfdata); + e_config_randr_dialog_subdialog_orientation_keep_changes(cdd->cfdata); + e_config_randr_dialog_subdialog_policies_keep_changes(cdd->cfdata); + e_config_randr_dialog_subdialog_resolutions_keep_changes(cdd->cfdata); + _e_conf_randr_confirmation_dialog_delete_cb(dia->win); +} + + static void +_e_conf_randr_confirmation_dialog_discard_cb(void *data, E_Dialog *dia) +{ + E_Config_Randr_Dialog_Confirmation_Dialog_Data *cdd = (E_Config_Randr_Dialog_Confirmation_Dialog_Data*)data; + + if (!cdd) return; + + e_config_randr_dialog_subdialog_arrangement_discard_changes(cdd->cfdata); + e_config_randr_dialog_subdialog_orientation_discard_changes(cdd->cfdata); + e_config_randr_dialog_subdialog_policies_discard_changes(cdd->cfdata); + e_config_randr_dialog_subdialog_resolutions_discard_changes(cdd->cfdata); + _e_conf_randr_confirmation_dialog_delete_cb(dia->win); +} + + static void +_e_conf_randr_confirmation_dialog_store_cb(void *data, E_Dialog *dia) +{ + E_Config_Randr_Dialog_Confirmation_Dialog_Data *cdd = (E_Config_Randr_Dialog_Confirmation_Dialog_Data*)data; + + if (!cdd) return; + + _e_conf_randr_confirmation_dialog_keep_cb(data, dia); + e_randr_store_configuration(e_randr_screen_info); +} + + static void +_e_conf_randr_confirmation_dialog_new(E_Config_Dialog *cfd) +{ + E_Config_Randr_Dialog_Confirmation_Dialog_Data *cd = E_NEW(E_Config_Randr_Dialog_Confirmation_Dialog_Data, 1); + + if (!cd) return; + + cd->cfd = cfd; + + if((cd->dialog = e_dialog_new(cfd->con, "E", "e_randr_confirmation_dialog"))) + { + e_dialog_title_set(cd->dialog, _("New settings confirmation")); + cd->cfdata = cfd->cfdata; + cd->timer = ecore_timer_add(1.0, _e_conf_randr_confirmation_dialog_timer_cb, cd); + cd->countdown = 15; + cd->dialog->data = cd; + e_dialog_icon_set(cd->dialog, "preferences-system-screen-resolution", 48); + e_win_delete_callback_set(cd->dialog->win, _e_conf_randr_confirmation_dialog_delete_cb); + e_dialog_button_add(cd->dialog, _("Keep"), NULL, _e_conf_randr_confirmation_dialog_keep_cb, cd); + e_dialog_button_add(cd->dialog, _("Store Permanently"), NULL, _e_conf_randr_confirmation_dialog_store_cb, cd); + e_dialog_button_add(cd->dialog, _("Restore"), NULL, _e_conf_randr_confirmation_dialog_discard_cb, cd); + e_dialog_button_focus_num(cd->dialog, 1); + e_win_centered_set(cd->dialog->win, 1); + e_win_borderless_set(cd->dialog->win, 1); + e_win_layer_set(cd->dialog->win, 6); + e_win_sticky_set(cd->dialog->win, 1); + e_dialog_show(cd->dialog); + e_object_ref(E_OBJECT(cfd)); + } + +} + + static Evas_Object * +basic_create_widgets (E_Config_Dialog *cfd, Evas *canvas, E_Config_Dialog_Data *cfdata) +{ + Evas_Object *table = NULL, *wl = NULL; + + EINA_SAFETY_ON_TRUE_RETURN_VAL (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2), NULL); + EINA_SAFETY_ON_TRUE_RETURN_VAL((!canvas || !cfdata), NULL); + + if(!(cfdata->gui.subdialogs.arrangement.dialog = e_config_randr_dialog_subdialog_arrangement_basic_create_widgets(canvas))) goto _e_config_randr_dialog_create_subdialog_arrangement_fail; + if(!(cfdata->gui.subdialogs.policies.dialog = e_config_randr_dialog_subdialog_policies_basic_create_widgets(canvas))) goto _e_config_randr_dialog_create_subdialog_policies_fail; + if(!(cfdata->gui.subdialogs.resolutions.dialog = e_config_randr_dialog_subdialog_resolutions_basic_create_widgets(canvas))) goto _e_config_randr_dialog_create_subdialog_resolutions_fail; + if(!(cfdata->gui.subdialogs.orientation.dialog = e_config_randr_dialog_subdialog_orientation_basic_create_widgets(canvas))) goto _e_config_randr_dialog_create_subdialog_orientation_fail; + + EINA_SAFETY_ON_FALSE_GOTO((table = e_widget_table_add(canvas, EINA_FALSE)), _e_config_randr_dialog_create_widgets_fail); + EINA_SAFETY_ON_FALSE_GOTO((wl = e_widget_list_add(canvas, EINA_FALSE, EINA_TRUE)), _e_config_randr_dialog_create_widget_list_fail); + + //e_widget_table_object_append(Evas_Object *obj, Evas_Object *sobj, int col, int row, int colspan, int rowspan, int fill_w, int fill_h, int expand_w, int expand_h); + e_widget_table_object_append(table, cfdata->gui.subdialogs.arrangement.dialog, 1, 1, 1, 1, EVAS_HINT_FILL, EVAS_HINT_FILL, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + /* + e_widget_table_object_append(table, cfdata->gui.subdialogs.policies.dialog, 1, 2, 1, 1, 0, 0, 0, 0); + e_widget_table_object_append(table, cfdata->gui.subdialogs.orientation.dialog, 2, 2, 1, 1, 0, 0, 0, 0); + e_widget_table_object_append(table, cfdata->gui.subdialogs.resolutions.dialog, 3, 2, 1, 1, EVAS_HINT_FILL, EVAS_HINT_FILL, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + */ + //e_widget_list_object_append(Evas_Object *obj, Evas_Object *sobj, int fill, int expand, double align); + e_widget_list_object_append(wl, cfdata->gui.subdialogs.policies.dialog, 0, 0, 0.0); + e_widget_list_object_append(wl, cfdata->gui.subdialogs.orientation.dialog, 0, 0, 0.0); + e_widget_list_object_append(wl, cfdata->gui.subdialogs.resolutions.dialog, EVAS_HINT_FILL, EVAS_HINT_EXPAND, 1.0); + e_widget_table_object_append(table, wl, 1, 2, 1, 1, EVAS_HINT_FILL, EVAS_HINT_FILL, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + cfdata->gui.widget_list = wl; + + cfdata->gui.dialog = table; + + e_dialog_resizable_set(cfd->dia, EINA_TRUE); + + return cfdata->gui.dialog; + +_e_config_randr_dialog_create_widget_list_fail: + evas_object_del(table); +_e_config_randr_dialog_create_widgets_fail: + evas_object_del(cfdata->gui.subdialogs.orientation.dialog); +_e_config_randr_dialog_create_subdialog_orientation_fail: + evas_object_del(cfdata->gui.subdialogs.resolutions.dialog); +_e_config_randr_dialog_create_subdialog_resolutions_fail: + evas_object_del(cfdata->gui.subdialogs.policies.dialog); +_e_config_randr_dialog_create_subdialog_policies_fail: + evas_object_del(cfdata->gui.subdialogs.arrangement.dialog); +_e_config_randr_dialog_create_subdialog_arrangement_fail: + return NULL; +} + +static int + basic_apply_data +(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata) +{ + Eina_Bool ret = EINA_TRUE; + + fprintf(stderr, "CONF_RANDR: New configuration is beeing applied.\n"); + //this is a special case, where the function is called, before the + //configuration data is created. + if (!cfdata) return EINA_FALSE; + + //the order matters except for policies! + if (e_config_randr_dialog_subdialog_policies_basic_check_changed(cfd, cfdata)) + { + ret &= e_config_randr_dialog_subdialog_policies_basic_apply_data(cfd, cfdata); + if (!ret) return EINA_FALSE; + } + + if (e_config_randr_dialog_subdialog_resolutions_basic_check_changed(cfd, cfdata)) + { + ret &= e_config_randr_dialog_subdialog_resolutions_basic_apply_data(cfd, cfdata); + if (!ret) return EINA_FALSE; + } + + if (e_config_randr_dialog_subdialog_arrangement_basic_check_changed(cfd, cfdata)) + { + ret &= e_config_randr_dialog_subdialog_arrangement_basic_apply_data(cfd, cfdata); + if (!ret) return EINA_FALSE; + } + + if (e_config_randr_dialog_subdialog_orientation_basic_check_changed(cfd, cfdata)) + ret &= e_config_randr_dialog_subdialog_orientation_basic_apply_data(cfd, cfdata); + + _e_conf_randr_confirmation_dialog_new(cfd); + + return ret; +} + +E_Config_Dialog * +e_int_config_randr(E_Container *con, const char *params __UNUSED__){ + E_Config_Dialog *cfd; + E_Config_Dialog_View *v; + + if (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2)) + { + ecore_timer_add(0.5, _deferred_noxrandr_error, NULL); + fprintf(stderr, "CONF_RANDR: XRandR version >= 1.2 necessary to work.\n"); + return NULL; + } + + //Dialog already opened? + if (e_config_dialog_find("E", "screen/screen_setup")) return NULL; + + v = E_NEW(E_Config_Dialog_View, 1); + v->create_cfdata = create_data; + v->free_cfdata = free_cfdata; + v->basic.apply_cfdata = basic_apply_data; + v->basic.create_widgets = basic_create_widgets; + v->basic.check_changed = basic_check_changed; + //v->override_auto_apply = 0; + + cfd = e_config_dialog_new(con, _("Screen Setup"), + "E", "screen/screen_setup", + "preferences-system-screen-setup", 0, v, NULL); + return cfd; +} + + static Eina_Bool +_deferred_noxrandr_error(void *data __UNUSED__) +{ + e_util_dialog_show(_("Missing Features"), + _("Your X Display Server is missing support for
" + "the XRandR (X Resize and Rotate) extension version 1.2 or above.
" + "You cannot change screen resolutions without
" + "the support of this extension. It could also be
" + "that at the time ecore was built, there
" + "was no XRandR support detected.")); + return ECORE_CALLBACK_CANCEL; +} + + static int +basic_check_changed (E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata) +{ + if (!cfdata) return EINA_FALSE; + else + return (e_config_randr_dialog_subdialog_arrangement_basic_check_changed(cfd, cfdata) + || e_config_randr_dialog_subdialog_policies_basic_check_changed(cfd, cfdata) + || e_config_randr_dialog_subdialog_orientation_basic_check_changed(cfd, cfdata) + || e_config_randr_dialog_subdialog_resolutions_basic_check_changed(cfd, cfdata)); +} + diff --git a/src/modules/conf_randr/e_int_config_randr.h b/src/modules/conf_randr/e_int_config_randr.h new file mode 100644 index 000000000..5356e2494 --- /dev/null +++ b/src/modules/conf_randr/e_int_config_randr.h @@ -0,0 +1,73 @@ +#ifdef E_TYPEDEFS +#else +#ifndef E_INT_CONFIG_RANDR_H +#define E_INT_CONFIG_RANDR_H + +#include "e.h" + +typedef struct _E_Config_Randr_Dialog_Output_Dialog_Data E_Config_Randr_Dialog_Output_Dialog_Data; +typedef struct _E_Config_Randr_Dialog_Confirmation_Dialog_Data E_Config_Randr_Dialog_Confirmation_Dialog_Data; + +struct _E_Config_Dialog_Data +{ + E_Config_Dialog *cfd; + + //list of E_Config_Randr_Dialog_Output_Dialog_Data + Eina_List *output_dialog_data_list; + E_Manager *manager; + struct { + Evas_Object *dialog, *widget_list, *selected_eo; + E_Config_Randr_Dialog_Output_Dialog_Data *selected_output_dd; + E_Config_Randr_Dialog_Confirmation_Dialog_Data *confirmation_dialog; + struct { + struct { + Evas_Object *dialog, *swallowing_edje, *smart_parent, *suggestion, *clipper; + Evas_Coord_Point previous_pos, relative_zero; + int suggestion_dist_min; + } arrangement; + struct { + Evas_Object *dialog; + //Evas_Object *swallowing_edje; + Evas_Object *radio_above, *radio_right, *radio_below, *radio_left, *radio_clone, *radio_none; + int radio_val; + //Evas_Object *current_displays_setup, *current_displays_setup_background, *new_display, *new_display_background; + } policies; + struct { + Evas_Object *dialog; + } resolutions; + struct { + Evas_Object *dialog; + //Evas_Object *swallowing_edje; + Evas_Object *radio_normal, *radio_rot90, *radio_rot180, *radio_rot270, *radio_reflect_horizontal, *radio_reflect_vertical; + int radio_val; + } orientation; + } subdialogs; + } gui; + Ecore_X_Randr_Screen_Size screen_size; + +}; + +struct _E_Config_Randr_Dialog_Output_Dialog_Data +{ + E_Randr_Crtc_Info *crtc; + E_Randr_Output_Info *output; + Evas_Coord_Point previous_pos, new_pos; + Ecore_X_Randr_Mode_Info *previous_mode, *new_mode, *preferred_mode; + Ecore_X_Randr_Orientation previous_orientation, new_orientation; + Ecore_X_Randr_Output_Policy previous_policy, new_policy; + Evas_Object *bg; +}; + +struct _E_Config_Randr_Dialog_Confirmation_Dialog_Data +{ + E_Config_Dialog *cfd; + E_Config_Dialog_Data *cfdata; + E_Dialog *dialog; + Ecore_Timer *timer; + int countdown; +}; + +E_Config_Dialog *e_int_config_randr(E_Container *con, const char *params __UNUSED__); + +#endif +#endif diff --git a/src/modules/conf_randr/e_int_config_randr_arrangement.c b/src/modules/conf_randr/e_int_config_randr_arrangement.c new file mode 100644 index 000000000..d30260ace --- /dev/null +++ b/src/modules/conf_randr/e_int_config_randr_arrangement.c @@ -0,0 +1,806 @@ +#include "e_int_config_randr.h" +#include "e_randr.h" +#include "Ecore_X.h" + +#ifndef ECORE_X_RANDR_1_2 +#define ECORE_X_RANDR_1_2 ((1 << 16) | 2) +#endif +#ifndef ECORE_X_RANDR_1_3 +#define ECORE_X_RANDR_1_3 ((1 << 16) | 3) +#endif + +#ifndef Ecore_X_Randr_Unset +#define Ecore_X_Randr_Unset -1 +#endif + +#define DOUBLECLICK_TIMEOUT 0.2 +#define CRTC_THUMB_SIZE_W 300 +#define CRTC_THUMB_SIZE_H 300 + +Eina_Bool e_config_randr_dialog_subdialog_arrangement_create_data (E_Config_Dialog_Data *e_config_runtime_info); +Evas_Object *e_config_randr_dialog_subdialog_arrangement_basic_create_widgets (Evas *canvas); +Eina_Bool e_config_randr_dialog_subdialog_arrangement_basic_check_changed (E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); +Eina_Bool e_config_randr_dialog_subdialog_arrangement_basic_apply_data (E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); +void e_config_randr_dialog_subdialog_arrangement_free_data (E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); +static inline Eina_List *_e_config_randr_dialog_subdialog_arrangement_neighbors_get (Evas_Object *obj); +static void _e_config_randr_dialog_subdialog_arrangement_determine_positions_recursive (Evas_Object *obj); + +static inline E_Config_Randr_Dialog_Output_Dialog_Data *_e_config_randr_dialog_subdialog_arrangement_output_dialog_data_new (E_Randr_Crtc_Info *crtc_info, E_Randr_Output_Info *output_info); +static inline void _e_config_randr_dialog_subdialog_arrangement_suggestion_add (Evas *evas); +static inline void _e_config_randr_dialog_subdialog_arrangement_make_suggestion (Evas_Object *obj); +static void _e_config_randr_dialog_subdialog_arrangement_smart_class_resize (Evas_Object *obj, Evas_Coord w, Evas_Coord h); +static Evas_Object *_e_config_randr_dialog_subdialog_arrangement_output_add (Evas *canvas, E_Config_Randr_Dialog_Output_Dialog_Data *output_dialog_data); +static void _e_config_randr_dialog_subdialog_arrangement_output_mouse_down_cb (void *data, Evas *e, Evas_Object *obj, void *event_info); +static void _e_config_randr_dialog_subdialog_arrangement_output_mouse_move_cb (void *data, Evas *e, Evas_Object *obj, void *event_info); +static void _e_config_randr_dialog_subdialog_arrangement_output_mouse_up_cb (void *data, Evas *e, Evas_Object *obj, void *event_info); + +// Function for the resolutions subdialog interaction +extern void e_config_randr_dialog_subdialog_resolutions_update_list (Evas_Object *crtc); +// Function for the orientation subdialog interaction +extern void e_config_randr_dialog_subdialog_orientation_update_radio_buttons (Evas_Object *crtc); +extern void e_config_randr_dialog_subdialog_orientation_update_edje (Evas_Object *crtc); +// Functions for the orientation subdialog interaction +extern void e_config_randr_dialog_subdialog_policies_update_radio_buttons (Evas_Object *crtc); + +Evas_Smart_Class screen_setup_smart_class = EVAS_SMART_CLASS_INIT_NAME_VERSION("EvasObjectSmartScreenSetup"); +Evas_Smart *screen_setup_smart; + +extern E_Config_Dialog_Data *e_config_runtime_info; +extern char _theme_file_path[]; + + static void +_e_config_randr_dialog_subdialog_arrangement_output_dialog_data_fill(E_Config_Randr_Dialog_Output_Dialog_Data *odd) +{ + if (!odd) return; + + if (odd->crtc) + { + //already enabled screen + odd->previous_pos.x = odd->crtc->geometry.x; + odd->previous_pos.y = odd->crtc->geometry.y; + odd->previous_mode = odd->crtc->current_mode; + } + else if (odd->output) + { + //disabled monitor + //try to get a mode from the preferred list, else use default list + if(!(odd->preferred_mode = (Ecore_X_Randr_Mode_Info*)eina_list_data_get(eina_list_last(odd->output->preferred_modes)))) + odd->preferred_mode = (Ecore_X_Randr_Mode_Info*)eina_list_data_get(eina_list_last(odd->output->modes)); + odd->previous_pos.x = Ecore_X_Randr_Unset; + odd->previous_pos.y = Ecore_X_Randr_Unset; + } + + odd->new_pos.x = Ecore_X_Randr_Unset; + odd->new_pos.y = Ecore_X_Randr_Unset; +} + + Eina_Bool +e_config_randr_dialog_subdialog_arrangement_create_data(E_Config_Dialog_Data *data) +{ + Eina_List *iter; + E_Config_Randr_Dialog_Output_Dialog_Data *dialog_data; + + EINA_LIST_FOREACH(data->output_dialog_data_list, iter, dialog_data) + { + _e_config_randr_dialog_subdialog_arrangement_output_dialog_data_fill(dialog_data); + } + + return EINA_TRUE; +} + +//IMPROVABLE: Clean up properly if instances can't be created + Evas_Object * +e_config_randr_dialog_subdialog_arrangement_basic_create_widgets(Evas *canvas) +{ + Evas_Object *subdialog, *crtc; + E_Config_Randr_Dialog_Output_Dialog_Data *output_dialog_data; + Eina_List *iter; + + if (!canvas || !e_config_runtime_info || !e_config_runtime_info->output_dialog_data_list) return NULL; + + //initialize smart object + evas_object_smart_clipped_smart_set(&screen_setup_smart_class); + screen_setup_smart_class.resize = _e_config_randr_dialog_subdialog_arrangement_smart_class_resize; + screen_setup_smart = evas_smart_class_new(&screen_setup_smart_class); + + subdialog = evas_object_smart_add(canvas, screen_setup_smart); + e_config_runtime_info->gui.subdialogs.arrangement.clipper = evas_object_smart_clipped_clipper_get(subdialog); + fprintf(stderr, "CONF_RANDR: Arrangement subdialog added (%p).\n", subdialog); + + + //only use information we can restore. + EINA_LIST_FOREACH(e_config_runtime_info->output_dialog_data_list, iter, output_dialog_data) + { + if ((!output_dialog_data->crtc && !output_dialog_data->output)) + continue; + crtc = _e_config_randr_dialog_subdialog_arrangement_output_add(canvas, output_dialog_data); + + if (!crtc) continue; + evas_object_show(crtc); + + evas_object_event_callback_add (crtc, EVAS_CALLBACK_MOUSE_DOWN, _e_config_randr_dialog_subdialog_arrangement_output_mouse_down_cb, NULL); + evas_object_event_callback_add (crtc, EVAS_CALLBACK_MOUSE_MOVE, _e_config_randr_dialog_subdialog_arrangement_output_mouse_move_cb, NULL); + evas_object_event_callback_add (crtc, EVAS_CALLBACK_MOUSE_UP, _e_config_randr_dialog_subdialog_arrangement_output_mouse_up_cb, NULL); + + + evas_object_smart_member_add(crtc, subdialog); + fprintf(stderr, "CONF_RANDR: CRTC representation (%p) added to arrangement subdialog (%p).\n", crtc, subdialog); + } + + e_config_runtime_info->gui.subdialogs.arrangement.smart_parent = subdialog; + + return subdialog; +} + + static Evas_Object * +_e_config_randr_dialog_subdialog_arrangement_output_add(Evas *canvas, E_Config_Randr_Dialog_Output_Dialog_Data *output_dialog_data) +{ + E_Randr_Output_Info *output_info; + Evas_Object *output, *bg; + const char* output_name = NULL; + + if (!canvas || !output_dialog_data || !e_config_runtime_info) return NULL; + + EINA_SAFETY_ON_FALSE_RETURN_VAL((output = edje_object_add(canvas)), NULL); + + //set instance data for output + evas_object_data_set(output, "output_info", output_dialog_data); + + //set theme for monitor representation + EINA_SAFETY_ON_FALSE_GOTO(edje_object_file_set(output, _theme_file_path, "e/conf/randr/dialog/subdialog/arrangement/output"), _e_config_randr_dialog_subdialog_arrangement_output_add_edje_set_fail); + //indicate monitor state + if (!output_dialog_data->crtc || (output_dialog_data->crtc && !output_dialog_data->previous_mode)) + edje_object_signal_emit(output, "disabled", "e"); + else + edje_object_signal_emit(output, "enabled", "e"); + //for now use deskpreview widget as background of output, maybe change this to + //live image from comp module + output_dialog_data->bg = e_widget_deskpreview_add(canvas, 1, 1); + edje_object_part_swallow(output, "e.swallow.content", output_dialog_data->bg); + + //Try to get the name of the monitor connected to the output's last output via edid + //else use the output's name + if (output_dialog_data->crtc) + output_info = (E_Randr_Output_Info*)eina_list_data_get(eina_list_last(output_dialog_data->crtc->outputs)); + else + output_info = output_dialog_data->output; + if (output_info) + { + if (ecore_x_randr_edid_has_valid_header(output_info->edid, output_info->edid_length)) + output_name = ecore_x_randr_edid_display_name_get(output_info->edid, output_info->edid_length); + else if (output_info->name) + output_name = output_info->name; + } + if (output_name) + edje_object_part_text_set(output, "output_txt", output_name); + + //set output orientation + e_config_randr_dialog_subdialog_orientation_update_edje(output); + return output; + +_e_config_randr_dialog_subdialog_arrangement_output_add_edje_set_fail: + evas_object_del(output); + return NULL; +} + + static void +_e_config_randr_dialog_subdialog_arrangement_smart_class_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h) +{ + Evas_Object *output; + Evas_Coord real_sum_w = 0 , real_sum_h = 0; + Eina_Rectangle parent_geo, new_geo; + Evas_Coord_Point offset = {.x = 0, .y = 0}; + Evas_Coord offset_x_max = 0; + float scaling_factor = 0.1; + Eina_List *lst, *itr; + const E_Config_Randr_Dialog_Output_Dialog_Data *output_dialog_data; + + evas_object_geometry_get(obj, &parent_geo.x, &parent_geo.y, &parent_geo.w, &parent_geo.h); + fprintf(stderr, "CONF_RANDR: Arrangement dialog shall be resized to %d x %d\n", w, h); + fprintf(stderr, "CONF_RANDR: Arrangement dialog Smart object geo: %d x %d, %d x %d\n", parent_geo.x, parent_geo.y, parent_geo.w, parent_geo.h); + if ((w < 1) || (h < 1)) return; + + lst = evas_object_smart_members_get(obj); + //Calc average aspect ratio from all available monitors + EINA_LIST_FOREACH(lst, itr, output) + { + if ((output == e_config_runtime_info->gui.subdialogs.arrangement.clipper) || !(output_dialog_data = evas_object_data_get(output, "output_info")) || (!output_dialog_data->previous_mode && !output_dialog_data->preferred_mode)) continue; + if (output_dialog_data->previous_mode) + { + real_sum_w += output_dialog_data->previous_mode->width; + real_sum_h += output_dialog_data->previous_mode->height; + } + else + { + real_sum_w += output_dialog_data->preferred_mode->width; + real_sum_h += output_dialog_data->preferred_mode->height; + } + } + + scaling_factor = (((float)parent_geo.w / (float)real_sum_w) < ((float)parent_geo.h / (float)real_sum_h)) ? ((float)parent_geo.w / (float)real_sum_w) : ((float)parent_geo.h / (float)real_sum_h); + scaling_factor *= e_scale; + + EINA_LIST_FOREACH(lst, itr, output) + { + //Skip elements that are either the clipped smart object or falsely added + //to the list of outputs (which should not happen) + if ((output == e_config_runtime_info->gui.subdialogs.arrangement.clipper) || !(output_dialog_data = evas_object_data_get(output, "output_info"))) continue; + if (output_dialog_data->previous_mode) + { + new_geo.w = (int)((float)output_dialog_data->previous_mode->width * scaling_factor); + new_geo.h = (int)((float)output_dialog_data->previous_mode->height * scaling_factor); + } + else if (output_dialog_data->preferred_mode) + { + new_geo.w = (int)((float)output_dialog_data->preferred_mode->width * scaling_factor); + new_geo.h = (int)((float)output_dialog_data->preferred_mode->height * scaling_factor); + } + else + { + fprintf(stderr, "CONF_RANDR: Can't resize thumb, as neither mode nor preferred mode are avavailable for %x\n", (output_dialog_data->crtc ? output_dialog_data->crtc->xid : output_dialog_data->output->xid)); + continue; + } + if ((new_geo.w <= 0) || (new_geo.h <= 0)) + { + //this is an effect, occuring during dialog closing. + //If we don't return here, e_thumb will segfault! + return; + } + if ((output_dialog_data->previous_pos.x == Ecore_X_Randr_Unset) || (output_dialog_data->previous_pos.y == Ecore_X_Randr_Unset)) + { + //this is a non enabled monitor + new_geo.x = parent_geo.x + parent_geo.w - new_geo.w - offset.x; + new_geo.y = parent_geo.y + offset.y; + offset.y = new_geo.y + new_geo.h; + if (offset_x_max < new_geo.w) + { + //adopt new max value for x + offset_x_max = new_geo.w; + } + if ((offset.y + new_geo.h) > (parent_geo.y + parent_geo.h)) + { + //reset offset.y and adjust offset.x + offset.y = 0; + offset.x += offset_x_max; + } + } + else + { + new_geo.x = ((int)((float)output_dialog_data->previous_pos.x * scaling_factor)) + parent_geo.x; + new_geo.y = ((int)((float)output_dialog_data->previous_pos.y * scaling_factor)) + parent_geo.y; + } + //resize edje element + evas_object_resize(output, new_geo.w, new_geo.h); + //also resize bg + e_thumb_icon_size_set(output_dialog_data->bg, new_geo.w, new_geo.h); //need to clarify the usage of e_thumb. Usable without e_thumb_icon_file_set??!! + evas_object_move(output, new_geo.x, new_geo.y); + fprintf(stderr, "CONF_RANDR: output representation %p was resized to %d x %d\n", output, new_geo.w, new_geo.h); + fprintf(stderr, "CONF_RANDR: output representation %p was moved to %d x %d\n", output, new_geo.x, new_geo.y); + } +} + + static void +_e_config_randr_dialog_subdialog_arrangement_output_mouse_down_cb (void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + Evas_Event_Mouse_Down *ev = (Evas_Event_Mouse_Down*)event_info; + Evas_Object *element = NULL; + Eina_List *iter; + Eina_Bool crtc_selected = EINA_FALSE; + + EINA_LIST_FOREACH(evas_object_smart_members_get(evas_object_smart_parent_get(obj)), iter, element) + { + if (e_config_runtime_info->gui.subdialogs.arrangement.clipper == obj) continue; + if (element != obj) + edje_object_signal_emit(element, "deselect", "e"); + else + { + edje_object_signal_emit(element, "select", "e"); + //update data for other dialogs + e_config_runtime_info->gui.selected_eo = obj; + + //update resolutions list + e_config_randr_dialog_subdialog_resolutions_update_list(obj); + + //update orientation radio buttons + e_config_randr_dialog_subdialog_orientation_update_radio_buttons(obj); + + //update policy radio buttons + e_config_randr_dialog_subdialog_policies_update_radio_buttons(obj); + + crtc_selected = EINA_TRUE; + } + } + if (!crtc_selected) + { + //update data for other dialogs + e_config_runtime_info->gui.selected_eo = NULL; + + //update resolutions list + e_config_randr_dialog_subdialog_resolutions_update_list(NULL); + + //update orientation radio buttons + e_config_randr_dialog_subdialog_orientation_update_radio_buttons(NULL); + + //update policy radio buttons + e_config_randr_dialog_subdialog_policies_update_radio_buttons(NULL); + } + + evas_object_geometry_get(obj, &e_config_runtime_info->gui.subdialogs.arrangement.previous_pos.x, &e_config_runtime_info->gui.subdialogs.arrangement.previous_pos.y, NULL, NULL); +} + + static void +_e_config_randr_dialog_subdialog_arrangement_output_mouse_move_cb (void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + Evas_Event_Mouse_Move *ev = event_info; + Eina_Rectangle geo, parent; + Evas_Coord_Point delta, new; + + if (ev->buttons == 1) + { + evas_object_geometry_get (obj, &geo.x, &geo.y, &geo.w, &geo.h); + evas_object_geometry_get (evas_object_smart_parent_get(obj), &parent.x, &parent.y, &parent.w, &parent.h); + delta.x = ev->cur.canvas.x - ev->prev.canvas.x; + delta.y = ev->cur.canvas.y - ev->prev.canvas.y; + + new.x = geo.x + delta.x; + new.y = geo.y + delta.y; + //respect container borders + if (new.x < parent.x + 1) + new.x = parent.x + 1; + else if (new.x > parent.x + parent.w - geo.w) + new.x = parent.x + parent.w - geo.w; + if (new.y < parent.y + 1) + new.y = parent.y + 1; + else if (new.y > parent.y + parent.h - geo.h) + new.y = parent.y + parent.h - geo.h; + //only take action if position changed + if ((geo.x != new.x) || (geo.y != new.y)) + { + evas_object_move(obj, new.x, new.y); + _e_config_randr_dialog_subdialog_arrangement_make_suggestion(obj); + } + } +} + + static void +_e_config_randr_dialog_subdialog_arrangement_output_mouse_up_cb (void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + Evas_Coord_Point coords; + + if (evas_object_visible_get(e_config_runtime_info->gui.subdialogs.arrangement.suggestion)) + { + edje_object_signal_emit(e_config_runtime_info->gui.subdialogs.arrangement.suggestion, "hide", "e"); + evas_object_geometry_get(e_config_runtime_info->gui.subdialogs.arrangement.suggestion, &coords.x, &coords.y, NULL, NULL); + evas_object_move(obj, coords.x, coords.y); + } + else + { + evas_object_move(obj, e_config_runtime_info->gui.subdialogs.arrangement.previous_pos.x, e_config_runtime_info->gui.subdialogs.arrangement.previous_pos.y); + } + +} + +void +_e_config_randr_dialog_subdialog_arrangement_suggestion_add(Evas *evas) +{ + const char *theme_data_item = NULL; + + e_config_runtime_info->gui.subdialogs.arrangement.suggestion = edje_object_add(evas); + edje_object_file_set(e_config_runtime_info->gui.subdialogs.arrangement.suggestion, _theme_file_path, "e/conf/randr/dialog/subdialog/arrangement/suggestion"); + if ((theme_data_item = edje_object_data_get(e_config_runtime_info->gui.subdialogs.arrangement.suggestion, "distance_min"))) + e_config_runtime_info->gui.subdialogs.arrangement.suggestion_dist_min = MIN(MAX(atoi(theme_data_item), 0), 100); + else + e_config_runtime_info->gui.subdialogs.arrangement.suggestion_dist_min = 20; +} + + void +_e_config_randr_dialog_subdialog_arrangement_make_suggestion (Evas_Object *obj) +{ + Eina_List *li, *crtcs = evas_object_smart_members_get(evas_object_smart_parent_get(obj)); + Evas_Object *crtc = NULL; + Eina_Rectangle p_geo, geo, crtc_geo, s_geo; + int dxa = 10000, dya = 10000, tmp, min_dist; + + if (!obj) return; + + if (!e_config_runtime_info->gui.subdialogs.arrangement.suggestion) + { + _e_config_randr_dialog_subdialog_arrangement_suggestion_add(evas_object_evas_get(obj)); + evas_object_show(e_config_runtime_info->gui.subdialogs.arrangement.suggestion); + } + + min_dist = e_config_runtime_info->gui.subdialogs.arrangement.suggestion_dist_min; + + evas_object_geometry_get(evas_object_smart_parent_get(obj), &p_geo.x, &p_geo.y, &p_geo.w, &p_geo.h); + evas_object_geometry_get(obj, &geo.x, &geo.y, &geo.w, &geo.h); + + s_geo.x = geo.x; + s_geo.y = geo.y; + s_geo.w = geo.w; + s_geo.h = geo.h; + + //compare possible positions + //aritifical (relative) 0x0 element + tmp = s_geo.x; + if ((tmp < dxa) && (tmp < min_dist)) + { + s_geo.x = p_geo.x; + dxa = tmp; + } + tmp = s_geo.y; + if ((tmp < dya) && (tmp < min_dist)) + { + s_geo.y = p_geo.y; + dya = tmp; + } + //iterate crtc list + EINA_LIST_FOREACH(crtcs, li, crtc) + { + if ((crtc == obj) || (crtc == e_config_runtime_info->gui.subdialogs.arrangement.clipper)) continue; + evas_object_geometry_get(crtc, &crtc_geo.x, &crtc_geo.y, &crtc_geo.w, &crtc_geo.h); + //X-Axis + tmp = abs(s_geo.x - crtc_geo.x); + if ((tmp < dxa) && (tmp < min_dist)) + { + s_geo.x = crtc_geo.x; + dxa = abs(s_geo.x - crtc_geo.x); + } + + tmp = abs(s_geo.x - (crtc_geo.x + crtc_geo.w)); + if ((tmp < dxa) && (tmp < min_dist)) + { + s_geo.x = (crtc_geo.x + crtc_geo.w); + dxa = tmp; + } + + tmp = abs((s_geo.x + s_geo.w) - (crtc_geo.x - 1)); + if ((tmp < dxa) && (tmp < min_dist)) + { + s_geo.x = (crtc_geo.x - s_geo.w); + dxa = tmp; + } + + tmp = abs((s_geo.x + s_geo.w) - (crtc_geo.x + crtc_geo.w)); + if ((tmp < dxa) && (tmp < min_dist)) + { + s_geo.x = (crtc_geo.x + crtc_geo.w - s_geo.w); + dxa = tmp; + } + + //Y-Axis + tmp = abs(s_geo.y - crtc_geo.y); + if ((tmp < dya) && (tmp < min_dist)) + { + s_geo.y = crtc_geo.y; + dya = abs(s_geo.y - crtc_geo.y); + } + + tmp = abs(s_geo.y - (crtc_geo.y + crtc_geo.h)); + if ((tmp < dya) && (tmp < min_dist)) + { + s_geo.y = (crtc_geo.y + crtc_geo.h); + dya = tmp; + } + + tmp = abs((s_geo.y + s_geo.h) - (crtc_geo.y - 1)); + if ((tmp < dya) && (tmp < min_dist)) + { + s_geo.y = (crtc_geo.y - s_geo.h); + dya = tmp; + } + + tmp = abs((s_geo.y + s_geo.h) - (crtc_geo.y + crtc_geo.h)); + if ((tmp < dya) && (tmp < min_dist)) + { + s_geo.y = (crtc_geo.y + crtc_geo.h - s_geo.h); + dya = tmp; + } + + } + + + if ((s_geo.x != geo.x) && (s_geo.y != geo.y)) + { + if (s_geo.x < p_geo.x) s_geo.x = p_geo.x; + if ((s_geo.x + s_geo.w) > (p_geo.x + p_geo.w)) s_geo.x = ((p_geo.x + p_geo.w) - s_geo.w); + if (s_geo.y < p_geo.y) s_geo.y = p_geo.y; + if ((s_geo.y + s_geo.h) > (p_geo.y + p_geo.h)) s_geo.y = ((p_geo.y + p_geo.h) - s_geo.h); + + if (!evas_object_visible_get(e_config_runtime_info->gui.subdialogs.arrangement.suggestion)) + { + evas_object_show(e_config_runtime_info->gui.subdialogs.arrangement.suggestion); + edje_object_signal_emit(e_config_runtime_info->gui.subdialogs.arrangement.suggestion, "show", "e"); + } + + evas_object_resize(e_config_runtime_info->gui.subdialogs.arrangement.suggestion, s_geo.w, s_geo.h); + evas_object_move(e_config_runtime_info->gui.subdialogs.arrangement.suggestion, s_geo.x, s_geo.y); + } + else + { + edje_object_signal_emit(e_config_runtime_info->gui.subdialogs.arrangement.suggestion, "hide", "e"); + evas_object_hide(e_config_runtime_info->gui.subdialogs.arrangement.suggestion); + } +} + + void +e_config_randr_dialog_subdialog_arrangement_free_data(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata) +{ + E_Config_Randr_Dialog_Output_Dialog_Data *dialog_data; + + EINA_SAFETY_ON_NULL_RETURN(cfdata); + + EINA_LIST_FREE(cfdata->output_dialog_data_list, dialog_data) + { + if (dialog_data) + { + if (dialog_data->bg) + { + evas_object_del(dialog_data->bg); + dialog_data->bg = NULL; + } + free(dialog_data); + dialog_data = NULL; + } + } +} + + static Eina_List +*_e_config_randr_dialog_subdialog_arrangement_neighbors_get(Evas_Object *obj) +{ + Evas_Object *smart_parent, *crtc; + Eina_List *crtcs, *iter, *neighbors = NULL; + Eina_Rectangle geo, neighbor_geo; + E_Config_Randr_Dialog_Output_Dialog_Data *dialog_data, *neighbor_info; + + smart_parent = evas_object_smart_parent_get(obj); + crtcs = evas_object_smart_members_get(smart_parent); + + EINA_SAFETY_ON_FALSE_RETURN_VAL((dialog_data = evas_object_data_get(obj, "output_info")), NULL); + evas_object_geometry_get(obj, &geo.x, &geo.y, &geo.w, &geo.h); + EINA_LIST_FOREACH(crtcs, iter, crtc) + { + if ((crtc == obj) + || (crtc == e_config_runtime_info->gui.subdialogs.arrangement.clipper)) continue; + evas_object_geometry_get(crtc, &neighbor_geo.x, &neighbor_geo.y, &neighbor_geo.w, &neighbor_geo.h); + if(!(neighbor_info = evas_object_data_get(crtc, "output_info"))) continue; + + if (((geo.x + geo.w) == neighbor_geo.x) + || (geo.x == (neighbor_geo.x + neighbor_geo.w)) + || (geo.x == neighbor_geo.x) + || ((geo.x + geo.w) == (neighbor_geo.x + neighbor_geo.w)) + || ((geo.y + geo.h) == neighbor_geo.y) + || (geo.y == (neighbor_geo.y + neighbor_geo.h)) + || (geo.y == neighbor_geo.y) + || ((geo.y + geo.h) == (neighbor_geo.y + neighbor_geo.h))) + { + neighbors = eina_list_append(neighbors, crtc); + } + } + + return neighbors; +} + + static void +_e_config_randr_dialog_subdialog_arrangement_determine_positions_recursive(Evas_Object *obj) +{ + Eina_List *neighbors, *iter; + Evas_Object *smart_parent, *crtc; + E_Config_Randr_Dialog_Output_Dialog_Data *dialog_data, *neighbor_info; + Eina_Rectangle geo, neighbor_geo, smart_geo; + + // Each object is seen as a tree. All its edges are compared to their + // neighbors and wandered recusively. + EINA_SAFETY_ON_NULL_RETURN(obj); + + smart_parent = e_config_runtime_info->gui.subdialogs.arrangement.smart_parent; + evas_object_geometry_get(smart_parent, &smart_geo.x, &smart_geo.y, &smart_geo.w, &smart_geo.h); + //fprintf(stderr, "CONF_RANDR: Smart Parent is at %dx%d\n", smart_geo.x, smart_geo.y); + neighbors = _e_config_randr_dialog_subdialog_arrangement_neighbors_get(obj); + + EINA_SAFETY_ON_FALSE_RETURN((dialog_data = evas_object_data_get(obj, "output_info"))); + evas_object_geometry_get(obj, &geo.x, &geo.y, &geo.w, &geo.h); + + //fprintf(stderr, "CONF_RANDR: Traversed element (%p) is at %dx%d\n", obj, geo.x, geo.y); + if (geo.x == e_config_runtime_info->gui.subdialogs.arrangement.relative_zero.x) dialog_data->new_pos.x = 0; + if (geo.y == e_config_runtime_info->gui.subdialogs.arrangement.relative_zero.y) dialog_data->new_pos.y = 0; + + if ((dialog_data->new_pos.x != 0) || (dialog_data->new_pos.y != 0)) + { + // Find neighbor object we can calculate our own coordinates from + EINA_LIST_FOREACH(neighbors, iter, crtc) + { + evas_object_geometry_get(crtc, &neighbor_geo.x, &neighbor_geo.y, &neighbor_geo.w, &neighbor_geo.h); + if (!(neighbor_info = evas_object_data_get(crtc, "output_info"))) continue; + + evas_object_geometry_get(crtc, &neighbor_geo.x, &neighbor_geo.y, &neighbor_geo.w, &neighbor_geo.h); + + if ((dialog_data->new_pos.x == Ecore_X_Randr_Unset) && (neighbor_info->new_pos.x != Ecore_X_Randr_Unset)) + { + if ((geo.x + geo.w) == neighbor_geo.x) + { + dialog_data->new_pos.x = neighbor_info->new_pos.x - dialog_data->previous_mode->width; + } + + if (geo.x == (neighbor_geo.x + neighbor_geo.w)) + { + dialog_data->new_pos.x = neighbor_info->new_pos.x + neighbor_info->previous_mode->width; + } + + if (geo.x == neighbor_geo.x) + { + dialog_data->new_pos.x = neighbor_info->new_pos.x; + } + + if ((geo.x + geo.w) == (neighbor_geo.x + neighbor_geo.w)) + { + dialog_data->new_pos.x = (neighbor_info->new_pos.x + neighbor_info->previous_mode->width) - dialog_data->previous_mode->width; + } + } + + if ((dialog_data->new_pos.y == Ecore_X_Randr_Unset) && (neighbor_info->new_pos.y != Ecore_X_Randr_Unset)) + { + if ((geo.y + geo.h) == neighbor_geo.y) + { + dialog_data->new_pos.y = neighbor_info->new_pos.y - dialog_data->previous_mode->height; + } + + if (geo.y == (neighbor_geo.y + neighbor_geo.h)) + { + dialog_data->new_pos.y = neighbor_info->new_pos.y + neighbor_info->previous_mode->height; + } + + if (geo.y == neighbor_geo.y) + { + dialog_data->new_pos.y = neighbor_info->new_pos.y; + } + + if ((geo.y + geo.h) == (neighbor_geo.y + neighbor_geo.h)) + { + dialog_data->new_pos.y = (neighbor_info->new_pos.y + neighbor_info->previous_mode->height) - dialog_data->previous_mode->height; + } + } + if ((dialog_data->new_pos.x != Ecore_X_Randr_Unset) + && (dialog_data->new_pos.y != Ecore_X_Randr_Unset)) + { + //fprintf(stderr, "CONF_RANDR: Determined position for %p: %dx%d\n", obj, dialog_data->new_pos.x, dialog_data->new_pos.y); + break; + } + } + } + if ((dialog_data->new_pos.x != Ecore_X_Randr_Unset) || (dialog_data->new_pos.y != Ecore_X_Randr_Unset)) + { + //Only wander all neighbors recursively, if they can use the current + //element as reference for their position + EINA_LIST_FOREACH(neighbors, iter, crtc) + { + neighbor_info = evas_object_data_get(crtc, "output_info"); + if ((neighbor_info->new_pos.x == Ecore_X_Randr_Unset) + || (neighbor_info->new_pos.y == Ecore_X_Randr_Unset)) + { + //fprintf(stderr, "CONF_RANDR: Now going to travel %p.\n", crtc); + _e_config_randr_dialog_subdialog_arrangement_determine_positions_recursive(crtc); + } + } + } + eina_list_free(neighbors); +} + + Eina_Bool +e_config_randr_dialog_subdialog_arrangement_basic_apply_data(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata) +{ + Eina_List *crtcs, *iter; + Evas_Object *smart_parent, *crtc, *top_left = NULL; + Eina_Rectangle geo, smart_geo; + E_Config_Randr_Dialog_Output_Dialog_Data *odd; + Evas_Coord_Point relz = { .x = 10000, .y = 10000}; + Eina_Bool arrangement_failed = EINA_FALSE; + + smart_parent = e_config_runtime_info->gui.subdialogs.arrangement.smart_parent; + evas_object_geometry_get(smart_parent, &smart_geo.x, &smart_geo.y, &smart_geo.w, &smart_geo.h); + crtcs = evas_object_smart_members_get(smart_parent); + + //Create virtual borders around the displayed representations by finding + //relative x and y as virtual 0x0 + EINA_LIST_FOREACH(crtcs, iter, crtc) + { + if (crtc == e_config_runtime_info->gui.subdialogs.arrangement.clipper) continue; + //Already reset values for upcoming calculation + if (!(odd = evas_object_data_get(crtc, "output_info"))) continue; + odd->new_pos.x = Ecore_X_Randr_Unset; + odd->new_pos.y = Ecore_X_Randr_Unset; + odd = NULL; + + //See whether this element is closer to 0x0 than any before + evas_object_geometry_get(crtc, &geo.x, &geo.y, &geo.w, &geo.h); + if (geo.x < relz.x) + { + relz.x = geo.x; + top_left = crtc; + } + if (geo.y < relz.y) + { + relz.y = geo.y; + top_left = crtc; + } + } + e_config_runtime_info->gui.subdialogs.arrangement.relative_zero.x = relz.x; + e_config_runtime_info->gui.subdialogs.arrangement.relative_zero.y = relz.y; + if (top_left) _e_config_randr_dialog_subdialog_arrangement_determine_positions_recursive(top_left); + + EINA_LIST_FOREACH(crtcs, iter, crtc) + { + if ((crtc == e_config_runtime_info->gui.subdialogs.arrangement.clipper) || !(odd = evas_object_data_get(crtc, "output_info")) || !odd->crtc + || ((odd->new_pos.x == Ecore_X_Randr_Unset) || (odd->new_pos.y == Ecore_X_Randr_Unset))) continue; + if ((odd->previous_pos.x != odd->new_pos.x) || (odd->previous_pos.y != odd->new_pos.y)) + { + fprintf(stderr, "CONF_RANDR: CRTC %x is moved to %dx%d\n", odd->crtc->xid, odd->new_pos.x, odd->new_pos.y); + if (!ecore_x_randr_crtc_pos_set(cfd->con->manager->root, odd->crtc->xid, odd->new_pos.x, odd->new_pos.y)) + { + arrangement_failed = EINA_TRUE; + break; + } + } + } + if (arrangement_failed) + return EINA_FALSE; + else + { + ecore_x_randr_screen_reset(cfd->con->manager->root); + return EINA_TRUE; + } +} + + Eina_Bool +e_config_randr_dialog_subdialog_arrangement_basic_check_changed(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata) +{ + Eina_List *iter; + E_Config_Randr_Dialog_Output_Dialog_Data *output_dialog_data; + + EINA_LIST_FOREACH(cfdata->output_dialog_data_list, iter, output_dialog_data) + { + if ((output_dialog_data->previous_pos.x != output_dialog_data->new_pos.x) + || (output_dialog_data->previous_pos.y != output_dialog_data->new_pos.y) + ) return EINA_TRUE; + } + return EINA_FALSE; +} + + void +e_config_randr_dialog_subdialog_arrangement_keep_changes(E_Config_Dialog_Data *cfdata) +{ + E_Config_Randr_Dialog_Output_Dialog_Data *odd; + Eina_List *iter; + + if (!cfdata) return; + + EINA_LIST_FOREACH(cfdata->output_dialog_data_list, iter, odd) + { + if (!odd->crtc || ((odd->new_pos.x == Ecore_X_Randr_Unset) || (odd->new_pos.y == Ecore_X_Randr_Unset))) continue; + odd->previous_pos.x = odd->new_pos.x; + odd->previous_pos.y = odd->new_pos.y; + odd->new_pos.x = Ecore_X_Randr_Unset; + odd->new_pos.y = Ecore_X_Randr_Unset; + } +} + + void +e_config_randr_dialog_subdialog_arrangement_discard_changes(E_Config_Dialog_Data *cfdata) +{ + E_Config_Randr_Dialog_Output_Dialog_Data *odd; + Eina_List *iter; + + if (!cfdata) return; + + EINA_LIST_FOREACH(cfdata->output_dialog_data_list, iter, odd) + { + if (!odd->crtc || ((odd->previous_pos.x == Ecore_X_Randr_Unset) || (odd->previous_pos.y == Ecore_X_Randr_Unset))) continue; + if (ecore_x_randr_crtc_pos_set(cfdata->manager->root, odd->crtc->xid, odd->previous_pos.x, odd->previous_pos.y)) + { + odd->new_pos.x = odd->previous_pos.x; + odd->new_pos.y = odd->previous_pos.y; + odd->previous_pos.x = Ecore_X_Randr_Unset; + odd->previous_pos.y = Ecore_X_Randr_Unset; + ecore_x_randr_screen_reset(cfdata->manager->root); + } + } +} diff --git a/src/modules/conf_randr/e_int_config_randr_orientation.c b/src/modules/conf_randr/e_int_config_randr_orientation.c new file mode 100644 index 000000000..3a0121baf --- /dev/null +++ b/src/modules/conf_randr/e_int_config_randr_orientation.c @@ -0,0 +1,336 @@ +#include "e_int_config_randr.h" +#include "e_randr.h" + +#ifndef Ecore_X_Randr_Unset +#define Ecore_X_Randr_Unset -1 +#endif + +#define RANDR_DIALOG_ORIENTATION_ALL (ECORE_X_RANDR_ORIENTATION_ROT_0 | ECORE_X_RANDR_ORIENTATION_ROT_90 | ECORE_X_RANDR_ORIENTATION_ROT_180 | ECORE_X_RANDR_ORIENTATION_ROT_270 | ECORE_X_RANDR_ORIENTATION_ROT_270 | ECORE_X_RANDR_ORIENTATION_FLIP_X | ECORE_X_RANDR_ORIENTATION_FLIP_Y) + +Eina_Bool e_config_randr_dialog_subdialog_orientation_create_data (E_Config_Dialog_Data *cfdata); +Evas_Object *e_config_randr_dialog_subdialog_orientation_basic_create_widgets(Evas *canvas); +Eina_Bool e_config_randr_dialog_subdialog_orientation_basic_apply_data (E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); +Eina_Bool e_config_randr_dialog_subdialog_orientation_basic_check_changed(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); +Eina_Bool e_config_randr_dialog_subdialog_orientation_basic_apply_data(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); +void e_config_randr_dialog_subdialog_orientation_update_radio_buttons(Evas_Object *crtc); +void e_config_randr_dialog_subdialog_orientation_update_edje(Evas_Object *crtc); + +static void _e_config_randr_dialog_subdialog_orientation_policy_mouse_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info); +extern E_Config_Dialog_Data *e_config_runtime_info; +extern char _theme_file_path[]; + +/* +static void +_e_config_randr_dialog_subdialog_orientation_radio_add_callbacks(void) +{ + evas_object_event_callback_add (e_config_runtime_info->gui.subdialogs.orientation.radio_reflect_vertical, EVAS_CALLBACK_MOUSE_UP, _e_config_randr_dialog_subdialog_orientation_policy_mouse_up_cb, NULL); + evas_object_event_callback_add (e_config_runtime_info->gui.subdialogs.orientation.radio_reflect_horizontal, EVAS_CALLBACK_MOUSE_UP, _e_config_randr_dialog_subdialog_orientation_policy_mouse_up_cb, NULL); + evas_object_event_callback_add (e_config_runtime_info->gui.subdialogs.orientation.radio_rot270, EVAS_CALLBACK_MOUSE_UP, _e_config_randr_dialog_subdialog_orientation_policy_mouse_up_cb, NULL); + evas_object_event_callback_add (e_config_runtime_info->gui.subdialogs.orientation.radio_rot180, EVAS_CALLBACK_MOUSE_UP, _e_config_randr_dialog_subdialog_orientation_policy_mouse_up_cb, NULL); + evas_object_event_callback_add (e_config_runtime_info->gui.subdialogs.orientation.radio_rot90, EVAS_CALLBACK_MOUSE_UP, _e_config_randr_dialog_subdialog_orientation_policy_mouse_up_cb, NULL); + evas_object_event_callback_add (e_config_runtime_info->gui.subdialogs.orientation.radio_normal, EVAS_CALLBACK_MOUSE_UP, _e_config_randr_dialog_subdialog_orientation_policy_mouse_up_cb, NULL); +} +*/ + + Eina_Bool +e_config_randr_dialog_subdialog_orientation_create_data(E_Config_Dialog_Data *cfdata) +{ + E_Config_Randr_Dialog_Output_Dialog_Data *odd; + E_Randr_Crtc_Info *ci; + Eina_List *iter; + + if (!cfdata || !cfdata->output_dialog_data_list) return EINA_FALSE; + + EINA_LIST_FOREACH(cfdata->output_dialog_data_list, iter, odd) + { + if (!ci || !ci->current_mode) continue; + odd->new_orientation = Ecore_X_Randr_Unset; + odd->previous_orientation = ci->current_orientation; + } + + return EINA_TRUE; +} + +Evas_Object * +e_config_randr_dialog_subdialog_orientation_basic_create_widgets(Evas *canvas) +{ + Evas_Object *subdialog; + E_Radio_Group *rg; + //char signal[29]; + + if (!canvas || !e_config_runtime_info) return NULL; + if (e_config_runtime_info->gui.subdialogs.orientation.dialog) return e_config_runtime_info->gui.subdialogs.orientation.dialog; + + if (!(subdialog = e_widget_framelist_add(canvas, _("Display Orientation"), EINA_FALSE))) return NULL; + + // Add radio buttons + if(!(rg = e_widget_radio_group_new(&e_config_runtime_info->gui.subdialogs.orientation.radio_val))) goto _e_config_randr_dialog_subdialog_orientation_radio_add_fail; + + //IMPROVABLE: use enum to determine objects via 'switch'-statement + e_config_runtime_info->gui.subdialogs.orientation.radio_normal = e_widget_radio_add(canvas, _("Normal"), ECORE_X_RANDR_OUTPUT_POLICY_ABOVE, rg); + e_widget_framelist_object_append(subdialog, e_config_runtime_info->gui.subdialogs.orientation.radio_normal); + + e_config_runtime_info->gui.subdialogs.orientation.radio_rot90 = e_widget_radio_add(canvas, _("Rotated, 90°"), ECORE_X_RANDR_OUTPUT_POLICY_RIGHT, rg); + e_widget_framelist_object_append(subdialog, e_config_runtime_info->gui.subdialogs.orientation.radio_rot90); + + e_config_runtime_info->gui.subdialogs.orientation.radio_rot180 = e_widget_radio_add(canvas, _("Rotated, 180°"), ECORE_X_RANDR_OUTPUT_POLICY_BELOW, rg); + e_widget_framelist_object_append(subdialog, e_config_runtime_info->gui.subdialogs.orientation.radio_rot180); + + e_config_runtime_info->gui.subdialogs.orientation.radio_rot270 = e_widget_radio_add(canvas, _("Rotated, 270°"), ECORE_X_RANDR_OUTPUT_POLICY_LEFT, rg); + e_widget_framelist_object_append(subdialog, e_config_runtime_info->gui.subdialogs.orientation.radio_rot270); + + e_config_runtime_info->gui.subdialogs.orientation.radio_reflect_horizontal = e_widget_radio_add(canvas, _("Flipped, horizontally"), ECORE_X_RANDR_OUTPUT_POLICY_CLONE, rg); + e_widget_framelist_object_append(subdialog, e_config_runtime_info->gui.subdialogs.orientation.radio_reflect_horizontal); + + e_config_runtime_info->gui.subdialogs.orientation.radio_reflect_vertical = e_widget_radio_add(canvas, _("Flipped, vertically"), ECORE_X_RANDR_OUTPUT_POLICY_NONE, rg); + e_widget_framelist_object_append(subdialog, e_config_runtime_info->gui.subdialogs.orientation.radio_reflect_vertical); + + //_e_config_randr_dialog_subdialog_orientation_radio_add_callbacks(); + + /* + // Add orientation demonstration edje + if (!(e_config_runtime_info->gui.subdialogs.orientation.swallowing_edje = edje_object_add(canvas))) + goto _e_config_randr_dialog_subdialog_orientation_edje_add_fail; + if (!edje_object_file_set(e_config_runtime_info->gui.subdialogs.orientation.swallowing_edje, _theme_file_path, "e/conf/randr/dialog/subdialog/orientation")) + goto _e_config_randr_dialog_subdialog_orientation_edje_set_fail; + + e_widget_table_object_align_append(subdialog, e_config_runtime_info->gui.subdialogs.orientation.swallowing_edje, 1, 0, 1, 1, 1, 1, 1, 1, 1.0, 1.0); + */ + + //disable widgets, if no CRTC is selected + e_config_randr_dialog_subdialog_orientation_update_radio_buttons(e_config_runtime_info->gui.selected_eo); + + //evas_object_show(e_config_runtime_info->gui.subdialogs.orientation.swallowing_edje); + + return subdialog; + + /* +_e_config_randr_dialog_subdialog_orientation_edje_set_fail: + evas_object_del(ol); + evas_object_del(e_config_runtime_info->gui.subdialogs.orientation.swallowing_edje); +_e_config_randr_dialog_subdialog_orientation_edje_add_fail: + fprintf(stderr, "CONF_RANDR: Couldn't set edj for orientation subdialog!\n"); + evas_object_del(subdialog); + return NULL; + */ +_e_config_randr_dialog_subdialog_orientation_radio_add_fail: + evas_object_del(subdialog); + fprintf(stderr, "CONF_RANDR: Could not add radio group!\n"); + return NULL; +} + +/* + static void +_e_config_randr_dialog_subdialog_orientation_policy_mouse_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + char signal[40]; + int orientation = ECORE_X_RANDR_ORIENTATION_ROT_0; + + /* + * IMPROVABLE: + * "sadly" the evas callbacks are called before radio_val is set to its new + * value. If that is ever changed, remove the used code below and just use the + * 1-liner below. + * snprintf(signal, sizeof(signal), "conf,randr,dialog,orientation,%d", e_config_runtime_info->gui.subdialogs.orientation.radio_val); + * / + if (obj == e_config_runtime_info->gui.subdialogs.orientation.radio_normal) orientation = ECORE_X_RANDR_ORIENTATION_ROT_0; + if (obj == e_config_runtime_info->gui.subdialogs.orientation.radio_rot90) orientation = ECORE_X_RANDR_ORIENTATION_ROT_90; + if (obj == e_config_runtime_info->gui.subdialogs.orientation.radio_rot180) orientation = ECORE_X_RANDR_ORIENTATION_ROT_180; + if (obj == e_config_runtime_info->gui.subdialogs.orientation.radio_rot270) orientation = ECORE_X_RANDR_ORIENTATION_ROT_270; + if (obj == e_config_runtime_info->gui.subdialogs.orientation.radio_reflect_horizontal) orientation = ECORE_X_RANDR_ORIENTATION_FLIP_X; + if (obj == e_config_runtime_info->gui.subdialogs.orientation.radio_reflect_vertical) orientation = ECORE_X_RANDR_ORIENTATION_FLIP_Y; + + snprintf(signal, sizeof(signal), "conf,randr,dialog,orientation,%d", orientation); + + edje_object_signal_emit(e_config_runtime_info->gui.subdialogs.orientation.swallowing_edje, signal, "e"); + + fprintf(stderr, "CONF_RANDR: mouse button released. Emitted signal to orientation: %s\n", signal); +} +*/ + + void +e_config_randr_dialog_subdialog_orientation_update_radio_buttons(Evas_Object *crtc) +{ + E_Config_Randr_Dialog_Output_Dialog_Data *output_dialog_data; + Ecore_X_Randr_Orientation supported_oris, ori; + char signal[40]; + + //disable widgets, if no crtc is selected + if (!crtc) + { + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.orientation.radio_normal, EINA_TRUE); + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.orientation.radio_rot90, EINA_TRUE); + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.orientation.radio_rot180, EINA_TRUE); + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.orientation.radio_rot270, EINA_TRUE); + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.orientation.radio_reflect_horizontal, EINA_TRUE); + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.orientation.radio_reflect_vertical, EINA_TRUE); + return; + } + + if (!(output_dialog_data = evas_object_data_get(crtc, "output_info"))) return; + + if (output_dialog_data->crtc) + { + //enabled monitor + supported_oris = output_dialog_data->crtc->orientations; + ori = output_dialog_data->crtc->current_orientation; + } + else + { + //disabled monitor + //assume all orientations are supported + supported_oris = RANDR_DIALOG_ORIENTATION_ALL; + ori = ECORE_X_RANDR_ORIENTATION_ROT_0; + } + + if (supported_oris & ECORE_X_RANDR_ORIENTATION_ROT_0) + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.orientation.radio_normal, EINA_FALSE); + else + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.orientation.radio_normal, EINA_TRUE); + + if (supported_oris & ECORE_X_RANDR_ORIENTATION_ROT_90) + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.orientation.radio_rot90, EINA_FALSE); + else + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.orientation.radio_rot90, EINA_TRUE); + + if (supported_oris & ECORE_X_RANDR_ORIENTATION_ROT_180) + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.orientation.radio_rot180, EINA_FALSE); + else + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.orientation.radio_rot180, EINA_TRUE); + + if (supported_oris & ECORE_X_RANDR_ORIENTATION_ROT_270) + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.orientation.radio_rot270, EINA_FALSE); + else + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.orientation.radio_rot270, EINA_TRUE); + + if (supported_oris & ECORE_X_RANDR_ORIENTATION_FLIP_X) + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.orientation.radio_reflect_horizontal, EINA_FALSE); + else + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.orientation.radio_reflect_horizontal, EINA_TRUE); + + if (supported_oris & ECORE_X_RANDR_ORIENTATION_FLIP_Y) + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.orientation.radio_reflect_vertical, EINA_FALSE); + else + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.orientation.radio_reflect_vertical, EINA_TRUE); + + //toggle the switch of the currently used orientation + switch (ori) + { + case ECORE_X_RANDR_ORIENTATION_ROT_90: + e_widget_radio_toggle_set(e_config_runtime_info->gui.subdialogs.orientation.radio_rot90, EINA_TRUE); + break; + case ECORE_X_RANDR_ORIENTATION_ROT_180: + e_widget_radio_toggle_set(e_config_runtime_info->gui.subdialogs.orientation.radio_rot180, EINA_TRUE); + break; + case ECORE_X_RANDR_ORIENTATION_ROT_270: + e_widget_radio_toggle_set(e_config_runtime_info->gui.subdialogs.orientation.radio_rot270, EINA_TRUE); + break; + case ECORE_X_RANDR_ORIENTATION_FLIP_X: + e_widget_radio_toggle_set(e_config_runtime_info->gui.subdialogs.orientation.radio_reflect_horizontal, EINA_TRUE); + break; + case ECORE_X_RANDR_ORIENTATION_FLIP_Y: + e_widget_radio_toggle_set(e_config_runtime_info->gui.subdialogs.orientation.radio_reflect_vertical, EINA_TRUE); + break; + default: //== ECORE_X_RANDR_ORIENTATION_ROT_0: + e_widget_radio_toggle_set(e_config_runtime_info->gui.subdialogs.orientation.radio_normal, EINA_TRUE); + } +} + + void +e_config_randr_dialog_subdialog_orientation_update_edje(Evas_Object *crtc) +{ + E_Config_Randr_Dialog_Output_Dialog_Data *output_dialog_data; + Ecore_X_Randr_Orientation supported_oris, ori; + char signal[40]; + + if (!e_config_runtime_info->gui.selected_eo || !(output_dialog_data = evas_object_data_get(crtc, "output_info"))) return; + + if (output_dialog_data->crtc) + { + //enabled monitor + supported_oris = output_dialog_data->crtc->orientations; + ori = output_dialog_data->crtc->current_orientation; + } + else + { + //disabled monitor + //assume all orientations are supported + supported_oris = RANDR_DIALOG_ORIENTATION_ALL; + ori = ECORE_X_RANDR_ORIENTATION_ROT_0; + } + //Send signal to the edje, to represent the supported and current set orientation + snprintf(signal, sizeof(signal), "conf,randr,dialog,orientation,supported,%d", supported_oris); + edje_object_signal_emit(crtc, signal, "e"); + snprintf(signal, sizeof(signal), "conf,randr,dialog,orientation,current,%d", ori); + edje_object_signal_emit(crtc, signal, "e"); +} + + Eina_Bool +e_config_randr_dialog_subdialog_orientation_basic_apply_data (E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata) +{ + Ecore_X_Randr_Orientation orientation; + E_Config_Randr_Dialog_Output_Dialog_Data *output_dialog_data; + + if (!e_config_runtime_info->gui.subdialogs.orientation.dialog || !e_config_runtime_info->gui.selected_eo || !(output_dialog_data = evas_object_data_get(e_config_runtime_info->gui.selected_eo, "output_info")) || !output_dialog_data->crtc) return EINA_FALSE; + + orientation = e_config_runtime_info->gui.subdialogs.orientation.radio_val; + + fprintf(stderr, "CONF_RANDR: Change orientation of crtc %x to %d.\n", output_dialog_data->crtc->xid, orientation); + + if (ecore_x_randr_crtc_orientation_set(cfd->con->manager->root, output_dialog_data->crtc->xid, orientation)) + { + ecore_x_randr_screen_reset(cfd->con->manager->root); + output_dialog_data->previous_orientation = output_dialog_data->new_orientation; + output_dialog_data->new_orientation = orientation; + return EINA_TRUE; + } + else + return EINA_FALSE; +} + + Eina_Bool +e_config_randr_dialog_subdialog_orientation_basic_check_changed(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata) +{ + Ecore_X_Randr_Orientation orientation = ECORE_X_RANDR_ORIENTATION_ROT_0; + E_Config_Randr_Dialog_Output_Dialog_Data *output_dialog_data; + + if (!e_config_runtime_info->gui.subdialogs.orientation.dialog || !e_config_runtime_info->gui.selected_eo || !(output_dialog_data = evas_object_data_get(e_config_runtime_info->gui.selected_eo, "output_info"))) return EINA_FALSE; + + return (output_dialog_data->previous_orientation != e_config_runtime_info->gui.subdialogs.orientation.radio_val); +} + + void +e_config_randr_dialog_subdialog_orientation_keep_changes(E_Config_Dialog_Data *cfdata) +{ + E_Config_Randr_Dialog_Output_Dialog_Data *odd; + Eina_List *iter; + + if (!cfdata) return; + + EINA_LIST_FOREACH(cfdata->output_dialog_data_list, iter, odd) + { + if (!odd || (odd->previous_orientation == Ecore_X_Randr_Unset)) continue; + odd->previous_orientation = odd->new_orientation; + odd->new_orientation = Ecore_X_Randr_Unset; + } +} + + void +e_config_randr_dialog_subdialog_orientation_discard_changes(E_Config_Dialog_Data *cfdata) +{ + E_Config_Randr_Dialog_Output_Dialog_Data *odd; + Eina_List *iter; + + if (!cfdata) return; + + EINA_LIST_FOREACH(cfdata->output_dialog_data_list, iter, odd) + { + if (!odd->crtc || (odd->previous_orientation == Ecore_X_Randr_Unset)) continue; + if (ecore_x_randr_crtc_orientation_set(cfdata->manager->root, odd->crtc->xid, odd->previous_orientation)) + { + odd->new_orientation = odd->previous_orientation; + odd->previous_orientation = Ecore_X_Randr_Unset; + ecore_x_randr_screen_reset(cfdata->manager->root); + } + } +} diff --git a/src/modules/conf_randr/e_int_config_randr_policies.c b/src/modules/conf_randr/e_int_config_randr_policies.c new file mode 100644 index 000000000..77b204c5e --- /dev/null +++ b/src/modules/conf_randr/e_int_config_randr_policies.c @@ -0,0 +1,302 @@ +#include "e_int_config_randr.h" +#include "e_randr.h" + +#ifndef ECORE_X_RANDR_1_2 +#define ECORE_X_RANDR_1_2 ((1 << 16) | 2) +#endif +#ifndef ECORE_X_RANDR_1_3 +#define ECORE_X_RANDR_1_3 ((1 << 16) | 3) +#endif + +#ifndef Ecore_X_Randr_Unset +#define Ecore_X_Randr_Unset -1 +#endif + +Evas_Object *e_config_randr_dialog_subdialog_policies_basic_create_widgets(Evas *canvas); +Eina_Bool e_config_randr_dialog_subdialog_policies_basic_apply_data (E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); +Eina_Bool e_config_randr_dialog_subdialog_policies_basic_check_changed(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); +Eina_Bool e_config_randr_dialog_subdialog_policies_basic_apply_data(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); +void e_config_randr_dialog_subdialog_policies_update_radio_buttons(Evas_Object *crtc); + +static void _e_config_randr_dialog_subdialog_policies_policy_mouse_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info); +extern E_Config_Dialog_Data *e_config_runtime_info; +extern char _theme_file_path[]; + +/* +static void +_e_config_randr_dialog_subdialog_policies_radio_add_callbacks(void) +{ + evas_object_event_callback_add(e_config_runtime_info->gui.subdialogs.policies.radio_none, EVAS_CALLBACK_MOUSE_UP, _e_config_randr_dialog_subdialog_policies_policy_mouse_up_cb, NULL); + evas_object_event_callback_add(e_config_runtime_info->gui.subdialogs.policies.radio_clone, EVAS_CALLBACK_MOUSE_UP, _e_config_randr_dialog_subdialog_policies_policy_mouse_up_cb, NULL); + evas_object_event_callback_add(e_config_runtime_info->gui.subdialogs.policies.radio_left, EVAS_CALLBACK_MOUSE_UP, _e_config_randr_dialog_subdialog_policies_policy_mouse_up_cb, NULL); + evas_object_event_callback_add(e_config_runtime_info->gui.subdialogs.policies.radio_below, EVAS_CALLBACK_MOUSE_UP, _e_config_randr_dialog_subdialog_policies_policy_mouse_up_cb, NULL); + evas_object_event_callback_add(e_config_runtime_info->gui.subdialogs.policies.radio_above, EVAS_CALLBACK_MOUSE_UP, _e_config_randr_dialog_subdialog_policies_policy_mouse_up_cb, NULL); + evas_object_event_callback_add(e_config_runtime_info->gui.subdialogs.policies.radio_right, EVAS_CALLBACK_MOUSE_UP, _e_config_randr_dialog_subdialog_policies_policy_mouse_up_cb, NULL); +} +*/ + + Eina_Bool +e_config_randr_dialog_subdialog_policies_create_data(E_Config_Dialog_Data *e_config_runtime_info) +{ + E_Config_Randr_Dialog_Output_Dialog_Data *odd; + E_Randr_Output_Info *oi; + Eina_List *iter; + + if (!e_config_runtime_info || !e_config_runtime_info->output_dialog_data_list) return EINA_FALSE; + + EINA_LIST_FOREACH(e_config_runtime_info->output_dialog_data_list, iter, odd) + { + if (odd->crtc) + oi = eina_list_data_get(eina_list_last(odd->crtc->outputs)); + else if (odd->output) + oi = odd->output; + if (!oi) continue; + odd->previous_policy = oi->policy; + odd->new_policy = Ecore_X_Randr_Unset; + } + + return EINA_TRUE; +} + +Evas_Object * +e_config_randr_dialog_subdialog_policies_basic_create_widgets(Evas *canvas) +{ + Evas_Object *subdialog; + E_Radio_Group *rg; + //char signal[29]; + + if (!canvas || !e_config_runtime_info) return NULL; + + if (e_config_runtime_info->gui.subdialogs.policies.dialog) return e_config_runtime_info->gui.subdialogs.policies.dialog; + + if(!(subdialog = e_widget_framelist_add(canvas, _("Screen attachement policy"), EINA_FALSE))) return NULL; + + // Add radio buttons + if (!(rg = e_widget_radio_group_new(&e_config_runtime_info->gui.subdialogs.policies.radio_val))) goto _e_config_randr_dialog_subdialog_policies_radio_add_fail; + + //IMPROVABLE: use enum to determine objects via 'switch'-statement + e_config_runtime_info->gui.subdialogs.policies.radio_above = e_widget_radio_add(canvas, _("Above"), ECORE_X_RANDR_OUTPUT_POLICY_ABOVE, rg); + e_widget_framelist_object_append(subdialog, e_config_runtime_info->gui.subdialogs.policies.radio_above); + + e_config_runtime_info->gui.subdialogs.policies.radio_right = e_widget_radio_add(canvas, _("Right"), ECORE_X_RANDR_OUTPUT_POLICY_RIGHT, rg); + e_widget_framelist_object_append(subdialog, e_config_runtime_info->gui.subdialogs.policies.radio_right); + + e_config_runtime_info->gui.subdialogs.policies.radio_below = e_widget_radio_add(canvas, _("Below"), ECORE_X_RANDR_OUTPUT_POLICY_BELOW, rg); + e_widget_framelist_object_append(subdialog, e_config_runtime_info->gui.subdialogs.policies.radio_below); + + e_config_runtime_info->gui.subdialogs.policies.radio_left = e_widget_radio_add(canvas, _("Left"), ECORE_X_RANDR_OUTPUT_POLICY_LEFT, rg); + e_widget_framelist_object_append(subdialog, e_config_runtime_info->gui.subdialogs.policies.radio_left); + + e_config_runtime_info->gui.subdialogs.policies.radio_clone = e_widget_radio_add(canvas, _("Clone display content"), ECORE_X_RANDR_OUTPUT_POLICY_CLONE, rg); + e_widget_framelist_object_append(subdialog, e_config_runtime_info->gui.subdialogs.policies.radio_clone); + + e_config_runtime_info->gui.subdialogs.policies.radio_none = e_widget_radio_add(canvas, _("No reaction"), ECORE_X_RANDR_OUTPUT_POLICY_NONE, rg); + e_widget_framelist_object_append(subdialog, e_config_runtime_info->gui.subdialogs.policies.radio_none); + + //_e_config_randr_dialog_subdialog_policies_radio_add_callbacks(); + + /* + // Add policies demonstration edje + if (!(e_config_runtime_info->gui.subdialogs.policies.swallowing_edje = edje_object_add(canvas))) + { + goto _e_config_randr_dialog_subdialog_policies_edje_add_fail; + + } + if (!edje_object_file_set(e_config_runtime_info->gui.subdialogs.policies.swallowing_edje, _theme_file_path, "e/conf/randr/dialog/subdialog/policies")) + { + goto _e_config_randr_dialog_subdialog_policies_edje_set_fail; + } + + e_widget_table_object_align_append(subdialog, e_config_runtime_info->gui.subdialogs.policies.swallowing_edje, 1, 0, 1, 1, 1, 1, 1, 1, 1.0, 1.0); + */ + + /* + evas_object_show(e_config_runtime_info->gui.subdialogs.policies.swallowing_edje); + + //emit signal to edje so a demonstration can be shown + snprintf(signal, sizeof(signal), "conf,randr,dialog,policies,%d", e_randr_screen_info->rrvd_info.randr_info_12->output_policy); + edje_object_signal_emit(e_config_runtime_info->gui.subdialogs.policies.swallowing_edje, signal, "e"); + fprintf(stderr, "CONF_RANDR: Initial signal emitted to policy dialog: %s\n", signal); + + //Use theme's background as screen representation + e_config_runtime_info->gui.subdialogs.policies.new_display = edje_object_add(canvas); + e_theme_edje_object_set(e_config_runtime_info->gui.subdialogs.policies.new_display, "base/theme/widgets", "e/widgets/frame"); + e_config_runtime_info->gui.subdialogs.policies.new_display_background = edje_object_add(canvas); + e_theme_edje_object_set(e_config_runtime_info->gui.subdialogs.policies.new_display_background, "base/theme/background", "e/desktop/background"); + edje_object_part_swallow(e_config_runtime_info->gui.subdialogs.policies.new_display, "e.swallow.content", e_config_runtime_info->gui.subdialogs.policies.new_display_background); + edje_object_part_text_set(e_config_runtime_info->gui.subdialogs.policies.new_display, "e.text.label", _("New display")); + edje_object_part_swallow(e_config_runtime_info->gui.subdialogs.policies.swallowing_edje, "new_display.swallow.content", e_config_runtime_info->gui.subdialogs.policies.new_display); + //add theme's frame + //for now use the theme's background for the new display as well + e_config_runtime_info->gui.subdialogs.policies.current_displays_setup = edje_object_add(canvas); + e_theme_edje_object_set(e_config_runtime_info->gui.subdialogs.policies.current_displays_setup, "base/theme/widgets", "e/widgets/frame"); + e_config_runtime_info->gui.subdialogs.policies.current_displays_setup_background = edje_object_add(canvas); + e_theme_edje_object_set(e_config_runtime_info->gui.subdialogs.policies.current_displays_setup_background, "base/theme/background", "e/desktop/background"); + edje_object_part_swallow(e_config_runtime_info->gui.subdialogs.policies.current_displays_setup, "e.swallow.content", e_config_runtime_info->gui.subdialogs.policies.current_displays_setup_background); + edje_object_part_text_set(e_config_runtime_info->gui.subdialogs.policies.current_displays_setup, "e.text.label", _("Used display")); + edje_object_part_swallow(e_config_runtime_info->gui.subdialogs.policies.swallowing_edje, "current_displays_setup.swallow.content", e_config_runtime_info->gui.subdialogs.policies.current_displays_setup); + */ + + evas_object_show(subdialog); + + return subdialog; + + /* +_e_config_randr_dialog_subdialog_policies_edje_set_fail: + evas_object_del(e_config_runtime_info->gui.subdialogs.policies.swallowing_edje); +_e_config_randr_dialog_subdialog_policies_edje_add_fail: + fprintf(stderr, "CONF_RANDR: Couldn't set edj for policies subdialog!\n"); + evas_object_del(subdialog); + return NULL; + */ +_e_config_randr_dialog_subdialog_policies_radio_add_fail: + evas_object_del(subdialog); + return NULL; +} + + static void +_e_config_randr_dialog_subdialog_policies_policy_mouse_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + char signal[29]; + int policy = ECORE_X_RANDR_OUTPUT_POLICY_NONE; + + /* + * IMPROVABLE: + * "sadly" the evas callbacks are called before radio_val is set to its new + * value. If that is ever changed, remove the used code below and just use the + * 1-liner below. + * snprintf(signal, sizeof(signal), "conf,randr,dialog,policies,%d", e_config_runtime_info->gui.subdialogs.policies.radio_val); + */ + if (obj == e_config_runtime_info->gui.subdialogs.policies.radio_above) policy = ECORE_X_RANDR_OUTPUT_POLICY_ABOVE; + if (obj == e_config_runtime_info->gui.subdialogs.policies.radio_right) policy = ECORE_X_RANDR_OUTPUT_POLICY_RIGHT; + if (obj == e_config_runtime_info->gui.subdialogs.policies.radio_below) policy = ECORE_X_RANDR_OUTPUT_POLICY_BELOW; + if (obj == e_config_runtime_info->gui.subdialogs.policies.radio_left) policy = ECORE_X_RANDR_OUTPUT_POLICY_LEFT; + if (obj == e_config_runtime_info->gui.subdialogs.policies.radio_clone) policy = ECORE_X_RANDR_OUTPUT_POLICY_CLONE; + if (obj == e_config_runtime_info->gui.subdialogs.policies.radio_none) policy = ECORE_X_RANDR_OUTPUT_POLICY_NONE; + + snprintf(signal, sizeof(signal), "conf,randr,dialog,policies,%d", policy); + + //edje_object_signal_emit(e_config_runtime_info->gui.subdialogs.policies.swallowing_edje, signal, "e"); + + fprintf(stderr, "CONF_RANDR: mouse button released. Emitted signal to policy: %s\n", signal); +} + + Eina_Bool +e_config_randr_dialog_subdialog_policies_basic_apply_data (E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata) +{ + E_Randr_Output_Info *output_info; + + if (!e_randr_screen_info || !e_config_runtime_info->gui.selected_output_dd) return EINA_FALSE; + + //policy update + e_config_runtime_info->gui.selected_output_dd->previous_policy = e_config_runtime_info->gui.selected_output_dd->new_policy; + e_config_runtime_info->gui.selected_output_dd->new_policy = e_config_runtime_info->gui.subdialogs.policies.radio_val; + fprintf(stderr, "CONF_RANDR: 'New display attached'-policy set to %d\n", e_config_runtime_info->gui.selected_output_dd->new_policy); + + return EINA_TRUE; +} + + Eina_Bool +e_config_randr_dialog_subdialog_policies_basic_check_changed(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata) +{ + if (!e_randr_screen_info || !cfdata || !cfdata->gui.selected_output_dd) return EINA_FALSE; + + return (cfdata->gui.selected_output_dd->previous_policy != cfdata->gui.subdialogs.policies.radio_val); +} + + void +e_config_randr_dialog_subdialog_policies_update_radio_buttons(Evas_Object *crtc) +{ + E_Config_Randr_Dialog_Output_Dialog_Data *output_dialog_data; + E_Randr_Output_Info *output; + Ecore_X_Randr_Output_Policy policy; + char signal[40]; + + //disable widgets, if no crtc is selected + if (!crtc || !(output_dialog_data = evas_object_data_get(crtc, "output_info"))) + { + //Evas_Object *radio_above, *radio_right, *radio_below, *radio_left, *radio_clone, *radio_none; + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.policies.radio_above, EINA_TRUE); + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.policies.radio_right, EINA_TRUE); + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.policies.radio_below, EINA_TRUE); + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.policies.radio_left, EINA_TRUE); + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.policies.radio_clone, EINA_TRUE); + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.policies.radio_none, EINA_TRUE); + return; + } + else + { + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.policies.radio_above, EINA_FALSE); + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.policies.radio_right, EINA_FALSE); + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.policies.radio_below, EINA_FALSE); + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.policies.radio_left, EINA_FALSE); + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.policies.radio_clone, EINA_FALSE); + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.policies.radio_none, EINA_FALSE); + } + + if (output_dialog_data->crtc && output_dialog_data->crtc->outputs) + { + output = (E_Randr_Output_Info*)eina_list_data_get(eina_list_last(output_dialog_data->crtc->outputs)); + } + else if (output_dialog_data->output) + { + output = output_dialog_data->output; + } + + if (!output) return; + policy = output->policy; + e_config_runtime_info->gui.selected_output_dd = output_dialog_data; + //toggle the switch of the currently used policies + switch (policy) + { + case ECORE_X_RANDR_OUTPUT_POLICY_RIGHT: + e_widget_radio_toggle_set(e_config_runtime_info->gui.subdialogs.policies.radio_right, EINA_TRUE); + break; + case ECORE_X_RANDR_OUTPUT_POLICY_BELOW: + e_widget_radio_toggle_set(e_config_runtime_info->gui.subdialogs.policies.radio_below, EINA_TRUE); + break; + case ECORE_X_RANDR_OUTPUT_POLICY_LEFT: + e_widget_radio_toggle_set(e_config_runtime_info->gui.subdialogs.policies.radio_left, EINA_TRUE); + break; + case ECORE_X_RANDR_OUTPUT_POLICY_CLONE: + e_widget_radio_toggle_set(e_config_runtime_info->gui.subdialogs.policies.radio_clone, EINA_TRUE); + break; + case ECORE_X_RANDR_OUTPUT_POLICY_NONE: + e_widget_radio_toggle_set(e_config_runtime_info->gui.subdialogs.policies.radio_none, EINA_TRUE); + break; + default: //== ECORE_X_RANDR_OUTPUT_POLICY_ABOVE: + e_widget_radio_toggle_set(e_config_runtime_info->gui.subdialogs.policies.radio_above, EINA_TRUE); + } +} + + void +e_config_randr_dialog_subdialog_policies_keep_changes(E_Config_Dialog_Data *cfdata) +{ + E_Config_Randr_Dialog_Output_Dialog_Data *odd; + Eina_List *iter; + + if (!cfdata) return; + + EINA_LIST_FOREACH(cfdata->output_dialog_data_list, iter, odd) + { + if (!odd || (odd->previous_policy == Ecore_X_Randr_Unset)) continue; + odd->previous_policy = odd->new_policy; + odd->new_policy = Ecore_X_Randr_Unset; + } +} + + void +e_config_randr_dialog_subdialog_policies_discard_changes(E_Config_Dialog_Data *cfdata) +{ + E_Config_Randr_Dialog_Output_Dialog_Data *odd; + Eina_List *iter; + + if (!cfdata) return; + + EINA_LIST_FOREACH(cfdata->output_dialog_data_list, iter, odd) + { + if (!odd->crtc || (odd->previous_policy == Ecore_X_Randr_Unset)) continue; + odd->new_policy = odd->previous_policy; + odd->previous_policy = Ecore_X_Randr_Unset; + } +} diff --git a/src/modules/conf_randr/e_int_config_randr_resolutions.c b/src/modules/conf_randr/e_int_config_randr_resolutions.c new file mode 100644 index 000000000..ea3bb9362 --- /dev/null +++ b/src/modules/conf_randr/e_int_config_randr_resolutions.c @@ -0,0 +1,265 @@ +#include "e_int_config_randr.h" +#include "e_randr.h" +#include "e_widget_ilist.h" + +#ifdef Ecore_X_Randr_Unset +#undef Ecore_X_Randr_Unset +#define Ecore_X_Randr_Unset -1 +#else +#define Ecore_X_Randr_Unset -1 +#endif + +#ifdef Ecore_X_Randr_None +#undef Ecore_X_Randr_None +#endif +#define Ecore_X_Randr_None 0 + +#define ICON_WIDTH 10 +#define ICON_HEIGHT 10 +#define RESOLUTION_TXT_MAX_LENGTH 50 + +Evas_Object *e_config_randr_dialog_subdialog_resolutions_basic_create_widgets(Evas *canvas); +Eina_Bool e_config_randr_dialog_subdialog_resolutions_basic_apply_data (E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); +Eina_Bool e_config_randr_dialog_subdialog_resolutions_basic_check_changed(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); +void e_config_randr_dialog_subdialog_resolutions_update_list(Evas_Object *crtc); +void e_config_randr_dialog_subdialog_resolutions_keep_changes(E_Config_Dialog_Data *cfdata); +void e_config_randr_dialog_subdialog_resolutions_discard_changes(E_Config_Dialog_Data *cfdata); + +extern E_Config_Dialog_Data *e_config_runtime_info; + + Eina_Bool +e_config_randr_dialog_subdialog_resolutions_create_data(E_Config_Dialog_Data *cfdata) +{ + E_Config_Randr_Dialog_Output_Dialog_Data *odd; + E_Randr_Crtc_Info *ci; + Ecore_X_Randr_Mode_Info *mi; + Eina_List *iter; + + if (!cfdata || !cfdata->output_dialog_data_list) return EINA_FALSE; + + EINA_LIST_FOREACH(cfdata->output_dialog_data_list, iter, odd) + { + if (odd->previous_mode || odd->preferred_mode) + { + //this means, that mode info is already filled + //(by the display arrangement code) + break; + } + if (odd->crtc) + { + if(!(mi = odd->crtc->current_mode)) + mi = (Ecore_X_Randr_Mode_Info*)eina_list_data_get(eina_list_last(odd->crtc->outputs_common_modes)); + odd->previous_mode = mi; + } + else if (odd->output) + { + odd->preferred_mode = (Ecore_X_Randr_Mode_Info*)eina_list_data_get(eina_list_last(odd->output->preferred_modes)); + } + } + + return EINA_TRUE; +} + + Evas_Object * +e_config_randr_dialog_subdialog_resolutions_basic_create_widgets(Evas *canvas) +{ + Evas_Object *subdialog; + + if (!canvas || !e_config_runtime_info || e_config_runtime_info->gui.subdialogs.resolutions.dialog || !(subdialog = e_widget_ilist_add(canvas, ICON_WIDTH * e_scale, ICON_HEIGHT * e_scale, NULL))) return NULL; + + e_widget_ilist_multi_select_set(subdialog, EINA_FALSE); + e_widget_disabled_set(subdialog, EINA_TRUE); + + evas_object_show(subdialog); + + return subdialog; +} + + Eina_Bool +e_config_randr_dialog_subdialog_resolutions_basic_apply_data (E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata) +{ + //Apply new mode + Ecore_X_Randr_Mode_Info* selected_mode; + Ecore_X_ID selected_mode_xid; + E_Config_Randr_Dialog_Output_Dialog_Data *output_dialog_data; + Ecore_X_Randr_Output *output = NULL; + E_Randr_Crtc_Info *crtc_info = NULL, *crtc_iter; + Eina_List *iter; + int noutputs = Ecore_X_Randr_Unset; + + if (!e_config_runtime_info->gui.selected_eo || !(output_dialog_data = evas_object_data_get(e_config_runtime_info->gui.selected_eo, "output_info"))) + { + fprintf(stderr, "CONF_RADNR: no crtc was selected or no output info could be retrieved for the selected crtc element (%p).\n", e_config_runtime_info->gui.selected_eo); + return EINA_FALSE; + } + + if (output_dialog_data->crtc) + { + //CRTC is already asssigned, easy one! + crtc_info = output_dialog_data->crtc; + } + else if (output_dialog_data->output) + { + //CRTC not assigned yet. Let's try to find a non occupied one. + fprintf(stderr, "CONF_RANDR: Trying to find a CRTC for output %x, %d crtcs are possible.\n", output_dialog_data->output->xid, eina_list_count(output_dialog_data->output->possible_crtcs)); + output = &output_dialog_data->output->xid; + noutputs = 1; + EINA_LIST_FOREACH(output_dialog_data->output->possible_crtcs, iter, crtc_iter) + { + if (!crtc_iter->outputs) + { + //CRTC is not occupied yet + crtc_info = crtc_iter; + break; + } + } + } + if (!crtc_info) + { + fprintf(stderr, "CONF_RANDR: Changing mode failed, no unoccupied CRTC found!\n"); + return EINA_FALSE; + } + //get selected mode + if ((selected_mode = (Ecore_X_Randr_Mode_Info*)e_widget_ilist_selected_data_get(e_config_runtime_info->gui.subdialogs.resolutions.dialog))) + { + selected_mode_xid = selected_mode->xid; + } + else + { + selected_mode_xid = Ecore_X_Randr_None; + } + + fprintf(stderr, "CONF_RANDR: Change mode of crtc %x to %x.\n", crtc_info->xid, selected_mode_xid); + + if (ecore_x_randr_crtc_mode_set(cfd->con->manager->root, crtc_info->xid, output, noutputs, selected_mode_xid)) + { + //remove unused space + ecore_x_randr_screen_reset(cfd->con->manager->root); + //update information + if (!output_dialog_data->crtc) + output_dialog_data->crtc = crtc_info; + output_dialog_data->new_mode = selected_mode; + return EINA_TRUE; + } + + return EINA_FALSE; +} + + Eina_Bool +e_config_randr_dialog_subdialog_resolutions_basic_check_changed(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata) +{ + Ecore_X_Randr_Mode_Info* selected_mode; + E_Config_Randr_Dialog_Output_Dialog_Data *output_dialog_data; + + if (!e_config_runtime_info->gui.selected_eo || !(selected_mode = (Ecore_X_Randr_Mode_Info*)e_widget_ilist_selected_data_get(e_config_runtime_info->gui.subdialogs.resolutions.dialog)) || !(output_dialog_data = evas_object_data_get(e_config_runtime_info->gui.selected_eo, "output_info"))) return EINA_FALSE; + + return (selected_mode != output_dialog_data->previous_mode); +} + + void +e_config_randr_dialog_subdialog_resolutions_update_list(Evas_Object *crtc) +{ + Eina_List *iter, *modelist = NULL; + E_Config_Randr_Dialog_Output_Dialog_Data *output_dialog_data; + Ecore_X_Randr_Mode_Info *mode_info, *current_mode; + char resolution_text[RESOLUTION_TXT_MAX_LENGTH]; + float rate; + int str_ret, i = 0; + + e_widget_ilist_freeze(e_config_runtime_info->gui.subdialogs.resolutions.dialog); + e_widget_ilist_clear(e_config_runtime_info->gui.subdialogs.resolutions.dialog); + if (!crtc) + { + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.resolutions.dialog, EINA_TRUE); + return; + } + if (!(output_dialog_data = evas_object_data_get(crtc, "output_info"))) + return; + + //select correct mode list + if (output_dialog_data->crtc) + { + current_mode = output_dialog_data->crtc->current_mode; + modelist = output_dialog_data->crtc->outputs_common_modes; + } + else if (output_dialog_data->output) + { + current_mode = NULL; + if (output_dialog_data->output->modes) + modelist = output_dialog_data->output->modes; + else + modelist = output_dialog_data->output->modes; + } + EINA_LIST_FOREACH(modelist, iter, mode_info) + { + //calculate refresh rate + if (!mode_info) continue; + if (mode_info->hTotal && mode_info->vTotal) + rate = ((float) mode_info->dotClock / + ((float) mode_info->hTotal * (float) mode_info->vTotal)); + else + rate = 0.0; + + str_ret = snprintf(resolution_text, RESOLUTION_TXT_MAX_LENGTH, "%dx%d@%.1fHz", mode_info->width, mode_info->height, rate); + if (str_ret < 0 || str_ret > (RESOLUTION_TXT_MAX_LENGTH - 1)) + { + fprintf(stderr, "CONF_RANDR: Resolution text could not be created."); + continue; + } + e_widget_ilist_append(e_config_runtime_info->gui.subdialogs.resolutions.dialog, NULL, resolution_text, NULL, mode_info, NULL); + + //select currently enabled mode + if (mode_info == current_mode) + e_widget_ilist_selected_set(e_config_runtime_info->gui.subdialogs.resolutions.dialog, i); + i++; + } + + //append 'disabled' mode + e_widget_ilist_append(e_config_runtime_info->gui.subdialogs.resolutions.dialog, NULL, _("Disabled"), NULL, NULL, NULL); + + //reenable widget + e_widget_disabled_set(e_config_runtime_info->gui.subdialogs.resolutions.dialog, EINA_FALSE); + e_widget_ilist_go(e_config_runtime_info->gui.subdialogs.resolutions.dialog); + e_widget_ilist_thaw(e_config_runtime_info->gui.subdialogs.resolutions.dialog); +} + + +void +e_config_randr_dialog_subdialog_resolutions_keep_changes(E_Config_Dialog_Data *cfdata) +{ + E_Config_Randr_Dialog_Output_Dialog_Data *odd; + Eina_List *iter; + + if (!cfdata) return; + + EINA_LIST_FOREACH(cfdata->output_dialog_data_list, iter, odd) + { + if (odd && odd->new_mode && (odd->new_mode != odd->previous_mode)) + { + odd->previous_mode = odd->new_mode; + odd->new_mode = NULL; + } + } +} + + void +e_config_randr_dialog_subdialog_resolutions_discard_changes(E_Config_Dialog_Data *cfdata) +{ + E_Config_Randr_Dialog_Output_Dialog_Data *odd; + Eina_List *iter; + + if (!cfdata) return; + + EINA_LIST_FOREACH(cfdata->output_dialog_data_list, iter, odd) + { + //for now, there is no way to redisable an output during discartion + if (!odd->crtc || !odd->previous_mode) continue; + //use currently used outputs (noutputs == Ecore_X_Randr_Unset) + if (ecore_x_randr_crtc_mode_set(cfdata->manager->root, odd->crtc->xid, NULL, Ecore_X_Randr_Unset, odd->previous_mode->xid)) + { + odd->new_mode = odd->previous_mode; + odd->previous_mode = NULL; + ecore_x_randr_screen_reset(cfdata->manager->root); + } + } +} diff --git a/src/modules/conf_randr/e_mod_main.c b/src/modules/conf_randr/e_mod_main.c new file mode 100644 index 000000000..6358594d7 --- /dev/null +++ b/src/modules/conf_randr/e_mod_main.c @@ -0,0 +1,42 @@ +/* + * vim:ts=8:sw=3:sts=8:expandtab:cino=>5n-3f0^-2{2 + */ +#include "e.h" +#include "e_mod_main.h" + +/* actual module specifics */ +E_Module *conf_randr_module = NULL; + +/* module setup */ +EAPI E_Module_Api e_modapi = +{ + E_MODULE_API_VERSION, + "Settings - Screen Setup" +}; + +EAPI void * +e_modapi_init(E_Module *m) +{ + e_configure_registry_category_add("screen", 30, _("Screen"), NULL, "preferences-desktop-display"); + e_configure_registry_item_add("screen/randr", 20, _("Screen Setup"), NULL, "preferences-system-screen-resolution", e_int_config_randr); + conf_randr_module = m; + e_module_delayed_set(m, 1); + return m; +} + +EAPI int +e_modapi_shutdown(E_Module *m) +{ + E_Config_Dialog *cfd; + while ((cfd = e_config_dialog_get("E", "screen/randr"))) e_object_del(E_OBJECT(cfd)); + e_configure_registry_item_del("screen/randr"); + e_configure_registry_category_del("screen"); + conf_randr_module = NULL; + return 1; +} + +EAPI int +e_modapi_save(E_Module *m) +{ + return 1; +} diff --git a/src/modules/conf_randr/e_mod_main.h b/src/modules/conf_randr/e_mod_main.h new file mode 100644 index 000000000..8735ba71d --- /dev/null +++ b/src/modules/conf_randr/e_mod_main.h @@ -0,0 +1,19 @@ +/* + * vim:ts=8:sw=3:sts=8:expandtab:cino=>5n-3f0^-2{2 + */ +#ifndef E_MOD_MAIN_H +#define E_MOD_MAIN_H + +#define E_TYPEDEFS 1 +#include "e_int_config_randr.h" + +#undef E_TYPEDEFS +#include "e_int_config_randr.h" + +EAPI extern E_Module_Api e_modapi; + +EAPI void *e_modapi_init (E_Module *m); +EAPI int e_modapi_shutdown (E_Module *m); +EAPI int e_modapi_save (E_Module *m); + +#endif diff --git a/src/modules/conf_randr/images/display-glass-shine.png b/src/modules/conf_randr/images/display-glass-shine.png new file mode 100644 index 000000000..0f299a631 Binary files /dev/null and b/src/modules/conf_randr/images/display-glass-shine.png differ diff --git a/src/modules/conf_randr/images/display.png b/src/modules/conf_randr/images/display.png new file mode 100644 index 000000000..589385f5c Binary files /dev/null and b/src/modules/conf_randr/images/display.png differ diff --git a/src/modules/conf_randr/images/icon.png b/src/modules/conf_randr/images/icon.png new file mode 100644 index 000000000..11aa540be Binary files /dev/null and b/src/modules/conf_randr/images/icon.png differ diff --git a/src/modules/conf_randr/images/video-display.svg b/src/modules/conf_randr/images/video-display.svg new file mode 100644 index 000000000..3c29c6683 --- /dev/null +++ b/src/modules/conf_randr/images/video-display.svg @@ -0,0 +1,741 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/modules/conf_randr/module.desktop.in b/src/modules/conf_randr/module.desktop.in new file mode 100644 index 000000000..e0b1c0773 --- /dev/null +++ b/src/modules/conf_randr/module.desktop.in @@ -0,0 +1,32 @@ +[Desktop Entry] +Type=Link +Name=Settings - Screen Setup +Name[cs]=Nastavení - rozlišení obrazovky +Name[de]=Konfiguration - Bildschirm +Name[eo]=Agordo - Ekrandistingivo +Name[es]=Configuración - Resolución de pantalla +Name[fr]=Configuration - Résolution de l'écran +Name[hu]=Beállítások - Képernyő felbontása +Name[it]=Configurazione - Risoluzione schermo +Name[ja]= +Name[pt]= +Name[pt_BR]= +Name[tr]=Ayarlar - Ekran Çözünürlüğü +Name[zh_CN]= +Name[zh_TW]= +Icon=e-module-conf_randr +Comment=Used to configure your screen's resolution. +Comment[cs]=Použit k nastavení rozlišení obrazovky. +Comment[de]= +Comment[eo]=Agordi sian ekrandistingivon. +Comment[es]=Usado para configurar su resolución de pantalla. +Comment[fr]=Permet de configurer la résolution de l'écran. +Comment[hu]=Segítségével beállíthatod a képernyőd felbontását. +Comment[it]=Usato per configurare la risoluzione del vostro schermo. +Comment[ja]= +Comment[pt]= +Comment[pt_BR]= +Comment[tr]=Ekranınızın çözünürlüğünü yapılandırır. +Comment[zh_CN]= +Comment[zh_TW]= +X-Enlightenment-ModuleType=settings