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