tizen 2.4 release
[framework/uifw/elementary.git] / src / lib / elm_app_client.c
1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4
5 #include <Elementary.h>
6 #include "elm_priv.h"
7
8 #define MY_CLASS ELM_APP_CLIENT_CLASS
9
10 #define MY_CLASS_NAME "Elm_App_Client"
11
12 typedef struct
13 {
14    Eldbus_Proxy *app_proxy;
15    Eina_Hash *views;
16 } Elm_App_Client_Data;
17
18 static void
19 _sub_path_process(Elm_App_Client *eo, Eldbus_Message_Iter *obj_iter, Elm_App_Client_Data *data, Eina_Bool loading_list)
20 {
21    const char *obj_path;
22    Eldbus_Message_Iter *array_iface, *iface;
23
24    eldbus_message_iter_arguments_get(obj_iter, "oa{sa{sv}}", &obj_path, &array_iface);
25    while (eldbus_message_iter_get_and_next(array_iface, '{', &iface))
26      {
27         const char *iface_name;
28         Eldbus_Message_Iter *array_props;
29         Elm_App_Client_View *view;
30
31         eldbus_message_iter_arguments_get(iface, "sa{sv}", &iface_name,
32                                           &array_props);
33         if (strcmp(iface_name, "org.enlightenment.ApplicationView1"))
34           continue;
35
36         view = eina_hash_find(data->views, obj_path);
37         if (view)
38           continue;
39
40         view = eo_add(ELM_APP_CLIENT_VIEW_CLASS, eo,
41                              elm_app_client_view_constructor(obj_path));
42         eina_hash_add(data->views, obj_path, view);
43         if (!loading_list)
44           eo_do(eo, eo_event_callback_call(ELM_APP_CLIENT_EVENT_VIEW_CREATED, view));
45      }
46 }
47
48 static void
49 _objects_get(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED)
50 {
51    Eo *eo = data;
52    Elm_App_Client_Data *cdata = eo_data_scope_get(eo, MY_CLASS);
53    Eldbus_Message_Iter *array_path, *path;
54
55    if (eldbus_message_error_get(msg, NULL, NULL))
56      return;
57
58    if (!eldbus_message_arguments_get(msg, "a{oa{sa{sv}}}", &array_path))
59      return;
60    while (eldbus_message_iter_get_and_next(array_path, '{', &path))
61      _sub_path_process(eo, path, cdata, EINA_TRUE);
62
63    eo_do(eo, eo_event_callback_call(ELM_APP_CLIENT_EVENT_VIEW_LIST_LOADED,
64                                     NULL));
65 }
66
67 static void _iface_add(void *data, const Eldbus_Message *msg)
68 {
69    Eo *eo = data;
70    Elm_App_Client_Data *cdata = eo_data_scope_get(eo, MY_CLASS);
71    Eldbus_Message_Iter *main_iter;
72
73    main_iter = eldbus_message_iter_get(msg);
74    _sub_path_process(eo, main_iter, cdata, EINA_FALSE);
75 }
76
77 static void
78 _iface_del(void *data, const Eldbus_Message *msg)
79 {
80    Eo *eo = data;
81    Elm_App_Client_Data *cdata = eo_data_scope_get(eo, MY_CLASS);
82    const char *path, *iface;
83    Eldbus_Message_Iter *array_iface;
84
85    if (!eldbus_message_arguments_get(msg, "oas", &path, &array_iface))
86      return;
87    while (eldbus_message_iter_get_and_next(array_iface, 's', &iface))
88      {
89         Elm_App_Client_View *view;
90         Elm_App_View_State view_state = ELM_APP_VIEW_STATE_UNKNOWN;
91
92         if (strcmp(iface, "org.enlightenment.ApplicationView1"))
93           continue;
94
95         view = eina_hash_find(cdata->views, path);
96         if (!view)
97           continue;
98
99         eo_do(view, view_state = elm_app_client_view_state_get());
100         if (view_state != ELM_APP_VIEW_STATE_CLOSED)
101           {
102              elm_app_client_view_internal_state_set(view,
103                                                     ELM_APP_VIEW_STATE_SHALLOW);
104              continue;
105           }
106
107         eina_hash_del(cdata->views, path, NULL);
108         eo_do(eo, eo_event_callback_call(ELM_APP_CLIENT_EVENT_VIEW_DELETED,
109                                          view));
110         eo_del(view);
111      }
112 }
113
114 static void
115 _pkg_name_owner_changed_cb(void *data, const char *bus EINA_UNUSED, const char *old_id EINA_UNUSED, const char *new_id)
116 {
117    Elm_App_Client *eo = data;
118    Elm_App_Client_Data *cdata = eo_data_scope_get(eo, MY_CLASS);
119    Eina_Iterator *iter;
120    Elm_App_Client_View *view;
121    Eina_List *views_list = NULL;
122
123    if (!new_id || (new_id[0] == '\0'))
124      return;
125
126    iter = eina_hash_iterator_data_new(cdata->views);
127    EINA_ITERATOR_FOREACH(iter, view)
128      views_list = eina_list_append(views_list, view);
129    eina_iterator_free(iter);
130
131    /*
132     * remove all views that are closed of the views hash
133     * views not closed, only set they to SHALLOW
134     */
135    EINA_LIST_FREE(views_list, view)
136      {
137         Elm_App_View_State view_state = ELM_APP_VIEW_STATE_UNKNOWN;
138         const char *path = NULL;
139
140         eo_do(view, view_state = elm_app_client_view_state_get(),
141               path = elm_app_client_view_path_get());
142         if (view_state != ELM_APP_VIEW_STATE_CLOSED)
143           {
144              elm_app_client_view_internal_state_set(view,
145                                                     ELM_APP_VIEW_STATE_SHALLOW);
146              continue;
147           }
148
149         eina_hash_del(cdata->views, path, NULL);
150         eo_do(eo, eo_event_callback_call(ELM_APP_CLIENT_EVENT_VIEW_DELETED,
151                                          view));
152         eo_del(view);
153      }
154 }
155
156 EOLIAN static void
157 _elm_app_client_constructor(Eo *eo, Elm_App_Client_Data *data, const char *pkg)
158 {
159    Eldbus_Connection *conn;
160    Eldbus_Object *obj;
161    char *path;
162
163    EINA_SAFETY_ON_NULL_GOTO(pkg, error);
164
165    data->views = eina_hash_string_small_new(NULL);
166
167    path = _dbus_package_to_path(pkg);
168
169    eldbus_init();
170    conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION);
171    obj = eldbus_object_get(conn, pkg, path);
172    data->app_proxy = eldbus_proxy_get(obj, "org.enlightenment.Application1");
173    eldbus_object_managed_objects_get(obj, _objects_get, eo);
174    eldbus_object_manager_interfaces_added(obj, _iface_add, eo);
175    eldbus_object_manager_interfaces_removed(obj, _iface_del, eo);
176    eldbus_name_owner_changed_callback_add(conn, pkg, _pkg_name_owner_changed_cb,
177                                           eo, EINA_FALSE);
178
179    free(path);
180
181    return;
182 error:
183    eo_error_set(eo);
184 }
185
186 static void
187 _create_view_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
188 {
189    Elm_App_Client_Open_View_Cb cb = eldbus_pending_data_del(pending, "user_cb");
190    void *user_data = eldbus_pending_data_del(pending, "user_data");
191    const char *error_name, *error_message, *view_path;
192    Elm_App_Client *eo = data;
193    Elm_App_Client_View *view;
194    Elm_App_Client_Data *cdata = eo_data_scope_get(eo, MY_CLASS);
195
196    if (eldbus_message_error_get(msg, &error_name, &error_message))
197      {
198         if (!cb)
199           return;
200         if (error_name && !strcmp(error_name, ELDBUS_ERROR_PENDING_CANCELED))
201           cb(user_data, NULL, ELM_APP_CLIENT_VIEW_OPEN_CANCELED, NULL);
202         else if (error_name && !strcmp(error_name, ELDBUS_ERROR_PENDING_TIMEOUT))
203           cb(user_data, NULL, ELM_APP_CLIENT_VIEW_OPEN_TIMEOUT, error_message);
204         else
205           cb(user_data, NULL, error_name, error_message);
206         return;
207      }
208
209    if (!eldbus_message_arguments_get(msg, "o", &view_path))
210      {
211         if (cb)
212           cb(user_data, NULL, "Unknow error", NULL);
213         return;
214      }
215
216    /**
217     * Because a IntefaceAdd signal could arrive first
218     */
219    view = eina_hash_find(cdata->views, view_path);
220    if (!view)
221      {
222         view = eo_add(ELM_APP_CLIENT_VIEW_CLASS, eo,
223                              elm_app_client_view_constructor(view_path));
224         eina_hash_add(cdata->views, view_path, view);
225         eo_do(eo, eo_event_callback_call(ELM_APP_CLIENT_EVENT_VIEW_CREATED,
226                                          view));
227      }
228
229    if (!view)
230      {
231         if (cb)
232           cb(user_data, NULL, ELM_APP_CLEINT_VIEW_OPEN_ERROR, NULL);
233         return;
234      }
235    if (cb)
236      cb(user_data, view, NULL, NULL);
237 }
238
239 EOLIAN static Elm_App_Client_Pending *
240 _elm_app_client_view_open(Eo *eo, Elm_App_Client_Data *data, Eina_Value *args, Elm_App_Client_Open_View_Cb cb, const void *user_data)
241 {
242    Eldbus_Message *msg;
243    Eldbus_Pending *pending;
244
245    msg = eldbus_proxy_method_call_new(data->app_proxy, "CreateView");
246
247    if (args)
248      {
249         if (!eldbus_message_from_eina_value("a{sv}", msg, args))
250           {
251              eldbus_message_unref(msg);
252              //TODO test to find out what type eina_value must be
253              ERR("Eina_Value of args don't have a structure of a{sv}");
254              return NULL;
255           }
256      }
257    else
258     {
259        Eldbus_Message_Iter *main_iter = eldbus_message_iter_get(msg);
260        Eldbus_Message_Iter *array;
261
262        eldbus_message_iter_arguments_append(main_iter, "a{sv}", &array);
263        eldbus_message_iter_container_close(main_iter, array);
264     }
265
266    pending = eldbus_proxy_send(data->app_proxy, msg, _create_view_cb, eo, -1);
267    if (user_data)
268      eldbus_pending_data_set(pending, "user_data", user_data);
269    if (cb)
270      eldbus_pending_data_set(pending, "user_cb", cb);
271
272    return pending;
273 }
274
275 EOLIAN static Eina_Iterator*
276 _elm_app_client_views_get(Eo *eo EINA_UNUSED, Elm_App_Client_Data *data)
277 {
278    return eina_hash_iterator_data_new(data->views);
279 }
280
281 static void
282 _elm_app_client_view_all_close(Eo *obj EINA_UNUSED, Elm_App_Client_Data *data)
283 {
284    eldbus_proxy_call(data->app_proxy, "CloseAllViews", NULL, NULL, -1, "");
285 }
286
287 EOLIAN static void
288 _elm_app_client_terminate(Eo *eo EINA_UNUSED, Elm_App_Client_Data *data)
289 {
290    eldbus_proxy_call(data->app_proxy, "Terminate", NULL, NULL, -1, "");
291 }
292
293 EOLIAN static const char*
294 _elm_app_client_package_get(Eo *eo EINA_UNUSED, Elm_App_Client_Data *data)
295 {
296    Eldbus_Object *obj;
297
298    obj = eldbus_proxy_object_get(data->app_proxy);
299    return eldbus_object_bus_name_get(obj);
300 }
301
302 EOLIAN static void
303 _elm_app_client_view_open_cancel(Eo *eo EINA_UNUSED, Elm_App_Client_Data *_pd EINA_UNUSED, Elm_App_Client_Pending *pending)
304 {
305    eldbus_pending_cancel(pending);
306 }
307
308 EOLIAN static void
309 _elm_app_client_eo_base_destructor(Eo *eo, Elm_App_Client_Data *data)
310 {
311    Eldbus_Object *obj;
312    Eldbus_Connection *conn;
313    Eina_Iterator *iter;
314    Elm_App_Client_View *view;
315
316    iter = eina_hash_iterator_data_new(data->views);
317    EINA_ITERATOR_FOREACH(iter, view)
318      eo_del(view);
319    eina_iterator_free(iter);
320    eina_hash_free(data->views);
321
322    obj = eldbus_proxy_object_get(data->app_proxy);
323    conn = eldbus_object_connection_get(obj);
324    eldbus_name_owner_changed_callback_del(conn, eldbus_object_bus_name_get(obj),
325                                           _pkg_name_owner_changed_cb, eo);
326    eldbus_proxy_unref(data->app_proxy);
327    eldbus_object_unref(obj);
328    eldbus_connection_unref(conn);
329    eldbus_shutdown();
330
331    eo_do_super(eo, MY_CLASS, eo_destructor());
332 }
333
334 #include "elm_app_client.eo.c"