Fix build error
[platform/core/appfw/appcore-widget.git] / src / 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 <stdbool.h>
20
21 #include <bundle.h>
22 #include <bundle_internal.h>
23 #include <aul.h>
24 #include <dlog.h>
25 #include <glib.h>
26 #include <glib-object.h>
27 #include <stdlib.h>
28 #include <Elementary.h>
29 #include <widget_errno.h>
30 #include <widget_instance.h>
31 #include <aul_app_com.h>
32 #include <Ecore_Wayland.h>
33 #include <system_info.h>
34 #include <vconf.h>
35 #include <vconf-internal-keys.h>
36 #include <screen_connector_provider.h>
37 #include <appcore_multiwindow_base.h>
38
39 #include "widget_app.h"
40 #include "widget-log.h"
41 #include "widget-private.h"
42 #include "widget_app_internal.h"
43
44 #ifdef LOG_TAG
45 #undef LOG_TAG
46 #endif
47
48 #define LOG_TAG "CAPI_WIDGET_APPLICATION"
49 #define APP_TYPE_WIDGET "widgetapp"
50 #define STATUS_FOREGROUND "fg"
51 #define STATUS_BACKGROUND "bg"
52
53 struct widget_extra {
54         void *extra;
55         char *instance_id;
56         bundle *args;
57         char *content;
58         Evas_Object *win;
59 };
60
61 struct widget_class_context {
62         widget_instance_lifecycle_callback_s callback;
63         void *data;
64 };
65
66 struct widget_app_context {
67         widget_app_lifecycle_callback_s callback;
68         void *data;
69         bool dirty;
70 };
71
72 struct widget_foreach_context {
73         widget_context_cb callback;
74         void *data;
75 };
76
77 struct app_event_info {
78         app_event_type_e type;
79         void *value;
80 };
81
82 struct app_event_handler {
83         app_event_type_e type;
84         app_event_cb cb;
85         void *data;
86         void *raw;
87 };
88
89 struct _widget_context {
90         int dummy;
91 };
92
93 static int __app_event_converter[APPCORE_BASE_EVENT_MAX] = {
94         [APP_EVENT_LOW_MEMORY] = APPCORE_BASE_EVENT_LOW_MEMORY,
95         [APP_EVENT_LOW_BATTERY] = APPCORE_BASE_EVENT_LOW_BATTERY,
96         [APP_EVENT_LANGUAGE_CHANGED] = APPCORE_BASE_EVENT_LANG_CHANGE,
97         [APP_EVENT_DEVICE_ORIENTATION_CHANGED] = APPCORE_BASE_EVENT_DEVICE_ORIENTATION_CHANGED,
98         [APP_EVENT_REGION_FORMAT_CHANGED] = APPCORE_BASE_EVENT_REGION_CHANGE,
99         [APP_EVENT_SUSPENDED_STATE_CHANGED] = APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE,
100 };
101
102 static struct widget_app_context __context;
103 static char *__appid;
104 static char *__package_id;
105 static bool __fg_signal;
106 char *_viewer_endpoint;
107
108 static bool __is_widget_feature_enabled(void)
109 {
110         static bool feature = false;
111         static bool retrieved = false;
112         int ret;
113
114         if (retrieved == true)
115                 return feature;
116
117         ret = system_info_get_platform_bool(
118                         "http://tizen.org/feature/shell.appwidget", &feature);
119         if (ret != SYSTEM_INFO_ERROR_NONE) {
120                 _E("failed to get system info"); /* LCOV_EXCL_LINE */
121                 return false; /* LCOV_EXCL_LINE */
122         }
123
124         retrieved = true;
125
126         return feature;
127 }
128
129 /* LCOV_EXCL_START */
130 static void __on_poweroff(keynode_t *key, void *data)
131 {
132         int val;
133
134         val = vconf_keynode_get_int(key);
135         switch (val) {
136         case VCONFKEY_SYSMAN_POWER_OFF_DIRECT:
137         case VCONFKEY_SYSMAN_POWER_OFF_RESTART:
138                 _I("power off changed: %d", val);
139                 widget_app_exit();
140                 break;
141         case VCONFKEY_SYSMAN_POWER_OFF_NONE:
142         case VCONFKEY_SYSMAN_POWER_OFF_POPUP:
143         default:
144                 /* DO NOTHING */
145                 break;
146         }
147 }
148 /* LCOV_EXCL_STOP */
149
150 static int __widget_app_create(void *data)
151 {
152         char pkgid[256] = {0, };
153
154         appcore_multiwindow_base_on_create();
155         app_get_id(&__appid);
156         if (aul_app_get_pkgid_bypid(getpid(), pkgid, sizeof(pkgid)) == 0)
157                 __package_id = strdup(pkgid);
158
159         if (!__package_id || !__appid) {
160                 _E("__package_id is NULL");
161                 return -1;
162         }
163
164         screen_connector_provider_init();
165         vconf_notify_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, __on_poweroff, NULL);
166
167         if (__context.callback.create == NULL) {
168                 _E("__context.callback.create(is NULL");
169                 return -1;
170         }
171
172         if (__context.callback.create(__context.data) == NULL) {
173                 _E("app_create_cb() returns NULL");
174                 return -1;
175         }
176
177         _D("widget app is created");
178         return 0;
179 }
180
181 static int __widget_app_terminate(void *data)
182 {
183         if (__context.callback.terminate)
184                 __context.callback.terminate(__context.data);
185
186         vconf_ignore_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, __on_poweroff);
187         screen_connector_provider_fini();
188
189         if (_viewer_endpoint) {
190                 free(_viewer_endpoint);
191                 _viewer_endpoint = NULL;
192         }
193
194         if (__package_id) {
195                 free(__package_id);
196                 __package_id = NULL;
197         }
198
199         if (__appid) {
200                 free(__appid);
201                 __appid = NULL;
202         }
203
204         appcore_multiwindow_base_on_terminate();
205
206         _D("widget app is terminated");
207         return 0;
208 }
209
210 static int __send_lifecycle_event(const char *class_id, const char *instance_id,
211         int status)
212 {
213         bundle *b = bundle_create();
214         int ret;
215
216         if (b == NULL) {
217                 _E("out of memory"); /* LCOV_EXCL_LINE */
218                 return -1; /* LCOV_EXCL_LINE */
219         }
220
221         bundle_add_str(b, AUL_K_WIDGET_ID, class_id);
222         bundle_add_str(b, AUL_K_WIDGET_INSTANCE_ID, instance_id);
223         bundle_add_byte(b, AUL_K_WIDGET_STATUS, &status, sizeof(int));
224         bundle_add_str(b, AUL_K_PKGID, __package_id);
225
226         _D("send lifecycle %s(%d)", instance_id, status);
227         ret = aul_app_com_send("widget.status", b);
228         if (ret < 0)
229                 _E("send lifecycle error:%d", ret); /* LCOV_EXCL_LINE */
230
231         bundle_free(b);
232
233         return ret;
234 }
235
236 static int __send_update_status(const char *class_id, const char *instance_id,
237         int status, bundle *extra)
238 {
239         bundle *b;
240         int lifecycle = -1;
241         bundle_raw *raw = NULL;
242         int len;
243
244         b = bundle_create();
245         if (!b) {
246                 _E("out of memory"); /* LCOV_EXCL_LINE */
247                 return -1; /* LCOV_EXCL_LINE */
248         }
249
250         bundle_add_str(b, AUL_K_WIDGET_ID, class_id);
251         bundle_add_str(b, AUL_K_WIDGET_INSTANCE_ID, instance_id);
252         bundle_add_byte(b, AUL_K_WIDGET_STATUS, &status, sizeof(int));
253
254         if (extra) {
255                 bundle_encode(extra, &raw, &len);
256                 bundle_add_str(b, WIDGET_K_CONTENT_INFO, (const char *)raw);
257                 aul_widget_instance_add(class_id, instance_id);
258         }
259
260         _D("send update %s(%d) to %s", instance_id, status, _viewer_endpoint);
261         aul_app_com_send(_viewer_endpoint, b);
262
263         switch (status) {
264         case WIDGET_INSTANCE_EVENT_CREATE:
265                 lifecycle = WIDGET_LIFE_CYCLE_EVENT_CREATE;
266                 break;
267         case WIDGET_INSTANCE_EVENT_DESTROY:
268                 lifecycle = WIDGET_LIFE_CYCLE_EVENT_DESTROY;
269                 break;
270         case WIDGET_INSTANCE_EVENT_PAUSE:
271                 lifecycle = WIDGET_LIFE_CYCLE_EVENT_PAUSE;
272                 break;
273         case WIDGET_INSTANCE_EVENT_RESUME:
274                 lifecycle = WIDGET_LIFE_CYCLE_EVENT_RESUME;
275                 break;
276         }
277
278         if (lifecycle > -1)
279                 __send_lifecycle_event(class_id, instance_id, lifecycle);
280
281         bundle_free(b);
282         if (raw)
283                 free(raw);
284
285         return 0;
286 }
287
288 static void __instance_resume(const char *class_id, const char *id, bundle *b)
289 {
290         appcore_multiwindow_base_instance_h cxt;
291
292         cxt = appcore_multiwindow_base_instance_find(id);
293
294         if (!cxt) {
295                 _E("context not found: %s", id);
296                 return;
297         }
298
299         appcore_multiwindow_base_instance_resume(cxt);
300
301         __send_update_status(class_id, id,
302                         WIDGET_INSTANCE_EVENT_RESUME, NULL);
303         if (!__fg_signal) {
304                 _D("Send fg signal to resourceD");
305                 aul_send_app_status_change_signal(getpid(),
306                                 __appid,
307                                 __package_id,
308                                 STATUS_FOREGROUND,
309                                 APP_TYPE_WIDGET);
310                 __fg_signal = true;
311         }
312 }
313
314 static void __instance_pause(const char *class_id, const char *id, bundle *b)
315 {
316         appcore_multiwindow_base_instance_h cxt;
317
318         cxt = appcore_multiwindow_base_instance_find(id);
319
320         if (!cxt) {
321                 _E("context not found: %s", id);
322                 return;
323         }
324
325         appcore_multiwindow_base_instance_pause(cxt);
326
327         if (__fg_signal) {
328                 _D("Send bg signal to resourceD");
329                 aul_send_app_status_change_signal(getpid(),
330                                 __appid,
331                                 __package_id,
332                                 STATUS_BACKGROUND,
333                                 APP_TYPE_WIDGET);
334                 __fg_signal = false;
335         }
336 }
337
338 static void __instance_resize(const char *class_id, const char *id, bundle *b)
339 {
340         appcore_multiwindow_base_instance_h cxt;
341         struct widget_class_context *class_cxt;
342         const appcore_multiwindow_base_class *cls;
343         struct widget_extra *we;
344         char *remain = NULL;
345         char *w_str = NULL;
346         char *h_str = NULL;
347         int w = 0;
348         int h = 0;
349
350         cxt = appcore_multiwindow_base_instance_find(id);
351
352         if (!cxt) {
353                 _E("context not found: %s", id);
354                 return;
355         }
356
357         cls = appcore_multiwindow_base_instance_get_class(cxt);
358         if (!cls)
359                 return;
360
361         class_cxt = cls->data;
362         if (!class_cxt) {
363                 _E("class is NULL");
364                 return;
365         }
366
367         we = appcore_multiwindow_base_instance_get_extra(cxt);
368         if (!we) {
369                 _E("widget extra is NULL");
370                 return;
371         }
372
373         bundle_get_str(b, WIDGET_K_WIDTH, &w_str);
374         bundle_get_str(b, WIDGET_K_HEIGHT, &h_str);
375
376         if (w_str)
377                 w = (int)g_ascii_strtoll(w_str, &remain, 10);
378
379         if (h_str)
380                 h = (int)g_ascii_strtoll(h_str, &remain, 10);
381
382         if (we->win)
383                 evas_object_resize(we->win, w, h);
384         else
385                 _E("unable to find window of %s", id);
386
387         if (class_cxt->callback.resize)
388                 class_cxt->callback.resize(cxt, w, h, class_cxt->data);
389         _D("%s is resized to %dx%d", id, w, h);
390         __send_update_status(class_id, id,
391                 WIDGET_INSTANCE_EVENT_SIZE_CHANGED, NULL);
392 }
393
394 static void __inst_cb(const char *class_id, const char *id,
395                 appcore_multiwindow_base_instance_h cxt, void *data)
396 {
397         struct widget_class_context *class_cxt;
398         const appcore_multiwindow_base_class *cls;
399         bundle *content = NULL;
400         char *content_raw = NULL;
401         char *force_str = NULL;
402         int force;
403         bundle *b = data;
404
405         if (!b) {
406                 _E("bundle is NULL");
407                 return;
408         }
409
410         cls = appcore_multiwindow_base_instance_get_class(cxt);
411         if (!cls) {
412                 _E("class is NULL");
413                 return;
414         }
415
416         class_cxt = cls->data;
417         if (!class_cxt) {
418                 _E("class context is NULL");
419                 return;
420         }
421
422         if (!class_cxt->callback.update) {
423                 _E("update callback is NULL");
424                 return;
425         }
426
427         bundle_get_str(b, WIDGET_K_FORCE, &force_str);
428
429         if (force_str && strcmp(force_str, "true") == 0)
430                 force = 1;
431         else
432                 force = 0;
433
434         bundle_get_str(b, WIDGET_K_CONTENT_INFO, &content_raw);
435
436         if (content_raw)
437                 content = bundle_decode((const bundle_raw *)content_raw, strlen(content_raw));
438         class_cxt->callback.update(cxt, content, force, class_cxt->data);
439         __send_update_status(class_id, id,
440                 WIDGET_INSTANCE_EVENT_UPDATE, NULL);
441         _D("updated:%s", id);
442
443         if (content)
444                 bundle_free(content);
445 }
446
447 static void __instance_update(const char *class_id, const char *id, bundle *b)
448 {
449         appcore_multiwindow_base_instance_h cxt;
450
451         if (!id) {
452                 appcore_multiwindow_base_instance_foreach(class_id, __inst_cb, b);
453                 return;
454         }
455
456         cxt = appcore_multiwindow_base_instance_find(id);
457
458         if (!cxt) {
459                 _E("context not found: %s", id);
460                 return;
461         }
462
463         __inst_cb(class_id, id, cxt, b);
464 }
465
466 static void __instance_create(const char *class_id, const char *id, bundle *b)
467 {
468         struct widget_extra *we;
469         char *content = NULL;
470
471         we = (struct widget_extra *)calloc(1, sizeof(struct widget_extra));
472         if (!we) {
473                 _E("Out of memory");
474                 return;
475         }
476
477         we->instance_id = strdup(id);
478         we->args = b;
479         appcore_multiwindow_base_instance_run(class_id, id, we);
480         we->args = NULL;
481         we->win = NULL;
482         bundle_get_str(b, WIDGET_K_CONTENT_INFO, &content);
483         if (content)
484                 we->content = strdup(content);
485
486 }
487
488 static void __check_empty_instance(void)
489 {
490         int cnt = appcore_multiwindow_base_instance_get_cnt();
491
492         if (cnt == 0)
493                 widget_app_exit();
494 }
495
496 static void __instance_destroy(const char *class_id, const char *id, bundle *b)
497 {
498         appcore_multiwindow_base_instance_h cxt;
499         struct widget_extra *we;
500
501         cxt = appcore_multiwindow_base_instance_find(id);
502         if (!cxt) {
503                 _E("could not find widget obj: %s, clear amd info", id);
504                 aul_widget_instance_del(class_id, id);
505                 return;
506         }
507
508         we = appcore_multiwindow_base_instance_get_extra(cxt);
509         we->args = b;
510         appcore_multiwindow_base_instance_exit(cxt);
511         free(we->instance_id);
512         free(we->content);
513         free(we);
514         __check_empty_instance();
515 }
516
517 static int __widget_app_control(bundle *b, void *data)
518 {
519         char *class_id = NULL;
520         char *id = NULL;
521         char *operation = NULL;
522
523         appcore_multiwindow_base_on_control(b);
524
525         bundle_get_str(b, WIDGET_K_CLASS, &class_id);
526         /* for previous version compatibility, use appid for default class id */
527         if (class_id == NULL)
528                 class_id = __appid;
529
530         bundle_get_str(b, AUL_K_WIDGET_INSTANCE_ID, &id);
531         bundle_get_str(b, WIDGET_K_OPERATION, &operation);
532
533         if (!operation) {
534                 _E("operation is NULL");
535                 return 0;
536         }
537
538         if (strcmp(operation, "create") == 0) {
539                 __instance_create(class_id, id, b);
540         } else if (strcmp(operation, "resize") == 0) {
541                 __instance_resize(class_id, id, b);
542         } else if (strcmp(operation, "update") == 0) {
543                 __instance_update(class_id, id, b);
544         } else if (strcmp(operation, "destroy") == 0) {
545                 __instance_destroy(class_id, id, b);
546         } else if (strcmp(operation, "resume") == 0) {
547                 __instance_resume(class_id, id, b);
548         } else if (strcmp(operation, "pause") == 0) {
549                 __instance_pause(class_id, id, b);
550         } else if (strcmp(operation, "terminate") == 0) {
551                 __instance_destroy(class_id, id, b);
552         }
553
554         return 0;
555 }
556
557 static void __inst_resume_cb(const char *class_id, const char *id,
558                 appcore_multiwindow_base_instance_h cxt, void *data)
559 {
560         __instance_resume(class_id, id, data);
561 }
562
563 static void __get_content(bundle *b)
564 {
565         char *instance_id = NULL;
566         appcore_multiwindow_base_instance_h cxt;
567         struct widget_extra *we;
568
569         bundle_get_str(b, AUL_K_WIDGET_INSTANCE_ID, &instance_id);
570         if (!instance_id) {
571                 _E("instance id is NULL");
572                 return;
573         }
574
575         cxt = appcore_multiwindow_base_instance_find(instance_id);
576         if (!cxt) {
577                 _E("could not find widget obj: %s", instance_id);
578                 return;
579         }
580
581         we = appcore_multiwindow_base_instance_get_extra(cxt);
582         if (!we) {
583                 _E("widget extra is NULL");
584                 return;
585         }
586
587         if (we->content) {
588                 bundle_add_str(b, AUL_K_WIDGET_CONTENT_INFO, we->content);
589                 _D("content info of %s found", instance_id);
590         } else {
591                 bundle_add_str(b, AUL_K_WIDGET_CONTENT_INFO, "");
592                 _D("empty content info added");
593         }
594 }
595
596 static int __widget_app_receive(aul_type type, bundle *b, void *data)
597 {
598         appcore_multiwindow_base_on_receive(type, b);
599
600         switch (type) {
601         case AUL_RESUME:
602                 appcore_multiwindow_base_instance_foreach_full(__inst_resume_cb, b);
603                 break;
604         case AUL_TERMINATE:
605                 widget_app_exit();
606                 break;
607         case AUL_WIDGET_CONTENT:
608                 __get_content(b);
609                 break;
610         default:
611                 break;
612         }
613
614         return 0;
615 }
616
617 static void __widget_app_init(int argc, char **argv, void *data)
618 {
619         elm_init(argc, argv);
620 }
621
622 static void __widget_app_finish(void)
623 {
624         elm_shutdown();
625
626         /* Check Loader case */
627         if (getenv("AUL_LOADER_INIT")) {
628                 unsetenv("AUL_LOADER_INIT");
629                 elm_shutdown();
630         }
631 }
632
633 static void __widget_app_run(void *data)
634 {
635         elm_run();
636 }
637
638 static void __widget_app_exit(void *data)
639 {
640         elm_exit();
641 }
642
643 EXPORT_API int widget_app_main(int argc, char **argv,
644                 widget_app_lifecycle_callback_s *callback, void *user_data)
645 {
646         bundle *kb;
647         char *viewer_endpoint = NULL;
648
649         if (!__is_widget_feature_enabled()) {
650                 _E("not supported"); /* LCOV_EXCL_LINE */
651                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
652         }
653
654         if (argc <= 0 || argv == NULL || callback == NULL)
655                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
656                                 __FUNCTION__, NULL);
657
658         if (__context.dirty) {
659                 _E("Already started");
660                 return widget_app_error(WIDGET_ERROR_FAULT, __FUNCTION__, NULL);
661         }
662
663         if (callback->create == NULL)
664                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
665                                 __FUNCTION__,
666                                 "widget_app_create_cb() callback must be "
667                                 "registered");
668
669         appcore_multiwindow_base_ops ops = appcore_multiwindow_base_get_default_ops();
670
671         /* override methods */
672         ops.base.create = __widget_app_create;
673         ops.base.control = __widget_app_control;
674         ops.base.terminate = __widget_app_terminate;
675         ops.base.receive = __widget_app_receive;
676         ops.base.init = __widget_app_init;
677         ops.base.finish = __widget_app_finish;
678         ops.base.run = __widget_app_run;
679         ops.base.exit = __widget_app_exit;
680
681         __context.callback = *callback;
682         __context.data = user_data;
683         kb = bundle_import_from_argv(argc, argv);
684         if (kb) {
685                 bundle_get_str(kb, WIDGET_K_ENDPOINT, &viewer_endpoint);
686                 if (viewer_endpoint) {
687                         _D("viewer endpoint :%s", viewer_endpoint);
688                         _viewer_endpoint = strdup(viewer_endpoint);
689                 } else {
690                         _E("endpoint is missing");
691                 }
692
693                 bundle_free(kb);
694         } else {
695                 _E("failed to get launch argv"); /* LCOV_EXCL_LINE */
696                 return widget_app_error(WIDGET_ERROR_FAULT, __FUNCTION__, NULL);
697         }
698
699         __context.dirty = true;
700         appcore_multiwindow_base_init(ops, argc, argv, NULL);
701         appcore_multiwindow_base_fini();
702         __context.dirty = false;
703
704         return WIDGET_ERROR_NONE;
705 }
706
707 EXPORT_API int widget_app_exit(void)
708 {
709         if (!__is_widget_feature_enabled()) {
710                 _E("not supported"); /* LCOV_EXCL_LINE */
711                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
712         }
713
714         appcore_multiwindow_base_exit();
715         aul_widget_notify_exit();
716
717         return WIDGET_ERROR_NONE;
718 }
719
720 static gboolean __finish_event_cb(gpointer user_data)
721 {
722         appcore_multiwindow_base_instance_h cxt = user_data;
723         bundle *b;
724         const char *id;
725         const char *class_id;
726
727         if (!cxt) {
728                 _E("user_data is NULL");
729                 return FALSE;
730         }
731
732         id = appcore_multiwindow_base_instance_get_id(cxt);
733         class_id = appcore_multiwindow_base_instance_get_class_id(cxt);
734         b = bundle_create();
735
736         if (!b) {
737                 _E("Out-of-memory");
738                 return FALSE;
739         }
740
741         bundle_add_str(b, WIDGET_K_OPERATION, "terminate");
742         __instance_destroy(class_id, id, b);
743         bundle_free(b);
744
745         return FALSE;
746 }
747
748 EXPORT_API int widget_app_terminate_context(widget_context_h context)
749 {
750         if (!__is_widget_feature_enabled()) {
751                 _E("not supported"); /* LCOV_EXCL_LINE */
752                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
753         }
754
755         if (context == NULL)
756                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
757                                 __FUNCTION__, NULL);
758
759         g_idle_add(__finish_event_cb, context);
760         return WIDGET_ERROR_NONE;
761 }
762
763 static void __inst_full_cb(const char *class_id, const char *id,
764                 appcore_multiwindow_base_instance_h cxt, void *data)
765 {
766         struct widget_foreach_context *foreach_context = data;
767
768         if (!data)
769                 return;
770
771         if (foreach_context->callback)
772                 foreach_context->callback(cxt, foreach_context->data);
773 }
774
775 EXPORT_API int widget_app_foreach_context(widget_context_cb cb, void *data)
776 {
777         struct widget_foreach_context foreach_context;
778
779         if (!__is_widget_feature_enabled()) {
780                 _E("not supported"); /* LCOV_EXCL_LINE */
781                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
782         }
783
784         if (!cb) {
785                 _E("callback is NULL");
786                 return WIDGET_ERROR_INVALID_PARAMETER;
787         }
788
789         foreach_context.callback = cb;
790         foreach_context.data = data;
791         appcore_multiwindow_base_instance_foreach_full(__inst_full_cb, &foreach_context);
792
793         return WIDGET_ERROR_NONE;
794 }
795
796 int __event_cb(void *event, void *data)
797 {
798         app_event_handler_h handler = data;
799
800         struct app_event_info app_event;
801
802         app_event.type = handler->type;
803         app_event.value = event;
804
805         if (handler->cb)
806                 handler->cb(&app_event, handler->data);
807
808         return 0;
809 }
810
811 EXPORT_API int widget_app_add_event_handler(app_event_handler_h *event_handler,
812                                         app_event_type_e event_type, app_event_cb callback,
813                                         void *user_data)
814 {
815         int r;
816         bool feature;
817         app_event_handler_h handler;
818
819         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
820         if (r < 0)
821                 return WIDGET_ERROR_FAULT;
822
823         if (!feature)
824                 return WIDGET_ERROR_NOT_SUPPORTED;
825
826         if (event_handler == NULL || callback == NULL)
827                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
828
829         if (event_type < APP_EVENT_LOW_MEMORY
830             || event_type > APP_EVENT_REGION_FORMAT_CHANGED)
831                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
832
833         if (event_type == APP_EVENT_DEVICE_ORIENTATION_CHANGED)
834                 return widget_app_error(WIDGET_ERROR_NOT_SUPPORTED, __FUNCTION__, NULL);
835
836
837         handler = calloc(1, sizeof(struct app_event_handler));
838         if (!handler)
839                 return widget_app_error(WIDGET_ERROR_OUT_OF_MEMORY, __FUNCTION__, "failed to create handler");
840
841         handler->type = event_type;
842         handler->cb = callback;
843         handler->data = user_data;
844         handler->raw = appcore_base_add_event(__app_event_converter[event_type], __event_cb, handler);
845         *event_handler = handler;
846
847         return WIDGET_ERROR_NONE;
848 }
849
850 EXPORT_API int widget_app_remove_event_handler(app_event_handler_h
851                                                 event_handler)
852 {
853         int r;
854         bool feature;
855
856         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
857         if (r < 0)
858                 return WIDGET_ERROR_FAULT;
859
860         if (!feature)
861                 return WIDGET_ERROR_NOT_SUPPORTED;
862
863         app_event_type_e type;
864
865         if (event_handler == NULL)
866                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
867
868         type = event_handler->type;
869         if (type < APP_EVENT_LOW_MEMORY || type > APP_EVENT_REGION_FORMAT_CHANGED)
870                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
871
872         r = appcore_base_remove_event(event_handler->raw);
873         if (r < 0)
874                 return widget_app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "invalid raw handler");
875
876         free(event_handler);
877
878         return WIDGET_ERROR_NONE;
879 }
880
881 EXPORT_API const char *widget_app_get_id(widget_context_h context)
882 {
883         if (!__is_widget_feature_enabled()) {
884                 _E("not supported"); /* LCOV_EXCL_LINE */
885                 set_last_result(WIDGET_ERROR_NOT_SUPPORTED); /* LCOV_EXCL_LINE */
886                 return NULL; /* LCOV_EXCL_LINE */
887         }
888
889         if (!context) {
890                 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
891                 return NULL;
892         }
893
894         set_last_result(WIDGET_ERROR_NONE);
895         return appcore_multiwindow_base_instance_get_id(context);
896 }
897
898 static void __win_del_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
899 {
900         char *plug_id;
901         plug_id = evas_object_data_del(obj, "___PLUGID");
902         free(plug_id);
903 }
904
905 EXPORT_API int widget_app_get_elm_win(widget_context_h context,
906                                         Evas_Object **win)
907 {
908         Evas_Object *ret_win;
909         Ecore_Wl_Window *wl_win;
910         struct wl_surface *surface;
911         struct widget_extra *we;
912         char buffer[256];
913         int rots[3] = {0};
914         int win_id;
915         const char *id;
916         appcore_multiwindow_base_instance_h cxt;
917
918         if (!__is_widget_feature_enabled()) {
919                 _E("not supported"); /* LCOV_EXCL_LINE */
920                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
921         }
922
923         if (context == NULL || win == NULL)
924                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
925                                 __FUNCTION__, NULL);
926
927         cxt = (appcore_multiwindow_base_instance_h)context;
928         id = appcore_multiwindow_base_instance_get_id(cxt);
929         ret_win = elm_win_add(NULL, id, ELM_WIN_BASIC);
930         if (ret_win == NULL) {
931                 _E("failed to create window"); /* LCOV_EXCL_LINE */
932                 goto fault; /* LCOV_EXCL_LINE */
933         }
934
935         elm_win_wm_rotation_preferred_rotation_set(ret_win, -1);
936         elm_win_wm_rotation_available_rotations_set(ret_win, rots, 1);
937
938         wl_win = elm_win_wl_window_get(ret_win);
939         if (wl_win == NULL) {
940                 _E("failed to get wayland window"); /* LCOV_EXCL_LINE */
941                 goto fault;
942         }
943
944         surface = ecore_wl_window_surface_get(wl_win);
945         if (surface == NULL) {
946                 _E("failed to get surface"); /* LCOV_EXCL_LINE */
947                 goto fault; /* LCOV_EXCL_LINE */
948         }
949         screen_connector_provider_remote_enable(id, surface);
950
951         ecore_wl_window_class_name_set(wl_win, id);
952         elm_win_aux_hint_add(ret_win, "wm.policy.win.user.geometry", "1");
953
954         *win = ret_win;
955         we  = appcore_multiwindow_base_instance_get_extra(cxt);
956         we->win = ret_win;
957         win_id = ecore_wl_window_id_get(wl_win);
958
959         /* Set data to use in accessibility */
960         snprintf(buffer, sizeof(buffer), "%s:%d", id, getpid());
961         evas_object_data_set(ret_win, "___PLUGID", strdup(buffer));
962         evas_object_event_callback_add(ret_win, EVAS_CALLBACK_DEL, __win_del_cb, NULL);
963         appcore_multiwindow_base_window_bind(cxt, wl_win);
964
965         _D("window created: %d", win_id);
966
967         return WIDGET_ERROR_NONE;
968
969 fault:
970         if (ret_win)    /* LCOV_EXCL_LINE */
971                 evas_object_del(ret_win); /* LCOV_EXCL_LINE */
972
973         return WIDGET_ERROR_FAULT; /* LCOV_EXCL_LINE */
974 }
975
976 static void __instance_drop(appcore_multiwindow_base_instance_h cxt)
977 {
978         struct widget_extra *we;
979
980         we = appcore_multiwindow_base_instance_get_extra(cxt);
981         appcore_multiwindow_base_instance_drop(cxt);
982         free(we->instance_id);
983         free(we->content);
984         free(we);
985         __check_empty_instance();
986 }
987
988 static void __stub_create(appcore_multiwindow_base_instance_h context, void *data)
989 {
990         struct widget_class_context *cxt  = data;
991         struct widget_extra *we;
992         bundle *b;
993         bundle *content_info = NULL;
994         char *id = NULL;
995         char *class_id = NULL;
996         char *operation = NULL;
997         char *content = NULL;
998         char *w_str = NULL;
999         char *h_str = NULL;
1000         char *remain = NULL;
1001         int w = 0;
1002         int h = 0;
1003         int ret = -1;
1004
1005         appcore_multiwindow_base_class_on_create(context);
1006         we  = appcore_multiwindow_base_instance_get_extra((appcore_multiwindow_base_instance_h)context);
1007         b = we->args;
1008
1009         bundle_get_str(b, WIDGET_K_CLASS, &class_id);
1010         /* for previous version compatibility, use appid for default class id */
1011         if (class_id == NULL)
1012                 class_id = __appid;
1013
1014         bundle_get_str(b, AUL_K_WIDGET_INSTANCE_ID, &id);
1015         bundle_get_str(b, WIDGET_K_OPERATION, &operation);
1016
1017         if (!operation) {
1018                 _E("no operation provided");
1019                 return;
1020         }
1021
1022         bundle_get_str(b, WIDGET_K_CONTENT_INFO, &content);
1023         bundle_get_str(b, WIDGET_K_WIDTH, &w_str);
1024         bundle_get_str(b, WIDGET_K_HEIGHT, &h_str);
1025
1026         if (w_str)
1027                 w = (int)g_ascii_strtoll(w_str, &remain, 10);
1028
1029         if (h_str)
1030                 h = (int)g_ascii_strtoll(h_str, &remain, 10);
1031
1032         if (content)
1033                 content_info = bundle_decode((const bundle_raw *)content, strlen(content));
1034
1035         if (cxt->callback.create)
1036                 ret = cxt->callback.create(context, content_info, w, h, cxt->data);
1037         _D("%s is created", id);
1038
1039         if (ret < 0) {
1040                 _W("Create callback returns error(%d)", ret);
1041                 ret = __send_update_status(class_id, id,
1042                                 WIDGET_INSTANCE_EVENT_CREATE_ABORTED, NULL);
1043                 __instance_drop(context);
1044         } else {
1045                 ret = __send_update_status(class_id, id,
1046                         WIDGET_INSTANCE_EVENT_CREATE, NULL);
1047
1048                 aul_widget_instance_add(class_id, id);
1049         }
1050
1051         if (content_info)
1052                 bundle_free(content_info);
1053 }
1054
1055 static void __stub_terminate(appcore_multiwindow_base_instance_h context, void *data)
1056 {
1057         struct widget_class_context *class_cxt  = data;
1058         struct widget_extra *we;
1059         bundle *b;
1060         char *operation = NULL;
1061         bundle *content_info;
1062         widget_app_destroy_type_e reason = WIDGET_APP_DESTROY_TYPE_TEMPORARY;
1063         int event = WIDGET_INSTANCE_EVENT_TERMINATE;
1064         const char *id;
1065         const char *class_id;
1066
1067         id = appcore_multiwindow_base_instance_get_id(context);
1068         class_id = appcore_multiwindow_base_instance_get_class_id(context);
1069         we  = appcore_multiwindow_base_instance_get_extra((appcore_multiwindow_base_instance_h)context);
1070         b = we->args;
1071
1072         if (b) {
1073                 bundle_get_str(b, WIDGET_K_OPERATION, &operation);
1074                 if (operation && strcmp(operation, "destroy") == 0)
1075                         reason = WIDGET_APP_DESTROY_TYPE_PERMANENT;
1076         }
1077
1078         if (we->content)
1079                 content_info = bundle_decode((const bundle_raw *)we->content, strlen(we->content));
1080         else
1081                 content_info = bundle_create();
1082
1083         if (class_cxt->callback.destroy)
1084                 class_cxt->callback.destroy(context, reason, content_info, class_cxt->data);
1085         _D("%s is destroyed %d", id, reason);
1086
1087         if (reason == WIDGET_APP_DESTROY_TYPE_PERMANENT) {
1088                 event = WIDGET_INSTANCE_EVENT_DESTROY;
1089                 aul_widget_instance_del(class_id, id);
1090         } else {
1091                 __send_update_status(class_id, id,
1092                                 WIDGET_INSTANCE_EVENT_EXTRA_UPDATED, content_info);
1093         }
1094
1095         if (content_info)
1096                 bundle_free(content_info);
1097
1098         __send_update_status(class_id, id, event, NULL);
1099         appcore_multiwindow_base_class_on_terminate(context);
1100 }
1101
1102 static void __stub_pause(appcore_multiwindow_base_instance_h context, void *data)
1103 {
1104         struct widget_class_context *class_cxt  = data;
1105         const char *id;
1106         const char *class_id;
1107
1108         appcore_multiwindow_base_class_on_pause(context);
1109         id = appcore_multiwindow_base_instance_get_id(context);
1110         class_id = appcore_multiwindow_base_instance_get_class_id(context);
1111
1112         if (!class_cxt) {
1113                 _E("class context is NULL");
1114                 return;
1115         }
1116
1117         if (class_cxt->callback.pause)
1118                 class_cxt->callback.pause(context, class_cxt->data);
1119         _D("%s is paused", id);
1120         __send_update_status(class_id, id,
1121                 WIDGET_INSTANCE_EVENT_PAUSE, NULL);
1122 }
1123
1124 static void __stub_resume(appcore_multiwindow_base_instance_h context, void *data)
1125 {
1126         struct widget_class_context *class_cxt  = data;
1127         const char *id;
1128         const char *class_id;
1129
1130         appcore_multiwindow_base_class_on_resume(context);
1131         id = appcore_multiwindow_base_instance_get_id(context);
1132         class_id = appcore_multiwindow_base_instance_get_class_id(context);
1133
1134         if (!class_cxt) {
1135                 _E("class context is NULL");
1136                 return;
1137         }
1138
1139         if (class_cxt->callback.resume)
1140                 class_cxt->callback.resume(context, class_cxt->data);
1141         _D("%s is resumed", id);
1142         __send_update_status(class_id, id,
1143                 WIDGET_INSTANCE_EVENT_RESUME, NULL);
1144 }
1145
1146 EXPORT_API widget_class_h widget_app_class_add(widget_class_h widget_class,
1147                 const char *class_id,
1148                 widget_instance_lifecycle_callback_s callback, void *user_data)
1149 {
1150         appcore_multiwindow_base_class cls;
1151         struct widget_class_context *cxt;
1152
1153         if (!__is_widget_feature_enabled()) {
1154                 _E("not supported");
1155                 set_last_result(WIDGET_ERROR_NOT_SUPPORTED);
1156                 return NULL;
1157         }
1158
1159         if (!class_id) {
1160                 _E("class is is NULL");
1161                 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
1162                 return NULL;
1163         }
1164
1165         cxt = calloc(1, sizeof(struct widget_class_context));
1166
1167         if (!cxt) {
1168                 _E("failed to calloc : %s", __FUNCTION__);
1169                 set_last_result(WIDGET_ERROR_OUT_OF_MEMORY);
1170                 return NULL;
1171         }
1172
1173         cxt->callback = callback;
1174         cxt->data = user_data;
1175
1176         cls.id = strdup(class_id);
1177         cls.data = cxt;
1178         cls.create = __stub_create;
1179         cls.terminate = __stub_terminate;
1180         cls.pause = __stub_pause;
1181         cls.resume = __stub_resume;
1182
1183         appcore_multiwindow_base_class_add(cls);
1184         set_last_result(WIDGET_ERROR_NONE);
1185
1186         return (widget_class_h)cxt;
1187 }
1188
1189 EXPORT_API widget_class_h widget_app_class_create(
1190                 widget_instance_lifecycle_callback_s callback, void *user_data)
1191 {
1192         return widget_app_class_add(NULL, __appid, callback, user_data);
1193 }
1194
1195 EXPORT_API int widget_app_context_set_tag(widget_context_h context, void *tag)
1196 {
1197         struct widget_extra *we;
1198
1199         if (!__is_widget_feature_enabled()) {
1200                 _E("not supported"); /* LCOV_EXCL_LINE */
1201                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1202         }
1203
1204         if (!context)
1205                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1206                                 __FUNCTION__, NULL);
1207
1208         we = appcore_multiwindow_base_instance_get_extra((appcore_multiwindow_base_instance_h)context);
1209         we->extra = tag;
1210
1211         return WIDGET_ERROR_NONE;
1212 }
1213
1214 EXPORT_API int widget_app_context_get_tag(widget_context_h context, void **tag)
1215 {
1216         struct widget_extra *we;
1217
1218         if (!__is_widget_feature_enabled()) {
1219                 _E("not supported"); /* LCOV_EXCL_LINE */
1220                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1221         }
1222
1223         if (!context || !tag)
1224                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1225                                 __FUNCTION__, NULL);
1226
1227         we  = appcore_multiwindow_base_instance_get_extra((appcore_multiwindow_base_instance_h)context);
1228         if (we == NULL)
1229                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1230                                 __FUNCTION__, NULL);
1231         *tag = we->extra;
1232
1233         return WIDGET_ERROR_NONE;
1234 }
1235
1236 EXPORT_API int widget_app_context_set_content_info(widget_context_h context,
1237                 bundle *content_info)
1238 {
1239         int ret = 0;
1240         bundle_raw *raw = NULL;
1241         int len;
1242         const char *id;
1243         const char *class_id;
1244         struct widget_extra *we;
1245         appcore_multiwindow_base_instance_h cxt;
1246
1247         if (!__is_widget_feature_enabled()) {
1248                 _E("not supported"); /* LCOV_EXCL_LINE */
1249                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1250         }
1251
1252         if (!context || !content_info)
1253                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1254                                 __FUNCTION__, NULL);
1255
1256         cxt = (appcore_multiwindow_base_instance_h)context;
1257         id = appcore_multiwindow_base_instance_get_id(cxt);
1258         class_id = appcore_multiwindow_base_instance_get_class_id(cxt);
1259         we  = appcore_multiwindow_base_instance_get_extra(cxt);
1260
1261         if (!class_id || !id || !we)
1262                 return widget_app_error(WIDGET_ERROR_FAULT, __FUNCTION__, NULL);
1263
1264         ret = __send_update_status(class_id, id,
1265                         WIDGET_INSTANCE_EVENT_EXTRA_UPDATED, content_info);
1266
1267         if (we->content)
1268                 free(we->content);
1269
1270         bundle_encode(content_info, &raw, &len);
1271         if (raw)
1272                 we->content = strdup((const char *)raw);
1273         else
1274                 we->content = NULL;
1275
1276         free(raw);
1277         if (ret < 0) {
1278                 /* LCOV_EXCL_START */
1279                 _E("failed to send content info: %s of %s (%d)", id,
1280                                 class_id, ret);
1281                 return widget_app_error(WIDGET_ERROR_IO_ERROR, __FUNCTION__,
1282                                 NULL);
1283                 /* LCOV_EXCL_STOP */
1284         }
1285
1286         return WIDGET_ERROR_NONE;
1287 }
1288
1289 EXPORT_API int widget_app_context_set_title(widget_context_h context,
1290                 const char *title)
1291 {
1292         appcore_multiwindow_base_instance_h cxt;
1293         struct widget_extra *we;
1294
1295         if (!__is_widget_feature_enabled()) {
1296                 _E("not supported"); /* LCOV_EXCL_LINE */
1297                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1298         }
1299
1300         if (!context || !title) {
1301                 _E("Invalid parameter %p %p", context, title);
1302                 return WIDGET_ERROR_INVALID_PARAMETER;
1303         }
1304
1305         cxt = (appcore_multiwindow_base_instance_h)context;
1306         we  = appcore_multiwindow_base_instance_get_extra(cxt);
1307
1308         if (we->win)
1309                 elm_win_title_set(we->win, title);
1310
1311         return WIDGET_ERROR_NONE;
1312 }