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