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