174195f547571da9cc3d79013673840aba2c3723
[platform/core/appfw/appcore-widget.git] / src / efl_base / widget_app.c
1 /*
2  * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17
18 #include <stdlib.h>
19 #include <glib.h>
20
21 #include <bundle.h>
22 #include <aul.h>
23 #include <aul_widget.h>
24 #include <dlog.h>
25 #include <Elementary.h>
26 #include <widget_errno.h>
27 #include <widget_instance.h>
28
29 #include "widget_base.h"
30 #include "widget_app.h"
31 #include "widget-log.h"
32 #include "widget-private.h"
33 #include "widget_app_internal.h"
34
35 #ifdef LOG_TAG
36 #undef LOG_TAG
37 #endif
38
39 #define LOG_TAG "CAPI_WIDGET_APPLICATION"
40 #define ICONIFY_TIMEOUT 500
41
42 struct instance_data {
43         Evas_Object *win;
44         guint iconify_timer;
45         bool is_iconified;
46 };
47
48 struct app_cb_info {
49         widget_app_lifecycle_callback_s *callback;
50         void *user_data;
51 };
52
53 struct app_class_cb_info {
54         widget_instance_lifecycle_callback_s callback;
55         void *user_data;
56 };
57
58 static GList *__class_data_list;
59
60 static int __class_resize(widget_base_instance_h instance_h, int w, int h,
61                 void *class_data)
62 {
63         int ret = 0;
64         struct instance_data *data;
65         struct app_class_cb_info *callback_data =
66                         (struct app_class_cb_info *)class_data;
67
68         widget_base_class_on_resize(instance_h, w, h);
69         data = (struct instance_data *)
70                         widget_base_context_get_user_data(instance_h);
71
72         if (!data) {
73                 _E("widget_base_context_get_user_data() returns null");
74
75                 return -1;
76         }
77
78         if (data->win)
79                 evas_object_resize(data->win, w, h);
80         else
81                 _E("unable to find window");
82
83         if (callback_data && callback_data->callback.resize) {
84                 ret = callback_data->callback.resize(
85                                 (widget_context_h)instance_h,
86                                 w, h, callback_data->user_data);
87         }
88
89         return ret;
90 }
91
92 static int __class_update(widget_base_instance_h instance_h, bundle *content,
93                 int force, void *class_data)
94 {
95         int ret = 0;
96         struct app_class_cb_info *callback_data =
97                         (struct app_class_cb_info *)class_data;
98
99         widget_base_class_on_update(instance_h, content, force);
100         if (callback_data && callback_data->callback.update) {
101                 ret = callback_data->callback.update(
102                                 (widget_context_h)instance_h,
103                                 content, force, callback_data->user_data);
104         }
105
106         return ret;
107 }
108
109 static int __class_create(widget_base_instance_h instance_h, bundle *content,
110                 int w, int h, void *class_data)
111 {
112         int ret = -1;
113         struct app_class_cb_info *callback_data =
114                         (struct app_class_cb_info *)class_data;
115
116         widget_base_class_on_create(instance_h, content, w, h);
117         if (callback_data && callback_data->callback.create) {
118                 ret = callback_data->callback.create(
119                                 (widget_context_h)instance_h,
120                                 content, w, h, callback_data->user_data);
121                 aul_widget_write_log(LOG_TAG, "[%s:%d]  ret : %d",
122                         __FUNCTION__, __LINE__, ret);
123         }
124         return ret;
125 }
126
127 static int __class_destroy(widget_base_instance_h instance_h,
128                 widget_base_destroy_type_e reason, bundle *content,
129                 void *class_data)
130 {
131         int ret = 0;
132         struct instance_data *data;
133         struct app_class_cb_info *callback_data =
134                         (struct app_class_cb_info *)class_data;
135
136         if (callback_data && callback_data->callback.destroy) {
137                 ret = callback_data->callback.destroy(
138                                 (widget_context_h)instance_h,
139                                 reason, content, callback_data->user_data);
140                 aul_widget_write_log(LOG_TAG, "[%s:%d]  ret : %d",
141                         __FUNCTION__, __LINE__, ret);
142         }
143
144         data = (struct instance_data *)widget_base_context_get_user_data(instance_h);
145         if (data != NULL) {
146                 widget_base_context_set_user_data(instance_h, NULL);
147                 if (data->iconify_timer > 0)
148                         g_source_remove(data->iconify_timer);
149                 free(data);
150         }
151
152         widget_base_class_on_destroy(instance_h, reason, content);
153
154         return ret;
155 }
156
157 static gboolean __iconify_timeout_cb(gpointer user_data)
158 {
159         struct instance_data *data = user_data;
160         Ecore_Wl2_Window *win = ecore_evas_wayland2_window_get(
161                         ecore_evas_ecore_evas_get(evas_object_evas_get(data->win)));
162
163         if (win) {
164                 ecore_wl2_window_iconified_set(win, EINA_TRUE);
165                 data->is_iconified = true;
166                 _D("set iconify true");
167         }
168
169         data->iconify_timer = 0;
170
171         return G_SOURCE_REMOVE;
172 }
173
174 static int __class_pause(widget_base_instance_h instance_h, void *class_data)
175 {
176         int ret = 0;
177         struct app_class_cb_info *callback_data =
178                         (struct app_class_cb_info *)class_data;
179         struct instance_data *data = (struct instance_data *)
180                         widget_base_context_get_user_data(instance_h);
181
182         if (data->iconify_timer > 0)
183                 g_source_remove(data->iconify_timer);
184
185         data->iconify_timer = g_timeout_add(ICONIFY_TIMEOUT,
186                         __iconify_timeout_cb, data);
187
188         widget_base_class_on_pause(instance_h);
189         if (callback_data && callback_data->callback.pause) {
190                 ret = callback_data->callback.pause(
191                                 (widget_context_h)instance_h,
192                                 callback_data->user_data);
193         }
194
195         return ret;
196 }
197
198 static int __class_resume(widget_base_instance_h instance_h, void *class_data)
199 {
200         int ret = 0;
201         struct app_class_cb_info *callback_data =
202                         (struct app_class_cb_info *)class_data;
203         Ecore_Wl2_Window *win;
204         struct instance_data *data = (struct instance_data *)
205                         widget_base_context_get_user_data(instance_h);
206
207         if (data->iconify_timer > 0) {
208                 g_source_remove(data->iconify_timer);
209                 data->iconify_timer = 0;
210         }
211
212         if (data->is_iconified) {
213                 win = ecore_evas_wayland2_window_get(
214                         ecore_evas_ecore_evas_get(evas_object_evas_get(data->win)));
215                 if (win) {
216                         ecore_wl2_window_iconified_set(win, EINA_FALSE);
217                         data->is_iconified = false;
218                         _D("set iconify false");
219                 }
220         }
221
222         widget_base_class_on_resume(instance_h);
223         if (callback_data && callback_data->callback.resume) {
224                 ret = callback_data->callback.resume(
225                                 (widget_context_h)instance_h,
226                                 callback_data->user_data);
227         }
228
229         return ret;
230 }
231
232 static int __widget_app_create(void *data)
233 {
234         struct app_cb_info *cb_info = (struct app_cb_info *)data;
235         widget_app_lifecycle_callback_s *callback;
236
237         widget_base_on_create();
238         if (cb_info && cb_info->callback && cb_info->callback->create) {
239                 callback = cb_info->callback;
240                 if (callback->create(cb_info->user_data) == NULL) {
241                         _D("fail to create widget");
242                         return -1;
243                 }
244                 _D("widget app is created");
245                 aul_widget_write_log(LOG_TAG, "[%s:%d]", __FUNCTION__, __LINE__);
246                 return 0;
247         }
248
249         return -1;
250 }
251
252 static int __widget_app_terminate(void *data)
253 {
254         struct app_cb_info *cb_info = (struct app_cb_info *)data;
255         widget_app_lifecycle_callback_s *callback;
256
257         if (cb_info && cb_info->callback && cb_info->callback->terminate) {
258                 callback = cb_info->callback;
259                 callback->terminate(cb_info->user_data);
260                 widget_base_on_terminate();
261                 _D("widget app is terminated");
262                 aul_widget_write_log(LOG_TAG, "[%s:%d]", __FUNCTION__, __LINE__);
263                 return 0;
264         }
265
266         widget_base_on_terminate();
267
268         return -1;
269 }
270
271 static void __widget_app_init(int argc, char **argv, void *data)
272 {
273         elm_init(argc, argv);
274 }
275
276 static void __widget_app_finish(void)
277 {
278         elm_shutdown();
279 }
280
281 static void __widget_app_run(void *data)
282 {
283         elm_run();
284 }
285
286 static void __widget_app_exit(void *data)
287 {
288         elm_exit();
289 }
290
291 static void __widget_app_trim_memory(void *data)
292 {
293         _D("Trim memory");
294         elm_cache_all_flush();
295         widget_base_on_trim_memory();
296 }
297
298 EXPORT_API int widget_app_main(int argc, char **argv,
299                 widget_app_lifecycle_callback_s *callback, void *user_data)
300 {
301         widget_base_ops ops;
302         struct app_cb_info cb_info;
303         int r;
304
305         if (argc <= 0 || argv == NULL || callback == NULL)
306                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
307                                 __FUNCTION__, NULL);
308
309         if (callback->create == NULL)
310                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
311                                 __FUNCTION__,
312                                 "widget_app_create_cb() callback must be "
313                                 "registered");
314
315         ops.create = __widget_app_create;
316         ops.terminate = __widget_app_terminate;
317         ops.init = __widget_app_init;
318         ops.finish = __widget_app_finish;
319         ops.run = __widget_app_run;
320         ops.exit = __widget_app_exit;
321         ops.trim_memory = __widget_app_trim_memory;
322
323         cb_info.callback = callback;
324         cb_info.user_data = user_data;
325
326         r = widget_base_init(ops, argc, argv, &cb_info);
327         widget_base_fini();
328
329         if (__class_data_list) {
330                 g_list_free_full(__class_data_list, free);
331                 __class_data_list = NULL;
332         }
333
334         return r;
335 }
336
337 EXPORT_API int widget_app_exit(void)
338 {
339         return widget_base_exit();
340 }
341
342 EXPORT_API int widget_app_terminate_context(widget_context_h context)
343 {
344         return widget_base_terminate_context((widget_base_instance_h)context);
345 }
346
347 EXPORT_API int widget_app_foreach_context(widget_context_cb cb, void *data)
348 {
349         return widget_base_foreach_context((widget_base_instance_cb)cb, data);
350 }
351
352 EXPORT_API int widget_app_add_event_handler(app_event_handler_h *event_handler,
353                                         app_event_type_e event_type,
354                                         app_event_cb callback,
355                                         void *user_data)
356 {
357         return widget_base_add_event_handler(event_handler, event_type,
358                                         callback, user_data);
359 }
360
361 EXPORT_API int widget_app_remove_event_handler(app_event_handler_h
362                                                 event_handler)
363 {
364         return widget_base_remove_event_handler(event_handler);
365 }
366
367 EXPORT_API const char *widget_app_get_id(widget_context_h context)
368 {
369         int ret;
370         char *id;
371
372         if (!context) {
373                 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
374                 return NULL;
375         }
376
377         ret = widget_base_context_get_id((widget_base_instance_h)context, &id);
378         if (ret != WIDGET_BASE_ERROR_NONE) {
379                 _E("failed to get context id"); /* LCOV_EXCL_LINE */
380                 set_last_result(ret); /* LCOV_EXCL_LINE */
381                 return NULL; /* LCOV_EXCL_LINE */
382         }
383
384         set_last_result(WIDGET_ERROR_NONE);
385         return id;
386 }
387
388 static void __win_del_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
389 {
390         char *plug_id;
391         plug_id = evas_object_data_del(obj, "___PLUGID");
392         free(plug_id);
393 }
394
395 EXPORT_API int widget_app_get_elm_win(widget_context_h context,
396                                         Evas_Object **win)
397 {
398         Evas_Object *ret_win = NULL;
399         Ecore_Wl2_Window *wl_win;
400         struct instance_data *data;
401         char buffer[256];
402         int rots[3] = {0};
403         int win_id;
404         char *id;
405         int ret;
406
407         if (context == NULL || win == NULL)
408                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
409                                 __FUNCTION__, NULL);
410
411         ret = widget_base_context_get_id((widget_base_instance_h)context, &id);
412         if (ret != WIDGET_BASE_ERROR_NONE) {
413                 _E("failed to get context id"); /* LCOV_EXCL_LINE */
414                 goto fault; /* LCOV_EXCL_LINE */
415         }
416
417         ret_win = elm_win_add(NULL, id, ELM_WIN_BASIC);
418         if (ret_win == NULL) {
419                 _E("failed to create window"); /* LCOV_EXCL_LINE */
420                 goto fault; /* LCOV_EXCL_LINE */
421         }
422
423         elm_win_wm_rotation_preferred_rotation_set(ret_win, -1);
424         elm_win_wm_rotation_available_rotations_set(ret_win, rots, 1);
425
426         wl_win = ecore_evas_wayland2_window_get(ecore_evas_ecore_evas_get(evas_object_evas_get(ret_win)));
427         if (wl_win == NULL) {
428                 _E("failed to get wayland window"); /* LCOV_EXCL_LINE */
429                 goto fault;
430         }
431
432         ecore_wl2_window_class_set(wl_win, id);
433         elm_win_aux_hint_add(ret_win, "wm.policy.win.user.geometry", "1");
434         widget_base_context_window_bind((widget_base_instance_h)context,        id, wl_win);
435
436         /* Set data to use in accessibility */
437         snprintf(buffer, sizeof(buffer), "%s:%d", id, getpid());
438         evas_object_data_set(ret_win, "___PLUGID", strdup(buffer));
439         evas_object_event_callback_add(ret_win, EVAS_CALLBACK_DEL, __win_del_cb, NULL);
440
441         win_id = ecore_wl2_window_id_get(wl_win);
442         _D("window created: %d", win_id);
443
444         data = (struct instance_data *)widget_base_context_get_user_data(
445                         (widget_base_instance_h)context);
446         if (data == NULL) {
447                 data = calloc(1, sizeof(struct instance_data));
448                 if (data == NULL) {
449                         _E("failed to alloc instance_data"); /* LCOV_EXCL_LINE */
450                         goto fault; /* LCOV_EXCL_LINE */
451                 }
452
453                 ret = widget_base_context_set_user_data((widget_base_instance_h)context, data);
454                 if (ret != WIDGET_BASE_ERROR_NONE) {
455                         _E("fail to set extra data"); /* LCOV_EXCL_LINE */
456                         goto fault; /* LCOV_EXCL_LINE */
457                 }
458         }
459
460         data->win = ret_win;
461         *win = ret_win;
462
463         return WIDGET_ERROR_NONE;
464
465 fault:
466         if (ret_win)    /* LCOV_EXCL_LINE */
467                 evas_object_del(ret_win); /* LCOV_EXCL_LINE */
468
469         return WIDGET_ERROR_FAULT; /* LCOV_EXCL_LINE */
470 }
471
472 EXPORT_API widget_class_h widget_app_class_add(widget_class_h widget_class,
473                 const char *class_id,
474                 widget_instance_lifecycle_callback_s callback, void *user_data)
475 {
476         widget_base_class cls;
477         struct app_class_cb_info *callback_data;
478         widget_class_h wc;
479
480         cls = widget_base_class_get_default();
481
482         /* override methods */
483         cls.ops.create = __class_create;
484         cls.ops.destroy = __class_destroy;
485         cls.ops.pause = __class_pause;
486         cls.ops.resume = __class_resume;
487         cls.ops.resize = __class_resize;
488         cls.ops.update = __class_update;
489
490         callback_data = calloc(1, sizeof(struct app_class_cb_info));
491         if (!callback_data) {
492                 _E("failed to calloc : %s", __FUNCTION__);
493                 set_last_result(WIDGET_ERROR_OUT_OF_MEMORY);
494                 return NULL;
495         }
496         callback_data->callback = callback;
497         callback_data->user_data = user_data;
498
499         wc = (widget_class_h)widget_base_class_add(cls, class_id,
500                         callback_data);
501
502         if (!wc) {
503                 free(callback_data);
504                 return NULL;
505         }
506
507         __class_data_list = g_list_append(__class_data_list, callback_data);
508         set_last_result(WIDGET_ERROR_NONE);
509
510         return wc;
511 }
512
513 EXPORT_API widget_class_h widget_app_class_create(
514                 widget_instance_lifecycle_callback_s callback, void *user_data)
515 {
516         char *appid;
517         widget_class_h wc;
518
519         app_get_id(&appid);
520         if (!appid) {
521                 LOGE("appid is NULL");
522                 return NULL;
523         }
524
525         wc = (widget_class_h)widget_app_class_add(NULL, appid, callback,
526                         user_data);
527         free(appid);
528
529         return wc;
530 }
531
532 EXPORT_API int widget_app_context_set_tag(widget_context_h context, void *tag)
533 {
534         int ret = 0;
535
536         ret = widget_base_context_set_tag((widget_base_instance_h)context, tag);
537         if (ret != WIDGET_BASE_ERROR_NONE)
538                 return widget_app_error(ret, __FUNCTION__, NULL);
539
540         return WIDGET_ERROR_NONE;
541 }
542
543 EXPORT_API int widget_app_context_get_tag(widget_context_h context, void **tag)
544 {
545         int ret = 0;
546
547         ret = widget_base_context_get_tag((widget_base_instance_h)context, tag);
548         if (ret != WIDGET_BASE_ERROR_NONE)
549                 return widget_app_error(ret, __FUNCTION__, NULL);
550
551         return WIDGET_ERROR_NONE;
552 }
553
554 EXPORT_API int widget_app_context_set_content_info(widget_context_h context,
555                 bundle *content_info)
556 {
557         int ret = 0;
558
559         ret = widget_base_context_set_content_info(
560                         (widget_base_instance_h)context, content_info);
561         if (ret != WIDGET_BASE_ERROR_NONE)
562                 return widget_app_error(ret, __FUNCTION__, NULL);
563
564         return WIDGET_ERROR_NONE;
565 }
566
567 EXPORT_API int widget_app_context_set_title(widget_context_h context,
568                 const char *title)
569 {
570         struct instance_data *data = NULL;
571         int ret;
572
573         if (!context || !title) {
574                 _E("Invalid parameter %p %p", context, title);
575                 return WIDGET_ERROR_INVALID_PARAMETER;
576         }
577
578         data = (struct instance_data *)widget_base_context_get_user_data(
579                         (widget_base_instance_h)context);
580         if (data == NULL) {
581                 data = calloc(1, sizeof(struct instance_data));
582                 if (data == NULL) {
583                         return widget_app_error(WIDGET_ERROR_FAULT,
584                                         __FUNCTION__, NULL);
585                 }
586                 ret = widget_base_context_set_user_data(context, data);
587                 if (ret != WIDGET_BASE_ERROR_NONE)
588                         widget_app_error(ret, __FUNCTION__, NULL);
589         }
590
591         if (data->win)
592                 elm_win_title_set(data->win, title);
593
594         return WIDGET_ERROR_NONE;
595 }