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