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