Refactoring communication functions
[platform/core/appfw/appcore-widget.git] / src / base / widget_base.c
1 /*
2  * Copyright (c) 2017 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 #include <stdlib.h>
18 #include <stdbool.h>
19
20 #include <bundle.h>
21 #include <bundle_internal.h>
22 #include <aul.h>
23 #include <aul_widget.h>
24 #include <dlog.h>
25 #include <glib.h>
26 #include <glib-object.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <widget_errno.h>
30 #include <widget_instance.h>
31 #include <aul_app_com.h>
32 #include <Ecore_Wl2.h>
33 #include <system_info.h>
34 #include <screen_connector_provider.h>
35 #include <appcore_multiwindow_base.h>
36
37 #include "widget_base.h"
38
39 #ifdef LOG_TAG
40 #undef LOG_TAG
41 #endif
42
43 #define LOG_TAG "CAPI_WIDGET_APPLICATION"
44 #define APP_TYPE_WIDGET "widgetapp"
45 #define STATUS_FOREGROUND "fg"
46 #define STATUS_BACKGROUND "bg"
47
48 static int __app_event_converter[APPCORE_BASE_EVENT_MAX] = {
49         [APP_EVENT_LOW_MEMORY] = APPCORE_BASE_EVENT_LOW_MEMORY,
50         [APP_EVENT_LOW_BATTERY] = APPCORE_BASE_EVENT_LOW_BATTERY,
51         [APP_EVENT_LANGUAGE_CHANGED] = APPCORE_BASE_EVENT_LANG_CHANGE,
52         [APP_EVENT_DEVICE_ORIENTATION_CHANGED]
53                         = APPCORE_BASE_EVENT_DEVICE_ORIENTATION_CHANGED,
54         [APP_EVENT_REGION_FORMAT_CHANGED] = APPCORE_BASE_EVENT_REGION_CHANGE,
55         [APP_EVENT_SUSPENDED_STATE_CHANGED]
56                         = APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE,
57 };
58
59 struct app_event_info {
60         app_event_type_e type;
61         void *value;
62 };
63
64 struct app_event_handler {
65         app_event_type_e type;
66         app_event_cb cb;
67         void *data;
68         void *raw;
69 };
70
71 struct widget_foreach_context {
72         widget_base_instance_cb callback;
73         void *data;
74 };
75
76 typedef struct _widget_base_context {
77         widget_base_ops ops;
78         void *data;
79         int argc;
80         char **argv;
81         GList *classes;
82 } widget_base_context;
83
84 typedef struct _widget_base_instance_data {
85         bundle *args;
86         char *id;
87         char *content;
88         void *tag;
89         double period;
90         guint periodic_timer;
91         bool pending_update;
92         char *pending_content;
93         void *user_data;
94 } widget_base_instance_data;
95
96 static widget_base_context __context;
97 static char *__appid;
98 static char *__package_id;
99 static bool __fg_signal;
100 static char *__viewer_endpoint;
101 static bool __is_permanent;
102 static void __call_update_cb(const char *class_id, const char *id, int force,
103                 const char *content_raw);
104
105 static gboolean __timeout_cb(gpointer user_data)
106 {
107         widget_base_instance_data *data =
108                         (widget_base_instance_data *)user_data;
109         appcore_multiwindow_base_instance_h cxt;
110         const char *class_id;
111
112         cxt = appcore_multiwindow_base_instance_find(data->id);
113
114         if (!cxt) {
115                 LOGE("Can't find the instance");
116                 return G_SOURCE_REMOVE;
117         }
118
119         if (appcore_multiwindow_base_instance_is_resumed(cxt)) {
120                 LOGD("Periodic update!");
121                 class_id = appcore_multiwindow_base_instance_get_class_id(cxt);
122                 __call_update_cb(class_id, data->id, 0, NULL);
123         } else {
124                 data->pending_update = true;
125                 if (data->periodic_timer) {
126                         LOGD("Remove timer!");
127                         g_source_remove(data->periodic_timer);
128                         data->periodic_timer = 0;
129                 }
130         }
131
132         return G_SOURCE_CONTINUE;
133 }
134
135 static bool __is_widget_feature_enabled(void)
136 {
137         static bool feature = false;
138         static bool retrieved = false;
139         int ret;
140
141         if (retrieved == true)
142                 return feature;
143
144         ret = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
145         if (ret != SYSTEM_INFO_ERROR_NONE) {
146                 LOGE("failed to get system info"); /* LCOV_EXCL_LINE */
147                 return false; /* LCOV_EXCL_LINE */
148         }
149
150         retrieved = true;
151
152         return feature;
153 }
154
155 static void __check_empty_instance(void)
156 {
157         int cnt = appcore_multiwindow_base_instance_get_cnt();
158
159         if (cnt == 0)
160                 widget_base_exit();
161 }
162
163 static void __instance_drop(appcore_multiwindow_base_instance_h instance_h)
164 {
165         widget_base_instance_data *data;
166
167         data = appcore_multiwindow_base_instance_get_extra(instance_h);
168         appcore_multiwindow_base_instance_drop(instance_h);
169         free(data->pending_content);
170         free(data->content);
171         free(data->id);
172         free(data);
173         __check_empty_instance();
174 }
175
176 static gint __comp_class(gconstpointer a, gconstpointer b)
177 {
178         const widget_base_class *cls = a;
179
180         return strcmp(cls->id, b);
181 }
182
183 static widget_base_class *__get_class(const char *class_id)
184 {
185         widget_base_class *cls;
186         GList *class_node;
187
188         class_node = g_list_find_custom(__context.classes, class_id,
189                         __comp_class);
190         if (class_node == NULL) {
191                 LOGE("empty classes");
192                 return NULL;
193         }
194         cls = (widget_base_class *)class_node->data;
195
196         return cls;
197 }
198
199 static int __send_update_status(const char *class_id, const char *instance_id,
200         int status, int err, bundle *extra)
201 {
202         int lifecycle;
203
204         aul_widget_send_status_to_viewer(class_id, instance_id,
205                         __viewer_endpoint, status, err, extra);
206         lifecycle = widget_instance_convert_event_to_lifecycle_status(status);
207         if (lifecycle > -1) {
208                 aul_widget_send_status_to_service(
209                                 class_id, instance_id, __package_id, lifecycle);
210         }
211
212         return 0;
213 }
214
215 static void __control_create(const char *class_id, const char *id, bundle *b)
216 {
217         widget_base_instance_data *data;
218         char *content = NULL;
219
220         if (appcore_multiwindow_base_instance_find(id)) {
221                 LOGE("Already exist id (%s)", id);
222                 return;
223         }
224
225         data = (widget_base_instance_data *)
226                         calloc(1, sizeof(widget_base_instance_data));
227         if (!data) {
228                 LOGE("Out of memory");
229                 return;
230         }
231
232         data->id = strdup(id);
233         data->args = b;
234
235         /* call stub create */
236         appcore_multiwindow_base_instance_run(class_id, id, data);
237         if (appcore_multiwindow_base_instance_find(id)) {
238                 data->args = NULL;
239                 bundle_get_str(b, WIDGET_K_CONTENT_INFO, &content);
240                 if (content)
241                         data->content = strdup(content);
242         }
243 }
244
245 static void __control_resume(const char *class_id, const char *id, bundle *b)
246 {
247         appcore_multiwindow_base_instance_h cxt;
248
249         cxt = appcore_multiwindow_base_instance_find(id);
250         if (!cxt) {
251                 LOGE("context not found: %s", id);
252                 return;
253         }
254
255         /* call stub resume */
256         appcore_multiwindow_base_instance_resume(cxt);
257 }
258
259 static void __control_pause(const char *class_id, const char *id, bundle *b)
260 {
261         appcore_multiwindow_base_instance_h instance_h;
262
263         instance_h = appcore_multiwindow_base_instance_find(id);
264
265         if (!instance_h) {
266                 LOGE("instance not found: %s", id);
267                 return;
268         }
269
270         /* call stub pause */
271         appcore_multiwindow_base_instance_pause(instance_h);
272 }
273
274 static void __control_resize(const char *class_id, const char *id, bundle *b)
275 {
276         appcore_multiwindow_base_instance_h instance_h;
277         char *remain = NULL;
278         char *w_str = NULL;
279         char *h_str = NULL;
280         int w = 0;
281         int h = 0;
282         void *class_data;
283         widget_base_class *cls;
284         const appcore_multiwindow_base_class *raw_cls;
285
286         instance_h = appcore_multiwindow_base_instance_find(id);
287         if (!instance_h) {
288                 LOGE("context not found: %s", id);
289                 return;
290         }
291
292         raw_cls = appcore_multiwindow_base_instance_get_class(instance_h);
293         if (!raw_cls)
294                 return;
295
296         cls = __get_class(class_id);
297         if (cls == NULL) {
298                 LOGE("class not found: %s", class_id);
299                 return;
300         }
301         class_data = raw_cls->data;
302         bundle_get_str(b, WIDGET_K_WIDTH, &w_str);
303         bundle_get_str(b, WIDGET_K_HEIGHT, &h_str);
304
305         if (w_str)
306                 w = (int)g_ascii_strtoll(w_str, &remain, 10);
307
308         if (h_str)
309                 h = (int)g_ascii_strtoll(h_str, &remain, 10);
310
311         if (cls->ops.resize)
312                 cls->ops.resize(instance_h, w, h, class_data);
313
314         LOGD("%s is resized to %dx%d", id, w, h);
315         __send_update_status(class_id, id,
316                 WIDGET_INSTANCE_EVENT_SIZE_CHANGED, 0, NULL);
317 }
318
319 static void __call_update_cb(const char *class_id, const char *id, int force,
320                 const char *content_raw)
321 {
322         void *class_data;
323         widget_base_class *cls;
324         const appcore_multiwindow_base_class *raw_cls;
325         appcore_multiwindow_base_instance_h instance_h;
326         bundle *content = NULL;
327
328         instance_h = appcore_multiwindow_base_instance_find(id);
329         if (!instance_h) {
330                 LOGE("context not found: %s", id);
331                 return;
332         }
333
334         raw_cls = appcore_multiwindow_base_instance_get_class(instance_h);
335         if (!raw_cls) {
336                 LOGE("class is NULL");
337                 return;
338         }
339
340         class_data = raw_cls->data;
341         cls = __get_class(class_id);
342         if (cls == NULL) {
343                 LOGE("class not found: %s", class_id);
344                 return;
345         }
346
347         if (!cls->ops.update) {
348                 LOGE("update callback is NULL");
349                 return;
350         }
351
352         if (content_raw) {
353                 content = bundle_decode((const bundle_raw *)content_raw,
354                                 strlen(content_raw));
355         }
356
357         if (cls->ops.update)
358                 cls->ops.update(instance_h, content, force, class_data);
359
360         __send_update_status(class_id, id,
361                 WIDGET_INSTANCE_EVENT_UPDATE, 0, NULL);
362         LOGD("updated:%s", id);
363
364         if (content)
365                 bundle_free(content);
366 }
367
368 static void __update_pending_content(
369                 appcore_multiwindow_base_instance_h instance_h,
370                 const char *content_raw)
371 {
372         widget_base_instance_data *data;
373
374         data = (widget_base_instance_data *)
375                         appcore_multiwindow_base_instance_get_extra(instance_h);
376
377         if (data->pending_content) {
378                 free(data->pending_content);
379                 data->pending_content = NULL;
380         }
381
382         if (content_raw) {
383                 data->pending_content = strdup(content_raw);
384                 if (data->pending_content == NULL)
385                         LOGW("Out of memory");
386         }
387
388         data->pending_update = true;
389 }
390
391 static void __update_process(const char *class_id, const char *id,
392                 appcore_multiwindow_base_instance_h instance_h, void *data)
393 {
394         char *content_raw = NULL;
395         char *force_str = NULL;
396         int force;
397         bundle *b = data;
398
399         if (!b) {
400                 LOGE("bundle is NULL");
401                 return;
402         }
403
404         bundle_get_str(b, WIDGET_K_FORCE, &force_str);
405
406         if (force_str && strcmp(force_str, "true") == 0)
407                 force = 1;
408         else
409                 force = 0;
410
411         bundle_get_str(b, WIDGET_K_CONTENT_INFO, &content_raw);
412         if (!appcore_multiwindow_base_instance_is_resumed(instance_h) && !force)
413                 __update_pending_content(instance_h, content_raw);
414         else
415                 __call_update_cb(class_id, id, force, content_raw);
416 }
417
418 static void __control_update(const char *class_id, const char *id, bundle *b)
419 {
420         appcore_multiwindow_base_instance_h instance_h;
421
422         if (!id) {
423                 appcore_multiwindow_base_instance_foreach(class_id,
424                                 __update_process, b);
425                 return;
426         }
427
428         instance_h = appcore_multiwindow_base_instance_find(id);
429         if (!instance_h) {
430                 LOGE("context not found: %s", id);
431                 return;
432         }
433
434         __update_process(class_id, id, instance_h, b);
435 }
436
437 static void __control_destroy(const char *class_id, const char *id, bundle *b)
438 {
439         appcore_multiwindow_base_instance_h instance_h;
440         widget_base_instance_data *data;
441
442         instance_h = appcore_multiwindow_base_instance_find(id);
443         if (!instance_h) {
444                 LOGE("could not find widget obj: %s, clear amd info", id);
445                 aul_widget_instance_del(class_id, id);
446                 return;
447         }
448
449         data = (widget_base_instance_data *)
450                         appcore_multiwindow_base_instance_get_extra(instance_h);
451         data->args = b;
452
453         /* call stub terminate */
454         appcore_multiwindow_base_instance_exit(instance_h);
455         free(data->pending_content);
456         free(data->content);
457         free(data->id);
458         free(data);
459         __check_empty_instance();
460         aul_widget_write_log(LOG_TAG,
461                 "[%s:%d] instance_id(%s)", __FUNCTION__, __LINE__, id);
462 }
463
464 static void __control_change_period(const char *class_id, const char *id,
465                 bundle *b)
466 {
467         appcore_multiwindow_base_instance_h instance_h;
468         widget_base_instance_data *data;
469         double *period = NULL;
470         size_t size;
471         int ret;
472
473         instance_h = appcore_multiwindow_base_instance_find(id);
474         if (!instance_h) {
475                 LOGE("context not found: %s", id);
476                 return;
477         }
478
479         data = (widget_base_instance_data *)
480                         appcore_multiwindow_base_instance_get_extra(instance_h);
481
482         if (!data) {
483                 LOGE("could not find instance data: %s", id);
484                 return;
485         }
486
487         if (data->periodic_timer) {
488                 LOGD("Remove timer!");
489                 g_source_remove(data->periodic_timer);
490                 data->periodic_timer = 0;
491         }
492
493         ret = bundle_get_byte(b, WIDGET_K_PERIOD, (void **)&period, &size);
494         if (ret == BUNDLE_ERROR_NONE)
495                 data->period = *period;
496
497         if (data->period > 0) {
498                 LOGD("Restart timer!");
499                 data->periodic_timer = g_timeout_add_seconds(data->period,
500                                 __timeout_cb, data);
501         }
502
503         return;
504 }
505
506 static int __multiwindow_create(void *data)
507 {
508         char pkgid[256] = {0, };
509         int ret = 0;
510
511         appcore_multiwindow_base_on_create();
512         app_get_id(&__appid);
513         if (aul_app_get_pkgid_bypid(getpid(), pkgid, sizeof(pkgid)) == 0)
514                 __package_id = strdup(pkgid);
515
516         if (!__package_id || !__appid) {
517                 LOGE("__package_id is NULL");
518                 return -1;
519         }
520
521         screen_connector_provider_init();
522         if (__context.ops.create)
523                 ret = __context.ops.create(data);
524
525         LOGD("widget base is created");
526         return ret;
527 }
528
529 static int __multiwindow_terminate(void *data)
530 {
531         if (__context.ops.terminate)
532                 __context.ops.terminate(data);
533         screen_connector_provider_fini();
534
535         if (__viewer_endpoint) {
536                 free(__viewer_endpoint);
537                 __viewer_endpoint = NULL;
538         }
539
540         if (__package_id) {
541                 free(__package_id);
542                 __package_id = NULL;
543         }
544
545         if (__appid) {
546                 free(__appid);
547                 __appid = NULL;
548         }
549
550         appcore_multiwindow_base_on_terminate();
551
552         LOGD("widget base is terminated");
553         return 0;
554 }
555
556 static int __multiwindow_control(bundle *b, void *data)
557 {
558         char *class_id = NULL;
559         char *id = NULL;
560         char *operation = NULL;
561
562         appcore_multiwindow_base_on_control(b);
563         bundle_get_str(b, WIDGET_K_CLASS, &class_id);
564         /* for previous version compatibility, use appid for default class id */
565         if (class_id == NULL)
566                 class_id = __appid;
567
568         bundle_get_str(b, AUL_K_WIDGET_INSTANCE_ID, &id);
569         bundle_get_str(b, WIDGET_K_OPERATION, &operation);
570
571         if (!operation) {
572                 LOGE("operation is NULL");
573                 return 0;
574         }
575
576         LOGI("app control operation(%s)", operation);
577         if (strcmp(operation, "create") == 0)
578                 __control_create(class_id, id, b);
579         else if (strcmp(operation, "resize") == 0)
580                 __control_resize(class_id, id, b);
581         else if (strcmp(operation, "update") == 0)
582                 __control_update(class_id, id, b);
583         else if (strcmp(operation, "destroy") == 0)
584                 __control_destroy(class_id, id, b);
585         else if (strcmp(operation, "resume") == 0)
586                 __control_resume(class_id, id, b);
587         else if (strcmp(operation, "pause") == 0)
588                 __control_pause(class_id, id, b);
589         else if (strcmp(operation, "terminate") == 0)
590                 __control_destroy(class_id, id, b);
591         else if (strcmp(operation, "period") == 0)
592                 __control_change_period(class_id, id, b);
593
594         return 0;
595 }
596
597 static void __inst_resume_cb(const char *class_id, const char *id,
598                 appcore_multiwindow_base_instance_h cxt, void *data)
599 {
600         __control_resume(class_id, id, data);
601 }
602
603 static void __get_content(bundle *b)
604 {
605         char *instance_id = NULL;
606         appcore_multiwindow_base_instance_h cxt;
607         widget_base_instance_data * we;
608
609         bundle_get_str(b, AUL_K_WIDGET_INSTANCE_ID, &instance_id);
610         if (!instance_id) {
611                 LOGE("instance id is NULL");
612                 return;
613         }
614
615         cxt = appcore_multiwindow_base_instance_find(instance_id);
616         if (!cxt) {
617                 LOGE("could not find widget obj: %s", instance_id);
618                 return;
619         }
620
621         we = appcore_multiwindow_base_instance_get_extra(cxt);
622         if (!we) {
623                 LOGE("widget extra is NULL");
624                 return;
625         }
626
627         if (we->content) {
628                 bundle_add_str(b, AUL_K_WIDGET_CONTENT_INFO, we->content);
629                 LOGD("content info of %s found", instance_id);
630         } else {
631                 bundle_add_str(b, AUL_K_WIDGET_CONTENT_INFO, "");
632                 LOGD("empty content info added");
633         }
634 }
635
636 static int __multiwindow_receive(aul_type type, bundle *b, void *data)
637 {
638         appcore_multiwindow_base_on_receive(type, b);
639
640         switch (type) {
641         case AUL_RESUME:
642                 appcore_multiwindow_base_instance_foreach_full(
643                                 __inst_resume_cb, b);
644                 break;
645         case AUL_TERMINATE:
646                 widget_base_exit();
647                 break;
648         case AUL_WIDGET_CONTENT:
649                 __get_content(b);
650                 break;
651         default:
652                 break;
653         }
654
655         return 0;
656 }
657
658 static void __multiwindow_init(int argc, char **argv, void *data)
659 {
660         if (__context.ops.init)
661                 __context.ops.init(argc, argv, data);
662 }
663
664 static void __multiwindow_finish(void)
665 {
666         if (__context.ops.finish) {
667                 __context.ops.finish();
668                 /* Check Loader case */
669                 if (getenv("AUL_LOADER_INIT")) {
670                         unsetenv("AUL_LOADER_INIT");
671                         __context.ops.finish();
672                 }
673         }
674 }
675
676 static void __multiwindow_run(void *data)
677 {
678         if (__context.ops.run)
679                 __context.ops.run(data);
680 }
681
682 static void __multiwindow_exit(void *data)
683 {
684         if (__context.ops.exit)
685                 __context.ops.exit(data);
686 }
687
688 static void __multiwindow_trim_memory(void *data)
689 {
690         if (__context.ops.trim_memory)
691                 __context.ops.trim_memory(data);
692 }
693
694 EXPORT_API int widget_base_exit(void)
695 {
696         int ret = 0;
697         int cnt;
698
699         appcore_multiwindow_base_exit();
700         cnt = appcore_multiwindow_base_instance_get_cnt();
701         if (cnt == 0 && __is_permanent)
702                 ret = aul_notify_exit();
703
704         aul_widget_write_log(LOG_TAG,
705                 "[%s:%d] exit : ret(%d), cnt(%d), permanent(%d)",
706                         __FUNCTION__, __LINE__, ret, cnt, __is_permanent);
707
708         return 0;
709 }
710
711 static gboolean __finish_event_cb(gpointer user_data)
712 {
713         appcore_multiwindow_base_instance_h cxt = user_data;
714         bundle *b;
715         const char *id;
716         const char *class_id;
717
718         if (!cxt) {
719                 LOGE("user_data is NULL");
720                 return FALSE;
721         }
722
723         id = appcore_multiwindow_base_instance_get_id(cxt);
724         class_id = appcore_multiwindow_base_instance_get_class_id(cxt);
725         b = bundle_create();
726
727         if (!b) {
728                 LOGE("Out-of-memory");
729                 return FALSE;
730         }
731
732         bundle_add_str(b, WIDGET_K_OPERATION, "terminate");
733         __control_destroy(class_id, id, b);
734         bundle_free(b);
735
736         return FALSE;
737 }
738
739 EXPORT_API int widget_base_terminate_context(widget_base_instance_h context)
740 {
741         if (!__is_widget_feature_enabled()) {
742                 LOGE("not supported"); /* LCOV_EXCL_LINE */
743                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
744         }
745
746         if (!context) {
747                 LOGE("context is null");
748                 return WIDGET_ERROR_INVALID_PARAMETER;
749         }
750
751         g_idle_add(__finish_event_cb, context);
752
753         return WIDGET_ERROR_NONE;
754 }
755
756 static void __inst_full_cb(const char *class_id, const char *id,
757                 appcore_multiwindow_base_instance_h cxt, void *data)
758 {
759         struct widget_foreach_context *foreach_context = data;
760
761         if (!data)
762                 return;
763
764         if (foreach_context->callback)
765                 foreach_context->callback(cxt, foreach_context->data);
766 }
767
768 EXPORT_API int widget_base_foreach_context(widget_base_instance_cb cb, void *data)
769 {
770         struct widget_foreach_context foreach_context;
771
772         if (!__is_widget_feature_enabled()) {
773                 LOGE("not supported"); /* LCOV_EXCL_LINE */
774                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
775         }
776
777         if (!cb) {
778                 LOGE("callback is NULL");
779                 return WIDGET_ERROR_INVALID_PARAMETER;
780         }
781
782         foreach_context.callback = cb;
783         foreach_context.data = data;
784         appcore_multiwindow_base_instance_foreach_full(__inst_full_cb, &foreach_context);
785
786         return WIDGET_ERROR_NONE;
787 }
788
789 static int __event_cb(void *event, void *data)
790 {
791         app_event_handler_h handler = data;
792
793         struct app_event_info app_event;
794
795         app_event.type = handler->type;
796         app_event.value = event;
797
798         if (handler->cb)
799                 handler->cb(&app_event, handler->data);
800
801         return 0;
802 }
803
804 EXPORT_API int widget_base_add_event_handler(app_event_handler_h *event_handler,
805                                         app_event_type_e event_type,
806                                         app_event_cb callback,
807                                         void *user_data)
808 {
809         int r;
810         bool feature;
811         app_event_handler_h handler;
812
813         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
814         if (r < 0)
815                 return WIDGET_BASE_ERROR_FAULT;
816
817         if (!feature)
818                 return WIDGET_BASE_ERROR_NOT_SUPPORTED;
819
820         if (event_handler == NULL || callback == NULL)
821                 return WIDGET_BASE_ERROR_INVALID_PARAMETER;
822
823         if (event_type < APP_EVENT_LOW_MEMORY
824             || event_type > APP_EVENT_REGION_FORMAT_CHANGED)
825                 return WIDGET_BASE_ERROR_INVALID_PARAMETER;
826
827         if (event_type == APP_EVENT_DEVICE_ORIENTATION_CHANGED)
828                 return WIDGET_BASE_ERROR_NOT_SUPPORTED;
829
830
831         handler = calloc(1, sizeof(struct app_event_handler));
832         if (!handler)
833                 return WIDGET_BASE_ERROR_OUT_OF_MEMORY;
834
835         handler->type = event_type;
836         handler->cb = callback;
837         handler->data = user_data;
838         handler->raw = appcore_base_add_event(
839                         __app_event_converter[event_type], __event_cb, handler);
840         *event_handler = handler;
841
842         return WIDGET_BASE_ERROR_NONE;
843 }
844
845 EXPORT_API int widget_base_remove_event_handler(app_event_handler_h
846                                                 event_handler)
847 {
848         int r;
849         bool feature;
850         app_event_type_e type;
851
852         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
853         if (r < 0)
854                 return WIDGET_BASE_ERROR_FAULT;
855
856         if (!feature)
857                 return WIDGET_BASE_ERROR_NOT_SUPPORTED;
858
859         if (event_handler == NULL)
860                 return WIDGET_BASE_ERROR_INVALID_PARAMETER;
861
862         type = event_handler->type;
863         if (type < APP_EVENT_LOW_MEMORY ||
864                         type > APP_EVENT_REGION_FORMAT_CHANGED)
865                 return WIDGET_BASE_ERROR_INVALID_PARAMETER;
866
867         r = appcore_base_remove_event(event_handler->raw);
868         if (r < 0)
869                 return WIDGET_BASE_ERROR_INVALID_PARAMETER;
870
871         free(event_handler);
872
873         return WIDGET_BASE_ERROR_NONE;
874 }
875
876 EXPORT_API int widget_base_context_set_content_info(
877                 widget_base_instance_h context,
878                 bundle *content_info)
879 {
880         int ret = 0;
881         bundle_raw *raw = NULL;
882         int len;
883         const char *id;
884         const char *class_id;
885         widget_base_instance_data *data;
886         appcore_multiwindow_base_instance_h instance_h;
887
888         if (!__is_widget_feature_enabled()) {
889                 LOGE("not supported"); /* LCOV_EXCL_LINE */
890                 return WIDGET_BASE_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
891         }
892
893         if (!context || !content_info)
894                 return WIDGET_BASE_ERROR_INVALID_PARAMETER;
895
896         instance_h = (appcore_multiwindow_base_instance_h)context;
897         id = appcore_multiwindow_base_instance_get_id(instance_h);
898         class_id = appcore_multiwindow_base_instance_get_class_id(instance_h);
899         data = appcore_multiwindow_base_instance_get_extra(instance_h);
900
901         if (!class_id || !id || !data)
902                 return WIDGET_BASE_ERROR_FAULT;
903
904         ret = __send_update_status(class_id, id,
905                         WIDGET_INSTANCE_EVENT_EXTRA_UPDATED, 0, content_info);
906
907         if (data->content)
908                 free(data->content);
909
910         bundle_encode(content_info, &raw, &len);
911         if (raw)
912                 data->content = strdup((const char *)raw);
913         else
914                 data->content = NULL;
915
916         free(raw);
917         if (ret < 0) {
918                 /* LCOV_EXCL_START */
919                 LOGE("failed to send content info: %s of %s (%d)", id,
920                                 class_id, ret);
921                 return WIDGET_BASE_ERROR_IO_ERROR;
922                 /* LCOV_EXCL_STOP */
923         }
924
925         return WIDGET_BASE_ERROR_NONE;
926 }
927
928 EXPORT_API int widget_base_context_get_tag(widget_base_instance_h context, void **tag)
929 {
930         appcore_multiwindow_base_instance_h instance_h;
931         widget_base_instance_data *data;
932
933         if (!__is_widget_feature_enabled()) {
934                 LOGE("not supported"); /* LCOV_EXCL_LINE */
935                 return WIDGET_BASE_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
936         }
937
938         if (!context || !tag) {
939                 LOGE("Invalid parameter");
940                 return WIDGET_BASE_ERROR_INVALID_PARAMETER;
941         }
942
943         instance_h = (appcore_multiwindow_base_instance_h)context;
944         data = (widget_base_instance_data *)
945                         appcore_multiwindow_base_instance_get_extra(instance_h);
946
947         if (!data) {
948                 LOGE("Invalid parameter");
949                 return WIDGET_ERROR_INVALID_PARAMETER;
950         }
951
952         *tag = data->tag;
953
954         return WIDGET_BASE_ERROR_NONE;
955 }
956
957 EXPORT_API int widget_base_context_set_tag(widget_base_instance_h context, void *tag)
958 {
959         appcore_multiwindow_base_instance_h instance_h;
960         widget_base_instance_data *data;
961
962         if (!__is_widget_feature_enabled()) {
963                 LOGE("not supported"); /* LCOV_EXCL_LINE */
964                 return WIDGET_BASE_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
965         }
966
967         if (!context) {
968                 LOGE("Invalid parameter");
969                 return WIDGET_BASE_ERROR_INVALID_PARAMETER;
970         }
971
972         instance_h = (appcore_multiwindow_base_instance_h)context;
973         data = (widget_base_instance_data *)
974                         appcore_multiwindow_base_instance_get_extra(instance_h);
975         data->tag = tag;
976
977         return WIDGET_BASE_ERROR_NONE;
978 }
979
980 EXPORT_API void *widget_base_context_get_user_data(
981                 widget_base_instance_h context)
982 {
983         appcore_multiwindow_base_instance_h instance_h;
984         widget_base_instance_data *data;
985
986         if (!__is_widget_feature_enabled()) {
987                 LOGE("not supported"); /* LCOV_EXCL_LINE */
988                 return NULL; /* LCOV_EXCL_LINE */
989         }
990
991         if (!context) {
992                 LOGE("Invalid parameter");
993                 return NULL;
994         }
995
996         instance_h = (appcore_multiwindow_base_instance_h)context;
997         data = (widget_base_instance_data *)
998                         appcore_multiwindow_base_instance_get_extra(instance_h);
999
1000         return data->user_data;
1001 }
1002
1003
1004 EXPORT_API int widget_base_context_set_user_data(
1005                 widget_base_instance_h context, void *user_data)
1006 {
1007         appcore_multiwindow_base_instance_h instance_h;
1008         widget_base_instance_data *data;
1009
1010         if (!__is_widget_feature_enabled()) {
1011                 LOGE("not supported"); /* LCOV_EXCL_LINE */
1012                 return WIDGET_BASE_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1013         }
1014
1015         if (!context) {
1016                 LOGE("Invalid parameter");
1017                 return WIDGET_BASE_ERROR_INVALID_PARAMETER;
1018         }
1019
1020         instance_h = (appcore_multiwindow_base_instance_h)context;
1021         data = (widget_base_instance_data *)
1022                         appcore_multiwindow_base_instance_get_extra(instance_h);
1023         data->user_data = user_data;
1024
1025         return WIDGET_BASE_ERROR_NONE;
1026 }
1027
1028 EXPORT_API int widget_base_context_get_id(widget_base_instance_h context, char **id)
1029 {
1030         appcore_multiwindow_base_instance_h instance_h;
1031
1032         if (!__is_widget_feature_enabled()) {
1033                 LOGE("not supported"); /* LCOV_EXCL_LINE */
1034                 return WIDGET_BASE_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1035         }
1036
1037         instance_h = (appcore_multiwindow_base_instance_h)context;
1038         *id = (char *)appcore_multiwindow_base_instance_get_id(instance_h);
1039
1040         return WIDGET_BASE_ERROR_NONE;
1041 }
1042
1043 EXPORT_API const char *widget_base_get_viewer_endpoint()
1044 {
1045         return __viewer_endpoint;
1046 }
1047
1048 EXPORT_API int widget_base_init(widget_base_ops ops, int argc, char **argv,
1049                 void *data)
1050 {
1051         bundle *kb;
1052         char *viewer_endpoint = NULL;
1053         appcore_multiwindow_base_ops raw_ops
1054                         = appcore_multiwindow_base_get_default_ops();
1055
1056         __context.ops = ops;
1057         __context.argc = argc;
1058         __context.argv = argv;
1059         __context.data = data;
1060
1061         /* override methods */
1062         raw_ops.base.create = __multiwindow_create;
1063         raw_ops.base.control = __multiwindow_control;
1064         raw_ops.base.terminate = __multiwindow_terminate;
1065         raw_ops.base.receive = __multiwindow_receive;
1066         raw_ops.base.init = __multiwindow_init;
1067         raw_ops.base.finish = __multiwindow_finish;
1068         raw_ops.base.run = __multiwindow_run;
1069         raw_ops.base.exit = __multiwindow_exit;
1070         raw_ops.base.trim_memory = __multiwindow_trim_memory;
1071
1072         if (!__is_widget_feature_enabled()) {
1073                 LOGE("not supported"); /* LCOV_EXCL_LINE */
1074                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1075         }
1076
1077         kb = bundle_import_from_argv(argc, argv);
1078         if (kb) {
1079                 bundle_get_str(kb, AUL_K_WIDGET_VIEWER, &viewer_endpoint);
1080                 if (viewer_endpoint) {
1081                         LOGD("viewer endpoint :%s", viewer_endpoint);
1082                         __viewer_endpoint = strdup(viewer_endpoint);
1083                 } else {
1084                         LOGE("endpoint is missing");
1085                 }
1086
1087                 bundle_free(kb);
1088         } else {
1089                 LOGE("failed to get launch argv"); /* LCOV_EXCL_LINE */
1090                 return WIDGET_ERROR_FAULT;
1091         }
1092
1093         if (appcore_multiwindow_base_init(raw_ops, argc, argv, data) < 0)
1094                return WIDGET_ERROR_FAULT;
1095
1096         return WIDGET_ERROR_NONE;
1097 }
1098
1099 static int __on_create(void *data)
1100 {
1101         return widget_base_on_create();
1102 }
1103
1104 static int __on_terminate(void *data)
1105 {
1106         return widget_base_on_terminate();
1107 }
1108
1109 static void __on_init(int argc, char **argv, void *data)
1110 {
1111         widget_base_on_init(argc, argv);
1112 }
1113
1114 static void __on_finish(void)
1115 {
1116         widget_base_on_finish();
1117 }
1118
1119 static void __on_run(void *data)
1120 {
1121         widget_base_on_run();
1122 }
1123
1124 static void __on_exit(void *data)
1125 {
1126         widget_base_on_exit();
1127 }
1128
1129 static void __on_trim_memory(void *data)
1130 {
1131         widget_base_on_trim_memory();
1132 }
1133
1134 EXPORT_API int widget_base_on_create(void)
1135 {
1136         appcore_multiwindow_base_on_create();
1137
1138         return 0;
1139 }
1140
1141 EXPORT_API int widget_base_on_terminate(void)
1142 {
1143         appcore_multiwindow_base_on_terminate();
1144
1145         return 0;
1146 }
1147
1148 EXPORT_API int widget_base_on_init(int argc, char **argv)
1149 {
1150         return 0;
1151 }
1152
1153 EXPORT_API void widget_base_on_finish(void)
1154 {
1155 }
1156
1157 EXPORT_API void widget_base_on_run(void)
1158 {
1159 }
1160
1161 EXPORT_API void widget_base_on_exit(void)
1162 {
1163 }
1164
1165 EXPORT_API int widget_base_on_trim_memory(void)
1166 {
1167         appcore_multiwindow_base_on_trim_memory();
1168
1169         return 0;
1170 }
1171
1172 EXPORT_API widget_base_ops widget_base_get_default_ops(void)
1173 {
1174         widget_base_ops ops;
1175
1176         /* override methods */
1177         ops.create = __on_create;
1178         ops.terminate = __on_terminate;
1179         ops.init = __on_init;
1180         ops.finish = __on_finish;
1181         ops.run = __on_run;
1182         ops.exit = __on_exit;
1183         ops.trim_memory = __on_trim_memory;
1184
1185         return ops;
1186 }
1187
1188 static void __free_class(gpointer data)
1189 {
1190         widget_base_class *cls = data;
1191
1192         free(cls->id);
1193         free(cls);
1194 }
1195
1196 EXPORT_API void widget_base_fini(void)
1197 {
1198         appcore_multiwindow_base_fini();
1199         g_list_free_full(__context.classes, __free_class);
1200         __context.classes = NULL;
1201 }
1202
1203 EXPORT_API int widget_base_context_window_bind(
1204                 widget_base_instance_h instance_h, const char *id,
1205                 Ecore_Wl2_Window *wl_win)
1206 {
1207         struct wl_surface *surface;
1208
1209         surface = ecore_wl2_window_surface_get(wl_win);
1210         if (surface == NULL) {
1211                 LOGE("failed to get surface"); /* LCOV_EXCL_LINE */
1212                 return WIDGET_BASE_ERROR_FAULT; /* LCOV_EXCL_LINE */
1213         }
1214
1215         screen_connector_provider_remote_enable(id, surface);
1216         appcore_multiwindow_base_window_bind(instance_h, wl_win);
1217
1218         return WIDGET_BASE_ERROR_NONE;
1219 }
1220
1221 static int __class_on_create(widget_base_instance_h instance_h, bundle *content,
1222                 int w, int h, void *class_data)
1223 {
1224         return widget_base_class_on_create(instance_h, content, w, h);
1225 }
1226
1227 static int __class_on_resume(widget_base_instance_h instance_h, void *class_data)
1228 {
1229         return widget_base_class_on_resume(instance_h);
1230 }
1231
1232 static int __class_on_pause(widget_base_instance_h instance_h,
1233                 void *class_data)
1234 {
1235         return widget_base_class_on_pause(instance_h);
1236 }
1237
1238 static int __class_on_resize(widget_base_instance_h instance_h, int w, int h,
1239                 void *class_data)
1240 {
1241         return widget_base_class_on_resize(instance_h, w, h);
1242 }
1243
1244 static int __class_on_update(widget_base_instance_h instance_h, bundle *content,
1245                 int force, void *class_data)
1246 {
1247         return widget_base_class_on_update(instance_h, content, force);
1248 }
1249
1250 static int __class_on_destroy(widget_base_instance_h instance_h,
1251                 widget_base_destroy_type_e reason, bundle *content,
1252                 void *class_data)
1253 {
1254         return widget_base_class_on_destroy(instance_h, reason, content);
1255 }
1256
1257 static void __multiwindow_instance_create(
1258                 appcore_multiwindow_base_instance_h instance_h,
1259                 void *class_data)
1260 {
1261         widget_base_instance_data *instance_data;
1262         bundle *b;
1263         bundle *content_info = NULL;
1264         char *id = NULL;
1265         char *class_id = NULL;
1266         char *operation = NULL;
1267         char *content = NULL;
1268         char *w_str = NULL;
1269         char *h_str = NULL;
1270         char *remain = NULL;
1271         int w = 0;
1272         int h = 0;
1273         int ret = -1;
1274         widget_base_class *cls;
1275         double *period = NULL;
1276         size_t size;
1277
1278         appcore_multiwindow_base_class_on_create(instance_h);
1279         instance_data = appcore_multiwindow_base_instance_get_extra(instance_h);
1280         b = instance_data->args;
1281
1282         bundle_get_str(b, WIDGET_K_CLASS, &class_id);
1283         /* for previous version compatibility, use appid for default class id */
1284         if (class_id == NULL)
1285                 class_id = __appid;
1286
1287         cls = __get_class(class_id);
1288         if (cls == NULL) {
1289                 LOGE("class not found: %s", class_id);
1290                 return;
1291         }
1292
1293         bundle_get_str(b, AUL_K_WIDGET_INSTANCE_ID, &id);
1294         bundle_get_str(b, WIDGET_K_OPERATION, &operation);
1295
1296         if (!operation) {
1297                 LOGE("no operation provided");
1298                 return;
1299         }
1300
1301         bundle_get_str(b, WIDGET_K_CONTENT_INFO, &content);
1302         bundle_get_str(b, WIDGET_K_WIDTH, &w_str);
1303         bundle_get_str(b, WIDGET_K_HEIGHT, &h_str);
1304
1305         if (w_str)
1306                 w = (int)g_ascii_strtoll(w_str, &remain, 10);
1307
1308         if (h_str)
1309                 h = (int)g_ascii_strtoll(h_str, &remain, 10);
1310
1311         if (content)
1312                 content_info = bundle_decode((const bundle_raw *)content,
1313                                 strlen(content));
1314
1315         if (cls->ops.create)
1316                 ret = cls->ops.create(instance_h, content_info, w, h, class_data);
1317
1318         if (ret < 0) {
1319                 LOGW("Create callback returns error(%d)", ret);
1320                 ret = __send_update_status(class_id, id,
1321                                 WIDGET_INSTANCE_EVENT_CREATE_ABORTED, ret, NULL);
1322                 if (ret < 0)
1323                         LOGE("Fail to send abort status (%d) ", ret);
1324                 __instance_drop(instance_h);
1325         } else {
1326                 LOGD("%s is created", id);
1327                 aul_widget_instance_add(class_id, id);
1328                 ret = __send_update_status(class_id, id,
1329                         WIDGET_INSTANCE_EVENT_CREATE, 0, NULL);
1330                 if (ret < 0)
1331                         LOGE("Fail to send create status (%d) ", ret);
1332
1333                 ret = bundle_get_byte(b, WIDGET_K_PERIOD, (void **)&period,
1334                                 &size);
1335                 if (ret == BUNDLE_ERROR_NONE && *period > 0) {
1336                         LOGI("set periodic update timer (%lf)", *period);
1337                         instance_data->period = *period;
1338                         instance_data->periodic_timer = g_timeout_add_seconds(
1339                                         instance_data->period,
1340                                         __timeout_cb, instance_data);
1341                 }
1342         }
1343
1344         if (content_info)
1345                 bundle_free(content_info);
1346 }
1347
1348 static void __multiwindow_instance_resume(
1349                 appcore_multiwindow_base_instance_h instance_h,
1350                 void *class_data)
1351 {
1352         const char *id;
1353         const char *class_id;
1354         widget_base_class *cls;
1355         widget_base_instance_data *data;
1356
1357         appcore_multiwindow_base_class_on_resume(instance_h);
1358         id = appcore_multiwindow_base_instance_get_id(instance_h);
1359         class_id = appcore_multiwindow_base_instance_get_class_id(instance_h);
1360         cls = __get_class(class_id);
1361         if (cls == NULL) {
1362                 LOGE("class not found: %s", class_id);
1363                 return;
1364         }
1365
1366         data = (widget_base_instance_data *)
1367                         appcore_multiwindow_base_instance_get_extra(instance_h);
1368
1369         if (data->pending_update) {
1370                 LOGD("pending update!");
1371                 data->pending_update = false;
1372                 __call_update_cb(class_id, data->id, 0, data->pending_content);
1373                 if (data->period > 0) {
1374                         LOGD("Restart timer!");
1375                         data->periodic_timer = g_timeout_add_seconds(
1376                                         data->period,
1377                                         __timeout_cb, data);
1378                 }
1379         }
1380
1381         if (cls->ops.resume)
1382                 cls->ops.resume(instance_h, class_data);
1383
1384         LOGD("%s is resumed", id);
1385         __send_update_status(class_id, id,
1386                 WIDGET_INSTANCE_EVENT_RESUME, 0, NULL);
1387
1388         if (!__fg_signal) {
1389                 LOGD("Send fg signal to resourceD");
1390                 aul_widget_instance_change_status(class_id, STATUS_FOREGROUND);
1391                 __fg_signal = true;
1392         }
1393 }
1394
1395 static void __multiwindow_instance_pause(
1396                 appcore_multiwindow_base_instance_h instance_h,
1397                 void *class_data)
1398 {
1399         const char *id;
1400         const char *class_id;
1401         widget_base_class *cls;
1402
1403         appcore_multiwindow_base_class_on_pause(instance_h);
1404         id = appcore_multiwindow_base_instance_get_id(instance_h);
1405         class_id = appcore_multiwindow_base_instance_get_class_id(instance_h);
1406         cls = __get_class(class_id);
1407         if (cls == NULL) {
1408                 LOGE("class not found: %s", class_id);
1409                 return;
1410         }
1411
1412         if (cls->ops.pause)
1413                 cls->ops.pause(instance_h, class_data);
1414
1415         LOGD("%s is paused", id);
1416         __send_update_status(class_id, id,
1417                 WIDGET_INSTANCE_EVENT_PAUSE, 0, NULL);
1418
1419         if (__fg_signal) {
1420                 LOGD("Send bg signal to resourceD");
1421                 aul_widget_instance_change_status(class_id, STATUS_BACKGROUND);
1422                 __fg_signal = false;
1423         }
1424 }
1425
1426 static void __multiwindow_instance_terminate(
1427                 appcore_multiwindow_base_instance_h instance_h,
1428                 void *class_data)
1429 {
1430         widget_base_instance_data *data;
1431         bundle *b;
1432         char *operation = NULL;
1433         bundle *content_info;
1434         widget_base_destroy_type_e reason = WIDGET_BASE_DESTROY_TYPE_TEMPORARY;
1435         int event = WIDGET_INSTANCE_EVENT_TERMINATE;
1436         const char *id;
1437         const char *class_id;
1438         widget_base_class *cls;
1439
1440         id = appcore_multiwindow_base_instance_get_id(instance_h);
1441         class_id = appcore_multiwindow_base_instance_get_class_id(instance_h);
1442         data  = appcore_multiwindow_base_instance_get_extra(
1443                         (appcore_multiwindow_base_instance_h)instance_h);
1444         b = data->args;
1445         cls = __get_class(class_id);
1446         if (cls == NULL) {
1447                 LOGE("class not found: %s", class_id);
1448                 return;
1449         }
1450
1451         if (b) {
1452                 bundle_get_str(b, WIDGET_K_OPERATION, &operation);
1453                 if (operation && strcmp(operation, "destroy") == 0)
1454                         reason = WIDGET_BASE_DESTROY_TYPE_PERMANENT;
1455         }
1456
1457         if (data->content)
1458                 content_info = bundle_decode((const bundle_raw *)data->content,
1459                                 strlen(data->content));
1460         else
1461                 content_info = bundle_create();
1462
1463         if (cls->ops.destroy)
1464                 cls->ops.destroy(instance_h, reason, content_info, class_data);
1465
1466         LOGW("%s is destroyed %d", id, reason);
1467         if (reason == WIDGET_BASE_DESTROY_TYPE_PERMANENT) {
1468                 __is_permanent = true;
1469                 event = WIDGET_INSTANCE_EVENT_DESTROY;
1470                 aul_widget_instance_del(class_id, id);
1471         } else {
1472                 __is_permanent = false;
1473                 __send_update_status(class_id, id,
1474                                 WIDGET_INSTANCE_EVENT_EXTRA_UPDATED, 0,
1475                                 content_info);
1476         }
1477
1478         if (content_info)
1479                 bundle_free(content_info);
1480
1481         if (data->periodic_timer)
1482                 g_source_remove(data->periodic_timer);
1483
1484         __send_update_status(class_id, id, event, 0, NULL);
1485         appcore_multiwindow_base_class_on_terminate(instance_h);
1486 }
1487
1488 EXPORT_API int widget_base_class_on_create(widget_base_instance_h instance_h,
1489                 bundle *content, int w, int h)
1490 {
1491         appcore_multiwindow_base_class_on_create(instance_h);
1492
1493         return 0;
1494 }
1495
1496 EXPORT_API int widget_base_class_on_pause(widget_base_instance_h instance_h)
1497 {
1498         appcore_multiwindow_base_class_on_pause(instance_h);
1499
1500         return 0;
1501 }
1502
1503 EXPORT_API int widget_base_class_on_resume(widget_base_instance_h instance_h)
1504 {
1505         appcore_multiwindow_base_class_on_resume(instance_h);
1506
1507         return 0;
1508 }
1509
1510 EXPORT_API int widget_base_class_on_resize(widget_base_instance_h instance_h,
1511                 int w, int h)
1512 {
1513         return 0;
1514 }
1515
1516 EXPORT_API int widget_base_class_on_update(widget_base_instance_h instance_h,
1517                 bundle *content, int force)
1518 {
1519         return 0;
1520 }
1521
1522 EXPORT_API int widget_base_class_on_destroy(widget_base_instance_h instance_h,
1523                 widget_base_destroy_type_e reason, bundle *content)
1524 {
1525         appcore_multiwindow_base_class_on_terminate(instance_h);
1526
1527         return 0;
1528 }
1529
1530 EXPORT_API widget_base_class widget_base_class_get_default(void)
1531 {
1532         widget_base_class cls;
1533
1534         cls.ops.create = __class_on_create;
1535         cls.ops.resize = __class_on_resize;
1536         cls.ops.update = __class_on_update;
1537         cls.ops.destroy = __class_on_destroy;
1538         cls.ops.pause = __class_on_pause;
1539         cls.ops.resume = __class_on_resume;
1540         cls.id = NULL;
1541
1542         return cls;
1543 }
1544
1545 EXPORT_API widget_base_class *widget_base_class_add(widget_base_class cls,
1546                 const char *class_id, void *class_data)
1547 {
1548         widget_base_class *c;
1549         appcore_multiwindow_base_class raw_cls;
1550
1551         if (!__is_widget_feature_enabled()) {
1552                 LOGE("not supported");
1553                 set_last_result(WIDGET_ERROR_NOT_SUPPORTED);
1554                 return NULL;
1555         }
1556
1557         if (!class_id) {
1558                 LOGE("class id is NULL");
1559                 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
1560                 return NULL;
1561         }
1562
1563         raw_cls.id = strdup(class_id);
1564         raw_cls.data = class_data;
1565         raw_cls.create = __multiwindow_instance_create;
1566         raw_cls.terminate = __multiwindow_instance_terminate;
1567         raw_cls.pause = __multiwindow_instance_pause;
1568         raw_cls.resume = __multiwindow_instance_resume;
1569         appcore_multiwindow_base_class_add(raw_cls);
1570
1571         c = malloc(sizeof(widget_base_class));
1572         if (!c)
1573                 return NULL;
1574
1575         *c = cls;
1576         c->id = strdup(class_id);
1577         __context.classes = g_list_append(__context.classes, c);
1578
1579         return c;
1580 }