X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fwidget_app.c;h=3840ac29fd926ab3506fefde4c57d16699b59362;hb=5fc3c815929af673eeb28d4f0f9fad2ffe2379f4;hp=d337d647f6ffd9d00a5ba97798ef63c96ee42d75;hpb=0d73d4df19bbea7d7d71f055406b51673a409532;p=platform%2Fcore%2Fappfw%2Fappcore-widget.git diff --git a/src/widget_app.c b/src/widget_app.c index d337d64..3840ac2 100755 --- a/src/widget_app.c +++ b/src/widget_app.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ #include +#include #include #include @@ -24,15 +25,16 @@ #include #include #include -#include -#include #include #include #include -#include #include #include #include +#include +#include +#include +#include #include "widget_app.h" #include "widget-log.h" @@ -43,20 +45,32 @@ #undef LOG_TAG #endif -#define STR_MAX_BUF 128 #define LOG_TAG "CAPI_WIDGET_APPLICATION" -#define K_REASON "__WC_K_REASON__" +#define APP_TYPE_WIDGET "widgetapp" +#define STATUS_FOREGROUND "fg" +#define STATUS_BACKGROUND "bg" + +struct widget_extra { + void *extra; + char *instance_id; + bundle *args; + char *content; + Evas_Object *win; +}; -typedef enum _widget_obj_state_e { - WC_READY = 0, - WC_RUNNING = 1, - WC_PAUSED = 2, - WC_TERMINATED = 3 -} widget_obj_state_e; +struct widget_class_context { + widget_instance_lifecycle_callback_s callback; + void *data; +}; -struct app_event_handler { - app_event_type_e type; - app_event_cb cb; +struct widget_app_context { + widget_app_lifecycle_callback_s callback; + void *data; + bool dirty; +}; + +struct widget_foreach_context { + widget_context_cb callback; void *data; }; @@ -65,36 +79,33 @@ struct app_event_info { void *value; }; -struct _widget_class { - void *user_data; - widget_instance_lifecycle_callback_s ops; - char *classid; - struct _widget_class *next; - struct _widget_class *prev; +struct app_event_handler { + app_event_type_e type; + app_event_cb cb; + void *data; + void *raw; }; struct _widget_context { - char *id; - struct _widget_class *provider; - int state; - void *tag; - Evas_Object *win; - bundle *content; - widget_instance_lifecycle_callback_s ops; + int dummy; }; -typedef struct _widget_class widget_class_s; -typedef struct _widget_context widget_context_s; +static int __app_event_converter[APPCORE_BASE_EVENT_MAX] = { + [APP_EVENT_LOW_MEMORY] = APPCORE_BASE_EVENT_LOW_MEMORY, + [APP_EVENT_LOW_BATTERY] = APPCORE_BASE_EVENT_LOW_BATTERY, + [APP_EVENT_LANGUAGE_CHANGED] = APPCORE_BASE_EVENT_LANG_CHANGE, + [APP_EVENT_DEVICE_ORIENTATION_CHANGED] = APPCORE_BASE_EVENT_DEVICE_ORIENTATION_CHANGED, + [APP_EVENT_REGION_FORMAT_CHANGED] = APPCORE_BASE_EVENT_REGION_CHANGE, + [APP_EVENT_SUSPENDED_STATE_CHANGED] = APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE, +}; -static int caller_pid = 0; -static widget_app_lifecycle_callback_s *app_ops; -static void *app_user_data = NULL; -static char *appid = NULL; -static widget_class_h class_provider = NULL; -static GList *contexts = NULL; -static char *viewer_endpoint = NULL; +static struct widget_app_context __context; +static char *__appid; +static char *__package_id; +static bool __fg_signal; +char *_viewer_endpoint; -static inline bool _is_widget_feature_enabled(void) +static bool __is_widget_feature_enabled(void) { static bool feature = false; static bool retrieved = false; @@ -106,8 +117,8 @@ static inline bool _is_widget_feature_enabled(void) ret = system_info_get_platform_bool( "http://tizen.org/feature/shell.appwidget", &feature); if (ret != SYSTEM_INFO_ERROR_NONE) { - _E("failed to get system info"); - return false; + _E("failed to get system info"); /* LCOV_EXCL_LINE */ + return false; /* LCOV_EXCL_LINE */ } retrieved = true; @@ -115,407 +126,599 @@ static inline bool _is_widget_feature_enabled(void) return feature; } -static gint __comp_by_id(gconstpointer a, gconstpointer b) +/* LCOV_EXCL_START */ +static void __on_poweroff(keynode_t *key, void *data) { - widget_context_s *wc = (widget_context_s *)a; + int val; - return strcmp(wc->id, (const char *)b); + val = vconf_keynode_get_int(key); + switch (val) { + case VCONFKEY_SYSMAN_POWER_OFF_DIRECT: + case VCONFKEY_SYSMAN_POWER_OFF_RESTART: + _I("power off changed: %d", val); + widget_app_exit(); + break; + case VCONFKEY_SYSMAN_POWER_OFF_NONE: + case VCONFKEY_SYSMAN_POWER_OFF_POPUP: + default: + /* DO NOTHING */ + break; + } } +/* LCOV_EXCL_STOP */ -static widget_context_s *__find_context_by_id(const char *id) +static int __widget_app_create(void *data) { - GList *ret = g_list_find_custom(contexts, id, __comp_by_id); + char pkgid[256] = {0, }; - if (ret == NULL) - return NULL; + appcore_multiwindow_base_on_create(); + app_get_id(&__appid); + if (aul_app_get_pkgid_bypid(getpid(), pkgid, sizeof(pkgid)) == 0) + __package_id = strdup(pkgid); + + if (!__package_id || !__appid) { + _E("__package_id is NULL"); + return -1; + } + + screen_connector_provider_init(); + vconf_notify_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, __on_poweroff, NULL); - return ret->data; + if (__context.callback.create == NULL) { + _E("__context.callback.create(is NULL"); + return -1; + } + + if (__context.callback.create(__context.data) == NULL) { + _E("app_create_cb() returns NULL"); + return -1; + } + + _D("widget app is created"); + return 0; } -static int __send_update_status(const char *class_id, const char *instance_id, - int status, bundle *extra, int internal_only) +static int __widget_app_terminate(void *data) { - bundle *b = extra; + if (__context.callback.terminate) + __context.callback.terminate(__context.data); - if (b == NULL) - b = bundle_create(); + vconf_ignore_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, __on_poweroff); + screen_connector_provider_fini(); - bundle_add_str(b, WIDGET_K_ID, class_id); - bundle_add_str(b, WIDGET_K_INSTANCE, instance_id); - bundle_add_byte(b, WIDGET_K_STATUS, &status, sizeof(int)); + if (_viewer_endpoint) { + free(_viewer_endpoint); + _viewer_endpoint = NULL; + } + + if (__package_id) { + free(__package_id); + __package_id = NULL; + } - _E("send update %s(%d) to %s", instance_id, status, viewer_endpoint); - aul_app_com_send(viewer_endpoint, b); + if (__appid) { + free(__appid); + __appid = NULL; + } - if (extra == NULL) - bundle_free(b); + appcore_multiwindow_base_on_terminate(); + _D("widget app is terminated"); return 0; } -static int __instance_create(widget_class_h handle, const char *id, bundle *b) +static int __send_lifecycle_event(const char *class_id, const char *instance_id, + int status) { - widget_context_s *wc = NULL; - int w = 0, h = 0; - char *w_str = NULL, *h_str = NULL; - char *remain = NULL; - int ret = 0; - - wc = (widget_context_s *)malloc(sizeof(widget_context_s)); - if (!wc) - return WIDGET_ERROR_OUT_OF_MEMORY; - - wc->state = WC_READY; - wc->id = g_strdup(id); - wc->provider = handle; - wc->win = NULL; - - wc->content = bundle_dup(b); - bundle_get_str(b, WIDGET_K_WIDTH, &w_str); - bundle_get_str(b, WIDGET_K_HEIGHT, &h_str); + bundle *b = bundle_create(); + int ret; - if (w_str) - w = (int)g_ascii_strtoll(w_str, &remain, 10); + if (b == NULL) { + _E("out of memory"); /* LCOV_EXCL_LINE */ + return -1; /* LCOV_EXCL_LINE */ + } - if (h_str) - h = (int)g_ascii_strtoll(h_str, &remain, 10); + bundle_add_str(b, AUL_K_WIDGET_ID, class_id); + bundle_add_str(b, AUL_K_WIDGET_INSTANCE_ID, instance_id); + bundle_add_byte(b, AUL_K_WIDGET_STATUS, &status, sizeof(int)); + bundle_add_str(b, AUL_K_PKGID, __package_id); - contexts = g_list_append(contexts, wc); + _D("send lifecycle %s(%d)", instance_id, status); + ret = aul_app_com_send("widget.status", b); + if (ret < 0) + _E("send lifecycle error:%d", ret); /* LCOV_EXCL_LINE */ - handle->ops.create(wc, b, w, h, handle->user_data); - ret = __send_update_status(handle->classid, wc->id, - WIDGET_INSTANCE_EVENT_CREATE, b, 0); + bundle_free(b); return ret; } -static int __instance_destroy(widget_class_h handle, const char *id, - widget_destroy_type_e reason, bundle *b) +static int __send_update_status(const char *class_id, const char *instance_id, + int status, bundle *extra) { - widget_context_s *wc = __find_context_by_id(id); - int ret = 0; + bundle *b; + int lifecycle = -1; + bundle_raw *raw = NULL; + int len; + + b = bundle_create(); + if (!b) { + _E("out of memory"); /* LCOV_EXCL_LINE */ + return -1; /* LCOV_EXCL_LINE */ + } - if (wc) { - wc->state = WC_TERMINATED; - handle->ops.destroy(wc, (widget_app_destroy_type_e)reason, b, - handle->user_data); + bundle_add_str(b, AUL_K_WIDGET_ID, class_id); + bundle_add_str(b, AUL_K_WIDGET_INSTANCE_ID, instance_id); + bundle_add_byte(b, AUL_K_WIDGET_STATUS, &status, sizeof(int)); - ret = __send_update_status(handle->classid, id, - WIDGET_INSTANCE_EVENT_TERMINATE, b, 0); + if (extra) { + bundle_encode(extra, &raw, &len); + bundle_add_str(b, WIDGET_K_CONTENT_INFO, (const char *)raw); + aul_widget_instance_add(class_id, instance_id); + } - contexts = g_list_remove(contexts, wc); + _D("send update %s(%d) to %s", instance_id, status, _viewer_endpoint); + aul_app_com_send(_viewer_endpoint, b); - if (wc->id) - free(wc->id); - free(wc); - } else { - _E("could not find widget obj: %s", id); - ret = WIDGET_ERROR_INVALID_PARAMETER; + switch (status) { + case WIDGET_INSTANCE_EVENT_CREATE: + lifecycle = WIDGET_LIFE_CYCLE_EVENT_CREATE; + break; + case WIDGET_INSTANCE_EVENT_DESTROY: + lifecycle = WIDGET_LIFE_CYCLE_EVENT_DESTROY; + break; + case WIDGET_INSTANCE_EVENT_PAUSE: + lifecycle = WIDGET_LIFE_CYCLE_EVENT_PAUSE; + break; + case WIDGET_INSTANCE_EVENT_RESUME: + lifecycle = WIDGET_LIFE_CYCLE_EVENT_RESUME; + break; } - return ret; + if (lifecycle > -1) + __send_lifecycle_event(class_id, instance_id, lifecycle); + + bundle_free(b); + if (raw) + free(raw); + + return 0; } -static widget_class_h __find_class_handler(const char *class_id, - widget_class_h handle) +static void __instance_resume(const char *class_id, const char *id, bundle *b) { - if (!class_id || !handle) - return NULL; + appcore_multiwindow_base_instance_h cxt; - widget_class_h head = handle; + cxt = appcore_multiwindow_base_instance_find(id); - while (head) { - if (head->classid && strcmp(head->classid, class_id) == 0) - return head; + if (!cxt) { + _E("context not found: %s", id); + return; + } + + appcore_multiwindow_base_instance_resume(cxt); + + __send_update_status(class_id, id, + WIDGET_INSTANCE_EVENT_RESUME, NULL); + if (!__fg_signal) { + _D("Send fg signal to resourceD"); + aul_send_app_status_change_signal(getpid(), + __appid, + __package_id, + STATUS_FOREGROUND, + APP_TYPE_WIDGET); + __fg_signal = true; + } +} + +static void __instance_pause(const char *class_id, const char *id, bundle *b) +{ + appcore_multiwindow_base_instance_h cxt; - head = head->next; + cxt = appcore_multiwindow_base_instance_find(id); + + if (!cxt) { + _E("context not found: %s", id); + return; } - return NULL; + appcore_multiwindow_base_instance_pause(cxt); + + if (__fg_signal) { + _D("Send bg signal to resourceD"); + aul_send_app_status_change_signal(getpid(), + __appid, + __package_id, + STATUS_BACKGROUND, + APP_TYPE_WIDGET); + __fg_signal = false; + } } -static void __control(bundle *b) +static void __instance_resize(const char *class_id, const char *id, bundle *b) { - char *class_id = NULL; - char *id = NULL; - char *operation = NULL; - char *reason = NULL; + appcore_multiwindow_base_instance_h cxt; + struct widget_class_context *class_cxt; + const appcore_multiwindow_base_class *cls; + struct widget_extra *we; char *remain = NULL; - int destroy_type = WIDGET_DESTROY_TYPE_DEFAULT; + char *w_str = NULL; + char *h_str = NULL; + int w = 0; + int h = 0; - widget_class_h handle = NULL; - bundle_get_str(b, WIDGET_K_CLASS, &class_id); - /* for previous version compatibility, use appid for default class id */ - if (class_id == NULL) - class_id = appid; + cxt = appcore_multiwindow_base_instance_find(id); - bundle_get_str(b, WIDGET_K_INSTANCE, &id); - bundle_get_str(b, WIDGET_K_OPERATION, &operation); + if (!cxt) { + _E("context not found: %s", id); + return; + } + + cls = appcore_multiwindow_base_instance_get_class(cxt); + if (!cls) + return; - handle = __find_class_handler(class_id, class_provider); - if (!handle) { - _E("no handle provided: %s", class_id); - goto error; + class_cxt = cls->data; + if (!class_cxt) { + _E("class is NULL"); + return; } - if (!operation) { - _E("no operation provided"); - goto error; + we = appcore_multiwindow_base_instance_get_extra(cxt); + if (!we) { + _E("widget extra is NULL"); + return; } - if (strcmp(operation, "create") == 0) { - __instance_create(handle, id, b); - } else if (strcmp(operation, "resize") == 0) { - /* TODO */ - } else if (strcmp(operation, "update") == 0) { - /* TODO */ - } else if (strcmp(operation, "destroy") == 0) { - bundle_get_str(b, WIDGET_K_REASON, &reason); - if (reason) - destroy_type = (int)g_ascii_strtoll(reason, &remain, - 10); + bundle_get_str(b, WIDGET_K_WIDTH, &w_str); + bundle_get_str(b, WIDGET_K_HEIGHT, &h_str); - __instance_destroy(handle, id, destroy_type, b); - } else if (strcmp(operation, "resume") == 0) { - /* TODO */ - } else if (strcmp(operation, "pause") == 0) { - /* TODO */ - } + if (w_str) + w = (int)g_ascii_strtoll(w_str, &remain, 10); - return; -error: - LOGD("error on control"); - return; -} + if (h_str) + h = (int)g_ascii_strtoll(h_str, &remain, 10); -static void __show_all() -{ - LOGD("resume"); + if (we->win) + evas_object_resize(we->win, w, h); + else + _E("unable to find window of %s", id); + + if (class_cxt->callback.resize) + class_cxt->callback.resize(cxt, w, h, class_cxt->data); + _D("%s is resized to %dx%d", id, w, h); + __send_update_status(class_id, id, + WIDGET_INSTANCE_EVENT_SIZE_CHANGED, NULL); } -static int __aul_handler(aul_type type, bundle *b, void *data) +static void __inst_cb(const char *class_id, const char *id, + appcore_multiwindow_base_instance_h cxt, void *data) { - char *caller = NULL; - char *remain = NULL; + struct widget_class_context *class_cxt; + const appcore_multiwindow_base_class *cls; + bundle *content = NULL; + char *content_raw = NULL; + char *force_str = NULL; + int force; + bundle *b = data; + + if (!b) { + _E("bundle is NULL"); + return; + } - switch (type) { - case AUL_START: - if (b) { - bundle_get_str(b, WIDGET_K_CALLER, &caller); - if (caller) { - caller_pid = g_ascii_strtoll(caller, &remain, - 10); - } else { - /* using caller appid and query pid using caller appid? */ - _E("no caller pid"); - } - } + cls = appcore_multiwindow_base_instance_get_class(cxt); + if (!cls) { + _E("class is NULL"); + return; + } - __control(b); - break; - case AUL_RESUME: - __show_all(); - break; - case AUL_TERMINATE: - widget_app_exit(); - break; - default: - break; + class_cxt = cls->data; + if (!class_cxt) { + _E("class context is NULL"); + return; } - return 0; + if (!class_cxt->callback.update) { + _E("update callback is NULL"); + return; + } + + bundle_get_str(b, WIDGET_K_FORCE, &force_str); + + if (force_str && strcmp(force_str, "true") == 0) + force = 1; + else + force = 0; + + bundle_get_str(b, WIDGET_K_CONTENT_INFO, &content_raw); + + if (content_raw) + content = bundle_decode((const bundle_raw *)content_raw, strlen(content_raw)); + class_cxt->callback.update(cxt, content, force, class_cxt->data); + __send_update_status(class_id, id, + WIDGET_INSTANCE_EVENT_UPDATE, NULL); + _D("updated:%s", id); + + if (content) + bundle_free(content); } -static char *__get_domain_name(char *appid) +static void __instance_update(const char *class_id, const char *id, bundle *b) { - char *name_token; + appcore_multiwindow_base_instance_h cxt; - if (appid == NULL) { - _E("appid is NULL"); - return NULL; + if (!id) { + appcore_multiwindow_base_instance_foreach(class_id, __inst_cb, b); + return; } - name_token = strrchr(appid, '.'); + cxt = appcore_multiwindow_base_instance_find(id); - if (name_token == NULL) { - _E("appid is invalid"); - return appid; + if (!cxt) { + _E("context not found: %s", id); + return; } - name_token++; - - return name_token; + __inst_cb(class_id, id, cxt, b); } -extern int _set_i18n(const char *name); - -static int __before_loop(int argc, char **argv) +static void __instance_create(const char *class_id, const char *id, bundle *b) { - int r; - bundle *kb = NULL; - char *wayland_display = NULL; - char *xdg_runtime_dir = NULL; - char *name; + struct widget_extra *we; + char *content = NULL; -#if !(GLIB_CHECK_VERSION(2, 36, 0)) - g_type_init(); -#endif + we = (struct widget_extra *)calloc(1, sizeof(struct widget_extra)); + if (!we) { + _E("Out of memory"); + return; + } - kb = bundle_import_from_argv(argc, argv); - if (kb) { - bundle_get_str(kb, AUL_K_WAYLAND_WORKING_DIR, &xdg_runtime_dir); - bundle_get_str(kb, AUL_K_WAYLAND_DISPLAY, &wayland_display); - bundle_get_str(kb, WIDGET_K_ENDPOINT, &viewer_endpoint); - if (viewer_endpoint) { - _E("viewer endpoint :%s", viewer_endpoint); - viewer_endpoint = strdup(viewer_endpoint); - } else { - _E("endpoint is missing"); - } + we->instance_id = strdup(id); + we->args = b; + appcore_multiwindow_base_instance_run(class_id, id, we); + we->args = NULL; + we->win = NULL; + bundle_get_str(b, WIDGET_K_CONTENT_INFO, &content); + if (content) + we->content = strdup(content); - if (xdg_runtime_dir) - setenv("XDG_RUNTIME_DIR", xdg_runtime_dir, 1); +} - if (wayland_display) - setenv("WAYLAND_DISPLAY", wayland_display, 1); +static void __check_empty_instance(void) +{ + int cnt = appcore_multiwindow_base_instance_get_cnt(); - bundle_free(kb); - kb = NULL; - } else { - _E("failed to get launch argv"); + if (cnt == 0) + widget_app_exit(); +} + +static void __instance_destroy(const char *class_id, const char *id, bundle *b) +{ + appcore_multiwindow_base_instance_h cxt; + struct widget_extra *we; + + cxt = appcore_multiwindow_base_instance_find(id); + if (!cxt) { + _E("could not find widget obj: %s, clear amd info", id); + aul_widget_instance_del(class_id, id); + return; } - elm_init(argc, argv); + we = appcore_multiwindow_base_instance_get_extra(cxt); + we->args = b; + appcore_multiwindow_base_instance_exit(cxt); + free(we->instance_id); + free(we->content); + free(we); + __check_empty_instance(); +} - r = aul_launch_init(__aul_handler, NULL); - if (r < 0) { - return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, - __FUNCTION__, - "Fail to call the aul_launch_init"); +static int __widget_app_control(bundle *b, void *data) +{ + char *class_id = NULL; + char *id = NULL; + char *operation = NULL; + + appcore_multiwindow_base_on_control(b); + + bundle_get_str(b, WIDGET_K_CLASS, &class_id); + /* for previous version compatibility, use appid for default class id */ + if (class_id == NULL) + class_id = __appid; + + bundle_get_str(b, AUL_K_WIDGET_INSTANCE_ID, &id); + bundle_get_str(b, WIDGET_K_OPERATION, &operation); + + if (!operation) { + _E("operation is NULL"); + return 0; } - r = aul_launch_argv_handler(argc, argv); - if (r < 0) { - return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, - __FUNCTION__, - "Fail to call the aul_launch_argv_handler"); + if (strcmp(operation, "create") == 0) { + __instance_create(class_id, id, b); + } else if (strcmp(operation, "resize") == 0) { + __instance_resize(class_id, id, b); + } else if (strcmp(operation, "update") == 0) { + __instance_update(class_id, id, b); + } else if (strcmp(operation, "destroy") == 0) { + __instance_destroy(class_id, id, b); + } else if (strcmp(operation, "resume") == 0) { + __instance_resume(class_id, id, b); + } else if (strcmp(operation, "pause") == 0) { + __instance_pause(class_id, id, b); + } else if (strcmp(operation, "terminate") == 0) { + __instance_destroy(class_id, id, b); } - r = app_get_id(&appid); - if (r != APP_ERROR_NONE) - return r; + return 0; +} - name = __get_domain_name(appid); +static void __inst_resume_cb(const char *class_id, const char *id, + appcore_multiwindow_base_instance_h cxt, void *data) +{ + __instance_resume(class_id, id, data); +} - if (name == NULL) { - return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, - __FUNCTION__, - "Fail to call __get_domain_name"); +static void __get_content(bundle *b) +{ + char *instance_id = NULL; + appcore_multiwindow_base_instance_h cxt; + struct widget_extra *we; + + bundle_get_str(b, AUL_K_WIDGET_INSTANCE_ID, &instance_id); + if (!instance_id) { + _E("instance id is NULL"); + return; } - r = _set_i18n(name); - - if (r < 0) { - return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, - __FUNCTION__, - "Fail to call _set_i18n"); + cxt = appcore_multiwindow_base_instance_find(instance_id); + if (!cxt) { + _E("could not find widget obj: %s", instance_id); + return; } - class_provider = app_ops->create(app_user_data); - if (class_provider == NULL) { - return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, - __FUNCTION__, "widget_class is NULL"); + we = appcore_multiwindow_base_instance_get_extra(cxt); + if (!we) { + _E("widget extra is NULL"); + return; } - return WIDGET_ERROR_NONE; + if (we->content) { + bundle_add_str(b, AUL_K_WIDGET_CONTENT_INFO, we->content); + _D("content info of %s found", instance_id); + } else { + bundle_add_str(b, AUL_K_WIDGET_CONTENT_INFO, ""); + _D("empty content info added"); + } } -static void __after_loop() +static int __widget_app_receive(aul_type type, bundle *b, void *data) { - if (app_ops->terminate) - app_ops->terminate(app_user_data); + appcore_multiwindow_base_on_receive(type, b); - if (viewer_endpoint) - free(viewer_endpoint); + switch (type) { + case AUL_RESUME: + appcore_multiwindow_base_instance_foreach_full(__inst_resume_cb, b); + break; + case AUL_TERMINATE: + widget_app_exit(); + break; + case AUL_WIDGET_CONTENT: + __get_content(b); + break; + default: + break; + } - elm_shutdown(); + return 0; } EXPORT_API int widget_app_main(int argc, char **argv, widget_app_lifecycle_callback_s *callback, void *user_data) { - int r; + bundle *kb; + char *viewer_endpoint = NULL; - if (!_is_widget_feature_enabled()) { - _E("not supported"); - return WIDGET_ERROR_NOT_SUPPORTED; + if (!__is_widget_feature_enabled()) { + _E("not supported"); /* LCOV_EXCL_LINE */ + return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */ } if (argc <= 0 || argv == NULL || callback == NULL) return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL); + if (__context.dirty) { + _E("Already started"); + return widget_app_error(WIDGET_ERROR_FAULT, __FUNCTION__, NULL); + } + if (callback->create == NULL) return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, "widget_app_create_cb() callback must be " "registered"); - app_ops = callback; - app_user_data = user_data; - r = __before_loop(argc, argv); - if (r < 0) - return r; + appcore_multiwindow_base_ops ops = appcore_multiwindow_base_get_default_ops(); - ecore_main_loop_begin(); - aul_status_update(STATUS_DYING); - __after_loop(); + /* override methods */ + ops.base.create = __widget_app_create; + ops.base.control = __widget_app_control; + ops.base.terminate = __widget_app_terminate; + ops.base.receive = __widget_app_receive; + __context.callback = *callback; + __context.data = user_data; + kb = bundle_import_from_argv(argc, argv); + if (kb) { + bundle_get_str(kb, WIDGET_K_ENDPOINT, &viewer_endpoint); + if (viewer_endpoint) { + _D("viewer endpoint :%s", viewer_endpoint); + _viewer_endpoint = strdup(viewer_endpoint); + } else { + _E("endpoint is missing"); + } + + bundle_free(kb); + } else { + _E("failed to get launch argv"); /* LCOV_EXCL_LINE */ + return widget_app_error(WIDGET_ERROR_FAULT, __FUNCTION__, NULL); + } + + __context.dirty = true; + appcore_multiwindow_base_init(ops, argc, argv, NULL); + appcore_multiwindow_base_fini(); + __context.dirty = false; return WIDGET_ERROR_NONE; } EXPORT_API int widget_app_exit(void) { - if (!_is_widget_feature_enabled()) { - _E("not supported"); - return WIDGET_ERROR_NOT_SUPPORTED; + if (!__is_widget_feature_enabled()) { + _E("not supported"); /* LCOV_EXCL_LINE */ + return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */ } - ecore_main_loop_quit(); + appcore_multiwindow_base_exit(); + aul_widget_notify_exit(); return WIDGET_ERROR_NONE; } static gboolean __finish_event_cb(gpointer user_data) { - if (user_data == NULL) - return FALSE; + appcore_multiwindow_base_instance_h cxt = user_data; + bundle *b; + const char *id; + const char *class_id; - widget_context_s *wc = (widget_context_s *)user_data; - - switch (wc->state) { - case WC_READY: - - break; - case WC_RUNNING: + if (!cxt) { + _E("user_data is NULL"); + return FALSE; + } - break; - case WC_PAUSED: + id = appcore_multiwindow_base_instance_get_id(cxt); + class_id = appcore_multiwindow_base_instance_get_class_id(cxt); + b = bundle_create(); - break; - default: - break; + if (!b) { + _E("Out-of-memory"); + return FALSE; } + bundle_add_str(b, WIDGET_K_OPERATION, "terminate"); + __instance_destroy(class_id, id, b); + bundle_free(b); return FALSE; } EXPORT_API int widget_app_terminate_context(widget_context_h context) { - if (!_is_widget_feature_enabled()) { - _E("not supported"); - return WIDGET_ERROR_NOT_SUPPORTED; + if (!__is_widget_feature_enabled()) { + _E("not supported"); /* LCOV_EXCL_LINE */ + return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */ } if (context == NULL) @@ -526,44 +729,89 @@ EXPORT_API int widget_app_terminate_context(widget_context_h context) return WIDGET_ERROR_NONE; } +static void __inst_full_cb(const char *class_id, const char *id, + appcore_multiwindow_base_instance_h cxt, void *data) +{ + struct widget_foreach_context *foreach_context = data; + + if (!data) + return; + + if (foreach_context->callback) + foreach_context->callback(cxt, foreach_context->data); +} + EXPORT_API int widget_app_foreach_context(widget_context_cb cb, void *data) { - if (!_is_widget_feature_enabled()) { - _E("not supported"); - return WIDGET_ERROR_NOT_SUPPORTED; + struct widget_foreach_context foreach_context; + + if (!__is_widget_feature_enabled()) { + _E("not supported"); /* LCOV_EXCL_LINE */ + return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */ } - if (!cb) + if (!cb) { + _E("callback is NULL"); return WIDGET_ERROR_INVALID_PARAMETER; + } + + foreach_context.callback = cb; + foreach_context.data = data; + appcore_multiwindow_base_instance_foreach_full(__inst_full_cb, &foreach_context); return WIDGET_ERROR_NONE; } +int __event_cb(void *event, void *data) +{ + app_event_handler_h handler = data; + + struct app_event_info app_event; + + app_event.type = handler->type; + app_event.value = event; + + if (handler->cb) + handler->cb(&app_event, handler->data); + + return 0; +} + EXPORT_API int widget_app_add_event_handler(app_event_handler_h *event_handler, - app_event_type_e event_type, app_event_cb callback, - void *user_data) + app_event_type_e event_type, app_event_cb callback, + void *user_data) { - if (!_is_widget_feature_enabled()) { - _E("not supported"); + int r; + bool feature; + app_event_handler_h handler; + + r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature); + if (r < 0) + return WIDGET_ERROR_FAULT; + + if (!feature) return WIDGET_ERROR_NOT_SUPPORTED; - } - /* TODO */ - if (!event_handler || !callback) - return WIDGET_ERROR_INVALID_PARAMETER; + if (event_handler == NULL || callback == NULL) + return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL); - switch (event_type) { - case APP_EVENT_LOW_MEMORY: - case APP_EVENT_LOW_BATTERY: - case APP_EVENT_LANGUAGE_CHANGED: - case APP_EVENT_DEVICE_ORIENTATION_CHANGED: - case APP_EVENT_REGION_FORMAT_CHANGED: - case APP_EVENT_SUSPENDED_STATE_CHANGED: + if (event_type < APP_EVENT_LOW_MEMORY + || event_type > APP_EVENT_REGION_FORMAT_CHANGED) + return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL); + + if (event_type == APP_EVENT_DEVICE_ORIENTATION_CHANGED) + return widget_app_error(WIDGET_ERROR_NOT_SUPPORTED, __FUNCTION__, NULL); - break; - default: - return WIDGET_ERROR_INVALID_PARAMETER; - } + + handler = calloc(1, sizeof(struct app_event_handler)); + if (!handler) + return widget_app_error(WIDGET_ERROR_OUT_OF_MEMORY, __FUNCTION__, "failed to create handler"); + + handler->type = event_type; + handler->cb = callback; + handler->data = user_data; + handler->raw = appcore_base_add_event(__app_event_converter[event_type], __event_cb, handler); + *event_handler = handler; return WIDGET_ERROR_NONE; } @@ -571,24 +819,40 @@ EXPORT_API int widget_app_add_event_handler(app_event_handler_h *event_handler, EXPORT_API int widget_app_remove_event_handler(app_event_handler_h event_handler) { - if (!_is_widget_feature_enabled()) { - _E("not supported"); + int r; + bool feature; + + r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature); + if (r < 0) + return WIDGET_ERROR_FAULT; + + if (!feature) return WIDGET_ERROR_NOT_SUPPORTED; - } - /* TODO */ - if (!event_handler) - return WIDGET_ERROR_INVALID_PARAMETER; + app_event_type_e type; + + if (event_handler == NULL) + return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL); + + type = event_handler->type; + if (type < APP_EVENT_LOW_MEMORY || type > APP_EVENT_REGION_FORMAT_CHANGED) + return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL); + + r = appcore_base_remove_event(event_handler->raw); + if (r < 0) + return widget_app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "invalid raw handler"); + + free(event_handler); return WIDGET_ERROR_NONE; } EXPORT_API const char *widget_app_get_id(widget_context_h context) { - if (!_is_widget_feature_enabled()) { - _E("not supported"); - set_last_result(WIDGET_ERROR_NOT_SUPPORTED); - return NULL; + if (!__is_widget_feature_enabled()) { + _E("not supported"); /* LCOV_EXCL_LINE */ + set_last_result(WIDGET_ERROR_NOT_SUPPORTED); /* LCOV_EXCL_LINE */ + return NULL; /* LCOV_EXCL_LINE */ } if (!context) { @@ -596,125 +860,344 @@ EXPORT_API const char *widget_app_get_id(widget_context_h context) return NULL; } - return context->id; + set_last_result(WIDGET_ERROR_NONE); + return appcore_multiwindow_base_instance_get_id(context); +} + +static void __win_del_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + char *plug_id; + plug_id = evas_object_data_del(obj, "___PLUGID"); + free(plug_id); } EXPORT_API int widget_app_get_elm_win(widget_context_h context, Evas_Object **win) { - widget_context_s *cxt = (widget_context_s *)context; Evas_Object *ret_win; Ecore_Wl_Window *wl_win; - - if (!_is_widget_feature_enabled()) { - _E("not supported"); - return WIDGET_ERROR_NOT_SUPPORTED; + struct wl_surface *surface; + struct widget_extra *we; + char buffer[256]; + int rots[3] = {0}; + int win_id; + const char *id; + appcore_multiwindow_base_instance_h cxt; + + if (!__is_widget_feature_enabled()) { + _E("not supported"); /* LCOV_EXCL_LINE */ + return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */ } if (context == NULL || win == NULL) return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL); - ret_win = elm_win_add(NULL, cxt->id, ELM_WIN_BASIC); + cxt = (appcore_multiwindow_base_instance_h)context; + id = appcore_multiwindow_base_instance_get_id(cxt); + ret_win = elm_win_add(NULL, id, ELM_WIN_BASIC); if (ret_win == NULL) { - _E("failed to create window"); - return WIDGET_ERROR_FAULT; + _E("failed to create window"); /* LCOV_EXCL_LINE */ + goto fault; /* LCOV_EXCL_LINE */ } + elm_win_wm_rotation_preferred_rotation_set(ret_win, -1); + elm_win_wm_rotation_available_rotations_set(ret_win, rots, 1); + wl_win = elm_win_wl_window_get(ret_win); if (wl_win == NULL) { - _E("failed to get wayland window"); - evas_object_del(ret_win); - return WIDGET_ERROR_FAULT; + _E("failed to get wayland window"); /* LCOV_EXCL_LINE */ + goto fault; + } + + surface = ecore_wl_window_surface_get(wl_win); + if (surface == NULL) { + _E("failed to get surface"); /* LCOV_EXCL_LINE */ + goto fault; /* LCOV_EXCL_LINE */ } + screen_connector_provider_remote_enable(id, surface); - ecore_wl_window_class_name_set(wl_win, cxt->id); + ecore_wl_window_class_name_set(wl_win, id); + elm_win_aux_hint_add(ret_win, "wm.policy.win.user.geometry", "1"); *win = ret_win; - cxt->win = ret_win; + we = appcore_multiwindow_base_instance_get_extra(cxt); + we->win = ret_win; + win_id = ecore_wl_window_id_get(wl_win); + + /* Set data to use in accessibility */ + snprintf(buffer, sizeof(buffer), "%s:%d", id, getpid()); + evas_object_data_set(ret_win, "___PLUGID", strdup(buffer)); + evas_object_event_callback_add(ret_win, EVAS_CALLBACK_DEL, __win_del_cb, NULL); + appcore_multiwindow_base_window_bind(cxt, ret_win); + + _D("window created: %d", win_id); return WIDGET_ERROR_NONE; + +fault: + if (ret_win) /* LCOV_EXCL_LINE */ + evas_object_del(ret_win); /* LCOV_EXCL_LINE */ + + return WIDGET_ERROR_FAULT; /* LCOV_EXCL_LINE */ +} + +static void __instance_drop(appcore_multiwindow_base_instance_h cxt) +{ + struct widget_extra *we; + + we = appcore_multiwindow_base_instance_get_extra(cxt); + appcore_multiwindow_base_instance_drop(cxt); + free(we->instance_id); + free(we->content); + free(we); + __check_empty_instance(); } -widget_class_h _widget_class_create(widget_class_s *prev, const char *class_id, +static void __stub_create(appcore_multiwindow_base_instance_h context, void *data) +{ + struct widget_class_context *cxt = data; + struct widget_extra *we; + bundle *b; + bundle *content_info = NULL; + char *id = NULL; + char *class_id = NULL; + char *operation = NULL; + char *content = NULL; + char *w_str = NULL; + char *h_str = NULL; + char *remain = NULL; + int w = 0; + int h = 0; + int ret = -1; + + appcore_multiwindow_base_class_on_create(context); + we = appcore_multiwindow_base_instance_get_extra((appcore_multiwindow_base_instance_h)context); + b = we->args; + + bundle_get_str(b, WIDGET_K_CLASS, &class_id); + /* for previous version compatibility, use appid for default class id */ + if (class_id == NULL) + class_id = __appid; + + bundle_get_str(b, AUL_K_WIDGET_INSTANCE_ID, &id); + bundle_get_str(b, WIDGET_K_OPERATION, &operation); + + if (!operation) { + _E("no operation provided"); + return; + } + + bundle_get_str(b, WIDGET_K_CONTENT_INFO, &content); + bundle_get_str(b, WIDGET_K_WIDTH, &w_str); + bundle_get_str(b, WIDGET_K_HEIGHT, &h_str); + + if (w_str) + w = (int)g_ascii_strtoll(w_str, &remain, 10); + + if (h_str) + h = (int)g_ascii_strtoll(h_str, &remain, 10); + + if (content) + content_info = bundle_decode((const bundle_raw *)content, strlen(content)); + + if (cxt->callback.create) + ret = cxt->callback.create(context, content_info, w, h, cxt->data); + _D("%s is created %d", id); + + if (ret < 0) { + _W("Create callback returns error(%d)", ret); + ret = __send_update_status(class_id, id, + WIDGET_INSTANCE_EVENT_CREATE_ABORTED, NULL); + __instance_drop(context); + } else { + ret = __send_update_status(class_id, id, + WIDGET_INSTANCE_EVENT_CREATE, NULL); + + aul_widget_instance_add(class_id, id); + } + + if (content_info) + bundle_free(content_info); +} + +static void __stub_terminate(appcore_multiwindow_base_instance_h context, void *data) +{ + struct widget_class_context *class_cxt = data; + struct widget_extra *we; + bundle *b; + char *operation = NULL; + bundle *content_info; + widget_app_destroy_type_e reason = WIDGET_APP_DESTROY_TYPE_TEMPORARY; + int event = WIDGET_INSTANCE_EVENT_TERMINATE; + const char *id; + const char *class_id; + + id = appcore_multiwindow_base_instance_get_id(context); + class_id = appcore_multiwindow_base_instance_get_class_id(context); + we = appcore_multiwindow_base_instance_get_extra((appcore_multiwindow_base_instance_h)context); + b = we->args; + + if (b) { + bundle_get_str(b, WIDGET_K_OPERATION, &operation); + if (operation && strcmp(operation, "destroy") == 0) + reason = WIDGET_APP_DESTROY_TYPE_PERMANENT; + } + + if (we->content) + content_info = bundle_decode((const bundle_raw *)we->content, strlen(we->content)); + else + content_info = bundle_create(); + + if (class_cxt->callback.destroy) + class_cxt->callback.destroy(context, reason, content_info, class_cxt->data); + _D("%s is destroyed %d", id, reason); + + if (reason == WIDGET_APP_DESTROY_TYPE_PERMANENT) { + event = WIDGET_INSTANCE_EVENT_DESTROY; + aul_widget_instance_del(class_id, id); + } else { + __send_update_status(class_id, id, + WIDGET_INSTANCE_EVENT_EXTRA_UPDATED, content_info); + } + + if (content_info) + bundle_free(content_info); + + __send_update_status(class_id, id, event, NULL); + appcore_multiwindow_base_class_on_terminate(context); +} + +static void __stub_pause(appcore_multiwindow_base_instance_h context, void *data) +{ + struct widget_class_context *class_cxt = data; + const char *id; + const char *class_id; + + appcore_multiwindow_base_class_on_pause(context); + id = appcore_multiwindow_base_instance_get_id(context); + class_id = appcore_multiwindow_base_instance_get_class_id(context); + + if (!class_cxt) { + _E("class context is NULL"); + return; + } + + if (class_cxt->callback.pause) + class_cxt->callback.pause(context, class_cxt->data); + _D("%s is paused", id); + __send_update_status(class_id, id, + WIDGET_INSTANCE_EVENT_PAUSE, NULL); +} + +static void __stub_resume(appcore_multiwindow_base_instance_h context, void *data) +{ + struct widget_class_context *class_cxt = data; + const char *id; + const char *class_id; + + appcore_multiwindow_base_class_on_resume(context); + id = appcore_multiwindow_base_instance_get_id(context); + class_id = appcore_multiwindow_base_instance_get_class_id(context); + + if (!class_cxt) { + _E("class context is NULL"); + return; + } + + if (class_cxt->callback.resume) + class_cxt->callback.resume(context, class_cxt->data); + _D("%s is resumed", id); + __send_update_status(class_id, id, + WIDGET_INSTANCE_EVENT_RESUME, NULL); +} + +EXPORT_API widget_class_h widget_app_class_add(widget_class_h widget_class, + const char *class_id, widget_instance_lifecycle_callback_s callback, void *user_data) { - widget_class_s *wc; + appcore_multiwindow_base_class cls; + struct widget_class_context *cxt; - if (!_is_widget_feature_enabled()) { + if (!__is_widget_feature_enabled()) { _E("not supported"); set_last_result(WIDGET_ERROR_NOT_SUPPORTED); return NULL; } - if (class_id == NULL) { + if (!class_id) { + _E("class is is NULL"); set_last_result(WIDGET_ERROR_INVALID_PARAMETER); return NULL; } - wc = (widget_class_s *)malloc(sizeof(widget_class_s)); - if (wc == NULL) { - _E("failed to malloc : %s", __FUNCTION__); + cxt = calloc(1, sizeof(struct widget_class_context)); + + if (!cxt) { + _E("failed to calloc : %s", __FUNCTION__); set_last_result(WIDGET_ERROR_OUT_OF_MEMORY); return NULL; } - wc->classid = strdup(class_id); - wc->user_data = user_data; - wc->ops = callback; - wc->next = prev; - wc->prev = NULL; - - set_last_result(WIDGET_ERROR_NONE); + cxt->callback = callback; + cxt->data = user_data; - if (prev) - prev->prev = wc; + cls.id = strdup(class_id); + cls.data = cxt; + cls.create = __stub_create; + cls.terminate = __stub_terminate; + cls.pause = __stub_pause; + cls.resume = __stub_resume; - return wc; -} + appcore_multiwindow_base_class_add(cls); + set_last_result(WIDGET_ERROR_NONE); -EXPORT_API widget_class_h widget_app_class_add(widget_class_h widget_class, - const char *class_id, - widget_instance_lifecycle_callback_s callback, void *user_data) -{ - return _widget_class_create(widget_class, class_id, callback, - user_data); + return (widget_class_h)cxt; } EXPORT_API widget_class_h widget_app_class_create( widget_instance_lifecycle_callback_s callback, void *user_data) { - return _widget_class_create(class_provider, appid, callback, user_data); + return widget_app_class_add(NULL, __appid, callback, user_data); } EXPORT_API int widget_app_context_set_tag(widget_context_h context, void *tag) { - if (!_is_widget_feature_enabled()) { - _E("not supported"); - return WIDGET_ERROR_NOT_SUPPORTED; + struct widget_extra *we; + + if (!__is_widget_feature_enabled()) { + _E("not supported"); /* LCOV_EXCL_LINE */ + return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */ } - if (context == NULL) + if (!context) return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL); - context->tag = tag; + we = appcore_multiwindow_base_instance_get_extra((appcore_multiwindow_base_instance_h)context); + we->extra = tag; return WIDGET_ERROR_NONE; } EXPORT_API int widget_app_context_get_tag(widget_context_h context, void **tag) { - if (!_is_widget_feature_enabled()) { - _E("not supported"); - return WIDGET_ERROR_NOT_SUPPORTED; + struct widget_extra *we; + + if (!__is_widget_feature_enabled()) { + _E("not supported"); /* LCOV_EXCL_LINE */ + return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */ } - if (context == NULL || tag == NULL) + if (!context || !tag) return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL); - *tag = context->tag; + we = appcore_multiwindow_base_instance_get_extra((appcore_multiwindow_base_instance_h)context); + if (we == NULL) + return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, + __FUNCTION__, NULL); + *tag = we->extra; return WIDGET_ERROR_NONE; } @@ -722,35 +1205,51 @@ EXPORT_API int widget_app_context_get_tag(widget_context_h context, void **tag) EXPORT_API int widget_app_context_set_content_info(widget_context_h context, bundle *content_info) { - const char *class_id = NULL; int ret = 0; - - if (!_is_widget_feature_enabled()) { - _E("not supported"); - return WIDGET_ERROR_NOT_SUPPORTED; + bundle_raw *raw = NULL; + int len; + const char *id; + const char *class_id; + struct widget_extra *we; + appcore_multiwindow_base_instance_h cxt; + + if (!__is_widget_feature_enabled()) { + _E("not supported"); /* LCOV_EXCL_LINE */ + return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */ } - if (context == NULL || content_info == NULL) - return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, - __FUNCTION__, NULL); - - if (context->provider == NULL) + if (!context || !content_info) return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL); - class_id = context->provider->classid; + cxt = (appcore_multiwindow_base_instance_h)context; + id = appcore_multiwindow_base_instance_get_id(cxt); + class_id = appcore_multiwindow_base_instance_get_class_id(cxt); + we = appcore_multiwindow_base_instance_get_extra(cxt); - if (class_id == NULL) + if (!class_id || !id || !we) return widget_app_error(WIDGET_ERROR_FAULT, __FUNCTION__, NULL); - ret = __send_update_status(class_id, context->id, - WIDGET_INSTANCE_EVENT_UPDATE, content_info, true); + ret = __send_update_status(class_id, id, + WIDGET_INSTANCE_EVENT_EXTRA_UPDATED, content_info); + + if (we->content) + free(we->content); + bundle_encode(content_info, &raw, &len); + if (raw) + we->content = strdup((const char *)raw); + else + we->content = NULL; + + free(raw); if (ret < 0) { - _E("failed to send content info: %s of %s (%d)", context->id, + /* LCOV_EXCL_START */ + _E("failed to send content info: %s of %s (%d)", id, class_id, ret); return widget_app_error(WIDGET_ERROR_IO_ERROR, __FUNCTION__, NULL); + /* LCOV_EXCL_STOP */ } return WIDGET_ERROR_NONE; @@ -759,18 +1258,24 @@ EXPORT_API int widget_app_context_set_content_info(widget_context_h context, EXPORT_API int widget_app_context_set_title(widget_context_h context, const char *title) { - if (!_is_widget_feature_enabled()) { - _E("not supported"); - return WIDGET_ERROR_NOT_SUPPORTED; - } + appcore_multiwindow_base_instance_h cxt; + struct widget_extra *we; - /* TODO - call elm_win_title_set() - */ + if (!__is_widget_feature_enabled()) { + _E("not supported"); /* LCOV_EXCL_LINE */ + return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */ + } - if (!context || !title) + if (!context || !title) { + _E("Invalid parameter %p %p", context, title); return WIDGET_ERROR_INVALID_PARAMETER; + } + + cxt = (appcore_multiwindow_base_instance_h)context; + we = appcore_multiwindow_base_instance_get_extra(cxt); + + if (we->win) + elm_win_title_set(we->win, title); return WIDGET_ERROR_NONE; } -