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