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