From 5fc3c815929af673eeb28d4f0f9fad2ffe2379f4 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Tue, 30 May 2017 19:12:24 +0900 Subject: [PATCH 01/16] Handle abnormal exit Whlie calling widget_app_exit(), the widget app sends the normal termination signal to the amd. If the amd doesn't get the signal when the widget app is dead, the amd will send the widget fault signal to the widget viewer. Requires: - https://review.tizen.org/gerrit/#/c/131674/ [aul-1] - https://review.tizen.org/gerrit/#/c/131685/ [amd] - https://review.tizen.org/gerrit/#/c/131692/ [widget-service] - https://review.tizen.org/gerrit/#/c/131695/ [widget-viewer] Change-Id: I2815cc30c51ad538e2069a87b7f405e602c585c4 Signed-off-by: Hwankyu Jhun --- src/widget_app.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/widget_app.c b/src/widget_app.c index b059fc2..3840ac2 100755 --- a/src/widget_app.c +++ b/src/widget_app.c @@ -681,6 +681,8 @@ EXPORT_API int widget_app_exit(void) } appcore_multiwindow_base_exit(); + aul_widget_notify_exit(); + return WIDGET_ERROR_NONE; } -- 2.7.4 From 7f8984e3e6a2c5e57b4276fd35108af79940e605 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Thu, 1 Jun 2017 09:25:36 +0900 Subject: [PATCH 02/16] Release version 1.1.2 Changes: - Handle abnormal exit - Move unversioned so file to devel package Change-Id: I6c27b04200455d05c1324373a189a3b224552522 Signed-off-by: Hwankyu Jhun --- packaging/appcore-widget.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/appcore-widget.spec b/packaging/appcore-widget.spec index 18c7fd2..42899da 100644 --- a/packaging/appcore-widget.spec +++ b/packaging/appcore-widget.spec @@ -1,6 +1,6 @@ Name: appcore-widget Summary: Widget Application -Version: 1.1.1 +Version: 1.1.2 Release: 1 Group: Application Framework/Libraries License: Apache-2.0 -- 2.7.4 From f42c993425ba9047016c56762e84ddf1ac28692c Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Tue, 20 Jun 2017 14:50:05 +0900 Subject: [PATCH 03/16] Override multiwindow base methods The methods are init(), finish(), run() and exit(). The elementary dependency is removed from multiwindow base. Requires: - https://review.tizen.org/gerrit/#/c/134810/ Change-Id: Icc01285d3ca1313f20e5ad0767da7d78b8b6676e Signed-off-by: Hwankyu Jhun --- src/widget_app.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/widget_app.c b/src/widget_app.c index 3840ac2..4c20c2c 100755 --- a/src/widget_app.c +++ b/src/widget_app.c @@ -614,6 +614,33 @@ static int __widget_app_receive(aul_type type, bundle *b, void *data) return 0; } +static int __widget_app_init(int argc, char **argv, void *data) +{ + elm_init(argc, argv); + return 0; +} + +static void __widget_app_finish(void) +{ + elm_shutdown(); + + /* Check Loader case */ + if (getenv("AUL_LOADER_INIT")) { + unsetenv("AUL_LOADER_INIT"); + elm_shutdown(); + } +} + +static void __widget_app_run(void *data) +{ + elm_run(); +} + +static void __widget_app_exit(void *data) +{ + elm_exit(); +} + EXPORT_API int widget_app_main(int argc, char **argv, widget_app_lifecycle_callback_s *callback, void *user_data) { @@ -647,6 +674,11 @@ EXPORT_API int widget_app_main(int argc, char **argv, ops.base.control = __widget_app_control; ops.base.terminate = __widget_app_terminate; ops.base.receive = __widget_app_receive; + ops.base.init = __widget_app_init; + ops.base.finish = __widget_app_finish; + ops.base.run = __widget_app_run; + ops.base.exit = __widget_app_exit; + __context.callback = *callback; __context.data = user_data; kb = bundle_import_from_argv(argc, argv); @@ -929,7 +961,7 @@ EXPORT_API int widget_app_get_elm_win(widget_context_h context, 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); + appcore_multiwindow_base_window_bind(cxt, wl_win); _D("window created: %d", win_id); -- 2.7.4 From e655f9a68af50188238c647bacaa61476818075c Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Wed, 21 Jun 2017 09:24:00 +0900 Subject: [PATCH 04/16] Fix invalid log format Change-Id: I2c0d30f1a90754ff1744d2ec9a1e31d6a88902b1 Signed-off-by: Hwankyu Jhun --- src/widget_app.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widget_app.c b/src/widget_app.c index 4c20c2c..63ef11b 100755 --- a/src/widget_app.c +++ b/src/widget_app.c @@ -1035,7 +1035,7 @@ static void __stub_create(appcore_multiwindow_base_instance_h context, void *dat if (cxt->callback.create) ret = cxt->callback.create(context, content_info, w, h, cxt->data); - _D("%s is created %d", id); + _D("%s is created", id); if (ret < 0) { _W("Create callback returns error(%d)", ret); -- 2.7.4 From 9925d8896be783d8e6fe9c99ab5813732698ac49 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Thu, 29 Jun 2017 14:02:02 +0900 Subject: [PATCH 05/16] Release version 1.1.3 Changes: - Fix invalid log format - Override multiwindow base methods Change-Id: I61b54252730f6f6be653a4e0afa1994aac4ed7e6 Signed-off-by: Hwankyu Jhun --- packaging/appcore-widget.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/appcore-widget.spec b/packaging/appcore-widget.spec index 42899da..40d32e4 100644 --- a/packaging/appcore-widget.spec +++ b/packaging/appcore-widget.spec @@ -1,6 +1,6 @@ Name: appcore-widget Summary: Widget Application -Version: 1.1.2 +Version: 1.1.3 Release: 1 Group: Application Framework/Libraries License: Apache-2.0 -- 2.7.4 From f14751ab0da7cd0e15c73faaa1e5a40e40936cf4 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Thu, 6 Jul 2017 15:58:52 +0900 Subject: [PATCH 06/16] Fix typo The LOG_TAG should be "CAPI_WIDGET_APPLICATION". Change-Id: Ib8bb756b23156462ca0bba966d56c21a1fda7f24 Signed-off-by: Hwankyu Jhun --- src/widget_error.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widget_error.c b/src/widget_error.c index 8f90de4..cd79e5f 100755 --- a/src/widget_error.c +++ b/src/widget_error.c @@ -27,7 +27,7 @@ #undef LOG_TAG #endif -#define LOG_TAG "CAPI_WIDGET_APPLICATIO" +#define LOG_TAG "CAPI_WIDGET_APPLICATION" static const char *widget_app_error_to_string(widget_error_e error) { -- 2.7.4 From c93e468993a30c8c4cfbad075aae7136cff854b9 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Fri, 7 Jul 2017 13:01:24 +0900 Subject: [PATCH 07/16] Release version 1.1.4 Changes: - Fix typo Change-Id: I54dde607de7b9d9c853a9ba48fff0214edeeeefe Signed-off-by: Hwankyu Jhun --- packaging/appcore-widget.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/appcore-widget.spec b/packaging/appcore-widget.spec index 40d32e4..b36d898 100644 --- a/packaging/appcore-widget.spec +++ b/packaging/appcore-widget.spec @@ -1,6 +1,6 @@ Name: appcore-widget Summary: Widget Application -Version: 1.1.3 +Version: 1.1.4 Release: 1 Group: Application Framework/Libraries License: Apache-2.0 -- 2.7.4 From 67d554c153366b6482e3e16222bbc2706c599abb Mon Sep 17 00:00:00 2001 From: Daehyeon Jung Date: Wed, 30 Aug 2017 13:53:59 +0900 Subject: [PATCH 08/16] Fix wrong description Change-Id: Ic1a7a27fb1442e32d0ffbee03c23d014d842e957 Signed-off-by: Daehyeon Jung --- include/widget_app.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/widget_app.h b/include/widget_app.h index cf1b275..1bae4a5 100755 --- a/include/widget_app.h +++ b/include/widget_app.h @@ -432,7 +432,7 @@ int widget_app_context_set_title(widget_context_h context, const char *title); * @return The new widget class object, * NULL on error * @exception #WIDGET_ERROR_NONE Successfully added - * @exception #WIDGET_ERROR_INVALID_PARAMETER Not supported + * @exception #WIDGET_ERROR_INVALID_PARAMETER Invalid parameter * @exception #WIDGET_ERROR_NOT_SUPPORTED Not supported * @exception #WIDGET_ERROR_OUT_OF_MEMORY Out of memory * @see get_last_result() -- 2.7.4 From 3151b95ac4ca7e44e3796686d5bc7384d8abe387 Mon Sep 17 00:00:00 2001 From: Junghoon Park Date: Wed, 6 Sep 2017 13:47:01 +0900 Subject: [PATCH 09/16] Fix build error - Require: https://review.tizen.org/gerrit/#/c/147906/ Change-Id: I5fbe33b00d4acc6e5ba43a0a94452b3906eb4a09 Signed-off-by: Junghoon Park --- src/widget_app.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/widget_app.c b/src/widget_app.c index 63ef11b..5479b95 100755 --- a/src/widget_app.c +++ b/src/widget_app.c @@ -614,10 +614,9 @@ static int __widget_app_receive(aul_type type, bundle *b, void *data) return 0; } -static int __widget_app_init(int argc, char **argv, void *data) +static void __widget_app_init(int argc, char **argv, void *data) { elm_init(argc, argv); - return 0; } static void __widget_app_finish(void) -- 2.7.4 From bc80aba1fa289601d45a4bae9690dd7bf0a67442 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Fri, 8 Sep 2017 12:13:16 +0900 Subject: [PATCH 10/16] Release version 1.1.5 Changes: - Fix build error - Fix wrong description Change-Id: I31c661f2b98a08e0ebfd8e07231c65e3ec8144f0 Signed-off-by: Hwankyu Jhun --- packaging/appcore-widget.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/appcore-widget.spec b/packaging/appcore-widget.spec index b36d898..ee9de3d 100644 --- a/packaging/appcore-widget.spec +++ b/packaging/appcore-widget.spec @@ -1,6 +1,6 @@ Name: appcore-widget Summary: Widget Application -Version: 1.1.4 +Version: 1.1.5 Release: 1 Group: Application Framework/Libraries License: Apache-2.0 -- 2.7.4 From 409d1e95a1f99acb699ee4d38ffc3be10256e5f7 Mon Sep 17 00:00:00 2001 From: Hyunho Kang Date: Fri, 8 Sep 2017 14:10:36 +0900 Subject: [PATCH 11/16] Create widget base API set Change-Id: I65e7c0405b4839b23aeefc666075b7270dddd5bd Signed-off-by: Hyunho Kang Signed-off-by: Junghoon Park --- CMakeLists.txt | 50 +- appcore-widget-base.pc.in | 13 + capi-appfw-widget-application.pc.in | 3 +- include/widget_app.h | 2 +- include/widget_base.h | 133 +++ packaging/appcore-widget.spec | 36 +- src/base/widget_base.c | 1450 ++++++++++++++++++++++++++++++ src/{ => efl_base}/widget-log.h | 0 src/{ => efl_base}/widget-private.h | 2 - src/efl_base/widget_app.c | 518 +++++++++++ src/{ => efl_base}/widget_app_internal.c | 4 +- src/{ => efl_base}/widget_error.c | 0 src/widget_app.c | 1312 --------------------------- 13 files changed, 2192 insertions(+), 1331 deletions(-) create mode 100644 appcore-widget-base.pc.in create mode 100644 include/widget_base.h create mode 100644 src/base/widget_base.c rename src/{ => efl_base}/widget-log.h (100%) mode change 100755 => 100644 rename src/{ => efl_base}/widget-private.h (92%) create mode 100644 src/efl_base/widget_app.c rename src/{ => efl_base}/widget_app_internal.c (95%) rename src/{ => efl_base}/widget_error.c (100%) mode change 100755 => 100644 delete mode 100755 src/widget_app.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 6dc73c9..a665178 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,9 +18,46 @@ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") SET(CMAKE_SKIP_BUILD_RPATH TRUE) ################################################################# +# Build appcore-widget base Library +# ------------------------------ +SET(APPCORE_WIDGET_BASE "appcore-widget-base") +SET(SOURCES_base src/base/widget_base.c) + +INCLUDE(FindPkgConfig) +pkg_check_modules(pkg_widget_base REQUIRED + dlog + appcore-common + capi-appfw-app-common + vconf + vconf-internal-keys + widget_service + capi-system-info + ecore-wayland + capi-system-info + screen_connector_provider + appcore-multiwindow + ) + +FOREACH(flag ${pkg_widget_base_CFLAGS}) + SET(EXTRA_CFLAGS_widget "${EXTRA_CFLAGS_widget} ${flag}") +ENDFOREACH(flag) + +ADD_LIBRARY(${APPCORE_WIDGET_BASE} SHARED ${SOURCES_base}) +SET_TARGET_PROPERTIES(${APPCORE_WIDGET_BASE} PROPERTIES SOVERSION ${MAJORVER}) +SET_TARGET_PROPERTIES(${APPCORE_WIDGET_BASE} PROPERTIES VERSION ${FULLVER}) +SET_TARGET_PROPERTIES(${APPCORE_WIDGET_BASE} PROPERTIES COMPILE_FLAGS ${EXTRA_CFLAGS_widget}) +TARGET_LINK_LIBRARIES(${APPCORE_WIDGET_BASE} ${pkg_widget_base_LDFLAGS} "-ldl -Wl,--no-undefined") + +CONFIGURE_FILE(${APPCORE_WIDGET_BASE}.pc.in ${APPCORE_WIDGET_BASE}.pc @ONLY) +INSTALL(TARGETS ${APPCORE_WIDGET_BASE} DESTINATION ${LIB_INSTALL_DIR} COMPONENT RuntimeLibraries) +INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${APPCORE_WIDGET_BASE}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) + + +################################################################# # Build appcore-widget Library # ------------------------------ SET(APPCORE_WIDGET "capi-appfw-widget-application") +SET(SOURCES_efl src/efl_base/widget_app.c src/efl_base/widget_app_internal.c src/efl_base/widget_error.c) INCLUDE(FindPkgConfig) pkg_check_modules(pkg_widget REQUIRED @@ -28,25 +65,17 @@ pkg_check_modules(pkg_widget REQUIRED dlog appcore-common capi-appfw-app-common - vconf elementary - vconf-internal-keys - widget_service - capi-system-info - ecore-wayland - screen_connector_provider - appcore-multiwindow ) FOREACH(flag ${pkg_widget_CFLAGS}) SET(EXTRA_CFLAGS_widget "${EXTRA_CFLAGS_widget} ${flag}") ENDFOREACH(flag) -AUX_SOURCE_DIRECTORY(src SOURCES) -ADD_LIBRARY(${APPCORE_WIDGET} SHARED ${SOURCES}) +ADD_LIBRARY(${APPCORE_WIDGET} SHARED ${SOURCES_efl}) SET_TARGET_PROPERTIES(${APPCORE_WIDGET} PROPERTIES SOVERSION ${MAJORVER}) SET_TARGET_PROPERTIES(${APPCORE_WIDGET} PROPERTIES VERSION ${FULLVER}) SET_TARGET_PROPERTIES(${APPCORE_WIDGET} PROPERTIES COMPILE_FLAGS ${EXTRA_CFLAGS_widget}) -TARGET_LINK_LIBRARIES(${APPCORE_WIDGET} ${pkg_widget_LDFLAGS} "-ldl -Wl,--no-undefined") +TARGET_LINK_LIBRARIES(${APPCORE_WIDGET} ${pkg_widget_LDFLAGS} ${APPCORE_WIDGET_BASE} "-ldl -Wl,--no-undefined") CONFIGURE_FILE(${APPCORE_WIDGET}.pc.in ${APPCORE_WIDGET}.pc @ONLY) INSTALL(TARGETS ${APPCORE_WIDGET} DESTINATION ${LIB_INSTALL_DIR} COMPONENT RuntimeLibraries) @@ -56,3 +85,4 @@ INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/include/ DESTINATION include/appfw/ FILES_MATCHING PATTERN "*.h" ) + diff --git a/appcore-widget-base.pc.in b/appcore-widget-base.pc.in new file mode 100644 index 0000000..78de159 --- /dev/null +++ b/appcore-widget-base.pc.in @@ -0,0 +1,13 @@ +# Package Information for pkg-config + +prefix=@PREFIX@ +exec_prefix=@EXEC_PREFIX@ +libdir=@LIB_INSTALL_DIR@ +includedir=@INCLUDEDIR@ + +Name: appcore-widget-base +Description: widget base library +Version: @VERSION@ +Requires: aul dlog capi-appfw-app-common widget_service +Libs: -L${libdir} -lappcore-widget-base +Cflags: -I${includedir} -I${includedir}/appfw diff --git a/capi-appfw-widget-application.pc.in b/capi-appfw-widget-application.pc.in index 8512e85..6f7ec01 100644 --- a/capi-appfw-widget-application.pc.in +++ b/capi-appfw-widget-application.pc.in @@ -8,6 +8,7 @@ includedir=@INCLUDEDIR@ Name: capi-appfw-widget-application Description: widget application library Version: @VERSION@ -Requires: aul dlog elementary capi-appfw-app-common widget_service +Requires.private: aul dlog elementary capi-appfw-app-common widget_service +Requires: appcore-widget-base Libs: -L${libdir} -lcapi-appfw-widget-application Cflags: -I${includedir} -I${includedir}/appfw diff --git a/include/widget_app.h b/include/widget_app.h index 1bae4a5..cf1b275 100755 --- a/include/widget_app.h +++ b/include/widget_app.h @@ -432,7 +432,7 @@ int widget_app_context_set_title(widget_context_h context, const char *title); * @return The new widget class object, * NULL on error * @exception #WIDGET_ERROR_NONE Successfully added - * @exception #WIDGET_ERROR_INVALID_PARAMETER Invalid parameter + * @exception #WIDGET_ERROR_INVALID_PARAMETER Not supported * @exception #WIDGET_ERROR_NOT_SUPPORTED Not supported * @exception #WIDGET_ERROR_OUT_OF_MEMORY Out of memory * @see get_last_result() diff --git a/include/widget_base.h b/include/widget_base.h new file mode 100644 index 0000000..0358000 --- /dev/null +++ b/include/widget_base.h @@ -0,0 +1,133 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#define FEATURE_SHELL_APPWIDGET "http://tizen.org/feature/shell.appwidget" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum widget_base_destroy_type { + WIDGET_BASE_DESTROY_TYPE_PERMANENT = 0x00, + WIDGET_BASE_DESTROY_TYPE_TEMPORARY = 0x01, +} widget_base_destroy_type_e; + +typedef enum widget_base_error { + WIDGET_BASE_ERROR_NONE = TIZEN_ERROR_NONE, /**< Operation is successfully completed */ + WIDGET_BASE_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid function parameter */ + WIDGET_BASE_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY, /**< Out of memory */ + WIDGET_BASE_ERROR_RESOURCE_BUSY = TIZEN_ERROR_RESOURCE_BUSY, /**< Device or resource busy */ + WIDGET_BASE_ERROR_PERMISSION_DENIED = TIZEN_ERROR_PERMISSION_DENIED, /**< Permission denied */ + WIDGET_BASE_ERROR_CANCELED = TIZEN_ERROR_CANCELED, /**< Operation Canceled */ + WIDGET_BASE_ERROR_IO_ERROR = TIZEN_ERROR_IO_ERROR, /**< I/O error */ + WIDGET_BASE_ERROR_TIMED_OUT = TIZEN_ERROR_TIMED_OUT, /**< Time out */ + WIDGET_BASE_ERROR_NOT_SUPPORTED = TIZEN_ERROR_NOT_SUPPORTED, /**< Not supported */ + WIDGET_BASE_ERROR_FILE_NO_SPACE_ON_DEVICE = TIZEN_ERROR_FILE_NO_SPACE_ON_DEVICE, /**< No space left on device */ + WIDGET_BASE_ERROR_FAULT = TIZEN_ERROR_WIDGET | 0x0001, /**< Fault - Unable to recover from the error */ + WIDGET_BASE_ERROR_ALREADY_EXIST = TIZEN_ERROR_WIDGET | 0x0002, /**< Already exists */ + WIDGET_BASE_ERROR_ALREADY_STARTED = TIZEN_ERROR_WIDGET | 0x0004, /**< Operation is already started */ + WIDGET_BASE_ERROR_NOT_EXIST = TIZEN_ERROR_WIDGET | 0x0008, /**< Not exists */ + WIDGET_BASE_ERROR_DISABLED = TIZEN_ERROR_WIDGET | 0x0010, /**< Disabled */ + WIDGET_BASE_ERROR_MAX_EXCEEDED = TIZEN_ERROR_WIDGET | 0x0011, /**< Maximum number of instances exceeded (Since 3.0) */ +} widget_base_error_e; + +typedef appcore_multiwindow_base_instance_h widget_base_instance_h; + +typedef struct _widget_base_class_ops { + int (*create)(widget_base_instance_h instance_h, bundle *content, + int w, int h, void *class_data); + int (*destroy)(widget_base_instance_h instance_h, + widget_base_destroy_type_e reason, bundle *content, + void *class_data); + int (*pause)(widget_base_instance_h instance_h, void *class_data); + int (*resume)(widget_base_instance_h instance_h, void *class_data); + int (*resize)(widget_base_instance_h instance_h, int w, int h, void *class_data); + int (*update)(widget_base_instance_h instance_h, bundle *content, int force, + void *class_data); +} widget_base_class_ops; + +typedef struct _widget_base_ops { + int (*create)(void *data); + int (*terminate)(void *data); + void (*init)(int argc, char **argv, void *data); + void (*finish)(void); + void (*run)(void *data); + void (*exit)(void *data); +} widget_base_ops; + +typedef struct _widget_base_class { + char *id; + widget_base_class_ops ops; +} widget_base_class; + +typedef bool (*widget_base_instance_cb)(widget_base_instance_h instance, void *data); + +int widget_base_foreach_context(widget_base_instance_cb cb, void *data); +int widget_base_terminate_context(widget_base_instance_h instance_h); +int widget_base_add_event_handler(app_event_handler_h *event_handler, + app_event_type_e event_type, + app_event_cb callback, + void *user_data); +int widget_base_remove_event_handler(app_event_handler_h + event_handler); +int widget_base_context_set_content_info(widget_base_instance_h instance_h, + bundle *content_info); +int widget_base_context_get_tag(widget_base_instance_h instance_h, void **tag); +int widget_base_context_set_tag(widget_base_instance_h instance_h, void *tag); +void *widget_base_context_get_user_data(widget_base_instance_h instance_h); +int widget_base_context_set_user_data(widget_base_instance_h instance_h, + void *user_data); +int widget_base_context_get_id(widget_base_instance_h instance_h, char **id); +const char *widget_base_get_viewer_endpoint(void); +int widget_base_init(widget_base_ops ops, int argc, char **argv, void *data); +int widget_base_on_create(void); +int widget_base_on_terminate(void); +int widget_base_on_init(int argc, char **argv); +void widget_base_on_finish(void); +void widget_base_on_run(void); +void widget_base_on_exit(void); +widget_base_ops widget_base_get_default_ops(void); +void widget_base_fini(void); +int widget_base_exit(void); +int widget_base_context_window_bind( + widget_base_instance_h instance_h, const char *id, + Ecore_Wl_Window *wl_win); +int widget_base_class_on_create(widget_base_instance_h instance_h, + bundle *content, int w, int h); +int widget_base_class_on_pause(widget_base_instance_h instance_h); +int widget_base_class_on_resume(widget_base_instance_h instance_h); +int widget_base_class_on_resize(widget_base_instance_h instance_h, + int w, int h); +int widget_base_class_on_update(widget_base_instance_h instance_h, + bundle *content, int force); +int widget_base_class_on_destroy(widget_base_instance_h instance_h, + widget_base_destroy_type_e reason, bundle *content); +widget_base_class widget_base_class_get_default(void); +widget_base_class *widget_base_class_add(widget_base_class cls, + const char *class_id, void *class_data); + +#ifdef __cplusplus +} +#endif diff --git a/packaging/appcore-widget.spec b/packaging/appcore-widget.spec index ee9de3d..9cc0e6f 100644 --- a/packaging/appcore-widget.spec +++ b/packaging/appcore-widget.spec @@ -20,9 +20,28 @@ BuildRequires: pkgconfig(appcore-multiwindow) BuildRequires: pkgconfig(screen_connector_provider) BuildRequires: cmake +%description +Widget base + +%package -n appcore-widget-base +Summary: Widget base +Group: Development/Libraries +Requires(post): /sbin/ldconfig +%description -n appcore-widget-base +Requires(postun): /sbin/ldconfig %description -Widget application +Widget base devel + +%package -n appcore-widget-base-devel +Summary: Widget base +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} +%description -n appcore-widget-base-devel +widget application (development files) + +%description +Widget application devel %package -n capi-appfw-widget-application-devel Summary: Widget application @@ -50,9 +69,20 @@ cp capi-appfw-widget-application.pc %{buildroot}%{_libdir}/pkgconfig %postun -p /sbin/ldconfig +%files -n appcore-widget-base +%manifest %{name}.manifest +%defattr(-,root,root,-) +%{_libdir}/libappcore-widget-base.so.* +%license LICENSE + +%files -n appcore-widget-base-devel +/usr/include/appfw/widget_base.h +%{_libdir}/pkgconfig/appcore-widget-base.pc +%{_libdir}/libappcore-widget-base.so + -%files -%manifest appcore-widget.manifest +%files -n appcore-widget +%manifest %{name}.manifest %defattr(-,root,root,-) %{_libdir}/libcapi-appfw-widget-application.so.* %license LICENSE diff --git a/src/base/widget_base.c b/src/base/widget_base.c new file mode 100644 index 0000000..7cbba6c --- /dev/null +++ b/src/base/widget_base.c @@ -0,0 +1,1450 @@ +/* + * Copyright (c) 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "widget_base.h" + +#ifdef LOG_TAG +#undef LOG_TAG +#endif + +#define LOG_TAG "CAPI_WIDGET_APPLICATION" +#define APP_TYPE_WIDGET "widgetapp" +#define STATUS_FOREGROUND "fg" +#define STATUS_BACKGROUND "bg" + +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, +}; + +struct app_event_info { + app_event_type_e type; + void *value; +}; + +struct app_event_handler { + app_event_type_e type; + app_event_cb cb; + void *data; + void *raw; +}; + +struct widget_foreach_context { + widget_base_instance_cb callback; + void *data; +}; + +typedef struct _widget_base_context { + widget_base_ops ops; + void *data; + int argc; + char **argv; + GList *classes; +} widget_base_context; + +typedef struct _widget_base_instance_data { + bundle *args; + char *content; + void *tag; + void *user_data; +} widget_base_instance_data; + +static widget_base_context __context; +static char *__appid; +static char *__package_id; +static bool __fg_signal; +static char *__viewer_endpoint; + +static bool __is_widget_feature_enabled(void) +{ + static bool feature = false; + static bool retrieved = false; + int ret; + + if (retrieved == true) + return feature; + + ret = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature); + if (ret != SYSTEM_INFO_ERROR_NONE) { + LOGE("failed to get system info"); /* LCOV_EXCL_LINE */ + return false; /* LCOV_EXCL_LINE */ + } + + retrieved = true; + + return feature; +} + +/* LCOV_EXCL_START */ +static void __on_poweroff(keynode_t *key, void *data) +{ + int val; + + val = vconf_keynode_get_int(key); + switch (val) { + case VCONFKEY_SYSMAN_POWER_OFF_DIRECT: + case VCONFKEY_SYSMAN_POWER_OFF_RESTART: + LOGI("power off changed: %d", val); + widget_base_exit(); + break; + case VCONFKEY_SYSMAN_POWER_OFF_NONE: + case VCONFKEY_SYSMAN_POWER_OFF_POPUP: + default: + /* DO NOTHING */ + break; + } +} +/* LCOV_EXCL_STOP */ + +static void __check_empty_instance(void) +{ + int cnt = appcore_multiwindow_base_instance_get_cnt(); + + if (cnt == 0) + widget_base_exit(); +} + +static void __instance_drop(appcore_multiwindow_base_instance_h instance_h) +{ + widget_base_instance_data *data; + + data = appcore_multiwindow_base_instance_get_extra(instance_h); + appcore_multiwindow_base_instance_drop(instance_h); + free(data->content); + free(data); + __check_empty_instance(); +} + +static gint __comp_class(gconstpointer a, gconstpointer b) +{ + const widget_base_class *cls = a; + + return strcmp(cls->id, b); +} + +static widget_base_class __get_class(const char *class_id) +{ + widget_base_class *cls; + GList *class_node; + + class_node = g_list_find_custom(__context.classes, class_id, + __comp_class); + cls = (widget_base_class *)class_node->data; + + return *cls; +} + +static int __send_lifecycle_event(const char *class_id, const char *instance_id, + int status) +{ + bundle *b = bundle_create(); + int ret; + + if (b == NULL) { + LOGE("out of memory"); /* LCOV_EXCL_LINE */ + return -1; /* LCOV_EXCL_LINE */ + } + + 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); + + LOGD("send lifecycle %s(%d)", instance_id, status); + ret = aul_app_com_send("widget.status", b); + if (ret < 0) + LOGE("send lifecycle error:%d", ret); /* LCOV_EXCL_LINE */ + + bundle_free(b); + + return ret; +} + +static int __send_update_status(const char *class_id, const char *instance_id, + int status, bundle *extra) +{ + bundle *b; + int lifecycle = -1; + bundle_raw *raw = NULL; + int len; + + b = bundle_create(); + if (!b) { + LOGE("out of memory"); /* LCOV_EXCL_LINE */ + return -1; /* LCOV_EXCL_LINE */ + } + + 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)); + + 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); + } + + LOGD("send update %s(%d) to %s", instance_id, status, __viewer_endpoint); + aul_app_com_send(__viewer_endpoint, b); + + 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; + } + + if (lifecycle > -1) + __send_lifecycle_event(class_id, instance_id, lifecycle); + + bundle_free(b); + if (raw) + free(raw); + + return 0; +} + +static void __control_create(const char *class_id, const char *id, bundle *b) +{ + widget_base_instance_data *data; + char *content = NULL; + + data = (widget_base_instance_data *) + calloc(1, sizeof(widget_base_instance_data)); + if (!data) { + LOGE("Out of memory"); + return; + } + + data->args = b; + + /* call stub create */ + appcore_multiwindow_base_instance_run(class_id, id, data); + data->args = NULL; + bundle_get_str(b, WIDGET_K_CONTENT_INFO, &content); + if (content) + data->content = strdup(content); + +} + +static void __control_resume(const char *class_id, const char *id, bundle *b) +{ + appcore_multiwindow_base_instance_h cxt; + + cxt = appcore_multiwindow_base_instance_find(id); + if (!cxt) { + LOGE("context not found: %s", id); + return; + } + + /* call stub resume */ + appcore_multiwindow_base_instance_resume(cxt); +} + +static void __control_pause(const char *class_id, const char *id, bundle *b) +{ + appcore_multiwindow_base_instance_h instance_h; + + instance_h = appcore_multiwindow_base_instance_find(id); + + if (!instance_h) { + LOGE("instance not found: %s", id); + return; + } + + /* call stub pause */ + appcore_multiwindow_base_instance_pause(instance_h); +} + +static void __control_resize(const char *class_id, const char *id, bundle *b) +{ + appcore_multiwindow_base_instance_h instance_h; + char *remain = NULL; + char *w_str = NULL; + char *h_str = NULL; + int w = 0; + int h = 0; + void *class_data; + widget_base_class cls; + const appcore_multiwindow_base_class *raw_cls; + + instance_h = appcore_multiwindow_base_instance_find(id); + if (!instance_h) { + LOGE("context not found: %s", id); + return; + } + + raw_cls = appcore_multiwindow_base_instance_get_class(instance_h); + if (!raw_cls) + return; + + cls = __get_class(class_id); + class_data = raw_cls->data; + 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 (cls.ops.resize) + cls.ops.resize(instance_h, w, h, class_data); + + LOGD("%s is resized to %dx%d", id, w, h); + __send_update_status(class_id, id, + WIDGET_INSTANCE_EVENT_SIZE_CHANGED, NULL); +} + +static void __update_cb(const char *class_id, const char *id, + appcore_multiwindow_base_instance_h instance_h, void *data) +{ + void *class_data; + const appcore_multiwindow_base_class *raw_cls; + bundle *content = NULL; + char *content_raw = NULL; + char *force_str = NULL; + int force; + bundle *b = data; + widget_base_class cls; + + if (!b) { + LOGE("bundle is NULL"); + return; + } + + raw_cls = appcore_multiwindow_base_instance_get_class(instance_h); + if (!raw_cls) { + LOGE("class is NULL"); + return; + } + + class_data = raw_cls->data; + cls = __get_class(class_id); + + if (!cls.ops.update) { + LOGE("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)); + } + + if (cls.ops.update) + cls.ops.update(instance_h, content, force, class_data); + + __send_update_status(class_id, id, + WIDGET_INSTANCE_EVENT_UPDATE, NULL); + LOGD("updated:%s", id); + + if (content) + bundle_free(content); +} + +static void __control_update(const char *class_id, const char *id, bundle *b) +{ + appcore_multiwindow_base_instance_h instance_h; + + if (!id) { + appcore_multiwindow_base_instance_foreach(class_id, + __update_cb, b); + return; + } + + instance_h = appcore_multiwindow_base_instance_find(id); + if (!instance_h) { + LOGE("context not found: %s", id); + return; + } + + __update_cb(class_id, id, instance_h, b); +} + +static void __control_destroy(const char *class_id, const char *id, bundle *b) +{ + appcore_multiwindow_base_instance_h instance_h; + widget_base_instance_data *data; + + instance_h = appcore_multiwindow_base_instance_find(id); + if (!instance_h) { + LOGE("could not find widget obj: %s, clear amd info", id); + aul_widget_instance_del(class_id, id); + return; + } + + data = (widget_base_instance_data *) + appcore_multiwindow_base_instance_get_extra(instance_h); + data->args = b; + + /* call stub terminate */ + appcore_multiwindow_base_instance_exit(instance_h); + free(data->content); + free(data); + __check_empty_instance(); +} + +static int __multiwindow_create(void *data) +{ + char pkgid[256] = {0, }; + int ret = 0; + + 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) { + LOGE("__package_id is NULL"); + return -1; + } + + screen_connector_provider_init(); + vconf_notify_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, + __on_poweroff, NULL); + + + if (__context.ops.create) + ret = __context.ops.create(data); + + LOGD("widget base is created"); + return ret; +} + +static int __multiwindow_terminate(void *data) +{ + if (__context.ops.terminate) + __context.ops.terminate(data); + + vconf_ignore_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, + __on_poweroff); + screen_connector_provider_fini(); + + if (__viewer_endpoint) { + free(__viewer_endpoint); + __viewer_endpoint = NULL; + } + + if (__package_id) { + free(__package_id); + __package_id = NULL; + } + + if (__appid) { + free(__appid); + __appid = NULL; + } + + appcore_multiwindow_base_on_terminate(); + + LOGD("widget base is terminated"); + return 0; +} + +static int __multiwindow_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) { + LOGE("operation is NULL"); + return 0; + } + + if (strcmp(operation, "create") == 0) + __control_create(class_id, id, b); + else if (strcmp(operation, "resize") == 0) + __control_resize(class_id, id, b); + else if (strcmp(operation, "update") == 0) + __control_update(class_id, id, b); + else if (strcmp(operation, "destroy") == 0) + __control_destroy(class_id, id, b); + else if (strcmp(operation, "resume") == 0) + __control_resume(class_id, id, b); + else if (strcmp(operation, "pause") == 0) + __control_pause(class_id, id, b); + else if (strcmp(operation, "terminate") == 0) + __control_destroy(class_id, id, b); + + return 0; +} + +static void __inst_resume_cb(const char *class_id, const char *id, + appcore_multiwindow_base_instance_h cxt, void *data) +{ + __control_resume(class_id, id, data); +} + +static void __get_content(bundle *b) +{ + char *instance_id = NULL; + appcore_multiwindow_base_instance_h cxt; + widget_base_instance_data * we; + + bundle_get_str(b, AUL_K_WIDGET_INSTANCE_ID, &instance_id); + if (!instance_id) { + LOGE("instance id is NULL"); + return; + } + + cxt = appcore_multiwindow_base_instance_find(instance_id); + if (!cxt) { + LOGE("could not find widget obj: %s", instance_id); + return; + } + + we = appcore_multiwindow_base_instance_get_extra(cxt); + if (!we) { + LOGE("widget extra is NULL"); + return; + } + + if (we->content) { + bundle_add_str(b, AUL_K_WIDGET_CONTENT_INFO, we->content); + LOGD("content info of %s found", instance_id); + } else { + bundle_add_str(b, AUL_K_WIDGET_CONTENT_INFO, ""); + LOGD("empty content info added"); + } +} + +static int __multiwindow_receive(aul_type type, bundle *b, void *data) +{ + appcore_multiwindow_base_on_receive(type, b); + + switch (type) { + case AUL_RESUME: + appcore_multiwindow_base_instance_foreach_full( + __inst_resume_cb, b); + break; + case AUL_TERMINATE: + widget_base_exit(); + break; + case AUL_WIDGET_CONTENT: + __get_content(b); + break; + default: + break; + } + + return 0; +} + +static void __multiwindow_init(int argc, char **argv, void *data) +{ + if (__context.ops.init) + __context.ops.init(argc, argv, data); +} + +static void __multiwindow_finish(void) +{ + if (__context.ops.finish) { + __context.ops.finish(); + /* Check Loader case */ + if (getenv("AUL_LOADER_INIT")) { + unsetenv("AUL_LOADER_INIT"); + __context.ops.finish(); + } + } +} + +static void __multiwindow_run(void *data) +{ + if (__context.ops.run) + __context.ops.run(data); +} + +static void __multiwindow_exit(void *data) +{ + if (__context.ops.exit) + __context.ops.exit(data); +} + +EXPORT_API int widget_base_exit(void) +{ + appcore_multiwindow_base_exit(); + aul_widget_notify_exit(); + + return 0; +} + +static gboolean __finish_event_cb(gpointer user_data) +{ + appcore_multiwindow_base_instance_h cxt = user_data; + bundle *b; + const char *id; + const char *class_id; + + if (!cxt) { + LOGE("user_data is NULL"); + return FALSE; + } + + id = appcore_multiwindow_base_instance_get_id(cxt); + class_id = appcore_multiwindow_base_instance_get_class_id(cxt); + b = bundle_create(); + + if (!b) { + LOGE("Out-of-memory"); + return FALSE; + } + + bundle_add_str(b, WIDGET_K_OPERATION, "terminate"); + __control_destroy(class_id, id, b); + bundle_free(b); + + return FALSE; +} + +EXPORT_API int widget_base_terminate_context(widget_base_instance_h context) +{ + if (!__is_widget_feature_enabled()) { + LOGE("not supported"); /* LCOV_EXCL_LINE */ + return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */ + } + + if (!context) { + LOGE("context is null"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + g_idle_add(__finish_event_cb, 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_base_foreach_context(widget_base_instance_cb cb, void *data) +{ + struct widget_foreach_context foreach_context; + + if (!__is_widget_feature_enabled()) { + LOGE("not supported"); /* LCOV_EXCL_LINE */ + return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */ + } + + if (!cb) { + LOGE("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; +} + +static 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_base_add_event_handler(app_event_handler_h *event_handler, + app_event_type_e event_type, + app_event_cb callback, + void *user_data) +{ + int r; + bool feature; + app_event_handler_h handler; + + r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature); + if (r < 0) + return WIDGET_BASE_ERROR_FAULT; + + if (!feature) + return WIDGET_BASE_ERROR_NOT_SUPPORTED; + + if (event_handler == NULL || callback == NULL) + return WIDGET_BASE_ERROR_INVALID_PARAMETER; + + if (event_type < APP_EVENT_LOW_MEMORY + || event_type > APP_EVENT_REGION_FORMAT_CHANGED) + return WIDGET_BASE_ERROR_INVALID_PARAMETER; + + if (event_type == APP_EVENT_DEVICE_ORIENTATION_CHANGED) + return WIDGET_BASE_ERROR_NOT_SUPPORTED; + + + handler = calloc(1, sizeof(struct app_event_handler)); + if (!handler) + return WIDGET_BASE_ERROR_OUT_OF_MEMORY; + + 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_BASE_ERROR_NONE; +} + +EXPORT_API int widget_base_remove_event_handler(app_event_handler_h + event_handler) +{ + int r; + bool feature; + app_event_type_e type; + + r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature); + if (r < 0) + return WIDGET_BASE_ERROR_FAULT; + + if (!feature) + return WIDGET_BASE_ERROR_NOT_SUPPORTED; + + if (event_handler == NULL) + return WIDGET_BASE_ERROR_INVALID_PARAMETER; + + type = event_handler->type; + if (type < APP_EVENT_LOW_MEMORY || + type > APP_EVENT_REGION_FORMAT_CHANGED) + return WIDGET_BASE_ERROR_INVALID_PARAMETER; + + r = appcore_base_remove_event(event_handler->raw); + if (r < 0) + return WIDGET_BASE_ERROR_INVALID_PARAMETER; + + free(event_handler); + + return WIDGET_BASE_ERROR_NONE; +} + +EXPORT_API int widget_base_context_set_content_info( + widget_base_instance_h context, + bundle *content_info) +{ + int ret = 0; + bundle_raw *raw = NULL; + int len; + const char *id; + const char *class_id; + widget_base_instance_data *data; + appcore_multiwindow_base_instance_h instance_h; + + if (!__is_widget_feature_enabled()) { + LOGE("not supported"); /* LCOV_EXCL_LINE */ + return WIDGET_BASE_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */ + } + + if (!context || !content_info) + return WIDGET_BASE_ERROR_INVALID_PARAMETER; + + instance_h = (appcore_multiwindow_base_instance_h)context; + id = appcore_multiwindow_base_instance_get_id(instance_h); + class_id = appcore_multiwindow_base_instance_get_class_id(instance_h); + data = appcore_multiwindow_base_instance_get_extra(instance_h); + + if (!class_id || !id || !data) + return WIDGET_BASE_ERROR_FAULT; + + ret = __send_update_status(class_id, id, + WIDGET_INSTANCE_EVENT_EXTRA_UPDATED, content_info); + + if (data->content) + free(data->content); + + bundle_encode(content_info, &raw, &len); + if (raw) + data->content = strdup((const char *)raw); + else + data->content = NULL; + + free(raw); + if (ret < 0) { + /* LCOV_EXCL_START */ + LOGE("failed to send content info: %s of %s (%d)", id, + class_id, ret); + return WIDGET_BASE_ERROR_IO_ERROR; + /* LCOV_EXCL_STOP */ + } + + return WIDGET_BASE_ERROR_NONE; +} + +EXPORT_API int widget_base_context_get_tag(widget_base_instance_h context, void **tag) +{ + appcore_multiwindow_base_instance_h instance_h; + widget_base_instance_data *data; + + if (!__is_widget_feature_enabled()) { + LOGE("not supported"); /* LCOV_EXCL_LINE */ + return WIDGET_BASE_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */ + } + + if (!context || !tag) { + LOGE("Invalid parameter"); + return WIDGET_BASE_ERROR_INVALID_PARAMETER; + } + + instance_h = (appcore_multiwindow_base_instance_h)context; + data = (widget_base_instance_data *) + appcore_multiwindow_base_instance_get_extra(instance_h); + + if (!data) { + LOGE("Invalid parameter"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + *tag = data->tag; + + return WIDGET_BASE_ERROR_NONE; +} + +EXPORT_API int widget_base_context_set_tag(widget_base_instance_h context, void *tag) +{ + appcore_multiwindow_base_instance_h instance_h; + widget_base_instance_data *data; + + if (!__is_widget_feature_enabled()) { + LOGE("not supported"); /* LCOV_EXCL_LINE */ + return WIDGET_BASE_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */ + } + + if (!context) { + LOGE("Invalid parameter"); + return WIDGET_BASE_ERROR_INVALID_PARAMETER; + } + + instance_h = (appcore_multiwindow_base_instance_h)context; + data = (widget_base_instance_data *) + appcore_multiwindow_base_instance_get_extra(instance_h); + data->tag = tag; + + return WIDGET_BASE_ERROR_NONE; +} + +EXPORT_API void *widget_base_context_get_user_data( + widget_base_instance_h context) +{ + appcore_multiwindow_base_instance_h instance_h; + widget_base_instance_data *data; + + if (!__is_widget_feature_enabled()) { + LOGE("not supported"); /* LCOV_EXCL_LINE */ + return NULL; /* LCOV_EXCL_LINE */ + } + + if (!context) { + LOGE("Invalid parameter"); + return NULL; + } + + instance_h = (appcore_multiwindow_base_instance_h)context; + data = (widget_base_instance_data *) + appcore_multiwindow_base_instance_get_extra(instance_h); + + return data->user_data; +} + + +EXPORT_API int widget_base_context_set_user_data( + widget_base_instance_h context, void *user_data) +{ + appcore_multiwindow_base_instance_h instance_h; + widget_base_instance_data *data; + + if (!__is_widget_feature_enabled()) { + LOGE("not supported"); /* LCOV_EXCL_LINE */ + return WIDGET_BASE_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */ + } + + if (!context) { + LOGE("Invalid parameter"); + return WIDGET_BASE_ERROR_INVALID_PARAMETER; + } + + instance_h = (appcore_multiwindow_base_instance_h)context; + data = (widget_base_instance_data *) + appcore_multiwindow_base_instance_get_extra(instance_h); + data->user_data = user_data; + + return WIDGET_BASE_ERROR_NONE; +} + +EXPORT_API int widget_base_context_get_id(widget_base_instance_h context, char **id) +{ + appcore_multiwindow_base_instance_h instance_h; + + if (!__is_widget_feature_enabled()) { + LOGE("not supported"); /* LCOV_EXCL_LINE */ + return WIDGET_BASE_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */ + } + + instance_h = (appcore_multiwindow_base_instance_h)context; + *id = (char *)appcore_multiwindow_base_instance_get_id(instance_h); + + return WIDGET_BASE_ERROR_NONE; +} + +EXPORT_API const char *widget_base_get_viewer_endpoint() +{ + return __viewer_endpoint; +} + +EXPORT_API int widget_base_init(widget_base_ops ops, int argc, char **argv, + void *data) +{ + bundle *kb; + char *viewer_endpoint = NULL; + appcore_multiwindow_base_ops raw_ops + = appcore_multiwindow_base_get_default_ops(); + + __context.ops = ops; + __context.argc = argc; + __context.argv = argv; + __context.data = data; + + /* override methods */ + raw_ops.base.create = __multiwindow_create; + raw_ops.base.control = __multiwindow_control; + raw_ops.base.terminate = __multiwindow_terminate; + raw_ops.base.receive = __multiwindow_receive; + raw_ops.base.init = __multiwindow_init; + raw_ops.base.finish = __multiwindow_finish; + raw_ops.base.run = __multiwindow_run; + raw_ops.base.exit = __multiwindow_exit; + + if (!__is_widget_feature_enabled()) { + LOGE("not supported"); /* LCOV_EXCL_LINE */ + return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */ + } + + kb = bundle_import_from_argv(argc, argv); + if (kb) { + bundle_get_str(kb, WIDGET_K_ENDPOINT, &viewer_endpoint); + if (viewer_endpoint) { + LOGD("viewer endpoint :%s", viewer_endpoint); + __viewer_endpoint = strdup(viewer_endpoint); + } else { + LOGE("endpoint is missing"); + } + + bundle_free(kb); + } else { + LOGE("failed to get launch argv"); /* LCOV_EXCL_LINE */ + return WIDGET_ERROR_FAULT; + } + + if (appcore_multiwindow_base_init(raw_ops, argc, argv, data) < 0) + return WIDGET_ERROR_FAULT; + + return WIDGET_ERROR_NONE; +} + +static int __on_create(void *data) +{ + return widget_base_on_create(); +} + +static int __on_terminate(void *data) +{ + return widget_base_on_terminate(); +} + +static void __on_init(int argc, char **argv, void *data) +{ + widget_base_on_init(argc, argv); +} + +static void __on_finish(void) +{ + widget_base_on_finish(); +} + +static void __on_run(void *data) +{ + widget_base_on_run(); +} + +static void __on_exit(void *data) +{ + widget_base_on_exit(); +} + +EXPORT_API int widget_base_on_create(void) +{ + appcore_multiwindow_base_on_create(); + + return 0; +} + +EXPORT_API int widget_base_on_terminate(void) +{ + appcore_multiwindow_base_on_terminate(); + + return 0; +} + +EXPORT_API int widget_base_on_init(int argc, char **argv) +{ + return 0; +} + +EXPORT_API void widget_base_on_finish(void) +{ +} + +EXPORT_API void widget_base_on_run(void) +{ +} + +EXPORT_API void widget_base_on_exit(void) +{ +} + +EXPORT_API widget_base_ops widget_base_get_default_ops(void) +{ + widget_base_ops ops; + + /* override methods */ + ops.create = __on_create; + ops.terminate = __on_terminate; + ops.init = __on_init; + ops.finish = __on_finish; + ops.run = __on_run; + ops.exit = __on_exit; + + return ops; +} + +static void __free_class(gpointer data) +{ + widget_base_class *cls = data; + + free(cls->id); + free(cls); +} + +EXPORT_API void widget_base_fini(void) +{ + g_list_free_full(__context.classes, __free_class); + __context.classes = NULL; + + appcore_multiwindow_base_fini(); +} + +EXPORT_API int widget_base_context_window_bind( + widget_base_instance_h instance_h, const char *id, + Ecore_Wl_Window *wl_win) +{ + struct wl_surface *surface; + + surface = ecore_wl_window_surface_get(wl_win); + if (surface == NULL) { + LOGE("failed to get surface"); /* LCOV_EXCL_LINE */ + return WIDGET_BASE_ERROR_FAULT; /* LCOV_EXCL_LINE */ + } + + screen_connector_provider_remote_enable(id, surface); + appcore_multiwindow_base_window_bind(instance_h, wl_win); + + return WIDGET_BASE_ERROR_NONE; +} + +static int __class_on_create(widget_base_instance_h instance_h, bundle *content, + int w, int h, void *class_data) +{ + return widget_base_class_on_create(instance_h, content, w, h); +} + +static int __class_on_resume(widget_base_instance_h instance_h, void *class_data) +{ + return widget_base_class_on_resume(instance_h); +} + +static int __class_on_pause(widget_base_instance_h instance_h, + void *class_data) +{ + return widget_base_class_on_pause(instance_h); +} + +static int __class_on_resize(widget_base_instance_h instance_h, int w, int h, + void *class_data) +{ + return widget_base_class_on_resize(instance_h, w, h); +} + +static int __class_on_update(widget_base_instance_h instance_h, bundle *content, + int force, void *class_data) +{ + return widget_base_class_on_update(instance_h, content, force); +} + +static int __class_on_destroy(widget_base_instance_h instance_h, + widget_base_destroy_type_e reason, bundle *content, + void *class_data) +{ + return widget_base_class_on_destroy(instance_h, reason, content); +} + +static void __multiwindow_instance_create( + appcore_multiwindow_base_instance_h instance_h, + void *class_data) +{ + widget_base_instance_data *instance_data; + 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; + widget_base_class cls; + + appcore_multiwindow_base_class_on_create(instance_h); + instance_data = appcore_multiwindow_base_instance_get_extra(instance_h); + b = instance_data->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; + + cls = __get_class(class_id); + bundle_get_str(b, AUL_K_WIDGET_INSTANCE_ID, &id); + bundle_get_str(b, WIDGET_K_OPERATION, &operation); + + if (!operation) { + LOGE("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 (cls.ops.create) + ret = cls.ops.create(instance_h, content_info, w, h, class_data); + + if (ret < 0) { + LOGW("Create callback returns error(%d)", ret); + ret = __send_update_status(class_id, id, + WIDGET_INSTANCE_EVENT_CREATE_ABORTED, NULL); + __instance_drop(instance_h); + } else { + LOGD("%s is created", id); + 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 __multiwindow_instance_resume( + appcore_multiwindow_base_instance_h instance_h, + void *class_data) +{ + const char *id; + const char *class_id; + widget_base_class cls; + + appcore_multiwindow_base_class_on_resume(instance_h); + id = appcore_multiwindow_base_instance_get_id(instance_h); + class_id = appcore_multiwindow_base_instance_get_class_id(instance_h); + cls = __get_class(class_id); + + if (cls.ops.resume) + cls.ops.resume(instance_h, class_data); + + LOGD("%s is resumed", id); + __send_update_status(class_id, id, + WIDGET_INSTANCE_EVENT_RESUME, NULL); + + if (!__fg_signal) { + LOGD("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 __multiwindow_instance_pause( + appcore_multiwindow_base_instance_h instance_h, + void *class_data) +{ + const char *id; + const char *class_id; + widget_base_class cls; + + appcore_multiwindow_base_class_on_pause(instance_h); + id = appcore_multiwindow_base_instance_get_id(instance_h); + class_id = appcore_multiwindow_base_instance_get_class_id(instance_h); + cls = __get_class(class_id); + + if (cls.ops.pause) + cls.ops.pause(instance_h, class_data); + + LOGD("%s is paused", id); + __send_update_status(class_id, id, + WIDGET_INSTANCE_EVENT_PAUSE, NULL); + + if (__fg_signal) { + LOGD("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 __multiwindow_instance_terminate( + appcore_multiwindow_base_instance_h instance_h, + void *class_data) +{ + widget_base_instance_data *data; + bundle *b; + char *operation = NULL; + bundle *content_info; + widget_base_destroy_type_e reason = WIDGET_BASE_DESTROY_TYPE_TEMPORARY; + int event = WIDGET_INSTANCE_EVENT_TERMINATE; + const char *id; + const char *class_id; + widget_base_class cls; + + id = appcore_multiwindow_base_instance_get_id(instance_h); + class_id = appcore_multiwindow_base_instance_get_class_id(instance_h); + data = appcore_multiwindow_base_instance_get_extra( + (appcore_multiwindow_base_instance_h)instance_h); + b = data->args; + cls = __get_class(class_id); + + if (b) { + bundle_get_str(b, WIDGET_K_OPERATION, &operation); + if (operation && strcmp(operation, "destroy") == 0) + reason = WIDGET_BASE_DESTROY_TYPE_PERMANENT; + } + + if (data->content) + content_info = bundle_decode((const bundle_raw *)data->content, + strlen(data->content)); + else + content_info = bundle_create(); + + if (cls.ops.destroy) + cls.ops.destroy(instance_h, reason, content_info, class_data); + + LOGD("%s is destroyed %d", id, reason); + if (reason == WIDGET_BASE_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(instance_h); +} + +EXPORT_API int widget_base_class_on_create(widget_base_instance_h instance_h, + bundle *content, int w, int h) +{ + appcore_multiwindow_base_class_on_create(instance_h); + + return 0; +} + +EXPORT_API int widget_base_class_on_pause(widget_base_instance_h instance_h) +{ + appcore_multiwindow_base_class_on_pause(instance_h); + + return 0; +} + +EXPORT_API int widget_base_class_on_resume(widget_base_instance_h instance_h) +{ + appcore_multiwindow_base_class_on_resume(instance_h); + + return 0; +} + +EXPORT_API int widget_base_class_on_resize(widget_base_instance_h instance_h, + int w, int h) +{ + return 0; +} + +EXPORT_API int widget_base_class_on_update(widget_base_instance_h instance_h, + bundle *content, int force) +{ + return 0; +} + +EXPORT_API int widget_base_class_on_destroy(widget_base_instance_h instance_h, + widget_base_destroy_type_e reason, bundle *content) +{ + appcore_multiwindow_base_class_on_terminate(instance_h); + + return 0; +} + +EXPORT_API widget_base_class widget_base_class_get_default(void) +{ + widget_base_class cls; + + cls.ops.create = __class_on_create; + cls.ops.resize = __class_on_resize; + cls.ops.update = __class_on_update; + cls.ops.destroy = __class_on_destroy; + cls.ops.pause = __class_on_pause; + cls.ops.resume = __class_on_resume; + + return cls; +} + +EXPORT_API widget_base_class *widget_base_class_add(widget_base_class cls, + const char *class_id, void *class_data) +{ + widget_base_class *c; + appcore_multiwindow_base_class raw_cls; + + if (!__is_widget_feature_enabled()) { + LOGE("not supported"); + set_last_result(WIDGET_ERROR_NOT_SUPPORTED); + return NULL; + } + + if (!class_id) { + LOGE("class is is NULL"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + raw_cls.id = strdup(class_id); + raw_cls.data = class_data; + raw_cls.create = __multiwindow_instance_create; + raw_cls.terminate = __multiwindow_instance_terminate; + raw_cls.pause = __multiwindow_instance_pause; + raw_cls.resume = __multiwindow_instance_resume; + appcore_multiwindow_base_class_add(raw_cls); + + c = malloc(sizeof(widget_base_class)); + if (!c) + return NULL; + + *c = cls; + c->id = strdup(class_id); + __context.classes = g_list_append(__context.classes, c); + + return c; +} diff --git a/src/widget-log.h b/src/efl_base/widget-log.h old mode 100755 new mode 100644 similarity index 100% rename from src/widget-log.h rename to src/efl_base/widget-log.h diff --git a/src/widget-private.h b/src/efl_base/widget-private.h similarity index 92% rename from src/widget-private.h rename to src/efl_base/widget-private.h index 293e226..34fdc5f 100644 --- a/src/widget-private.h +++ b/src/efl_base/widget-private.h @@ -25,8 +25,6 @@ #include #include -#define FEATURE_SHELL_APPWIDGET "http://tizen.org/feature/shell.appwidget" - int widget_app_error(widget_error_e error, const char *function, const char *description); diff --git a/src/efl_base/widget_app.c b/src/efl_base/widget_app.c new file mode 100644 index 0000000..640dca2 --- /dev/null +++ b/src/efl_base/widget_app.c @@ -0,0 +1,518 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "widget_base.h" +#include "widget_app.h" +#include "widget-log.h" +#include "widget-private.h" +#include "widget_app_internal.h" + +#ifdef LOG_TAG +#undef LOG_TAG +#endif + +#define LOG_TAG "CAPI_WIDGET_APPLICATION" + +struct instance_data { + Evas_Object *win; +}; + +struct app_cb_info { + widget_app_lifecycle_callback_s *callback; + void *user_data; +}; + +struct app_class_cb_info { + widget_instance_lifecycle_callback_s callback; + void *user_data; +}; + +static int __class_resize(widget_base_instance_h instance_h, int w, int h, + void *class_data) +{ + int ret = 0; + struct instance_data *data; + struct app_class_cb_info *callback_data = + (struct app_class_cb_info *)class_data; + + widget_base_class_on_resize(instance_h, w, h); + data = (struct instance_data *) + widget_base_context_get_user_data(instance_h); + if (data->win) + evas_object_resize(data->win, w, h); + else + _E("unable to find window"); + + if (callback_data && callback_data->callback.resize) { + ret = callback_data->callback.resize( + (widget_context_h)instance_h, + w, h, callback_data->user_data); + } + + return ret; +} + +static int __class_update(widget_base_instance_h instance_h, bundle *content, + int force, void *class_data) +{ + int ret = 0; + struct app_class_cb_info *callback_data = + (struct app_class_cb_info *)class_data; + + widget_base_class_on_update(instance_h, content, force); + if (callback_data && callback_data->callback.update) { + ret = callback_data->callback.update( + (widget_context_h)instance_h, + content, force, callback_data->user_data); + } + + return ret; +} + +static int __class_create(widget_base_instance_h instance_h, bundle *content, + int w, int h, void *class_data) +{ + int ret = -1; + struct app_class_cb_info *callback_data = + (struct app_class_cb_info *)class_data; + + widget_base_class_on_create(instance_h, content, w, h); + if (callback_data && callback_data->callback.create) { + ret = callback_data->callback.create( + (widget_context_h)instance_h, + content, w, h, callback_data->user_data); + } + return ret; +} + +static int __class_destroy(widget_base_instance_h instance_h, + widget_base_destroy_type_e reason, bundle *content, + void *class_data) +{ + int ret = 0; + struct instance_data *data; + struct app_class_cb_info *callback_data = + (struct app_class_cb_info *)class_data; + + if (callback_data && callback_data->callback.destroy) { + ret = callback_data->callback.destroy( + (widget_context_h)instance_h, + reason, content, callback_data->user_data); + } + + data = (struct instance_data *)widget_base_context_get_user_data(instance_h); + if (data != NULL) { + widget_base_context_set_user_data(instance_h, NULL); + free(data); + } + + widget_base_class_on_destroy(instance_h, reason, content); + + return ret; +} + +static int __class_pause(widget_base_instance_h instance_h, void *class_data) +{ + int ret = 0; + struct app_class_cb_info *callback_data = + (struct app_class_cb_info *)class_data; + + widget_base_class_on_pause(instance_h); + if (callback_data && callback_data->callback.pause) { + ret = callback_data->callback.pause( + (widget_context_h)instance_h, + callback_data->user_data); + } + + return ret; +} + +static int __class_resume(widget_base_instance_h instance_h, void *class_data) +{ + int ret = 0; + struct app_class_cb_info *callback_data = + (struct app_class_cb_info *)class_data; + + widget_base_class_on_resume(instance_h); + if (callback_data && callback_data->callback.resume) { + ret = callback_data->callback.resume( + (widget_context_h)instance_h, + callback_data->user_data); + } + + return ret; +} + +static int __widget_app_create(void *data) +{ + struct app_cb_info *cb_info = (struct app_cb_info *)data; + widget_app_lifecycle_callback_s *callback; + + widget_base_on_create(); + if (cb_info && cb_info->callback && cb_info->callback->create) { + callback = cb_info->callback; + if (callback->create(cb_info->user_data) == NULL) { + _D("fail to create widget"); + return -1; + } + _D("widget app is created"); + return 0; + } + + return -1; +} + +static int __widget_app_terminate(void *data) +{ + struct app_cb_info *cb_info = (struct app_cb_info *)data; + widget_app_lifecycle_callback_s *callback; + + if (cb_info && cb_info->callback && cb_info->callback->terminate) { + callback = cb_info->callback; + callback->terminate(cb_info->user_data); + widget_base_on_terminate(); + _D("widget app is terminated"); + + return 0; + } + + widget_base_on_terminate(); + + return -1; +} + +static void __widget_app_init(int argc, char **argv, void *data) +{ + elm_init(argc, argv); +} + +static void __widget_app_finish(void) +{ + elm_shutdown(); +} + +static void __widget_app_run(void *data) +{ + elm_run(); +} + +static void __widget_app_exit(void *data) +{ + elm_exit(); +} + +EXPORT_API int widget_app_main(int argc, char **argv, + widget_app_lifecycle_callback_s *callback, void *user_data) +{ + widget_base_ops ops; + struct app_cb_info cb_info; + int r; + + if (argc <= 0 || argv == NULL || callback == NULL) + return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, + __FUNCTION__, NULL); + + if (callback->create == NULL) + return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, + __FUNCTION__, + "widget_app_create_cb() callback must be " + "registered"); + + ops.create = __widget_app_create; + ops.terminate = __widget_app_terminate; + ops.init = __widget_app_init; + ops.finish = __widget_app_finish; + ops.run = __widget_app_run; + ops.exit = __widget_app_exit; + + cb_info.callback = callback; + cb_info.user_data = user_data; + + r = widget_base_init(ops, argc, argv, &cb_info); + widget_base_fini(); + + return r; +} + +EXPORT_API int widget_app_exit(void) +{ + return widget_base_exit(); +} + +EXPORT_API int widget_app_terminate_context(widget_context_h context) +{ + return widget_base_terminate_context((widget_base_instance_h)context); +} + +EXPORT_API int widget_app_foreach_context(widget_context_cb cb, void *data) +{ + return widget_base_foreach_context((widget_base_instance_cb)cb, data); +} + +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) +{ + return widget_base_add_event_handler(event_handler, event_type, + callback, user_data); +} + +EXPORT_API int widget_app_remove_event_handler(app_event_handler_h + event_handler) +{ + return widget_base_remove_event_handler(event_handler); +} + +EXPORT_API const char *widget_app_get_id(widget_context_h context) +{ + int ret; + char *id; + + if (!context) { + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + ret = widget_base_context_get_id((widget_base_instance_h)context, &id); + if (ret != WIDGET_BASE_ERROR_NONE) { + _E("failed to get context id"); /* LCOV_EXCL_LINE */ + set_last_result(ret); /* LCOV_EXCL_LINE */ + return NULL; /* LCOV_EXCL_LINE */ + } + + set_last_result(WIDGET_ERROR_NONE); + return id; +} + +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) +{ + Evas_Object *ret_win = NULL; + Ecore_Wl_Window *wl_win; + struct instance_data *data; + char buffer[256]; + int rots[3] = {0}; + int win_id; + char *id; + int ret; + + if (context == NULL || win == NULL) + return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, + __FUNCTION__, NULL); + + ret = widget_base_context_get_id((widget_base_instance_h)context, &id); + if (ret != WIDGET_BASE_ERROR_NONE) { + _E("failed to get context id"); /* LCOV_EXCL_LINE */ + goto fault; /* LCOV_EXCL_LINE */ + } + + ret_win = elm_win_add(NULL, id, ELM_WIN_BASIC); + if (ret_win == NULL) { + _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"); /* LCOV_EXCL_LINE */ + goto fault; + } + + ecore_wl_window_class_name_set(wl_win, id); + elm_win_aux_hint_add(ret_win, "wm.policy.win.user.geometry", "1"); + widget_base_context_window_bind((widget_base_instance_h)context, id, 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); + + win_id = ecore_wl_window_id_get(wl_win); + _D("window created: %d", win_id); + + data = (struct instance_data *)widget_base_context_get_user_data( + (widget_base_instance_h)context); + if (data == NULL) { + data = calloc(1, sizeof(struct instance_data)); + if (data == NULL) { + _E("failed to alloc instance_data"); /* LCOV_EXCL_LINE */ + goto fault; /* LCOV_EXCL_LINE */ + } + + ret = widget_base_context_set_user_data((widget_base_instance_h)context, data); + if (ret != WIDGET_BASE_ERROR_NONE) { + _E("fail to set extra data"); /* LCOV_EXCL_LINE */ + goto fault; /* LCOV_EXCL_LINE */ + } + } + + data->win = ret_win; + *win = ret_win; + + 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 */ +} + +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_base_class cls; + struct app_class_cb_info *callback_data; + widget_class_h wc; + + cls = widget_base_class_get_default(); + + /* override methods */ + cls.ops.create = __class_create; + cls.ops.destroy = __class_destroy; + cls.ops.pause = __class_pause; + cls.ops.resume = __class_resume; + cls.ops.resize = __class_resize; + cls.ops.update = __class_update; + + callback_data = calloc(1, sizeof(struct app_class_cb_info)); + if (!callback_data) { + _E("failed to calloc : %s", __FUNCTION__); + set_last_result(WIDGET_ERROR_OUT_OF_MEMORY); + return NULL; + } + callback_data->callback = callback; + callback_data->user_data = user_data; + + wc = (widget_class_h)widget_base_class_add(cls, class_id, + callback_data); + + if (!wc) { + free(callback_data); + return NULL; + } + + set_last_result(WIDGET_ERROR_NONE); + + return wc; +} + +EXPORT_API widget_class_h widget_app_class_create( + widget_instance_lifecycle_callback_s callback, void *user_data) +{ + char *appid; + widget_class_h wc; + + app_get_id(&appid); + if (!appid) { + LOGE("appid is NULL"); + return NULL; + } + + wc = (widget_class_h)widget_app_class_add(NULL, appid, callback, + user_data); + free(appid); + + return wc; +} + +EXPORT_API int widget_app_context_set_tag(widget_context_h context, void *tag) +{ + int ret = 0; + + ret = widget_base_context_set_tag((widget_base_instance_h)context, tag); + if (ret != WIDGET_BASE_ERROR_NONE) + return widget_app_error(ret, __FUNCTION__, NULL); + + return WIDGET_ERROR_NONE; +} + +EXPORT_API int widget_app_context_get_tag(widget_context_h context, void **tag) +{ + int ret = 0; + + ret = widget_base_context_get_tag((widget_base_instance_h)context, tag); + if (ret != WIDGET_BASE_ERROR_NONE) + return widget_app_error(ret, __FUNCTION__, NULL); + + return WIDGET_ERROR_NONE; +} + +EXPORT_API int widget_app_context_set_content_info(widget_context_h context, + bundle *content_info) +{ + int ret = 0; + + ret = widget_base_context_set_content_info( + (widget_base_instance_h)context, content_info); + if (ret != WIDGET_BASE_ERROR_NONE) + return widget_app_error(ret, __FUNCTION__, NULL); + + return WIDGET_ERROR_NONE; +} + +EXPORT_API int widget_app_context_set_title(widget_context_h context, + const char *title) +{ + struct instance_data *data = NULL; + int ret; + + if (!context || !title) { + _E("Invalid parameter %p %p", context, title); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + data = (struct instance_data *)widget_base_context_get_user_data( + (widget_base_instance_h)context); + if (data == NULL) { + data = calloc(1, sizeof(struct instance_data)); + if (data == NULL) { + return widget_app_error(WIDGET_ERROR_FAULT, + __FUNCTION__, NULL); + } + ret = widget_base_context_set_user_data(context, data); + if (ret != WIDGET_BASE_ERROR_NONE) + widget_app_error(ret, __FUNCTION__, NULL); + } + + if (data->win) + elm_win_title_set(data->win, title); + + return WIDGET_ERROR_NONE; +} diff --git a/src/widget_app_internal.c b/src/efl_base/widget_app_internal.c similarity index 95% rename from src/widget_app_internal.c rename to src/efl_base/widget_app_internal.c index 302248f..43de979 100644 --- a/src/widget_app_internal.c +++ b/src/efl_base/widget_app_internal.c @@ -34,13 +34,13 @@ #include "widget-private.h" #include "widget_app_internal.h" #include "widget-private.h" +#include "widget_base.h" #ifdef LOG_TAG #undef LOG_TAG #endif #define LOG_TAG "CAPI_WIDGET_APPLICATION" -extern char *_viewer_endpoint; static char *__class_id; static void __inst_cb(const char *class_id, const char *id, @@ -61,7 +61,7 @@ EXPORT_API int widget_app_restart(void) kb = bundle_create(); bundle_add_str(kb, AUL_K_WIDGET_ID, __class_id); bundle_add_byte(kb, AUL_K_WIDGET_STATUS, &status, sizeof(int)); - ret = aul_app_com_send(_viewer_endpoint, kb); + ret = aul_app_com_send(widget_base_get_viewer_endpoint(), kb); bundle_free(kb); if (__class_id) { free(__class_id); diff --git a/src/widget_error.c b/src/efl_base/widget_error.c old mode 100755 new mode 100644 similarity index 100% rename from src/widget_error.c rename to src/efl_base/widget_error.c diff --git a/src/widget_app.c b/src/widget_app.c deleted file mode 100755 index 5479b95..0000000 --- a/src/widget_app.c +++ /dev/null @@ -1,1312 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "widget_app.h" -#include "widget-log.h" -#include "widget-private.h" -#include "widget_app_internal.h" - -#ifdef LOG_TAG -#undef LOG_TAG -#endif - -#define LOG_TAG "CAPI_WIDGET_APPLICATION" -#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; -}; - -struct widget_class_context { - widget_instance_lifecycle_callback_s callback; - void *data; -}; - -struct widget_app_context { - widget_app_lifecycle_callback_s callback; - void *data; - bool dirty; -}; - -struct widget_foreach_context { - widget_context_cb callback; - void *data; -}; - -struct app_event_info { - app_event_type_e type; - void *value; -}; - -struct app_event_handler { - app_event_type_e type; - app_event_cb cb; - void *data; - void *raw; -}; - -struct _widget_context { - int dummy; -}; - -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 struct widget_app_context __context; -static char *__appid; -static char *__package_id; -static bool __fg_signal; -char *_viewer_endpoint; - -static bool __is_widget_feature_enabled(void) -{ - static bool feature = false; - static bool retrieved = false; - int ret; - - if (retrieved == true) - return feature; - - 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"); /* LCOV_EXCL_LINE */ - return false; /* LCOV_EXCL_LINE */ - } - - retrieved = true; - - return feature; -} - -/* LCOV_EXCL_START */ -static void __on_poweroff(keynode_t *key, void *data) -{ - int val; - - 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 int __widget_app_create(void *data) -{ - char pkgid[256] = {0, }; - - 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); - - 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 __widget_app_terminate(void *data) -{ - if (__context.callback.terminate) - __context.callback.terminate(__context.data); - - vconf_ignore_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, __on_poweroff); - screen_connector_provider_fini(); - - if (_viewer_endpoint) { - free(_viewer_endpoint); - _viewer_endpoint = NULL; - } - - if (__package_id) { - free(__package_id); - __package_id = NULL; - } - - if (__appid) { - free(__appid); - __appid = NULL; - } - - appcore_multiwindow_base_on_terminate(); - - _D("widget app is terminated"); - return 0; -} - -static int __send_lifecycle_event(const char *class_id, const char *instance_id, - int status) -{ - bundle *b = bundle_create(); - int ret; - - if (b == NULL) { - _E("out of memory"); /* LCOV_EXCL_LINE */ - return -1; /* LCOV_EXCL_LINE */ - } - - 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); - - _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 */ - - bundle_free(b); - - return ret; -} - -static int __send_update_status(const char *class_id, const char *instance_id, - int status, bundle *extra) -{ - 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 */ - } - - 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)); - - 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); - } - - _D("send update %s(%d) to %s", instance_id, status, _viewer_endpoint); - aul_app_com_send(_viewer_endpoint, b); - - 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; - } - - if (lifecycle > -1) - __send_lifecycle_event(class_id, instance_id, lifecycle); - - bundle_free(b); - if (raw) - free(raw); - - return 0; -} - -static void __instance_resume(const char *class_id, const char *id, bundle *b) -{ - appcore_multiwindow_base_instance_h cxt; - - cxt = appcore_multiwindow_base_instance_find(id); - - 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; - - cxt = appcore_multiwindow_base_instance_find(id); - - if (!cxt) { - _E("context not found: %s", id); - return; - } - - 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 __instance_resize(const char *class_id, const char *id, bundle *b) -{ - 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; - char *w_str = NULL; - char *h_str = NULL; - int w = 0; - int h = 0; - - cxt = appcore_multiwindow_base_instance_find(id); - - if (!cxt) { - _E("context not found: %s", id); - return; - } - - cls = appcore_multiwindow_base_instance_get_class(cxt); - if (!cls) - return; - - class_cxt = cls->data; - if (!class_cxt) { - _E("class is NULL"); - return; - } - - we = appcore_multiwindow_base_instance_get_extra(cxt); - if (!we) { - _E("widget extra is NULL"); - return; - } - - 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 (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 void __inst_cb(const char *class_id, const char *id, - appcore_multiwindow_base_instance_h cxt, void *data) -{ - 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; - } - - cls = appcore_multiwindow_base_instance_get_class(cxt); - if (!cls) { - _E("class is NULL"); - return; - } - - class_cxt = cls->data; - if (!class_cxt) { - _E("class context is NULL"); - return; - } - - 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 void __instance_update(const char *class_id, const char *id, bundle *b) -{ - appcore_multiwindow_base_instance_h cxt; - - if (!id) { - appcore_multiwindow_base_instance_foreach(class_id, __inst_cb, b); - return; - } - - cxt = appcore_multiwindow_base_instance_find(id); - - if (!cxt) { - _E("context not found: %s", id); - return; - } - - __inst_cb(class_id, id, cxt, b); -} - -static void __instance_create(const char *class_id, const char *id, bundle *b) -{ - struct widget_extra *we; - char *content = NULL; - - we = (struct widget_extra *)calloc(1, sizeof(struct widget_extra)); - if (!we) { - _E("Out of memory"); - return; - } - - 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); - -} - -static void __check_empty_instance(void) -{ - int cnt = appcore_multiwindow_base_instance_get_cnt(); - - 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; - } - - 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(); -} - -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; - } - - 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); - } - - return 0; -} - -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); -} - -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; - } - - cxt = appcore_multiwindow_base_instance_find(instance_id); - if (!cxt) { - _E("could not find widget obj: %s", instance_id); - return; - } - - we = appcore_multiwindow_base_instance_get_extra(cxt); - if (!we) { - _E("widget extra is NULL"); - return; - } - - 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 int __widget_app_receive(aul_type type, bundle *b, void *data) -{ - appcore_multiwindow_base_on_receive(type, b); - - 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; - } - - return 0; -} - -static void __widget_app_init(int argc, char **argv, void *data) -{ - elm_init(argc, argv); -} - -static void __widget_app_finish(void) -{ - elm_shutdown(); - - /* Check Loader case */ - if (getenv("AUL_LOADER_INIT")) { - unsetenv("AUL_LOADER_INIT"); - elm_shutdown(); - } -} - -static void __widget_app_run(void *data) -{ - elm_run(); -} - -static void __widget_app_exit(void *data) -{ - elm_exit(); -} - -EXPORT_API int widget_app_main(int argc, char **argv, - widget_app_lifecycle_callback_s *callback, void *user_data) -{ - bundle *kb; - char *viewer_endpoint = NULL; - - 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"); - - appcore_multiwindow_base_ops ops = appcore_multiwindow_base_get_default_ops(); - - /* 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; - ops.base.init = __widget_app_init; - ops.base.finish = __widget_app_finish; - ops.base.run = __widget_app_run; - ops.base.exit = __widget_app_exit; - - __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"); /* LCOV_EXCL_LINE */ - return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */ - } - - appcore_multiwindow_base_exit(); - aul_widget_notify_exit(); - - return WIDGET_ERROR_NONE; -} - -static gboolean __finish_event_cb(gpointer user_data) -{ - appcore_multiwindow_base_instance_h cxt = user_data; - bundle *b; - const char *id; - const char *class_id; - - if (!cxt) { - _E("user_data is NULL"); - return FALSE; - } - - id = appcore_multiwindow_base_instance_get_id(cxt); - class_id = appcore_multiwindow_base_instance_get_class_id(cxt); - b = bundle_create(); - - 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"); /* LCOV_EXCL_LINE */ - return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */ - } - - if (context == NULL) - return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, - __FUNCTION__, NULL); - - g_idle_add(__finish_event_cb, 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) -{ - 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) { - _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) -{ - 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; - - if (event_handler == NULL || callback == NULL) - return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL); - - 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); - - - 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; -} - -EXPORT_API int widget_app_remove_event_handler(app_event_handler_h - event_handler) -{ - 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; - - 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"); /* LCOV_EXCL_LINE */ - set_last_result(WIDGET_ERROR_NOT_SUPPORTED); /* LCOV_EXCL_LINE */ - return NULL; /* LCOV_EXCL_LINE */ - } - - if (!context) { - set_last_result(WIDGET_ERROR_INVALID_PARAMETER); - return NULL; - } - - 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) -{ - Evas_Object *ret_win; - Ecore_Wl_Window *wl_win; - 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); - - 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"); /* 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"); /* 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, id); - elm_win_aux_hint_add(ret_win, "wm.policy.win.user.geometry", "1"); - - *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, wl_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(); -} - -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", 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) -{ - appcore_multiwindow_base_class cls; - struct widget_class_context *cxt; - - if (!__is_widget_feature_enabled()) { - _E("not supported"); - set_last_result(WIDGET_ERROR_NOT_SUPPORTED); - return NULL; - } - - if (!class_id) { - _E("class is is NULL"); - set_last_result(WIDGET_ERROR_INVALID_PARAMETER); - return NULL; - } - - 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; - } - - cxt->callback = callback; - cxt->data = user_data; - - cls.id = strdup(class_id); - cls.data = cxt; - cls.create = __stub_create; - cls.terminate = __stub_terminate; - cls.pause = __stub_pause; - cls.resume = __stub_resume; - - appcore_multiwindow_base_class_add(cls); - set_last_result(WIDGET_ERROR_NONE); - - 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_app_class_add(NULL, __appid, callback, user_data); -} - -EXPORT_API int widget_app_context_set_tag(widget_context_h context, void *tag) -{ - 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) - return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, - __FUNCTION__, NULL); - - 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) -{ - 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 || !tag) - return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, - __FUNCTION__, NULL); - - 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; -} - -EXPORT_API int widget_app_context_set_content_info(widget_context_h context, - bundle *content_info) -{ - int ret = 0; - 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 || !content_info) - return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, - __FUNCTION__, NULL); - - 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 || !id || !we) - return widget_app_error(WIDGET_ERROR_FAULT, __FUNCTION__, NULL); - - 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) { - /* 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; -} - -EXPORT_API int widget_app_context_set_title(widget_context_h context, - const char *title) -{ - appcore_multiwindow_base_instance_h cxt; - 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 || !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; -} -- 2.7.4 From 77971833be97a92e33b931311dc0bfc1152e5767 Mon Sep 17 00:00:00 2001 From: Junghoon Park Date: Tue, 12 Sep 2017 09:50:02 +0900 Subject: [PATCH 12/16] Release version 1.2.0 Changes: - Create widget base API set Change-Id: Ieab9ae316d562894df32fe53fc3d7d9aaa680326 Signed-off-by: Junghoon Park --- packaging/appcore-widget.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/appcore-widget.spec b/packaging/appcore-widget.spec index 9cc0e6f..bf74f68 100644 --- a/packaging/appcore-widget.spec +++ b/packaging/appcore-widget.spec @@ -1,6 +1,6 @@ Name: appcore-widget Summary: Widget Application -Version: 1.1.5 +Version: 1.2.0 Release: 1 Group: Application Framework/Libraries License: Apache-2.0 -- 2.7.4 From fdf263c9b2470291ad6ee3c599a21ad1cd6c7231 Mon Sep 17 00:00:00 2001 From: Hyunho Kang Date: Wed, 20 Sep 2017 20:22:16 +0900 Subject: [PATCH 13/16] Fix base fini sequence Change-Id: I8cee3f3c86d9ffaeb54ecdc8d41078d27302bf4e Signed-off-by: Hyunho Kang --- src/base/widget_base.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/base/widget_base.c b/src/base/widget_base.c index 7cbba6c..9df3504 100644 --- a/src/base/widget_base.c +++ b/src/base/widget_base.c @@ -1110,10 +1110,9 @@ static void __free_class(gpointer data) EXPORT_API void widget_base_fini(void) { + appcore_multiwindow_base_fini(); g_list_free_full(__context.classes, __free_class); __context.classes = NULL; - - appcore_multiwindow_base_fini(); } EXPORT_API int widget_base_context_window_bind( -- 2.7.4 From b4dcaba71d2eb7f78055b01b7cc2acef438c5915 Mon Sep 17 00:00:00 2001 From: Hyunho Kang Date: Wed, 20 Sep 2017 20:25:34 +0900 Subject: [PATCH 14/16] Add get class exception handling logic Change-Id: Ia7098fae5c74d763b59a5853bd4801329a5d4a68 Signed-off-by: Hyunho Kang --- src/base/widget_base.c | 71 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 21 deletions(-) diff --git a/src/base/widget_base.c b/src/base/widget_base.c index 9df3504..6f19ce9 100644 --- a/src/base/widget_base.c +++ b/src/base/widget_base.c @@ -162,16 +162,20 @@ static gint __comp_class(gconstpointer a, gconstpointer b) return strcmp(cls->id, b); } -static widget_base_class __get_class(const char *class_id) +static widget_base_class *__get_class(const char *class_id) { widget_base_class *cls; GList *class_node; class_node = g_list_find_custom(__context.classes, class_id, __comp_class); + if (class_node == NULL) { + LOGE("empty classes"); + return NULL; + } cls = (widget_base_class *)class_node->data; - return *cls; + return cls; } static int __send_lifecycle_event(const char *class_id, const char *instance_id, @@ -313,7 +317,7 @@ static void __control_resize(const char *class_id, const char *id, bundle *b) int w = 0; int h = 0; void *class_data; - widget_base_class cls; + widget_base_class *cls; const appcore_multiwindow_base_class *raw_cls; instance_h = appcore_multiwindow_base_instance_find(id); @@ -327,6 +331,10 @@ static void __control_resize(const char *class_id, const char *id, bundle *b) return; cls = __get_class(class_id); + if (cls == NULL) { + LOGE("class not found: %s", class_id); + return; + } class_data = raw_cls->data; bundle_get_str(b, WIDGET_K_WIDTH, &w_str); bundle_get_str(b, WIDGET_K_HEIGHT, &h_str); @@ -337,8 +345,8 @@ static void __control_resize(const char *class_id, const char *id, bundle *b) if (h_str) h = (int)g_ascii_strtoll(h_str, &remain, 10); - if (cls.ops.resize) - cls.ops.resize(instance_h, w, h, class_data); + if (cls->ops.resize) + cls->ops.resize(instance_h, w, h, class_data); LOGD("%s is resized to %dx%d", id, w, h); __send_update_status(class_id, id, @@ -355,7 +363,7 @@ static void __update_cb(const char *class_id, const char *id, char *force_str = NULL; int force; bundle *b = data; - widget_base_class cls; + widget_base_class *cls; if (!b) { LOGE("bundle is NULL"); @@ -370,8 +378,12 @@ static void __update_cb(const char *class_id, const char *id, class_data = raw_cls->data; cls = __get_class(class_id); + if (cls == NULL) { + LOGE("class not found: %s", class_id); + return; + } - if (!cls.ops.update) { + if (!cls->ops.update) { LOGE("update callback is NULL"); return; } @@ -390,8 +402,8 @@ static void __update_cb(const char *class_id, const char *id, strlen(content_raw)); } - if (cls.ops.update) - cls.ops.update(instance_h, content, force, class_data); + if (cls->ops.update) + cls->ops.update(instance_h, content, force, class_data); __send_update_status(class_id, id, WIDGET_INSTANCE_EVENT_UPDATE, NULL); @@ -1186,7 +1198,7 @@ static void __multiwindow_instance_create( int w = 0; int h = 0; int ret = -1; - widget_base_class cls; + widget_base_class *cls; appcore_multiwindow_base_class_on_create(instance_h); instance_data = appcore_multiwindow_base_instance_get_extra(instance_h); @@ -1198,6 +1210,11 @@ static void __multiwindow_instance_create( class_id = __appid; cls = __get_class(class_id); + if (cls == NULL) { + LOGE("class not found: %s", class_id); + return; + } + bundle_get_str(b, AUL_K_WIDGET_INSTANCE_ID, &id); bundle_get_str(b, WIDGET_K_OPERATION, &operation); @@ -1220,8 +1237,8 @@ static void __multiwindow_instance_create( content_info = bundle_decode((const bundle_raw *)content, strlen(content)); - if (cls.ops.create) - ret = cls.ops.create(instance_h, content_info, w, h, class_data); + if (cls->ops.create) + ret = cls->ops.create(instance_h, content_info, w, h, class_data); if (ret < 0) { LOGW("Create callback returns error(%d)", ret); @@ -1246,15 +1263,19 @@ static void __multiwindow_instance_resume( { const char *id; const char *class_id; - widget_base_class cls; + widget_base_class *cls; appcore_multiwindow_base_class_on_resume(instance_h); id = appcore_multiwindow_base_instance_get_id(instance_h); class_id = appcore_multiwindow_base_instance_get_class_id(instance_h); cls = __get_class(class_id); + if (cls == NULL) { + LOGE("class not found: %s", class_id); + return; + } - if (cls.ops.resume) - cls.ops.resume(instance_h, class_data); + if (cls->ops.resume) + cls->ops.resume(instance_h, class_data); LOGD("%s is resumed", id); __send_update_status(class_id, id, @@ -1277,15 +1298,19 @@ static void __multiwindow_instance_pause( { const char *id; const char *class_id; - widget_base_class cls; + widget_base_class *cls; appcore_multiwindow_base_class_on_pause(instance_h); id = appcore_multiwindow_base_instance_get_id(instance_h); class_id = appcore_multiwindow_base_instance_get_class_id(instance_h); cls = __get_class(class_id); + if (cls == NULL) { + LOGE("class not found: %s", class_id); + return; + } - if (cls.ops.pause) - cls.ops.pause(instance_h, class_data); + if (cls->ops.pause) + cls->ops.pause(instance_h, class_data); LOGD("%s is paused", id); __send_update_status(class_id, id, @@ -1314,7 +1339,7 @@ static void __multiwindow_instance_terminate( int event = WIDGET_INSTANCE_EVENT_TERMINATE; const char *id; const char *class_id; - widget_base_class cls; + widget_base_class *cls; id = appcore_multiwindow_base_instance_get_id(instance_h); class_id = appcore_multiwindow_base_instance_get_class_id(instance_h); @@ -1322,6 +1347,10 @@ static void __multiwindow_instance_terminate( (appcore_multiwindow_base_instance_h)instance_h); b = data->args; cls = __get_class(class_id); + if (cls == NULL) { + LOGE("class not found: %s", class_id); + return; + } if (b) { bundle_get_str(b, WIDGET_K_OPERATION, &operation); @@ -1335,8 +1364,8 @@ static void __multiwindow_instance_terminate( else content_info = bundle_create(); - if (cls.ops.destroy) - cls.ops.destroy(instance_h, reason, content_info, class_data); + if (cls->ops.destroy) + cls->ops.destroy(instance_h, reason, content_info, class_data); LOGD("%s is destroyed %d", id, reason); if (reason == WIDGET_BASE_DESTROY_TYPE_PERMANENT) { -- 2.7.4 From d991f02b6d603d98d9bed4478b31d21efc562877 Mon Sep 17 00:00:00 2001 From: Hyunho Kang Date: Wed, 28 Jun 2017 20:41:33 +0900 Subject: [PATCH 15/16] Use common normal exit notify API - aul_notify_exit https://review.tizen.org/gerrit/#/c/136199/ (amd) https://review.tizen.org/gerrit/#/c/136200/ (aul-1) https://review.tizen.org/gerrit/#/c/136201/ (appcore-widget) https://review.tizen.org/gerrit/#/c/136209/ (widget-service) Change-Id: I92863ca2c88e8ac552012a5b5c4ae4f190833029 Signed-off-by: Hyunho Kang --- src/base/widget_base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/base/widget_base.c b/src/base/widget_base.c index 6f19ce9..8e74db9 100644 --- a/src/base/widget_base.c +++ b/src/base/widget_base.c @@ -644,7 +644,7 @@ static void __multiwindow_exit(void *data) EXPORT_API int widget_base_exit(void) { appcore_multiwindow_base_exit(); - aul_widget_notify_exit(); + aul_notify_exit(); return 0; } -- 2.7.4 From c2233b1e963b14080d8725edbde500649eb7ad52 Mon Sep 17 00:00:00 2001 From: Junghoon Park Date: Wed, 19 Jul 2017 15:09:56 +0900 Subject: [PATCH 16/16] Implement periodic update - update-callabck should be invoked periodically when the value of 'update-period' is bigger then 0 - Paused widget's update-callback should be deferred until it is resumed - Require https://review.tizen.org/gerrit/#/c/139466/ Change-Id: Id30e4de0576f3cb8b35743fff0ac37989356df6d Signed-off-by: Junghoon Park Signed-off-by: Hyunho Kang --- src/base/widget_base.c | 117 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 96 insertions(+), 21 deletions(-) diff --git a/src/base/widget_base.c b/src/base/widget_base.c index 8e74db9..d479c52 100644 --- a/src/base/widget_base.c +++ b/src/base/widget_base.c @@ -84,8 +84,12 @@ typedef struct _widget_base_context { typedef struct _widget_base_instance_data { bundle *args; + char *id; char *content; void *tag; + double period; + guint periodic_timer; + bool pending_update; void *user_data; } widget_base_instance_data; @@ -94,6 +98,32 @@ static char *__appid; static char *__package_id; static bool __fg_signal; static char *__viewer_endpoint; +static void __call_update_cb(const char *class_id, const char *id, int force, + const char *content_raw); + +static gboolean __timeout_cb(gpointer user_data) +{ + widget_base_instance_data *data = + (widget_base_instance_data *)user_data; + appcore_multiwindow_base_instance_h cxt; + const char *class_id; + + cxt = appcore_multiwindow_base_instance_find(data->id); + if (appcore_multiwindow_base_instance_is_resumed(cxt)) { + LOGD("Periodic update!"); + class_id = appcore_multiwindow_base_instance_get_class_id(cxt); + __call_update_cb(class_id, data->id, 0, NULL); + } else { + data->pending_update = true; + if (data->periodic_timer) { + LOGD("Remove timer!"); + g_source_remove(data->periodic_timer); + data->periodic_timer = 0; + } + } + + return G_SOURCE_CONTINUE; +} static bool __is_widget_feature_enabled(void) { @@ -151,6 +181,7 @@ static void __instance_drop(appcore_multiwindow_base_instance_h instance_h) data = appcore_multiwindow_base_instance_get_extra(instance_h); appcore_multiwindow_base_instance_drop(instance_h); free(data->content); + free(data->id); free(data); __check_empty_instance(); } @@ -260,6 +291,9 @@ static void __control_create(const char *class_id, const char *id, bundle *b) { widget_base_instance_data *data; char *content = NULL; + double *period = NULL; + size_t size; + int ret; data = (widget_base_instance_data *) calloc(1, sizeof(widget_base_instance_data)); @@ -268,7 +302,14 @@ static void __control_create(const char *class_id, const char *id, bundle *b) return; } + data->id = strdup(id); data->args = b; + ret = bundle_get_byte(b, WIDGET_K_PERIOD, (void **)&period, &size); + if (ret == BUNDLE_ERROR_NONE) { + data->period = *period; + data->periodic_timer = g_timeout_add_seconds(data->period, + __timeout_cb, data); + } /* call stub create */ appcore_multiwindow_base_instance_run(class_id, id, data); @@ -353,20 +394,18 @@ static void __control_resize(const char *class_id, const char *id, bundle *b) WIDGET_INSTANCE_EVENT_SIZE_CHANGED, NULL); } -static void __update_cb(const char *class_id, const char *id, - appcore_multiwindow_base_instance_h instance_h, void *data) +static void __call_update_cb(const char *class_id, const char *id, int force, + const char *content_raw) { void *class_data; + widget_base_class *cls; const appcore_multiwindow_base_class *raw_cls; + appcore_multiwindow_base_instance_h instance_h; bundle *content = NULL; - char *content_raw = NULL; - char *force_str = NULL; - int force; - bundle *b = data; - widget_base_class *cls; - if (!b) { - LOGE("bundle is NULL"); + instance_h = appcore_multiwindow_base_instance_find(id); + if (!instance_h) { + LOGE("context not found: %s", id); return; } @@ -388,15 +427,6 @@ static void __update_cb(const char *class_id, const char *id, 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)); @@ -413,13 +443,37 @@ static void __update_cb(const char *class_id, const char *id, bundle_free(content); } +static void __update_process(const char *class_id, const char *id, + appcore_multiwindow_base_instance_h instance_h, void *data) +{ + char *content_raw = NULL; + char *force_str = NULL; + int force; + bundle *b = data; + + if (!b) { + LOGE("bundle 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); + __call_update_cb(class_id, id, force, content_raw); +} + static void __control_update(const char *class_id, const char *id, bundle *b) { appcore_multiwindow_base_instance_h instance_h; if (!id) { appcore_multiwindow_base_instance_foreach(class_id, - __update_cb, b); + __update_process, b); return; } @@ -429,7 +483,7 @@ static void __control_update(const char *class_id, const char *id, bundle *b) return; } - __update_cb(class_id, id, instance_h, b); + __update_process(class_id, id, instance_h, b); } static void __control_destroy(const char *class_id, const char *id, bundle *b) @@ -451,6 +505,7 @@ static void __control_destroy(const char *class_id, const char *id, bundle *b) /* call stub terminate */ appcore_multiwindow_base_instance_exit(instance_h); free(data->content); + free(data->id); free(data); __check_empty_instance(); } @@ -1122,9 +1177,10 @@ static void __free_class(gpointer data) EXPORT_API void widget_base_fini(void) { - appcore_multiwindow_base_fini(); g_list_free_full(__context.classes, __free_class); __context.classes = NULL; + + appcore_multiwindow_base_fini(); } EXPORT_API int widget_base_context_window_bind( @@ -1264,6 +1320,7 @@ static void __multiwindow_instance_resume( const char *id; const char *class_id; widget_base_class *cls; + widget_base_instance_data *data; appcore_multiwindow_base_class_on_resume(instance_h); id = appcore_multiwindow_base_instance_get_id(instance_h); @@ -1274,6 +1331,21 @@ static void __multiwindow_instance_resume( return; } + data = (widget_base_instance_data *) + appcore_multiwindow_base_instance_get_extra(instance_h); + + if (data->pending_update) { + LOGD("pending update!"); + data->pending_update = false; + __control_update(class_id, data->id, data->args); + if (data->period > 0) { + LOGD("Restart timer!"); + data->periodic_timer = g_timeout_add_seconds( + data->period, + __timeout_cb, data); + } + } + if (cls->ops.resume) cls->ops.resume(instance_h, class_data); @@ -1380,6 +1452,9 @@ static void __multiwindow_instance_terminate( if (content_info) bundle_free(content_info); + if (data->periodic_timer) + g_source_remove(data->periodic_timer); + __send_update_status(class_id, id, event, NULL); appcore_multiwindow_base_class_on_terminate(instance_h); } -- 2.7.4