sync with tizen_2.4
[platform/core/appfw/appcore-widget.git] / src / widget_app.c
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17
18 #include <stdlib.h>
19
20 #include <bundle.h>
21 #include <aul.h>
22 #include <dlog.h>
23 #include <glib.h>
24 #include <glib-object.h>
25 #include <app_control.h>
26 #include <app_control_internal.h>
27 #include <widget.h>
28 #include <widget_service.h>
29 #include <widget_service_internal.h>
30 #include <widget_provider_app.h>
31 #include <widget_provider_app_internal.h>
32 #include <Elementary.h>
33 #include <vconf.h>
34 #include <widget_errno.h>
35 #include <system_info.h>
36
37 #include "widget_app.h"
38 #include "widget-log.h"
39 #include "widget-private.h"
40 #include "widget_app_internal.h"
41
42 #ifdef LOG_TAG
43 #undef LOG_TAG
44 #endif
45
46 #define STR_MAX_BUF 128
47 #define LOG_TAG "CAPI_WIDGET_APPLICATION"
48 #define K_REASON    "__WC_K_REASON__"
49
50 #define ELM_WIN_TIZEN_WIDGET -1
51 /* TODO
52  * This definition is intended to prevent the build break.
53  * This should be removed after adding ELM_WIN_TIZEN_WIDGET in Elm_Win_Type.
54  */
55
56 #define WIDGET_APP_EVENT_MAX 5
57 static GList *handler_list[WIDGET_APP_EVENT_MAX] = {NULL, };
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 struct app_event_handler {
67         app_event_type_e type;
68         app_event_cb cb;
69         void *data;
70 };
71
72 struct app_event_info {
73         app_event_type_e type;
74         void *value;
75 };
76
77 struct _widget_class {
78         void *user_data;
79         widget_instance_lifecycle_callback_s ops;
80         widget_obj_private_ops_s ops_private;
81 };
82
83 struct _widget_context {
84         char *id;
85         int state;
86         void *tag;
87         widget_instance_lifecycle_callback_s ops;
88         widget_obj_private_ops_s ops_private;
89 };
90
91 typedef struct _widget_class widget_class_s;
92 typedef struct _widget_context widget_context_s;
93
94 static widget_app_lifecycle_callback_s *app_ops = NULL;
95 static void *app_user_data = NULL;
96 static widget_class_factory_full_s factory;
97 static widget_class_s *widget_class = NULL;
98 static widget_class_s widget_class_tmp;
99 static GList *contexts = NULL;
100 static int is_init_provider = 0;
101 static char *appid = NULL;
102 static int is_background = -1;
103
104 static gint __comp_by_id(gconstpointer a, gconstpointer b)
105 {
106         widget_context_s *wc = (widget_context_s*)a;
107
108         return strcmp(wc->id, (const char*)b);
109 }
110
111 static void __check_status_for_cgroup(void)
112 {
113         GList *iter = g_list_first(contexts);
114
115         while (iter != NULL) {
116                 widget_context_s *cxt = (widget_context_s*) iter->data;
117
118                 if (cxt->state != WC_PAUSED) {
119                         if (is_background != 0) {
120                                 is_background = 0;
121                                 _I("enter foreground group");
122                                 //TODO: Do something to enter foreground group
123                         }
124                         return;
125                 }
126                 iter = g_list_next(iter);
127         }
128
129         if (g_list_length(contexts) > 0 && is_background == 0) {
130                 is_background = 1;
131                 _I("enter background group");
132                 //TODO: DO something to enter background group
133         }
134 }
135
136 static widget_context_s* __find_context_by_id(const char *id)
137 {
138         GList* ret = g_list_find_custom(contexts, id, __comp_by_id);
139
140         if (ret == NULL)
141                 return NULL;
142
143         return ret->data;
144 }
145
146 static int __provider_create_cb(const char *id, const char *content, int w,
147                                 int h,
148                                 void *data)
149 {
150         int ret = WIDGET_ERROR_FAULT;
151         widget_context_s *wc = (widget_context_s*)malloc(sizeof(widget_context_s));
152         if (wc == NULL)
153                 return WIDGET_ERROR_OUT_OF_MEMORY;
154
155         wc->id = strdup(id);
156         wc->state = WC_READY;
157         wc->tag = NULL;
158         wc->ops = widget_class->ops;
159         wc->ops_private = widget_class->ops_private;
160         contexts = g_list_append(contexts, wc);
161
162         if (wc->ops.create) {
163                 bundle *b = NULL;
164                 if (content)
165                         b = bundle_decode((const bundle_raw*)content, strlen(content));
166                 ret = wc->ops.create(wc, b,  w, h, widget_class->user_data);
167                 if (b)
168                         bundle_free(b);
169         }
170         _I("widget obj was created");
171
172         return ret;
173 }
174
175 static int __provider_resize_cb(const char *id, int w, int h, void *data)
176 {
177         int ret = WIDGET_ERROR_FAULT;
178         widget_context_s *cxt = __find_context_by_id(id);
179
180         if (cxt) {
181                 if (cxt->ops.resize)
182                         ret = cxt->ops.resize(cxt, w, h, widget_class->user_data);
183                 _I("received resizing signal");
184         } else {
185                 _E("could not find widget obj : %s", __FUNCTION__);
186         }
187
188         return ret;
189 }
190
191 static int __provider_destroy_cb(const char *id, widget_destroy_type_e reason,
192                                 void *data)
193 {
194         int ret = WIDGET_ERROR_FAULT;
195         widget_context_s *cxt = __find_context_by_id(id);
196
197         if (cxt) {
198                 cxt->state = WC_TERMINATED;
199                 if (cxt->ops.destroy) {
200                         bundle *b  = bundle_create();
201                         ret = cxt->ops.destroy(cxt, (widget_app_destroy_type_e)reason, b, widget_class->user_data);
202
203                         bundle_raw *raw = NULL;
204                         int len;
205
206                         bundle_encode(b, &raw, &len);
207                         if (raw) {
208                                 widget_provider_app_send_extra_info(id, (const char*)raw, NULL);
209                                 free(raw);
210                         }
211
212                         bundle_free(b);
213                         contexts = g_list_remove(contexts, cxt);
214
215                         free(cxt->id);
216                         free(cxt);
217                 }
218                 _I("widget obj was deleted");
219         } else {
220                 _E("could not find widget obj : %s", __FUNCTION__);
221         }
222
223         return ret;
224 }
225
226 static int __provider_update_cb(const char *id, const char *content, int force,
227                                 void *data)
228 {
229         int ret = WIDGET_ERROR_FAULT;
230         widget_context_s *cxt = __find_context_by_id(id);
231
232         if (cxt) {
233                 if (cxt->ops.update) {
234                         bundle *b = NULL;
235                         if (content)
236                                 b = bundle_decode((const bundle_raw*)content, strlen(content));
237                         ret = cxt->ops.update(cxt, b, force, widget_class->user_data);
238
239                         if (b)
240                                 bundle_free(b);
241                 }
242                 _I("received updating signal");
243         } else {
244                 _E("could not find widget obj : %s", __FUNCTION__);
245         }
246
247         return ret;
248 }
249
250 static int __provider_pause_cb(const char *id, void *data)
251 {
252         int ret = WIDGET_ERROR_FAULT;
253         widget_context_s *cxt = __find_context_by_id(id);
254
255         if (cxt) {
256                 if (cxt->ops.pause)
257                         ret = cxt->ops.pause(cxt, widget_class->user_data);
258                 cxt->state = WC_PAUSED;
259                 _I("widget obj was paused");
260         } else {
261                 _E("could not find widget obj : %s", __FUNCTION__);
262         }
263
264         __check_status_for_cgroup();
265         return ret;
266 }
267
268 static int __provider_resume_cb(const char *id, void *data)
269 {
270         int ret = WIDGET_ERROR_FAULT;
271         widget_context_s *cxt = __find_context_by_id(id);
272
273         if (cxt) {
274                 if (cxt->ops.resume)
275                         ret = cxt->ops.resume(cxt, widget_class->user_data);
276                 cxt->state = WC_RUNNING;
277                 _I("widget obj was resumed");
278         } else {
279                 _E("could not find widget obj : %s", __FUNCTION__);
280         }
281
282         __check_status_for_cgroup();
283         return ret;
284 }
285
286 static int __provider_text_signal_cb(const char *id, const char *signal_name,
287                                 const char *source, struct widget_event_info *info, void *data)
288 {
289         int ret = WIDGET_ERROR_FAULT;
290         widget_context_s *cxt = __find_context_by_id(id);
291
292         if (cxt) {
293                 if (cxt->ops_private.text_signal) {
294                         ret = cxt->ops_private.text_signal(cxt, signal_name, source,
295                                                         (widget_obj_event_info_s*)info, widget_class->user_data);
296                 }
297                 _I("received text signal");
298         } else {
299                 _E("could not find widget obj : %s", __FUNCTION__);
300         }
301
302         return ret;
303 }
304
305 static const widget_class_factory_full_s*
306 __widget_class_factory_override_text_signal(widget_instance_text_signal_cb op)
307 {
308         widget_class_tmp.ops_private.text_signal = op;
309         return &factory;
310 }
311
312 static void __free_handler_cb(gpointer data)
313 {
314         if (data)
315                 free(data);
316 }
317
318 static void __free_handler_list(void)
319 {
320         int i;
321
322         for (i = 0; i < WIDGET_APP_EVENT_MAX; i++) {
323                 g_list_free_full(handler_list[i], __free_handler_cb);
324                 handler_list[i] = NULL;
325         }
326 }
327
328 static void __control(bundle *b)
329 {
330         app_control_h app_control;
331
332         if (is_init_provider) {
333                 _E("already initialized");
334                 return;
335         }
336
337         if (app_control_create_event(b, &app_control) != 0) {
338                 _E("failed to get the app_control handle");
339                 return;
340         }
341
342         char *op = NULL;
343         app_control_get_operation(app_control, &op);
344
345         if (op && strcmp(op, "http://tizen.org/appcontrol/operation/main") == 0) {
346                 static struct widget_provider_event_callback cb = {
347                         .create = __provider_create_cb,
348                         .resize = __provider_resize_cb,
349                         .destroy = __provider_destroy_cb,
350
351                         .update = __provider_update_cb,
352                         .text_signal = __provider_text_signal_cb,
353
354                         .pause = __provider_pause_cb,
355                         .resume = __provider_resume_cb,
356
357                         .connected = NULL,
358                         .disconnected = NULL,
359
360                         .data = NULL,
361                 };
362
363                 if (widget_provider_app_init(app_control, &cb) == 0)
364                         is_init_provider = 1;
365
366         }
367
368         app_control_destroy(app_control);
369         if (op)
370                 free(op);
371 }
372
373 static void __pause_all()
374 {
375         GList *iter = g_list_first(contexts);
376
377         while (iter != NULL) {
378                 widget_context_s *cxt = (widget_context_s*) iter->data;
379                 const char *id = cxt->id;
380
381                 switch (cxt->state) {
382                 case WC_READY:
383                         __provider_resume_cb(id, NULL);
384                         __provider_pause_cb(id, NULL);
385                         break;
386
387                 case WC_RUNNING:
388                         __provider_pause_cb(id, NULL);
389                         break;
390                 }
391                 iter = g_list_next(iter);
392         }
393 }
394
395 static int __aul_handler(aul_type type, bundle *b, void *data)
396 {
397         switch (type) {
398         case AUL_START:
399                 __control(b);
400                 break;
401         case AUL_RESUME:
402                 break;
403         case AUL_TERMINATE:
404                 widget_app_exit();
405                 break;
406         default:
407                 break;
408         }
409
410         return 0;
411 }
412
413 static char* __get_domain_name(const char *aid)
414 {
415         char *name_token = NULL;
416
417         if (aid == NULL) {
418                 _E("appid is NULL");
419                 return NULL;
420         }
421
422         /* com.vendor.name -> name */
423         name_token = strrchr(aid, '.');
424
425         if (name_token == NULL) {
426                 _E("appid is invalid");
427                 return strdup(aid);
428         }
429
430         name_token++;
431
432         return strdup(name_token);
433 }
434
435 static int __before_loop(int argc, char **argv)
436 {
437         int r;
438
439 #if !(GLIB_CHECK_VERSION(2, 36, 0))
440         g_type_init();
441 #endif
442
443         elm_init(argc, argv);
444
445         factory.override_text_signal = __widget_class_factory_override_text_signal;
446
447         r = aul_launch_init(__aul_handler, NULL);
448         if (r < 0) {
449                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__,
450                                         "Fail to call the aul_launch_init");
451         }
452
453         r = aul_launch_argv_handler(argc, argv);
454         if (r < 0) {
455                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__,
456                                         "Fail to call the aul_launch_argv_handler");
457         }
458
459         r = app_get_id(&appid);
460         if (r != APP_ERROR_NONE)
461                 return r;
462
463         char *name = __get_domain_name(appid);
464
465         if (name == NULL) {
466                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__,
467                                         "Fail to call __get_domain_name");
468         }
469
470         r = _set_i18n(name);
471
472         free(name);
473         if (r < 0) {
474                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__,
475                                         "Fail to call _set_i18n");
476         }
477
478         widget_provider_app_create_app();
479
480         memset(&widget_class_tmp, 0, sizeof(widget_class_tmp));
481         widget_class = app_ops->create(app_user_data);
482         if (widget_class == NULL) {
483                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__,
484                                         "widget_class is NULL");
485         }
486
487         return WIDGET_ERROR_NONE;
488 }
489
490 static void __after_loop()
491 {
492         __pause_all();
493         widget_provider_app_terminate_app(WIDGET_DESTROY_TYPE_TEMPORARY, 1);
494
495         if (app_ops->terminate)
496                 app_ops->terminate(app_user_data);
497
498         if (is_init_provider) {
499                 widget_provider_app_fini();
500                 is_init_provider = 0;
501         }
502         __free_handler_list();
503         elm_shutdown();
504         if (appid)
505                 free(appid);
506         if (contexts)
507                 g_list_free(contexts);
508         contexts = NULL;
509 }
510
511 static gboolean __finish_event_cb(gpointer user_data)
512 {
513         if (user_data == NULL)
514                 return FALSE;
515
516         widget_context_s *wc = (widget_context_s*) user_data;
517         const char* id = wc->id;
518
519         switch (wc->state) {
520         case WC_READY:
521                 __provider_resume_cb(id, NULL);
522                 __provider_pause_cb(id, NULL);
523                 __provider_destroy_cb(id, WIDGET_DESTROY_TYPE_DEFAULT, NULL);
524                 break;
525
526         case WC_RUNNING:
527                 __provider_pause_cb(id, NULL);
528                 __provider_destroy_cb(id, WIDGET_DESTROY_TYPE_DEFAULT, NULL);
529                 break;
530
531         case WC_PAUSED:
532                 __provider_destroy_cb(id, WIDGET_DESTROY_TYPE_DEFAULT, NULL);
533                 break;
534         }
535
536         widget_provider_app_send_deleted(id);
537         return FALSE;
538 }
539
540 static void __on_low_memory(keynode_t *key, void *data)
541 {
542         int val;
543
544         val = vconf_keynode_get_int(key);
545         if (val == VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING) {
546                 app_event_handler_h handler;
547                 struct app_event_info event;
548
549                 _I("widget_app_low_memory");
550
551                 event.type = APP_EVENT_LOW_MEMORY;
552                 event.value = (void*)&val;
553
554                 GList *iter = g_list_first(handler_list[APP_EVENT_LOW_MEMORY]);
555
556                 while (iter) {
557                         handler = (app_event_handler_h) iter->data;
558                         handler->cb(&event, handler->data);
559                         iter = g_list_next(iter);
560                 }
561         }
562 }
563
564 static void __on_low_battery(keynode_t *key, void *data)
565 {
566         int val;
567
568         val = vconf_keynode_get_int(key);
569         if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW) {
570                 app_event_handler_h handler;
571                 struct app_event_info event;
572
573                 _I("widget_app_low_battery");
574
575                 event.type = APP_EVENT_LOW_BATTERY;
576                 event.value = (void*)&val;
577
578                 GList *iter = g_list_first(handler_list[APP_EVENT_LOW_BATTERY]);
579
580                 while (iter) {
581                         handler = (app_event_handler_h) iter->data;
582                         handler->cb(&event, handler->data);
583                         iter = g_list_next(iter);
584                 }
585         }
586 }
587
588 static void __on_lang_changed(keynode_t *key, void *data)
589 {
590         char *val;
591
592         _update_lang();
593         val = vconf_keynode_get_str(key);
594
595         app_event_handler_h handler;
596         struct app_event_info event;
597
598         _I("widget_app_lang_changed");
599
600         event.type = APP_EVENT_LANGUAGE_CHANGED;
601         event.value = (void*)val;
602
603         GList *iter = g_list_first(handler_list[APP_EVENT_LANGUAGE_CHANGED]);
604
605         while (iter) {
606                 handler = (app_event_handler_h) iter->data;
607                 handler->cb(&event, handler->data);
608                 iter = g_list_next(iter);
609         }
610 }
611
612 static void __on_region_changed(keynode_t *key, void *data)
613 {
614         char *val;
615
616         _update_region();
617         val = vconf_keynode_get_str(key);
618
619         app_event_handler_h handler;
620         struct app_event_info event;
621
622         _I("widget_app_region_changed");
623
624         event.type = APP_EVENT_REGION_FORMAT_CHANGED;
625         event.value = (void*)val;
626
627         GList *iter = g_list_first(handler_list[APP_EVENT_REGION_FORMAT_CHANGED]);
628
629         while (iter) {
630                 handler = (app_event_handler_h) iter->data;
631                 handler->cb(&event, handler->data);
632                 iter = g_list_next(iter);
633         }
634 }
635
636 static void __register_event(int event_type)
637 {
638         switch (event_type) {
639         case APP_EVENT_LOW_MEMORY:
640                 vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __on_low_memory, NULL);
641                 break;
642
643         case APP_EVENT_LOW_BATTERY:
644                 vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __on_low_battery, NULL);
645                 break;
646
647         case APP_EVENT_LANGUAGE_CHANGED:
648                 vconf_notify_key_changed(VCONFKEY_LANGSET, __on_lang_changed, NULL);
649                 break;
650
651         case APP_EVENT_REGION_FORMAT_CHANGED:
652                 vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, __on_region_changed, NULL);
653                 break;
654         }
655 }
656
657 static void __unregister_event(int event_type)
658 {
659         switch (event_type) {
660         case APP_EVENT_LOW_MEMORY:
661                 vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __on_low_memory);
662                 break;
663
664         case APP_EVENT_LOW_BATTERY:
665                 vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __on_low_battery);
666                 break;
667
668         case APP_EVENT_LANGUAGE_CHANGED:
669                 vconf_ignore_key_changed(VCONFKEY_LANGSET, __on_lang_changed);
670                 break;
671
672         case APP_EVENT_REGION_FORMAT_CHANGED:
673                 vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, __on_region_changed);
674                 break;
675         }
676 }
677
678 EXPORT_API int widget_app_main(int argc, char **argv,
679                                 widget_app_lifecycle_callback_s *callback, void *user_data)
680 {
681         int r;
682         bool feature;
683
684         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
685         if (r < 0)
686                 return WIDGET_ERROR_FAULT;
687
688         if (!feature)
689                 return WIDGET_ERROR_NOT_SUPPORTED;
690
691         if (argc <= 0 || argv == NULL || callback == NULL)
692                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
693
694         if (callback->create == NULL)
695                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, "widget_app_create_cb() callback must be registered");
696
697         app_ops = callback;
698         app_user_data = user_data;
699         r = __before_loop(argc, argv);
700         if (r < 0)
701                 return r;
702
703         ecore_main_loop_begin();
704         //aul_status_update(STATUS_DYING);
705         __after_loop();
706
707         return WIDGET_ERROR_NONE;
708 }
709
710 EXPORT_API int widget_app_exit(void)
711 {
712         int r;
713         bool feature;
714
715         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
716         if (r < 0)
717                 return WIDGET_ERROR_FAULT;
718
719         if (!feature)
720                 return WIDGET_ERROR_NOT_SUPPORTED;
721
722         ecore_main_loop_quit();
723
724         return WIDGET_ERROR_NONE;
725 }
726
727 EXPORT_API int widget_app_terminate_context(widget_context_h context)
728 {
729         int r;
730         bool feature;
731
732         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
733         if (r < 0)
734                 return WIDGET_ERROR_FAULT;
735
736         if (!feature)
737                 return WIDGET_ERROR_NOT_SUPPORTED;
738
739         if (context == NULL) {
740                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__,
741                                         "obj is NULL");
742         }
743
744         g_idle_add(__finish_event_cb, context);
745         return WIDGET_ERROR_NONE;
746 }
747
748 EXPORT_API int widget_app_foreach_context(widget_context_cb cb, void *data)
749 {
750         int r;
751         bool feature;
752
753         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
754         if (r < 0)
755                 return WIDGET_ERROR_FAULT;
756
757         if (!feature)
758                 return WIDGET_ERROR_NOT_SUPPORTED;
759
760         if (cb == NULL)
761                 return WIDGET_ERROR_INVALID_PARAMETER;
762
763         GList *iter = g_list_first(contexts);
764
765         while (iter != NULL) {
766                 widget_context_s *cxt = (widget_context_s*) iter->data;
767
768                 if (!cb(cxt, data))
769                         return WIDGET_ERROR_CANCELED;
770
771                 iter = g_list_next(iter);
772         }
773
774         return WIDGET_ERROR_NONE;
775 }
776
777 EXPORT_API int widget_app_add_event_handler(app_event_handler_h *event_handler,
778                                         app_event_type_e event_type, app_event_cb callback,
779                                         void *user_data)
780 {
781         int r;
782         bool feature;
783
784         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
785         if (r < 0)
786                 return WIDGET_ERROR_FAULT;
787
788         if (!feature)
789                 return WIDGET_ERROR_NOT_SUPPORTED;
790
791         app_event_handler_h handler;
792
793         if (event_handler == NULL || callback == NULL)
794                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
795
796         if (event_type < APP_EVENT_LOW_MEMORY
797             || event_type > APP_EVENT_REGION_FORMAT_CHANGED)
798                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
799
800         if (event_type == APP_EVENT_DEVICE_ORIENTATION_CHANGED)
801                 return widget_app_error(WIDGET_ERROR_NOT_SUPPORTED, __FUNCTION__, NULL);
802
803         GList *iter = g_list_first(handler_list[event_type]);
804
805         while (iter) {
806                 handler = (app_event_handler_h) iter->data;
807
808                 if (handler->cb == callback)
809                         return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
810
811                 iter = g_list_next(iter);
812         }
813
814         handler = calloc(1, sizeof(struct app_event_handler));
815         if (!handler)
816                 return widget_app_error(WIDGET_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
817
818         if (g_list_length(handler_list[event_type]) == 0)
819                 __register_event(event_type);
820
821         handler->type = event_type;
822         handler->cb = callback;
823         handler->data = user_data;
824         handler_list[event_type] = g_list_append(handler_list[event_type], handler);
825
826         *event_handler = handler;
827
828         return WIDGET_ERROR_NONE;
829 }
830
831 EXPORT_API int widget_app_remove_event_handler(app_event_handler_h
832                                                 event_handler)
833 {
834         int r;
835         bool feature;
836
837         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
838         if (r < 0)
839                 return WIDGET_ERROR_FAULT;
840
841         if (!feature)
842                 return WIDGET_ERROR_NOT_SUPPORTED;
843
844         app_event_type_e type;
845
846         if (event_handler == NULL)
847                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
848
849         type = event_handler->type;
850         if (type < APP_EVENT_LOW_MEMORY || type > APP_EVENT_REGION_FORMAT_CHANGED)
851                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
852
853         handler_list[type] = g_list_remove(handler_list[type], event_handler);
854         free(event_handler);
855
856         if (g_list_length(handler_list[type]) == 0)
857                 __unregister_event(type);
858
859         return WIDGET_ERROR_NONE;
860 }
861
862 EXPORT_API const char* widget_app_get_id(widget_context_h context)
863 {
864         int r;
865         bool feature;
866
867         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
868         if (r < 0) {
869                 set_last_result(WIDGET_ERROR_FAULT);
870                 return NULL;
871         }
872
873         if (!feature) {
874                 set_last_result(WIDGET_ERROR_NOT_SUPPORTED);
875                 return NULL;
876         }
877
878         if (context == NULL) {
879                 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
880                 return NULL;
881         }
882
883         widget_context_s *cxt = (widget_context_s*)context;
884
885         set_last_result(WIDGET_ERROR_NONE);
886         return cxt->id;
887 }
888
889 EXPORT_API int widget_app_get_elm_win(widget_context_h context,
890                                         Evas_Object **win)
891 {
892         int r;
893         bool feature;
894
895         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
896         if (r < 0)
897                 return WIDGET_ERROR_FAULT;
898
899         if (!feature)
900                 return WIDGET_ERROR_NOT_SUPPORTED;
901
902         if (context == NULL || win == NULL)
903                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
904
905         widget_context_s *cxt = (widget_context_s*)context;
906         Evas *evas;
907         Evas_Object *ret_win = NULL;
908
909         evas = widget_get_evas(cxt->id);
910         if (evas) {
911                 Evas_Object *widget_parent;
912                 widget_parent = evas_object_rectangle_add(evas);
913                 if (widget_parent) {
914                         ret_win = elm_win_add(widget_parent, cxt->id, ELM_WIN_TIZEN_WIDGET);
915                         /* ret_win = elm_win_tizen_widget_add(cxt->id, widget_parent); */
916
917                         evas_object_del(widget_parent);
918                         if (ret_win == NULL) {
919                                 _E("win is NULL");
920                                 return widget_app_error(WIDGET_ERROR_FAULT, __FUNCTION__, NULL);
921                         }
922                 } else {
923                         _E("Failed to get parent widget");
924                         return widget_app_error(WIDGET_ERROR_FAULT, __FUNCTION__, NULL);
925                 }
926         } else {
927                 _E("parent evas object is NULL");
928                 return widget_app_error(WIDGET_ERROR_FAULT, __FUNCTION__, NULL);
929         }
930
931         *win = ret_win;
932         return WIDGET_ERROR_NONE;
933 }
934
935 EXPORT_API widget_class_h widget_app_class_create(widget_instance_lifecycle_callback_s callback, void *user_data)
936 {
937         int r;
938         bool feature;
939
940         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
941         if (r < 0) {
942                 set_last_result(WIDGET_ERROR_FAULT);
943                 return NULL;
944         }
945
946         if (!feature) {
947                 set_last_result(WIDGET_ERROR_NOT_SUPPORTED);
948                 return NULL;
949         }
950
951         widget_class_s *wc = (widget_class_s*)malloc(sizeof(widget_class_s));
952
953         if (wc == NULL) {
954                 _E("failed to malloc : %s", __FUNCTION__);
955                 set_last_result(WIDGET_ERROR_OUT_OF_MEMORY);
956                 return NULL;
957         }
958
959         wc->user_data = user_data;
960         wc->ops = callback;
961         wc->ops_private = widget_class_tmp.ops_private;
962         set_last_result(WIDGET_ERROR_NONE);
963         return wc;
964 }
965
966 EXPORT_API int widget_app_context_set_tag(widget_context_h context, void *tag)
967 {
968         int r;
969         bool feature;
970
971         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
972         if (r < 0)
973                 return WIDGET_ERROR_FAULT;
974
975         if (!feature)
976                 return WIDGET_ERROR_NOT_SUPPORTED;
977
978         if (context == NULL)
979                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
980
981         context->tag = tag;
982
983         return WIDGET_ERROR_NONE;
984 }
985
986 EXPORT_API int widget_app_context_get_tag(widget_context_h context, void **tag)
987 {
988         int r;
989         bool feature;
990
991         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
992         if (r < 0)
993                 return WIDGET_ERROR_FAULT;
994
995         if (!feature)
996                 return WIDGET_ERROR_NOT_SUPPORTED;
997
998         if (context == NULL || tag == NULL)
999                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
1000
1001         *tag = context->tag;
1002
1003         return WIDGET_ERROR_NONE;
1004 }
1005
1006 EXPORT_API int widget_app_context_set_content_info(widget_context_h context, bundle *content_info)
1007 {
1008         int r;
1009         bool feature;
1010
1011         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
1012         if (r < 0)
1013                 return WIDGET_ERROR_FAULT;
1014
1015         if (!feature)
1016                 return WIDGET_ERROR_NOT_SUPPORTED;
1017
1018         if (content_info == NULL)
1019                 return WIDGET_ERROR_INVALID_PARAMETER;
1020
1021         bundle_raw *raw = NULL;
1022         int len;
1023         int ret = WIDGET_ERROR_FAULT;
1024
1025         bundle_encode(content_info, &raw, &len);
1026         if (raw) {
1027                 ret = widget_provider_app_send_extra_info(context->id, (const char*)raw, NULL);
1028                 free(raw);
1029         }
1030
1031         return ret;
1032 }
1033
1034 EXPORT_API int widget_app_context_set_title(widget_context_h context, const char *title)
1035 {
1036         int r;
1037         bool feature;
1038
1039         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
1040         if (r < 0)
1041                 return WIDGET_ERROR_FAULT;
1042
1043         if (!feature)
1044                 return WIDGET_ERROR_NOT_SUPPORTED;
1045
1046         if (context == NULL)
1047                 return WIDGET_ERROR_INVALID_PARAMETER;
1048
1049         return widget_provider_app_send_extra_info(context->id, NULL, title);
1050 }
1051
1052 /* private API */
1053 EXPORT_API const widget_class_factory_full_s* widget_app_get_class_factory(void)
1054 {
1055         return &factory;
1056 }