77b2889aad12b9e2d66e2f20150b98c285807582
[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 #include <stdbool.h>
20
21 #include <bundle.h>
22 #include <bundle_internal.h>
23 #include <aul.h>
24 #include <dlog.h>
25 #include <glib.h>
26 #include <glib-object.h>
27 #include <stdlib.h>
28 #include <app_control.h>
29 #include <app_control_internal.h>
30 #include <Elementary.h>
31 #include <widget_errno.h>
32 #include <widget_instance.h>
33 #include <widget_service.h>
34 #include <widget_service_internal.h>
35 #include <aul_app_com.h>
36 #include <Ecore_Wayland.h>
37 #include <system_info.h>
38 #include <vconf.h>
39 #include <vconf-internal-keys.h>
40 #include <screen_connector_provider.h>
41
42 #include "widget_app.h"
43 #include "widget-log.h"
44 #include "widget-private.h"
45 #include "widget_app_internal.h"
46
47 #ifdef LOG_TAG
48 #undef LOG_TAG
49 #endif
50
51 #define STR_MAX_BUF 128
52 #define LOG_TAG "CAPI_WIDGET_APPLICATION"
53 #define K_REASON    "__WC_K_REASON__"
54 #define APP_TYPE_WIDGET "widgetapp"
55 #define STATUS_FOREGROUND "fg"
56 #define STATUS_BACKGROUND "bg"
57
58 typedef enum _widget_obj_state_e {
59         WC_READY = 0,
60         WC_RUNNING = 1,
61         WC_PAUSED = 2,
62         WC_TERMINATED = 3
63 } widget_obj_state_e;
64
65 enum {
66         UPDATE_LOCAL = 0,
67         UPDATE_ALL = 1,
68 };
69
70 struct app_event_handler {
71         app_event_type_e type;
72         app_event_cb cb;
73         void *data;
74 };
75
76 struct app_event_info {
77         app_event_type_e type;
78         void *value;
79 };
80
81 typedef struct _widget_class widget_class_s;
82
83 #define WIDGET_APP_EVENT_MAX 5
84 static GList *handler_list[WIDGET_APP_EVENT_MAX] = {NULL, };
85
86 static int caller_pid;
87 static widget_app_lifecycle_callback_s *app_ops;
88 static void *app_user_data;
89 static char *appid;
90 static widget_class_h class_provider;
91 static int exit_called;
92 static char *package_id;
93 static bool fg_signal;
94 static bool is_permanent;
95
96 static void _widget_core_set_appcore_event_cb(void);
97 static void _widget_core_unset_appcore_event_cb(void);
98 static int __instance_update(widget_class_h handle, const char *id, int force, const char *content);
99
100 static void __free_handler_cb(gpointer data)
101 {
102         if (data)
103                 free(data);
104 }
105
106 static void __free_handler_list(void)
107 {
108         int i;
109
110         for (i = 0; i < WIDGET_APP_EVENT_MAX; i++) {
111                 g_list_free_full(handler_list[i], __free_handler_cb);
112                 handler_list[i] = NULL;
113         }
114 }
115
116 static inline bool _is_widget_feature_enabled(void)
117 {
118         static bool feature = false;
119         static bool retrieved = false;
120         int ret;
121
122         if (retrieved == true)
123                 return feature;
124
125         ret = system_info_get_platform_bool(
126                         "http://tizen.org/feature/shell.appwidget", &feature);
127         if (ret != SYSTEM_INFO_ERROR_NONE) {
128                 _E("failed to get system info"); /* LCOV_EXCL_LINE */
129                 return false; /* LCOV_EXCL_LINE */
130         }
131
132         retrieved = true;
133
134         return feature;
135 }
136
137 static gint __comp_by_id(gconstpointer a, gconstpointer b)
138 {
139         widget_context_s *wc = (widget_context_s *)a;
140
141         return strcmp(wc->id, (const char *)b);
142 }
143
144 static widget_context_s *__find_context_by_id(const char *id)
145 {
146         GList *ret;
147         GList *contexts = _widget_app_get_contexts();
148
149         if (id == NULL)
150                 return NULL;
151
152         ret = g_list_find_custom(contexts, id, __comp_by_id);
153         if (ret == NULL)
154                 return NULL;
155
156         return ret->data;
157 }
158
159 static gint __comp_by_state(gconstpointer a, gconstpointer b)
160 {
161         widget_context_s *wc = (widget_context_s *)a;
162
163         if (wc->state == (widget_obj_state_e)GPOINTER_TO_INT(b))
164                 return 0;
165
166         return -1;
167 }
168
169 static widget_context_s *__find_context_by_state(widget_obj_state_e state)
170 {
171         GList *ret;
172         GList *contexts = _widget_app_get_contexts();
173
174         ret = g_list_find_custom(contexts, GINT_TO_POINTER((int)state), __comp_by_state);
175         if (ret == NULL)
176                 return NULL;
177
178         return ret->data;
179 }
180
181 static gint __comp_by_win(gconstpointer a, gconstpointer b)
182 {
183         int win = GPOINTER_TO_INT(b);
184         widget_context_s *wc = (widget_context_s *)a;
185
186         return (wc && wc->win_id == win) ? 0 : -1;
187 }
188
189 static widget_context_s *__find_context_by_win(int win)
190 {
191         GList *contexts = _widget_app_get_contexts();
192         GList *ret = g_list_find_custom(contexts, GINT_TO_POINTER(win), __comp_by_win);
193
194         if (ret == NULL)
195                 return NULL;
196
197         return ret->data;
198 }
199
200 static int __send_lifecycle_event(const char *class_id, const char *instance_id,
201         int status)
202 {
203         bundle *b = bundle_create();
204         char pkgid[256] = {0, };
205         int ret;
206
207         if (b == NULL) {
208                 _E("out of memory"); /* LCOV_EXCL_LINE */
209                 return -1; /* LCOV_EXCL_LINE */
210         }
211
212         if (package_id == NULL) {
213                 ret = aul_app_get_pkgid_bypid(getpid(), pkgid, sizeof(pkgid));
214                 if (ret == 0)
215                         package_id = strdup(pkgid);
216         }
217
218         bundle_add_str(b, AUL_K_WIDGET_ID, class_id);
219         bundle_add_str(b, AUL_K_WIDGET_INSTANCE_ID, instance_id);
220         bundle_add_byte(b, AUL_K_WIDGET_STATUS, &status, sizeof(int));
221         if (package_id)
222                 bundle_add_str(b, AUL_K_PKGID, package_id);
223
224         _D("send lifecycle %s(%d)", instance_id, status);
225         ret = aul_app_com_send("widget.status", b);
226         if (ret < 0)
227                 _E("send lifecycle error:%d", ret); /* LCOV_EXCL_LINE */
228
229         bundle_free(b);
230
231         return ret;
232 }
233
234 static int __send_update_status(const char *class_id, const char *instance_id,
235         int status, int err, bundle *extra)
236 {
237         bundle *b;
238         int lifecycle = -1;
239         bundle_raw *raw = NULL;
240         int len;
241         char *viewer_endpoint = _widget_app_get_viewer_endpoint();
242         char err_str[256];
243
244         b = bundle_create();
245         if (!b) {
246                 _E("out of memory"); /* LCOV_EXCL_LINE */
247                 return -1; /* LCOV_EXCL_LINE */
248         }
249
250         if (err < 0) {
251                 snprintf(err_str, sizeof(err_str), "%d", err);
252                 bundle_add_str(b, AUL_K_WIDGET_ERROR_CODE, err_str);
253         }
254
255         bundle_add_str(b, AUL_K_WIDGET_ID, class_id);
256         bundle_add_str(b, AUL_K_WIDGET_INSTANCE_ID, instance_id);
257         bundle_add_byte(b, AUL_K_WIDGET_STATUS, &status, sizeof(int));
258
259         if (extra) {
260                 bundle_encode(extra, &raw, &len);
261                 bundle_add_str(b, WIDGET_K_CONTENT_INFO, (const char *)raw);
262                 aul_widget_instance_add(class_id, instance_id);
263         }
264
265         _D("send update %s(%d) to %s", instance_id, status, viewer_endpoint);
266         aul_app_com_send(viewer_endpoint, b);
267
268         switch (status) {
269         case WIDGET_INSTANCE_EVENT_CREATE:
270                 lifecycle = WIDGET_LIFE_CYCLE_EVENT_CREATE;
271                 break;
272         case WIDGET_INSTANCE_EVENT_DESTROY:
273                 lifecycle = WIDGET_LIFE_CYCLE_EVENT_DESTROY;
274                 break;
275         case WIDGET_INSTANCE_EVENT_PAUSE:
276                 lifecycle = WIDGET_LIFE_CYCLE_EVENT_PAUSE;
277                 break;
278         case WIDGET_INSTANCE_EVENT_RESUME:
279                 lifecycle = WIDGET_LIFE_CYCLE_EVENT_RESUME;
280                 break;
281         }
282
283         if (lifecycle > -1)
284                 __send_lifecycle_event(class_id, instance_id, lifecycle);
285
286         bundle_free(b);
287         if (raw)
288                 free(raw);
289
290         return 0;
291 }
292
293 static gboolean __timeout_cb(gpointer user_data)
294 {
295         widget_context_s *wc = user_data;
296
297         if (wc->state == WC_RUNNING) {
298                 _D("Periodic update!");
299                 __instance_update(wc->provider, wc->id, 0, NULL);
300         } else if (wc->state == WC_PAUSED ||
301                         wc->state == WC_READY) {
302                 wc->pending_update = true;
303                 if (wc->periodic_timer) {
304                         _D("Remove timer!");
305                         g_source_remove(wc->periodic_timer);
306                         wc->periodic_timer = 0;
307                 }
308         }
309
310         return G_SOURCE_CONTINUE;
311 }
312
313 static int __instance_resume(widget_class_h handle, const char *id, int send_update)
314 {
315         widget_context_s *wc = __find_context_by_id(id);
316         int ret;
317
318         if (!wc) {
319                 _E("context not found: %s", id); /* LCOV_EXCL_LINE */
320                 return -1; /* LCOV_EXCL_LINE */
321         }
322
323         if (wc->state == WC_RUNNING) {
324                 _D("%s is already in running state", id); /* LCOV_EXCL_LINE */
325                 return 0; /* LCOV_EXCL_LINE */
326         }
327
328         if (wc->state == WC_TERMINATED) {
329                 _D("%s is in terminated state", id); /* LCOV_EXCL_LINE */
330                 return 0; /* LCOV_EXCL_LINE */
331         }
332
333         wc->state = WC_RUNNING;
334         if (wc->pending_update) {
335                 _D("pending update!");
336                 wc->pending_update = false;
337                 __instance_update(wc->provider, wc->id, 0, wc->pending_content);
338
339                 if (wc->period > 0) {
340                         _D("Restart timer!");
341                         wc->periodic_timer = g_timeout_add_seconds(wc->period,
342                                         __timeout_cb, wc);
343                 }
344         }
345
346         if (handle->ops.resume)
347                 handle->ops.resume(wc, handle->user_data);
348
349         _D("%s is resumed", id);
350         if (send_update) {
351                 ret = __send_update_status(handle->classid, wc->id,
352                         WIDGET_INSTANCE_EVENT_RESUME, 0, NULL);
353                 if (!fg_signal) {
354                         _D("Send fg signal to resourceD");
355                         aul_send_app_status_change_signal(getpid(),
356                                         appid,
357                                         package_id,
358                                         STATUS_FOREGROUND,
359                                         APP_TYPE_WIDGET);
360                         fg_signal = true;
361                 }
362         } else {
363                 ret = 0;
364         }
365
366         return ret;
367 }
368
369 static int __instance_pause(widget_class_h handle, const char *id, int send_update)
370 {
371         widget_context_s *wc = __find_context_by_id(id);
372         int ret;
373
374         if (!wc) {
375                 _E("context not found: %s", id); /* LCOV_EXCL_LINE */
376                 return -1; /* LCOV_EXCL_LINE */
377         }
378
379         if (wc->state == WC_PAUSED) {
380                 _D("%s is already in paused state", id); /* LCOV_EXCL_LINE */
381                 return 0; /* LCOV_EXCL_LINE */
382         }
383
384         if (wc->state == WC_TERMINATED) {
385                 _D("%s is in terminated state", id); /* LCOV_EXCL_LINE */
386                 return 0; /* LCOV_EXCL_LINE */
387         }
388
389         if (handle->ops.pause)
390                 handle->ops.pause(wc, handle->user_data);
391
392         wc->state = WC_PAUSED;
393         _D("%s is paused", id);
394         if (send_update) {
395                 ret = __send_update_status(handle->classid, wc->id,
396                         WIDGET_INSTANCE_EVENT_PAUSE, 0, NULL);
397                 wc = __find_context_by_state(WC_RUNNING);
398                 if (!wc && fg_signal) {
399                         _D("Send bg signal to resourceD");
400                         aul_send_app_status_change_signal(getpid(),
401                                         appid,
402                                         package_id,
403                                         STATUS_BACKGROUND,
404                                         APP_TYPE_WIDGET);
405                         fg_signal = false;
406                 }
407         } else {
408                 ret = 0;
409         }
410
411         return ret;
412 }
413
414 static int __instance_resize(widget_class_h handle, const char *id, int w, int h)
415 {
416         widget_context_s *wc = __find_context_by_id(id);
417         int ret;
418
419         if (!wc) {
420                 _E("context not found: %s", id); /* LCOV_EXCL_LINE */
421                 return -1; /* LCOV_EXCL_LINE */
422         }
423
424         if (handle->ops.resize)
425                 handle->ops.resize(wc, w, h, handle->user_data);
426
427         _D("%s is resized to %dx%d", id, w, h);
428         ret = __send_update_status(handle->classid, wc->id,
429                 WIDGET_INSTANCE_EVENT_SIZE_CHANGED, 0, NULL);
430
431         return ret;
432 }
433
434 static void __update_pending_content(widget_context_s *wc, const char *content)
435 {
436         if (wc->pending_content) {
437                 free(wc->pending_content);
438                 wc->pending_content = NULL;
439         }
440
441         if (content) {
442                 wc->pending_content = strdup(content);
443                 if (wc->pending_content == NULL)
444                         _W("Out of memory");
445         }
446 }
447
448 /* LCOV_EXCL_START */
449 static int __instance_update_all(widget_class_h handle, int force, const char *content)
450 {
451         widget_context_s *wc;
452         int ret = 0;
453         bundle *b = NULL;
454         GList *context = _widget_app_get_contexts();
455
456         if (content)
457                 b = bundle_decode((const bundle_raw *)content, strlen(content));
458
459         if (handle->ops.update) {
460                 while (context) {
461                         wc = (widget_context_s *)context->data;
462                         context = context->next;
463                         if (wc->state != WC_RUNNING && !force) {
464                                 __update_pending_content(wc, content);
465                                 wc->pending_update = true;
466                                 continue;
467                         }
468
469                         handle->ops.update(wc, b, force, handle->user_data);
470                         ret = __send_update_status(handle->classid, wc->id,
471                                 WIDGET_INSTANCE_EVENT_UPDATE, 0, NULL);
472                         _D("updated:%s", wc->id);
473                 }
474         }
475
476         if (b)
477                 bundle_free(b);
478
479         return ret;
480 }
481 /* LCOV_EXCL_STOP */
482
483 /* LCOV_EXCL_START */
484 static int __instance_update(widget_class_h handle, const char *id, int force, const char *content)
485 {
486         widget_context_s *wc = __find_context_by_id(id);
487         int ret = 0;
488         bundle *b = NULL;
489         if (!wc) {
490                 _E("context not found: %s", id);
491                 return -1;
492         }
493
494         if (wc->state != WC_RUNNING && !force) {
495                 __update_pending_content(wc, content);
496                 wc->pending_update = true;
497                 return 0;
498         }
499
500         if (content)
501                 b = bundle_decode((const bundle_raw *)content, strlen(content));
502
503         if (handle->ops.update) {
504                 handle->ops.update(wc, b, force, handle->user_data);
505                 ret = __send_update_status(handle->classid, wc->id,
506                         WIDGET_INSTANCE_EVENT_UPDATE, 0, NULL);
507                 _D("updated:%s", id);
508         }
509
510         if (b)
511                 bundle_free(b);
512
513         return ret;
514 }
515 /* LCOV_EXCL_STOP */
516
517 static int __instance_create(widget_class_h handle, const char *id,
518                 const char *content, int w, int h, double period)
519 {
520         widget_context_s *wc = NULL;
521         int ret = 0;
522         int send_ret = 0;
523         bundle *content_info = NULL;
524
525         wc = (widget_context_s *)calloc(1, sizeof(widget_context_s));
526         if (!wc) {
527                 _E("Out of memory");
528                 return WIDGET_ERROR_OUT_OF_MEMORY;
529         }
530
531         wc->state = WC_READY;
532         wc->id = strdup(id);
533         wc->provider = handle;
534         wc->win = NULL;
535         wc->win_id = -1;
536
537         if (content) {
538                 wc->content = strdup(content);
539                 content_info = bundle_decode((const bundle_raw *)content, strlen(content));
540         }
541
542         _widget_app_add_context(wc);
543
544         ret = handle->ops.create(wc, content_info, w, h, handle->user_data);
545         if (ret < 0) {
546                 _W("Create callback resturns error(%d)", ret);
547                 send_ret = __send_update_status(handle->classid, wc->id,
548                                 WIDGET_INSTANCE_EVENT_CREATE_ABORTED, ret, NULL);
549                 if (send_ret < 0)
550                         _E("Fail to send abort status (%d)", send_ret);
551
552                 _widget_app_remove_context(wc);
553                 if (wc->id)
554                         free(wc->id);
555                 if (wc->content)
556                         free(wc->content);
557                 free(wc);
558
559                 if (_widget_app_get_contexts() == NULL && !exit_called)
560                         widget_app_exit();
561         } else {
562                 ret = __send_update_status(handle->classid, wc->id,
563                         WIDGET_INSTANCE_EVENT_CREATE, 0, NULL);
564
565                 if (content == NULL)
566                         content = "NULL";
567
568                 aul_widget_instance_add(handle->classid, id);
569
570                 if (period > 0) {
571                         wc->period = period;
572                         wc->periodic_timer = g_timeout_add_seconds(period,
573                                         __timeout_cb, wc);
574                 }
575         }
576
577         if (content_info)
578                 bundle_free(content_info);
579
580         return ret;
581 }
582
583 static int __instance_destroy(widget_class_h handle, const char *id,
584                 widget_app_destroy_type_e reason, int send_update)
585 {
586         widget_context_s *wc = __find_context_by_id(id);
587         int ret = 0;
588         int event = WIDGET_INSTANCE_EVENT_TERMINATE;
589         bundle *content_info;
590
591         if (!wc) {
592                 _E("could not find widget obj: %s, clear amd info", id);        /* LCOV_EXCL_LINE */
593                 aul_widget_instance_del(handle->classid, id);                   /* LCOV_EXCL_LINE */
594                 return WIDGET_ERROR_NONE;                                       /* LCOV_EXCL_LINE */
595         }
596
597         wc->state = WC_TERMINATED;
598         if (wc->content)
599                 content_info = bundle_decode((const bundle_raw *)wc->content, strlen(wc->content));
600         else
601                 content_info = bundle_create();
602
603         handle->ops.destroy(wc, reason, content_info,
604                         handle->user_data);
605
606         if (reason == WIDGET_APP_DESTROY_TYPE_PERMANENT) {
607                 is_permanent = true;
608                 event = WIDGET_INSTANCE_EVENT_DESTROY;
609                 aul_widget_instance_del(handle->classid, id);
610         } else {
611                 is_permanent = false;
612                 ret = __send_update_status(handle->classid, id,
613                                 WIDGET_INSTANCE_EVENT_EXTRA_UPDATED, 0, content_info);
614         }
615
616         if (content_info)
617                 bundle_free(content_info);
618
619         ret = __send_update_status(handle->classid, id, event, 0, NULL);
620
621         _widget_app_remove_context(wc);
622
623         if (wc->id)
624                 free(wc->id);
625
626         if (wc->content)
627                 free(wc->content);
628
629         if (wc->periodic_timer)
630                 g_source_remove(wc->periodic_timer);
631
632         if (wc->pending_content)
633                 free(wc->pending_content);
634
635         free(wc);
636
637         if (_widget_app_get_contexts() == NULL && !exit_called) /* all instance destroyed */
638                 widget_app_exit();
639
640         return ret;
641 }
642
643 static int __instance_change_period(const char *id, double period)
644 {
645         widget_context_s *wc = __find_context_by_id(id);
646
647         if (!wc) {
648                 _E("could not find widget obj: %s", id);
649                 return -1;
650         }
651
652         if (wc->periodic_timer) {
653                 _D("Remove timer!");
654                 g_source_remove(wc->periodic_timer);
655                 wc->periodic_timer = 0;
656         }
657
658         wc->period = period;
659         if (wc->period > 0) {
660                 _D("Restart timer!");
661                 wc->periodic_timer = g_timeout_add_seconds(wc->period,
662                                 __timeout_cb, wc);
663         }
664
665         return 0;
666 }
667
668 static widget_class_h __find_class_handler(const char *class_id,
669                 widget_class_h handle)
670 {
671         if (!class_id || !handle)
672                 return NULL;
673
674         widget_class_h head = handle;
675
676         while (head) {
677                 if (head->classid && strcmp(head->classid, class_id) == 0)
678                         return head;
679
680                 head = head->next;
681         }
682
683         return NULL;
684 }
685
686 /* LCOV_EXCL_START */
687 static void __resize_window(char *id, int w, int h)
688 {
689         widget_context_s *wc = __find_context_by_id(id);
690
691         if (!wc) {
692                 _E("can not find instance: %s", id);
693                 return;
694         }
695
696         if (wc->win)
697                 evas_object_resize(wc->win, w, h);
698         else
699                 _E("unable to find window of %d", wc->id);
700 }
701 /* LCOV_EXCL_STOP */
702
703 static void __control(bundle *b)
704 {
705         char *class_id = NULL;
706         char *id = NULL;
707         char *operation = NULL;
708         char *content = NULL;
709         char *w_str = NULL;
710         char *h_str = NULL;
711         int w = 0;
712         int h = 0;
713         char *remain = NULL;
714         int force;
715         char *force_str = NULL;
716         double *period = NULL;
717         double update_period = 0;
718         widget_class_h handle = NULL;
719         size_t size;
720         int ret;
721
722         bundle_get_str(b, WIDGET_K_CLASS, &class_id);
723         /* for previous version compatibility, use appid for default class id */
724         if (class_id == NULL)
725                 class_id = appid;
726
727         bundle_get_str(b, AUL_K_WIDGET_INSTANCE_ID, &id);
728         bundle_get_str(b, WIDGET_K_OPERATION, &operation);
729
730         handle = __find_class_handler(class_id, class_provider);
731         if (!handle) {
732                 _E("no handle provided: %s", class_id); /* LCOV_EXCL_LINE */
733                 goto error;
734         }
735
736         if (!operation) {
737                 _E("no operation provided");
738                 goto error;
739         }
740
741         bundle_get_str(b, WIDGET_K_FORCE, &force_str);
742
743         if (force_str && strcmp(force_str, "true") == 0)
744                 force = 1;
745         else
746                 force = 0;
747
748         bundle_get_str(b, WIDGET_K_CONTENT_INFO, &content);
749         bundle_get_str(b, WIDGET_K_WIDTH, &w_str);
750         bundle_get_str(b, WIDGET_K_HEIGHT, &h_str);
751         if (w_str)
752                 w = (int)g_ascii_strtoll(w_str, &remain, 10);
753
754         if (h_str)
755                 h = (int)g_ascii_strtoll(h_str, &remain, 10);
756
757         ret = bundle_get_byte(b, WIDGET_K_PERIOD, (void **)&period, &size);
758         if (ret == BUNDLE_ERROR_NONE)
759                 update_period = *period;
760
761         if (strcmp(operation, "create") == 0) {
762                 __instance_create(handle, id, content, w, h, update_period);
763         } else if (strcmp(operation, "resize") == 0) {
764                 __resize_window(id, w, h);
765                 __instance_resize(handle, id, w, h);
766         } else if (strcmp(operation, "update") == 0) {
767                 if (id)
768                         __instance_update(handle, id, force, content);
769                 else
770                         __instance_update_all(handle, force, content);
771
772         } else if (strcmp(operation, "destroy") == 0) {
773                 __instance_destroy(handle, id, WIDGET_APP_DESTROY_TYPE_PERMANENT, UPDATE_ALL);
774         } else if (strcmp(operation, "resume") == 0) {
775                 __instance_resume(handle, id, UPDATE_ALL);
776         } else if (strcmp(operation, "pause") == 0) {
777                 __instance_pause(handle, id, UPDATE_ALL);
778         } else if (strcmp(operation, "terminate") == 0) {
779                 __instance_destroy(handle, id, WIDGET_APP_DESTROY_TYPE_TEMPORARY, UPDATE_ALL);
780         } else if (strcmp(operation, "period") == 0) {
781                 __instance_change_period(id, update_period);
782         }
783
784         return;
785 error:
786         LOGD("error on control");
787         return;
788 }
789
790 static void __pause_all(int send_update)
791 {
792         GList *contexts = _widget_app_get_contexts();
793         GList *iter = g_list_first(contexts);
794
795         while (iter != NULL) {
796                 widget_context_s *cxt = (widget_context_s *)iter->data;
797
798                 switch (cxt->state) {
799                 case WC_READY:
800                         __instance_resume(cxt->provider, cxt->id, send_update);
801                         __instance_pause(cxt->provider, cxt->id, send_update);
802                         break;
803                 case WC_RUNNING:
804                         __instance_pause(cxt->provider, cxt->id, send_update);
805                         break;
806                 }
807                 LOGD("pause %s", cxt->id);
808                 iter = g_list_next(iter);
809         }
810 }
811
812 /* LCOV_EXCL_START */
813 static void __resume_all(int send_update)
814 {
815         GList *contexts = _widget_app_get_contexts();
816         GList *iter = g_list_first(contexts);
817
818         while (iter != NULL) {
819                 widget_context_s *cxt = (widget_context_s *)iter->data;
820
821                 switch (cxt->state) {
822                 case WC_READY:
823                         __instance_resume(cxt->provider, cxt->id, send_update);
824                         break;
825                 case WC_PAUSED:
826                         __instance_resume(cxt->provider, cxt->id, send_update);
827                         break;
828                 }
829                 iter = g_list_next(iter);
830         }
831 }
832 /* LCOV_EXCL_STOP */
833
834 static void __destroy_all(int reason, int send_update)
835 {
836         GList *contexts = _widget_app_get_contexts();
837         GList *iter = g_list_first(contexts);
838
839         __pause_all(send_update);
840         while (iter != NULL) {
841                 widget_context_s *cxt = (widget_context_s *)iter->data;
842                 iter = g_list_next(iter);
843                 switch (cxt->state) {
844                 case WC_PAUSED:
845                         LOGD("destroy %d : %s", cxt->state, cxt->id);
846                         __instance_destroy(cxt->provider, cxt->id, reason, send_update);
847                         break;
848                 }
849         }
850 }
851
852 static Eina_Bool __visibility_cb(void *data, int type, void *event)
853 {
854         Ecore_Wl_Event_Window_Visibility_Change *ev = event;
855         widget_context_s *cxt = __find_context_by_win(ev->win);
856
857         LOGD("visiblity change: %d %d", (unsigned int)ev->win,  (unsigned int)ev->fully_obscured);
858
859         if (!cxt) {
860                 LOGE("unknown window error: %d", ev->win);
861                 return ECORE_CALLBACK_RENEW;
862         }
863
864         if ((cxt->state == WC_READY || cxt->state == WC_PAUSED)
865                         && ev->fully_obscured == 0) {
866                 __instance_resume(cxt->provider, cxt->id, UPDATE_ALL);
867         } else if (cxt->state == WC_RUNNING && ev->fully_obscured == 1) {
868                 __instance_pause(cxt->provider, cxt->id, UPDATE_ALL);
869         } else {
870                 LOGD("cxt:%s state:%d obscured:%d", cxt->id, cxt->state, ev->fully_obscured);
871         }
872
873         return ECORE_CALLBACK_RENEW;
874 }
875
876 /* LCOV_EXCL_START */
877 static Eina_Bool __lower_cb(void *data, int type, void *event)
878 {
879         LOGD("lower");
880         return ECORE_CALLBACK_RENEW;
881 }
882 /* LCOV_EXCL_STOP */
883
884 static Eina_Bool __configure_cb(void *data, int type, void *event)
885 {
886         Ecore_Wl_Event_Window_Configure *ev = event;
887         widget_context_s *cxt = __find_context_by_win(ev->win);
888
889         LOGD("configure: %d %d", ev->w, ev->h);
890
891         if (!cxt) {
892                 LOGE("unknown window error: %d", ev->win); /* LCOV_EXCL_LINE */
893                 return ECORE_CALLBACK_RENEW; /* LCOV_EXCL_LINE */
894         }
895
896         if (cxt->state == WC_PAUSED || cxt->state == WC_RUNNING)
897                 __instance_resize(cxt->provider, cxt->id, ev->w, ev->h);
898         LOGD("cxt:%s resized to %dx%d", cxt->id, ev->w, ev->h);
899
900         return ECORE_CALLBACK_RENEW;
901 }
902
903 static void __add_climsg()
904 {
905         ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_VISIBILITY_CHANGE, __visibility_cb, NULL);
906         ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_LOWER, __lower_cb, NULL);
907         ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_CONFIGURE, __configure_cb, NULL);
908 }
909
910 static void __get_content(bundle *b)
911 {
912         char *instance_id = NULL;
913         widget_context_s *cxt = NULL;
914
915         bundle_get_str(b, AUL_K_WIDGET_INSTANCE_ID, &instance_id);
916         if (!instance_id)
917                 return;
918
919         cxt = __find_context_by_id(instance_id);
920         if (!cxt) {
921                 _E("can not find instance id:%s", instance_id);
922                 return;
923         }
924
925         if (cxt->content) {
926                 bundle_add_str(b, AUL_K_WIDGET_CONTENT_INFO, cxt->content);
927                 _D("content info of %s found", cxt->id);
928         } else {
929                 bundle_add_str(b, AUL_K_WIDGET_CONTENT_INFO, "");
930                 _D("empty content info added");
931         }
932 }
933
934 static int __aul_handler(aul_type type, bundle *b, void *data)
935 {
936         char *caller = NULL;
937         char *remain = NULL;
938
939         switch (type) {
940         case AUL_START:
941                 if (b) {
942                         bundle_get_str(b, WIDGET_K_CALLER, &caller);
943                         if (caller) {
944                                 caller_pid = g_ascii_strtoll(caller, &remain,
945                                                 10);
946                         } else {
947                                 /* using caller appid and query pid using caller appid? */
948                                 _E("no caller pid");
949                         }
950                 }
951
952                 __control(b);
953                 break;
954         case AUL_RESUME:
955                 __resume_all(UPDATE_ALL);
956                 break;
957         case AUL_TERMINATE:
958                 widget_app_exit();
959                 break;
960         case AUL_WIDGET_CONTENT:
961                 __get_content(b);
962                 break;
963         default:
964                 break;
965         }
966
967         return 0;
968 }
969
970 static char *__get_domain_name(char *appid)
971 {
972         char *name_token;
973
974         if (appid == NULL) {
975                 _E("appid is NULL"); /* LCOV_EXCL_LINE */
976                 return NULL; /* LCOV_EXCL_LINE */
977         }
978
979         name_token = strrchr(appid, '.');
980
981         if (name_token == NULL) {
982                 _E("appid is invalid"); /* LCOV_EXCL_LINE */
983                 return appid; /* LCOV_EXCL_LINE */
984         }
985
986         name_token++;
987
988         return name_token;
989 }
990
991 /* LCOV_EXCL_START */
992 static void __on_poweroff(keynode_t *key, void *data)
993 {
994         int val;
995
996         val = vconf_keynode_get_int(key);
997         switch (val) {
998         case VCONFKEY_SYSMAN_POWER_OFF_DIRECT:
999         case VCONFKEY_SYSMAN_POWER_OFF_RESTART:
1000                 _I("power off changed: %d", val);
1001                 widget_app_exit();
1002                 break;
1003         case VCONFKEY_SYSMAN_POWER_OFF_NONE:
1004         case VCONFKEY_SYSMAN_POWER_OFF_POPUP:
1005         default:
1006                 /* DO NOTHING */
1007                 break;
1008         }
1009 }
1010 /* LCOV_EXCL_STOP */
1011
1012 extern int _set_i18n(const char *name);
1013 extern void aul_finalize();
1014
1015 static int __before_loop(int argc, char **argv)
1016 {
1017         int r;
1018         bundle *kb = NULL;
1019         char *name;
1020         char *viewer_endpoint = NULL;
1021
1022 #if !(GLIB_CHECK_VERSION(2, 36, 0))
1023         g_type_init();
1024 #endif
1025
1026         kb = bundle_import_from_argv(argc, argv);
1027         if (kb) {
1028                 bundle_get_str(kb, WIDGET_K_ENDPOINT, &viewer_endpoint);
1029                 if (viewer_endpoint) {
1030                         _E("viewer endpoint :%s", viewer_endpoint);
1031                         _widget_app_set_viewer_endpoint(viewer_endpoint);
1032                 } else {
1033                         _E("endpoint is missing");
1034                 }
1035
1036                 bundle_free(kb);
1037                 kb = NULL;
1038         } else {
1039                 _E("failed to get launch argv"); /* LCOV_EXCL_LINE */
1040         }
1041
1042         screen_connector_provider_init();
1043         elm_init(argc, argv);
1044
1045         r = aul_launch_init(__aul_handler, NULL);
1046         if (r < 0) {
1047                 /* LCOV_EXCL_START */
1048                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1049                                 __FUNCTION__,
1050                                 "Fail to call the aul_launch_init");
1051                 /* LCOV_EXCL_STOP */
1052         }
1053
1054         r = aul_launch_argv_handler(argc, argv);
1055         if (r < 0) {
1056                 /* LCOV_EXCL_START */
1057                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1058                                 __FUNCTION__,
1059                                 "Fail to call the aul_launch_argv_handler");
1060                 /* LCOV_EXCL_STOP */
1061         }
1062
1063         r = app_get_id(&appid);
1064         if (r != APP_ERROR_NONE)
1065                 return r;
1066
1067         name = __get_domain_name(appid);
1068
1069         if (name == NULL) {
1070                 /* LCOV_EXCL_START */
1071                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1072                                 __FUNCTION__,
1073                                 "Fail to call __get_domain_name");
1074                 /* LCOV_EXCL_STOP */
1075         }
1076
1077         r = _set_i18n(name);
1078
1079         if (r < 0) {
1080                 /* LCOV_EXCL_START */
1081                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1082                                 __FUNCTION__,
1083                                 "Fail to call _set_i18n");
1084                 /* LCOV_EXCL_STOP */
1085         }
1086
1087         __add_climsg();
1088
1089         _widget_core_set_appcore_event_cb();
1090
1091         class_provider = app_ops->create(app_user_data);
1092         if (class_provider == NULL) {
1093                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1094                                 __FUNCTION__, "widget_class is NULL");
1095         }
1096
1097         vconf_notify_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, __on_poweroff, NULL);
1098
1099         return WIDGET_ERROR_NONE;
1100 }
1101
1102 static void __after_loop()
1103 {
1104         exit_called = 1;
1105         vconf_ignore_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, __on_poweroff);
1106
1107         __pause_all(UPDATE_LOCAL);
1108         __destroy_all(WIDGET_APP_DESTROY_TYPE_TEMPORARY, UPDATE_ALL);
1109
1110         if (app_ops->terminate)
1111                 app_ops->terminate(app_user_data);
1112         aul_finalize();
1113
1114         screen_connector_provider_fini();
1115
1116         _widget_app_free_viewer_endpoint();
1117         _widget_core_unset_appcore_event_cb();
1118         __free_handler_list();
1119
1120         if (package_id) {
1121                 free(package_id);
1122                 package_id = NULL;
1123         }
1124
1125         if (appid) {
1126                 free(appid);
1127                 appid = NULL;
1128         }
1129         elm_shutdown();
1130
1131         /* Check loader case */
1132         if (getenv("AUL_LOADER_INIT")) {
1133                 unsetenv("AUL_LOADER_INIT");
1134                 elm_shutdown();
1135         }
1136
1137 }
1138
1139 static void __on_low_memory(keynode_t *key, void *data)
1140 {
1141         int val;
1142
1143         val = vconf_keynode_get_int(key);
1144         if (val == VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING) {
1145                 app_event_handler_h handler;
1146                 struct app_event_info event;
1147
1148                 _I("widget_app_low_memory");
1149
1150                 event.type = APP_EVENT_LOW_MEMORY;
1151                 event.value = (void *)&val;
1152
1153                 GList *iter = g_list_first(handler_list[APP_EVENT_LOW_MEMORY]);
1154
1155                 while (iter) {
1156                         handler = (app_event_handler_h) iter->data;
1157                         handler->cb(&event, handler->data);
1158                         iter = g_list_next(iter);
1159                 }
1160         }
1161 }
1162
1163 static void __on_low_battery(keynode_t *key, void *data)
1164 {
1165         int val;
1166
1167         val = vconf_keynode_get_int(key);
1168         if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW) {
1169                 app_event_handler_h handler;
1170                 struct app_event_info event;
1171
1172                 _I("widget_app_low_battery");
1173
1174                 event.type = APP_EVENT_LOW_BATTERY;
1175                 event.value = (void *)&val;
1176
1177                 GList *iter = g_list_first(handler_list[APP_EVENT_LOW_BATTERY]);
1178
1179                 while (iter) {
1180                         handler = (app_event_handler_h) iter->data;
1181                         handler->cb(&event, handler->data);
1182                         iter = g_list_next(iter);
1183                 }
1184         }
1185 }
1186
1187 static void __on_lang_changed(keynode_t *key, void *data)
1188 {
1189         char *val;
1190
1191         _update_lang();
1192         val = vconf_keynode_get_str(key);
1193
1194         app_event_handler_h handler;
1195         struct app_event_info event;
1196
1197         _I("widget_app_lang_changed");
1198
1199         event.type = APP_EVENT_LANGUAGE_CHANGED;
1200         event.value = (void *)val;
1201
1202         GList *iter = g_list_first(handler_list[APP_EVENT_LANGUAGE_CHANGED]);
1203
1204         while (iter) {
1205                 handler = (app_event_handler_h) iter->data;
1206                 handler->cb(&event, handler->data);
1207                 iter = g_list_next(iter);
1208         }
1209 }
1210
1211 static void __on_region_changed(keynode_t *key, void *data)
1212 {
1213         char *val;
1214
1215         _update_region();
1216         val = vconf_keynode_get_str(key);
1217
1218         app_event_handler_h handler;
1219         struct app_event_info event;
1220
1221         _I("widget_app_region_changed");
1222
1223         event.type = APP_EVENT_REGION_FORMAT_CHANGED;
1224         event.value = (void *)val;
1225
1226         GList *iter = g_list_first(handler_list[APP_EVENT_REGION_FORMAT_CHANGED]);
1227
1228         while (iter) {
1229                 handler = (app_event_handler_h) iter->data;
1230                 handler->cb(&event, handler->data);
1231                 iter = g_list_next(iter);
1232         }
1233 }
1234
1235 static void __register_event(int event_type)
1236 {
1237         switch (event_type) {
1238         case APP_EVENT_LOW_MEMORY:
1239                 vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __on_low_memory, NULL);
1240                 break;
1241
1242         case APP_EVENT_LOW_BATTERY:
1243                 vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __on_low_battery, NULL);
1244                 break;
1245
1246         case APP_EVENT_LANGUAGE_CHANGED:
1247                 vconf_notify_key_changed(VCONFKEY_LANGSET, __on_lang_changed, NULL);
1248                 break;
1249
1250         case APP_EVENT_REGION_FORMAT_CHANGED:
1251                 vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, __on_region_changed, NULL);
1252                 break;
1253         }
1254 }
1255
1256 static void __unregister_event(int event_type)
1257 {
1258         switch (event_type) {
1259         case APP_EVENT_LOW_MEMORY:
1260                 vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __on_low_memory);
1261                 break;
1262
1263         case APP_EVENT_LOW_BATTERY:
1264                 vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __on_low_battery);
1265                 break;
1266
1267         case APP_EVENT_LANGUAGE_CHANGED:
1268                 vconf_ignore_key_changed(VCONFKEY_LANGSET, __on_lang_changed);
1269                 break;
1270
1271         case APP_EVENT_REGION_FORMAT_CHANGED:
1272                 vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, __on_region_changed);
1273                 break;
1274         }
1275 }
1276
1277 static void _widget_core_set_appcore_event_cb(void)
1278 {
1279         __register_event(APP_EVENT_LANGUAGE_CHANGED);
1280         __register_event(APP_EVENT_REGION_FORMAT_CHANGED);
1281 }
1282
1283 static void _widget_core_unset_appcore_event_cb(void)
1284 {
1285         __unregister_event(APP_EVENT_LANGUAGE_CHANGED);
1286         __unregister_event(APP_EVENT_REGION_FORMAT_CHANGED);
1287 }
1288
1289 EXPORT_API int widget_app_main(int argc, char **argv,
1290                 widget_app_lifecycle_callback_s *callback, void *user_data)
1291 {
1292         int r;
1293
1294         if (!_is_widget_feature_enabled()) {
1295                 _E("not supported"); /* LCOV_EXCL_LINE */
1296                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1297         }
1298
1299         if (argc <= 0 || argv == NULL || callback == NULL)
1300                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1301                                 __FUNCTION__, NULL);
1302
1303         if (callback->create == NULL)
1304                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1305                                 __FUNCTION__,
1306                                 "widget_app_create_cb() callback must be "
1307                                 "registered");
1308         app_ops = callback;
1309         app_user_data = user_data;
1310         r = __before_loop(argc, argv);
1311         if (r < 0) {
1312                 if (appid) {
1313                         free(appid);
1314                         appid = NULL;
1315                 }
1316                 return r;
1317         }
1318
1319         elm_run();
1320         aul_status_update(STATUS_DYING);
1321         __after_loop();
1322
1323         return WIDGET_ERROR_NONE;
1324 }
1325
1326 EXPORT_API int widget_app_exit(void)
1327 {
1328         if (!_is_widget_feature_enabled()) {
1329                 _E("not supported"); /* LCOV_EXCL_LINE */
1330                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1331         }
1332
1333         if (exit_called)
1334                 return WIDGET_ERROR_NONE;
1335
1336         exit_called = 1;
1337
1338         elm_exit();
1339         if (!_widget_app_get_contexts() && is_permanent)
1340                 aul_notify_exit();
1341
1342         return WIDGET_ERROR_NONE;
1343 }
1344
1345 /* LCOV_EXCL_START */
1346 static gboolean __finish_event_cb(gpointer user_data)
1347 {
1348         if (user_data == NULL)
1349                 return FALSE;
1350
1351         widget_context_s *wc = (widget_context_s *)user_data;
1352
1353         switch (wc->state) {
1354         case WC_READY:
1355                 __instance_resume(wc->provider, wc->id, UPDATE_LOCAL);
1356         case WC_RUNNING:
1357                 __instance_pause(wc->provider, wc->id, UPDATE_LOCAL);
1358         case WC_PAUSED:
1359                 __instance_destroy(wc->provider, wc->id,
1360                                 WIDGET_DESTROY_TYPE_TEMPORARY, UPDATE_ALL);
1361                 break;
1362         default:
1363                 break;
1364         }
1365
1366         return FALSE;
1367 }
1368 /* LCOV_EXCL_STOP */
1369
1370 EXPORT_API int widget_app_terminate_context(widget_context_h context)
1371 {
1372         if (!_is_widget_feature_enabled()) {
1373                 _E("not supported"); /* LCOV_EXCL_LINE */
1374                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1375         }
1376
1377         if (context == NULL)
1378                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1379                                 __FUNCTION__, NULL);
1380
1381         g_idle_add(__finish_event_cb, context);
1382         return WIDGET_ERROR_NONE;
1383 }
1384
1385 EXPORT_API int widget_app_foreach_context(widget_context_cb cb, void *data)
1386 {
1387         GList *contexts = _widget_app_get_contexts();
1388         GList *list;
1389         widget_context_s *wc;
1390
1391         if (!_is_widget_feature_enabled()) {
1392                 _E("not supported"); /* LCOV_EXCL_LINE */
1393                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1394         }
1395
1396         if (!cb)
1397                 return WIDGET_ERROR_INVALID_PARAMETER;
1398
1399         list = g_list_first(contexts);
1400
1401         while (list) {
1402                 wc = (widget_context_s *)list->data;
1403                 if (wc) {
1404                         if (!cb(wc, data))
1405                                 break;
1406                 }
1407                 list = list->next;
1408         }
1409
1410         return WIDGET_ERROR_NONE;
1411 }
1412
1413 EXPORT_API int widget_app_add_event_handler(app_event_handler_h *event_handler,
1414                                         app_event_type_e event_type, app_event_cb callback,
1415                                         void *user_data)
1416 {
1417         int r;
1418         bool feature;
1419
1420         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
1421         if (r < 0)
1422                 return WIDGET_ERROR_FAULT;
1423
1424         if (!feature)
1425                 return WIDGET_ERROR_NOT_SUPPORTED;
1426
1427         app_event_handler_h handler;
1428
1429         if (event_handler == NULL || callback == NULL)
1430                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
1431
1432         if (event_type < APP_EVENT_LOW_MEMORY
1433             || event_type > APP_EVENT_REGION_FORMAT_CHANGED)
1434                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
1435
1436         if (event_type == APP_EVENT_DEVICE_ORIENTATION_CHANGED)
1437                 return widget_app_error(WIDGET_ERROR_NOT_SUPPORTED, __FUNCTION__, NULL);
1438
1439         GList *iter = g_list_first(handler_list[event_type]);
1440
1441         while (iter) {
1442                 handler = (app_event_handler_h) iter->data;
1443
1444                 if (handler->cb == callback)
1445                         return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
1446
1447                 iter = g_list_next(iter);
1448         }
1449
1450         handler = calloc(1, sizeof(struct app_event_handler));
1451         if (!handler)
1452                 return widget_app_error(WIDGET_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL); /* LCOV_EXCL_LINE */
1453
1454         if (g_list_length(handler_list[event_type]) == 0)
1455                 __register_event(event_type);
1456
1457         handler->type = event_type;
1458         handler->cb = callback;
1459         handler->data = user_data;
1460         handler_list[event_type] = g_list_append(handler_list[event_type], handler);
1461
1462         *event_handler = handler;
1463
1464         return WIDGET_ERROR_NONE;
1465 }
1466
1467 EXPORT_API int widget_app_remove_event_handler(app_event_handler_h
1468                                                 event_handler)
1469 {
1470         int r;
1471         bool feature;
1472
1473         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
1474         if (r < 0)
1475                 return WIDGET_ERROR_FAULT;
1476
1477         if (!feature)
1478                 return WIDGET_ERROR_NOT_SUPPORTED;
1479
1480         app_event_type_e type;
1481
1482         if (event_handler == NULL)
1483                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
1484
1485         type = event_handler->type;
1486         if (type < APP_EVENT_LOW_MEMORY || type > APP_EVENT_REGION_FORMAT_CHANGED)
1487                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
1488
1489         handler_list[type] = g_list_remove(handler_list[type], event_handler);
1490         free(event_handler);
1491
1492         if (g_list_length(handler_list[type]) == 0)
1493                 __unregister_event(type);
1494
1495         return WIDGET_ERROR_NONE;
1496 }
1497
1498 EXPORT_API const char *widget_app_get_id(widget_context_h context)
1499 {
1500         if (!_is_widget_feature_enabled()) {
1501                 _E("not supported"); /* LCOV_EXCL_LINE */
1502                 set_last_result(WIDGET_ERROR_NOT_SUPPORTED); /* LCOV_EXCL_LINE */
1503                 return NULL; /* LCOV_EXCL_LINE */
1504         }
1505
1506         if (!context) {
1507                 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
1508                 return NULL;
1509         }
1510
1511         set_last_result(WIDGET_ERROR_NONE);
1512         return context->id;
1513 }
1514
1515 static void _win_del_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
1516 {
1517        /* Remove data used in accessibility */
1518         char *plug_id;
1519         plug_id = evas_object_data_del(obj, "___PLUGID");
1520         free(plug_id);
1521 }
1522
1523 EXPORT_API int widget_app_get_elm_win(widget_context_h context,
1524                                         Evas_Object **win)
1525 {
1526         widget_context_s *cxt = (widget_context_s *)context;
1527         Evas_Object *ret_win;
1528         Ecore_Wl_Window *wl_win;
1529         struct wl_surface *surface;
1530         char buffer[256];
1531         int rots[3] = {0};
1532
1533         if (!_is_widget_feature_enabled()) {
1534                 _E("not supported"); /* LCOV_EXCL_LINE */
1535                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1536         }
1537
1538         if (context == NULL || win == NULL)
1539                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1540                                 __FUNCTION__, NULL);
1541
1542         ret_win = elm_win_add(NULL, cxt->id, ELM_WIN_BASIC);
1543         if (ret_win == NULL) {
1544                 _E("failed to create window"); /* LCOV_EXCL_LINE */
1545                 goto fault; /* LCOV_EXCL_LINE */
1546         }
1547
1548         elm_win_wm_rotation_preferred_rotation_set(ret_win, -1);
1549         elm_win_wm_rotation_available_rotations_set(ret_win, rots, 1);
1550
1551         wl_win = elm_win_wl_window_get(ret_win);
1552         if (wl_win == NULL) {
1553                 _E("failed to get wayland window"); /* LCOV_EXCL_LINE */
1554                 goto fault;
1555         }
1556
1557         surface = ecore_wl_window_surface_get(wl_win);
1558         if (surface == NULL) {
1559                 _E("failed to get surface"); /* LCOV_EXCL_LINE */
1560                 goto fault; /* LCOV_EXCL_LINE */
1561         }
1562         screen_connector_provider_remote_enable(cxt->id, surface);
1563
1564         ecore_wl_window_class_name_set(wl_win, cxt->id);
1565         elm_win_aux_hint_add(ret_win, "wm.policy.win.user.geometry", "1");
1566
1567         *win = ret_win;
1568         cxt->win = ret_win;
1569         cxt->win_id = ecore_wl_window_id_get(wl_win);
1570
1571         /* Set data to use in accessibility */
1572         snprintf(buffer, sizeof(buffer), "%s:%d", cxt->id, getpid());
1573         evas_object_data_set(ret_win, "___PLUGID", strdup(buffer));
1574         evas_object_event_callback_add(ret_win, EVAS_CALLBACK_DEL, _win_del_cb, NULL);
1575
1576         _D("window created: %d", cxt->win_id);
1577
1578         return WIDGET_ERROR_NONE;
1579
1580 fault:
1581         if (ret_win)    /* LCOV_EXCL_LINE */
1582                 evas_object_del(ret_win); /* LCOV_EXCL_LINE */
1583
1584         return WIDGET_ERROR_FAULT; /* LCOV_EXCL_LINE */
1585
1586 }
1587
1588 widget_class_h _widget_class_create(widget_class_s *prev, const char *class_id,
1589                 widget_instance_lifecycle_callback_s callback, void *user_data)
1590 {
1591         widget_class_s *wc;
1592
1593         if (!_is_widget_feature_enabled()) {
1594                 _E("not supported"); /* LCOV_EXCL_LINE */
1595                 set_last_result(WIDGET_ERROR_NOT_SUPPORTED); /* LCOV_EXCL_LINE */
1596                 return NULL;
1597         }
1598
1599         if (class_id == NULL) {
1600                 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
1601                 return NULL;
1602         }
1603
1604         wc = (widget_class_s *)calloc(1, sizeof(widget_class_s));
1605         if (wc == NULL) {
1606                 _E("failed to calloc : %s", __FUNCTION__); /* LCOV_EXCL_LINE */
1607                 set_last_result(WIDGET_ERROR_OUT_OF_MEMORY); /* LCOV_EXCL_LINE */
1608                 return NULL; /* LCOV_EXCL_LINE */
1609         }
1610
1611         wc->classid = strdup(class_id);
1612         wc->user_data = user_data;
1613         wc->ops = callback;
1614         wc->next = prev;
1615         wc->prev = NULL;
1616
1617         set_last_result(WIDGET_ERROR_NONE);
1618
1619         if (prev)
1620                 prev->prev = wc;
1621
1622         return wc;
1623 }
1624
1625 EXPORT_API widget_class_h widget_app_class_add(widget_class_h widget_class,
1626                 const char *class_id,
1627                 widget_instance_lifecycle_callback_s callback, void *user_data)
1628 {
1629         return _widget_class_create(widget_class, class_id, callback,
1630                         user_data);
1631 }
1632
1633 EXPORT_API widget_class_h widget_app_class_create(
1634                 widget_instance_lifecycle_callback_s callback, void *user_data)
1635 {
1636         return _widget_class_create(class_provider, appid, callback, user_data);
1637 }
1638
1639 EXPORT_API int widget_app_context_set_tag(widget_context_h context, void *tag)
1640 {
1641         if (!_is_widget_feature_enabled()) {
1642                 _E("not supported"); /* LCOV_EXCL_LINE */
1643                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1644         }
1645
1646         if (context == NULL)
1647                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1648                                 __FUNCTION__, NULL);
1649
1650         context->tag = tag;
1651
1652         return WIDGET_ERROR_NONE;
1653 }
1654
1655 EXPORT_API int widget_app_context_get_tag(widget_context_h context, void **tag)
1656 {
1657         if (!_is_widget_feature_enabled()) {
1658                 _E("not supported"); /* LCOV_EXCL_LINE */
1659                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1660         }
1661
1662         if (context == NULL || tag == NULL)
1663                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1664                                 __FUNCTION__, NULL);
1665
1666         *tag = context->tag;
1667
1668         return WIDGET_ERROR_NONE;
1669 }
1670
1671 EXPORT_API int widget_app_context_set_content_info(widget_context_h context,
1672                 bundle *content_info)
1673 {
1674         const char *class_id = NULL;
1675         int ret = 0;
1676         bundle_raw *raw = NULL;
1677         int len;
1678
1679         if (!_is_widget_feature_enabled()) {
1680                 _E("not supported"); /* LCOV_EXCL_LINE */
1681                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1682         }
1683
1684         if (context == NULL || content_info == NULL)
1685                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1686                                 __FUNCTION__, NULL);
1687
1688         if (context->provider == NULL)
1689                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1690                                 __FUNCTION__, NULL);
1691
1692         class_id = context->provider->classid;
1693         if (class_id == NULL)
1694                 return widget_app_error(WIDGET_ERROR_FAULT, __FUNCTION__, NULL);
1695
1696         ret = __send_update_status(class_id, context->id,
1697                         WIDGET_INSTANCE_EVENT_EXTRA_UPDATED, 0, content_info);
1698
1699         if (context->content)
1700                 free(context->content);
1701
1702         bundle_encode(content_info, &raw, &len);
1703         if (raw)
1704                 context->content = strdup((const char *)raw);
1705         else
1706                 context->content = NULL;
1707
1708         free(raw);
1709         if (ret < 0) {
1710                 /* LCOV_EXCL_START */
1711                 _E("failed to send content info: %s of %s (%d)", context->id,
1712                                 class_id, ret);
1713                 return widget_app_error(WIDGET_ERROR_IO_ERROR, __FUNCTION__,
1714                                 NULL);
1715                 /* LCOV_EXCL_STOP */
1716         }
1717
1718         return WIDGET_ERROR_NONE;
1719 }
1720
1721 EXPORT_API int widget_app_context_set_title(widget_context_h context,
1722                 const char *title)
1723 {
1724         if (!_is_widget_feature_enabled()) {
1725                 _E("not supported"); /* LCOV_EXCL_LINE */
1726                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1727         }
1728
1729         if (!context || !title)
1730                 return WIDGET_ERROR_INVALID_PARAMETER;
1731
1732         if (context->win)
1733                 elm_win_title_set(context->win, title);
1734
1735         return WIDGET_ERROR_NONE;
1736 }