Fix crash issue
[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 <dlog.h>
24 #include <Elementary.h>
25 #include <widget_errno.h>
26 #include <widget_instance.h>
27
28 #include "widget_base.h"
29 #include "widget_app.h"
30 #include "widget-log.h"
31 #include "widget-private.h"
32 #include "widget_app_internal.h"
33
34 #ifdef LOG_TAG
35 #undef LOG_TAG
36 #endif
37
38 #define LOG_TAG "CAPI_WIDGET_APPLICATION"
39
40 struct instance_data {
41         Evas_Object *win;
42 };
43
44 struct app_cb_info {
45         widget_app_lifecycle_callback_s *callback;
46         void *user_data;
47 };
48
49 struct app_class_cb_info {
50         widget_instance_lifecycle_callback_s callback;
51         void *user_data;
52 };
53
54 static GList *__class_data_list;
55
56 static int __class_resize(widget_base_instance_h instance_h, int w, int h,
57                 void *class_data)
58 {
59         int ret = 0;
60         struct instance_data *data;
61         struct app_class_cb_info *callback_data =
62                         (struct app_class_cb_info *)class_data;
63
64         widget_base_class_on_resize(instance_h, w, h);
65         data = (struct instance_data *)
66                         widget_base_context_get_user_data(instance_h);
67
68         if (!data) {
69                 _E("widget_base_context_get_user_data() returns null");
70
71                 return -1;
72         }
73
74         if (data->win)
75                 evas_object_resize(data->win, w, h);
76         else
77                 _E("unable to find window");
78
79         if (callback_data && callback_data->callback.resize) {
80                 ret = callback_data->callback.resize(
81                                 (widget_context_h)instance_h,
82                                 w, h, callback_data->user_data);
83         }
84
85         return ret;
86 }
87
88 static int __class_update(widget_base_instance_h instance_h, bundle *content,
89                 int force, void *class_data)
90 {
91         int ret = 0;
92         struct app_class_cb_info *callback_data =
93                         (struct app_class_cb_info *)class_data;
94
95         widget_base_class_on_update(instance_h, content, force);
96         if (callback_data && callback_data->callback.update) {
97                 ret = callback_data->callback.update(
98                                 (widget_context_h)instance_h,
99                                 content, force, callback_data->user_data);
100         }
101
102         return ret;
103 }
104
105 static int __class_create(widget_base_instance_h instance_h, bundle *content,
106                 int w, int h, void *class_data)
107 {
108         int ret = -1;
109         struct app_class_cb_info *callback_data =
110                         (struct app_class_cb_info *)class_data;
111
112         widget_base_class_on_create(instance_h, content, w, h);
113         if (callback_data && callback_data->callback.create) {
114                 ret = callback_data->callback.create(
115                                 (widget_context_h)instance_h,
116                                 content, w, h, callback_data->user_data);
117         }
118         return ret;
119 }
120
121 static int __class_destroy(widget_base_instance_h instance_h,
122                 widget_base_destroy_type_e reason, bundle *content,
123                 void *class_data)
124 {
125         int ret = 0;
126         struct instance_data *data;
127         struct app_class_cb_info *callback_data =
128                         (struct app_class_cb_info *)class_data;
129
130         if (callback_data && callback_data->callback.destroy) {
131                 ret = callback_data->callback.destroy(
132                                 (widget_context_h)instance_h,
133                                 reason, content, callback_data->user_data);
134         }
135
136         data = (struct instance_data *)widget_base_context_get_user_data(instance_h);
137         if (data != NULL) {
138                 widget_base_context_set_user_data(instance_h, NULL);
139                 free(data);
140         }
141
142         widget_base_class_on_destroy(instance_h, reason, content);
143
144         return ret;
145 }
146
147 static int __class_pause(widget_base_instance_h instance_h, void *class_data)
148 {
149         int ret = 0;
150         struct app_class_cb_info *callback_data =
151                         (struct app_class_cb_info *)class_data;
152
153         widget_base_class_on_pause(instance_h);
154         if (callback_data && callback_data->callback.pause) {
155                 ret = callback_data->callback.pause(
156                                 (widget_context_h)instance_h,
157                                 callback_data->user_data);
158         }
159
160         return ret;
161 }
162
163 static int __class_resume(widget_base_instance_h instance_h, void *class_data)
164 {
165         int ret = 0;
166         struct app_class_cb_info *callback_data =
167                         (struct app_class_cb_info *)class_data;
168
169         widget_base_class_on_resume(instance_h);
170         if (callback_data && callback_data->callback.resume) {
171                 ret = callback_data->callback.resume(
172                                 (widget_context_h)instance_h,
173                                 callback_data->user_data);
174         }
175
176         return ret;
177 }
178
179 static int __widget_app_create(void *data)
180 {
181         struct app_cb_info *cb_info = (struct app_cb_info *)data;
182         widget_app_lifecycle_callback_s *callback;
183
184         widget_base_on_create();
185         if (cb_info && cb_info->callback && cb_info->callback->create) {
186                 callback = cb_info->callback;
187                 if (callback->create(cb_info->user_data) == NULL) {
188                         _D("fail to create widget");
189                         return -1;
190                 }
191                 _D("widget app is created");
192                 return 0;
193         }
194
195         return -1;
196 }
197
198 static int __widget_app_terminate(void *data)
199 {
200         struct app_cb_info *cb_info = (struct app_cb_info *)data;
201         widget_app_lifecycle_callback_s *callback;
202
203         if (cb_info && cb_info->callback && cb_info->callback->terminate) {
204                 callback = cb_info->callback;
205                 callback->terminate(cb_info->user_data);
206                 widget_base_on_terminate();
207                 _D("widget app is terminated");
208
209                 return 0;
210         }
211
212         widget_base_on_terminate();
213
214         return -1;
215 }
216
217 static void __widget_app_init(int argc, char **argv, void *data)
218 {
219         elm_init(argc, argv);
220 }
221
222 static void __widget_app_finish(void)
223 {
224         elm_shutdown();
225 }
226
227 static void __widget_app_run(void *data)
228 {
229         elm_run();
230 }
231
232 static void __widget_app_exit(void *data)
233 {
234         elm_exit();
235 }
236
237 EXPORT_API int widget_app_main(int argc, char **argv,
238                 widget_app_lifecycle_callback_s *callback, void *user_data)
239 {
240         widget_base_ops ops;
241         struct app_cb_info cb_info;
242         int r;
243
244         if (argc <= 0 || argv == NULL || callback == NULL)
245                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
246                                 __FUNCTION__, NULL);
247
248         if (callback->create == NULL)
249                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
250                                 __FUNCTION__,
251                                 "widget_app_create_cb() callback must be "
252                                 "registered");
253
254         ops.create = __widget_app_create;
255         ops.terminate = __widget_app_terminate;
256         ops.init = __widget_app_init;
257         ops.finish = __widget_app_finish;
258         ops.run = __widget_app_run;
259         ops.exit = __widget_app_exit;
260
261         cb_info.callback = callback;
262         cb_info.user_data = user_data;
263
264         r = widget_base_init(ops, argc, argv, &cb_info);
265         widget_base_fini();
266
267         if (__class_data_list) {
268                 g_list_free_full(__class_data_list, free);
269                 __class_data_list = NULL;
270         }
271
272         return r;
273 }
274
275 EXPORT_API int widget_app_exit(void)
276 {
277         return widget_base_exit();
278 }
279
280 EXPORT_API int widget_app_terminate_context(widget_context_h context)
281 {
282         return widget_base_terminate_context((widget_base_instance_h)context);
283 }
284
285 EXPORT_API int widget_app_foreach_context(widget_context_cb cb, void *data)
286 {
287         return widget_base_foreach_context((widget_base_instance_cb)cb, data);
288 }
289
290 EXPORT_API int widget_app_add_event_handler(app_event_handler_h *event_handler,
291                                         app_event_type_e event_type,
292                                         app_event_cb callback,
293                                         void *user_data)
294 {
295         return widget_base_add_event_handler(event_handler, event_type,
296                                         callback, user_data);
297 }
298
299 EXPORT_API int widget_app_remove_event_handler(app_event_handler_h
300                                                 event_handler)
301 {
302         return widget_base_remove_event_handler(event_handler);
303 }
304
305 EXPORT_API const char *widget_app_get_id(widget_context_h context)
306 {
307         int ret;
308         char *id;
309
310         if (!context) {
311                 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
312                 return NULL;
313         }
314
315         ret = widget_base_context_get_id((widget_base_instance_h)context, &id);
316         if (ret != WIDGET_BASE_ERROR_NONE) {
317                 _E("failed to get context id"); /* LCOV_EXCL_LINE */
318                 set_last_result(ret); /* LCOV_EXCL_LINE */
319                 return NULL; /* LCOV_EXCL_LINE */
320         }
321
322         set_last_result(WIDGET_ERROR_NONE);
323         return id;
324 }
325
326 static void __win_del_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
327 {
328         char *plug_id;
329         plug_id = evas_object_data_del(obj, "___PLUGID");
330         free(plug_id);
331 }
332
333 EXPORT_API int widget_app_get_elm_win(widget_context_h context,
334                                         Evas_Object **win)
335 {
336         Evas_Object *ret_win = NULL;
337         Ecore_Wl_Window *wl_win;
338         struct instance_data *data;
339         char buffer[256];
340         int rots[3] = {0};
341         int win_id;
342         char *id;
343         int ret;
344
345         if (context == NULL || win == NULL)
346                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
347                                 __FUNCTION__, NULL);
348
349         ret = widget_base_context_get_id((widget_base_instance_h)context, &id);
350         if (ret != WIDGET_BASE_ERROR_NONE) {
351                 _E("failed to get context id"); /* LCOV_EXCL_LINE */
352                 goto fault; /* LCOV_EXCL_LINE */
353         }
354
355         ret_win = elm_win_add(NULL, id, ELM_WIN_BASIC);
356         if (ret_win == NULL) {
357                 _E("failed to create window"); /* LCOV_EXCL_LINE */
358                 goto fault; /* LCOV_EXCL_LINE */
359         }
360
361         elm_win_wm_rotation_preferred_rotation_set(ret_win, -1);
362         elm_win_wm_rotation_available_rotations_set(ret_win, rots, 1);
363
364         wl_win = elm_win_wl_window_get(ret_win);
365         if (wl_win == NULL) {
366                 _E("failed to get wayland window"); /* LCOV_EXCL_LINE */
367                 goto fault;
368         }
369
370         ecore_wl_window_class_name_set(wl_win, id);
371         elm_win_aux_hint_add(ret_win, "wm.policy.win.user.geometry", "1");
372         widget_base_context_window_bind((widget_base_instance_h)context,        id, wl_win);
373
374         /* Set data to use in accessibility */
375         snprintf(buffer, sizeof(buffer), "%s:%d", id, getpid());
376         evas_object_data_set(ret_win, "___PLUGID", strdup(buffer));
377         evas_object_event_callback_add(ret_win, EVAS_CALLBACK_DEL, __win_del_cb, NULL);
378
379         win_id = ecore_wl_window_id_get(wl_win);
380         _D("window created: %d", win_id);
381
382         data = (struct instance_data *)widget_base_context_get_user_data(
383                         (widget_base_instance_h)context);
384         if (data == NULL) {
385                 data = calloc(1, sizeof(struct instance_data));
386                 if (data == NULL) {
387                         _E("failed to alloc instance_data"); /* LCOV_EXCL_LINE */
388                         goto fault; /* LCOV_EXCL_LINE */
389                 }
390
391                 ret = widget_base_context_set_user_data((widget_base_instance_h)context, data);
392                 if (ret != WIDGET_BASE_ERROR_NONE) {
393                         _E("fail to set extra data"); /* LCOV_EXCL_LINE */
394                         goto fault; /* LCOV_EXCL_LINE */
395                 }
396         }
397
398         data->win = ret_win;
399         *win = ret_win;
400
401         return WIDGET_ERROR_NONE;
402
403 fault:
404         if (ret_win)    /* LCOV_EXCL_LINE */
405                 evas_object_del(ret_win); /* LCOV_EXCL_LINE */
406
407         return WIDGET_ERROR_FAULT; /* LCOV_EXCL_LINE */
408 }
409
410 EXPORT_API widget_class_h widget_app_class_add(widget_class_h widget_class,
411                 const char *class_id,
412                 widget_instance_lifecycle_callback_s callback, void *user_data)
413 {
414         widget_base_class cls;
415         struct app_class_cb_info *callback_data;
416         widget_class_h wc;
417
418         cls = widget_base_class_get_default();
419
420         /* override methods */
421         cls.ops.create = __class_create;
422         cls.ops.destroy = __class_destroy;
423         cls.ops.pause = __class_pause;
424         cls.ops.resume = __class_resume;
425         cls.ops.resize = __class_resize;
426         cls.ops.update = __class_update;
427
428         callback_data = calloc(1, sizeof(struct app_class_cb_info));
429         if (!callback_data) {
430                 _E("failed to calloc : %s", __FUNCTION__);
431                 set_last_result(WIDGET_ERROR_OUT_OF_MEMORY);
432                 return NULL;
433         }
434         callback_data->callback = callback;
435         callback_data->user_data = user_data;
436
437         wc = (widget_class_h)widget_base_class_add(cls, class_id,
438                         callback_data);
439
440         if (!wc) {
441                 free(callback_data);
442                 return NULL;
443         }
444
445         __class_data_list = g_list_append(__class_data_list, callback_data);
446         set_last_result(WIDGET_ERROR_NONE);
447
448         return wc;
449 }
450
451 EXPORT_API widget_class_h widget_app_class_create(
452                 widget_instance_lifecycle_callback_s callback, void *user_data)
453 {
454         char *appid;
455         widget_class_h wc;
456
457         app_get_id(&appid);
458         if (!appid) {
459                 LOGE("appid is NULL");
460                 return NULL;
461         }
462
463         wc = (widget_class_h)widget_app_class_add(NULL, appid, callback,
464                         user_data);
465         free(appid);
466
467         return wc;
468 }
469
470 EXPORT_API int widget_app_context_set_tag(widget_context_h context, void *tag)
471 {
472         int ret = 0;
473
474         ret = widget_base_context_set_tag((widget_base_instance_h)context, tag);
475         if (ret != WIDGET_BASE_ERROR_NONE)
476                 return widget_app_error(ret, __FUNCTION__, NULL);
477
478         return WIDGET_ERROR_NONE;
479 }
480
481 EXPORT_API int widget_app_context_get_tag(widget_context_h context, void **tag)
482 {
483         int ret = 0;
484
485         ret = widget_base_context_get_tag((widget_base_instance_h)context, tag);
486         if (ret != WIDGET_BASE_ERROR_NONE)
487                 return widget_app_error(ret, __FUNCTION__, NULL);
488
489         return WIDGET_ERROR_NONE;
490 }
491
492 EXPORT_API int widget_app_context_set_content_info(widget_context_h context,
493                 bundle *content_info)
494 {
495         int ret = 0;
496
497         ret = widget_base_context_set_content_info(
498                         (widget_base_instance_h)context, content_info);
499         if (ret != WIDGET_BASE_ERROR_NONE)
500                 return widget_app_error(ret, __FUNCTION__, NULL);
501
502         return WIDGET_ERROR_NONE;
503 }
504
505 EXPORT_API int widget_app_context_set_title(widget_context_h context,
506                 const char *title)
507 {
508         struct instance_data *data = NULL;
509         int ret;
510
511         if (!context || !title) {
512                 _E("Invalid parameter %p %p", context, title);
513                 return WIDGET_ERROR_INVALID_PARAMETER;
514         }
515
516         data = (struct instance_data *)widget_base_context_get_user_data(
517                         (widget_base_instance_h)context);
518         if (data == NULL) {
519                 data = calloc(1, sizeof(struct instance_data));
520                 if (data == NULL) {
521                         return widget_app_error(WIDGET_ERROR_FAULT,
522                                         __FUNCTION__, NULL);
523                 }
524                 ret = widget_base_context_set_user_data(context, data);
525                 if (ret != WIDGET_BASE_ERROR_NONE)
526                         widget_app_error(ret, __FUNCTION__, NULL);
527         }
528
529         if (data->win)
530                 elm_win_title_set(data->win, title);
531
532         return WIDGET_ERROR_NONE;
533 }