From 6605bdb861ea19b1afcf580f4fd9b13664e45d9d Mon Sep 17 00:00:00 2001 From: Gwanglim Lee Date: Tue, 19 Jun 2012 15:20:29 +0900 Subject: [PATCH] Added per-window profile to support multi-head display. Change-Id: Id6d67d7e5b76215246ec78be8f368e2684f22e7a --- src/bin/Makefile.am | 1 + src/bin/test.c | 2 + src/bin/test_config.c | 120 +++++++++++++++++++++++++++++++++++++++ src/lib/elm_config.c | 30 ++++++++++ src/lib/elm_config.h | 10 ++++ src/lib/elm_priv.h | 1 + src/lib/elm_win.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib/elm_win.h | 26 +++++++++ 8 files changed, 341 insertions(+) create mode 100644 src/bin/test_config.c diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am index 93fd441..78e1e68 100644 --- a/src/bin/Makefile.am +++ b/src/bin/Makefile.am @@ -43,6 +43,7 @@ test_check.c \ test_clock.c \ test_cnp.c \ test_colorselector.c \ +test_config.c \ test_conform.c \ test_ctxpopup.c \ test_cursor.c \ diff --git a/src/bin/test.c b/src/bin/test.c index e1902ed..57e5788 100644 --- a/src/bin/test.c +++ b/src/bin/test.c @@ -176,6 +176,7 @@ void test_naviframe_complex(void *data, Evas_Object *obj, void *event_info); void test_datetime(void *data, Evas_Object *obj, void *event_info); void test_popup(void *data, Evas_Object *obj, void *event_info); void test_dayselector(void *data, Evas_Object *obj, void *event_info); +void test_config(void *data, Evas_Object *obj, void *event_info); #ifdef HAVE_EMOTION void test_video(void *data, Evas_Object *obj, void *event_info); #endif @@ -676,6 +677,7 @@ add_tests: ADD_TEST(NULL, "Micellaneous", "Weather", test_weather); ADD_TEST(NULL, "Micellaneous", "Icon Desktops", test_icon_desktops); ADD_TEST(NULL, "Micellaneous", "Floating Objects", test_floating); + ADD_TEST(NULL, "Micellaneous", "Configuration", test_config); #undef ADD_TEST diff --git a/src/bin/test_config.c b/src/bin/test_config.c new file mode 100644 index 0000000..0349885 --- /dev/null +++ b/src/bin/test_config.c @@ -0,0 +1,120 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif +#include +#ifndef ELM_LIB_QUICKLAUNCH + +typedef struct _Prof_Data Prof_Data; + +struct _Prof_Data +{ + Evas_Object *rdg; + Eina_List *profiles; +}; + +static void +_bt_clicked_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Evas_Object *win = (Evas_Object *)(data); + Prof_Data *pd = evas_object_data_get(win, "pd"); + Evas_Object *rd = elm_radio_selected_object_get(pd->rdg); + const char *str = elm_object_text_get(rd); + + elm_win_profiles_set(win, &str, 1); +} + +static void +_win_profile_changed_cb(void *data, Evas_Object *obj __UNUSED__, void *event __UNUSED__) +{ + Evas_Object *win = (Evas_Object *)(data); + Prof_Data *pd = evas_object_data_get(win, "pd"); + const char *profile = elm_win_profile_get(win); + + const char *str; + int num, i = 0; + Eina_List *l; + + EINA_LIST_FOREACH(pd->profiles, l, str) + { + if ((str) && (profile) && + (strcmp(str, profile) == 0)) + { + break; + } + i++; + } + + num = eina_list_count(pd->profiles); + if (i >= num) i = num - 1; + if (i < 0) i = 0; + + elm_radio_value_set(pd->rdg, i); +} + +void +test_config(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Prof_Data *pd; + Evas_Object *win, *bx, *lb, *bt, *rd, *rdg = NULL; + const char *str; + const char **plist; + Eina_List *profs, *l; + int num, i = 0; + + if (!(pd = calloc(1, sizeof(Prof_Data)))) return; + + win = elm_win_util_standard_add("config", "Configuration"); + elm_win_autodel_set(win, EINA_TRUE); + evas_object_data_set(win, "pd", pd); + + bx = elm_box_add(win); + evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_win_resize_object_add(win, bx); + + lb = elm_label_add(win); + elm_object_text_set(lb, "List of Profiles"); + evas_object_size_hint_weight_set(lb, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_box_pack_end(bx, lb); + evas_object_show(lb); + + profs = elm_config_profile_list_get(); + num = eina_list_count(profs); + plist = calloc(num, sizeof(char *)); + + EINA_LIST_FOREACH(profs, l, str) + { + rd = elm_radio_add(win); + if (!rdg) + { + rdg = rd; + pd->rdg = rdg; + } + plist[i] = strdup(str); + pd->profiles = eina_list_append(pd->profiles, + eina_stringshare_add(str)); + elm_radio_state_value_set(rd, i); + elm_radio_group_add(rd, rdg); + elm_object_text_set(rd, str); + evas_object_size_hint_weight_set(rd, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_box_pack_end(bx, rd); + evas_object_show(rd); + i++; + } + elm_config_profile_list_free(profs); + + bt = elm_button_add(win); + elm_object_text_set(bt, "Change Window Profile"); + evas_object_smart_callback_add(bt, "clicked", _bt_clicked_cb, win); + elm_box_pack_end(bx, bt); + evas_object_show(bt); + + elm_win_profiles_set(win, plist, num); + evas_object_smart_callback_add(win, "profile,changed", _win_profile_changed_cb, win); + + evas_object_resize(win, 480, 400); + evas_object_show(bx); + evas_object_show(win); + + free(plist); +} +#endif diff --git a/src/lib/elm_config.c b/src/lib/elm_config.c index 7f112b9..52cdbde 100644 --- a/src/lib/elm_config.c +++ b/src/lib/elm_config.c @@ -1678,6 +1678,13 @@ elm_config_profile_set(const char *profile) _elm_config_profile_set(profile); } +EAPI Eina_Bool +elm_config_profile_exists(const char *profile) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(profile, EINA_FALSE); + return _elm_config_profile_exists(profile); +} + EAPI const char * elm_config_engine_get(void) { @@ -2202,6 +2209,29 @@ _elm_config_profile_set(const char *profile) } } +Eina_Bool +_elm_config_profile_exists(const char *profile) +{ + Eina_List *profs = _elm_config_profiles_list(); + Eina_List *l; + const char *p, *dir; + Eina_Bool res = EINA_FALSE; + + EINA_LIST_FOREACH(profs, l, p) + { + if (!strcmp(profile, p)) + { + res = EINA_TRUE; + break; + } + } + + EINA_LIST_FREE(profs, dir) + eina_stringshare_del(dir); + + return res; +} + void _elm_config_shutdown(void) { diff --git a/src/lib/elm_config.h b/src/lib/elm_config.h index 20ce020..ff07a32 100644 --- a/src/lib/elm_config.h +++ b/src/lib/elm_config.h @@ -138,6 +138,16 @@ EAPI void elm_config_profile_list_free(Eina_List *l); EAPI void elm_config_profile_set(const char *profile); /** + * Check if the given Elementary's profile exists. + * + * @param profile The profile's name + * @return EINA_TRUE if the profile exists, EINA_FALSE otherwise. + * + * @ingroup Profile + */ +EAPI Eina_Bool elm_config_profile_exists(const char *profile); + +/** * @} */ diff --git a/src/lib/elm_priv.h b/src/lib/elm_priv.h index 4fe6e89..adefb32 100644 --- a/src/lib/elm_priv.h +++ b/src/lib/elm_priv.h @@ -253,6 +253,7 @@ const char *_elm_config_profile_dir_get(const char *prof, Eina_Bool is_ Eina_List *_elm_config_profiles_list(void); void _elm_config_all_update(void); void _elm_config_profile_set(const char *profile); +Eina_Bool _elm_config_profile_exists(const char *profile); void _elm_config_engine_set(const char *engine); diff --git a/src/lib/elm_win.c b/src/lib/elm_win.c index 3379763..a085dc1 100644 --- a/src/lib/elm_win.c +++ b/src/lib/elm_win.c @@ -60,6 +60,12 @@ struct _Elm_Win Eina_Bool top_animate : 1; Eina_Bool geometry_changed : 1; } focus_highlight; + struct + { + const char *name; + Ecore_Timer *timer; + Eina_List *names; + } profile; Evas_Object *icon; const char *title; @@ -129,6 +135,7 @@ static const char SIG_FULLSCREEN[] = "fullscreen"; static const char SIG_UNFULLSCREEN[] = "unfullscreen"; static const char SIG_MAXIMIZED[] = "maximized"; static const char SIG_UNMAXIMIZED[] = "unmaximized"; +static const char SIG_PROFILE_CHANGED[] = "profile,changed"; static const Evas_Smart_Cb_Description _signals[] = { {SIG_DELETE_REQUEST, ""}, @@ -144,6 +151,7 @@ static const Evas_Smart_Cb_Description _signals[] = { {SIG_UNFULLSCREEN, ""}, {SIG_MAXIMIZED, ""}, {SIG_UNMAXIMIZED, ""}, + {SIG_PROFILE_CHANGED, ""}, {NULL, NULL} }; @@ -423,6 +431,57 @@ _elm_win_focus_out(Ecore_Evas *ee) } static void +_elm_win_profile_update(Ecore_Evas *ee) +{ + Evas_Object *obj = ecore_evas_object_associate_get(ee); + Elm_Win *win; + + if (!obj) return; + win = elm_widget_data_get(obj); + if (!win) return; + + if (win->profile.timer) + ecore_timer_del(win->profile.timer); + win->profile.timer = NULL; + + /* TODO: We need the ability to bind a profile to a specific window. + * Elementary's configuration still has a single global profile for the app. + */ + _elm_config_profile_set(win->profile.name); + + evas_object_smart_callback_call(win->win_obj, SIG_PROFILE_CHANGED, NULL); +} + +static Eina_Bool +_elm_win_profile_change_delay(void *data) +{ + Elm_Win *win = data; + const char *profile; + Eina_Bool changed = EINA_FALSE; + + profile = eina_list_nth(win->profile.names, 0); + if (profile) + { + if (win->profile.name) + { + if (strcmp(win->profile.name, profile)) + { + eina_stringshare_replace(&(win->profile.name), profile); + changed = EINA_TRUE; + } + } + else + { + win->profile.name = eina_stringshare_add(profile); + changed = EINA_TRUE; + } + } + win->profile.timer = NULL; + if (changed) _elm_win_profile_update(win->ee); + return EINA_FALSE; +} + +static void _elm_win_state_change(Ecore_Evas *ee) { Evas_Object *obj; @@ -432,6 +491,8 @@ _elm_win_state_change(Ecore_Evas *ee) Eina_Bool ch_iconified = EINA_FALSE; Eina_Bool ch_fullscreen = EINA_FALSE; Eina_Bool ch_maximized = EINA_FALSE; + Eina_Bool ch_profile = EINA_FALSE; + const char *profile; if (!(obj = ecore_evas_object_associate_get(ee))) return; @@ -462,6 +523,24 @@ _elm_win_state_change(Ecore_Evas *ee) win->maximized = ecore_evas_maximized_get(win->ee); ch_maximized = EINA_TRUE; } + profile = ecore_evas_profile_get(win->ee); + if ((profile) && + _elm_config_profile_exists(profile)) + { + if (win->profile.name) + { + if (strcmp(win->profile.name, profile)) + { + eina_stringshare_replace(&(win->profile.name), profile); + ch_profile = EINA_TRUE; + } + } + else + { + win->profile.name = eina_stringshare_add(profile); + ch_profile = EINA_TRUE; + } + } if ((ch_withdrawn) || (ch_iconified)) { if (win->withdrawn) @@ -492,6 +571,10 @@ _elm_win_state_change(Ecore_Evas *ee) else evas_object_smart_callback_call(win->win_obj, SIG_UNMAXIMIZED, NULL); } + if (ch_profile) + { + _elm_win_profile_update(win->ee); + } } static Eina_Bool @@ -616,6 +699,7 @@ _elm_win_obj_callback_del(void *data, Evas *e, Evas_Object *obj, void *event_inf { Elm_Win *win = data; Evas_Object *child, *child2 = NULL; + const char *str; if (win->parent) { @@ -701,6 +785,10 @@ _elm_win_obj_callback_del(void *data, Evas *e, Evas_Object *obj, void *event_inf if (win->role) eina_stringshare_del(win->role); if (win->icon) evas_object_del(win->icon); + EINA_LIST_FREE(win->profile.names, str) eina_stringshare_del(str); + if (win->profile.name) eina_stringshare_del(win->profile.name); + if (win->profile.timer) ecore_timer_del(win->profile.timer); + free(win); if ((!_elm_win_list) && @@ -2538,6 +2626,69 @@ elm_win_withdrawn_get(const Evas_Object *obj) } EAPI void +elm_win_profiles_set(Evas_Object *obj, const char **profiles, unsigned int num_profiles) +{ + Elm_Win *win; + char **profiles_int; + const char *str; + unsigned int i, num; + Eina_List *l; + + ELM_CHECK_WIDTYPE(obj, widtype); + win = elm_widget_data_get(obj); + if (!win) return; + if (!profiles) return; + + if (win->profile.timer) ecore_timer_del(win->profile.timer); + win->profile.timer = ecore_timer_add(0.1, _elm_win_profile_change_delay, win); + EINA_LIST_FREE(win->profile.names, str) eina_stringshare_del(str); + + for (i = 0; i < num_profiles; i++) + { + if ((profiles[i]) && + _elm_config_profile_exists(profiles[i])) + { + str = eina_stringshare_add(profiles[i]); + win->profile.names = eina_list_append(win->profile.names, str); + } + } + + num = eina_list_count(win->profile.names); + profiles_int = alloca(num * sizeof(char *)); + + if (profiles_int) + { + i = 0; + EINA_LIST_FOREACH(win->profile.names, l, str) + { + if (str) + profiles_int[i] = strdup(str); + else + profiles_int[i] = NULL; + i++; + } + ecore_evas_profiles_set(win->ee, (const char **)profiles_int, i); + for (i = 0; i < num; i++) + { + if (profiles_int[i]) free(profiles_int[i]); + } + } + else + ecore_evas_profiles_set(win->ee, profiles, num_profiles); +} + +EAPI const char * +elm_win_profile_get(const Evas_Object *obj) +{ + Elm_Win *win; + ELM_CHECK_WIDTYPE(obj, widtype); + win = elm_widget_data_get(obj); + if (!win) return NULL; + + return win->profile.name; +} + +EAPI void elm_win_urgent_set(Evas_Object *obj, Eina_Bool urgent) { Elm_Win *win; diff --git a/src/lib/elm_win.h b/src/lib/elm_win.h index efa764e..248b14a 100644 --- a/src/lib/elm_win.h +++ b/src/lib/elm_win.h @@ -79,6 +79,7 @@ * @li "unfullscreen": window has stopped being fullscreen * @li "maximized": window has been maximized * @li "unmaximized": window has stopped being maximized + * @li "profile,changed": window's profile has been changed * * Examples: * @li @ref win_example_01 @@ -694,6 +695,31 @@ EAPI void elm_win_withdrawn_set(Evas_Object *obj, Eina_Bool wit EAPI Eina_Bool elm_win_withdrawn_get(const Evas_Object *obj); /** + * Set the profile list of a window. + * + * @param obj The window object + * @param profiles The list of profile's name + * @param num_profiles The number of profile names + * + * @ingroup Win + */ +EAPI void elm_win_profiles_set(Evas_Object *obj, const char **profiles, unsigned int num_profiles); + +/** + * Get the profile of a window. + * + * The returned string is an internal one and should not be freed or + * modified. It will also be rendered invalid if a new role is set or if + * the window is destroyed. + * + * @param obj The window object + * @return The profile's name + * + * @ingroup Win + */ +EAPI const char *elm_win_profile_get(const Evas_Object *obj); + +/** * Set the urgent state of a window. * * @param obj The window object -- 2.7.4