Added per-window profile to support multi-head display.
authorGwanglim Lee <gl77.lee@samsung.com>
Tue, 19 Jun 2012 06:20:29 +0000 (15:20 +0900)
committerGwanglim Lee <gl77.lee@samsung.com>
Tue, 19 Jun 2012 09:01:46 +0000 (18:01 +0900)
Change-Id: Id6d67d7e5b76215246ec78be8f368e2684f22e7a

src/bin/Makefile.am
src/bin/test.c
src/bin/test_config.c [new file with mode: 0644]
src/lib/elm_config.c
src/lib/elm_config.h
src/lib/elm_priv.h
src/lib/elm_win.c
src/lib/elm_win.h

index 93fd441..78e1e68 100644 (file)
@@ -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 \
index e1902ed..57e5788 100644 (file)
@@ -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 (file)
index 0000000..0349885
--- /dev/null
@@ -0,0 +1,120 @@
+#ifdef HAVE_CONFIG_H
+# include "elementary_config.h"
+#endif
+#include <Elementary.h>
+#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, "<b>List of Profiles</b>");
+   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
index 7f112b9..52cdbde 100644 (file)
@@ -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)
 {
index 20ce020..ff07a32 100644 (file)
@@ -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);
+
+/**
  * @}
  */
 
index 4fe6e89..adefb32 100644 (file)
@@ -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);
 
index 3379763..a085dc1 100644 (file)
@@ -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;
index efa764e..248b14a 100644 (file)
@@ -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