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