Implement window event callback
[platform/core/appfw/appcore-widget.git] / src / widget_app.c
1 /*
2  * Copyright (c) 2015 - 2016 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
20 #include <bundle.h>
21 #include <bundle_internal.h>
22 #include <aul.h>
23 #include <dlog.h>
24 #include <glib.h>
25 #include <glib-object.h>
26 #include <stdlib.h>
27 #include <app_control.h>
28 #include <app_control_internal.h>
29 #include <Elementary.h>
30 #include <widget_errno.h>
31 #include <widget_instance.h>
32 #include <widget_service.h>
33 #include <widget_service_internal.h>
34 #include <aul_app_com.h>
35 #include <Ecore_Wayland.h>
36 #include <system_info.h>
37 #include <vconf.h>
38 #include <vconf-internal-keys.h>
39
40 #include "widget_app.h"
41 #include "widget-log.h"
42 #include "widget-private.h"
43 #include "widget_app_internal.h"
44
45 #ifdef LOG_TAG
46 #undef LOG_TAG
47 #endif
48
49 #define STR_MAX_BUF 128
50 #define LOG_TAG "CAPI_WIDGET_APPLICATION"
51 #define K_REASON    "__WC_K_REASON__"
52
53 typedef enum _widget_obj_state_e {
54         WC_READY = 0,
55         WC_RUNNING = 1,
56         WC_PAUSED = 2,
57         WC_TERMINATED = 3
58 } widget_obj_state_e;
59
60 struct _widget_class {
61         void *user_data;
62         widget_instance_lifecycle_callback_s ops;
63         char *classid;
64         struct _widget_class *next;
65         struct _widget_class *prev;
66 };
67
68 struct app_event_handler {
69         app_event_type_e type;
70         app_event_cb cb;
71         void *data;
72 };
73
74 struct app_event_info {
75         app_event_type_e type;
76         void *value;
77 };
78
79 struct _widget_context {
80         char *id;
81         struct _widget_class *provider;
82         int state;
83         void *tag;
84         Evas_Object *win;
85         int win_id;
86         bundle *content;
87         widget_instance_lifecycle_callback_s ops;
88 };
89
90 typedef struct _widget_class widget_class_s;
91 typedef struct _widget_context widget_context_s;
92
93 #define WIDGET_APP_EVENT_MAX 5
94 static GList *handler_list[WIDGET_APP_EVENT_MAX] = {NULL, };
95
96 static int caller_pid = 0;
97 static widget_app_lifecycle_callback_s *app_ops;
98 static void *app_user_data = NULL;
99 static char *appid = NULL;
100 static widget_class_h class_provider = NULL;
101 static GList *contexts = NULL;
102 static char *viewer_endpoint = NULL;
103
104 static void _widget_core_set_appcore_event_cb(void);
105 static void _widget_core_unset_appcore_event_cb(void);
106
107 static void __free_handler_cb(gpointer data)
108 {
109         if (data)
110                 free(data);
111 }
112
113 static void __free_handler_list(void)
114 {
115         int i;
116
117         for (i = 0; i < WIDGET_APP_EVENT_MAX; i++) {
118                 g_list_free_full(handler_list[i], __free_handler_cb);
119                 handler_list[i] = NULL;
120         }
121 }
122
123 static inline bool _is_widget_feature_enabled(void)
124 {
125         static bool feature = false;
126         static bool retrieved = false;
127         int ret;
128
129         if (retrieved == true)
130                 return feature;
131
132         ret = system_info_get_platform_bool(
133                         "http://tizen.org/feature/shell.appwidget", &feature);
134         if (ret != SYSTEM_INFO_ERROR_NONE) {
135                 _E("failed to get system info");
136                 return false;
137         }
138
139         retrieved = true;
140
141         return feature;
142 }
143
144 static gint __comp_by_id(gconstpointer a, gconstpointer b)
145 {
146         widget_context_s *wc = (widget_context_s *)a;
147
148         return strcmp(wc->id, (const char *)b);
149 }
150
151 static widget_context_s *__find_context_by_id(const char *id)
152 {
153         GList *ret = g_list_find_custom(contexts, id, __comp_by_id);
154
155         if (ret == NULL)
156                 return NULL;
157
158         return ret->data;
159 }
160
161 static gint __comp_by_win(gconstpointer a, gconstpointer b)
162 {
163         int win = GPOINTER_TO_INT(b);
164         widget_context_s *wc = (widget_context_s *)a;
165
166         return (wc && wc->win_id == win) ? 0 : -1;
167 }
168
169 static widget_context_s *__find_context_by_win(int win)
170 {
171         GList *ret = g_list_find_custom(contexts, GINT_TO_POINTER(win), __comp_by_win);
172
173         if (ret == NULL)
174                 return NULL;
175
176         return ret->data;
177 }
178
179 static int __send_lifecycle_event(const char *class_id, const char *instance_id,
180         int status)
181 {
182         bundle *b = bundle_create();
183         int ret;
184
185         if (b == NULL) {
186                 _E("out of memory");
187                 return -1;
188         }
189
190         bundle_add_str(b, WIDGET_K_ID, class_id);
191         bundle_add_str(b, WIDGET_K_INSTANCE, instance_id);
192         bundle_add_byte(b, WIDGET_K_STATUS, &status, sizeof(int));
193
194         _D("send lifecycle %s(%d)", instance_id, status);
195         ret = aul_app_com_send("widget.status", b);
196         if (ret < 0)
197                 _E("send lifecycle error:%d", ret);
198
199         bundle_free(b);
200
201         return ret;
202 }
203
204 static int __send_update_status(const char *class_id, const char *instance_id,
205         int status, bundle *extra, int internal_only)
206 {
207         bundle *b = extra;
208         int lifecycle = -1;
209
210         if (b == NULL)
211                 b = bundle_create();
212
213         bundle_add_str(b, WIDGET_K_ID, class_id);
214         bundle_add_str(b, WIDGET_K_INSTANCE, instance_id);
215         bundle_add_byte(b, WIDGET_K_STATUS, &status, sizeof(int));
216
217         _D("send update %s(%d) to %s", instance_id, status, viewer_endpoint);
218         aul_app_com_send(viewer_endpoint, b);
219
220         switch (status) {
221         case WIDGET_INSTANCE_EVENT_CREATE:
222                 lifecycle = WIDGET_LIFE_CYCLE_EVENT_CREATE;
223                 break;
224         case WIDGET_INSTANCE_EVENT_DESTROY:
225                 lifecycle = WIDGET_LIFE_CYCLE_EVENT_DESTROY;
226                 break;
227         case WIDGET_INSTANCE_EVENT_PAUSE:
228                 lifecycle = WIDGET_LIFE_CYCLE_EVENT_PAUSE;
229                 break;
230         case WIDGET_INSTANCE_EVENT_RESUME:
231                 lifecycle = WIDGET_LIFE_CYCLE_EVENT_RESUME;
232                 break;
233         }
234
235         if (lifecycle > -1)
236                 __send_lifecycle_event(class_id, instance_id, lifecycle);
237
238         if (extra == NULL)
239                 bundle_free(b);
240
241         return 0;
242 }
243
244 static int __instance_resume(widget_class_h handle, const char *id, bundle *b)
245 {
246         widget_context_s *wc = __find_context_by_id(id);
247         int ret;
248
249         if (!wc) {
250                 _E("context not found: %s", id);
251                 return -1;
252         }
253
254         if (wc->state == WC_RUNNING) {
255                 _D("%s is already in running state", id);
256                 return 0;
257         }
258
259         if (wc->state == WC_TERMINATED) {
260                 _D("%s is in terminated state", id);
261                 return 0;
262         }
263
264         if (handle->ops.resume)
265                 handle->ops.resume(wc, handle->user_data);
266
267         wc->state = WC_RUNNING;
268         _D("%s is resumed", id);
269         ret = __send_update_status(handle->classid, wc->id,
270                 WIDGET_INSTANCE_EVENT_RESUME, NULL, 0);
271
272         return ret;
273 }
274
275 static int __instance_pause(widget_class_h handle, const char *id, bundle *b)
276 {
277         widget_context_s *wc = __find_context_by_id(id);
278         int ret;
279
280         if (!wc) {
281                 _E("context not found: %s", id);
282                 return -1;
283         }
284
285         if (wc->state == WC_PAUSED) {
286                 _D("%s is already in paused state", id);
287                 return 0;
288         }
289
290         if (wc->state == WC_TERMINATED) {
291                 _D("%s is in terminated state", id);
292                 return 0;
293         }
294
295         if (handle->ops.pause)
296                 handle->ops.pause(wc, handle->user_data);
297
298         wc->state = WC_PAUSED;
299         _D("%s is paused", id);
300         ret = __send_update_status(handle->classid, wc->id,
301                 WIDGET_INSTANCE_EVENT_PAUSE, NULL, 0);
302
303         return ret;
304 }
305
306 static int __instance_resize(widget_class_h handle, const char *id, int w, int h, bundle *b)
307 {
308         widget_context_s *wc = __find_context_by_id(id);
309         int ret;
310
311         if (!wc) {
312                 _E("context not found: %s", id);
313                 return -1;
314         }
315
316         if (handle->ops.resize)
317                 handle->ops.resize(wc, w, h, handle->user_data);
318
319         _D("%s is resized to %dx%d", id, w, h);
320         ret = __send_update_status(handle->classid, wc->id,
321                 WIDGET_INSTANCE_EVENT_SIZE_CHANGED, NULL, 0);
322
323         return ret;
324 }
325
326 static int __instance_update(widget_class_h handle, const char *id, bundle *b)
327 {
328         widget_context_s *wc = __find_context_by_id(id);
329         int ret;
330         int force;
331         char *force_str = NULL;
332
333         if (!wc) {
334                 _E("context not found: %s", id);
335                 return -1;
336         }
337
338         if (handle->ops.update) {
339                 if (b)
340                         bundle_get_str(b, WIDGET_K_FORCE, &force_str);
341
342                 if (force_str && strcmp(force_str, "true") == 0)
343                         force = 1;
344                 else
345                         force = 0;
346
347                 handle->ops.update(wc, b, force, handle->user_data);
348                 ret = __send_update_status(handle->classid, wc->id,
349                         WIDGET_INSTANCE_EVENT_UPDATE, b, 0);
350                 _D("updated:%s", id);
351         }
352
353         return ret;
354 }
355
356 static int __instance_create(widget_class_h handle, const char *id, bundle *b)
357 {
358         widget_context_s *wc = NULL;
359         int w = 0, h = 0;
360         char *w_str = NULL, *h_str = NULL;
361         char *remain = NULL;
362         int ret = 0;
363
364         wc = (widget_context_s *)malloc(sizeof(widget_context_s));
365         if (!wc)
366                 return WIDGET_ERROR_OUT_OF_MEMORY;
367
368         wc->state = WC_READY;
369         wc->id = g_strdup(id);
370         wc->provider = handle;
371         wc->win = NULL;
372         wc->win_id = -1;
373
374         wc->content = bundle_dup(b);
375         bundle_get_str(b, WIDGET_K_WIDTH, &w_str);
376         bundle_get_str(b, WIDGET_K_HEIGHT, &h_str);
377
378         if (w_str)
379                 w = (int)g_ascii_strtoll(w_str, &remain, 10);
380
381         if (h_str)
382                 h = (int)g_ascii_strtoll(h_str, &remain, 10);
383
384         contexts = g_list_append(contexts, wc);
385
386         handle->ops.create(wc, b, w, h, handle->user_data);
387         ret = __send_update_status(handle->classid, wc->id,
388                         WIDGET_INSTANCE_EVENT_CREATE, b, 0);
389
390         return ret;
391 }
392
393 static int __instance_destroy(widget_class_h handle, const char *id,
394                 widget_destroy_type_e reason, bundle *b)
395 {
396         widget_context_s *wc = __find_context_by_id(id);
397         int ret = 0;
398
399         if (!wc) {
400                 _E("could not find widget obj: %s", id);
401                 return WIDGET_ERROR_INVALID_PARAMETER;
402         }
403
404         wc->state = WC_TERMINATED;
405         handle->ops.destroy(wc, (widget_app_destroy_type_e)reason, b,
406                         handle->user_data);
407
408         ret = __send_update_status(handle->classid, id,
409                         WIDGET_INSTANCE_EVENT_TERMINATE, b, 0);
410
411         contexts = g_list_remove(contexts, wc);
412
413         if (wc->id)
414                 free(wc->id);
415
416         free(wc);
417
418         return ret;
419 }
420
421 static widget_class_h __find_class_handler(const char *class_id,
422                 widget_class_h handle)
423 {
424         if (!class_id || !handle)
425                 return NULL;
426
427         widget_class_h head = handle;
428
429         while (head) {
430                 if (head->classid && strcmp(head->classid, class_id) == 0)
431                         return head;
432
433                 head = head->next;
434         }
435
436         return NULL;
437 }
438
439 static void __resize_window(char *id, bundle *b)
440 {
441         widget_context_s *wc = __find_context_by_id(id);
442         char *w_str = NULL;
443         char *h_str = NULL;
444         char *remain = NULL;
445         int w;
446         int h;
447
448         bundle_get_str(b, WIDGET_K_WIDTH, &w_str);
449         bundle_get_str(b, WIDGET_K_HEIGHT, &h_str);
450
451         if (w_str) {
452                 w = (int)g_ascii_strtoll(w_str, &remain, 10);
453         } else {
454                 _E("unable to get width");
455                 return;
456         }
457
458         if (h_str) {
459                 h = (int)g_ascii_strtoll(h_str, &remain, 10);
460         } else {
461                 _E("unable to get height");
462                 return;
463         }
464
465         if (wc->win)
466                 evas_object_resize(wc->win, w, h);
467         else
468                 _E("unable to find window of %d", wc->id);
469 }
470
471 static void __control(bundle *b)
472 {
473         char *class_id = NULL;
474         char *id = NULL;
475         char *operation = NULL;
476         char *reason = NULL;
477         char *remain = NULL;
478         int destroy_type = WIDGET_DESTROY_TYPE_DEFAULT;
479
480         widget_class_h handle = NULL;
481         bundle_get_str(b, WIDGET_K_CLASS, &class_id);
482         /* for previous version compatibility, use appid for default class id */
483         if (class_id == NULL)
484                 class_id = appid;
485
486         bundle_get_str(b, WIDGET_K_INSTANCE, &id);
487         bundle_get_str(b, WIDGET_K_OPERATION, &operation);
488
489         handle = __find_class_handler(class_id, class_provider);
490         if (!handle) {
491                 _E("no handle provided: %s", class_id);
492                 goto error;
493         }
494
495         if (!operation) {
496                 _E("no operation provided");
497                 goto error;
498         }
499
500         if (strcmp(operation, "create") == 0) {
501                 __instance_create(handle, id, b);
502         } else if (strcmp(operation, "resize") == 0) {
503                 __resize_window(id, b);
504         } else if (strcmp(operation, "update") == 0) {
505                 __instance_update(handle, id, b);
506         } else if (strcmp(operation, "destroy") == 0) {
507                 bundle_get_str(b, WIDGET_K_REASON, &reason);
508                 if (reason)
509                         destroy_type = (int)g_ascii_strtoll(reason, &remain,
510                                         10);
511
512                 __instance_destroy(handle, id, destroy_type, b);
513         } else if (strcmp(operation, "resume") == 0) {
514                 __instance_resume(handle, id, b);
515         } else if (strcmp(operation, "pause") == 0) {
516                 __instance_pause(handle, id, b);
517         }
518
519         return;
520 error:
521         LOGD("error on control");
522         return;
523 }
524
525 static void __resume_cb(const char *id, void *data)
526 {
527         widget_context_s *cxt = __find_context_by_id(id);
528
529         if (!cxt) {
530                 _E("invalid context id:%s", id);
531                 return;
532         }
533
534         __instance_resume(cxt->provider, id, NULL);
535 }
536
537 static void __pause_cb(const char *id, void *data)
538 {
539         widget_context_s *cxt = __find_context_by_id(id);
540
541         if (!cxt) {
542                 _E("invalid context id:%s", id);
543                 return;
544         }
545
546         __instance_pause(cxt->provider, id, NULL);
547 }
548
549 static void __pause_all()
550 {
551         GList *iter = g_list_first(contexts);
552
553         while (iter != NULL) {
554                 widget_context_s *cxt = (widget_context_s *)iter->data;
555                 const char *id = cxt->id;
556
557                 switch (cxt->state) {
558                 case WC_READY:
559                         __resume_cb(id, NULL);
560                         __pause_cb(id, NULL);
561                         break;
562                 case WC_RUNNING:
563                         __pause_cb(id, NULL);
564                         break;
565                 }
566                 iter = g_list_next(iter);
567         }
568 }
569
570 static void __resume_all()
571 {
572         GList *iter = g_list_first(contexts);
573
574         while (iter != NULL) {
575                 widget_context_s *cxt = (widget_context_s *)iter->data;
576                 const char *id = cxt->id;
577
578                 switch (cxt->state) {
579                 case WC_READY:
580                         __resume_cb(id, NULL);
581                         break;
582                 case WC_PAUSED:
583                         __resume_cb(id, NULL);
584                         break;
585                 }
586                 iter = g_list_next(iter);
587         }
588 }
589
590 static Eina_Bool __show_cb(void *data, int type, void *event)
591 {
592         Ecore_Wl_Event_Window_Show *ev = event;
593         widget_context_s *cxt = __find_context_by_win(ev->win);
594
595         LOGD("show %d %d", (unsigned int)ev->win, (unsigned int)ev->data[0]);
596
597         if (cxt)
598                 __instance_resume(cxt->provider, cxt->id, NULL);
599         else
600                 LOGE("unknown window error: %d", ev->win);
601
602         return ECORE_CALLBACK_RENEW;
603 }
604
605 static Eina_Bool __hide_cb(void *data, int type, void *event)
606 {
607         Ecore_Wl_Event_Window_Hide *ev = event;
608         widget_context_s *cxt = __find_context_by_win(ev->win);
609
610
611         LOGD("hide %d", (unsigned int)ev->win);
612
613         if (cxt)
614                 __instance_pause(cxt->provider, cxt->id, NULL);
615         else
616                 LOGE("unknown window error: %d", ev->win);
617
618         return ECORE_CALLBACK_RENEW;
619 }
620
621 static Eina_Bool __visibility_cb(void *data, int type, void *event)
622 {
623         Ecore_Wl_Event_Window_Visibility_Change *ev = event;
624         widget_context_s *cxt = __find_context_by_win(ev->win);
625
626         LOGD("visiblity change: %d %d", (unsigned int)ev->win,  (unsigned int)ev->fully_obscured);
627
628         if (!cxt) {
629                 LOGE("unknown window error: %d", ev->win);
630                 return ECORE_CALLBACK_RENEW;
631         }
632
633         if (cxt->state == WC_PAUSED && ev->fully_obscured == 0) {
634                 __instance_resume(cxt->provider, cxt->id, NULL);
635         } else if (cxt->state == WC_RUNNING && ev->fully_obscured == 1) {
636                 __instance_pause(cxt->provider, cxt->id, NULL);
637         } else {
638                 LOGD("cxt:%s state:%d obscured:%d", cxt->id, cxt->state, ev->fully_obscured);
639         }
640
641         return ECORE_CALLBACK_RENEW;
642 }
643
644 static Eina_Bool __lower_cb(void *data, int type, void *event)
645 {
646         LOGD("lower");
647         return ECORE_CALLBACK_RENEW;
648 }
649
650 static Eina_Bool __configure_cb(void *data, int type, void *event)
651 {
652         Ecore_Wl_Event_Window_Configure *ev = event;
653         widget_context_s *cxt = __find_context_by_win(ev->win);
654
655         LOGD("configure: %d %d", ev->w, ev->h);
656
657         if (!cxt) {
658                 LOGE("unknown window error: %d", ev->win);
659                 return ECORE_CALLBACK_RENEW;
660         }
661
662         if (cxt->state == WC_PAUSED || cxt->state == WC_RUNNING)
663                 __instance_resize(cxt->provider, cxt->id, ev->w, ev->h, NULL);
664         LOGD("cxt:%s resized to %dx%d", cxt->id, ev->w, ev->h);
665
666         return ECORE_CALLBACK_RENEW;
667 }
668
669 static void __add_climsg()
670 {
671         ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_SHOW, __show_cb, NULL);
672         ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_HIDE, __hide_cb, NULL);
673         ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_VISIBILITY_CHANGE, __visibility_cb, NULL);
674         ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_LOWER, __lower_cb, NULL);
675         ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_CONFIGURE, __configure_cb, NULL);
676 }
677
678 static int __aul_handler(aul_type type, bundle *b, void *data)
679 {
680         char *caller = NULL;
681         char *remain = NULL;
682
683         switch (type) {
684         case AUL_START:
685                 if (b) {
686                         bundle_get_str(b, WIDGET_K_CALLER, &caller);
687                         if (caller) {
688                                 caller_pid = g_ascii_strtoll(caller, &remain,
689                                                 10);
690                         } else {
691                                 /* using caller appid and query pid using caller appid? */
692                                 _E("no caller pid");
693                         }
694                 }
695
696                 __control(b);
697                 break;
698         case AUL_RESUME:
699                 __resume_all();
700                 break;
701         case AUL_TERMINATE:
702                 widget_app_exit();
703                 break;
704         default:
705                 break;
706         }
707
708         return 0;
709 }
710
711 static char *__get_domain_name(char *appid)
712 {
713         char *name_token;
714
715         if (appid == NULL) {
716                 _E("appid is NULL");
717                 return NULL;
718         }
719
720         name_token = strrchr(appid, '.');
721
722         if (name_token == NULL) {
723                 _E("appid is invalid");
724                 return appid;
725         }
726
727         name_token++;
728
729         return name_token;
730 }
731
732 static void __on_poweroff(keynode_t *key, void *data)
733 {
734         int val;
735
736         val = vconf_keynode_get_int(key);
737         switch (val) {
738         case VCONFKEY_SYSMAN_POWER_OFF_DIRECT:
739         case VCONFKEY_SYSMAN_POWER_OFF_RESTART:
740                 _I("power off changed: %d", val);
741                 widget_app_exit();
742                 break;
743         case VCONFKEY_SYSMAN_POWER_OFF_NONE:
744         case VCONFKEY_SYSMAN_POWER_OFF_POPUP:
745         default:
746                 /* DO NOTHING */
747                 break;
748         }
749 }
750
751 extern int _set_i18n(const char *name);
752
753 static int __before_loop(int argc, char **argv)
754 {
755         int r;
756         bundle *kb = NULL;
757         char *wayland_display = NULL;
758         char *xdg_runtime_dir = NULL;
759         char *name;
760
761 #if !(GLIB_CHECK_VERSION(2, 36, 0))
762         g_type_init();
763 #endif
764
765         kb = bundle_import_from_argv(argc, argv);
766         if (kb) {
767                 bundle_get_str(kb, AUL_K_WAYLAND_WORKING_DIR, &xdg_runtime_dir);
768                 bundle_get_str(kb, AUL_K_WAYLAND_DISPLAY, &wayland_display);
769                 bundle_get_str(kb, WIDGET_K_ENDPOINT, &viewer_endpoint);
770                 if (viewer_endpoint) {
771                         _E("viewer endpoint :%s", viewer_endpoint);
772                         viewer_endpoint = strdup(viewer_endpoint);
773                 } else {
774                         _E("endpoint is missing");
775                 }
776
777                 if (xdg_runtime_dir)
778                         setenv("XDG_RUNTIME_DIR", xdg_runtime_dir, 1);
779
780                 _D("xdg_runtime_dir:%s", xdg_runtime_dir);
781
782                 if (wayland_display)
783                         setenv("WAYLAND_DISPLAY", wayland_display, 1);
784
785                 _D("wayland_display:%s", wayland_display);
786
787                 bundle_free(kb);
788                 kb = NULL;
789         } else {
790                 _E("failed to get launch argv");
791         }
792
793         elm_init(argc, argv);
794
795         r = aul_launch_init(__aul_handler, NULL);
796         if (r < 0) {
797                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
798                                 __FUNCTION__,
799                                 "Fail to call the aul_launch_init");
800         }
801
802         r = aul_launch_argv_handler(argc, argv);
803         if (r < 0) {
804                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
805                                 __FUNCTION__,
806                                 "Fail to call the aul_launch_argv_handler");
807         }
808
809         r = app_get_id(&appid);
810         if (r != APP_ERROR_NONE)
811                 return r;
812
813         name = __get_domain_name(appid);
814
815         if (name == NULL) {
816                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
817                                 __FUNCTION__,
818                                 "Fail to call __get_domain_name");
819         }
820
821         r = _set_i18n(name);
822
823         if (r < 0) {
824                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
825                                 __FUNCTION__,
826                                 "Fail to call _set_i18n");
827         }
828
829         __add_climsg();
830
831         _widget_core_set_appcore_event_cb();
832
833         class_provider = app_ops->create(app_user_data);
834         if (class_provider == NULL) {
835                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
836                                 __FUNCTION__, "widget_class is NULL");
837         }
838
839         vconf_notify_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, __on_poweroff, NULL);
840
841         return WIDGET_ERROR_NONE;
842 }
843
844 static void __after_loop()
845 {
846         vconf_ignore_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, __on_poweroff);
847
848         __pause_all();
849
850         if (app_ops->terminate)
851                 app_ops->terminate(app_user_data);
852
853         if (viewer_endpoint)
854                 free(viewer_endpoint);
855
856         _widget_core_unset_appcore_event_cb();
857         __free_handler_list();
858         elm_shutdown();
859 }
860
861 static void __on_low_memory(keynode_t *key, void *data)
862 {
863         int val;
864
865         val = vconf_keynode_get_int(key);
866         if (val == VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING) {
867                 app_event_handler_h handler;
868                 struct app_event_info event;
869
870                 _I("widget_app_low_memory");
871
872                 event.type = APP_EVENT_LOW_MEMORY;
873                 event.value = (void *)&val;
874
875                 GList *iter = g_list_first(handler_list[APP_EVENT_LOW_MEMORY]);
876
877                 while (iter) {
878                         handler = (app_event_handler_h) iter->data;
879                         handler->cb(&event, handler->data);
880                         iter = g_list_next(iter);
881                 }
882         }
883 }
884
885 static void __on_low_battery(keynode_t *key, void *data)
886 {
887         int val;
888
889         val = vconf_keynode_get_int(key);
890         if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW) {
891                 app_event_handler_h handler;
892                 struct app_event_info event;
893
894                 _I("widget_app_low_battery");
895
896                 event.type = APP_EVENT_LOW_BATTERY;
897                 event.value = (void *)&val;
898
899                 GList *iter = g_list_first(handler_list[APP_EVENT_LOW_BATTERY]);
900
901                 while (iter) {
902                         handler = (app_event_handler_h) iter->data;
903                         handler->cb(&event, handler->data);
904                         iter = g_list_next(iter);
905                 }
906         }
907 }
908
909 static void __on_lang_changed(keynode_t *key, void *data)
910 {
911         char *val;
912
913         _update_lang();
914         val = vconf_keynode_get_str(key);
915
916         app_event_handler_h handler;
917         struct app_event_info event;
918
919         _I("widget_app_lang_changed");
920
921         event.type = APP_EVENT_LANGUAGE_CHANGED;
922         event.value = (void *)val;
923
924         GList *iter = g_list_first(handler_list[APP_EVENT_LANGUAGE_CHANGED]);
925
926         while (iter) {
927                 handler = (app_event_handler_h) iter->data;
928                 handler->cb(&event, handler->data);
929                 iter = g_list_next(iter);
930         }
931 }
932
933 static void __on_region_changed(keynode_t *key, void *data)
934 {
935         char *val;
936
937         _update_region();
938         val = vconf_keynode_get_str(key);
939
940         app_event_handler_h handler;
941         struct app_event_info event;
942
943         _I("widget_app_region_changed");
944
945         event.type = APP_EVENT_REGION_FORMAT_CHANGED;
946         event.value = (void *)val;
947
948         GList *iter = g_list_first(handler_list[APP_EVENT_REGION_FORMAT_CHANGED]);
949
950         while (iter) {
951                 handler = (app_event_handler_h) iter->data;
952                 handler->cb(&event, handler->data);
953                 iter = g_list_next(iter);
954         }
955 }
956
957 static void __register_event(int event_type)
958 {
959         switch (event_type) {
960         case APP_EVENT_LOW_MEMORY:
961                 vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __on_low_memory, NULL);
962                 break;
963
964         case APP_EVENT_LOW_BATTERY:
965                 vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __on_low_battery, NULL);
966                 break;
967
968         case APP_EVENT_LANGUAGE_CHANGED:
969                 vconf_notify_key_changed(VCONFKEY_LANGSET, __on_lang_changed, NULL);
970                 break;
971
972         case APP_EVENT_REGION_FORMAT_CHANGED:
973                 vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, __on_region_changed, NULL);
974                 break;
975         }
976 }
977
978 static void __unregister_event(int event_type)
979 {
980         switch (event_type) {
981         case APP_EVENT_LOW_MEMORY:
982                 vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __on_low_memory);
983                 break;
984
985         case APP_EVENT_LOW_BATTERY:
986                 vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __on_low_battery);
987                 break;
988
989         case APP_EVENT_LANGUAGE_CHANGED:
990                 vconf_ignore_key_changed(VCONFKEY_LANGSET, __on_lang_changed);
991                 break;
992
993         case APP_EVENT_REGION_FORMAT_CHANGED:
994                 vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, __on_region_changed);
995                 break;
996         }
997 }
998
999 static void _widget_core_set_appcore_event_cb(void)
1000 {
1001         __register_event(APP_EVENT_LANGUAGE_CHANGED);
1002         __register_event(APP_EVENT_REGION_FORMAT_CHANGED);
1003 }
1004
1005 static void _widget_core_unset_appcore_event_cb(void)
1006 {
1007         __unregister_event(APP_EVENT_LANGUAGE_CHANGED);
1008         __unregister_event(APP_EVENT_REGION_FORMAT_CHANGED);
1009 }
1010
1011 EXPORT_API int widget_app_main(int argc, char **argv,
1012                 widget_app_lifecycle_callback_s *callback, void *user_data)
1013 {
1014         int r;
1015
1016         if (!_is_widget_feature_enabled()) {
1017                 _E("not supported");
1018                 return WIDGET_ERROR_NOT_SUPPORTED;
1019         }
1020
1021         if (argc <= 0 || argv == NULL || callback == NULL)
1022                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1023                                 __FUNCTION__, NULL);
1024
1025         if (callback->create == NULL)
1026                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1027                                 __FUNCTION__,
1028                                 "widget_app_create_cb() callback must be "
1029                                 "registered");
1030
1031         app_ops = callback;
1032         app_user_data = user_data;
1033         r = __before_loop(argc, argv);
1034         if (r < 0)
1035                 return r;
1036
1037         ecore_main_loop_begin();
1038         aul_status_update(STATUS_DYING);
1039         __after_loop();
1040
1041         return WIDGET_ERROR_NONE;
1042 }
1043
1044 EXPORT_API int widget_app_exit(void)
1045 {
1046         if (!_is_widget_feature_enabled()) {
1047                 _E("not supported");
1048                 return WIDGET_ERROR_NOT_SUPPORTED;
1049         }
1050
1051         ecore_main_loop_quit();
1052
1053         return WIDGET_ERROR_NONE;
1054 }
1055
1056 static gboolean __finish_event_cb(gpointer user_data)
1057 {
1058         if (user_data == NULL)
1059                 return FALSE;
1060
1061         widget_context_s *wc = (widget_context_s *)user_data;
1062
1063         switch (wc->state) {
1064         case WC_READY:
1065
1066                 break;
1067         case WC_RUNNING:
1068
1069                 break;
1070         case WC_PAUSED:
1071
1072                 break;
1073         default:
1074                 break;
1075         }
1076
1077         return FALSE;
1078 }
1079
1080 EXPORT_API int widget_app_terminate_context(widget_context_h context)
1081 {
1082         if (!_is_widget_feature_enabled()) {
1083                 _E("not supported");
1084                 return WIDGET_ERROR_NOT_SUPPORTED;
1085         }
1086
1087         if (context == NULL)
1088                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1089                                 __FUNCTION__, NULL);
1090
1091         g_idle_add(__finish_event_cb, context);
1092         return WIDGET_ERROR_NONE;
1093 }
1094
1095 EXPORT_API int widget_app_foreach_context(widget_context_cb cb, void *data)
1096 {
1097         GList *list;
1098         widget_context_s *wc;
1099
1100         if (!_is_widget_feature_enabled()) {
1101                 _E("not supported");
1102                 return WIDGET_ERROR_NOT_SUPPORTED;
1103         }
1104
1105         if (!cb)
1106                 return WIDGET_ERROR_INVALID_PARAMETER;
1107
1108         list = g_list_first(contexts);
1109
1110         while (list) {
1111                 wc = (widget_context_s *)list->data;
1112                 if (wc) {
1113                         if (!cb(wc, data))
1114                                 break;
1115                 }
1116                 list = list->next;
1117         }
1118
1119         return WIDGET_ERROR_NONE;
1120 }
1121
1122 EXPORT_API int widget_app_add_event_handler(app_event_handler_h *event_handler,
1123                                         app_event_type_e event_type, app_event_cb callback,
1124                                         void *user_data)
1125 {
1126         int r;
1127         bool feature;
1128
1129         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
1130         if (r < 0)
1131                 return WIDGET_ERROR_FAULT;
1132
1133         if (!feature)
1134                 return WIDGET_ERROR_NOT_SUPPORTED;
1135
1136         app_event_handler_h handler;
1137
1138         if (event_handler == NULL || callback == NULL)
1139                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
1140
1141         if (event_type < APP_EVENT_LOW_MEMORY
1142             || event_type > APP_EVENT_REGION_FORMAT_CHANGED)
1143                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
1144
1145         if (event_type == APP_EVENT_DEVICE_ORIENTATION_CHANGED)
1146                 return widget_app_error(WIDGET_ERROR_NOT_SUPPORTED, __FUNCTION__, NULL);
1147
1148         GList *iter = g_list_first(handler_list[event_type]);
1149
1150         while (iter) {
1151                 handler = (app_event_handler_h) iter->data;
1152
1153                 if (handler->cb == callback)
1154                         return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
1155
1156                 iter = g_list_next(iter);
1157         }
1158
1159         handler = calloc(1, sizeof(struct app_event_handler));
1160         if (!handler)
1161                 return widget_app_error(WIDGET_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
1162
1163         if (g_list_length(handler_list[event_type]) == 0)
1164                 __register_event(event_type);
1165
1166         handler->type = event_type;
1167         handler->cb = callback;
1168         handler->data = user_data;
1169         handler_list[event_type] = g_list_append(handler_list[event_type], handler);
1170
1171         *event_handler = handler;
1172
1173         return WIDGET_ERROR_NONE;
1174 }
1175
1176 EXPORT_API int widget_app_remove_event_handler(app_event_handler_h
1177                                                 event_handler)
1178 {
1179         int r;
1180         bool feature;
1181
1182         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
1183         if (r < 0)
1184                 return WIDGET_ERROR_FAULT;
1185
1186         if (!feature)
1187                 return WIDGET_ERROR_NOT_SUPPORTED;
1188
1189         app_event_type_e type;
1190
1191         if (event_handler == NULL)
1192                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
1193
1194         type = event_handler->type;
1195         if (type < APP_EVENT_LOW_MEMORY || type > APP_EVENT_REGION_FORMAT_CHANGED)
1196                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
1197
1198         handler_list[type] = g_list_remove(handler_list[type], event_handler);
1199         free(event_handler);
1200
1201         if (g_list_length(handler_list[type]) == 0)
1202                 __unregister_event(type);
1203
1204         return WIDGET_ERROR_NONE;
1205 }
1206
1207 EXPORT_API const char *widget_app_get_id(widget_context_h context)
1208 {
1209         if (!_is_widget_feature_enabled()) {
1210                 _E("not supported");
1211                 set_last_result(WIDGET_ERROR_NOT_SUPPORTED);
1212                 return NULL;
1213         }
1214
1215         if (!context) {
1216                 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
1217                 return NULL;
1218         }
1219
1220         set_last_result(WIDGET_ERROR_NONE);
1221         return context->id;
1222 }
1223
1224 EXPORT_API int widget_app_get_elm_win(widget_context_h context,
1225                                         Evas_Object **win)
1226 {
1227         widget_context_s *cxt = (widget_context_s *)context;
1228         Evas_Object *ret_win;
1229         Ecore_Wl_Window *wl_win;
1230
1231         if (!_is_widget_feature_enabled()) {
1232                 _E("not supported");
1233                 return WIDGET_ERROR_NOT_SUPPORTED;
1234         }
1235
1236         if (context == NULL || win == NULL)
1237                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1238                                 __FUNCTION__, NULL);
1239
1240         ret_win = elm_win_add(NULL, cxt->id, ELM_WIN_BASIC);
1241         if (ret_win == NULL) {
1242                 _E("failed to create window");
1243                 return WIDGET_ERROR_FAULT;
1244         }
1245
1246         wl_win = elm_win_wl_window_get(ret_win);
1247         if (wl_win == NULL) {
1248                 _E("failed to get wayland window");
1249                 evas_object_del(ret_win);
1250                 return WIDGET_ERROR_FAULT;
1251         }
1252
1253         ecore_wl_window_class_name_set(wl_win, cxt->id);
1254
1255         *win = ret_win;
1256         cxt->win = ret_win;
1257         cxt->win_id = ecore_wl_window_id_get(wl_win);
1258
1259         _D("window created: %d", cxt->win_id);
1260
1261         return WIDGET_ERROR_NONE;
1262 }
1263
1264 widget_class_h _widget_class_create(widget_class_s *prev, const char *class_id,
1265                 widget_instance_lifecycle_callback_s callback, void *user_data)
1266 {
1267         widget_class_s *wc;
1268
1269         if (!_is_widget_feature_enabled()) {
1270                 _E("not supported");
1271                 set_last_result(WIDGET_ERROR_NOT_SUPPORTED);
1272                 return NULL;
1273         }
1274
1275         if (class_id == NULL) {
1276                 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
1277                 return NULL;
1278         }
1279
1280         wc = (widget_class_s *)malloc(sizeof(widget_class_s));
1281         if (wc == NULL) {
1282                 _E("failed to malloc : %s", __FUNCTION__);
1283                 set_last_result(WIDGET_ERROR_OUT_OF_MEMORY);
1284                 return NULL;
1285         }
1286
1287         wc->classid = strdup(class_id);
1288         wc->user_data = user_data;
1289         wc->ops = callback;
1290         wc->next = prev;
1291         wc->prev = NULL;
1292
1293         set_last_result(WIDGET_ERROR_NONE);
1294
1295         if (prev)
1296                 prev->prev = wc;
1297
1298         return wc;
1299 }
1300
1301 EXPORT_API widget_class_h widget_app_class_add(widget_class_h widget_class,
1302                 const char *class_id,
1303                 widget_instance_lifecycle_callback_s callback, void *user_data)
1304 {
1305         return _widget_class_create(widget_class, class_id, callback,
1306                         user_data);
1307 }
1308
1309 EXPORT_API widget_class_h widget_app_class_create(
1310                 widget_instance_lifecycle_callback_s callback, void *user_data)
1311 {
1312         return _widget_class_create(class_provider, appid, callback, user_data);
1313 }
1314
1315 EXPORT_API int widget_app_context_set_tag(widget_context_h context, void *tag)
1316 {
1317         if (!_is_widget_feature_enabled()) {
1318                 _E("not supported");
1319                 return WIDGET_ERROR_NOT_SUPPORTED;
1320         }
1321
1322         if (context == NULL)
1323                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1324                                 __FUNCTION__, NULL);
1325
1326         context->tag = tag;
1327
1328         return WIDGET_ERROR_NONE;
1329 }
1330
1331 EXPORT_API int widget_app_context_get_tag(widget_context_h context, void **tag)
1332 {
1333         if (!_is_widget_feature_enabled()) {
1334                 _E("not supported");
1335                 return WIDGET_ERROR_NOT_SUPPORTED;
1336         }
1337
1338         if (context == NULL || tag == NULL)
1339                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1340                                 __FUNCTION__, NULL);
1341
1342         *tag = context->tag;
1343
1344         return WIDGET_ERROR_NONE;
1345 }
1346
1347 EXPORT_API int widget_app_context_set_content_info(widget_context_h context,
1348                 bundle *content_info)
1349 {
1350         const char *class_id = NULL;
1351         int ret = 0;
1352
1353         if (!_is_widget_feature_enabled()) {
1354                 _E("not supported");
1355                 return WIDGET_ERROR_NOT_SUPPORTED;
1356         }
1357
1358         if (context == NULL || content_info == NULL)
1359                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1360                                 __FUNCTION__, NULL);
1361
1362         if (context->provider == NULL)
1363                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1364                                 __FUNCTION__, NULL);
1365
1366         class_id = context->provider->classid;
1367
1368         if (class_id == NULL)
1369                 return widget_app_error(WIDGET_ERROR_FAULT, __FUNCTION__, NULL);
1370
1371         ret = __send_update_status(class_id, context->id,
1372                         WIDGET_INSTANCE_EVENT_EXTRA_UPDATED, content_info, true);
1373
1374         if (ret < 0) {
1375                 _E("failed to send content info: %s of %s (%d)", context->id,
1376                                 class_id, ret);
1377                 return widget_app_error(WIDGET_ERROR_IO_ERROR, __FUNCTION__,
1378                                 NULL);
1379         }
1380
1381         return WIDGET_ERROR_NONE;
1382 }
1383
1384 EXPORT_API int widget_app_context_set_title(widget_context_h context,
1385                 const char *title)
1386 {
1387         if (!_is_widget_feature_enabled()) {
1388                 _E("not supported");
1389                 return WIDGET_ERROR_NOT_SUPPORTED;
1390         }
1391
1392         if (!context || !title)
1393                 return WIDGET_ERROR_INVALID_PARAMETER;
1394
1395         if (context->win)
1396                 elm_win_title_set(context->win, title);
1397
1398         return WIDGET_ERROR_NONE;
1399 }
1400