From: Kyuho Jo Date: Wed, 29 Apr 2015 00:56:30 +0000 (+0900) Subject: Merge from tizen 2.3.1 X-Git-Tag: submit/tizen_mobile/20150511.123737~4 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F97%2F38797%2F1;p=platform%2Fcore%2Fappfw%2Fwidget-viewer.git Merge from tizen 2.3.1 Change-Id: I0fe8daa20d160ffe42a382a46b7d124714f21cac Signed-off-by: Kyuho Jo --- diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..53bc64b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,6 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) + +ADD_SUBDIRECTORY(widget_viewer) +ADD_SUBDIRECTORY(widget_viewer_evas) + +ADD_DEPENDENCIES(widget_viewer_evas widget_viewer) diff --git a/packaging/libwidget_viewer.manifest b/packaging/libwidget_viewer.manifest new file mode 100644 index 0000000..a76fdba --- /dev/null +++ b/packaging/libwidget_viewer.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/packaging/libwidget_viewer.spec b/packaging/libwidget_viewer.spec new file mode 100755 index 0000000..860caf2 --- /dev/null +++ b/packaging/libwidget_viewer.spec @@ -0,0 +1,125 @@ +%bcond_with wayland + +Name: libwidget_viewer +Summary: Library for developing the application +Version: 1.1.3 +Release: 1 +Group: HomeTF/widget +License: Flora +Source0: %{name}-%{version}.tar.gz +Source1001: %{name}.manifest +BuildRequires: cmake, gettext-tools, coreutils, edje-bin +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(aul) +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(gio-2.0) +BuildRequires: pkgconfig(com-core) +BuildRequires: pkgconfig(sqlite3) +BuildRequires: pkgconfig(db-util) +BuildRequires: pkgconfig(widget_service) +BuildRequires: pkgconfig(vconf) +BuildRequires: pkgconfig(elementary) +BuildRequires: model-build-features + +%if %{with wayland} +%else +BuildRequires: pkgconfig(x11) +BuildRequires: pkgconfig(xext) +%endif + +%if "%{model_build_feature_widget}" == "0" +ExclusiveArch: +%endif + +%description +API for creating a new instance of the widget and managing its life-cycle. + +%package devel +Summary: Development Library for widget Viewer Application (dev) +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description devel +Header and package configuration files for the widget viewer development + +%prep +%setup -q +cp %{SOURCE1001} . + +%build +%if 0%{?sec_build_binary_debug_enable} +export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE" +export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE" +export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE" +%endif + +%if 0%{?tizen_build_binary_release_type_eng} +export CFLAGS="${CFLAGS} -DTIZEN_ENGINEER_MODE" +export CXXFLAGS="${CXXFLAGS} -DTIZEN_ENGINEER_MODE" +export FFLAGS="${FFLAGS} -DTIZEN_ENGINEER_MODE" +%endif + +%if %{with wayland} +export WAYLAND_SUPPORT=On +export X11_SUPPORT=Off +%else +export WAYLAND_SUPPORT=Off +export X11_SUPPORT=On +%endif + +%cmake . -DWAYLAND_SUPPORT=${WAYLAND_SUPPORT} -DX11_SUPPORT=${X11_SUPPORT} -DWIDGET_ENABLED=On +make %{?jobs:-j%jobs} + +%install +rm -rf %{buildroot} +%make_install + +%post -n %{name} -p /sbin/ldconfig +%postun -n %{name} -p /sbin/ldconfig + +%files -n %{name} +%manifest %{name}.manifest +%defattr(-,root,root,-) +%{_libdir}/libwidget_viewer.so* +%{_datarootdir}/license/libwidget_viewer + +%files devel +%manifest %{name}.manifest +%defattr(-,root,root,-) +%{_includedir}/widget_viewer/widget_viewer.h +%{_libdir}/pkgconfig/widget_viewer.pc + +################################################# +# libwidget_viewer_evas +%package -n libwidget_viewer_evas +Summary: Library for developing the widget viewer evas +Group: HomeTF/widget +License: Flora +Requires: libwidget_viewer + +%description -n libwidget_viewer_evas +Provider APIs to develop the widget viewer EFL application. + +%package -n libwidget_viewer_evas-devel +Summary: Header & package configuration files to support development of the widget viewer applications. (for EFL app) +Group: Development/Libraries +Requires: libwidget_viewer_evas + +%description -n libwidget_viewer_evas-devel +widget provider application development library (dev) (EFL version) + +%files -n libwidget_viewer_evas +%manifest %{name}.manifest +%defattr(-,root,root,-) +%{_libdir}/libwidget_viewer_evas.so* +%{_datadir}/widget_viewer_evas/* +%{_datarootdir}/license/libwidget_viewer_evas + +%files -n libwidget_viewer_evas-devel +%manifest %{name}.manifest +%defattr(-,root,root,-) +%{_includedir}/widget_viewer_evas/widget_viewer_evas.h +%{_includedir}/widget_viewer_evas/widget_viewer_evas_internal.h +%{_libdir}/pkgconfig/widget_viewer_evas.pc + +# End of a file diff --git a/widget_viewer/CMakeLists.txt b/widget_viewer/CMakeLists.txt new file mode 100755 index 0000000..e610f48 --- /dev/null +++ b/widget_viewer/CMakeLists.txt @@ -0,0 +1,98 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(widget_viewer C) + +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) +SET(EXEC_PREFIX "\${prefix}") +SET(PROJECT_NAME "${PROJECT_NAME}") +SET(LIBDIR "\${exec_prefix}/lib") +SET(INCLUDEDIR "\${prefix}/include/${PROJECT_NAME}") +SET(VERSION_MAJOR 1) +SET(VERSION "${VERSION_MAJOR}.0.0") + +SET(CMAKE_SKIP_BUILD_RPATH true) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include) + +INCLUDE(FindPkgConfig) +pkg_check_modules(pkgs REQUIRED + dlog + aul + glib-2.0 + gio-2.0 + com-core + sqlite3 + db-util + widget_service + vconf +) + +SET(BUILD_SOURCE + src/client.c + src/conf.c + src/desc_parser.c + src/dlist.c + src/widget.c + src/widget_internal.c + src/file_service.c + src/master_rpc.c + src/util.c +) + +IF (X11_SUPPORT) +pkg_check_modules(pkgs_extra REQUIRED + x11 + xext +) + +SET(BUILD_SOURCE + ${BUILD_SOURCE} + src/fb.c +) +ADD_DEFINITIONS("-DHAVE_X11") +ENDIF (X11_SUPPORT) + +IF (WAYLAND_SUPPORT) +SET(BUILD_SOURCE + ${BUILD_SOURCE} + src/fb_wayland.c +) +ADD_DEFINITIONS("-DHAVE_WAYLAND") +ENDIF (WAYLAND_SUPPORT) + +FOREACH(flag ${pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +FOREACH(flag ${pkgs_extra_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden -Wall -Werror -Winline -g") + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") + +ADD_DEFINITIONS("-DPREFIX=\"${PREFIX}\"") +ADD_DEFINITIONS("-DLOG_TAG=\"WIDGET_VIEWER\"") +ADD_DEFINITIONS("-DNDEBUG") +ADD_DEFINITIONS("-D_USE_ECORE_TIME_GET") +#ADD_DEFINITIONS("-DFLOG") +ADD_DEFINITIONS("-DMASTER_PKGNAME=\"data-provider-master\"") +ADD_DEFINITIONS("-DINFO_SOCKET=\"/opt/usr/share/live_magazine/.live.socket\"") +ADD_DEFINITIONS("-DCLIENT_SOCKET=\"/opt/usr/share/live_magazine/.client.socket\"") +ADD_DEFINITIONS("-DSLAVE_SOCKET=\"/opt/usr/share/live_magazine/.slave.socket\"") +ADD_DEFINITIONS("-DSERVICE_SOCKET=\"/opt/usr/share/live_magazine/.service.socket\"") +ADD_LIBRARY(${PROJECT_NAME} SHARED ${BUILD_SOURCE}) + +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${VERSION_MAJOR}) +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES VERSION ${VERSION}) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} ${pkgs_extra_LDFLAGS} "-lpthread") + +CONFIGURE_FILE(${PROJECT_NAME}.pc.in ${PROJECT_NAME}.pc @ONLY) +SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${PROJECT_NAME}.pc") + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION lib) +INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc DESTINATION lib/pkgconfig) + +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/widget_viewer.h DESTINATION include/${PROJECT_NAME}) + +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE DESTINATION /usr/share/license RENAME "lib${PROJECT_NAME}") diff --git a/widget_viewer/LICENSE b/widget_viewer/LICENSE new file mode 100644 index 0000000..571fe79 --- /dev/null +++ b/widget_viewer/LICENSE @@ -0,0 +1,206 @@ +Flora License + +Version 1.1, April, 2013 + +http://floralicense.org/license/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, +and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by +the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and +all other entities that control, are controlled by, or are +under common control with that entity. For the purposes of +this definition, "control" means (i) the power, direct or indirect, +to cause the direction or management of such entity, +whether by contract or otherwise, or (ii) ownership of fifty percent (50%) +or more of the outstanding shares, or (iii) beneficial ownership of +such entity. + +"You" (or "Your") shall mean an individual or Legal Entity +exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, +including but not limited to software source code, documentation source, +and configuration files. + +"Object" form shall mean any form resulting from mechanical +transformation or translation of a Source form, including but +not limited to compiled object code, generated documentation, +and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, +made available under the License, as indicated by a copyright notice +that is included in or attached to the work (an example is provided +in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, +that is based on (or derived from) the Work and for which the editorial +revisions, annotations, elaborations, or other modifications represent, +as a whole, an original work of authorship. For the purposes of this License, +Derivative Works shall not include works that remain separable from, +or merely link (or bind by name) to the interfaces of, the Work and +Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original +version of the Work and any modifications or additions to that Work or +Derivative Works thereof, that is intentionally submitted to Licensor +for inclusion in the Work by the copyright owner or by an individual or +Legal Entity authorized to submit on behalf of the copyright owner. +For the purposes of this definition, "submitted" means any form of +electronic, verbal, or written communication sent to the Licensor or +its representatives, including but not limited to communication on +electronic mailing lists, source code control systems, and issue +tracking systems that are managed by, or on behalf of, the Licensor +for the purpose of discussing and improving the Work, but excluding +communication that is conspicuously marked or otherwise designated +in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity +on behalf of whom a Contribution has been received by Licensor and +subsequently incorporated within the Work. + +"Tizen Certified Platform" shall mean a software platform that complies +with the standards set forth in the Tizen Compliance Specification +and passes the Tizen Compliance Tests as defined from time to time +by the Tizen Technical Steering Group and certified by the Tizen +Association or its designated agent. + +2. Grant of Copyright License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the +Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +(except as stated in this section) patent license to make, have made, +use, offer to sell, sell, import, and otherwise transfer the Work +solely as incorporated into a Tizen Certified Platform, where such +license applies only to those patent claims licensable by such +Contributor that are necessarily infringed by their Contribution(s) +alone or by combination of their Contribution(s) with the Work solely +as incorporated into a Tizen Certified Platform to which such +Contribution(s) was submitted. If You institute patent litigation +against any entity (including a cross-claim or counterclaim +in a lawsuit) alleging that the Work or a Contribution incorporated +within the Work constitutes direct or contributory patent infringement, +then any patent licenses granted to You under this License for that +Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the +Work or Derivative Works thereof pursuant to the copyright license +above, in any medium, with or without modifications, and in Source or +Object form, provided that You meet the following conditions: + + 1. You must give any other recipients of the Work or Derivative Works + a copy of this License; and + 2. You must cause any modified files to carry prominent notices stating + that You changed the files; and + 3. You must retain, in the Source form of any Derivative Works that + You distribute, all copyright, patent, trademark, and attribution + notices from the Source form of the Work, excluding those notices + that do not pertain to any part of the Derivative Works; and + 4. If the Work includes a "NOTICE" text file as part of its distribution, + then any Derivative Works that You distribute must include a readable + copy of the attribution notices contained within such NOTICE file, + excluding those notices that do not pertain to any part of + the Derivative Works, in at least one of the following places: + within a NOTICE text file distributed as part of the Derivative Works; + within the Source form or documentation, if provided along with the + Derivative Works; or, within a display generated by the Derivative Works, + if and wherever such third-party notices normally appear. + The contents of the NOTICE file are for informational purposes only + and do not modify the License. You may add Your own attribution notices + within Derivative Works that You distribute, alongside or as an addendum + to the NOTICE text from the Work, provided that such additional attribution + notices cannot be construed as modifying the License. You may add Your own + copyright statement to Your modifications and may provide additional or + different license terms and conditions for use, reproduction, or + distribution of Your modifications, or for any such Derivative Works + as a whole, provided Your use, reproduction, and distribution of + the Work otherwise complies with the conditions stated in this License + and your own copyright statement or terms and conditions do not conflict + the conditions stated in the License including section 3. + +5. Submission of Contributions. Unless You explicitly state otherwise, +any Contribution intentionally submitted for inclusion in the Work +by You to the Licensor shall be under the terms and conditions of +this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify +the terms of any separate license agreement you may have executed +with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade +names, trademarks, service marks, or product names of the Licensor, +except as required for reasonable and customary use in describing the +origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or +agreed to in writing, Licensor provides the Work (and each +Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied, including, without limitation, any warranties or conditions +of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any +risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, +whether in tort (including negligence), contract, or otherwise, +unless required by applicable law (such as deliberate and grossly +negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, +incidental, or consequential damages of any character arising as a +result of this License or out of the use or inability to use the +Work (including but not limited to damages for loss of goodwill, +work stoppage, computer failure or malfunction, or any and all +other commercial damages or losses), even if such Contributor +has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing +the Work or Derivative Works thereof, You may choose to offer, +and charge a fee for, acceptance of support, warranty, indemnity, +or other liability obligations and/or rights consistent with this +License. However, in accepting such obligations, You may act only +on Your own behalf and on Your sole responsibility, not on behalf +of any other Contributor, and only if You agree to indemnify, +defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason +of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Flora License to your work + +To apply the Flora License to your work, attach the following +boilerplate notice, with the fields enclosed by brackets "[]" +replaced with your own identifying information. (Don't include +the brackets!) The text should be enclosed in the appropriate +comment syntax for the file format. We also recommend that a +file or class name and description of purpose be included on the +same "printed page" as the copyright notice for easier +identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Flora License, Version 1.1 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://floralicense.org/license/ + + 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. + diff --git a/widget_viewer/doc/image/PD.png b/widget_viewer/doc/image/PD.png new file mode 100644 index 0000000..ebb7367 Binary files /dev/null and b/widget_viewer/doc/image/PD.png differ diff --git a/widget_viewer/doc/image/download_folder.png b/widget_viewer/doc/image/download_folder.png new file mode 100644 index 0000000..1e5e01b Binary files /dev/null and b/widget_viewer/doc/image/download_folder.png differ diff --git a/widget_viewer/doc/image/front.jpg b/widget_viewer/doc/image/front.jpg new file mode 100644 index 0000000..9d46441 Binary files /dev/null and b/widget_viewer/doc/image/front.jpg differ diff --git a/widget_viewer/doc/image/image_format.png b/widget_viewer/doc/image/image_format.png new file mode 100644 index 0000000..8f79a0c Binary files /dev/null and b/widget_viewer/doc/image/image_format.png differ diff --git a/widget_viewer/doc/image/message.png b/widget_viewer/doc/image/message.png new file mode 100644 index 0000000..4cb7760 Binary files /dev/null and b/widget_viewer/doc/image/message.png differ diff --git a/widget_viewer/doc/image/preload_folder.png b/widget_viewer/doc/image/preload_folder.png new file mode 100644 index 0000000..3dbbf64 Binary files /dev/null and b/widget_viewer/doc/image/preload_folder.png differ diff --git a/widget_viewer/doc/image/script_format.png b/widget_viewer/doc/image/script_format.png new file mode 100644 index 0000000..1fec88a Binary files /dev/null and b/widget_viewer/doc/image/script_format.png differ diff --git a/widget_viewer/doc/image/stock.png b/widget_viewer/doc/image/stock.png new file mode 100644 index 0000000..fd274fe Binary files /dev/null and b/widget_viewer/doc/image/stock.png differ diff --git a/widget_viewer/doc/image/text_format.png b/widget_viewer/doc/image/text_format.png new file mode 100644 index 0000000..b492883 Binary files /dev/null and b/widget_viewer/doc/image/text_format.png differ diff --git a/widget_viewer/doc/image/twitter.png b/widget_viewer/doc/image/twitter.png new file mode 100644 index 0000000..36bce25 Binary files /dev/null and b/widget_viewer/doc/image/twitter.png differ diff --git a/widget_viewer/doc/image/weather.png b/widget_viewer/doc/image/weather.png new file mode 100644 index 0000000..2f41af1 Binary files /dev/null and b/widget_viewer/doc/image/weather.png differ diff --git a/widget_viewer/doc/widget_viewer_doc.h b/widget_viewer/doc/widget_viewer_doc.h new file mode 100755 index 0000000..e4d9cbd --- /dev/null +++ b/widget_viewer/doc/widget_viewer_doc.h @@ -0,0 +1,192 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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. + */ + +/** + * @ingroup CAPI_WIDGET_FRAMEWORK + * @defgroup WIDGET_VIEWER_MODULE widget Viewer + * @brief API for widget viewer (widget screen, home screen, ...) + * @section WIDGET_VIEWER_MODULE_HEADER Required Header + * \#include + * @section WIDGET_VIEWER_MODULE_OVERVIEW Overview + * Tizen homescreen S/W framework is supporing the widget. (aka widget which is similiar with the android widget) + * + * @image html front.jpg + * + * @subsection WhatIsTheDynamicBox 1. What is the widget + * The widget is the widget of the TIZEN. + * + * It works as a small application displayed on other applications' (such as homescreen, lockscreen, etc ...) view. + * Each widget can have (not a mandatory option) a Glance Bar (Glance Bar) in which more detailed information can be found. + * The content of Glance Bar can be exposed when a certain gesture (e.g., flick-down) has been applied to the widget. + * If you are interested in developing a widget, there are things you should know prior to making any source code for the box. + * To make your widget added to any widget viewer application (e.g., live panel in our case), then you need to create and prepare + * controller(SO file), layout script (EDJE for a Glance Bar if necessary), configuration files. + * + * A widget is managed by data provider, since each SO file of a widget is loaded on and controlled by data provider using predefined ABI. + * A viewer will receive any widget's content in forms of "image file", "buffer" or "text" and display the content in various formats on its window. + * A widget developer needs to make sure that your widget generates desirable content in-time on a explicit update-request or periodic update. + * + * After a data provider loads a widget's SO file, it then assigns a specific "file name" for the widget via an argument of a widget function. + * Since then the widget just generates content using then given file name. + * Passing an image file (whose name is the previously given name) is the basic method for providing contents to the viewer. + * But if you want play animation or handles user event in real-time, you can use the buffer type. + * + * And you should prepare the content of the Glance Bar. + * The Glance Bar is only updated by the "buffer" type. so you should prepare the layout script for it. + * If you didn't install any script file for Glance Bar, the viewer will ignore the "flick down" event from your widget. + * + * @subsubsection widget 1.1 widget + * Live box is a default content of your widget. It always displays on the screen and updated periodically. + * It looks like below captured images. + * @image html weather.png Weather widget + * @image html stock.png Stock widget + * @image html twitter.png Twitter widget + * + * @subsubsection GlanceBar 1.2 Glance Bar + * @image html PD.png Glance Bar + * Glance Bar will be displayed when a user flicks down a widget. (basically it depends on the implementation of the viewer applications) + * To supports this, a developer should prepare the layout script (EDJE only for the moment) of the widget's Glance Bar. (or you can use the buffer directly) + * Data provider supports EDJE script but the developer can use various scripts if (which is BIG IF) their interpreters can be implemented based on evas & ecore. + * + * When a layout script has been installed, data provider can load and rendering the given layout on the buffer. + * The content on the buffer can be shared between applications that need to display the content on their window. + * Description data file is necessary to place proper content components in rendered layout. + * Check this page Description Data. + * + * @subsubsection ClusterCategory 1.3 What is the "cluster" and "category" + * The cluster and the sub-cluster is just like the grouping concept. + * It is used for creating/destorying your widget instance when the data provider receives any context event from the context engine. + * You will only get "user,created" cluster and "default" category(sub cluster) info. + * + * @subsection DynamicBoxContent 2. How the widget can draw contents for viewer? + * There are several ways to update the content of a widget. + * + * @li Image file based content updating + * @li Description file based content updating (with the layout script file) + * @li Buffer based content updating + * + * Each method has specific benefit for implementing the widget. + * + * @subsubsection ImageFormat 2.1 Via image file + * This is the basic method for providing content of a widget to the viewer application. + * But this can be used only for the widget. (Unavailable for the Glance Bar). + * When your widget is created, the provider will assign an unique ID for your widget(it would be a filename). + * You should keep that ID until your widget is running. The ID will be passed to you via widget_create function. + * \image html image_format.png + * + * When you need to update the output of your widget, you should generate the image file using given ID(filename). + * Then the data provider will recognize the event of updated output of a widget and it will send that event to the viewer to reload it on the screen. + * + * @subsubsection ScriptFormat 2.2 Via layout script + * @image html script_format.png + * This method is supported for static layout & various contents (text & image) + * When you develop your widget, first design the layout of box content using script (edje is default) + * Then the provider will load it to the content buffer and start rendering. + * After the sciprt is loaded, you can fill it using description data format. + * libwidget defines description data handling functions. + * + * @subsubsection TextFormat 2.3 Via text data + * @image html text_format.png + * This is the simplified method to update the content of widget. + * So your box only need to update the text data using description data format. + * Then the viewer will parse it to fill its screen. + * So there is no buffer area, just viewer decide how handles it. + * + * @subsubsection BufferFormat 2.4 Via buffer + * This method is very complex to implement. + * The provider will give a content buffer to you, then your box should render its contents on this buffer. + * This type is only supported for 3rd party widget such as OSP and WEB. + * Inhouse(EFL) widget is not able to use this buffer type for the box content. + * + * @subsection DynamicBoxDirectory 3. widget directory hierachy + * @image html preload_folder.png + * @image html download_folder.png + * + * @subsection WritingViewerApp 4. Writing a new application for displaying Widgets + * If you want install dynamic boxes on your application screen, you should initialize the viewer system first. + * + * @code + * extern int widget_init(void *disp, int prevent_overwrite, double event_filter, int use_thread); + * @endcode + * + * @a disp should be current display object. if we are on X11 based windowing system, it will give you a Display Object, when you connect to X Server. + * Viewer application also needs it to preparing rendering buffer to display contents of dynamic boxes. + * + * @a prevent_overwirte flag is used for image or script type dynamic boxes. + * If this option is turn on, the viewer library will copy the image file of dyanmic box content to "reader" folder. + * To prevent from overwriting content image file. + * + * @a event_filter is used for feeding events. + * Basically, the widget can be feed touch event by viewer application or master widget controller. (aka, data-provider-master). + * If a viewer feeds event to the widget, it could more slow than data-provider-master's direct feeding. + * But sometimes, the viewer requires to feeds event by itself. + * In that case, we should choose the feeding option. feeding every events can be slow down. + * To save it, this event_filter will be used. if the event is generated in this time-gap, it will be ignored. + * + * @a use_thread if this flag is turned on, the viewer library will create a new thread for handling the IPC packets only. + * It will helps to increase the throughput of main thread. because it will not be interrupted to handles IPC packets. + * + * After the viewer is initiated, you can create a new box and locate it in your screen. + * + * Opposite function is "widget_fini" + * + * @code + * extern int widget_fini(void); + * @endcode + * + * Here is a sample code + * + * @code + * #include + * #include + * #include + * #include + * + * #include + * + * int errno; + * + * static bool _create_cb(void *data) + * { + * int ret; + * ret = widget_init(NULL, 1, 0.0f, 1); + * if (ret != WIDGET_ERROR_NONE) { + * LOGE("Failed to initialize the widget viewer"); + * } + * return true; + * } + * + * static void _terminate_cb(void *data) + * { + * widget_fini(); + * } + * + * int main(int argc, char *argv[]) + * { + * ui_app_lifecycle_callback_s event_callback; + * event_callback.create = _create_cb; + * event_callback.terminate = _terminate_cb; + * event_callback.pause = _pause_cb; + * event_callback.resume = _resume_cb; + * event_callback.app_control = _app_control; + * + * return ui_app_main(&argc, &argv, &event_callback, &main_info); + * } + * @endocde + * + * If you want add a new widget, you can call "widget_add()" function. + * + */ diff --git a/widget_viewer/include/client.h b/widget_viewer/include/client.h new file mode 100644 index 0000000..dc7a744 --- /dev/null +++ b/widget_viewer/include/client.h @@ -0,0 +1,24 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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. + */ + +extern int client_init(int use_thread); +extern int client_fd(void); +extern const char *client_addr(void); +extern const char *client_direct_addr(void); +extern int client_direct_fd(void); +extern int client_fini(void); + +/* End of a file */ diff --git a/widget_viewer/include/conf.h b/widget_viewer/include/conf.h new file mode 100755 index 0000000..1e96f47 --- /dev/null +++ b/widget_viewer/include/conf.h @@ -0,0 +1,48 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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. + */ + +/*! + * \note + * milli seconds + */ +#define MAX_LOG_FILE 3 +#define MAX_LOG_LINE 1000 +#define SLAVE_LOG_PATH "/tmp/.widget.service/log/" + +#if !defined(VCONFKEY_MASTER_STARTED) +#define VCONFKEY_MASTER_STARTED "memory/data-provider-master/started" +#endif + +#if !defined(VCONFKEY_MASTER_CLIENT_ADDR) +#define VCONFKEY_MASTER_CLIENT_ADDR "db/data-provider-master/serveraddr" +#endif + +extern void conf_set_manual_sync(int flag); +extern int conf_manual_sync(void); +extern void conf_set_frame_drop_for_resizing(int flag); +extern int conf_frame_drop_for_resizing(void); +extern void conf_set_shared_content(int flag); +extern int conf_shared_content(void); +extern double conf_event_filter(void); +extern void conf_set_event_filter(double filter); +extern void conf_set_direct_update(int flag); +extern int conf_direct_update(void); +extern int conf_extra_buffer_count(void); +extern void conf_set_extra_buffer_count(int buffer_count); +extern widget_status_e conf_last_status(void); +extern void conf_set_last_status(widget_status_e status); + +/* End of a file */ diff --git a/widget_viewer/include/debug.h b/widget_viewer/include/debug.h new file mode 100644 index 0000000..a6563ee --- /dev/null +++ b/widget_viewer/include/debug.h @@ -0,0 +1,28 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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. + */ + +#if !defined(FLOG) +#define DbgPrint(format, arg...) SECURE_LOGD(format, ##arg) +#define ErrPrint(format, arg...) SECURE_LOGE(format, ##arg) +#else +extern FILE *__file_log_fp; +#define DbgPrint(format, arg...) do { fprintf(__file_log_fp, "[LOG] [%s/%s:%d] " format, util_basename(__FILE__), __func__, __LINE__, ##arg); fflush(__file_log_fp); } while (0) + +#define ErrPrint(format, arg...) do { fprintf(__file_log_fp, "[ERR] [%s/%s:%d] " format, util_basename(__FILE__), __func__, __LINE__, ##arg); fflush(__file_log_fp); } while (0) +#endif + + +/* End of a file */ diff --git a/widget_viewer/include/desc_parser.h b/widget_viewer/include/desc_parser.h new file mode 100755 index 0000000..72c3dda --- /dev/null +++ b/widget_viewer/include/desc_parser.h @@ -0,0 +1,19 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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. + */ + +extern int parse_desc(struct widget_common *common, const char *filename, int is_pd); + +/* End of a file */ diff --git a/widget_viewer/include/dlist.h b/widget_viewer/include/dlist.h new file mode 100644 index 0000000..3f19827 --- /dev/null +++ b/widget_viewer/include/dlist.h @@ -0,0 +1,43 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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. + */ + +#define dlist_remove_data(list, data) do { \ + struct dlist *l; \ + l = dlist_find_data(list, data); \ + list = dlist_remove(list, l); \ +} while (0) + +#define dlist_foreach(list, l, data) \ + for ((l) = (list); (l) && ((data) = dlist_data(l)); (l) = dlist_next(l)) + +#define dlist_foreach_safe(list, l, n, data) \ + for ((l) = (list), (n) = dlist_next(l); \ + (l) && ((data) = dlist_data(l)); \ + (l) = (n), (n) = dlist_next(l)) + +struct dlist; + +extern struct dlist *dlist_append(struct dlist *list, void *data); +extern struct dlist *dlist_prepend(struct dlist *list, void *data); +extern struct dlist *dlist_remove(struct dlist *list, struct dlist *l); +extern struct dlist *dlist_find_data(struct dlist *list, void *data); +extern void *dlist_data(struct dlist *l); +extern struct dlist *dlist_next(struct dlist *l); +extern struct dlist *dlist_prev(struct dlist *l); +extern int dlist_count(struct dlist *l); +extern struct dlist *dlist_nth(struct dlist *l, int nth); + +/* End of a file */ diff --git a/widget_viewer/include/fb.h b/widget_viewer/include/fb.h new file mode 100644 index 0000000..e7b8543 --- /dev/null +++ b/widget_viewer/include/fb.h @@ -0,0 +1,35 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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. + */ + +struct fb_info; + +extern int fb_init(void *disp); +extern int fb_fini(void); +extern const char *fb_id(struct fb_info *info); +extern int fb_get_size(struct fb_info *info, int *w, int *h); +extern int fb_sync(struct fb_info *info, int x, int y, int w, int h); +extern int fb_size(struct fb_info *info); +extern int fb_refcnt(void *data); +extern int fb_is_created(struct fb_info *info); +extern int fb_type(struct fb_info *info); + +extern struct fb_info *fb_create(const char *filename, int w, int h); +extern int fb_destroy(struct fb_info *info); + +extern void *fb_acquire_buffer(struct fb_info *info); +extern int fb_release_buffer(void *data); + +/* End of a file */ diff --git a/widget_viewer/include/file_service.h b/widget_viewer/include/file_service.h new file mode 100644 index 0000000..9212d03 --- /dev/null +++ b/widget_viewer/include/file_service.h @@ -0,0 +1,21 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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. + */ + +extern int file_service_send_request(const char *filename, const char *save_to, void (*result_cb)(const char *filename, const char *save_to, int ret, void *data), void *data); +extern int file_service_fini(void); +extern int file_service_init(void); + +/* End of a file */ diff --git a/widget_viewer/include/master_rpc.h b/widget_viewer/include/master_rpc.h new file mode 100755 index 0000000..e07306d --- /dev/null +++ b/widget_viewer/include/master_rpc.h @@ -0,0 +1,24 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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. + */ + +extern int master_rpc_async_request(struct widget *handler, struct packet *packet, int urgent, void (*ret_cb)(struct widget *handler, const struct packet *result, void *data), void *data); +extern int master_rpc_sync_request(struct packet *packet); +extern void master_rpc_check_and_fire_consumer(void); +extern int master_rpc_request_only(struct widget *handler, struct packet *packet); +extern int master_rpc_clear_fault_package(const char *pkgname); +extern int master_rpc_clear_all_request(void); + +/* End of a file */ diff --git a/widget_viewer/include/util.h b/widget_viewer/include/util.h new file mode 100644 index 0000000..498a249 --- /dev/null +++ b/widget_viewer/include/util.h @@ -0,0 +1,31 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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. + */ + +extern int util_check_extension(const char *filename, const char *check_ptr); +extern double util_timestamp(void); +extern const char *util_basename(const char *name); +extern const char *util_uri_to_path(const char *uri); +extern int util_unlink(const char *filename); + +#define SCHEMA_FILE "file://" +#define SCHEMA_PIXMAP "pixmap://" +#define SCHEMA_SHM "shm://" + +#define container_of(ptr, type, member) \ + ({ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +/* End of a file */ diff --git a/widget_viewer/include/widget_viewer.h b/widget_viewer/include/widget_viewer.h new file mode 100755 index 0000000..61e2802 --- /dev/null +++ b/widget_viewer/include/widget_viewer.h @@ -0,0 +1,1639 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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 + +#ifndef __WIDGET_VIEWER_H +#define __WIDGET_VIEWER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file widget_viewer.h + * @brief This file declares API of libwidget-viewer library + * @since_tizen 2.3.1 + */ + +/** + * @addtogroup CAPI_WIDGET_VIEWER_MODULE + * @{ + */ + +/** + * @brief Structure definition for a widget instance. + * @since_tizen 2.3.1 + */ +typedef struct widget *widget_h; + +/** + * @internal + * @brief Definition for a default update period for widget (defined in the package manifest file). + * @since_tizen 2.3.1 + */ +#define WIDGET_DEFAULT_PERIOD -1.0f + +/** + * @internal + * @brief Enumeration for Mouse & Key event for buffer type widget or Glance Bar. + * @details Viewer should send these events to widget. + * @since_tizen 2.3.1 + */ +typedef enum widget_mouse_event_type { + WIDGET_MOUSE_EVENT_MASK = 0x20000000, /**< Mask value for mouse event */ + WIDGET_MOUSE_EVENT_GBAR_MASK = 0x10000000, /**< Mask value for Glance Bar event */ + WIDGET_MOUSE_EVENT_WIDGET_MASK = 0x40000000, /**< Mask value for widget event */ + + WIDGET_MOUSE_EVENT_DOWN = 0x00000001, /**< widget mouse down event for widget */ + WIDGET_MOUSE_EVENT_UP = 0x00000002, /**< widget mouse up event for widget */ + WIDGET_MOUSE_EVENT_MOVE = 0x00000004, /**< widget mouse move event for widget */ + WIDGET_MOUSE_EVENT_ENTER = 0x00000008, /**< widget mouse enter event for widget */ + WIDGET_MOUSE_EVENT_LEAVE = 0x00000010, /**< widget mouse leave event for widget */ + WIDGET_MOUSE_EVENT_SET = 0x00000020, /**< widget mouse set auto event for widget */ + WIDGET_MOUSE_EVENT_UNSET = 0x00000040, /**< widget mouse unset auto event for widget */ + + WIDGET_MOUSE_EVENT_ON_SCROLL = 0x00000080, /**< widget On scrolling */ + WIDGET_MOUSE_EVENT_ON_HOLD = 0x00000100, /**< widget On holding */ + WIDGET_MOUSE_EVENT_OFF_SCROLL = 0x00000200, /**< widget Stop scrolling */ + WIDGET_MOUSE_EVENT_OFF_HOLD = 0x00000400, /**< widget Stop holding */ + + WIDGET_MOUSE_ON_SCROLL = WIDGET_MOUSE_EVENT_WIDGET_MASK | WIDGET_MOUSE_EVENT_MASK | WIDGET_MOUSE_EVENT_ON_SCROLL, /**< Mouse event occurs while scrolling */ + WIDGET_MOUSE_ON_HOLD = WIDGET_MOUSE_EVENT_WIDGET_MASK | WIDGET_MOUSE_EVENT_MASK | WIDGET_MOUSE_EVENT_ON_HOLD, /**< Mouse event occurs on holding */ + WIDGET_MOUSE_OFF_SCROLL = WIDGET_MOUSE_EVENT_WIDGET_MASK | WIDGET_MOUSE_EVENT_MASK | WIDGET_MOUSE_EVENT_OFF_SCROLL, /**< Scrolling stopped */ + WIDGET_MOUSE_OFF_HOLD = WIDGET_MOUSE_EVENT_WIDGET_MASK | WIDGET_MOUSE_EVENT_MASK | WIDGET_MOUSE_EVENT_OFF_HOLD, /**< Holding stopped */ + + WIDGET_MOUSE_DOWN = WIDGET_MOUSE_EVENT_WIDGET_MASK | WIDGET_MOUSE_EVENT_MASK | WIDGET_MOUSE_EVENT_DOWN, /**< Mouse down on the widget */ + WIDGET_MOUSE_UP = WIDGET_MOUSE_EVENT_WIDGET_MASK | WIDGET_MOUSE_EVENT_MASK | WIDGET_MOUSE_EVENT_UP, /**< Mouse up on the widget */ + WIDGET_MOUSE_MOVE = WIDGET_MOUSE_EVENT_WIDGET_MASK | WIDGET_MOUSE_EVENT_MASK | WIDGET_MOUSE_EVENT_MOVE, /**< Move move on the widget */ + WIDGET_MOUSE_ENTER = WIDGET_MOUSE_EVENT_WIDGET_MASK | WIDGET_MOUSE_EVENT_MASK | WIDGET_MOUSE_EVENT_ENTER, /**< Mouse enter to the widget */ + WIDGET_MOUSE_LEAVE = WIDGET_MOUSE_EVENT_WIDGET_MASK | WIDGET_MOUSE_EVENT_MASK | WIDGET_MOUSE_EVENT_LEAVE, /**< Mouse leave from the widget */ + WIDGET_MOUSE_SET = WIDGET_MOUSE_EVENT_WIDGET_MASK | WIDGET_MOUSE_EVENT_MASK | WIDGET_MOUSE_EVENT_SET, /**< Mouse event, start feeding event by master */ + WIDGET_MOUSE_UNSET = WIDGET_MOUSE_EVENT_WIDGET_MASK | WIDGET_MOUSE_EVENT_MASK | WIDGET_MOUSE_EVENT_UNSET, /**< Mouse event, stop feeding event by master */ + + WIDGET_GBAR_MOUSE_ON_SCROLL = WIDGET_MOUSE_EVENT_GBAR_MASK | WIDGET_MOUSE_EVENT_MASK | WIDGET_MOUSE_EVENT_ON_SCROLL, /**< Mouse event occurs while scrolling */ + WIDGET_GBAR_MOUSE_ON_HOLD = WIDGET_MOUSE_EVENT_GBAR_MASK | WIDGET_MOUSE_EVENT_MASK | WIDGET_MOUSE_EVENT_ON_HOLD, /**< Mouse event occurs on holding */ + WIDGET_GBAR_MOUSE_OFF_SCROLL = WIDGET_MOUSE_EVENT_GBAR_MASK | WIDGET_MOUSE_EVENT_MASK | WIDGET_MOUSE_EVENT_OFF_SCROLL, /**< Scrolling stopped */ + WIDGET_GBAR_MOUSE_OFF_HOLD = WIDGET_MOUSE_EVENT_GBAR_MASK | WIDGET_MOUSE_EVENT_MASK | WIDGET_MOUSE_EVENT_OFF_HOLD, /**< Holding stopped */ + + WIDGET_GBAR_MOUSE_DOWN = WIDGET_MOUSE_EVENT_GBAR_MASK | WIDGET_MOUSE_EVENT_MASK | WIDGET_MOUSE_EVENT_DOWN, /**< Mouse down on the Glance Bar */ + WIDGET_GBAR_MOUSE_UP = WIDGET_MOUSE_EVENT_GBAR_MASK | WIDGET_MOUSE_EVENT_MASK | WIDGET_MOUSE_EVENT_UP, /**< Mouse up on the Glance Bar */ + WIDGET_GBAR_MOUSE_MOVE = WIDGET_MOUSE_EVENT_GBAR_MASK | WIDGET_MOUSE_EVENT_MASK | WIDGET_MOUSE_EVENT_MOVE, /**< Mouse move on the Glance Bar */ + WIDGET_GBAR_MOUSE_ENTER = WIDGET_MOUSE_EVENT_GBAR_MASK | WIDGET_MOUSE_EVENT_MASK | WIDGET_MOUSE_EVENT_ENTER, /**< Mouse enter to the Glance Bar */ + WIDGET_GBAR_MOUSE_LEAVE = WIDGET_MOUSE_EVENT_GBAR_MASK | WIDGET_MOUSE_EVENT_MASK | WIDGET_MOUSE_EVENT_LEAVE, /**< Mouse leave from the Glance Bar */ + WIDGET_GBAR_MOUSE_SET = WIDGET_MOUSE_EVENT_GBAR_MASK | WIDGET_MOUSE_EVENT_MASK | WIDGET_MOUSE_EVENT_SET, /**< Mouse event, start feeding event by master */ + WIDGET_GBAR_MOUSE_UNSET = WIDGET_MOUSE_EVENT_GBAR_MASK | WIDGET_MOUSE_EVENT_MASK | WIDGET_MOUSE_EVENT_UNSET, /**< Mouse event, stop feeding event by master */ + + WIDGET_MOUSE_EVENT_MAX = 0xFFFFFFFF /**< Unknown event */ +} widget_mouse_event_type_e; + +typedef enum widget_key_event_type { + WIDGET_KEY_EVENT_MASK = 0x80000000, /**< Mask value for key event */ + WIDGET_KEY_EVENT_GBAR_MASK = 0x10000000, /**< Mask value for Glance Bar event */ + WIDGET_KEY_EVENT_WIDGET_MASK = 0x40000000, /**< Mask value for widget event */ + + WIDGET_KEY_EVENT_DOWN = 0x00000001, /**< widget key press */ + WIDGET_KEY_EVENT_UP = 0x00000002, /**< widget key release */ + WIDGET_KEY_EVENT_FOCUS_IN = 0x00000008, /**< widget key focused in */ + WIDGET_KEY_EVENT_FOCUS_OUT = 0x00000010, /**< widget key focused out */ + WIDGET_KEY_EVENT_SET = 0x00000020, /**< widget Key, start feeding event by master */ + WIDGET_KEY_EVENT_UNSET = 0x00000040, /**< widget key, stop feeding event by master */ + + WIDGET_KEY_DOWN = WIDGET_KEY_EVENT_MASK | WIDGET_KEY_EVENT_WIDGET_MASK | WIDGET_KEY_EVENT_DOWN, /**< Key down on the widget */ + WIDGET_KEY_UP = WIDGET_KEY_EVENT_MASK | WIDGET_KEY_EVENT_WIDGET_MASK | WIDGET_KEY_EVENT_UP, /**< Key up on the widget */ + WIDGET_KEY_SET = WIDGET_KEY_EVENT_MASK | WIDGET_KEY_EVENT_WIDGET_MASK | WIDGET_KEY_EVENT_SET, /**< Key event, start feeding event by master */ + WIDGET_KEY_UNSET = WIDGET_KEY_EVENT_MASK | WIDGET_KEY_EVENT_WIDGET_MASK | WIDGET_KEY_EVENT_UNSET, /**< Key event, stop feeding event by master */ + WIDGET_KEY_FOCUS_IN = WIDGET_KEY_EVENT_MASK | WIDGET_KEY_EVENT_WIDGET_MASK | WIDGET_KEY_EVENT_FOCUS_IN, /**< Key event, focus in */ + WIDGET_KEY_FOCUS_OUT = WIDGET_KEY_EVENT_MASK | WIDGET_KEY_EVENT_WIDGET_MASK | WIDGET_KEY_EVENT_FOCUS_OUT, /**< Key event, foucs out */ + + WIDGET_GBAR_KEY_DOWN = WIDGET_KEY_EVENT_MASK | WIDGET_KEY_EVENT_GBAR_MASK | WIDGET_KEY_EVENT_DOWN, /**< Key down on the widget */ + WIDGET_GBAR_KEY_UP = WIDGET_KEY_EVENT_MASK | WIDGET_KEY_EVENT_GBAR_MASK | WIDGET_KEY_EVENT_UP, /**< Key up on the widget */ + WIDGET_GBAR_KEY_SET = WIDGET_KEY_EVENT_MASK | WIDGET_KEY_EVENT_GBAR_MASK | WIDGET_KEY_EVENT_SET, /**< Key event, start feeding event by master */ + WIDGET_GBAR_KEY_UNSET = WIDGET_KEY_EVENT_MASK | WIDGET_KEY_EVENT_GBAR_MASK | WIDGET_KEY_EVENT_UNSET, /**< Key event, stop feeding event by master */ + WIDGET_GBAR_KEY_FOCUS_IN = WIDGET_KEY_EVENT_MASK | WIDGET_KEY_EVENT_GBAR_MASK | WIDGET_KEY_EVENT_FOCUS_IN, /**< Key event, focus in */ + WIDGET_GBAR_KEY_FOCUS_OUT = WIDGET_KEY_EVENT_MASK | WIDGET_KEY_EVENT_GBAR_MASK | WIDGET_KEY_EVENT_FOCUS_OUT, /**< Key event, focus out */ + + WIDGET_KEY_EVENT_MAX = 0xFFFFFFFF /**< Unknown event */ +} widget_key_event_type_e; + +/** + * @internal + * @brief Enumeration for Accessibility event for buffer type widget or Glance Bar. + * @details These events are sync'd with Tizen accessibility event set. + * @since_tizen 2.3.1 + */ +typedef enum widget_access_event_type { + WIDGET_ACCESS_EVENT_GBAR_MASK = 0x10000000, /**< Glance Bar Accessibilivent mask */ + WIDGET_ACCESS_EVENT_WIDGET_MASK = 0x20000000, /**< widget Accessibility event mask */ + + WIDGET_ACCESS_EVENT_HIGHLIGHT = 0x00000100, /**< widget accessibility: Hightlight a object, Next, Prev,Unhighlight */ + WIDGET_ACCESS_EVENT_ACTIVATE = 0x00000200, /**< widget accessibility activate */ + WIDGET_ACCESS_EVENT_ACTION = 0x00000400, /**< widget accessibility value changed, Up, Down */ + WIDGET_ACCESS_EVENT_SCROLL = 0x00000800, /**< widget accessibility scroll down, move, up */ + WIDGET_ACCESS_EVENT_VALUE_CHANGE = 0x00001000, /**< LB accessibility value change */ + WIDGET_ACCESS_EVENT_MOUSE = 0x00002000, /**< Give mouse event to highlight object, down, move, up */ + WIDGET_ACCESS_EVENT_BACK = 0x00004000, /**< Go back to a previous view ex: pop naviframe item */ + WIDGET_ACCESS_EVENT_OVER = 0x00008000, /**< Mouse over an object */ + WIDGET_ACCESS_EVENT_READ = 0x00010000, /**< Highlight an object */ + WIDGET_ACCESS_EVENT_ENABLE = 0x00020000, /**< Disable highlight and read ability, disable, enable */ + + WIDGET_ACCESS_HIGHLIGHT = WIDGET_ACCESS_EVENT_WIDGET_MASK | WIDGET_ACCESS_EVENT_HIGHLIGHT, /**< Access event - Highlight an object in the widget */ + WIDGET_ACCESS_ACTIVATE = WIDGET_ACCESS_EVENT_WIDGET_MASK | WIDGET_ACCESS_EVENT_ACTIVATE, /**< Access event - Launch or activate the highlighted object */ + WIDGET_ACCESS_ACTION = WIDGET_ACCESS_EVENT_WIDGET_MASK | WIDGET_ACCESS_EVENT_ACTION, /**< Access event - down */ + WIDGET_ACCESS_SCROLL = WIDGET_ACCESS_EVENT_WIDGET_MASK | WIDGET_ACCESS_EVENT_SCROLL, /**< Access event - scroll down */ + WIDGET_ACCESS_VALUE_CHANGE = WIDGET_ACCESS_EVENT_WIDGET_MASK | WIDGET_ACCESS_EVENT_VALUE_CHANGE, /**< LB accessibility value change */ + WIDGET_ACCESS_MOUSE = WIDGET_ACCESS_EVENT_WIDGET_MASK | WIDGET_ACCESS_EVENT_MOUSE, /**< Give mouse event to highlight object */ + WIDGET_ACCESS_BACK = WIDGET_ACCESS_EVENT_WIDGET_MASK | WIDGET_ACCESS_EVENT_BACK, /**< Go back to a previous view ex: pop naviframe item */ + WIDGET_ACCESS_OVER = WIDGET_ACCESS_EVENT_WIDGET_MASK | WIDGET_ACCESS_EVENT_OVER, /**< Mouse over an object */ + WIDGET_ACCESS_READ = WIDGET_ACCESS_EVENT_WIDGET_MASK | WIDGET_ACCESS_EVENT_READ, /**< Highlight an object */ + WIDGET_ACCESS_ENABLE = WIDGET_ACCESS_EVENT_WIDGET_MASK | WIDGET_ACCESS_EVENT_ENABLE, /**< Enable highlight and read ability */ + + WIDGET_GBAR_ACCESS_HIGHLIGHT = WIDGET_ACCESS_EVENT_GBAR_MASK | WIDGET_ACCESS_EVENT_HIGHLIGHT, /**< Access event - Highlight an object in the Glance Bar */ + WIDGET_GBAR_ACCESS_ACTIVATE = WIDGET_ACCESS_EVENT_GBAR_MASK | WIDGET_ACCESS_EVENT_ACTIVATE, /**< Access event - Launch or activate the highlighted object */ + WIDGET_GBAR_ACCESS_ACTION = WIDGET_ACCESS_EVENT_GBAR_MASK | WIDGET_ACCESS_EVENT_ACTION, /**< Access event - down */ + WIDGET_GBAR_ACCESS_SCROLL = WIDGET_ACCESS_EVENT_GBAR_MASK | WIDGET_ACCESS_EVENT_SCROLL, /**< Access event - scroll down */ + WIDGET_GBAR_ACCESS_VALUE_CHANGE = WIDGET_ACCESS_EVENT_GBAR_MASK | WIDGET_ACCESS_EVENT_VALUE_CHANGE, /**< LB accessibility value change */ + WIDGET_GBAR_ACCESS_MOUSE = WIDGET_ACCESS_EVENT_GBAR_MASK | WIDGET_ACCESS_EVENT_MOUSE, /**< Give mouse event to highlight object */ + WIDGET_GBAR_ACCESS_BACK = WIDGET_ACCESS_EVENT_GBAR_MASK | WIDGET_ACCESS_EVENT_BACK, /**< Go back to a previous view ex: pop naviframe item */ + WIDGET_GBAR_ACCESS_OVER = WIDGET_ACCESS_EVENT_GBAR_MASK | WIDGET_ACCESS_EVENT_OVER, /**< Mouse over an object */ + WIDGET_GBAR_ACCESS_READ = WIDGET_ACCESS_EVENT_GBAR_MASK | WIDGET_ACCESS_EVENT_READ, /**< Highlight an object */ + WIDGET_GBAR_ACCESS_ENABLE = WIDGET_ACCESS_EVENT_GBAR_MASK | WIDGET_ACCESS_EVENT_ENABLE, /**< Enable highlight and read ability */ + WIDGET_GBAR_ACCESS_EVENT_MAX = 0xFFFFFFFF +} widget_access_event_type_e; + +/** + * @internal + * @brief Enumeration for widget content type. + * @since_tizen 2.3.1 + */ +typedef enum widget_type { + WIDGET_CONTENT_TYPE_IMAGE = 0x01, /**< Contents of a widget is based on the image file */ + WIDGET_CONTENT_TYPE_BUFFER = 0x02, /**< Contents of a widget is based on canvas buffer(shared) */ + WIDGET_CONTENT_TYPE_TEXT = 0x04, /**< Contents of a widget is based on formatted text file */ + WIDGET_CONTENT_TYPE_RESOURCE_ID = 0x08, /**< Contens of a widget is shared by the resource id(depends on window system) */ + WIDGET_CONTENT_TYPE_UIFW = 0x10, /**< Using UI F/W resource for sharing content & event */ + WIDGET_CONTENT_TYPE_INVALID = 0xFF /**< Unknown widget type */ +} widget_type_e; + +/** + * @brief Enumeration for widget option types. + * @since_tizen 2.3.1 + */ +typedef enum widget_option_type { + WIDGET_OPTION_MANUAL_SYNC, /**< Sync frame manually */ + WIDGET_OPTION_FRAME_DROP_FOR_RESIZE, /**< Drop frames while resizing */ + WIDGET_OPTION_SHARED_CONTENT, /**< Use only one real instance for multiple fake instances if user creates widget for same content */ + WIDGET_OPTION_DIRECT_UPDATE, /**< Use the private socket for receiving updated event */ + WIDGET_OPTION_EXTRA_BUFFER_CNT, /**< Extra buffer count, ReadOnly value */ + + WIDGET_OPTION_ERROR = 0xFFFFFFFF /**< To specify the size of this enumeration type */ +} widget_option_type_e; + +/** + * @internal + * @brief Reason of faults + * @since_tizen 2.3.1 + */ +typedef enum widget_fault_type { + WIDGET_FAULT_DEACTIVATED, /**< widget is deactivated by its fault operation */ + WIDGET_FAULT_PROVIDER_DISCONNECTED, /**< Provider is disconnected */ + WIDGET_FAULT_MAX = 0xFF /**< To specify the size of this enumeration type, some compiler enjoy of this kind of notation */ +} widget_fault_type_e; + +/** + * @brief Enumeration for widget visible states. + * @details Must be sync'd with a provider. + * @since_tizen 2.3.1 + */ +typedef enum widget_visible_state { + WIDGET_SHOW = 0x00, /**< widget is shown. Default state */ + WIDGET_HIDE = 0x01, /**< widget is hidden, Update timer will not be freezed. but you cannot receive any updates events. */ + + WIDGET_HIDE_WITH_PAUSE = 0x02, /**< widget is hidden, it will pause the update timer, but if a widget updates its contents, update event will be triggered */ + + WIDGET_VISIBLE_ERROR = 0xFF /**< To specify the size of this enumeration type */ +} widget_visible_state_e; + +/** + * @internal + * @brief Accessibility Event type + * @since_tizen 2.3.1 + * @see widget_feed_access_event() + */ +typedef enum widget_access_info_type { + WIDGET_ACCESS_TYPE_NONE = 0x00, /**< Initialized */ + + WIDGET_ACCESS_TYPE_DOWN = 0x00, /**< Mouse down */ + WIDGET_ACCESS_TYPE_MOVE = 0x01, /**< Mouse move */ + WIDGET_ACCESS_TYPE_UP = 0x02, /**< Mouse up */ + + WIDGET_ACCESS_TYPE_HIGHLIGHT = 0x00, /**< Highlight */ + WIDGET_ACCESS_TYPE_HIGHLIGHT_NEXT = 0x01, /**< Highlight next */ + WIDGET_ACCESS_TYPE_HIGHLIGHT_PREV = 0x02, /**< Highlight prev */ + WIDGET_ACCESS_TYPE_UNHIGHLIGHT = 0x03, /**< Unhighlight */ + + WIDGET_ACCESS_TYPE_DISABLE = 0x00, /**< Disable */ + WIDGET_ACCESS_TYPE_ENABLE = 0x01 /**< Enable */ +} widget_access_info_type_e; + +/** + * @internal + * @brief Accessibility Event Information + * @since_tizen 2.3.1 + */ +typedef struct widget_access_event_info { + double x; /**< X Coordinates that the event occurred */ + double y; /**< Y Coordinates that the event occurred */ + widget_access_info_type_e type; /**< Accessibility event type */ + int info; /**< Extra information for this event */ +} *widget_access_event_info_s; + +/** + * @internal + * @brief Damaged Region representation + * @since_tizen 2.3.1 + */ +typedef struct widget_damage_region { + int x; /**< Coordinates X of Left-Top corner */ + int y; /**< Coordinates Y of Left-Top corner */ + int w; /**< Damage'd Width */ + int h; /**< Damage'd Height */ +} widget_damage_region_s; + +/** + * @internal + * @brief Mouse Event Information + * @since_tizen 2.3.1 + */ +typedef struct widget_mouse_event_info { + double x; /**< X coordinates of Mouse Event */ + double y; /**< Y coordinates of Mouse Event */ +} *widget_mouse_event_info_s; + +/** + * @internal + * @brief Key Event Information + * @since_tizen 2.3.1 + */ +typedef struct widget_key_event_info { + unsigned int keycode; /**< Key code */ +} *widget_key_event_info_s; + +/** + * @internal + * @brief Structure for TEXT type widget contents handling opertators. + * @since_tizen 2.3.1 + */ +typedef struct widget_script_operators { + int (*update_begin)(widget_h handle); /**< Content parser is started */ + int (*update_end)(widget_h handle); /**< Content parser is finished */ + + /* Listed functions will be called when parser meets each typed content */ + int (*update_text)(widget_h handle, const char *id, const char *part, const char *data); /**< Update text content */ + int (*update_image)(widget_h handle, const char *id, const char *part, const char *data, const char *option); /**< Update image content */ + int (*update_script)(widget_h handle, const char *id, const char *new_id, const char *part, const char *file, const char *group); /**< Update script content */ + int (*update_signal)(widget_h handle, const char *id, const char *signal_name, const char *signal); /**< Update signal */ + int (*update_drag)(widget_h handle, const char *id, const char *part, double dx, double dy); /**< Update drag info */ + int (*update_info_size)(widget_h handle, const char *id, int w, int h); /**< Update content size */ + int (*update_info_category)(widget_h handle, const char *id, const char *category); /**< Update content category info */ + int (*update_access)(widget_h handle, const char *id, const char *part, const char *text, const char *option); /**< Update access information */ + int (*operate_access)(widget_h handle, const char *id, const char *part, const char *operation, const char *option); /**< Update access operation */ + int (*update_color)(widget_h handle, const char *id, const char *part, const char *data); /**< Update color */ +} *widget_script_operator_s; + +/** + * @internal + * @brief Called for every async function. + * @details Prototype of the return callback of every async functions. + * @since_tizen 2.3.1 + * @param[in] handle Handle of the widget instance + * @param[in] ret Result status of operation (WIDGET_STATUS_XXX defined from libwidget-service) + * @param[in] data Data for result callback + * @see widget_add() + * @see widget_del() + * @see widget_activate() + * @see widget_resize() + * @see widget_set_group() + * @see widget_set_period() + * @see widget_access_event() + * @see widget_set_pinup() + * @see widget_create_glance_bar() + * @see widget_destroy_glance_bar() + * @see widget_emit_text_signal() + * @see widget_acquire_resource_id() + * @see widget_set_update_mode() + */ +typedef void (*widget_ret_cb)(widget_h handle, int ret, void *data); + +/** + * @internal + * @brief Fault event handle + * @param[in] type Type of fault event. + * @param[in] widget_id Faulted widget Id + * @param[in] file faulted filename (implementation file if it is supported) + * @param[in] func faulted function name (if it is supported) + * @param[in] data Callback data + * @return 0 on success, otherwise a negative error value + * @retval @c EXIT_FAILURE delete this event callback from the event callback list + * @retval @c EXIT_SUCCESS successfully handled, keep this callback in the event callback list + */ +typedef int (*widget_fault_handler_cb)(enum widget_fault_type type, const char *widget_id, const char *file, const char *func, void *data); + +/** + * @brief Event handle + * @since_tizen 2.3.1 + * @param[in] handle widget Event handle + * @param[in] event Event type for widget + * @param[in] data Callback Data + * @return 0 on success, otherwise a negative error value + * @return @c EXIT_FAILURE delete this event callback from the event callback list + * @return @c EXIT_SUCCESS successfully handled, keep this callback in the event callback list + */ +typedef int (*widget_event_handler_cb)(widget_h handle, widget_event_type_e event, void *data); + +/** + * @brief Auto launch handle + * @since_tizen 2.3.1 + * @param[in] handle widget Handle + * @param[in] appid UI Application Id, which should be launched + * @param[in] data callback data + */ +typedef int (*widget_auto_launch_handler_cb)(widget_h handle, const char *appid, void *data); + +/** + * @internal + * @brief Initializes the widget system with some options. + * @details widget_init function uses environment value to initiate some configurable values. + * But some applications do not want to use the env value. + * For them, this API will give a chance to set default options using given arguments. + * @a disp is a Display object which is used to hold a connection with a display server (eg, Xorg) + * @since_tizen 2.3.1 + * @param[in] disp Display, If @a disp is @c NULL, the library will try to acquire a new connection to display server + * @param[in] prevent_overwrite Overwrite flag (when the content of an image type widget is updated, it will be overwriten (0) or not (1)) + * @param[in] event_filter If the widget_feed_mouse_event() is called again in this secs, it will be ignored and the widget_feed_mouse_event() will returns WIDGET_STATUS_ERROR_BUSY status code + * @param[in] use_thread If this value has true, the viewer library will create a new thread to communicate with master service + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return #WIDGET_STATUS_ERROR_NONE on success, + * otherwise an error code (see #WIDGET_STATUS_ERROR_XXX) on failure + * @retval #WIDGET_STATUS_ERROR_OUT_OF_MEMORY If a memory is not enough to do this operation. + * @retval #WIDGET_STATUS_ERROR_IO_ERROR If fails to access widget database. + * @see widget_fini() + * @see widget_feed_mouse_event() + */ +extern int widget_viewer_init(void *disp, int prevent_overwrite, double event_filter, int use_thread); + +/** + * @internal + * @brief Finalizes the widget system. + * @since_tizen 2.3.1 + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_SUCCES if success + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER if widget_init is not called + * @see widget_init() + */ +extern int widget_viewer_fini(void); + +/** + * @brief Notifies the status of a client ("it is paused") to the provider. + * @since_tizen 2.3.1 + * @privlevel public + * @privilege %http://tizen.org/privilege/widget.viewer + * @return #WIDGET_STATUS_ERROR_NONE on success, + * otherwise an error code (see #WIDGET_STATUS_ERROR_XXX) on failure + * @retval #WIDGET_STATUS_ERROR_FAULT if it failed to send state (paused) info + * @see widget_client_set_resumed() + */ +extern int widget_viewer_notify_paused_status_of_viewer(void); + +/** + * @brief Notifies the status of client ("it is resumed") to the provider. + * @since_tizen 2.3.1 + * @privlevel public + * @privilege %http://tizen.org/privilege/widget.viewer + * @return #WIDGET_STATUS_ERROR_NONE on success, + * otherwise an error code (see #WIDGET_STATUS_ERROR_XXX) on failure + * @retval #WIDGET_STATUS_ERROR_FAULT if it failed to send state (resumed) info + * @see widget_client_set_paused() + */ +extern int widget_viewer_notify_resumed_status_of_viewer(void); + +/** + * @internal + * @brief Adds a new widget. + * @details If the screen size is "1280x720", the below size lists are used for default. + * Or you can find the default sizes in pixel from /usr/share/data-provider-master/resolution.ini. + * Size types are defined from the libwidget-service package (widget-service.h). + * + * Normal mode widget + * 1x1=175x175, #WIDGET_SIZE_TYPE_1x1 + * 2x1=354x175, #WIDGET_SIZE_TYPE_2x1 + * 2x2=354x354, #WIDGET_SIZE_TYPE_2x2 + * 4x1=712x175, #WIDGET_SIZE_TYPE_4x1 + * 4x2=712x354, #WIDGET_SIZE_TYPE_4x2 + * 4x4=712x712, #WIDGET_SIZE_TYPE_4x4 + * + * Extended sizes + * 4x3=712x533, #WIDGET_SIZE_TYPE_4x3 + * 4x5=712x891, #WIDGET_SIZE_TYPE_4x5 + * 4x6=712x1070, #WIDGET_SIZE_TYPE_4x6 + * + * Easy mode widget + * 21x21=224x215, #WIDGET_SIZE_TYPE_EASY_1x1 + * 23x21=680x215, #WIDGET_SIZE_TYPE_EASY_3x1 + * 23x23=680x653, #WIDGET_SIZE_TYPE_EASY_3x3 + * + * Special widget + * 0x0=720x1280, #WIDGET_SIZE_TYPE_FULL + * @since_tizen 2.3.1 + * @remarks + * This is an ASYNCHRONOUS API. + * Even if you get a handle from the return value of this function, it is not a created instance. + * So you have to consider it as a not initialized handle. + * It can be initialized only after getting the return callback with "ret == #WIDGET_STATUS_ERROR_NONE" + * This function is Asynchronous, so you will get result of add requst from @a cb, if you failed to send request to create a new widget, + * This function will returns proper error code + * If this returns @c NULL, you can get the reason of failure using get_last_result() + * @param[in] widget_id widget Id + * @param[in] content Contents that will be given to the widget instance + * @param[in] cluster Identifier to group widgets which will be decided in runtime. + * @param[in] category Identifier to group widgets declared in the manifest file by the widget application. + * @param[in] period Update period (@c WIDGET_DEFAULT_PERIOD can be used for this; this argument will be used to specify the period of updating contents of a widget) + * @param[in] type Size type (defined from libwidget-service package) + * @param[in] cb After the request is sent to the master provider, this callback will be called + * @param[in] data This data will be passed to the callback + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return handle + * @retval Handle widget handle but not yet initialized + * @retval @c NULL if it fails to create a handle + * @see widget_ret_cb + */ +extern widget_h widget_viewer_add_widget(const char *widget_id, const char *content, const char *cluster, const char *category, double period, widget_size_type_e type, widget_ret_cb cb, void *data); + +/** + * @internal + * @brief Deletes a widget (will replace widget_del). + * @since_tizen 2.3.1 + * @remarks + * This is an ASYNCHRONOUS API. + * If you call this with an uninitialized handle, the return callback will be called synchronously. + * So before returning from this function, the return callback will be called first. + * This function is Asynchronous, so you will get result of add requst from @a cb, if you failed to send request to create a new widget, + * This function will returns proper error code + * @param[in] handle Handle of a widget instance + * @param[in] type Deletion type (WIDGET_DELETE_PERMANENTLY or WIDGET_DELETE_TEMPORARY) + * @param[in] cb Return callback + * @param[in] data User data for return callback + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_STATUS_ERROR_BUSY Already in process + * @retval #WIDGET_STATUS_ERROR_FAULT Failed to create a request packet + * @retval #WIDGET_STATUS_ERROR_NONE Successfully sent, return callack will be called + * @see widget_ret_cb + */ +extern int widget_viewer_delete_widget(widget_h handle, widget_delete_type_e type, widget_ret_cb cb, void *data); + +/** + * @internal + * @brief Sets a widget events callback. + * @details To get the event which is pushed from the provider, Register the event callback using this API. + * The registered callback will be invoked if there are any events from the provider. + * @since_tizen 2.3.1 + * @param[in] cb Event handle + * @param[in] data User data for the event handle + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_NONE If succeed to set event handle + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_STATUS_ERROR_OUT_OF_MEMORY Not enough memory + * @see widget_unset_event_handler() + */ +extern int widget_viewer_add_event_handler(widget_event_handler_cb cb, void *data); + +/** + * @brief Unsets the widget event handle. + * @since_tizen 2.3.1 + * @privlevel public + * @privilege %http://tizen.org/privilege/widget.viewer + * @param[in] cb Event handle + * @retval pointer Pointer of 'data' which is used with the widget_set_event_handler + * @see widget_set_event_handler() + */ +extern void *widget_viewer_remove_event_handler(widget_event_handler_cb cb); + +/** + * @internal + * @brief Registers the widget fault event handle. + * @details Argument list: event, pkgname, filename, funcname. + * @since_tizen 2.3.1 + * @param[in] cb Event handle + * @param[in] data Event handle data + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_NONE If succeed to set fault event handle + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_STATUS_ERROR_OUT_OF_MEMORY Not enough memory + * @see widget_unset_fault_handler() + */ +extern int widget_viewer_add_fault_handler(widget_fault_handler_cb cb, void *data); + +/** + * @brief Unsets the widget fault event handle. + * @since_tizen 2.3.1 + * * @param[in] cb Event handle + * @retval pointer Pointer of 'data' which is used with the widget_set_fault_handler + * @see widget_set_fault_handler() + */ +extern void *widget_viewer_remove_fault_handler(widget_fault_handler_cb cb); + +/** + * @internal + * @brief Activates the faulted widget. + * @details Request result will be returned via return callback. + * @since_tizen 2.3.1 + * @remarks + * This is an ASYNCHRONOUS API. + * Even though this function returns ERROR_NONE, it means that it just successfully sent a request to the provider. + * So you have to check the return callback and its "ret" argument. + * This function is Asynchronous, so you will get result of add requst from @a cb, if you failed to send request to create a new widget, + * This function will returns proper error code + * @param[in] widget_id Package name which should be activated + * @param[in] cb Result callback + * @param[in] data Callback data + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return #WIDGET_STATUS_ERROR_NONE on success, + * otherwise an error code (see #WIDGET_STATUS_ERROR_XXX) on failure + * @retval #WIDGET_STATUS_ERROR_NONE Successfully sent a request + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_STATUS_ERROR_FAULT Failed to make a request + * @see widget_ret_cb + */ +extern int widget_viewer_activate_faulted_widget(const char *widget_id, widget_ret_cb cb, void *data); + +/** + * @internal + * @brief Resizes the widget. + * @details + * Normal mode widget size + * 1x1=175x175, WIDGET_SIZE_TYPE_1x1 + * 2x1=354x175, WIDGET_SIZE_TYPE_2x1 + * 2x2=354x354, WIDGET_SIZE_TYPE_2x2 + * 4x1=712x175, WIDGET_SIZE_TYPE_4x1 + * 4x2=712x354, WIDGET_SIZE_TYPE_4x2 + * 4x4=712x712, WIDGET_SIZE_TYPE_4x4 + * + * Extended widget size + * 4x3=712x533, WIDGET_SIZE_TYPE_4x3 + * 4x5=712x891, WIDGET_SIZE_TYPE_4x5 + * 4x6=712x1070, WIDGET_SIZE_TYPE_4x6 + * + * Easy mode widget size + * 21x21=224x215, WIDGET_SIZE_TYPE_EASY_1x1 + * 23x21=680x215, WIDGET_SIZE_TYPE_EASY_3x1 + * 23x23=680x653, WIDGET_SIZE_TYPE_EASY_3x3 + * + * Special mode widget size + * 0x0=720x1280, WIDGET_SIZE_TYPE_FULL + * @since_tizen 2.3.1 + * @privlevel public + * @privilege %http://tizen.org/privilege/widget.viewer + * @remarks + * This is an ASYNCHRONOUS API. + * This function is Asynchronous, so you will get result of add requst from @a cb, if you failed to send request to create a new widget, + * This function will returns proper error code + * @param[in] handle Handle of a widget instance + * @param[in] type Type of a widget size (e.g., WIDGET_SIZE_TYPE_1x1, ...) + * @param[in] cb Result callback of the resize operation + * @param[in] data User data for return callback + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return #WIDGET_STATUS_ERROR_NONE on success, + * otherwise an error code (see #WIDGET_STATUS_ERROR_XXX) on failure + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_STATUS_ERROR_BUSY Previous request of resize is in progress + * @retval #WIDGET_STATUS_ERROR_ALREADY Already resized, there is no differences between current size and requested size + * @retval #WIDGET_STATUS_ERROR_PERMISSION_DENIED Permission denied, you only have view the content of this box + * @retval #WIDGET_STATUS_ERROR_FAULT Failed to make a request + * @see widget_ret_cb + */ +extern int widget_viewer_resize_widget(widget_h handle, widget_size_type_e type, widget_ret_cb cb, void *data); + +/** + * @internal + * @brief Sends the click event to a widget, This is not related with mouse_event, viewer can send "clicked" event directly. + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @param[in] x Rational X of the content width + * @param[in] y Rational Y of the content height + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred + * @retval #WIDGET_STATUS_ERROR_NONE Successfully done + */ +extern int widget_viewer_send_click_event(widget_h handle, double x, double y); + +/** + * @internal + * @brief Changes the cluster/sub-cluster name of the given widget handle. + * @since_tizen 2.3.1 + * @remarks + * This is an ASYNCHRONOUS API. + * This function is Asynchronous, so you will get result of add requst from @a cb, if you failed to send request to create a new widget, + * This function will returns proper error code + * @param[in] handle Handle of a widget instance + * @param[in] cluster New cluster of a widget + * @param[in] category New category of a widget + * @param[in] cb Result callback for changing the cluster/category of a widget + * @param[in] data User data for the result callback + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_NONE Request is successfully sent. the return callback will be called + * @retval #WIDGET_STATUS_ERROR_BUSY Previous request is not finished yet + * @retval #WIDGET_STATUS_ERROR_ALREADY Group name is same with current one + * @retval #WIDGET_STATUS_ERROR_PERMISSION_DENIED You have no permission to change property of this widget instance + * @retval #WIDGET_STATUS_ERROR_FAULT Failed to make a request + * @see widget_ret_cb + */ +extern int widget_viewer_set_group(widget_h handle, const char *cluster, const char *category, widget_ret_cb cb, void *data); + +/** + * @internal + * @brief Gets the cluster and category (sub-cluster) name of the given widget (it is not I18N format, only English). + * @since_tizen 2.3.1 + * @remarks You have to do not release the cluster & category. + * It is allocated inside of a given widget instance, so you can only read it. + * @param[in] handle Handle of a widget instance + * @param[out] cluster Storage(memory) for containing the cluster name + * @param[out] category Storage(memory) for containing the category name + * @return #WIDGET_STATUS_ERROR_NONE on success, + * otherwise an error code (see #WIDGET_STATUS_ERROR_XXX) on failure + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_STATUS_ERROR_NONE Successfully done + */ +extern int widget_viewer_get_group(widget_h handle, const char **cluster, const char **category); + +/** + * @brief Gets the update period of the widget. + * @since_tizen 2.3.1 + * * @param[in] handle Handle of a widget instance + * @param[out] period Update period of the widget. + * @return #WIDGET_STATUS_ERROR_NONE on success, + * otherwise an error code (see #WIDGET_STATUS_ERROR_XXX) on failure + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid parameters + */ +extern int widget_viewer_get_period(widget_h handle, double *period); + +/** + * @internal + * @brief Changes the update period. + * @since_tizen 2.3.1 + * @remarks + * This is an ASYNCHRONOUS API. + * This function is Asynchronous, so you will get result of add requst from @a cb, if you failed to send request to create a new widget, + * This function will returns proper error code + * @param[in] handle Handle of a widget instance + * @param[in] period New update period of a widget + * @param[in] cb Result callback of changing the update period of this widget + * @param[in] data User data for the result callback + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_NONE Successfully done + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_STATUS_ERROR_BUSY + * @retval #WIDGET_STATUS_ERROR_ALREADY + * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred + * @see widget_ret_cb + */ +extern int widget_viewer_set_period(widget_h handle, double period, widget_ret_cb cb, void *data); + +/** + * @brief Checks whether the given widget is a text type or not. + * @remarks + * If this returns WIDGET_CONTENT_TYPE_INVALID, you can get the reason of failure using get_last_result() + * @since_tizen 2.3.1 + * * @param[in] handle Handle of a widget instance + * @param[in] gbar 1 for Glance Bar or 0 + * @return widget_type + * @retval #WIDGET_CONTENT_TYPE_IMAGE Contents of a widget is based on the image file + * @retval #WIDGET_CONTENT_TYPE_BUFFER Contents of a widget is based on canvas buffer(shared) + * @retval #WIDGET_CONTENT_TYPE_TEXT Contents of a widget is based on formatted text file + * @retval #WIDGET_CONTENT_TYPE_RESOURCE_ID Contens of a widget is shared by the resource id (depends on the Window system, eg, Xorg) + * @retval #WIDGET_CONTENT_TYPE_UIFW UI F/W supported content type for widget + * @retval #WIDGET_CONTENT_TYPE_INVALID Invalid type + * @see widget_type() + */ +extern int widget_viewer_get_type(widget_h handle, int gbar, widget_type_e *widget_type); + +/** + * @brief Checks if the given widget is created by user or not. + * @remarks if this returns negative value, you can get the reason of failure using get_last_result() + * @since_tizen 2.3.1 + * @privlevel public + * @privilege %http://tizen.org/privilege/widget.viewer + * @details If the widget instance is created by a system this will return 0. + * @param[in] handle Handle of a widget instance + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval 0 Automatically created widget by the provider + * @retval 1 Created by user via widget_add() + * @see widget_add() + * @see widget_set_event_handler() + */ +extern int widget_viewer_is_created_by_user(widget_h handle); + +/** + * @internal + * @brief Gets content information string of the given widget. + * @remarks if this returns @c NULL, you can get the reason of failure using get_last_result() + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @return const char * + * @retval content_info widget content info that can be used again via content_info argument of widget_add() + * @see widget_add() + */ +extern const char *widget_viewer_get_content_string(widget_h handle); + +/** + * @brief Gets the sub cluster title string of the given widget. + * @details This API is now used for accessibility. + * Each box should set their content as a string to be read by TTS. + * So if the box has focused on the homescreen, the homescreen will read text using this API. + * @since_tizen 2.3.1 + * * @remarks The title returned by this API can be read by TTS. + * But it is just recomendation for the homescreen. + * So, to read it or not depends on its implementation. + * if this returns @c NULL, you can get the reason of failure using get_last_result() + * @param[in] handle Handle of a widget instance + * @return const char * + * @retval sub Cluster name + * @retval @c NULL + */ +extern const char *widget_viewer_get_title_string(widget_h handle); + +/** + * @internal + * @brief Gets the filename of the given widget, if it is an IMAGE type widget. + * @details If the box is developed as an image format to represent its contents, the homescreen should know its image file name. + * @remarks if this returns @c NULL, you can get the reason of failure using get_last_result() + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @return const char * + * @retval filename If the widget type is image this function will give you a abs-path of an image file (content is rendered) + * @retval @c NULL If this has no image file or type is not image file. + */ +extern const char *widget_viewer_get_filename(widget_h handle); + +/** + * @brief Gets the package name of the given widget handle. + * @remarks if this returns @c NULL, you can get the reason of failure using get_last_result() + * @since_tizen 2.3.1 + * * @param[in] handle Handle of a widget instance + * @return const char * + * @retval pkgname Package name + * @retval @c NULL If the handle is not valid + */ +extern const char *widget_viewer_get_pkgname(widget_h handle); + +/** + * @brief Gets the priority of a current content. + * @remarks if this returns negative value, you can get the reason of failure using get_last_result() + * @since_tizen 2.3.1 + * * @param[in] handle Handle of a widget instance + * @param[out] priority priority of the widget + * @return #WIDGET_STATUS_ERROR_NONE on success, + * otherwise an error code (see #WIDGET_STATUS_ERROR_XXX) on failure + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid parameters + */ +extern int widget_viewer_get_priority(widget_h handle, double *priority); + +/** + * @internal + * @brief Acquires the buffer of a given widget (only for the buffer type). + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @param[in] gbar 1 for Glance Bar or 0 + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @retval address Address of a Frame Buffer + * @retval @c NULL If it fails to get buffer address + */ +extern void *widget_viewer_acquire_buffer(widget_h handle, int gbar); + +/** + * @brief Releases the buffer of a widget (only for the buffer type). + * @since_tizen 2.3.1 + * @privlevel public + * @privilege %http://tizen.org/privilege/widget.viewer + * @param[in] buffer Buffer + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_STATUS_ERROR_NONE Successfully done + * @see widget_acquire_buffer() + */ +extern int widget_viewer_release_buffer(void *buffer); + +/** + * @internal + * @brief Gets the reference count of widget buffer (only for the buffer type). + * @since_tizen 2.3.1 + * @param[in] buffer Buffer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred + * @retval refcnt Positive integer value including ZERO + */ +extern int widget_viewer_get_buffer_reference_count(void *buffer); + +/** + * @brief Gets the size of the widget. + * @remarks + * If this returns WIDGET_SIZE_TYPE_UNKNOWN, you can get the reason of failure using get_last_result() + * @since_tizen 2.3.1 + * @privlevel public + * @privilege %http://tizen.org/privilege/widget.viewer + * @param[in] handle Handle of a widget instance + * @return widget_size_type_e + * @retval #WIDGET_SIZE_TYPE_NxM N by M size + * @retval #WIDGET_SIZE_TYPE_UNKNOWN Invalid handle or size type is not defined yet + */ +extern int widget_viewer_get_size_type(widget_h handle, widget_size_type_e *size_type); + +/** + * @internal + * @brief Gets the size of the Glance Bar. + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @param[out] w Width of glance bar in pixels + * @param[out] h Height of glance bar in pixels + * @return #WIDGET_STATUS_ERROR_NONE on success, + * otherwise an error code (see #WIDGET_STATUS_ERROR_XXX) on failure + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid parameters are used + * @retval #WIDGET_STATUS_ERROR_NONE Successfully done + */ +extern int widget_viewer_get_glance_bar_size(widget_h handle, int *w, int *h); + +/** + * @internal + * @brief Gets a list of the supported sizes of a given handle. + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @param[in] size_list Array buffer for getting the size types + * @param[in] cnt size of array + * @param[out] cnt Count of returned size types + * @param[out] size_list Array of size types + * @return #WIDGET_STATUS_ERROR_NONE on success, + * otherwise an error code (see #WIDGET_STATUS_ERROR_XXX) on failure + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_STATUS_ERROR_NONE Successfully done + */ +extern int widget_viewer_get_supported_sizes(widget_h handle, int *cnt, widget_size_type_e *size_list); + +/** + * @internal + * @brief Gets BUFFER SIZE of the widget if it is a buffer type. + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @param[in] gbar 1 for Glance Bar or 0 + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval size Size in bytes of the widget buffer + */ +extern int widget_viewer_get_buffer_size(widget_h handle, int gbar); + +/** + * @internal + * @brief Sends a content event (for buffer type) to the provider (widget). + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @param[in] type Event type + * @param[in] x Coordinates of X axis + * @param[in] y Coordinates of Y axis + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_STATUS_ERROR_BUSY Previous operation is not finished yet + * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred + * @retval #WIDGET_STATUS_ERROR_NONE Successfully sent + * @see widget_feed_access_event() + * @see widget_feed_key_event() + */ +extern int widget_viewer_feed_mouse_event(widget_h handle, widget_mouse_event_type_e type, widget_mouse_event_info_s info); + +/** + * @internal + * @brief Sends an access event (for buffer type) to the provider (widget). + * @remarks + * This is an ASYNCHRONOUS API. + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @param[in] type Event type + * @param[in] x Coordinates of X axsis + * @param[in] y Coordinates of Y axsis + * @param[in] cb Result callback function + * @param[in] data Callback data + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_STATUS_ERROR_BUSY Previous operation is not finished yet + * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred + * @retval #WIDGET_STATUS_ERROR_NONE Successfully sent + * @see widget_feed_mouse_event() + * @see widget_feed_key_event() + */ +extern int widget_viewer_feed_access_event(widget_h handle, widget_access_event_type_e type, widget_access_event_info_s info, widget_ret_cb cb, void *data); + +/** + * @internal + * @brief Sends a key event (for buffer type) to the provider (widget). + * @remarks + * This is an ASYNCHRONOUS API. + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @param[in] type Key event type + * @param[in] keycode Code of key + * @param[in] cb Result callback + * @param[in] data Callback data + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_STATUS_ERROR_BUSY Previous operation is not finished yet + * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred + * @retval #WIDGET_STATUS_ERROR_NONE Successfully sent + * @see widget_feed_mouse_event() + * @see widget_feed_access_event() + */ +extern int widget_viewer_feed_key_event(widget_h handle, widget_key_event_type_e type, widget_key_event_info_s info, widget_ret_cb cb, void *data); + +/** + * @internal + * @brief Sets pin-up status of the given handle. + * @details If the widget supports the pinup feature, + * you can freeze the update of the given widget. + * But it is different from pause. + * The box will be updated and it will decide wheter update its content or not when the pinup is on. + * @remarks + * This is an ASYNCHRONOUS API. + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @param[in] flag Pinup value + * @param[in] cb Result callback + * @param[in] data Callback data + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid parameters + * @see widget_ret_cb + * @see widget_set_visibility() + * @see widget_is_pinned_up() + */ +extern int widget_viewer_set_pinup(widget_h handle, int flag, widget_ret_cb cb, void *data); + +/** + * @internal + * @brief Checks the PIN-UP status of the given handle. + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid parameters + * @retval 1 Box is pinned up + * @retval 0 Box is not pinned up + * @see widget_set_pinup() + */ +extern int widget_viewer_is_pinned_up(widget_h handle); + +/** + * @internal + * @brief Checks the availability of the PIN-UP feature for the given handle. + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval 1 If the box support Pinup feature + * @retval 0 If the box does not support the Pinup feature + * @see widget_is_pinned_up() + * @see widget_set_pinup() + */ +extern int widget_viewer_has_pinup(widget_h handle); + +/** + * @internal + * @brief Checks the existence of Glance Bar for the given handle. + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval 1 If the box support the Glance Bar + * @retval 0 If the box has no Glance Bar + */ +extern int widget_viewer_has_glance_bar(widget_h handle); + +/** + * @internal + * @brief Creates Glance Bar of the given handle with the relative position from widget. + * @remarks + * This is an ASYNCHRONOUS API. + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @param[in] x 0.0 ~ 1.0 + * @param[in] y 0.0 ~ 1.0 + * @param[in] cb Result callback + * @param[in] data Callback data + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_NONE Successfully done + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_STATUS_ERROR_BUSY Previous operation is not finished yet + * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred + * @see widget_create_glance_bar() + * @see widget_destroy_glance_bar() + * @see widget_move_glance_bar() + */ +extern int widget_viewer_create_glance_bar(widget_h handle, double x, double y, widget_ret_cb cb, void *data); + +/** + * @internal + * @brief Updates a position of the given Glance Bar. + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @param[in] x 0.0 ~ 1.0, 0.0 indicates the coordinate X of left of widget + * @param[in] y 0.0 ~ 1.0, 0.0 indicates the coordinate Y of top of widget + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_NONE If sending a request for updating position of the Glance Bar has been done successfully + * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + */ +extern int widget_viewer_move_glance_bar(widget_h handle, double x, double y); + +/** + * @internal + * @brief Destroys the Glance Bar of the given handle if it is created. + * @remarks + * This is an ASYNCHRONOUS API. + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @param[in] cb Callback function + * @param[in] data Callback data + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred + * @retval #WIDGET_STATUS_ERROR_NONE Successfully done + * @see widget_ret_cb + */ +extern int widget_viewer_destroy_glance_bar(widget_h handle, widget_ret_cb cb, void *data); + +/** + * @internal + * @brief Checks the create status of the given widget handle. + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval 0 Glance Bar is not created + * @retval 1 Glance Bar is created + */ +extern int widget_viewer_glance_bar_is_created(widget_h handle); + +/** + * @internal + * @brief Sets a function table for parsing the text content of a widget. + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @param[in] gbar 1 for Glance Bar or 0 + * @param[in] ops + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_NONE Successfully done + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @see widget_set_gbar_text_handler() + */ +extern int widget_viewer_set_text_handler(widget_h handle, int gbar, widget_script_operator_s ops); + +/** + * @internal + * @brief Emits a text signal to the given widget only if it is a text type. + * @since_tizen 2.3.1 + * @remarks + * This is an ASYNCHRONOUS API. + * This function is Asynchronous, so you will get result of add requst from @a cb, if you failed to send request to create a new widget, + * This function will returns proper error code + * @param[in] handle Handle of a widget instance + * @param[in] signal_name Emission string + * @param[in] source Source string + * @param[in] sx Start X + * @param[in] sy Start Y + * @param[in] ex End X + * @param[in] ey End Y + * @param[in] cb Result callback + * @param[in] data Callback data + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid parameters + * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred + * @retval #WIDGET_STATUS_ERROR_NONE Successfully emitted + * @see widget_ret_cb + */ +extern int widget_viewer_emit_text_signal(widget_h handle, widget_text_signal_s event_info, widget_ret_cb cb, void *data); + +/** + * @internal + * @brief Sets a private data pointer to carry it using the given handle. + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @param[in] data Data pointer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_NONE Successfully registered + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @see widget_data() + */ +extern int widget_viewer_set_data(widget_h handle, void *data); + +/** + * @internal + * @brief Gets a private data pointer which is carried by a given handle. + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @retval data Data pointer + * @retval @c NULL If there is no data + * @see widget_set_data() + */ +extern void *widget_viewer_get_data(widget_h handle); + +/** + * @internal + * @brief Subscribes an event for widgetes only in a given cluster and sub-cluster. + * @details If you wrote a view-only client, + * you can receive the event of specific widgetes which belong to a given cluster/category. + * But you cannot modify their attributes (such as size, ...). + * @since_tizen 2.3.1 + * @param[in] cluster Cluster ("*" can be used for subscribe all cluster's widgetes event; If you use the "*", value in the category will be ignored) + * @param[in] category Category ("*" can be used for subscribe widgetes events of all category(sub-cluster) in a given "cluster") + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred + * @retval #WIDGET_STATUS_ERROR_NONE Successfully requested + * @see widget_unsubscribe_group() + */ +extern int widget_viewer_subscribe_group(const char *cluster, const char *sub_cluster); + +/** + * @internal + * @brief Unsubscribes an event for the widgetes, but you will receive already added widgetes events. + * @since_tizen 2.3.1 + * @param[in] cluster Cluster("*" can be used for subscribe all cluster's widgetes event; If you use the "*", value in the category will be ignored) + * @param[in] category Category ("*" can be used for subscribe all sub-cluster's widgetes event in a given "cluster") + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred + * @retval #WIDGET_STATUS_ERROR_NONE Successfully requested + * @see widget_subscribe_group() + */ +extern int widget_viewer_unsubscribe_group(const char *cluster, const char *sub_cluster); + +/** + * @internal + * @brief Subscribe events of widgetes which is categorized by given "category" string. + * "category" is written in the XML file of each widget manifest file. + * After subscribe the category, the master will send created event for all created widgetes, + * Also it will notify client when a new widget is created. + * @since_tizen 2.3.1 + * @param[in] category Category name + * @privlevel platform + * @privilege %http://developer.samsung.com/tizen/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred + * @retval #WIDGET_STATUS_ERROR_NONE Successfully requested + * @see widget_unsubscribe_category() + */ +extern int widget_viewer_subscribe_category(const char *category); + +/** + * @internal + * @brief Unsubscribe events of widgetes. + * @since_tizen 2.3.1 + * @param[in] category Category name + * @privlevel platform + * @privilege %http://developer.samsung.com/tizen/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred + * @retval #WIDGET_STATUS_ERROR_NONE Successfully requested + * @see widget_subscribe_category() + */ +extern int widget_viewer_unsubscribe_category(const char *category); + +/** + * @internal + * @brief Refreshes the group (cluster/sub-cluser (aka. category)). + * @details This function will trigger the update of all widgetes in a given cluster/category group. + * @since_tizen 2.3.1 + * @remarks Basically, a default widget system doesn't use the cluster/category concept. + * But you can use it. So if you decide to use it, then you can trigger the update of all widgetes in the given group. + * @param[in] cluster Cluster ID + * @param[in] category Sub-cluster ID + * @param[in] force 1 if the boxes should be updated even if they are paused + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred + * @retval #WIDGET_STATUS_ERROR_NONE Successfully requested + * @see widget_refresh() + */ +extern int widget_viewer_refresh_group(const char *cluster, const char *category, int force); + +/** + * @brief Refreshes a widget. + * @since_tizen 2.3.1 + * @privlevel public + * @privilege %http://tizen.org/privilege/widget.viewer + * @param[in] handle Handle of a widget instance + * @param[in] force 1 if the box should be updated even if it is paused + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred + * @retval #WIDGET_STATUS_ERROR_NONE Successfully requested + * @see widget_refresh_group() + */ +extern int widget_viewer_refresh(widget_h handle, int force); + +/** + * @brief Gets Resource id of a widget content. + * @details This function doesn't guarantee the life-cycle of the resource id. + * If the service provider destroyed the resource id, you will not know about it. + * So you should validate it before accessing it. + * @since_tizen 2.3.1 + * * @param[in] handle Handle of a widget instance + * @param[in] gbar 1 for Glance Bar or 0 + * @param[out] resouce_id result resource id of the widget + * @return #WIDGET_STATUS_ERROR_NONE on success, + * otherwise an error code (see #WIDGET_STATUS_ERROR_XXX) on failure + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred + * @see widget_get_resource_id() + */ +extern int widget_viewer_get_resource_id(const widget_h handle, int gbar, unsigned int *resouce_id); + +/** + * @internal + * @brief Gets the Resource Id of a widget. + * @details Even if a render process releases the Resource Id, the Resource Id will be kept before being released by widget_release_resource_id. + * You should release the resource id manually. + * @remarks + * This is an ASYNCHRONOUS API. + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @param[in] gbar 1 for Glance Bar or 0 + * @param[in] cb Callback function which will be called with result of acquiring widget resource id + * @param[in] data Callback data + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred + * @retval #WIDGET_STATUS_ERROR_NONE Successfully requested + * @pre widget service system should support the ResourceId type buffer. + * The widget should be designed to use the buffer (or script). + * @see widget_release_resource_id() + * @see widget_ret_cb + */ +extern int widget_viewer_acquire_resource_id(widget_h handle, int gbar, widget_ret_cb cb, void *data); + +/** + * @internal + * @brief Get the Resource Id of a widget for Extra buffer + * @details Even if a render process(provider) released the Resource Id, it will be kept while release it by viewer.\n + * This will prevent from unexpected resource releasing for viewer.\n + * You should release this using widget_release_resource_id() + * @remarks + * This is an ASYNCHRONOUS API. + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @param[in] gbar 1 for Glance Bar or 0 + * @param[in] idx Index of extra buffer, it is limited to widget configuration + * @param[in] cb Callback function which will be called with result of acquiring widget resource id + * @param[in] data Callback data + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred + * @retval #WIDGET_STATUS_ERROR_NONE Successfully requested + * @pre widget service system should support the resource id type buffer. + * The widget should be designed to use the buffer (or script) + * @see widget_release_resource_id() + * @see widget_ret_cb + */ +extern int widget_viewer_acquire_extra_resource_id(widget_h handle, int gbar, int idx, widget_ret_cb cb, void *data); + +/** + * @brief Releases the Resource Id of a widget. + * @details After a client gets a new Resource Id or does not need to keep the current Resource Id anymore, use this function to release it. + * If there is no user for a given Resource Id, the Resource Id will be destroyed. + * @since_tizen 2.3.1 + * @privlevel public + * @privilege %http://tizen.org/privilege/widget.viewer + * @param[in] handle Handle of a widget instance + * @param[in] gbar 1 for Glance Bar or 0 + * @param[in] resource_id Resource Id of given widget handle + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred + * @retval #WIDGET_STATUS_ERROR_NONE Successfully done + * @pre The Resource Id should be acquired by widget_acquire_resource_id + * @see widget_acquire_resource_id() + */ +extern int widget_viewer_release_resource_id(widget_h handle, int gbar, unsigned int resource_id); + +/** + * @brief Updates a visible state of the widget. + * @since_tizen 2.3.1 + * @privlevel public + * @privilege %http://tizen.org/privilege/widget.viewer + * @param[in] handle Handle of a widget instance + * @param[in] state Configure the current visible state of a widget + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return #WIDGET_STATUS_ERROR_NONE on success, + * otherwise an error code (see #WIDGET_STATUS_ERROR_XXX) on failure + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_STATUS_ERROR_PERMISSION_DENIED Permission denied + * @retval #WIDGET_STATUS_ERROR_ALREADY Input state is same to existing state + * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred + */ +extern int widget_viewer_set_visibility(widget_h handle, widget_visible_state_e state); + +/** + * @internal + * @brief Gets the current visible state of a widget. + * @remarks + * If this returns WIDGET_VISIBLE_ERROR, you can get the reason of failure using get_last_result() + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @return widget_visible_state + * @retval #WIDGET_SHOW widget is shown (Default state) + * @retval #WIDGET_HIDE widget is hidden, Update timer is not frozen (but a user cannot receive any updated events; a user should refresh(reload) the content of a widget when a user make this show again) + * @retval #WIDGET_HIDE_WITH_PAUSE widget is hidden, it will pause the update timer, but if a widget updates its contents, update event will occur + * @retval #WIDGET_VISIBLE_ERROR To enlarge the size of this enumeration type + */ +extern widget_visible_state_e widget_viewer_get_visibility(widget_h handle); + +/** + * @internal + * @brief Sets an update mode of the current widget. + * @details If you set 1 for active update mode, you should get a buffer without updated event from provider. + * But if it is passive mode, you have to update content of a box when you get updated events. + * Default is Passive mode. + * @since_tizen 2.3.1 + * @remarks + * This is an ASYNCHRONOUS API. + * This function is Asynchronous, so you will get result of add requst from @a cb, if you failed to send request to create a new widget, + * This function will returns proper error code + * @param[in] handle Handle of a widget instance + * @param[in] active_update 1 means active update, 0 means passive update (default) + * @param[in] cb Result callback function + * @param[in] data Callback data + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_STATUS_ERROR_BUSY + * @retval #WIDGET_STATUS_ERROR_PERMISSION_DENIED + * @retval #WIDGET_STATUS_ERROR_ALREADY + * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred + * @retval #WIDGET_STATUS_ERROR_NONE Successfully done + * @see widget_ret_cb + */ +extern int widget_viewer_set_update_mode(widget_h handle, int active_update, widget_ret_cb cb, void *data); + +/** + * @internal + * @brief Checks the active update mode of the given widget. + * @remarks + * If this returns negative value, you can get the reason of failure using get_last_result() + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @return 0 on success, otherwise a negative error value + * @retval 0 If passive mode + * @retval 1 If active mode or error code + */ +extern int widget_viewer_is_active_update(widget_h handle); + +/** + * @internal + * @brief Syncs manually + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @param[in] gbar 1 for Glance Bar or 0 + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_NONE If success + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid handle + * @see widget_set_manual_sync() + * @see widget_manual_sync() + */ +extern int widget_viewer_sync_buffer(widget_h handle, int gbar); + +/** + * @internal + * @brief Getting the damaged region info + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @param[in] gbar 1 for Glance Bar or 0 + * @param[out] region Readonly information for damaged area + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_NONE if success + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid handle + */ +extern int widget_viewer_get_damaged_region(widget_h handle, int gbar, const widget_damage_region_s *region); + +/** + * @internal + * @brief Gets an alternative icon of the given widget instance. + * @details If the box should be represented as a shortcut icon, this function will get the alternative icon. + * @remarks + * If this returns @c NULL, you can get the reason of failure using get_last_result() + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @return const char * + * @retval address Absolute path of an alternative icon file + * @retval @c NULL widget has no alternative icon file + * @see widget_alt_name() + */ +extern const char *widget_viewer_get_alternative_icon(widget_h handle); + +/** + * @internal + * @brief Gets an alternative name of the given widget instance. + * @details If the box should be represented as a shortcut name, this function will get the alternative name. + * @remarks + * If this returns @c NULL, you can get the reason of failure using get_last_result() + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @return const char * + * @retval name Alternative name of a widget + * @retval @c NULL widget has no alternative name + * @see widget_alt_icon() + */ +extern const char *widget_viewer_get_alternative_name(widget_h handle); + +/** + * @internal + * @brief Gets a lock for a frame buffer. + * @details This function should be used to prevent from rendering to the frame buffer while reading it. + * And the locking area should be short and must be released ASAP, or the render thread will be hanged. + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @param[in] gbar 1 for Glance Bar or 0 + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_STATUS_ERROR_NONE Successfully done + * @see widget_release_buffer_lock() + */ +extern int widget_viewer_acquire_buffer_lock(widget_h handle, int gbar); + +/** + * @internal + * @brief Releases a lock of the frame buffer. + * @details This function should be called ASAP after acquiring a lock of FB, or the render process will be blocked. + * @since_tizen 2.3.1 + * @param[in] handle Handle of a widget instance + * @param[in] gbar 1 for Glance Bar or 0 + * @privlevel platform + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_STATUS_ERROR_NONE Successfully done + * @see widget_acquire_buffer_lock() + */ +extern int widget_viewer_release_buffer_lock(widget_h handle, int gbar); + +/** + * @brief Sets options for controlling a widget sub-system. + * @details + * #WIDGET_OPTION_FRAME_DROP_FOR_RESIZE + * While resizing the box, viewer doesn't want to know the updated frames of an old size content anymore. + * In that case, turn this on, the provider will not send the updated event to the viewer about an old content. + * So the viewer can reduce its burden to update unnecessary frames. + * #WIDGET_OPTION_MANUAL_SYNC + * If you don't want to update frames automatically, or you want only reload the frames by your hands, (manually) + * Turn this on. + * After turnning it on, you should sync it using widget_sync_buffer(). + * #WIDGET_OPTION_SHARED_CONTENT + * If this option is turnned on, even though you create a new widget, + * if there are already added same instances that have same contents, the instance will not be created again. + * Instead of creating a new instance, a viewer will provide an old instance with a new handle. + * @since_tizen 2.3.1 + * * @param[in] option Option which will be affected by this call + * @param[in] state New value for given option + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Unknown option + * @retval #WIDGET_STATUS_ERROR_FAULT Failed to change the state of option + * @retval #WIDGET_STATUS_ERROR_NONE Successfully changed + * @see widget_get_option() + * @see widget_sync_buffer() + */ +extern int widget_viewer_set_option(widget_option_type_e option, int state); + +/** + * @internal + * @brief Gets options of a widget sub-system. + * @remarks + * If this returns negative value, you can get the reason of failure using get_last_result() + * @since_tizen 2.3.1 + * @param[in] option Type of option + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid option + * @retval #WIDGET_STATUS_ERROR_FAULT Failed to get option + * @retval >=0 Value of given option (must be >=0) + * @see widget_set_option() + */ +extern int widget_viewer_get_option(widget_option_type_e option); + +/** + * @internal + * @brief Set a handle for launching an app by auto-launch feature + * @details If a user clicks a box, which box enabled auto-launch option, the launcher_handler will be called. + * From that callback, you should launch an app using given ui-app id. + * @since_tizen 2.3.1 + * @param[in] launch_handler Handle for launching an app manually + * @param[in] data Callback data which will be given a data for launch_handler + * @return #WIDGET_STATUS_ERROR_NONE on success, + * otherwise an error code (see #WIDGET_STATUS_ERROR_XXX) on failure + * @retval #WIDGET_STATUS_ERROR_NONE Succeed to set new handle. there is no other cases + */ +extern int widget_viewer_set_auto_launch_handler(widget_auto_launch_handler_cb cb, void *data); + +/** + * @internal + * @brief Get the last extra buffer index and its id. + * @details + * If there is an event of #WIDGET_EVENT_WIDGET_EXTRA_BUFFER_CREATED or #WIDGET_EVENT_GBAR_EXTRA_BUFFER_CREATED, + * #WIDGET_EVENT_WIDGET_EXTRA_BUFFER_DESTROYED or #WIDGET_EVENT_GBAR_EXTRA_BUFFER_DESTROYED + * you can use this to get the last created buffer info + * @since_tizen 2.3.1 + * @param[in] handle widget handle + * @param[in] gbar 1 if you want get the glance bar's info or 0 + * @param[out] idx Index of buffer + * @param[out] resource_id Resource Id + * @return status + * @retval #WIDGET_STATUS_ERROR_NONE Successfully get + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Handle is not valid + * @retval #WIDGET_STATUS_ERROR_NOT_EXIST There is no extra buffer + */ +extern int widget_viewer_get_affected_extra_buffer(widget_h handle, int gbar, int *idx, unsigned int *resource_id); + +extern int widget_viewer_get_instance_id(widget_h handle, char **instance_id); + +extern int widget_viewer_notify_orientation_of_viewer(int orientation); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif // __WIDGET_VIEWER_H diff --git a/widget_viewer/include/widget_viewer_internal.h b/widget_viewer/include/widget_viewer_internal.h new file mode 100755 index 0000000..379cdf7 --- /dev/null +++ b/widget_viewer/include/widget_viewer_internal.h @@ -0,0 +1,278 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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. + */ + +#ifndef __WIDGET_VIEWER_INTERNAL_H +#define __WIDGET_VIEWER_INTERNAL_H + +#include "widget_viewer.h" +#include "widget_buffer.h" + +struct cb_info { + widget_ret_cb cb; + void *data; +}; + +extern void _widget_invoke_event_handler(struct widget *handler, widget_event_type_e event); +extern void _widget_invoke_fault_handler(widget_fault_type_e type, const char *pkgname, const char *filename, const char *function); + +extern struct widget_common *_widget_find_common_handle(const char *pkgname, const char *filename); +extern struct widget *_widget_new_widget(const char *pkgname, const char *id, double timestamp, const char *cluster, const char *category); +extern struct widget_common *_widget_find_common_handle_by_timestamp(double timestamp); + +extern int _widget_set_group(struct widget_common *common, const char *cluster, const char *category); +extern void _widget_set_size(struct widget_common *common, int w, int h); +extern void _widget_set_gbarsize(struct widget_common *common, int w, int h); +extern void _widget_set_default_gbarsize(struct widget_common *common, int w, int h); +extern int _widget_set_content(struct widget_common *common, const char *content); +extern int _widget_set_title(struct widget_common *handler, const char *title); +extern void _widget_set_auto_launch(struct widget_common *handler, const char *auto_launch); +extern void _widget_set_id(struct widget_common *handler, const char *id); +extern void _widget_set_size_list(struct widget_common *handler, int size_list); +extern void _widget_set_priority(struct widget_common *handler, double priority); +extern int _widget_set_widget_fb(struct widget_common *handler, const char *filename); +extern int _widget_set_gbar_fb(struct widget_common *handler, const char *filename); +extern struct fb_info *_widget_get_gbar_fb(struct widget_common *handler); +extern struct fb_info *_widget_get_widget_fb(struct widget_common *handler); +extern void _widget_set_user(struct widget_common *handler, int user); +extern void _widget_set_pinup(struct widget_common *handler, int pinup); +extern void _widget_set_text_widget(struct widget_common *handler); +extern void _widget_set_text_gbar(struct widget_common *handler); +extern int _widget_text_widget(struct widget_common *handler); +extern int _widget_text_gbar(struct widget_common *handler); +extern void _widget_set_period(struct widget_common *handler, double period); +extern void _widget_set_update_mode(struct widget_common *handler, int active_mode); +extern void _widget_set_filename(struct widget_common *handler, const char *filename); +extern void _widget_unlink_filename(struct widget_common *common); +extern void _widget_set_alt_icon(struct widget_common *handler, const char *icon); +extern void _widget_set_alt_name(struct widget_common *handle, const char *name); +extern int _widget_destroy_common_handle(struct widget_common *common); +extern struct widget_common *_widget_create_common_handle(struct widget *handle, const char *pkgname, const char *cluster, const char *category); +extern int _widget_sync_gbar_fb(struct widget_common *common); +extern int _widget_sync_widget_fb(struct widget_common *common); +extern int _widget_common_unref(struct widget_common *common, struct widget *handle); +extern int _widget_common_ref(struct widget_common *common, struct widget *handle); +extern struct widget_common *_widget_find_sharable_common_handle(const char *pkgname, const char *content, int w, int h, const char *cluster, const char *category); +extern struct widget *_widget_find_widget_in_show(struct widget_common *common); +extern struct widget *_widget_get_widget_nth(struct widget_common *common, int nth); +extern void *_widget_remove_event_handler(widget_event_handler_cb widget_cb); +extern int _widget_add_event_handler(widget_event_handler_cb widget_cb, void *data); +extern int _widget_add_fault_handler(widget_fault_handler_cb widget_cb, void *data); +extern void *_widget_remove_fault_handler(widget_fault_handler_cb widget_cb); +extern struct cb_info *_widget_create_cb_info(widget_ret_cb cb, void *data); +extern void _widget_destroy_cb_info(struct cb_info *info); + +extern struct widget *_widget_ref(struct widget *handler); +extern struct widget *_widget_unref(struct widget *handler, int destroy_common); +extern int _widget_send_delete(struct widget *handler, int type, widget_ret_cb cb, void *data); +extern int _widget_delete_all(void); + +typedef enum widget_state { + WIDGET_STATE_CREATE = 0xBEEFbeef, + WIDGET_STATE_DELETE = 0xDEADdead, /* Delete only for this client */ + WIDGET_STATE_DESTROYED = 0x00DEAD00 +} widget_state_e; + +struct widget_common { + widget_state_e state; + + struct dlist *widget_list; + int refcnt; + + char *cluster; + char *category; + + char *pkgname; + char *id; + + char *content; + char *title; + char *filename; + + double timestamp; + + struct alt_info { + char *icon; + char *name; + } alt; + + widget_delete_type_e delete_type; + + int is_user; + int is_gbar_created; + int is_pinned_up; + int is_active_update; + widget_visible_state_e visible; + + struct { + widget_widget_type_e type; + struct fb_info *fb; + + int size_list; + + int width; + int height; + double priority; + + char *auto_launch; + double period; + int pinup_supported; + bool mouse_event; + + /* For the filtering event */ + double x; + double y; + + /* For the extra buffer */ + unsigned int *extra_buffer; + int last_extra_buffer_idx; + + /* Lock */ + widget_lock_info_t lock; + + /* For damaged region */ + struct widget_damage_region last_damage; + } widget; + + struct { + widget_gbar_type_e type; + struct fb_info *fb; + + int width; + int height; + + int default_width; + int default_height; + + /* For the filtering event */ + double x; + double y; + + /* For the extra buffer */ + unsigned int *extra_buffer; + int last_extra_buffer_idx; + + /* Lock */ + widget_lock_info_t lock; + + /* For damaged region */ + struct widget_damage_region last_damage; + } gbar; + + int nr_of_sizes; + + struct requested_flag { + unsigned int created:1; + unsigned int deleted:1; + unsigned int pinup:1; + unsigned int group_changed:1; + unsigned int period_changed:1; + unsigned int size_changed:1; + unsigned int gbar_created:1; + unsigned int gbar_destroyed:1; + unsigned int update_mode:1; + unsigned int access_event:1; + unsigned int key_event:1; + + /*! + * \note + * Reserved + */ + unsigned int reserved:21; + } request; +}; + +struct job_item { + struct widget *handle; + widget_ret_cb cb; + int ret; + void *data; +}; + +struct widget { + widget_state_e state; + + int refcnt; + int paused_updating; + + widget_visible_state_e visible; + struct widget_common *common; + + void *data; + + struct callback_table { + struct widget_script_operators widget_ops; + struct widget_script_operators gbar_ops; + + struct created { + widget_ret_cb cb; + void *data; + } created; + + struct deleted { + widget_ret_cb cb; + void *data; + } deleted; + + struct pinup { + widget_ret_cb cb; + void *data; + } pinup; + + struct group_changed { + widget_ret_cb cb; + void *data; + } group_changed; + + struct period_changed { + widget_ret_cb cb; + void *data; + } period_changed; + + struct size_changed { + widget_ret_cb cb; + void *data; + } size_changed; + + struct gbar_created { + widget_ret_cb cb; + void *data; + } gbar_created; + + struct gbar_destroyed { + widget_ret_cb cb; + void *data; + } gbar_destroyed; + + struct update_mode { + widget_ret_cb cb; + void *data; + } update_mode; + + struct access_event { + widget_ret_cb cb; + void *data; + } access_event; + + struct key_event { + widget_ret_cb cb; + void *data; + } key_event; + } cbs; +}; + +#endif /* __WIDGET_VIEWER_INTERNAL_H */ + +/* End of a file */ diff --git a/widget_viewer/src/client.c b/widget_viewer/src/client.c new file mode 100755 index 0000000..7d87689 --- /dev/null +++ b/widget_viewer/src/client.c @@ -0,0 +1,2297 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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 + +#include "debug.h" +#include "client.h" +#include "widget_viewer.h" +#include "widget_viewer_internal.h" +#include "desc_parser.h" +#include "fb.h" +#include "util.h" +#include "master_rpc.h" +#include "conf.h" +#include "file_service.h" +#include "dlist.h" + +int errno; + +#define MAX_DIRECT_ADDR 256 + +static struct info { + int fd; + int direct_fd; + guint timer_id; + char *client_addr; + char *direct_addr; +} s_info = { + .fd = -1, + .direct_fd = -1, + .timer_id = 0, + .client_addr = NULL, + .direct_addr = NULL, +}; + +static struct packet *master_fault_package(pid_t pid, int handle, const struct packet *packet) +{ + const char *pkgname; + const char *id; + const char *function; + + if (packet_get(packet, "sss", &pkgname, &id, &function) != 3) { + ErrPrint("Invalid arguments\n"); + return NULL; + } + + DbgPrint("[%s]\n", pkgname); + master_rpc_clear_fault_package(pkgname); + _widget_invoke_fault_handler(WIDGET_FAULT_DEACTIVATED, pkgname, id, function); + return NULL; +} + +static struct packet *master_hold_scroll(pid_t pid, int handle, const struct packet *packet) +{ + struct widget_common *common; + widget_h widget; + const char *pkgname; + const char *id; + int seize; + int ret; + struct dlist *l; + + ret = packet_get(packet, "ssi", &pkgname, &id, &seize); + if (ret != 3) { + ErrPrint("Invalid argument\n"); + goto out; + } + + common = _widget_find_common_handle(pkgname, id); + if (!common) { + ErrPrint("Instance(%s) is not exists\n", id); + goto out; + } + + DbgPrint("HOLD: [%s] seize(%d)\n", id, seize); + seize = seize ? WIDGET_EVENT_HOLD_SCROLL : WIDGET_EVENT_RELEASE_SCROLL; + dlist_foreach(common->widget_list, l, widget) { + _widget_invoke_event_handler(widget, seize); + } + +out: + return NULL; +} + +static struct packet *master_pinup(pid_t pid, int handle, const struct packet *packet) +{ + const char *pkgname; + const char *id; + const char *content; + widget_h handler; + struct dlist *l; + struct dlist *n; + struct widget_common *common; + char *new_content; + int ret; + int status; + int pinup; + + ret = packet_get(packet, "iisss", &status, &pinup, &pkgname, &id, &content); + if (ret != 5) { + ErrPrint("Invalid argument\n"); + goto out; + } + + common = _widget_find_common_handle(pkgname, id); + if (!common) { + ErrPrint("Instance (%s) is not exists\n", id); + goto out; + } + + if (status == (int)WIDGET_ERROR_NONE) { + new_content = strdup(content); + if (new_content) { + free(common->content); + common->content = new_content; + common->is_pinned_up = pinup; + } else { + ErrPrint("Heap: %d\n", errno); + status = WIDGET_ERROR_OUT_OF_MEMORY; + } + } + + common->request.pinup = 0; + + dlist_foreach_safe(common->widget_list, l, n, handler) { + if (handler->cbs.pinup.cb) { + widget_ret_cb cb; + void *cbdata; + + /* Make sure that user can call pinup API in its result callback */ + cb = handler->cbs.pinup.cb; + cbdata = handler->cbs.pinup.data; + + handler->cbs.pinup.cb = NULL; + handler->cbs.pinup.data = NULL; + + cb(handler, status, cbdata); + } else if (status == (int)WIDGET_ERROR_NONE) { + _widget_invoke_event_handler(handler, WIDGET_EVENT_PINUP_CHANGED); + } + } + +out: + return NULL; +} + +static struct packet *master_deleted(pid_t pid, int handle, const struct packet *packet) +{ + const char *pkgname; + const char *id; + double timestamp; + widget_h handler; + struct widget_common *common; + struct dlist *l; + struct dlist *n; + int reason; + + if (packet_get(packet, "ssdi", &pkgname, &id, ×tamp, &reason) != 4) { + ErrPrint("Invalid arguemnt\n"); + goto out; + } + + DbgPrint("[%s]\n", pkgname); + common = _widget_find_common_handle_by_timestamp(timestamp); + if (!common) { + /*! + * \note + * This can be happens only if the user delete a widget + * right after create it before receive created event. + */ + goto out; + } + + /*!< Check validity of this "handler" */ + if (common->state != WIDGET_STATE_CREATE) { + if (common->state != WIDGET_STATE_DELETE) { + /*! + * \note + * This is not possible + */ + ErrPrint("Already deleted handler (%s - %s)\n", pkgname, id); + return NULL; + } + } + + common->request.deleted = 0; + /*! + * We should change the state of "common handler' before handling the callbacks. + * Because if user tries to create a new handle in the callbacks, + * find_sharable_common_handle will returns destroying object. + * Then we will get panic. + * To prevent it, we should change its state first. + */ + common->state = WIDGET_STATE_DELETE; + + dlist_foreach_safe(common->widget_list, l, n, handler) { + if (handler->cbs.created.cb) { + widget_ret_cb cb; + void *cbdata; + /*! + * \note + * + * "if (handler->id == NULL) {" + * + * The instance is not created yet. + * But the master forcely destroy it and send destroyed event to this + * without the created event. + * + * It could be destroyed when a slave has critical error(fault) + * before creating an instance successfully. + */ + if (handler->cbs.created.cb == handler->cbs.deleted.cb) { + if (handler->cbs.created.data != handler->cbs.deleted.data) { + DbgPrint("cb is same but cbdata is different (%s - %s)\n", pkgname, id); + } + + handler->cbs.deleted.cb = NULL; + handler->cbs.deleted.data = NULL; + } + + cb = handler->cbs.created.cb; + cbdata = handler->cbs.created.data; + + handler->cbs.created.cb = NULL; + handler->cbs.created.data = NULL; + + if (reason == (int)WIDGET_ERROR_NONE) { + reason = WIDGET_ERROR_CANCELED; + } + + cb(handler, reason, cbdata); + } else if (common->id) { + if (handler->cbs.deleted.cb) { + widget_ret_cb cb; + void *cbdata; + + cb = handler->cbs.deleted.cb; + cbdata = handler->cbs.deleted.data; + + handler->cbs.deleted.cb = NULL; + handler->cbs.deleted.data = NULL; + + cb(handler, reason, cbdata); + } else { + _widget_invoke_event_handler(handler, WIDGET_EVENT_DELETED); + } + } + + /* Just try to delete it, if a user didn't remove it from the live box list */ + _widget_unref(handler, 1); + } + +out: + return NULL; +} + +static struct packet *master_widget_update_begin(pid_t pid, int handle, const struct packet *packet) +{ + widget_h handler; + struct widget_common *common; + const char *pkgname; + const char *id; + const char *content; + const char *title; + const char *fbfile; + double priority; + int ret; + + ret = packet_get(packet, "ssdsss", &pkgname, &id, &priority, &content, &title, &fbfile); + if (ret != 6) { + ErrPrint("Invalid argument\n"); + goto out; + } + + common = _widget_find_common_handle(pkgname, id); + if (!common) { + ErrPrint("Instance[%s] is not exists\n", id); + goto out; + } + + if (common->state != WIDGET_STATE_CREATE) { + ErrPrint("(%s) is not created\n", id); + goto out; + } + + _widget_set_priority(common, priority); + _widget_set_content(common, content); + _widget_set_title(common, title); + + /*! + * \NOTE + * Width & Height is not changed in this case. + * If the active update is began, the size should not be changed, + * And if the size is changed, the provider should finish the updating first. + * And then begin updating again after change its size. + */ + if (_widget_get_widget_fb(common)) { + (void)_widget_set_widget_fb(common, fbfile); + + ret = _widget_sync_widget_fb(common); + + if (ret != (int)WIDGET_ERROR_NONE) { + ErrPrint("Failed to do sync FB (%s - %s) (%d)\n", pkgname, fbfile, ret); + } else { + struct dlist *l; + dlist_foreach(common->widget_list, l, handler) { + _widget_invoke_event_handler(handler, WIDGET_EVENT_WIDGET_UPDATE_BEGIN); + } + } + } else { + ErrPrint("Invalid request[%s], %s\n", id, fbfile); + } + +out: + return NULL; +} + +static struct packet *master_gbar_update_begin(pid_t pid, int handle, const struct packet *packet) +{ + widget_h handler; + struct widget_common *common; + const char *pkgname; + const char *id; + const char *fbfile; + int ret; + + ret = packet_get(packet, "sss", &pkgname, &id, &fbfile); + if (ret != 2) { + ErrPrint("Invalid argument\n"); + goto out; + } + + common = _widget_find_common_handle(pkgname, id); + if (!common) { + ErrPrint("Instance[%s] is not exists\n", id); + goto out; + } + + if (common->state != WIDGET_STATE_CREATE) { + ErrPrint("[%s] is not created\n", id); + goto out; + } + + if (_widget_get_gbar_fb(common)) { + (void)_widget_set_gbar_fb(common, fbfile); + + ret = _widget_sync_gbar_fb(common); + if (ret != (int)WIDGET_ERROR_NONE) { + ErrPrint("Failed to do sync FB (%s - %s) (%d)\n", pkgname, fbfile, ret); + } else { + struct dlist *l; + dlist_foreach(common->widget_list, l, handler) { + _widget_invoke_event_handler(handler, WIDGET_EVENT_GBAR_UPDATE_BEGIN); + } + } + } else { + ErrPrint("Invalid request[%s], %s\n", id, fbfile); + } + +out: + return NULL; +} + +static struct packet *master_widget_update_end(pid_t pid, int handle, const struct packet *packet) +{ + widget_h handler; + struct widget_common *common; + const char *pkgname; + const char *id; + int ret; + + ret = packet_get(packet, "ss", &pkgname, &id); + if (ret != 2) { + ErrPrint("Invalid argument\n"); + goto out; + } + + common = _widget_find_common_handle(pkgname, id); + if (!common) { + ErrPrint("Instance[%s] is not exists\n", id); + goto out; + } + + if (common->state != WIDGET_STATE_CREATE) { + ErrPrint("[%s] is not created\n", id); + goto out; + } + + if (_widget_get_widget_fb(common)) { + struct dlist *l; + dlist_foreach(common->widget_list, l, handler) { + _widget_invoke_event_handler(handler, WIDGET_EVENT_WIDGET_UPDATE_END); + } + } else { + ErrPrint("Invalid request[%s]\n", id); + } + +out: + return NULL; +} + +static struct packet *master_key_status(pid_t pid, int handle, const struct packet *packet) +{ + widget_h handler; + struct widget_common *common; + struct dlist *l; + const char *pkgname; + const char *id; + int ret; + int status; + + ret = packet_get(packet, "ssi", &pkgname, &id, &status); + if (ret != 3) { + ErrPrint("Invalid argument\n"); + goto out; + } + + common = _widget_find_common_handle(pkgname, id); + if (!common) { + ErrPrint("Instance[%s] is not exists\n", id); + goto out; + } + + if (common->state != WIDGET_STATE_CREATE) { + ErrPrint("[%s] is not created\n", id); + goto out; + } + + common->request.key_event = 0; + dlist_foreach(common->widget_list, l, handler) { + if (handler->cbs.key_event.cb) { + widget_ret_cb cb; + void *cbdata; + + cb = handler->cbs.key_event.cb; + cbdata = handler->cbs.key_event.data; + + handler->cbs.key_event.cb = NULL; + handler->cbs.key_event.data = NULL; + + cb(handler, status, cbdata); + } else { + ErrPrint("Invalid event[%s]\n", id); + } + } + +out: + return NULL; +} + +static struct packet *master_request_close_gbar(pid_t pid, int handle, const struct packet *packet) +{ + widget_h handler; + struct widget_common *common; + struct dlist *l; + const char *pkgname; + const char *id; + int ret; + int reason; + + ret = packet_get(packet, "ssi", &pkgname, &id, &reason); + if (ret != 3) { + ErrPrint("Invalid argument\n"); + goto out; + } + + common = _widget_find_common_handle(pkgname, id); + if (!common) { + ErrPrint("Instance[%s] is not exists\n", id); + goto out; + } + + if (common->state != WIDGET_STATE_CREATE) { + ErrPrint("[%s] is not created\n", id); + goto out; + } + + if (!common->is_gbar_created) { + DbgPrint("GBAR is not created, closing what?(%s)\n", id); + goto out; + } + + DbgPrint("Reason: %d\n", reason); + + dlist_foreach(common->widget_list, l, handler) { + _widget_invoke_event_handler(handler, WIDGET_EVENT_REQUEST_CLOSE_GBAR); + } +out: + return NULL; +} + +static struct packet *master_access_status(pid_t pid, int handle, const struct packet *packet) +{ + widget_h handler; + struct widget_common *common; + struct dlist *l; + const char *pkgname; + const char *id; + int ret; + int status; + + ret = packet_get(packet, "ssi", &pkgname, &id, &status); + if (ret != 3) { + ErrPrint("Invalid argument\n"); + goto out; + } + + common = _widget_find_common_handle(pkgname, id); + if (!common) { + ErrPrint("Instance[%s] is not exists\n", id); + goto out; + } + + if (common->state != WIDGET_STATE_CREATE) { + ErrPrint("[%s] is not created\n", id); + goto out; + } + + common->request.access_event = 0; + dlist_foreach(common->widget_list, l, handler) { + if (handler->cbs.access_event.cb) { + widget_ret_cb cb; + void *cbdata; + + cb = handler->cbs.access_event.cb; + cbdata = handler->cbs.access_event.data; + + handler->cbs.access_event.cb = NULL; + handler->cbs.access_event.data = NULL; + + cb(handler, status, cbdata); + } + } +out: + return NULL; +} + +static struct packet *master_gbar_update_end(pid_t pid, int handle, const struct packet *packet) +{ + widget_h handler; + struct widget_common *common; + const char *pkgname; + const char *id; + int ret; + + ret = packet_get(packet, "ss", &pkgname, &id); + if (ret != 2) { + ErrPrint("Invalid argument\n"); + goto out; + } + + common = _widget_find_common_handle(pkgname, id); + if (!common) { + ErrPrint("Instance[%s] is not exists\n", id); + goto out; + } + + if (common->state != WIDGET_STATE_CREATE) { + ErrPrint("[%s] is not created\n", id); + goto out; + } + + if (_widget_get_widget_fb(common)) { + struct dlist *l; + + dlist_foreach(common->widget_list, l, handler) { + _widget_invoke_event_handler(handler, WIDGET_EVENT_GBAR_UPDATE_END); + } + } else { + ErrPrint("Invalid request[%s]", id); + } + +out: + return NULL; +} + +static struct packet *master_extra_info(pid_t pid, int handle, const struct packet *packet) +{ + const char *pkgname; + const char *id; + const char *content; + const char *title; + const char *icon; + const char *name; + double priority; + int ret; + widget_h handler; + struct widget_common *common; + struct dlist *l; + struct dlist *n; + + ret = packet_get(packet, "ssssssd", &pkgname, &id, + &content, &title, + &icon, &name, + &priority); + if (ret != 7) { + ErrPrint("Invalid parameters\n"); + goto out; + } + + common = _widget_find_common_handle(pkgname, id); + if (!common) { + ErrPrint("instance(%s) is not exists\n", id); + goto out; + } + + if (common->state != WIDGET_STATE_CREATE) { + /*! + * \note + * Already deleted by the user. + * Don't try to notice anything with this, Just ignore all events + * Beacuse the user doesn't wants know about this anymore + */ + ErrPrint("(%s) is not exists, but updated\n", id); + goto out; + } + + _widget_set_priority(common, priority); + _widget_set_content(common, content); + _widget_set_title(common, title); + _widget_set_alt_icon(common, icon); + _widget_set_alt_name(common, name); + + dlist_foreach_safe(common->widget_list, l, n, handler) { + _widget_invoke_event_handler(handler, WIDGET_EVENT_EXTRA_INFO_UPDATED); + } +out: + return NULL; +} + +static struct packet *master_extra_updated(pid_t pid, int handle, const struct packet *packet) +{ + const char *pkgname; + const char *id; + widget_h handler; + struct widget_common *common; + int ret; + int x; + int y; + int w; + int h; + int is_gbar; + int event_type; + int idx; + + ret = packet_get(packet, "ssiiiiii", &pkgname, &id, &is_gbar, &idx, &x, &y, &w, &h); + if (ret != 8) { + ErrPrint("Invalid argument\n"); + goto out; + } + + common = _widget_find_common_handle(pkgname, id); + if (!common) { + ErrPrint("instance(%s) is not exists\n", id); + goto out; + } + + if (common->state != WIDGET_STATE_CREATE) { + /*! + * \note + * Already deleted by the user. + * Don't try to notice anything with this, Just ignore all events + * Beacuse the user doesn't wants know about this anymore + */ + ErrPrint("(%s) is not exists, but updated\n", id); + goto out; + } + + if (is_gbar) { + common->gbar.last_damage.x = x; + common->gbar.last_damage.y = y; + common->gbar.last_damage.w = w; + common->gbar.last_damage.h = h; + common->gbar.last_extra_buffer_idx = idx; + + event_type = WIDGET_EVENT_GBAR_EXTRA_UPDATED; + } else { + common->widget.last_damage.x = x; + common->widget.last_damage.y = y; + common->widget.last_damage.w = w; + common->widget.last_damage.h = h; + common->widget.last_extra_buffer_idx = idx; + + event_type = WIDGET_EVENT_WIDGET_EXTRA_UPDATED; + + if (conf_frame_drop_for_resizing() && common->request.size_changed) { + /* Just for skipping the update event callback call, After request to resize buffer, update event will be discarded */ + DbgPrint("Discards obsoloted update event\n"); + ret = WIDGET_ERROR_RESOURCE_BUSY; + } else { + if (!conf_manual_sync()) { + ret = _widget_sync_widget_fb(common); + if (ret != (int)WIDGET_ERROR_NONE) { + ErrPrint("Failed to do sync FB (%s - %s) (%d)\n", pkgname, util_basename(util_uri_to_path(id)), ret); + } + } else { + ret = WIDGET_ERROR_NONE; + } + } + } + + if (!common->request.created && ret == (int)WIDGET_ERROR_NONE) { + struct dlist *l; + struct dlist *n; + + dlist_foreach_safe(common->widget_list, l, n, handler) { + _widget_invoke_event_handler(handler, event_type); + } + } + +out: + return NULL; +} + +static struct packet *master_widget_updated(pid_t pid, int handle, const struct packet *packet) +{ + const char *pkgname; + const char *id; + const char *fbfile; + const char *safe_file; + widget_h handler; + struct widget_common *common; + int ret; + int x; + int y; + int w; + int h; + + ret = packet_get(packet, "ssssiiii", &pkgname, &id, &fbfile, &safe_file, &x, &y, &w, &h); + if (ret != 8) { + ErrPrint("Invalid argument\n"); + goto out; + } + + common = _widget_find_common_handle(pkgname, id); + if (!common) { + ErrPrint("instance(%s) is not exists\n", id); + goto out; + } + + if (common->state != WIDGET_STATE_CREATE) { + /*! + * \note + * Already deleted by the user. + * Don't try to notice anything with this, Just ignore all events + * Beacuse the user doesn't wants know about this anymore + */ + ErrPrint("(%s) is not exists, but updated\n", id); + goto out; + } + + common->widget.last_damage.x = x; + common->widget.last_damage.y = y; + common->widget.last_damage.w = w; + common->widget.last_damage.h = h; + common->widget.last_extra_buffer_idx = WIDGET_PRIMARY_BUFFER; + _widget_set_filename(common, safe_file); + + if (_widget_text_widget(common)) { + const char *common_filename; + + common_filename = common->filename ? common->filename : util_uri_to_path(common->id); + + (void)parse_desc(common, common_filename, 0); + /*! + * \note + * DESC parser will call the "text event callback". + * Don't need to call global event callback in this case. + */ + _widget_unlink_filename(common); + goto out; + } else if (_widget_get_widget_fb(common)) { + /*! + * \todo + * replace this with "flag" instead of "callback address" + */ + if (conf_frame_drop_for_resizing() && common->request.size_changed) { + /* Just for skipping the update event callback call, After request to resize buffer, update event will be discarded */ + DbgPrint("Discards obsoloted update event\n"); + ret = WIDGET_ERROR_RESOURCE_BUSY; + } else { + (void)_widget_set_widget_fb(common, fbfile); + + if (!conf_manual_sync()) { + ret = _widget_sync_widget_fb(common); + if (ret != (int)WIDGET_ERROR_NONE) { + ErrPrint("Failed to do sync FB (%s - %s) (%d)\n", pkgname, util_basename(util_uri_to_path(id)), ret); + } + } else { + ret = WIDGET_ERROR_NONE; + } + } + } else { + ret = WIDGET_ERROR_NONE; + } + + if (ret == (int)WIDGET_ERROR_NONE && !common->request.created) { + struct dlist *l; + struct dlist *n; + + dlist_foreach_safe(common->widget_list, l, n, handler) { + _widget_invoke_event_handler(handler, WIDGET_EVENT_WIDGET_UPDATED); + } + } + _widget_unlink_filename(common); + +out: + return NULL; +} + +static struct packet *master_gbar_created(pid_t pid, int handle, const struct packet *packet) +{ + widget_h handler; + struct widget_common *common; + const char *pkgname; + const char *id; + const char *buf_id; + struct dlist *l; + struct dlist *n; + int width; + int height; + int ret; + int status; + + ret = packet_get(packet, "sssiii", &pkgname, &id, &buf_id, &width, &height, &status); + if (ret != 6) { + ErrPrint("Invalid argument\n"); + goto out; + } + + DbgPrint("[%s]\n", pkgname); + common = _widget_find_common_handle(pkgname, id); + if (!common) { + ErrPrint("Instance(%s) is not exists\n", id); + goto out; + } + + if (common->state != WIDGET_STATE_CREATE) { + ErrPrint("Instance(%s) is not created\n", id); + goto out; + } + + if (!common->request.gbar_created) { + ErrPrint("GBAR create request is canceled\n"); + goto out; + } + + common->is_gbar_created = (status == (int)WIDGET_ERROR_NONE); + common->request.gbar_created = 0; + + if (common->is_gbar_created) { + _widget_set_gbarsize(common, width, height); + if (_widget_text_gbar(common)) { + DbgPrint("Text TYPE does not need to handle this\n"); + } else { + (void)_widget_set_gbar_fb(common, buf_id); + + switch (common->gbar.type) { + case GBAR_TYPE_SCRIPT: + case GBAR_TYPE_BUFFER: + switch (fb_type(_widget_get_gbar_fb(common))) { + case WIDGET_FB_TYPE_FILE: + case WIDGET_FB_TYPE_SHM: + common->gbar.lock = widget_service_create_lock(common->id, WIDGET_TYPE_GBAR, WIDGET_LOCK_READ); + break; + case WIDGET_FB_TYPE_PIXMAP: + case WIDGET_FB_TYPE_ERROR: + default: + break; + } + break; + case GBAR_TYPE_UIFW: + case GBAR_TYPE_TEXT: + default: + break; + } + + ret = _widget_sync_gbar_fb(common); + if (ret < 0) { + ErrPrint("Failed to do sync FB (%s - %s)\n", pkgname, util_basename(util_uri_to_path(id))); + } + } + } + + DbgPrint("PERF_WIDGET\n"); + dlist_foreach_safe(common->widget_list, l, n, handler) { + if (handler->cbs.gbar_created.cb) { + widget_ret_cb cb; + void *cbdata; + + cb = handler->cbs.gbar_created.cb; + cbdata = handler->cbs.gbar_created.data; + + handler->cbs.gbar_created.cb = NULL; + handler->cbs.gbar_created.data = NULL; + + /*! + * Before call the Callback function, + * gbar_create_cb must be reset. + * Because, in the create callback, user can call create_gbar function again. + */ + cb(handler, status, cbdata); + } else if (status == (int)WIDGET_ERROR_NONE) { + _widget_invoke_event_handler(handler, WIDGET_EVENT_GBAR_CREATED); + } + } + +out: + return NULL; +} + +static struct packet *master_gbar_destroyed(pid_t pid, int handle, const struct packet *packet) +{ + widget_h handler; + struct dlist *l; + struct widget_common *common; + const char *pkgname; + const char *id; + int ret; + int status; + + ret = packet_get(packet, "ssi", &pkgname, &id, &status); + if (ret != 3) { + ErrPrint("Invalid argument\n"); + goto out; + } + + DbgPrint("[%s]\n", pkgname); + common = _widget_find_common_handle(pkgname, id); + if (!common) { + ErrPrint("Instance(%s) is not exists\n", id); + goto out; + } + + if (common->state != WIDGET_STATE_CREATE) { + ErrPrint("Instance(%s) is not created\n", id); + goto out; + } + + if (common->is_gbar_created == 0) { + ErrPrint("GBAR is not created, event is ignored\n"); + goto out; + } + + common->is_gbar_created = 0; + common->request.gbar_destroyed = 0; + + dlist_foreach(common->widget_list, l, handler) { + if (handler->cbs.gbar_destroyed.cb) { + widget_ret_cb cb; + void *cbdata; + + cb = handler->cbs.gbar_destroyed.cb; + cbdata = handler->cbs.gbar_destroyed.data; + + handler->cbs.gbar_destroyed.cb = NULL; + handler->cbs.gbar_destroyed.data = NULL; + + /*! + * Before call the Callback function, + * gbar_destroyed_cb must be reset. + * Because, in the create callback, user can call destroy_gbar function again. + */ + cb(handler, status, cbdata); + } else if (status == (int)WIDGET_ERROR_NONE) { + _widget_invoke_event_handler(handler, WIDGET_EVENT_GBAR_DESTROYED); + } + } + + /*! + * \note + * Lock file should be deleted after all callbacks are processed. + */ + switch (common->gbar.type) { + case GBAR_TYPE_SCRIPT: + case GBAR_TYPE_BUFFER: + switch (fb_type(_widget_get_gbar_fb(common))) { + case WIDGET_FB_TYPE_FILE: + case WIDGET_FB_TYPE_SHM: + widget_service_destroy_lock(common->gbar.lock); + common->gbar.lock = NULL; + break; + case WIDGET_FB_TYPE_PIXMAP: + case WIDGET_FB_TYPE_ERROR: + default: + break; + } + break; + case GBAR_TYPE_UIFW: + case GBAR_TYPE_TEXT: + default: + break; + } + +out: + return NULL; +} + +static struct packet *master_gbar_updated(pid_t pid, int handle, const struct packet *packet) +{ + const char *pkgname; + const char *id; + const char *descfile; + const char *fbfile; + int ret; + widget_h handler; + struct widget_common *common; + struct dlist *l; + int x; + int y; + int w; + int h; + + ret = packet_get(packet, "ssssiiii", &pkgname, &id, &fbfile, &descfile, &x, &y, &w, &h); + if (ret != 8) { + ErrPrint("Invalid argument\n"); + goto out; + } + + common = _widget_find_common_handle(pkgname, id); + if (!common) { + ErrPrint("Instance(%s) is not exists\n", id); + goto out; + } + + common->gbar.last_damage.x = x; + common->gbar.last_damage.y = y; + common->gbar.last_damage.w = w; + common->gbar.last_damage.h = h; + + if (common->state != WIDGET_STATE_CREATE) { + /*! + * \note + * This handler is already deleted by the user. + * So don't try to notice anything about this anymore. + * Just ignore all events. + */ + ErrPrint("Instance(%s) is not created\n", id); + goto out; + } + + if (_widget_text_gbar(common)) { + (void)parse_desc(common, descfile, 1); + } else { + if (conf_frame_drop_for_resizing() && common->request.size_changed) { + /* Just for skipping the update event callback call, After request to resize buffer, update event will be discarded */ + DbgPrint("Discards obsoloted update event\n"); + } else { + (void)_widget_set_gbar_fb(common, fbfile); + + if (!conf_manual_sync()) { + ret = _widget_sync_gbar_fb(common); + if (ret < 0) { + ErrPrint("Failed to do sync FB (%s - %s), %d\n", pkgname, util_basename(util_uri_to_path(id)), ret); + } else { + dlist_foreach(common->widget_list, l, handler) { + _widget_invoke_event_handler(handler, WIDGET_EVENT_GBAR_UPDATED); + } + } + } else { + dlist_foreach(common->widget_list, l, handler) { + _widget_invoke_event_handler(handler, WIDGET_EVENT_GBAR_UPDATED); + } + } + } + } + +out: + return NULL; +} + +static struct packet *master_gbar_extra_buffer_destroyed(pid_t pid, int handle, const struct packet *packet) +{ + widget_h handler; + struct widget_common *common; + const char *pkgname; + struct dlist *l; + struct dlist *n; + const char *id; + int pixmap; + int idx; + int ret; + + if (!packet) { + ErrPrint("Invalid packet\n"); + goto out; + } + + ret = packet_get(packet, "ssii", &pkgname, &id, &pixmap, &idx); + if (ret != 4) { + ErrPrint("Invalid argument\n"); + goto out; + } + + if (idx < 0 || idx >= conf_extra_buffer_count()) { + ErrPrint("Extra buffer count is not matched\n"); + goto out; + } + + common = _widget_find_common_handle(pkgname, id); + if (!common) { + ErrPrint("WIDGET(%s) is not found\n", id); + goto out; + } + + if (common->state != WIDGET_STATE_CREATE) { + ErrPrint("WIDGET(%s) is not created yet\n", id); + goto out; + } + + if (!common->gbar.extra_buffer && conf_extra_buffer_count()) { + common->gbar.extra_buffer = calloc(conf_extra_buffer_count(), sizeof(*common->gbar.extra_buffer)); + if (!common->gbar.extra_buffer) { + ErrPrint("WIDGET(%s) calloc: %d\n", id, errno); + } + } + + common->gbar.last_extra_buffer_idx = idx; + if (common->gbar.extra_buffer[idx] != pixmap) { + DbgPrint("Extra buffer Pixmap is not matched %u <> %u\n", common->widget.extra_buffer[idx], pixmap); + } + + dlist_foreach_safe(common->widget_list, l, n, handler) { + _widget_invoke_event_handler(handler, WIDGET_EVENT_GBAR_EXTRA_BUFFER_DESTROYED); + } +out: + return NULL; +} + +static struct packet *master_widget_extra_buffer_destroyed(pid_t pid, int handle, const struct packet *packet) +{ + widget_h handler; + struct widget_common *common; + const char *pkgname; + struct dlist *l; + struct dlist *n; + const char *id; + int idx; + int pixmap; + int ret; + + if (!packet) { + ErrPrint("Invalid packet\n"); + goto out; + } + + ret = packet_get(packet, "ssii", &pkgname, &id, &pixmap, &idx); + if (ret != 4) { + ErrPrint("Invalid argument\n"); + goto out; + } + + if (idx < 0 || idx >= conf_extra_buffer_count()) { + ErrPrint("Extra buffer count is not matched\n"); + goto out; + } + + common = _widget_find_common_handle(pkgname, id); + if (!common) { + ErrPrint("WIDGET(%s) is not found\n", id); + goto out; + } + + if (common->state != WIDGET_STATE_CREATE) { + ErrPrint("WIDGET(%s) is not created yet\n", id); + goto out; + } + + if (!common->widget.extra_buffer && conf_extra_buffer_count()) { + common->widget.extra_buffer = calloc(conf_extra_buffer_count(), sizeof(*common->widget.extra_buffer)); + if (!common->widget.extra_buffer) { + ErrPrint("WIDGET(%s) calloc: %d\n", id, errno); + } + } + + common->widget.last_extra_buffer_idx = idx; + if (common->widget.extra_buffer[idx] != pixmap) { + DbgPrint("Extra buffer Pixmap is not matched %u <> %u\n", common->widget.extra_buffer[idx], pixmap); + } + + dlist_foreach_safe(common->widget_list, l, n, handler) { + _widget_invoke_event_handler(handler, WIDGET_EVENT_WIDGET_EXTRA_BUFFER_DESTROYED); + } +out: + return NULL; +} + +static struct packet *master_widget_extra_buffer_created(pid_t pid, int handle, const struct packet *packet) +{ + widget_h handler; + struct widget_common *common; + const char *pkgname; + struct dlist *l; + struct dlist *n; + const char *id; + int idx; + int pixmap; + int ret; + + if (!packet) { + ErrPrint("Invalid packet\n"); + goto out; + } + + ret = packet_get(packet, "ssii", &pkgname, &id, &pixmap, &idx); + if (ret != 4) { + ErrPrint("Invalid argument\n"); + goto out; + } + + if (idx < 0 || idx >= conf_extra_buffer_count()) { + ErrPrint("Extra buffer count is not matched\n"); + goto out; + } + + common = _widget_find_common_handle(pkgname, id); + if (!common) { + ErrPrint("WIDGET(%s) is not found\n", id); + goto out; + } + + if (common->state != WIDGET_STATE_CREATE) { + ErrPrint("WIDGET(%s) is not created yet\n", id); + goto out; + } + + if (!common->widget.extra_buffer && conf_extra_buffer_count()) { + common->widget.extra_buffer = calloc(conf_extra_buffer_count(), sizeof(*common->widget.extra_buffer)); + if (!common->widget.extra_buffer) { + ErrPrint("WIDGET(%s) calloc: %d\n", id, errno); + } + } + + common->widget.last_extra_buffer_idx = idx; + common->widget.extra_buffer[idx] = pixmap; + + dlist_foreach_safe(common->widget_list, l, n, handler) { + _widget_invoke_event_handler(handler, WIDGET_EVENT_WIDGET_EXTRA_BUFFER_CREATED); + } +out: + return NULL; +} + +static struct packet *master_gbar_extra_buffer_created(pid_t pid, int handle, const struct packet *packet) +{ + widget_h handler; + struct widget_common *common; + const char *pkgname; + struct dlist *l; + struct dlist *n; + const char *id; + int pixmap; + int idx; + int ret; + + if (!packet) { + ErrPrint("Invalid packet\n"); + goto out; + } + + ret = packet_get(packet, "ssii", &pkgname, &id, &pixmap, &idx); + if (ret != 4) { + ErrPrint("Invalid argument\n"); + goto out; + } + + if (idx < 0 || idx >= conf_extra_buffer_count()) { + ErrPrint("Extra buffer count is not matched\n"); + goto out; + } + + common = _widget_find_common_handle(pkgname, id); + if (!common) { + ErrPrint("WIDGET(%s) is not found\n", id); + goto out; + } + + if (common->state != WIDGET_STATE_CREATE) { + ErrPrint("WIDGET(%s) is not created yet\n", id); + goto out; + } + + if (!common->gbar.extra_buffer && conf_extra_buffer_count()) { + common->gbar.extra_buffer = calloc(conf_extra_buffer_count(), sizeof(*common->gbar.extra_buffer)); + if (!common->gbar.extra_buffer) { + ErrPrint("WIDGET(%s) calloc: %d\n", id, errno); + } + } + + common->gbar.last_extra_buffer_idx = idx; + common->gbar.extra_buffer[idx] = pixmap; + + dlist_foreach_safe(common->widget_list, l, n, handler) { + _widget_invoke_event_handler(handler, WIDGET_EVENT_GBAR_EXTRA_BUFFER_CREATED); + } +out: + return NULL; +} + +static struct packet *master_update_mode(pid_t pid, int handle, const struct packet *packet) +{ + widget_h handler; + struct widget_common *common; + struct dlist *l; + struct dlist *n; + const char *pkgname; + const char *id; + int active_mode; + int status; + int ret; + + if (!packet) { + ErrPrint("Invalid packet\n"); + goto out; + } + + ret = packet_get(packet, "ssii", &pkgname, &id, &status, &active_mode); + if (ret != 4) { + ErrPrint("Invalid argument\n"); + goto out; + } + + common = _widget_find_common_handle(pkgname, id); + if (!common) { + ErrPrint("WIDGET(%s) is not found\n", id); + goto out; + } + + if (common->state != WIDGET_STATE_CREATE) { + ErrPrint("WIDGET(%s) is not created yet\n", id); + goto out; + } + + if (status == (int)WIDGET_ERROR_NONE) { + _widget_set_update_mode(common, active_mode); + } + + common->request.update_mode = 0; + dlist_foreach_safe(common->widget_list, l, n, handler) { + if (handler->cbs.update_mode.cb) { + widget_ret_cb cb; + void *cbdata; + + cb = handler->cbs.update_mode.cb; + cbdata = handler->cbs.update_mode.data; + + handler->cbs.update_mode.cb = NULL; + handler->cbs.update_mode.data = NULL; + + cb(handler, status, cbdata); + } else if (status == (int)WIDGET_ERROR_NONE) { + _widget_invoke_event_handler(handler, WIDGET_EVENT_UPDATE_MODE_CHANGED); + } + } + +out: + return NULL; +} + +static struct packet *master_size_changed(pid_t pid, int handle, const struct packet *packet) +{ + widget_h handler; + struct widget_common *common; + const char *pkgname; + const char *id; + const char *fbfile; + int status; + int ret; + int w; + int h; + int is_gbar; + + if (!packet) { + ErrPrint("Invalid packet\n"); + goto out; + } + + ret = packet_get(packet, "sssiiii", &pkgname, &id, &fbfile, &is_gbar, &w, &h, &status); + if (ret != 7) { + ErrPrint("Invalid argument\n"); + goto out; + } + + common = _widget_find_common_handle(pkgname, id); + if (!common) { + ErrPrint("WIDGET(%s) is not found\n", id); + goto out; + } + + if (common->state != WIDGET_STATE_CREATE) { + ErrPrint("WIDGET(%s) is not created yet\n", id); + goto out; + } + + common->request.size_changed = 0; + if (is_gbar) { + /*! + * \NOTE + * GBAR is not able to resized by the client. + * GBAR is only can be managed by the provider. + * So the GBAR has no private resized event handler. + * Notify it via global event handler only. + */ + if (status == (int)WIDGET_ERROR_NONE) { + struct dlist *l; + + _widget_set_gbarsize(common, w, h); + dlist_foreach(common->widget_list, l, handler) { + _widget_invoke_event_handler(handler, WIDGET_EVENT_GBAR_SIZE_CHANGED); + } + } else { + ErrPrint("This is not possible. GBAR Size is changed but the return value is not ZERO (%d)\n", status); + } + } else { + struct dlist *l; + struct dlist *n; + + if (status == (int)WIDGET_ERROR_NONE) { + _widget_set_size(common, w, h); + + /*! + * \NOTE + * If there is a created WIDGET FB, + * Update it too. + */ + if (_widget_get_widget_fb(common)) { + (void)_widget_set_widget_fb(common, fbfile); + + ret = _widget_sync_widget_fb(common); + if (ret < 0) { + ErrPrint("Failed to do sync FB (%s - %s)\n", pkgname, util_basename(util_uri_to_path(id))); + } + + /* Just update the size info only. */ + } + } + + /*! + * \NOTE + * I cannot believe client. + * So I added some log before & after call the user callback. + */ + dlist_foreach_safe(common->widget_list, l, n, handler) { + if (handler->cbs.size_changed.cb) { + widget_ret_cb cb; + void *cbdata; + + cb = handler->cbs.size_changed.cb; + cbdata = handler->cbs.size_changed.data; + + handler->cbs.size_changed.cb = NULL; + handler->cbs.size_changed.data = NULL; + + cb(handler, status, cbdata); + } else if (status == (int)WIDGET_ERROR_NONE) { + _widget_invoke_event_handler(handler, WIDGET_EVENT_WIDGET_SIZE_CHANGED); + } + } + } + +out: + return NULL; +} + +static struct packet *master_period_changed(pid_t pid, int handle, const struct packet *packet) +{ + widget_h handler; + struct widget_common *common; + struct dlist *l; + struct dlist *n; + const char *pkgname; + const char *id; + int ret; + double period; + int status; + + ret = packet_get(packet, "idss", &status, &period, &pkgname, &id); + if (ret != 4) { + ErrPrint("Invalid argument\n"); + goto out; + } + + common = _widget_find_common_handle(pkgname, id); + if (!common) { + ErrPrint("WIDGET(%s) is not found\n", id); + goto out; + } + + if (common->state != WIDGET_STATE_CREATE) { + ErrPrint("WIDGET(%s) is not created\n", id); + goto out; + } + + if (status == (int)WIDGET_ERROR_NONE) { + _widget_set_period(common, period); + } + + common->request.period_changed = 0; + + dlist_foreach_safe(common->widget_list, l, n, handler) { + if (handler->cbs.period_changed.cb) { + widget_ret_cb cb; + void *cbdata; + + cb = handler->cbs.period_changed.cb; + cbdata = handler->cbs.period_changed.data; + + handler->cbs.period_changed.cb = NULL; + handler->cbs.period_changed.data = NULL; + + cb(handler, status, cbdata); + } else if (status == (int)WIDGET_ERROR_NONE) { + _widget_invoke_event_handler(handler, WIDGET_EVENT_PERIOD_CHANGED); + } + } + +out: + return NULL; +} + +static struct packet *master_group_changed(pid_t pid, int handle, const struct packet *packet) +{ + widget_h handler; + struct widget_common *common; + struct dlist *l; + struct dlist *n; + const char *pkgname; + const char *id; + int ret; + const char *cluster; + const char *category; + int status; + + ret = packet_get(packet, "ssiss", &pkgname, &id, &status, &cluster, &category); + if (ret != 5) { + ErrPrint("Invalid argument\n"); + goto out; + } + + common = _widget_find_common_handle(pkgname, id); + if (!common) { + ErrPrint("WIDGET(%s) is not exists\n", id); + goto out; + } + + if (common->state != WIDGET_STATE_CREATE) { + /*! + * \note + * Do no access this handler, + * You cannot believe this handler anymore. + */ + ErrPrint("WIDGET(%s) is not created\n", id); + goto out; + } + + if (status == (int)WIDGET_ERROR_NONE) { + (void)_widget_set_group(common, cluster, category); + } + + common->request.group_changed = 0; + + dlist_foreach_safe(common->widget_list, l, n, handler) { + if (handler->cbs.group_changed.cb) { + widget_ret_cb cb; + void *cbdata; + + cb = handler->cbs.group_changed.cb; + cbdata = handler->cbs.group_changed.data; + + handler->cbs.group_changed.cb = NULL; + handler->cbs.group_changed.data = NULL; + + cb(handler, status, cbdata); + } else if (status == (int)WIDGET_ERROR_NONE) { + _widget_invoke_event_handler(handler, WIDGET_EVENT_GROUP_CHANGED); + } + } + +out: + return NULL; +} + +static struct packet *master_update_id(pid_t pid, int handle, const struct packet *packet) +{ + int ret; + double timestamp; + const char *id; + struct widget_common *common; + + if (!packet) { + ErrPrint("Invalid packet\n"); + return NULL; + } + + ret = packet_get(packet, "ds", ×tamp, &id); + if (ret != 2) { + ErrPrint("Invalid paramter\n"); + return NULL; + } + + common = _widget_find_common_handle_by_timestamp(timestamp); + if (!common) { + ErrPrint("Handle is not found for %d\n", timestamp); + return NULL; + } + + _widget_set_id(common, id); + DbgPrint("Update ID(%s) for %lf\n", id, timestamp); + return NULL; +} + +static struct packet *master_created(pid_t pid, int handle, const struct packet *packet) +{ + widget_h handler; + struct widget_common *common; + struct dlist *l; + + int widget_w; + int widget_h; + int gbar_w; + int gbar_h; + const char *pkgname; + const char *id; + + const char *content; + const char *cluster; + const char *category; + const char *widget_fname; + const char *gbar_fname; + const char *title; + + double timestamp; + const char *auto_launch; + double priority; + int size_list; + int user; + int pinup_supported; + widget_widget_type_e widget_type; + widget_gbar_type_e gbar_type; + double period; + int is_pinned_up; + + int old_state = WIDGET_STATE_DESTROYED; + + int ret; + + ret = packet_get(packet, "dsssiiiisssssdiiiiidsi", + ×tamp, + &pkgname, &id, &content, + &widget_w, &widget_h, &gbar_w, &gbar_h, + &cluster, &category, &widget_fname, &gbar_fname, + &auto_launch, &priority, &size_list, &user, &pinup_supported, + &widget_type, &gbar_type, &period, &title, &is_pinned_up); + if (ret != 22) { + ErrPrint("Invalid argument\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + goto out; + } + + ErrPrint("[%lf] pkgname: %s, id: %s, content: %s, " + "gbar_w: %d, gbar_h: %d, widget_w: %d, widget_h: %d, " + "cluster: %s, category: %s, widget_fname: \"%s\", gbar_fname: \"%s\", " + "auto_launch: %s, priority: %lf, size_list: %d, user: %d, pinup: %d, " + "widget_type: %d, gbar_type: %d, period: %lf, title: [%s], is_pinned_up: %d\n", + timestamp, pkgname, id, content, + gbar_w, gbar_h, widget_w, widget_h, + cluster, category, widget_fname, gbar_fname, + auto_launch, priority, size_list, user, pinup_supported, + widget_type, gbar_type, period, title, is_pinned_up); + + common = _widget_find_common_handle_by_timestamp(timestamp); + if (!common) { + handler = _widget_new_widget(pkgname, id, timestamp, cluster, category); + if (!handler) { + ErrPrint("Failed to create a new widget\n"); + ret = WIDGET_ERROR_FAULT; + goto out; + } + common = handler->common; + old_state = common->state; + } else { + if (common->state != WIDGET_STATE_CREATE) { + if (common->state != WIDGET_STATE_DELETE) { + /*! + * \note + * This is not possible!!! + */ + ErrPrint("Invalid handler\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + goto out; + } + + /*! + * \note + * After get the delete states, + * call the create callback with deleted result. + */ + } + + old_state = common->state; + + if (common->id && common->request.created == 0) { + ErrPrint("Already created: timestamp[%lf] " + "pkgname[%s], id[%s] content[%s] " + "cluster[%s] category[%s] widget_fname[%s] gbar_fname[%s]\n", + timestamp, pkgname, id, + content, cluster, category, + widget_fname, gbar_fname); + + ret = WIDGET_ERROR_ALREADY_EXIST; + goto out; + } + + _widget_set_id(common, id); + } + + common->request.created = 0; + _widget_set_size(common, widget_w, widget_h); + common->widget.type = widget_type; + common->is_pinned_up = is_pinned_up; + + switch (widget_type) { + case WIDGET_TYPE_UIFW: + case WIDGET_TYPE_FILE: + break; + case WIDGET_TYPE_SCRIPT: + case WIDGET_TYPE_BUFFER: + if (!strlen(widget_fname)) { + break; + } + (void)_widget_set_widget_fb(common, widget_fname); + + /*! + * \note + * WIDGET should create the lock file from here. + * Even if the old_state == WIDGET_STATE_DELETE, + * the lock file will be deleted from deleted event callback. + */ + switch (fb_type(_widget_get_widget_fb(common))) { + case WIDGET_FB_TYPE_FILE: + case WIDGET_FB_TYPE_SHM: + common->widget.lock = widget_service_create_lock(common->id, WIDGET_TYPE_WIDGET, WIDGET_LOCK_READ); + break; + case WIDGET_FB_TYPE_PIXMAP: + case WIDGET_FB_TYPE_ERROR: + default: + break; + } + + ret = _widget_sync_widget_fb(common); + if (ret < 0) { + ErrPrint("Failed to do sync FB (%s - %s)\n", pkgname, util_basename(util_uri_to_path(id))); + } + break; + case WIDGET_TYPE_TEXT: + _widget_set_text_widget(common); + break; + default: + break; + } + + common->gbar.type = gbar_type; + _widget_set_gbarsize(common, gbar_w, gbar_h); + _widget_set_default_gbarsize(common, gbar_w, gbar_h); + switch (gbar_type) { + case GBAR_TYPE_SCRIPT: + case GBAR_TYPE_BUFFER: + if (!strlen(gbar_fname)) { + break; + } + + _widget_set_gbar_fb(common, gbar_fname); + + ret = _widget_sync_gbar_fb(common); + if (ret < 0) { + ErrPrint("Failed to do sync FB (%s - %s)\n", pkgname, util_basename(util_uri_to_path(id))); + } + + /*! + * \brief + * GBAR doesn't need to create the lock file from here. + * Just create it from GBAR_CREATED event. + */ + + break; + case GBAR_TYPE_TEXT: + _widget_set_text_gbar(common); + break; + case GBAR_TYPE_UIFW: + default: + break; + } + + _widget_set_priority(common, priority); + + _widget_set_size_list(common, size_list); + _widget_set_group(common, cluster, category); + + _widget_set_content(common, content); + _widget_set_title(common, title); + + _widget_set_user(common, user); + + _widget_set_auto_launch(common, auto_launch); + _widget_set_pinup(common, pinup_supported); + + _widget_set_period(common, period); + + ret = 0; + + if (common->state == WIDGET_STATE_CREATE) { + dlist_foreach(common->widget_list, l, handler) { + /*! + * \note + * These callback can change the handler->state. + * So we have to use the "old_state" which stored state before call these callbacks + */ + + if (handler->cbs.created.cb) { + widget_ret_cb cb; + void *cbdata; + + cb = handler->cbs.created.cb; + cbdata = handler->cbs.created.data; + + handler->cbs.created.cb = NULL; + handler->cbs.created.data = NULL; + + cb(handler, ret, cbdata); + } else { + _widget_invoke_event_handler(handler, WIDGET_EVENT_CREATED); + } + + /** + * If there is any updates before get this event, + * Invoke all update event forcely + */ + switch (common->widget.last_extra_buffer_idx) { + case WIDGET_UNKNOWN_BUFFER: + break; + case WIDGET_PRIMARY_BUFFER: + DbgPrint("Primary buffer updated\n"); + _widget_invoke_event_handler(handler, WIDGET_EVENT_WIDGET_UPDATED); + break; + default: + DbgPrint("Extra buffer updated\n"); + _widget_invoke_event_handler(handler, WIDGET_EVENT_WIDGET_EXTRA_UPDATED); + break; + } + } + } + +out: + if (ret == 0 && old_state == WIDGET_STATE_DELETE) { + struct dlist *n; + + DbgPrint("Take place an unexpected case [%d]\n", common->refcnt); + dlist_foreach_safe(common->widget_list, l, n, handler) { + if (handler->cbs.created.cb) { + if (!handler->common->request.deleted) { + if (_widget_send_delete(handler, common->delete_type, handler->cbs.created.cb, handler->cbs.created.data) < 0) { + /*! + * \note + * Already sent or something else happens. + * Callback will be called in any cases + */ + } + } else if (handler->state != WIDGET_STATE_DELETE) { + handler->cbs.created.cb(handler, WIDGET_ERROR_CANCELED, handler->cbs.created.data); + _widget_unref(handler, 1); + } + } else { + _widget_invoke_event_handler(handler, WIDGET_EVENT_DELETED); + _widget_unref(handler, 1); + } + } + + /*! + * \note + * handler->cbs.created.cb = NULL; + * handler->cbs.created.data = NULL; + * + * Do not clear this to use this from the deleted event callback. + * if this value is not cleared when the deleted event callback check it, + * it means that the created function is not called yet. + * Then the call the deleted event callback with WIDGET_ERROR_CANCELED errno. + */ + } + + return NULL; +} + +static struct method s_table[] = { + { /* WIDGET_UPDATED */ + .cmd = CMD_STR_WIDGET_UPDATED, /* pkgname, id, widget_w, widget_h, priority, ret */ + .handler = master_widget_updated, + }, + { /* GBAR_UPDATED */ + .cmd = CMD_STR_GBAR_UPDATED, /* pkgname, id, descfile, pd_w, pd_h, ret */ + .handler = master_gbar_updated, + }, + { /* EXTRA_UPDATED */ + .cmd = CMD_STR_EXTRA_UPDATED, + .handler = master_extra_updated, + }, + { /* EXTRA_INFO */ + .cmd = CMD_STR_EXTRA_INFO, + .handler = master_extra_info, + }, + { /* DELETED */ + .cmd = CMD_STR_DELETED, /* pkgname, id, timestamp, ret */ + .handler = master_deleted, + }, + { /* FAULTED */ + .cmd = CMD_STR_FAULT_PACKAGE, /* pkgname, id, function, ret */ + .handler = master_fault_package, + }, + { /* SCROLL */ + .cmd = CMD_STR_SCROLL, + .handler = master_hold_scroll, + }, + { /* WIDGET_UPDATE_BEGIN */ + .cmd = CMD_STR_WIDGET_UPDATE_BEGIN, + .handler = master_widget_update_begin, + }, + { /* WIDGET_UPDATE_END */ + .cmd = CMD_STR_WIDGET_UPDATE_END, + .handler = master_widget_update_end, + }, + { /* GBAR_UPDATE_BEGIN */ + .cmd = CMD_STR_GBAR_UPDATE_BEGIN, + .handler = master_gbar_update_begin, + }, + { /* GBAR_UPDATE_END */ + .cmd = CMD_STR_GBAR_UPDATE_END, + .handler = master_gbar_update_end, + }, + { /* ACCESS_STATUS */ + .cmd = CMD_STR_ACCESS_STATUS, + .handler = master_access_status, + }, + { /* KEY_STATUS */ + .cmd = CMD_STR_KEY_STATUS, + .handler = master_key_status, + }, + { /* CLOSE_GBAR */ + .cmd = CMD_STR_CLOSE_GBAR, + .handler = master_request_close_gbar, + }, + { /* GBAR_CREATED */ + .cmd = CMD_STR_GBAR_CREATED, + .handler = master_gbar_created, + }, + { /* GBAR_DESTROYED */ + .cmd = CMD_STR_GBAR_DESTROYED, + .handler = master_gbar_destroyed, + }, + { /* CREATED */ + .cmd = CMD_STR_CREATED, + .handler = master_created, + }, + { /* GROUP_CHANGED */ + .cmd = CMD_STR_GROUP_CHANGED, + .handler = master_group_changed, + }, + { /* PERIOD_CHANGED */ + .cmd = CMD_STR_PERIOD_CHANGED, + .handler = master_period_changed, + }, + { /* SIZE_CHANGED */ + .cmd = CMD_STR_SIZE_CHANGED, + .handler = master_size_changed, + }, + { /* PINUP */ + .cmd = CMD_STR_PINUP, + .handler = master_pinup, + }, + { /* UPDATE_MODE */ + .cmd = CMD_STR_UPDATE_MODE, + .handler = master_update_mode, + }, + { /* WIDGET_CREATE_XBUF */ + .cmd = CMD_STR_WIDGET_CREATE_XBUF, + .handler = master_widget_extra_buffer_created, + }, + { /* GBAR_CREATE_XBUF */ + .cmd = CMD_STR_GBAR_CREATE_XBUF, + .handler = master_gbar_extra_buffer_created, + }, + { /* WIDGET_DESTROY_XBUF */ + .cmd = CMD_STR_WIDGET_DESTROY_XBUF, + .handler = master_widget_extra_buffer_destroyed, + }, + { /* GBAR_DESTROY_XBUF */ + .cmd = CMD_STR_GBAR_DESTROY_XBUF, + .handler = master_gbar_extra_buffer_destroyed, + }, + { /* UPDATE_ID */ + .cmd = CMD_STR_UPDATE_ID, + .handler = master_update_id, + }, + { + .cmd = NULL, + .handler = NULL, + }, +}; + +static void acquire_cb(widget_h handler, const struct packet *result, void *data) +{ + if (!result) { + DbgPrint("Result packet is not valid\n"); + } else { + int ret; + int extra_buffer_count; + + if (packet_get(result, "ii", &ret, &extra_buffer_count) != 2) { + ErrPrint("Invalid argument\n"); + } else { + DbgPrint("Acquire returns: %d (%d)\n", ret, extra_buffer_count); + conf_set_extra_buffer_count(extra_buffer_count); + } + } + + return; +} + +static inline int make_connection(void) +{ + struct packet *packet; + unsigned int cmd = CMD_ACQUIRE; + int ret; + + DbgPrint("Let's making connection!\n"); + + s_info.fd = com_core_packet_client_init(client_addr(), 0, s_table); + if (s_info.fd < 0) { + ErrPrint("Try this again later\n"); + return WIDGET_ERROR_IO_ERROR; + } + + packet = packet_create((const char *)&cmd, "ds", util_timestamp(), client_direct_addr()); + if (!packet) { + com_core_packet_client_fini(s_info.fd); + s_info.fd = -1; + return WIDGET_ERROR_FAULT; + } + + ret = master_rpc_async_request(NULL, packet, 1, acquire_cb, NULL); + if (ret < 0) { + ErrPrint("Master RPC returns %d\n", ret); + com_core_packet_client_fini(s_info.fd); + s_info.fd = -1; + return WIDGET_ERROR_IO_ERROR; + } + + return WIDGET_ERROR_NONE; +} + +static int connected_cb(int handle, void *data) +{ + master_rpc_check_and_fire_consumer(); + return 0; +} + +static void master_started_cb(keynode_t *node, void *data) +{ + int state = 0; + + if (vconf_get_bool(VCONFKEY_MASTER_STARTED, &state) < 0) { + ErrPrint("Unable to get [%s]\n", VCONFKEY_MASTER_STARTED); + } + + DbgPrint("Master state: %d\n", state); + if (state == 1 && make_connection() == (int)WIDGET_ERROR_NONE) { + int ret; + ret = vconf_ignore_key_changed(VCONFKEY_MASTER_STARTED, master_started_cb); + if (ret < 0) { + DbgPrint("master_started vconf key de-registered [%d]\n", ret); + } + } +} + +static gboolean timeout_cb(gpointer data) +{ + if (vconf_notify_key_changed(VCONFKEY_MASTER_STARTED, master_started_cb, NULL) < 0) { + ErrPrint("Failed to add vconf for monitoring service state\n"); + } else { + DbgPrint("vconf event callback is registered\n"); + } + + master_started_cb(NULL, NULL); + + s_info.timer_id = 0; + return FALSE; +} + +static int disconnected_cb(int handle, void *data) +{ + if (s_info.fd != handle) { + /*!< This handle is not my favor */ + return 0; + } + + s_info.fd = -1; /*!< Disconnected */ + + master_rpc_clear_all_request(); + _widget_invoke_fault_handler(WIDGET_FAULT_PROVIDER_DISCONNECTED, MASTER_PKGNAME, "default", "disconnected"); + + _widget_delete_all(); + + /* Try to reconnect after 1 sec later */ + if (!s_info.timer_id) { + DbgPrint("Reconnecting timer is added\n"); + s_info.timer_id = g_timeout_add(1000, timeout_cb, NULL); + if (s_info.timer_id == 0) { + ErrPrint("Unable to add reconnecting timer\n"); + return 0; + } + } else { + ErrPrint("Reconnecting timer is already exists\n"); + } + + return 0; +} + +static struct method s_direct_table[] = { + { + .cmd = CMD_STR_WIDGET_UPDATED, /* pkgname, id, lb_w, lb_h, priority, ret */ + .handler = master_widget_updated, + }, + { + .cmd = CMD_STR_GBAR_UPDATED, /* pkgname, id, descfile, pd_w, pd_h, ret */ + .handler = master_gbar_updated, + }, + { + .cmd = CMD_STR_EXTRA_UPDATED, + .handler = master_extra_updated, + }, + { + .cmd = NULL, + .handler = NULL, + }, +}; + +static void prepare_direct_update(void) +{ + char path[MAX_DIRECT_ADDR]; + + if (!conf_direct_update()) { + return; + } + + if (!strncmp(s_info.client_addr, COM_CORE_REMOTE_SCHEME, strlen(COM_CORE_REMOTE_SCHEME))) { + ErrPrint("Remote model is not support this\n"); + return; + } + + snprintf(path, sizeof(path) - 1, "/tmp/.%d.%lf.widget.viewer", getpid(), util_timestamp()); + + s_info.direct_addr = strdup(path); + if (!s_info.direct_addr) { + ErrPrint("strdup: %d\n", errno); + return; + } + + s_info.direct_fd = com_core_packet_server_init(client_direct_addr(), s_direct_table); + if (s_info.direct_fd < 0) { + ErrPrint("Failed to prepare server: %s\n", client_direct_addr()); + return; + } + + DbgPrint("Direct update is prepared: %s - %d\n", client_direct_addr(), client_direct_fd()); +} + +int client_init(int use_thread) +{ + com_core_packet_use_thread(use_thread); + + s_info.client_addr = vconf_get_str(VCONFKEY_MASTER_CLIENT_ADDR); + if (!s_info.client_addr) { + s_info.client_addr = strdup(CLIENT_SOCKET); + if (!s_info.client_addr) { + ErrPrint("Heap: %d\n", errno); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + } + + (void)file_service_init(); + + DbgPrint("Server Address: %s\n", s_info.client_addr); + + com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL); + com_core_add_event_callback(CONNECTOR_CONNECTED, connected_cb, NULL); + + /** + * @note + * Before creating a connection with master, + * Initiate the private channel for getting the updated event from providers + * How could we propagates the our address to every providers? + */ + prepare_direct_update(); + + if (vconf_notify_key_changed(VCONFKEY_MASTER_STARTED, master_started_cb, NULL) < 0) { + ErrPrint("Failed to add vconf for service state\n"); + } else { + DbgPrint("vconf event callback is registered\n"); + } + + master_started_cb(NULL, NULL); + return WIDGET_ERROR_NONE; +} + +int client_fd(void) +{ + return s_info.fd; +} + +const char *client_addr(void) +{ + return s_info.client_addr; +} + +const char *client_direct_addr(void) +{ + return s_info.direct_addr; +} + +int client_direct_fd(void) +{ + return s_info.direct_fd; +} + +int client_fini(void) +{ + int ret; + + (void)file_service_fini(); + + ret = vconf_ignore_key_changed(VCONFKEY_MASTER_STARTED, master_started_cb); + if (ret < 0) { + DbgPrint("Ignore vconf key: %d\n", ret); + } + + com_core_del_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL); + com_core_del_event_callback(CONNECTOR_CONNECTED, connected_cb, NULL); + com_core_packet_client_fini(s_info.fd); + s_info.fd = -1; + + if (s_info.direct_fd >= 0) { + com_core_packet_server_fini(s_info.direct_fd); + s_info.direct_fd = -1; + } + + free(s_info.client_addr); + s_info.client_addr = NULL; + + free(s_info.direct_addr); + s_info.direct_addr = NULL; + return WIDGET_ERROR_NONE; +} + +/* End of a file */ diff --git a/widget_viewer/src/conf.c b/widget_viewer/src/conf.c new file mode 100755 index 0000000..fce80d3 --- /dev/null +++ b/widget_viewer/src/conf.c @@ -0,0 +1,82 @@ +#include +#include + +static struct info { + int manual_sync; + int frame_drop_for_resizing; + int shared_content; + int direct_update; + int extra_buffer_count; + + double event_filter; +} s_info = { + .manual_sync = 0, + .frame_drop_for_resizing = 1, + .shared_content = 0, + .direct_update = 0, + .extra_buffer_count = 0, + + .event_filter = 0.01f, +}; + +void conf_set_direct_update(int flag) +{ + s_info.direct_update = flag; +} + +int conf_direct_update(void) +{ + return s_info.direct_update; +} + +void conf_set_manual_sync(int flag) +{ + s_info.manual_sync = flag; +} + +int conf_manual_sync(void) +{ + return s_info.manual_sync; +} + +void conf_set_frame_drop_for_resizing(int flag) +{ + s_info.frame_drop_for_resizing = flag; +} + +int conf_frame_drop_for_resizing(void) +{ + return s_info.frame_drop_for_resizing; +} + +void conf_set_shared_content(int flag) +{ + s_info.shared_content = flag; +} + +int conf_shared_content(void) +{ + return s_info.shared_content; +} + +double conf_event_filter(void) +{ + return s_info.event_filter; +} + +void conf_set_event_filter(double filter) +{ + s_info.event_filter = filter; +} + +void conf_set_extra_buffer_count(int buffer_count) +{ + s_info.extra_buffer_count = buffer_count; +} + +int conf_extra_buffer_count(void) +{ + return s_info.extra_buffer_count; +} + +/* End of a file */ diff --git a/widget_viewer/src/desc_parser.c b/widget_viewer/src/desc_parser.c new file mode 100755 index 0000000..de8f283 --- /dev/null +++ b/widget_viewer/src/desc_parser.c @@ -0,0 +1,701 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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 /* malloc */ +#include /* strdup */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "widget_viewer.h" +#include "widget_viewer_internal.h" +#include "desc_parser.h" +#include "dlist.h" +#include "util.h" + +#define INFO_SIZE "size" +#define INFO_CATEGORY "category" + +static const char *type_list[] = { + "access", + "access,operation", + "color", + "drag", + "image", + "info", + "script", + "signal", + "text", + NULL +}; + +static const char *field_list[] = { + "type", + "part", + "data", + "option", + "id", + "target", + "file", + NULL +}; + +enum block_type { + TYPE_ACCESS, + TYPE_ACCESS_OP, + TYPE_COLOR, + TYPE_DRAG, + TYPE_IMAGE, + TYPE_INFO, + TYPE_SCRIPT, + TYPE_SIGNAL, + TYPE_TEXT, + TYPE_MAX +}; + +enum field_type { + FIELD_TYPE, + FIELD_PART, + FIELD_DATA, + FIELD_OPTION, + FIELD_ID, + FIELD_TARGET, + FIELD_FILE +}; + +struct block { + enum block_type type; + char *part; + char *data; + char *option; + char *id; + char *target; + char *file; + + /* Should be released */ + char *filebuf; + const char *filename; +}; + +static int update_text(widget_h handle, struct block *block, int is_gbar) +{ + struct widget_script_operators *ops; + + if (!block || !block->part || !block->data) { + ErrPrint("Invalid argument\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + ops = is_gbar ? &handle->cbs.gbar_ops : &handle->cbs.widget_ops; + if (ops->update_text) { + ops->update_text(handle, (const char *)block->id, (const char *)block->part, (const char *)block->data); + } + + return 0; +} + +static int update_image(widget_h handle, struct block *block, int is_gbar) +{ + struct widget_script_operators *ops; + + if (!block || !block->part) { + ErrPrint("Invalid argument\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + ops = is_gbar ? &handle->cbs.gbar_ops : &handle->cbs.widget_ops; + if (ops->update_image) { + ops->update_image(handle, block->id, block->part, block->data, block->option); + } + + return 0; +} + +static int update_script(widget_h handle, struct block *block, int is_gbar) +{ + struct widget_script_operators *ops; + + if (!block || !block->part) { + ErrPrint("Invalid argument\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + ops = is_gbar ? &handle->cbs.gbar_ops : &handle->cbs.widget_ops; + if (ops->update_script) { + ops->update_script(handle, block->id, block->target, block->part, block->data, block->option); + } + + return 0; +} + +static int update_signal(widget_h handle, struct block *block, int is_gbar) +{ + struct widget_script_operators *ops; + + if (!block) { + ErrPrint("Invalid argument\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + ops = is_gbar ? &handle->cbs.gbar_ops : &handle->cbs.widget_ops; + if (ops->update_signal) { + ops->update_signal(handle, block->id, block->data, block->part); + } + + return 0; +} + +static int update_drag(widget_h handle, struct block *block, int is_gbar) +{ + double dx, dy; + struct widget_script_operators *ops; + + if (!block || !block->data || !block->part) { + ErrPrint("Invalid argument\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (sscanf(block->data, "%lfx%lf", &dx, &dy) != 2) { + ErrPrint("Invalid format of data\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + ops = is_gbar ? &handle->cbs.gbar_ops : &handle->cbs.widget_ops; + if (ops->update_drag) { + ops->update_drag(handle, block->id, block->part, dx, dy); + } + + return 0; +} + +static int update_info(widget_h handle, struct block *block, int is_gbar) +{ + struct widget_script_operators *ops; + + if (!block || !block->part || !block->data) { + ErrPrint("Invalid argument\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + ops = is_gbar ? &handle->cbs.gbar_ops : &handle->cbs.widget_ops; + if (!strcasecmp(block->part, INFO_SIZE)) { + int w, h; + + if (sscanf(block->data, "%dx%d", &w, &h) != 2) { + ErrPrint("Invalid format (%s)\n", block->data); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (ops->update_info_size) { + ops->update_info_size(handle, block->id, w, h); + } + } else if (!strcasecmp(block->part, INFO_CATEGORY)) { + if (ops->update_info_category) { + ops->update_info_category(handle, block->id, block->data); + } + } + + return 0; +} + +static int update_access(widget_h handle, struct block *block, int is_gbar) +{ + struct widget_script_operators *ops; + + if (!block) { + ErrPrint("Invalid argument\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + ops = is_gbar ? &handle->cbs.gbar_ops : &handle->cbs.widget_ops; + if (ops->update_access) { + ops->update_access(handle, block->id, block->part, block->data, block->option); + } + + return 0; +} + +static int operate_access(widget_h handle, struct block *block, int is_gbar) +{ + struct widget_script_operators *ops; + + if (!block) { + ErrPrint("Invalid argument\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + ops = is_gbar ? &handle->cbs.gbar_ops : &handle->cbs.widget_ops; + if (ops->operate_access) { + ops->operate_access(handle, block->id, block->part, block->data, block->option); + } + + return 0; +} + +static int update_color(widget_h handle, struct block *block, int is_gbar) +{ + struct widget_script_operators *ops; + + if (!block) { + ErrPrint("Invalid argument\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + ops = is_gbar ? &handle->cbs.gbar_ops : &handle->cbs.widget_ops; + if (ops->update_color) { + ops->update_color(handle, block->id, block->part, block->data); + } + + return 0; +} + +static inline int update_begin(widget_h handle, int is_gbar) +{ + struct widget_script_operators *ops; + + ops = is_gbar ? &handle->cbs.gbar_ops : &handle->cbs.widget_ops; + if (ops->update_begin) { + ops->update_begin(handle); + } + + return 0; +} + +static inline int update_end(widget_h handle, int is_gbar) +{ + struct widget_script_operators *ops; + + ops = is_gbar ? &handle->cbs.gbar_ops : &handle->cbs.widget_ops; + if (ops->update_end) { + ops->update_end(handle); + } + + return 0; +} + +static inline void delete_block(struct block *block) +{ + free(block->filebuf); + free(block); +} + +static inline void consuming_parsed_block(widget_h handle, int is_gbar, struct block *block) +{ + typedef int (*update_function_t)(widget_h handle, struct block *block, int is_gbar); + static update_function_t updators[] = { + update_access, + operate_access, + update_color, + update_drag, + update_image, + update_info, + update_script, + update_signal, + update_text, + NULL + }; + + if (block->type >= 0 || block->type < TYPE_MAX) { + (void)updators[block->type](handle, block, is_gbar); + } else { + ErrPrint("Block type[%d] is not valid\n", block->type); + } +} + +static inline char *load_file(const char *filename) +{ + char *filebuf = NULL; + int fd; + off_t filesize; + int ret; + size_t readsize = 0; + + fd = open(filename, O_RDONLY); + if (fd < 0) { + ErrPrint("open: %d (%s)\n", errno, filename); + return NULL; + } + + filesize = lseek(fd, 0L, SEEK_END); + if (filesize == (off_t)-1) { + ErrPrint("lseek: %d\n", errno); + goto errout; + } + + if (lseek(fd, 0L, SEEK_SET) < 0) { + ErrPrint("lseek: %d\n", errno); + goto errout; + } + + filebuf = malloc(filesize + 1); + if (!filebuf) { + ErrPrint("malloc: %d\n", errno); + goto errout; + } + + while (readsize < filesize) { + ret = read(fd, filebuf + readsize, (size_t)filesize - readsize); + if (ret < 0) { + if (errno == EINTR) { + DbgPrint("Read is interrupted\n"); + continue; + } + + ErrPrint("read: %d\n", errno); + free(filebuf); + filebuf = NULL; + break; + } + + readsize += ret; + } + + if (filebuf) { + filebuf[readsize] = '\0'; + } + + /*! + * \note + * Now, we are ready to parse the filebuf. + */ + +errout: + if (close(fd) < 0) { + ErrPrint("close: %d\n", errno); + } + + return filebuf; +} + +int parse_desc(struct widget_common *common, const char *filename, int is_gbar) +{ + int type_idx = 0; + int type_len = 0; + int field_idx = 0; + int field_len = 0; + char *filebuf; + char *fileptr; + char *ptr = NULL; + struct block *block = NULL; + struct dlist *block_list = NULL; + struct dlist *l; + struct dlist *n; + struct dlist *handle_iterator; + widget_h handler; + enum state { + BEGIN, + FIELD, + DATA, + END, + DONE, + ERROR, + } state; + + filebuf = load_file(filename); + if (!filebuf) { + return WIDGET_ERROR_IO_ERROR; + } + + fileptr = filebuf; + + state = BEGIN; + while (*fileptr && state != ERROR) { + switch (state) { + case BEGIN: + if (*fileptr == '{') { + if (block) + free(block); + block = calloc(1, sizeof(*block)); + if (!block) { + ErrPrint("calloc: %d\n", errno); + state = ERROR; + continue; + } + state = FIELD; + ptr = NULL; + } + break; + case FIELD: + if (isspace(*fileptr)) { + if (ptr != NULL) { + *fileptr = '\0'; + } + } else if (*fileptr == '=') { + *fileptr = '\0'; + ptr = NULL; + state = DATA; + } else if (ptr == NULL) { + ptr = fileptr; + field_idx = 0; + field_len = 0; + + while (field_list[field_idx]) { + if (field_list[field_idx][field_len] == *fileptr) { + break; + } + field_idx++; + } + + if (!field_list[field_idx]) { + ErrPrint("Invalid field\n"); + state = ERROR; + continue; + } + + field_len++; + } else { + if (field_list[field_idx][field_len] != *fileptr) { + field_idx++; + while (field_list[field_idx]) { + if (!strncmp(field_list[field_idx], fileptr - field_len, field_len)) { + break; + } else { + field_idx++; + } + } + + if (!field_list[field_idx]) { + state = ERROR; + ErrPrint("field is not valid\n"); + continue; + } + } + + field_len++; + } + break; + case DATA: + switch (field_idx) { + case FIELD_TYPE: + if (ptr == NULL) { + if (isspace(*fileptr)) { + break; + } + + if (*fileptr == '\0') { + state = ERROR; + ErrPrint("Type is not valid\n"); + continue; + } + + ptr = fileptr; + type_idx = 0; + type_len = 0; + } + + if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) { + *fileptr = '\0'; + } + + if (type_list[type_idx][type_len] != *fileptr) { + type_idx++; + while (type_list[type_idx]) { + if (!strncmp(type_list[type_idx], fileptr - type_len, type_len)) { + break; + } else { + type_idx++; + } + } + + if (!type_list[type_idx]) { + state = ERROR; + ErrPrint("type is not valid (%s)\n", fileptr - type_len); + continue; + } + } + + if (!*fileptr) { + block->type = type_idx; + state = DONE; + ptr = NULL; + } + + type_len++; + break; + case FIELD_PART: + if (ptr == NULL) { + ptr = fileptr; + } + + if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) { + *fileptr = '\0'; + } + + if (!*fileptr) { + block->part = ptr; + state = DONE; + ptr = NULL; + } + break; + case FIELD_DATA: + if (ptr == NULL) { + ptr = fileptr; + } + + if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) { + *fileptr = '\0'; + } + + if (!*fileptr) { + block->data = ptr; + state = DONE; + ptr = NULL; + } + break; + case FIELD_OPTION: + if (ptr == NULL) { + ptr = fileptr; + } + + if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) { + *fileptr = '\0'; + } + + if (!*fileptr) { + block->option = ptr; + state = DONE; + ptr = NULL; + } + break; + case FIELD_ID: + if (ptr == NULL) { + ptr = fileptr; + } + + if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) { + *fileptr = '\0'; + } + + if (!*fileptr) { + block->id = ptr; + state = DONE; + ptr = NULL; + } + break; + case FIELD_TARGET: + if (ptr == NULL) { + ptr = fileptr; + } + + if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) { + *fileptr = '\0'; + } + + if (!*fileptr) { + block->target = ptr; + state = DONE; + ptr = NULL; + } + break; + case FIELD_FILE: + if (ptr == NULL) { + ptr = fileptr; + } + + if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) { + *fileptr = '\0'; + } + + if (!*fileptr) { + block->target = ptr; + state = DONE; + ptr = NULL; + } + default: + break; + } + + break; + case DONE: + if (isspace(*fileptr)) { + } else if (*fileptr == '}') { + state = BEGIN; + block->filename = filename; + block_list = dlist_append(block_list, block); + block = NULL; + } else { + state = FIELD; + continue; + } + break; + case END: + default: + break; + } + + fileptr++; + } + + if (state != BEGIN) { + struct dlist *l; + struct dlist *n; + ErrPrint("State %d\n", state); + + free(filebuf); + free(block); + + dlist_foreach_safe(block_list, l, n, block) { + free(block); + block_list = dlist_remove(block_list, l); + } + + return WIDGET_ERROR_FAULT; + } + + + block = dlist_data(dlist_prev(block_list)); + if (block) { + block->filebuf = filebuf; + } else { + ErrPrint("Last block is not exists (There is no parsed block)\n"); + free(filebuf); + } + + ErrPrint("Begin: Set content for object\n"); + dlist_foreach(common->widget_list, l, handler) { + update_begin(handler, is_gbar); + } + + dlist_foreach_safe(block_list, l, n, block) { + dlist_foreach(common->widget_list, handle_iterator, handler) { + consuming_parsed_block(handler, is_gbar, block); + } + + block_list = dlist_remove(block_list, l); + delete_block(block); + } + + dlist_foreach(common->widget_list, l, handler) { + update_end(handler, is_gbar); + } + ErrPrint("End: Set content for object\n"); + + return WIDGET_ERROR_NONE; +} + +/* End of a file */ diff --git a/widget_viewer/src/dlist.c b/widget_viewer/src/dlist.c new file mode 100644 index 0000000..3ae571b --- /dev/null +++ b/widget_viewer/src/dlist.c @@ -0,0 +1,189 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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 "dlist.h" + +/*! + * \brief + * This dlist is called Modified Doubly Linked List. + * + * Noramlly, The dobule linked list contains address of previous and next element. + * This dlist also contains them, but the tail element only contains prev address. + * + * The head element's prev pointer indicates the last element. + * But the last element's next pointer indicates NIL. + * + * So we can find the last element while crawling this DList + * But we have to remember the address of the head element. + */ + +struct dlist { + struct dlist *next; + struct dlist *prev; + void *data; +}; + +struct dlist *dlist_append(struct dlist *list, void *data) +{ + struct dlist *item; + + item = malloc(sizeof(*item)); + if (!item) { + return NULL; + } + + item->next = NULL; + item->data = data; + + if (!list) { + item->prev = item; + + list = item; + } else { + item->prev = list->prev; + item->prev->next = item; + list->prev = item; + } + + assert(!list->prev->next && "item NEXT"); + + return list; +} + +struct dlist *dlist_prepend(struct dlist *list, void *data) +{ + struct dlist *item; + + item = malloc(sizeof(*item)); + if (!item) { + return NULL; + } + + item->data = data; + + if (!list) { + item->prev = item; + item->next = NULL; + } else { + if (list->prev->next) { + list->prev->next = item; + } + + item->prev = list->prev; + item->next = list; + + list->prev = item; + + } + + return item; +} + +struct dlist *dlist_remove(struct dlist *list, struct dlist *l) +{ + if (!list || !l) { + return NULL; + } + + if (l == list) { + list = l->next; + } else { + l->prev->next = l->next; + } + + if (l->next) { + l->next->prev = l->prev; + } + /*! + * \note + * If the removed entry 'l' has no next element, it is the last element. + * In this case, check the existence of the list first, + * and if the list is not empty, update the 'prev' of the list (which is a head element of the list) + * + * If we didn't care about this, the head element(list) can indicates the invalid element. + */ + else if (list) { + list->prev = l->prev; + } + + free(l); + return list; +} + +struct dlist *dlist_find_data(struct dlist *list, void *data) +{ + struct dlist *l; + void *_data; + + dlist_foreach(list, l, _data) { + if (data == _data) { + return l; + } + } + + return NULL; +} + +void *dlist_data(struct dlist *l) +{ + return l ? l->data : NULL; +} + +struct dlist *dlist_next(struct dlist *l) +{ + return l ? l->next : NULL; +} + +struct dlist *dlist_prev(struct dlist *l) +{ + return l ? l->prev : NULL; +} + +int dlist_count(struct dlist *l) +{ + register int i; + struct dlist *n; + void *data; + + i = 0; + dlist_foreach(l, n, data) { + i++; + } + + return i; +} + +struct dlist *dlist_nth(struct dlist *l, int nth) +{ + register int i; + struct dlist *n; + + i = 0; + for (n = l; n; n = n->next) { + if (i == nth) { + return n; + } + i++; + } + + return NULL; +} + +/* End of a file */ diff --git a/widget_viewer/src/fb.c b/widget_viewer/src/fb.c new file mode 100755 index 0000000..05795b2 --- /dev/null +++ b/widget_viewer/src/fb.c @@ -0,0 +1,682 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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 /* For error code */ +#include /* For buffer event data */ +#include + +#include "debug.h" +#include "util.h" +#include "fb.h" + +int errno; + +static struct { + Display *disp; + int screen; + Visual *visual; + int disp_is_opened; +} s_info = { + .disp = NULL, + .disp_is_opened = 0, + .screen = -1, + .visual = NULL, +}; + +int fb_init(void *disp) +{ + s_info.disp = disp; + if (s_info.disp) { + Screen *screen; + + screen = DefaultScreenOfDisplay(s_info.disp); + + s_info.screen = DefaultScreen(s_info.disp); + s_info.visual = DefaultVisualOfScreen(screen); + } + + return WIDGET_ERROR_NONE; +} + +int fb_fini(void) +{ + if (s_info.disp_is_opened && s_info.disp) { + XCloseDisplay(s_info.disp); + } + + s_info.disp = NULL; + s_info.disp_is_opened = 0; + s_info.visual = NULL; + s_info.screen = -1; + return WIDGET_ERROR_NONE; +} + +static inline void update_fb_size(struct fb_info *info) +{ + info->bufsz = info->w * info->h * info->pixels; +} + +static int sync_for_file(struct fb_info *info, int x, int y, int w, int h) +{ + int fd; + widget_fb_t buffer; + const char *path = NULL; + + buffer = info->buffer; + + if (!buffer) { /* Ignore this sync request */ + return WIDGET_ERROR_NONE; + } + + if (buffer->state != WIDGET_FB_STATE_CREATED) { + ErrPrint("Invalid state of a FB\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (buffer->type != WIDGET_FB_TYPE_FILE) { + ErrPrint("Invalid buffer\n"); + return WIDGET_ERROR_NONE; + } + + path = util_uri_to_path(info->id); + + if (path == NULL) { + ErrPrint("Invalid parameter\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + fd = open(path, O_RDONLY); + if (fd < 0) { + ErrPrint("Failed to open a file (%s) because of (%d)\n", + util_uri_to_path(info->id), errno); + + /** + * @note + * But return ZERO, even if we couldn't get a buffer file, + * the viewer can draw empty screen. + * + * and then update it after it gots update events + */ + return WIDGET_ERROR_NONE; + } + + /** + * @note + * Could we get some advantage if we load a part of file instead of loading all of them? + */ + if (x != 0 || y != 0 || info->w != w || info->h != h) { + int iy; + register int index; + register int width; + + for (iy = y; iy < h; iy++) { + index = iy * info->w + x; + width = w * info->pixels; + + if (lseek(fd, index * info->pixels, SEEK_SET) != index * info->pixels) { + ErrPrint("lseek: %d\n", errno); + if (close(fd) < 0) { + ErrPrint("close: %d\n", errno); + } + /** + * @note + * But return ZERO, even if we couldn't get a buffer file, + * the viewer can draw empty screen. + * + * and then update it after it gots update events + */ + return WIDGET_ERROR_NONE; + } + + if (read(fd, ((unsigned int *)buffer->data) + index, width) != width) { + if (close(fd) < 0) { + ErrPrint("close: %d\n", errno); + } + /** + * @note + * But return ZERO, even if we couldn't get a buffer file, + * the viewer can draw empty screen. + * + * and then update it after it gots update events + */ + return WIDGET_ERROR_NONE; + } + } + } else { + if (read(fd, buffer->data, info->bufsz) != info->bufsz) { + ErrPrint("read: %d\n", errno); + if (close(fd) < 0) { + ErrPrint("close: %d\n", errno); + } + + /** + * @note + * But return ZERO, even if we couldn't get a buffer file, + * the viewer can draw empty screen. + * + * and then update it after it gots update events + */ + return WIDGET_ERROR_NONE; + } + } + + if (close(fd) < 0) { + ErrPrint("close: %d\n", errno); + } + return WIDGET_ERROR_NONE; +} + +static int sync_for_pixmap(struct fb_info *info, int x, int y, int w, int h) +{ + widget_fb_t buffer; + XShmSegmentInfo si; + XImage *xim; + + buffer = info->buffer; + if (!buffer) { /*!< Ignore this sync request */ + return WIDGET_ERROR_NONE; + } + + if (buffer->state != WIDGET_FB_STATE_CREATED) { + ErrPrint("Invalid state of a FB\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (buffer->type != WIDGET_FB_TYPE_PIXMAP) { + ErrPrint("Invalid buffer\n"); + return WIDGET_ERROR_NONE; + } + + if (!s_info.disp) { + s_info.disp = XOpenDisplay(NULL); + if (s_info.disp) { + Screen *screen; + + s_info.disp_is_opened = 1; + + screen = DefaultScreenOfDisplay(s_info.disp); + + s_info.screen = DefaultScreen(s_info.disp); + s_info.visual = DefaultVisualOfScreen(screen); + } else { + ErrPrint("Failed to open a display\n"); + return WIDGET_ERROR_FAULT; + } + } + + if (info->handle == 0) { + ErrPrint("Pixmap ID is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (info->bufsz == 0) { + /*! + * If the client does not acquire the buffer, + * This function will do nothing. + * It will work only if the buffer is acquired. + * To sync its contents. + */ + DbgPrint("Nothing can be sync\n"); + return WIDGET_ERROR_NONE; + } + + si.shmid = shmget(IPC_PRIVATE, info->bufsz, IPC_CREAT | 0666); + if (si.shmid < 0) { + ErrPrint("shmget: %d\n", errno); + return WIDGET_ERROR_FAULT; + } + + si.readOnly = False; + si.shmaddr = shmat(si.shmid, NULL, 0); + if (si.shmaddr == (void *)-1) { + if (shmctl(si.shmid, IPC_RMID, 0) < 0) { + ErrPrint("shmctl: %d\n", errno); + } + + return WIDGET_ERROR_FAULT; + } + + /*! + * \NOTE + * Use the 24 bits Pixmap for Video player + */ + xim = XShmCreateImage(s_info.disp, s_info.visual, + (info->pixels << 3), ZPixmap, NULL, + &si, + info->w, info->h); + if (xim == NULL) { + if (shmdt(si.shmaddr) < 0) { + ErrPrint("shmdt: %d\n", errno); + } + + if (shmctl(si.shmid, IPC_RMID, 0) < 0) { + ErrPrint("shmctl: %d\n", errno); + } + + return WIDGET_ERROR_FAULT; + } + + xim->data = si.shmaddr; + XShmAttach(s_info.disp, &si); + + XShmGetImage(s_info.disp, info->handle, xim, 0, 0, 0xFFFFFFFF); + XSync(s_info.disp, False); + + if (x != 0 || y != 0 || info->w != w || info->h != h) { + int ix; + int iy; + register int index; + + for (iy = y; iy < h; iy++) { + for (ix = x; ix < w; ix++) { + index = iy * info->w + x; + *(((unsigned int *)buffer->data) + index) = *(((unsigned int *)xim->data) + index); + } + } + } else { + memcpy(buffer->data, xim->data, info->bufsz); + } + + XShmDetach(s_info.disp, &si); + XDestroyImage(xim); + + if (shmdt(si.shmaddr) < 0) { + ErrPrint("shmdt: %d\n", errno); + } + + if (shmctl(si.shmid, IPC_RMID, 0) < 0) { + ErrPrint("shmctl: %d\n", errno); + } + + return WIDGET_ERROR_NONE; +} + +int fb_sync(struct fb_info *info, int x, int y, int w, int h) +{ + if (!info) { + ErrPrint("FB Handle is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!info->id || info->id[0] == '\0') { + DbgPrint("Ingore sync\n"); + return WIDGET_ERROR_NONE; + } + + if (!strncasecmp(info->id, SCHEMA_FILE, strlen(SCHEMA_FILE))) { + return sync_for_file(info, x, y, w, h); + } else if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP))) { + return sync_for_pixmap(info, x, y, w, h); + } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM))) { + /* No need to do sync */ + return WIDGET_ERROR_NONE; + } + + return WIDGET_ERROR_INVALID_PARAMETER; +} + +struct fb_info *fb_create(const char *id, int w, int h) +{ + struct fb_info *info; + + if (!id || id[0] == '\0') { + ErrPrint("Invalid ID\n"); + return NULL; + } + + info = calloc(1, sizeof(*info)); + if (!info) { + ErrPrint("Heap: %d\n", errno); + return NULL; + } + + info->id = strdup(id); + if (!info->id) { + ErrPrint("Heap: %d\n", errno); + free(info); + return NULL; + } + + info->pixels = sizeof(int); /* Use the default pixels(depth) */ + + if (sscanf(info->id, SCHEMA_SHM "%d", &info->handle) == 1) { + DbgPrint("SHMID: %d is gotten\n", info->handle); + } else if (sscanf(info->id, SCHEMA_PIXMAP "%d:%d", &info->handle, &info->pixels) == 2) { + DbgPrint("PIXMAP-SHMID: %d is gotten (%d)\n", info->handle, info->pixels); + } else { + info->handle = WIDGET_ERROR_INVALID_PARAMETER; + } + + info->bufsz = 0; + info->buffer = NULL; + info->w = w; + info->h = h; + + return info; +} + +int fb_destroy(struct fb_info *info) +{ + if (!info) { + ErrPrint("Handle is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (info->buffer) { + widget_fb_t buffer; + buffer = info->buffer; + + buffer->info = NULL; + } + + free(info->id); + free(info); + return WIDGET_ERROR_NONE; +} + +int fb_is_created(struct fb_info *info) +{ + if (!info) { + ErrPrint("Handle is not valid\n"); + return 0; + } + + if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP)) && info->handle != 0) { + return 1; + } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM)) && info->handle > 0) { + return 1; + } else { + const char *path; + path = util_uri_to_path(info->id); + if (path && access(path, F_OK | R_OK) == 0) { + return 1; + } else { + ErrPrint("access: %d (%s)\n", errno, path); + } + } + + return 0; +} + +void *fb_acquire_buffer(struct fb_info *info) +{ + widget_fb_t buffer; + + if (!info) { + ErrPrint("info == NIL\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + if (!info->buffer) { + if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP))) { + update_fb_size(info); + + buffer = calloc(1, sizeof(*buffer) + info->bufsz); + if (!buffer) { + ErrPrint("Heap: %d\n", errno); + set_last_result(WIDGET_ERROR_OUT_OF_MEMORY); + info->bufsz = 0; + return NULL; + } + + buffer->type = WIDGET_FB_TYPE_PIXMAP; + buffer->refcnt = 0; + buffer->state = WIDGET_FB_STATE_CREATED; + buffer->info = info; + info->buffer = buffer; + + /*! + * \note + * Just update from here. + */ + sync_for_pixmap(info, 0, 0, info->w, info->h); + } else if (!strncasecmp(info->id, SCHEMA_FILE, strlen(SCHEMA_FILE))) { + update_fb_size(info); + + buffer = calloc(1, sizeof(*buffer) + info->bufsz); + if (!buffer) { + ErrPrint("Heap: %d\n", errno); + info->bufsz = 0; + set_last_result(WIDGET_ERROR_OUT_OF_MEMORY); + return NULL; + } + + buffer->type = WIDGET_FB_TYPE_FILE; + buffer->refcnt = 0; + buffer->state = WIDGET_FB_STATE_CREATED; + buffer->info = info; + info->buffer = buffer; + + sync_for_file(info, 0, 0, info->w, info->h); + } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM))) { + buffer = shmat(info->handle, NULL, 0); + if (buffer == (void *)-1) { + ErrPrint("shmat: %d (%d)\n", errno, info->handle); + set_last_result(WIDGET_ERROR_FAULT); + return NULL; + } + + return buffer->data; + } else { + ErrPrint("Buffer is not created (%s)\n", info->id); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + } + + buffer = info->buffer; + + switch (buffer->type) { + case WIDGET_FB_TYPE_PIXMAP: + buffer->refcnt++; + break; + case WIDGET_FB_TYPE_FILE: + buffer->refcnt++; + break; + default: + DbgPrint("Unknwon FP: %d\n", buffer->type); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + break; + } + + return buffer->data; +} + +int fb_release_buffer(void *data) +{ + widget_fb_t buffer; + + if (!data) { + ErrPrint("buffer data == NIL\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + buffer = container_of(data, struct widget_fb, data); + + if (buffer->state != WIDGET_FB_STATE_CREATED) { + ErrPrint("Invalid handle\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + switch (buffer->type) { + case WIDGET_FB_TYPE_SHM: + if (shmdt(buffer) < 0) { + ErrPrint("shmdt: %d\n", errno); + } + break; + case WIDGET_FB_TYPE_PIXMAP: + buffer->refcnt--; + if (buffer->refcnt == 0) { + struct fb_info *info; + info = buffer->info; + + buffer->state = WIDGET_FB_STATE_DESTROYED; + + if (info && info->buffer == buffer) { + info->buffer = NULL; + } + free(buffer); + } + break; + case WIDGET_FB_TYPE_FILE: + buffer->refcnt--; + if (buffer->refcnt == 0) { + struct fb_info *info; + info = buffer->info; + + buffer->state = WIDGET_FB_STATE_DESTROYED; + + if (info && info->buffer == buffer) { + info->buffer = NULL; + } + + free(buffer); + } + break; + default: + ErrPrint("Unknwon buffer type\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + break; + } + + return WIDGET_ERROR_NONE; +} + +int fb_refcnt(void *data) +{ + widget_fb_t buffer; + struct shmid_ds buf; + int ret; + + if (!data) { + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + buffer = container_of(data, struct widget_fb, data); + + if (buffer->state != WIDGET_FB_STATE_CREATED) { + ErrPrint("Invalid handle\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + switch (buffer->type) { + case WIDGET_FB_TYPE_SHM: + if (shmctl(buffer->refcnt, IPC_STAT, &buf) < 0) { + ErrPrint("Error: %d\n", errno); + set_last_result(WIDGET_ERROR_FAULT); + return WIDGET_ERROR_FAULT; + } + + ret = buf.shm_nattch; + break; + case WIDGET_FB_TYPE_PIXMAP: + ret = buffer->refcnt; + break; + case WIDGET_FB_TYPE_FILE: + ret = buffer->refcnt; + break; + default: + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + ret = WIDGET_ERROR_INVALID_PARAMETER; + break; + } + + return ret; +} + +const char *fb_id(struct fb_info *info) +{ + return info ? info->id : NULL; +} + +int fb_get_size(struct fb_info *info, int *w, int *h) +{ + if (!info) { + ErrPrint("Handle is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + *w = info->w; + *h = info->h; + return WIDGET_ERROR_NONE; +} + +int fb_size(struct fb_info *info) +{ + if (!info) { + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return 0; + } + + update_fb_size(info); + + return info->bufsz; +} + +int fb_type(struct fb_info *info) +{ + widget_fb_t buffer; + + if (!info) { + return WIDGET_FB_TYPE_ERROR; + } + + buffer = info->buffer; + if (!buffer) { + int type = WIDGET_FB_TYPE_ERROR; + /*! + * \note + * Try to get this from SCHEMA + */ + if (info->id) { + if (!strncasecmp(info->id, SCHEMA_FILE, strlen(SCHEMA_FILE))) { + type = WIDGET_FB_TYPE_FILE; + } else if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP))) { + type = WIDGET_FB_TYPE_PIXMAP; + } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM))) { + type = WIDGET_FB_TYPE_SHM; + } + } + + return type; + } + + return buffer->type; +} +/* End of a file */ diff --git a/widget_viewer/src/fb_wayland.c b/widget_viewer/src/fb_wayland.c new file mode 100755 index 0000000..d69d17c --- /dev/null +++ b/widget_viewer/src/fb_wayland.c @@ -0,0 +1,485 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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 /* For error code */ +#include +#include + +#include "debug.h" +#include "util.h" +#include "fb.h" + +int errno; + +static struct { +} s_info = { +}; + +int fb_init(void *disp) +{ + return WIDGET_ERROR_NONE; +} + +int fb_fini(void) +{ + return WIDGET_ERROR_NONE; +} + +static inline void update_fb_size(struct fb_info *info) +{ + info->bufsz = info->w * info->h * info->pixels; +} + +static inline int sync_for_file(struct fb_info *info, int x, int y, int w, int h) +{ + int fd; + widget_fb_t buffer; + + buffer = info->buffer; + + if (!buffer) { /* Ignore this sync request */ + return WIDGET_ERROR_NONE; + } + + if (buffer->state != WIDGET_FB_STATE_CREATED) { + ErrPrint("Invalid state of a FB\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (buffer->type != WIDGET_FB_TYPE_FILE) { + ErrPrint("Invalid buffer\n"); + return WIDGET_ERROR_NONE; + } + + fd = open(util_uri_to_path(info->id), O_RDONLY); + if (fd < 0) { + ErrPrint("Failed to open a file (%s) because of (%d)\n", + util_uri_to_path(info->id), errno); + + /*! + * \note + * But return ZERO, even if we couldn't get a buffer file, + * the viewer can draw empty screen. + * + * and then update it after it gots update events + */ + return WIDGET_ERROR_NONE; + } + + if (x != 0 || y != 0 || info->w != w || info->h != h) { + int iy; + register int index; + register int width; + + for (iy = y; iy < h; iy++) { + index = iy * info->w + x; + width = w * info->pixels; + + if (lseek(fd, index * info->pixels, SEEK_SET) != index * info->pixels) { + ErrPrint("lseek: %d\n", errno); + if (close(fd) < 0) { + ErrPrint("close: %d\n", errno); + } + /** + * @note + * But return ZERO, even if we couldn't get a buffer file, + * the viewer can draw empty screen. + * + * and then update it after it gots update events + */ + return WIDGET_ERROR_NONE; + } + + if (read(fd, ((unsigned int *)buffer->data) + index, width) != width) { + if (close(fd) < 0) { + ErrPrint("close: %d\n", errno); + } + /** + * @note + * But return ZERO, even if we couldn't get a buffer file, + * the viewer can draw empty screen. + * + * and then update it after it gots update events + */ + return WIDGET_ERROR_NONE; + } + } + } else { + if (read(fd, buffer->data, info->bufsz) != info->bufsz) { + ErrPrint("read: %d\n", errno); + if (close(fd) < 0) { + ErrPrint("close: %d\n", errno); + } + + /*! + * \note + * But return ZERO, even if we couldn't get a buffer file, + * the viewer can draw empty screen. + * + * and then update it after it gots update events + */ + return WIDGET_ERROR_NONE; + } + } + + if (close(fd) < 0) { + ErrPrint("close: %d\n", errno); + } + return WIDGET_ERROR_NONE; +} + +int fb_sync(struct fb_info *info, int x, int y, int w, int h) +{ + if (!info) { + ErrPrint("FB Handle is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!info->id || info->id[0] == '\0') { + DbgPrint("Ingore sync\n"); + return WIDGET_ERROR_NONE; + } + + if (!strncasecmp(info->id, SCHEMA_FILE, strlen(SCHEMA_FILE))) { + return sync_for_file(info, x, y, w, h); + } else if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP))) { + /** + * @note + */ + } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM))) { + /* No need to do sync */ + return WIDGET_ERROR_NONE; + } + + return WIDGET_ERROR_INVALID_PARAMETER; +} + +struct fb_info *fb_create(const char *id, int w, int h) +{ + struct fb_info *info; + + if (!id || id[0] == '\0') { + ErrPrint("Invalid ID\n"); + return NULL; + } + + info = calloc(1, sizeof(*info)); + if (!info) { + ErrPrint("Heap: %d\n", errno); + return NULL; + } + + info->id = strdup(id); + if (!info->id) { + ErrPrint("Heap: %d\n", errno); + free(info); + return NULL; + } + + info->pixels = sizeof(int); /* Use the default pixels(depth) */ + + if (sscanf(info->id, SCHEMA_SHM "%d", &info->handle) == 1) { + DbgPrint("SHMID: %d is gotten\n", info->handle); + } else if (sscanf(info->id, SCHEMA_PIXMAP "%d:%d", &info->handle, &info->pixels) == 2) { + DbgPrint("PIXMAP-SHMID: %d is gotten (%d)\n", info->handle, info->pixels); + ErrPrint("Unsupported\n"); + free(info); + return NULL; + } else { + info->handle = WIDGET_ERROR_INVALID_PARAMETER; + } + + info->bufsz = 0; + info->buffer = NULL; + info->w = w; + info->h = h; + + return info; +} + +int fb_destroy(struct fb_info *info) +{ + if (!info) { + ErrPrint("Handle is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (info->buffer) { + widget_fb_t buffer; + buffer = info->buffer; + + buffer->info = NULL; + } + + free(info->id); + free(info); + return WIDGET_ERROR_NONE; +} + +int fb_is_created(struct fb_info *info) +{ + if (!info) { + ErrPrint("Handle is not valid\n"); + return 0; + } + + if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP)) && info->handle != 0) { + return 1; + } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM)) && info->handle > 0) { + return 1; + } else { + const char *path; + path = util_uri_to_path(info->id); + if (path && access(path, F_OK | R_OK) == 0) { + return 1; + } else { + ErrPrint("access: %d (%s)\n", errno, path); + } + } + + return 0; +} + +void *fb_acquire_buffer(struct fb_info *info) +{ + widget_fb_t buffer; + + if (!info) { + ErrPrint("info == NIL\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + if (!info->buffer) { + if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP))) { + ErrPrint("Unsupported Type\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } else if (!strncasecmp(info->id, SCHEMA_FILE, strlen(SCHEMA_FILE))) { + update_fb_size(info); + + buffer = calloc(1, sizeof(*buffer) + info->bufsz); + if (!buffer) { + ErrPrint("Heap: %d\n", errno); + info->bufsz = 0; + set_last_result(WIDGET_ERROR_OUT_OF_MEMORY); + return NULL; + } + + buffer->type = WIDGET_FB_TYPE_FILE; + buffer->refcnt = 0; + buffer->state = WIDGET_FB_STATE_CREATED; + buffer->info = info; + info->buffer = buffer; + + sync_for_file(info, 0, 0, info->w, info->h); + } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM))) { + buffer = shmat(info->handle, NULL, 0); + if (buffer == (void *)-1) { + ErrPrint("shmat: %d (%d)\n", errno, info->handle); + set_last_result(WIDGET_ERROR_FAULT); + return NULL; + } + + return buffer->data; + } else { + ErrPrint("Buffer is not created (%s)\n", info->id); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + } + + buffer = info->buffer; + + switch (buffer->type) { + case WIDGET_FB_TYPE_FILE: + buffer->refcnt++; + break; + case WIDGET_BUFFER_TYPE_PIXMAP: + default: + DbgPrint("Unknwon FP: %d\n", buffer->type); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + break; + } + + return buffer->data; +} + +int fb_release_buffer(void *data) +{ + widget_fb_t buffer; + + if (!data) { + ErrPrint("buffer data == NIL\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + buffer = container_of(data, struct widget_fb, data); + + if (buffer->state != WIDGET_FB_STATE_CREATED) { + ErrPrint("Invalid handle\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + switch (buffer->type) { + case WIDGET_BUFFER_TYPE_SHM: + if (shmdt(buffer) < 0) { + ErrPrint("shmdt: %d\n", errno); + } + break; + case WIDGET_BUFFER_TYPE_FILE: + buffer->refcnt--; + if (buffer->refcnt == 0) { + struct fb_info *info; + info = buffer->info; + + buffer->state = WIDGET_FB_STATE_DESTROYED; + + if (info && info->buffer == buffer) { + info->buffer = NULL; + } + + free(buffer); + } + break; + case WIDGET_BUFFER_TYPE_PIXMAP: + default: + ErrPrint("Unknwon buffer type\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + break; + } + + return WIDGET_ERROR_NONE; +} + +int fb_refcnt(void *data) +{ + widget_fb_t buffer; + struct shmid_ds buf; + int ret; + + if (!data) { + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + buffer = container_of(data, struct buffer, data); + + if (buffer->state != WIDGET_FB_STATE_CREATED) { + ErrPrint("Invalid handle\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + switch (buffer->type) { + case WIDGET_FB_TYPE_SHM: + if (shmctl(buffer->refcnt, IPC_STAT, &buf) < 0) { + ErrPrint("Error: %d\n", errno); + set_last_result(WIDGET_ERROR_FAULT); + return WIDGET_ERROR_FAULT; + } + + ret = buf.shm_nattch; + break; + case WIDGET_FB_TYPE_FILE: + ret = buffer->refcnt; + break; + case WIDGET_BUFFER_TYPE_PIXMAP: + default: + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + ret = WIDGET_ERROR_INVALID_PARAMETER; + break; + } + + return ret; +} + +const char *fb_id(struct fb_info *info) +{ + return info ? info->id : NULL; +} + +int fb_get_size(struct fb_info *info, int *w, int *h) +{ + if (!info) { + ErrPrint("Handle is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + *w = info->w; + *h = info->h; + return WIDGET_ERROR_NONE; +} + +int fb_size(struct fb_info *info) +{ + if (!info) { + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return 0; + } + + update_fb_size(info); + + return info->bufsz; +} + +int fb_type(struct fb_info *info) +{ + widget_fb_t buffer; + + if (!info) { + return WIDGET_BUFFER_TYPE_ERROR; + } + + buffer = info->buffer; + if (!buffer) { + int type = WIDGET_FB_TYPE_ERROR; + /*! + * \note + * Try to get this from SCHEMA + */ + if (info->id) { + if (!strncasecmp(info->id, SCHEMA_FILE, strlen(SCHEMA_FILE))) { + type = WIDGET_BUFFER_TYPE_FILE; + } else if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP))) { + /* Unsupported type */ + } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM))) { + type = WIDGET_BUFFER_TYPE_SHM; + } + } + + return type; + } + + return buffer->type; +} +/* End of a file */ diff --git a/widget_viewer/src/file_service.c b/widget_viewer/src/file_service.c new file mode 100755 index 0000000..36395c3 --- /dev/null +++ b/widget_viewer/src/file_service.c @@ -0,0 +1,715 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "client.h" +#include "debug.h" +#include "dlist.h" + +#define FILE_SERVICE_PORT 8209 + +#define CRITICAL_SECTION_BEGIN(handle) \ + do { \ + int ret; \ + ret = pthread_mutex_lock(handle); \ + if (ret != 0) { \ + ErrPrint("Failed to lock: %s\n", strerror(ret)); \ + } \ + } while (0) + +#define CRITICAL_SECTION_END(handle) \ + do { \ + int ret; \ + ret = pthread_mutex_unlock(handle); \ + if (ret != 0) { \ + ErrPrint("Failed to unlock: %s\n", strerror(ret)); \ + } \ + } while (0) + +#define CANCEL_SECTION_BEGIN() do { \ + int ret; \ + ret = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); \ + if (ret != 0) { \ + ErrPrint("Unable to set cancelate state: %s\n", strerror(ret)); \ + } \ +} while (0) + +#define CANCEL_SECTION_END() do { \ + int ret; \ + ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); \ + if (ret != 0) { \ + ErrPrint("Unable to set cancelate state: %s\n", strerror(ret)); \ + } \ +} while (0) + +#define CLOSE_PIPE(p) do { \ + int status; \ + status = close(p[PIPE_READ]); \ + if (status < 0) { \ + ErrPrint("close: %d\n", errno); \ + } \ + status = close(p[PIPE_WRITE]); \ + if (status < 0) { \ + ErrPrint("close: %d\n", errno); \ + } \ +} while (0) + +#define PIPE_READ 0 +#define PIPE_WRITE 1 +#define PIPE_MAX 2 + +#define EVT_END_CH 'c' +#define EVT_CH 'e' + +static struct { + pthread_t file_svc_thid; + pthread_mutex_t file_svc_lock; + int ctrl_pipe[PIPE_MAX]; + int evt_pipe[PIPE_MAX]; + struct dlist *request_list; + int file_service_fd; +} s_info = { + .ctrl_pipe = { -1, -1 }, + .evt_pipe = { -1, -1 }, + .request_list = NULL, + .file_service_fd = -1, +}; + +struct request_item { + char *filename; + char *save_to; + void (*result_cb)(const char *filename, const char *save_to, int ret, void *data); + void *data; + int ret; +}; + +/*! + * File transfer header. + * This must should be shared with client. + */ +struct burst_head { + off_t size; + int flen; + char fname[]; +}; + +struct burst_data { + int size; + char data[]; +}; + +static inline int put_event_ch(int fd, char ch) +{ + int ret; + + ret = write(fd, &ch, sizeof(ch)); + if (ret != sizeof(ch)) { + ErrPrint("write: %d\n", errno); + return ret; + } + + return 0; +} + +static inline int get_event_ch(int fd) +{ + int ret; + char ch; + + ret = read(fd, &ch, sizeof(ch)); + if (ret != sizeof(ch)) { + ErrPrint("read: %d\n", errno); + return ret; + } + + ret = (int)((unsigned int)ch); + return ret; +} + +static inline int file_service_close(int fd) +{ + return secure_socket_destroy_handle(fd); +} + +static inline int file_service_open(void) +{ + char *addr; + int port; + char *file_addr; + int len; + int fd; + + addr = malloc(strlen(client_addr()) + 1); + if (!addr) { + ErrPrint("Heap: %d\n", errno); + return -ENOMEM; + } + + if (sscanf(client_addr(), COM_CORE_REMOTE_SCHEME"%[^:]:%d", addr, &port) != 2) { + ErrPrint("Invalid URL\n"); + free(addr); + return -EINVAL; + } + + len = strlen(COM_CORE_REMOTE_SCHEME); + len+= strlen(addr); + len+= 6; /* Port length? */ + + file_addr = malloc(len); + if (!file_addr) { + ErrPrint("Heap: %d\n", errno); + free(addr); + return -ENOMEM; + } + + snprintf(file_addr, len, COM_CORE_REMOTE_SCHEME"%s:%d", addr, FILE_SERVICE_PORT); + DbgPrint("File service: %s\n", file_addr); + fd = secure_socket_create_client(file_addr); + free(file_addr); + free(addr); + + return fd; +} + +/*! + * Service Thread + */ +static void write_item_to_pipe(struct request_item *item, int ret) +{ + item->ret = WIDGET_ERROR_FAULT; + if (write(s_info.evt_pipe[PIPE_WRITE], &item, sizeof(item)) != sizeof(item)) { + ErrPrint("write: %d\n", errno); + free(item->filename); + free(item->save_to); + free(item); + item = NULL; + } +} + +/*! + * Service Thread + */ +static void *file_service_main(void *data) +{ + int ret = 0; + int select_fd; + struct timeval tv; + fd_set set; + int offset; + enum { + RECV_INIT, + RECV_HEADER, + RECV_DATA, + } recv_state; + struct burst_head *head; + struct burst_data *body; + int recvsz; + struct request_item *item; + int file_offset; + int file_fd; + + head = NULL; + item = NULL; + recv_state = RECV_INIT; + select_fd = (s_info.file_service_fd > s_info.ctrl_pipe[PIPE_READ] ? s_info.file_service_fd : s_info.ctrl_pipe[PIPE_READ]) + 1; + while (ret == 0) { + FD_ZERO(&set); + FD_SET(s_info.file_service_fd, &set); + FD_SET(s_info.ctrl_pipe[PIPE_READ], &set); + + tv.tv_sec = 3; + tv.tv_usec = 0; + ret = select(select_fd , &set, NULL, NULL, &tv); + if (ret < 0) { + ret = -errno; + if (errno == EINTR) { + ErrPrint("INTERRUPTED\n"); + ret = 0; + continue; + } + ErrPrint("Error: %d\n", errno); + break; + } else if (ret == 0) { + ErrPrint("Timeout\n"); + ret = -ETIMEDOUT; + break; + } + + if (item && FD_ISSET(s_info.file_service_fd, &set)) { + switch (recv_state) { + case RECV_INIT: + if (head == NULL) { + recvsz = sizeof(*head); + + head = malloc(recvsz); + if (!head) { + ErrPrint("Heap: %d\n", errno); + ret = WIDGET_ERROR_OUT_OF_MEMORY; + write_item_to_pipe(item, ret); + item = NULL; + break; + } + + offset = 0; + recv_state = RECV_HEADER; + } + case RECV_HEADER: + if (offset < recvsz) { + ret = secure_socket_recv(s_info.file_service_fd, (char *)head + offset, recvsz - offset, NULL); + if (ret > 0) { + offset += ret; + } else { + free(head); + head = NULL; + recv_state = RECV_INIT; + ret = WIDGET_ERROR_FAULT; + write_item_to_pipe(item, ret); + item = NULL; + break; + } + } + + if (offset == sizeof(*head)) { + void *tmp; + + recvsz += head->flen; + + tmp = realloc(head, recvsz); + if (!tmp) { + ErrPrint("Heap: %d\n", errno); + + free(head); + head = NULL; + recv_state = RECV_INIT; + + ret = WIDGET_ERROR_OUT_OF_MEMORY; + write_item_to_pipe(item, ret); + item = NULL; + break; + } + + head = tmp; + } else if (offset == recvsz) { + DbgPrint("Filesize: %d, name[%s]\n", head->size, head->fname); + if (strcmp(item->filename, head->fname)) { + ErrPrint("Invalid data sequence (%s <> %s)\n", item->filename, head->fname); + + free(head); + head = NULL; + recv_state = RECV_INIT; + ret = WIDGET_ERROR_FAULT; + write_item_to_pipe(item, ret); + item = NULL; + break; + } + + file_fd = open(item->save_to, O_WRONLY|O_CREAT, 0644); + if (file_fd < 0) { + ErrPrint("open: %d\n", errno); + free(head); + head = NULL; + recv_state = RECV_INIT; + + ret = WIDGET_ERROR_IO_ERROR; + write_item_to_pipe(item, ret); + item = NULL; + break; + } + + recv_state = RECV_DATA; + body = NULL; + + } else { + ErrPrint("Invalid state\n"); + free(head); + head = NULL; + recv_state = RECV_INIT; + ret = WIDGET_ERROR_INVALID_PARAMETER; + write_item_to_pipe(item, ret); + item = NULL; + } + break; + case RECV_DATA: + if (!body) { + body = malloc(sizeof(*body)); + if (!body) { + free(head); + head = NULL; + recv_state = RECV_INIT; + ret = WIDGET_ERROR_OUT_OF_MEMORY; + write_item_to_pipe(item, ret); + item = NULL; + break; + } + + recvsz = sizeof(*body); + offset = 0; + } + + ret = secure_socket_recv(s_info.file_service_fd, (char *)body + offset, recvsz - offset, NULL); + if (ret > 0) { + offset += ret; + } else { + free(head); + head = NULL; + free(body); + body = NULL; + recv_state = RECV_INIT; + ret = WIDGET_ERROR_FAULT; + write_item_to_pipe(item, ret); + item = NULL; + break; + } + + if (offset == sizeof(*body)) { + void *tmp; + + if (body->size < 0) { + ErrPrint("body->size: %d\n", body->size); + free(head); + head = NULL; + free(body); + body = NULL; + recv_state = RECV_INIT; + ret = WIDGET_ERROR_FAULT; + write_item_to_pipe(item, ret); + item = NULL; + break; + } + + recvsz += body->size; + + tmp = realloc(body, recvsz); + if (!tmp) { + ErrPrint("Heap: %d\n", errno); + free(head); + head = NULL; + + free(body); + body = NULL; + recv_state = RECV_INIT; + + ret = WIDGET_ERROR_OUT_OF_MEMORY; + write_item_to_pipe(item, ret); + item = NULL; + break; + } + } else if (offset == recvsz) { + /* Flush this to the file */ + ret = write(file_fd, body->data, body->size); + if (ret < 0) { + ErrPrint("write: %d\n", errno); + free(head); + head = NULL; + + free(body); + body = NULL; + recv_state = RECV_INIT; + + ret = WIDGET_ERROR_IO_ERROR; + write_item_to_pipe(item, ret); + item = NULL; + break; + } else { + if (body->size != ret) { + DbgPrint("Body is not flushed correctly: %d, %d\n", ret, body->size); + ret = body->size; + } + + file_offset += ret; + if (file_offset == head->size) { + if (close(file_fd) < 0) { + ErrPrint("close: %d\n", errno); + } + ret = WIDGET_ERROR_NONE; + write_item_to_pipe(item, ret); + item = NULL; + } + } + + free(body); + body = NULL; + + free(head); + head = NULL; + + recv_state = RECV_INIT; + } else { + ErrPrint("Invalid state\n"); + + ret = -EFAULT; + free(body); + body = NULL; + free(head); + head = NULL; + recv_state = RECV_INIT; + + ret = WIDGET_ERROR_FAULT; + write_item_to_pipe(item, ret); + item = NULL; + } + break; + default: + ErrPrint("Unknown event: %d\n", recv_state); + ret = WIDGET_ERROR_FAULT; + write_item_to_pipe(item, ret); + item = NULL; + break; + } + } else if (item == NULL && recv_state == RECV_INIT && FD_ISSET(s_info.ctrl_pipe[PIPE_READ], &set)) { + int ch; + struct dlist *l; + + /* Only if the recv state is not changed, we can get next request item */ + ch = get_event_ch(s_info.ctrl_pipe[PIPE_READ]); + if (ch == EVT_END_CH) { + DbgPrint("Service thread is canceled\n"); + break; + } + + CRITICAL_SECTION_BEGIN(&s_info.file_svc_lock); + l = dlist_nth(s_info.request_list, 0); + item = dlist_data(l); + s_info.request_list = dlist_remove(s_info.request_list, l); + CRITICAL_SECTION_END(&s_info.file_svc_lock); + } + } + + return (void *)ret; +} + +/* Master */ +static gboolean evt_cb(GIOChannel *src, GIOCondition cond, gpointer data) +{ + int fd; + struct request_item *item; + + fd = g_io_channel_unix_get_fd(src); + + if (!(cond & G_IO_IN)) { + DbgPrint("Client is disconencted\n"); + return FALSE; + } + + if ((cond & G_IO_ERR) || (cond & G_IO_HUP) || (cond & G_IO_NVAL)) { + DbgPrint("Client connection is lost\n"); + return FALSE; + } + + if (read(fd, &item, sizeof(item)) != sizeof(item)) { + ErrPrint("read: %d\n", errno); + } else { + if (item->result_cb) { + item->result_cb(item->filename, item->save_to, item->ret, item->data); + } + + free(item->filename); + free(item->save_to); + free(item); + } + + return TRUE; +} + +int file_service_send_request(const char *filename, const char *save_to, void (*result_cb)(const char *filename, const char *save_to, int ret, void *data), void *data) +{ + struct request_item *item; + + item = malloc(sizeof(*item)); + if (!item) { + ErrPrint("Heap: %d\n", errno); + return -ENOMEM; + } + + item->filename = strdup(filename); + if (!item->filename) { + ErrPrint("Heap: %d\n", errno); + free(item); + return -ENOMEM; + } + + item->save_to = strdup(save_to); + if (!item->save_to) { + ErrPrint("Heap: %d\n", errno); + free(item->filename); + free(item); + return -ENOMEM; + } + + item->result_cb = result_cb; + item->data = data; + + CRITICAL_SECTION_BEGIN(&s_info.file_svc_lock); + s_info.request_list = dlist_append(s_info.request_list, item); + CRITICAL_SECTION_END(&s_info.file_svc_lock); + return 0; +} + +int file_service_init(void) +{ + int status; + GIOChannel *gio; + guint id; + + if (strncmp(client_addr(), COM_CORE_REMOTE_SCHEME, strlen(COM_CORE_REMOTE_SCHEME))) { + return 0; + } + + s_info.file_service_fd = file_service_open(); + if (s_info.file_service_fd < 0) { + return -EFAULT; + } + + if (pipe2(s_info.ctrl_pipe, O_NONBLOCK | O_CLOEXEC) < 0) { + ErrPrint("file service: %d\n", errno); + file_service_close(s_info.file_service_fd); + s_info.file_service_fd = -1; + return -EFAULT; + } + + if (pipe2(s_info.evt_pipe, O_NONBLOCK | O_CLOEXEC) < 0) { + ErrPrint("file service: %d\n", errno); + CLOSE_PIPE(s_info.ctrl_pipe); + file_service_close(s_info.file_service_fd); + s_info.file_service_fd = -1; + return -EFAULT; + } + + status = pthread_mutex_init(&s_info.file_svc_lock, NULL); + if (status != 0) { + ErrPrint("Mutex: %s\n", strerror(status)); + CLOSE_PIPE(s_info.ctrl_pipe); + CLOSE_PIPE(s_info.evt_pipe); + file_service_close(s_info.file_service_fd); + s_info.file_service_fd = -1; + return -EFAULT; + } + + gio = g_io_channel_unix_new(s_info.evt_pipe[PIPE_READ]); + if (!gio) { + ErrPrint("io channel new\n"); + status = pthread_mutex_destroy(&s_info.file_svc_lock); + if (status != 0) { + ErrPrint("destroy: %s\n", strerror(status)); + } + CLOSE_PIPE(s_info.ctrl_pipe); + CLOSE_PIPE(s_info.evt_pipe); + file_service_close(s_info.file_service_fd); + s_info.file_service_fd = -1; + return -EFAULT; + } + + g_io_channel_set_close_on_unref(gio, FALSE); + + id = g_io_add_watch(gio, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, (GIOFunc)evt_cb, NULL); + if (id <= 0) { + GError *err = NULL; + ErrPrint("Failed to add IO watch\n"); + g_io_channel_shutdown(gio, TRUE, &err); + if (err) { + ErrPrint("Shutdown: %s\n", err->message); + g_error_free(err); + } + g_io_channel_unref(gio); + + status = pthread_mutex_destroy(&s_info.file_svc_lock); + if (status != 0) { + ErrPrint("destroy: %s\n", strerror(status)); + } + CLOSE_PIPE(s_info.ctrl_pipe); + CLOSE_PIPE(s_info.evt_pipe); + file_service_close(s_info.file_service_fd); + s_info.file_service_fd = -1; + return -EIO; + } + + status = pthread_create(&s_info.file_svc_thid, NULL, file_service_main, NULL); + if (status != 0) { + GError *err = NULL; + ErrPrint("Failed to add IO watch\n"); + g_io_channel_shutdown(gio, TRUE, &err); + if (err) { + ErrPrint("Shutdown: %s\n", err->message); + g_error_free(err); + } + g_io_channel_unref(gio); + + ErrPrint("file service: %s\n", strerror(status)); + CLOSE_PIPE(s_info.ctrl_pipe); + CLOSE_PIPE(s_info.evt_pipe); + file_service_close(s_info.file_service_fd); + s_info.file_service_fd = -1; + + status = pthread_mutex_destroy(&s_info.file_svc_lock); + if (status != 0) { + ErrPrint("destroy: %s\n", strerror(status)); + } + + return -EFAULT; + } + + g_io_channel_unref(gio); + return 0; +} + +int file_service_fini(void) +{ + void *svc_ret; + int ret; + + if (strncmp(client_addr(), COM_CORE_REMOTE_SCHEME, strlen(COM_CORE_REMOTE_SCHEME))) { + return 0; + } + + (void)put_event_ch(s_info.ctrl_pipe[PIPE_WRITE], EVT_END_CH); + + ret = pthread_join(s_info.file_svc_thid, &svc_ret); + if (ret != 0) { + ErrPrint("join: %s\n", strerror(ret)); + } else { + DbgPrint("file svc returns: %d\n", (int)svc_ret); + } + + ret = pthread_mutex_destroy(&s_info.file_svc_lock); + if (ret != 0) { + ErrPrint("destroy: %s\n", strerror(ret)); + } + + CLOSE_PIPE(s_info.evt_pipe); + CLOSE_PIPE(s_info.ctrl_pipe); + + return 0; +} + +/* End of a file */ diff --git a/widget_viewer/src/master_rpc.c b/widget_viewer/src/master_rpc.c new file mode 100755 index 0000000..3457ebc --- /dev/null +++ b/widget_viewer/src/master_rpc.c @@ -0,0 +1,319 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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 "debug.h" +#include "dlist.h" +#include "widget_viewer.h" +#include "widget_viewer_internal.h" +#include "master_rpc.h" +#include "client.h" +#include "util.h" + +#define DEFAULT_TTL 10 +#define REQUEST_DELAY 10 + +struct command { + int ttl; + struct packet *packet; + widget_h handler; + void (*ret_cb)(widget_h handler, const struct packet *result, void *data); + void *data; + enum { + TYPE_ACK, + TYPE_NOACK + } type; +}; + +int errno; + +static struct { + guint cmd_timer; + struct dlist *cmd_list; +} s_info = { + .cmd_timer = 0, + .cmd_list = NULL, +}; + +static int done_cb(pid_t pid, int handle, const struct packet *packet, void *data); + +static inline struct command *pop_command(void) +{ + struct dlist *l; + struct command *command; + + l = dlist_nth(s_info.cmd_list, 0); + if (!l) { + return NULL; + } + + command = dlist_data(l); + s_info.cmd_list = dlist_remove(s_info.cmd_list, l); + return command; +} + +static inline struct command *create_command(widget_h handler, struct packet *packet) +{ + struct command *command; + + command = malloc(sizeof(*command)); + if (!command) { + ErrPrint("Failed to allocate mem for command\n"); + return NULL; + } + + command->handler = _widget_ref(handler); + command->packet = packet_ref(packet); + return command; +} + +static inline void destroy_command(struct command *command) +{ + packet_unref(command->packet); + _widget_unref(command->handler, 1); + free(command); +} + +static gboolean cmd_consumer(gpointer user_data) +{ + struct command *command; + + command = pop_command(); + if (!command) { + s_info.cmd_timer = 0; + return FALSE; + } + + /*! + * \NOTE: + * Item will be deleted in the "done_cb" + * + * item->param be release by the g_dbus_proxy_call + * so to use it again from the done_cb function, + * increate the reference counter of the item->param + */ + if (command->type == TYPE_NOACK) { + if (com_core_packet_send_only(client_fd(), command->packet) < 0) { + ErrPrint("Failed to send a packet to master\n"); + } + + destroy_command(command); + } else { + if (com_core_packet_async_send(client_fd(), command->packet, 0u, done_cb, command) < 0) { + ErrPrint("Failed to send a packet to master\n"); + if (command->ret_cb) { + command->ret_cb(command->handler, NULL, command->data); + } + destroy_command(command); + } + } + return TRUE; +} + +static inline void prepend_command(struct command *command) +{ + s_info.cmd_list = dlist_prepend(s_info.cmd_list, command); + master_rpc_check_and_fire_consumer(); +} + +void master_rpc_check_and_fire_consumer(void) +{ + if (!s_info.cmd_list || s_info.cmd_timer || client_fd() < 0) { + return; + } + + s_info.cmd_timer = g_timeout_add(REQUEST_DELAY, cmd_consumer, NULL); + if (!s_info.cmd_timer) { + ErrPrint("Failed to add timer\n"); + } +} + +static int done_cb(pid_t pid, int handle, const struct packet *packet, void *data) +{ + struct command *command; + int ret; + + command = data; + + if (!packet) { + /*! \NOTE: + * Release resource even if + * we failed to finish the method call + */ + command->ttl--; + if (command->ttl > 0) { + prepend_command(command); + return 0; + } + + goto out; + } + + if (packet_get(packet, "i", &ret) != 1) { + ErrPrint("Invalid result packet\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + } + +out: + if (command->ret_cb) { + command->ret_cb(command->handler, packet, command->data); + } + + destroy_command(command); + return 0; +} + +static inline void push_command(struct command *command) +{ + s_info.cmd_list = dlist_append(s_info.cmd_list, command); + master_rpc_check_and_fire_consumer(); +} + +/*! + * \note + * "handler" could be NULL + */ +int master_rpc_async_request(widget_h handler, struct packet *packet, int urgent, void (*ret_cb)(widget_h handler, const struct packet *result, void *data), void *data) +{ + struct command *command; + + command = create_command(handler, packet); + if (!command) { + ErrPrint("Failed to create a command\n"); + packet_unref(packet); + return WIDGET_ERROR_FAULT; + } + + command->ret_cb = ret_cb; + command->data = data; + command->ttl = DEFAULT_TTL; + command->type = TYPE_ACK; + + if (urgent) { + prepend_command(command); + } else { + push_command(command); + } + + packet_unref(packet); + return WIDGET_ERROR_NONE; +} + +int master_rpc_request_only(widget_h handler, struct packet *packet) +{ + struct command *command; + + command = create_command(handler, packet); + if (!command) { + ErrPrint("Failed to create a command\n"); + packet_unref(packet); + return WIDGET_ERROR_FAULT; + } + + command->ret_cb = NULL; + command->data = NULL; + command->ttl = 0; + command->type = TYPE_NOACK; + + push_command(command); + packet_unref(packet); + return WIDGET_ERROR_NONE; +} + +int master_rpc_clear_fault_package(const char *pkgname) +{ + struct dlist *l; + struct dlist *n; + struct command *command; + + if (!pkgname) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + dlist_foreach_safe(s_info.cmd_list, l, n, command) { + if (!command->handler) { + continue; + } + + if (!strcmp(command->handler->common->pkgname, pkgname)) { + s_info.cmd_list = dlist_remove(s_info.cmd_list, l); + if (command->ret_cb) { + command->ret_cb(command->handler, NULL, command->data); + } + + destroy_command(command); + } + } + + return 0; +} + +int master_rpc_clear_all_request(void) +{ + struct command *command; + struct dlist *l; + struct dlist *n; + + dlist_foreach_safe(s_info.cmd_list, l, n, command) { + s_info.cmd_list = dlist_remove(s_info.cmd_list, l); + + if (command->ret_cb) { + command->ret_cb(command->handler, NULL, command->data); + } + + destroy_command(command); + } + + return 0; +} + +int master_rpc_sync_request(struct packet *packet) +{ + struct packet *result; + int ret; + + result = com_core_packet_oneshot_send(client_addr(), packet, 0.0f); + if (result) { + if (packet_get(result, "i", &ret) != 1) { + ErrPrint("Invalid result packet\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + } + + packet_unref(result); + } else { + ErrPrint("Failed to send a sync request\n"); + ret = WIDGET_ERROR_FAULT; + } + + packet_unref(packet); + return ret; +} + +/* End of a file */ diff --git a/widget_viewer/src/util.c b/widget_viewer/src/util.c new file mode 100755 index 0000000..5e44bbb --- /dev/null +++ b/widget_viewer/src/util.c @@ -0,0 +1,150 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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 /* For error code */ + +#include "debug.h" +#include "util.h" + +int errno; +#if defined(_USE_ECORE_TIME_GET) +static struct { + clockid_t type; +} s_info = { + .type = CLOCK_MONOTONIC, +}; +#endif + +int util_check_extension(const char *filename, const char *check_ptr) +{ + int name_len; + + name_len = strlen(filename); + while (--name_len >= 0 && *check_ptr) { + if (filename[name_len] != *check_ptr) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + check_ptr ++; + } + + return 0; +} + +double util_timestamp(void) +{ +#if defined(_USE_ECORE_TIME_GET) + struct timespec ts; + + do { + if (clock_gettime(s_info.type, &ts) == 0) { + return ts.tv_sec + ts.tv_nsec / 1000000000.0f; + } + + ErrPrint("%d: %d\n", s_info.type, errno); + if (s_info.type == CLOCK_MONOTONIC) { + s_info.type = CLOCK_REALTIME; + } else if (s_info.type == CLOCK_REALTIME) { + struct timeval tv; + if (gettimeofday(&tv, NULL) < 0) { + ErrPrint("gettimeofday: %d\n", errno); + break; + } + + return tv.tv_sec + tv.tv_usec / 1000000.0f; + } + } while (1); + + return 0.0f; +#else + struct timeval tv; + + if (gettimeofday(&tv, NULL) < 0) { + ErrPrint("gettimeofday: %d\n", errno); + tv.tv_sec = 0; + tv.tv_usec = 0; + } + + return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0f; +#endif +} + +const char *util_basename(const char *name) +{ + int length; + length = name ? strlen(name) : 0; + if (!length) { + return "."; + } + + while (--length > 0 && name[length] != '/'); + + return length <= 0 ? name : name + length + (name[length] == '/'); +} + +const char *util_uri_to_path(const char *uri) +{ + int len; + + len = strlen(SCHEMA_FILE); + if (strncasecmp(uri, SCHEMA_FILE, len)) { + return NULL; + } + + return uri + len; +} + +int util_unlink(const char *filename) +{ + char *descfile; + int desclen; + int ret; + + if (!filename) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + desclen = strlen(filename) + 6; /* .desc */ + descfile = malloc(desclen); + if (!descfile) { + ErrPrint("Heap: %d\n", errno); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + ret = snprintf(descfile, desclen, "%s.desc", filename); + if (ret < 0) { + ErrPrint("Error: %d\n", errno); + free(descfile); + return WIDGET_ERROR_FAULT; + } + + (void)unlink(descfile); + free(descfile); + (void)unlink(filename); + + return WIDGET_ERROR_NONE; +} + +/* End of a file */ diff --git a/widget_viewer/src/widget.c b/widget_viewer/src/widget.c new file mode 100755 index 0000000..58c5db7 --- /dev/null +++ b/widget_viewer/src/widget.c @@ -0,0 +1,4248 @@ +/* + * Copyright 2014 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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 /* malloc */ +#include /* strdup */ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "fb.h" +#include "widget_viewer.h" +#include "widget_viewer_internal.h" +#include "dlist.h" +#include "util.h" +#include "master_rpc.h" +#include "client.h" +#include "conf.h" + +#define EAPI __attribute__((visibility("default"))) +#if !defined(WIDGET_COUNT_OF_SIZE_TYPE) + #define WIDGET_COUNT_OF_SIZE_TYPE 13 +#endif + +#if defined(FLOG) +FILE *__file_log_fp; +#endif + +static int default_launch_handler(widget_h handle, const char *appid, void *data); + +static struct info { + int init_count; + int prevent_overwrite; + guint job_timer; + struct dlist *job_list; + + struct launch { + int (*handle)(widget_h handle, const char *appid, void *data); + void *data; + } launch; +} s_info = { + .init_count = 0, + .prevent_overwrite = 0, + .job_timer = 0, + .job_list = NULL, + .launch = { + .handle = default_launch_handler, + .data = NULL, + }, +}; + +static void widget_pixmap_acquired_cb(widget_h handle, const struct packet *result, void *data); +static void gbar_pixmap_acquired_cb(widget_h handle, const struct packet *result, void *data); +static void gbar_xpixmap_acquired_cb(widget_h handle, const struct packet *result, void *data); +static void widget_xpixmap_acquired_cb(widget_h handle, const struct packet *result, void *data); + +static int default_launch_handler(widget_h handle, const char *appid, void *data) +{ + int ret; + + ret = aul_launch_app(appid, NULL); + if (ret <= 0) { + ErrPrint("Failed to launch an app %s (%d)\n", appid, ret); + } + + /* + app_control_h service; + + DbgPrint("AUTO_LAUNCH [%s]\n", handle->common->widget.auto_launch); + + ret = app_control_create(&service); + if (ret == APP_CONTROL_ERROR_NONE) { + app_control_set_package(service, handle->common->widget.auto_launch); + app_control_send_launch_request(service, NULL, NULL); + app_control_destroy(service); + } else { + ErrPrint("Failed to launch an app %s (%d)\n", handle->common->widget.auto_launch, ret); + } + */ + + return ret > 0 ? WIDGET_ERROR_NONE : WIDGET_ERROR_FAULT; +} + +static inline void default_create_cb(widget_h handle, int ret, void *data) +{ + DbgPrint("Default created event handle: %d\n", ret); +} + +static inline void default_pinup_cb(widget_h handle, int ret, void *data) +{ + DbgPrint("Default pinup event handle: %d\n", ret); +} + +static inline void default_group_changed_cb(widget_h handle, int ret, void *data) +{ + DbgPrint("Default group changed event handle: %d\n", ret); +} + +static inline void default_period_changed_cb(widget_h handle, int ret, void *data) +{ + DbgPrint("Default period changed event handle: %d\n", ret); +} + +static inline void default_gbar_created_cb(widget_h handle, int ret, void *data) +{ + DbgPrint("Default GBAR created event handle: %d\n", ret); +} + +static inline void default_gbar_destroyed_cb(widget_h handle, int ret, void *data) +{ + DbgPrint("Default GBAR destroyed event handle: %d\n", ret); +} + +static inline void default_widget_size_changed_cb(widget_h handle, int ret, void *data) +{ + DbgPrint("Default WIDGET size changed event handle: %d\n", ret); +} + +static inline void default_update_mode_cb(widget_h handle, int ret, void *data) +{ + DbgPrint("Default update mode set event handle: %d\n", ret); +} + +static inline void default_access_event_cb(widget_h handle, int ret, void *data) +{ + DbgPrint("Default access event handle: %d\n", ret); +} + +static inline void default_key_event_cb(widget_h handle, int ret, void *data) +{ + DbgPrint("Default key event handle: %d\n", ret); +} + +static void update_mode_cb(widget_h handle, const struct packet *result, void *data) +{ + int ret; + + if (!result) { + ret = WIDGET_ERROR_FAULT; + goto errout; + } else if (packet_get(result, "i", &ret) != 1) { + ErrPrint("Invalid argument\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + goto errout; + } + + if (ret < 0) { + ErrPrint("Resize request is failed: %d\n", ret); + goto errout; + } + + return; + +errout: + handle->cbs.update_mode.cb(handle, ret, handle->cbs.update_mode.data); + handle->cbs.update_mode.cb = NULL; + handle->cbs.update_mode.data = NULL; + handle->common->request.update_mode = 0; + + if (handle->common->state != WIDGET_STATE_DELETE) { + if (ret == (int)WIDGET_ERROR_NOT_EXIST && handle->refcnt == 2) { + _widget_invoke_event_handler(handle, WIDGET_EVENT_DELETED); + _widget_unref(handle, 1); + } + } +} + +static void resize_cb(widget_h handle, const struct packet *result, void *data) +{ + int ret; + + if (!result) { + ret = WIDGET_ERROR_FAULT; + goto errout; + } else if (packet_get(result, "i", &ret) != 1) { + ErrPrint("Invalid argument\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + goto errout; + } + + /*! + * \note + * In case of resize request, + * The widget handle will not have resized value right after this callback, + * It can only get the new size when it makes updates. + * + * So the user can only get the resized value(result) from the first update event + * after this request. + */ + if (ret < 0) { + ErrPrint("Resize request is failed: %d\n", ret); + goto errout; + } + + return; + +errout: + handle->cbs.size_changed.cb(handle, ret, handle->cbs.size_changed.data); + handle->cbs.size_changed.cb = NULL; + handle->cbs.size_changed.data = NULL; + handle->common->request.size_changed = 0; + + if (handle->common->state != WIDGET_STATE_DELETE) { + if (ret == (int)WIDGET_ERROR_NOT_EXIST && handle->refcnt == 2) { + _widget_invoke_event_handler(handle, WIDGET_EVENT_DELETED); + _widget_unref(handle, 1); + } + } +} + +static void text_signal_cb(widget_h handle, const struct packet *result, void *data) +{ + int ret; + void *cbdata; + struct cb_info *info = data; + widget_ret_cb cb; + + cbdata = info->data; + cb = info->cb; + _widget_destroy_cb_info(info); + + if (!result) { + ret = WIDGET_ERROR_FAULT; + } else if (packet_get(result, "i", &ret) != 1) { + ErrPrint("Invalid argument\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + } + + if (cb) { + cb(handle, ret, cbdata); + } + return; +} + +static void set_group_ret_cb(widget_h handle, const struct packet *result, void *data) +{ + int ret; + + if (!result) { + ret = WIDGET_ERROR_FAULT; + goto errout; + } else if (packet_get(result, "i", &ret) != 1) { + ErrPrint("Invalid argument\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + goto errout; + } + + if (ret < 0) { + goto errout; + } + + return; + +errout: + handle->cbs.group_changed.cb(handle, ret, handle->cbs.group_changed.data); + handle->cbs.group_changed.cb = NULL; + handle->cbs.group_changed.data = NULL; + handle->common->request.group_changed = 0; + + if (handle->common->state != WIDGET_STATE_DELETE) { + if (ret == (int)WIDGET_ERROR_NOT_EXIST && handle->refcnt == 2) { + _widget_invoke_event_handler(handle, WIDGET_EVENT_DELETED); + _widget_unref(handle, 1); + } + } +} + +static void period_ret_cb(widget_h handle, const struct packet *result, void *data) +{ + int ret; + + if (!result) { + ret = WIDGET_ERROR_FAULT; + goto errout; + } else if (packet_get(result, "i", &ret) != 1) { + ErrPrint("Invalid argument\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + goto errout; + } + + if (ret < 0) { + goto errout; + } + + return; + +errout: + handle->cbs.period_changed.cb(handle, ret, handle->cbs.period_changed.data); + handle->cbs.period_changed.cb = NULL; + handle->cbs.period_changed.data = NULL; + handle->common->request.period_changed = 0; + + if (handle->common->state != WIDGET_STATE_DELETE) { + if (ret == (int)WIDGET_ERROR_NOT_EXIST && handle->refcnt == 2) { + _widget_invoke_event_handler(handle, WIDGET_EVENT_DELETED); + _widget_unref(handle, 1); + } + } +} + +static void gbar_create_cb(widget_h handle, const struct packet *result, void *data) +{ + int ret; + + if (!result) { + ret = WIDGET_ERROR_FAULT; + goto errout; + } else if (packet_get(result, "i", &ret) != 1) { + ret = WIDGET_ERROR_INVALID_PARAMETER; + goto errout; + } + + if (ret < 0) { + ErrPrint("Failed to create a GBAR[%d]\n", ret); + goto errout; + } + + return; + +errout: + handle->cbs.gbar_created.cb(handle, ret, handle->cbs.gbar_created.data); + handle->cbs.gbar_created.cb = NULL; + handle->cbs.gbar_created.data = NULL; + handle->common->request.gbar_created = 0; + + if (handle->common->state != WIDGET_STATE_DELETE) { + if (ret == (int)WIDGET_ERROR_NOT_EXIST && handle->refcnt == 2) { + _widget_invoke_event_handler(handle, WIDGET_EVENT_DELETED); + _widget_unref(handle, 1); + } + } +} + +static void activated_cb(widget_h handle, const struct packet *result, void *data) +{ + int ret; + struct cb_info *info = data; + void *cbdata; + widget_ret_cb cb; + const char *pkgname = ""; + + cbdata = info->data; + cb = info->cb; + _widget_destroy_cb_info(info); + + if (!result) { + ret = WIDGET_ERROR_FAULT; + } else if (packet_get(result, "is", &ret, &pkgname) != 2) { + ret = WIDGET_ERROR_INVALID_PARAMETER; + } + + if (cb) { + cb(handle, ret, cbdata); + } +} + +static void gbar_destroy_cb(widget_h handle, const struct packet *result, void *data) +{ + int ret; + widget_ret_cb cb; + void *cbdata; + struct cb_info *info = data; + + cbdata = info->data; + cb = info->cb; + _widget_destroy_cb_info(info); + + if (!result) { + ErrPrint("Result is NIL (may connection lost)\n"); + ret = WIDGET_ERROR_FAULT; + } else if (packet_get(result, "i", &ret) != 1) { + ErrPrint("Invalid parameter\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + } + + if (ret == (int)WIDGET_ERROR_NONE) { + handle->cbs.gbar_destroyed.cb = cb; + handle->cbs.gbar_destroyed.data = cbdata; + } else { + handle->common->is_gbar_created = 0; + handle->common->request.gbar_destroyed = 0; + + if (cb) { + cb(handle, ret, cbdata); + } + } +} + +static void _delete_cluster_cb(widget_h handle, const struct packet *result, void *data) +{ + struct cb_info *info = data; + int ret; + widget_ret_cb cb; + void *cbdata; + + cb = info->cb; + cbdata = info->data; + _widget_destroy_cb_info(info); + + if (!result) { + ret = WIDGET_ERROR_FAULT; + } else if (packet_get(result, "i", &ret) != 1) { + ret = WIDGET_ERROR_INVALID_PARAMETER; + } + + if (cb) { + cb(handle, ret, cbdata); + } +} + +static void _delete_category_cb(widget_h handle, const struct packet *result, void *data) +{ + struct cb_info *info = data; + int ret; + widget_ret_cb cb; + void *cbdata; + + cb = info->cb; + cbdata = info->data; + _widget_destroy_cb_info(info); + + if (!result) { + ret = WIDGET_ERROR_FAULT; + } else if (packet_get(result, "i", &ret) != 1) { + ret = WIDGET_ERROR_INVALID_PARAMETER; + } + + if (cb) { + cb(handle, ret, cbdata); + } +} + +static int _widget_acquire_widget_pixmap(widget_h handle, widget_ret_cb cb, void *data) +{ + struct packet *packet; + struct cb_info *cbinfo; + const char *id; + unsigned int cmd = CMD_WIDGET_ACQUIRE_PIXMAP; + int ret; + + id = fb_id(handle->common->widget.fb); + if (!id || strncasecmp(id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP))) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + packet = packet_create((const char *)&cmd, "ss", handle->common->pkgname, handle->common->id); + if (!packet) { + ErrPrint("Failed to build a param\n"); + return WIDGET_ERROR_FAULT; + } + + cbinfo = _widget_create_cb_info(cb, data); + if (!cbinfo) { + packet_destroy(packet); + return WIDGET_ERROR_FAULT; + } + + ret = master_rpc_async_request(handle, packet, 0, widget_pixmap_acquired_cb, cbinfo); + if (ret < 0) { + _widget_destroy_cb_info(cbinfo); + } + + return ret; +} + +static void widget_pixmap_acquired_cb(widget_h handle, const struct packet *result, void *data) +{ + int pixmap; + int ret = WIDGET_ERROR_INVALID_PARAMETER; + widget_ret_cb cb; + void *cbdata; + struct cb_info *info = data; + + cb = info->cb; + cbdata = info->data; + _widget_destroy_cb_info(info); + + if (!result) { + pixmap = 0; /* PIXMAP 0 means error */ + } else if (packet_get(result, "ii", &pixmap, &ret) != 2) { + pixmap = 0; + } + + if (ret == (int)WIDGET_ERROR_RESOURCE_BUSY) { + ret = _widget_acquire_widget_pixmap(handle, cb, cbdata); + DbgPrint("Busy, Try again: %d\n", ret); + /* Try again */ + } else if (ret == (int)WIDGET_ERROR_NOT_EXIST && handle->refcnt == 2) { + if (cb) { + cb(handle, pixmap, cbdata); + } + + if (handle->common->state != WIDGET_STATE_DELETE) { + _widget_invoke_event_handler(handle, WIDGET_EVENT_DELETED); + _widget_unref(handle, 1); + } + } else { + if (cb) { + cb(handle, pixmap, cbdata); + } + } +} + +static void widget_xpixmap_acquired_cb(widget_h handle, const struct packet *result, void *data) +{ + int pixmap; + int ret = WIDGET_ERROR_INVALID_PARAMETER; + widget_ret_cb cb; + void *cbdata; + struct cb_info *info = data; + + cb = info->cb; + cbdata = info->data; + _widget_destroy_cb_info(info); + + if (!result) { + pixmap = 0; + } else if (packet_get(result, "ii", &pixmap, &ret) != 2) { + pixmap = 0; + } + + if (cb) { + cb(handle, pixmap, cbdata); + } + + if (handle->common->state != WIDGET_STATE_DELETE) { + if (ret == (int)WIDGET_ERROR_NOT_EXIST && handle->refcnt == 2) { + _widget_invoke_event_handler(handle, WIDGET_EVENT_DELETED); + _widget_unref(handle, 1); + } + } +} + +static int widget_acquire_gbar_extra_pixmap(widget_h handle, int idx, widget_ret_cb cb, void *data) +{ + struct packet *packet; + struct cb_info *cbinfo; + unsigned int cmd = CMD_GBAR_ACQUIRE_XPIXMAP; + int ret; + + packet = packet_create((const char *)&cmd, "ssi", handle->common->pkgname, handle->common->id, idx); + if (!packet) { + ErrPrint("Failed to build a param\n"); + return WIDGET_ERROR_FAULT; + } + + cbinfo = _widget_create_cb_info(cb, data); + if (!cbinfo) { + packet_destroy(packet); + return WIDGET_ERROR_FAULT; + } + + ret = master_rpc_async_request(handle, packet, 0, gbar_xpixmap_acquired_cb, cbinfo); + if (ret < 0) { + /*! + * \note + * Packet will be destroyed by master_rpc_async_request + */ + _widget_destroy_cb_info(cbinfo); + } + + return ret; +} + +static int widget_acquire_widget_extra_pixmap(widget_h handle, int idx, widget_ret_cb cb, void *data) +{ + struct packet *packet; + struct cb_info *cbinfo; + unsigned int cmd = CMD_WIDGET_ACQUIRE_XPIXMAP; + int ret; + + packet = packet_create((const char *)&cmd, "ssi", handle->common->pkgname, handle->common->id, idx); + if (!packet) { + ErrPrint("Failed to build a param\n"); + return WIDGET_ERROR_FAULT; + } + + cbinfo = _widget_create_cb_info(cb, data); + if (!cbinfo) { + packet_destroy(packet); + return WIDGET_ERROR_FAULT; + } + + ret = master_rpc_async_request(handle, packet, 0, widget_xpixmap_acquired_cb, cbinfo); + if (ret < 0) { + /*! + * \note + * Packet will be destroyed by master_rpc_async_request + */ + _widget_destroy_cb_info(cbinfo); + } + + return ret; +} + +static int widget_acquire_gbar_pixmap(widget_h handle, widget_ret_cb cb, void *data) +{ + struct packet *packet; + struct cb_info *cbinfo; + unsigned int cmd = CMD_GBAR_ACQUIRE_PIXMAP; + const char *id; + int ret; + + id = fb_id(handle->common->gbar.fb); + if (!id || strncasecmp(id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP))) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + packet = packet_create((const char *)&cmd, "ss", handle->common->pkgname, handle->common->id); + if (!packet) { + ErrPrint("Failed to build a param\n"); + return WIDGET_ERROR_FAULT; + } + + cbinfo = _widget_create_cb_info(cb, data); + if (!cbinfo) { + packet_destroy(packet); + return WIDGET_ERROR_FAULT; + } + + ret = master_rpc_async_request(handle, packet, 0, gbar_pixmap_acquired_cb, cbinfo); + if (ret < 0) { + /*! + * \note + * Packet will be destroyed by master_rpc_async_request + */ + _widget_destroy_cb_info(cbinfo); + } + + return ret; +} + +static void gbar_xpixmap_acquired_cb(widget_h handle, const struct packet *result, void *data) +{ + int pixmap; + int ret; + widget_ret_cb cb; + void *cbdata; + struct cb_info *info = data; + + cb = info->cb; + cbdata = info->data; + _widget_destroy_cb_info(info); + + if (!result) { + pixmap = 0; /* PIXMAP 0 means error */ + ret = WIDGET_ERROR_FAULT; + } else if (packet_get(result, "ii", &pixmap, &ret) != 2) { + pixmap = 0; + ret = WIDGET_ERROR_INVALID_PARAMETER; + } + + if (cb) { + DbgPrint("ret: %x, pixmap: %d\n", ret, pixmap); + cb(handle, pixmap, cbdata); + } + + if (handle->common->state != WIDGET_STATE_DELETE) { + if (ret == (int)WIDGET_ERROR_NOT_EXIST && handle->refcnt == 2) { + _widget_invoke_event_handler(handle, WIDGET_EVENT_DELETED); + _widget_unref(handle, 1); + } + } +} + +static void gbar_pixmap_acquired_cb(widget_h handle, const struct packet *result, void *data) +{ + int pixmap; + int ret; + widget_ret_cb cb; + void *cbdata; + struct cb_info *info = data; + + cb = info->cb; + cbdata = info->data; + _widget_destroy_cb_info(info); + + if (!result) { + pixmap = 0; /* PIXMAP 0 means error */ + ret = WIDGET_ERROR_FAULT; + } else if (packet_get(result, "ii", &pixmap, &ret) != 2) { + pixmap = 0; + ret = WIDGET_ERROR_INVALID_PARAMETER; + } + + if (ret == (int)WIDGET_ERROR_RESOURCE_BUSY) { + ret = widget_acquire_gbar_pixmap(handle, cb, cbdata); + DbgPrint("Busy, Try again: %d\n", ret); + /* Try again */ + } else if (ret == (int)WIDGET_ERROR_NOT_EXIST && handle->refcnt == 2) { + if (cb) { + cb(handle, pixmap, cbdata); + } + + if (handle->common->state != WIDGET_STATE_DELETE) { + _widget_invoke_event_handler(handle, WIDGET_EVENT_DELETED); + _widget_unref(handle, 1); + } + } else { + if (cb) { + DbgPrint("ret: %d, pixmap: %d\n", ret, pixmap); + cb(handle, pixmap, cbdata); + } + } +} + +static void pinup_done_cb(widget_h handle, const struct packet *result, void *data) +{ + int ret; + + if (!result) { + ret = WIDGET_ERROR_FAULT; + goto errout; + } else if (packet_get(result, "i", &ret) != 1) { + goto errout; + } + + if (ret < 0) { + goto errout; + } + + return; + +errout: + handle->cbs.pinup.cb(handle, ret, handle->cbs.pinup.data); + handle->cbs.pinup.cb = NULL; + handle->cbs.pinup.data = NULL; + handle->common->request.pinup = 0; + + if (handle->common->state != WIDGET_STATE_DELETE) { + if (ret == (int)WIDGET_ERROR_NOT_EXIST && handle->refcnt == 2) { + _widget_invoke_event_handler(handle, WIDGET_EVENT_DELETED); + _widget_unref(handle, 1); + } + } +} + +static void key_ret_cb(widget_h handle, const struct packet *result, void *data) +{ + int ret; + + if (!result) { + ret = WIDGET_ERROR_FAULT; + return; + } + + if (packet_get(result, "i", &ret) != 1) { + ret = WIDGET_ERROR_INVALID_PARAMETER; + return; + } + + if (ret != WIDGET_ERROR_NONE) { + goto errout; + } + + return; +errout: + handle->cbs.key_event.cb(handle, ret, handle->cbs.key_event.data); + handle->cbs.key_event.cb = NULL; + handle->cbs.key_event.data = NULL; + handle->common->request.key_event = 0; + + if (handle->common->state != WIDGET_STATE_DELETE) { + if (ret == (int)WIDGET_ERROR_NOT_EXIST && handle->refcnt == 2) { + _widget_invoke_event_handler(handle, WIDGET_EVENT_DELETED); + _widget_unref(handle, 1); + } + } +} + +static void access_ret_cb(widget_h handle, const struct packet *result, void *data) +{ + int ret; + + if (!result) { + ret = WIDGET_ERROR_FAULT; + return; + } + + if (packet_get(result, "i", &ret) != 1) { + ret = WIDGET_ERROR_INVALID_PARAMETER; + return; + } + + if (ret != WIDGET_ERROR_NONE) { + goto errout; + } + + return; + +errout: + handle->cbs.access_event.cb(handle, ret, handle->cbs.access_event.data); + handle->cbs.access_event.cb = NULL; + handle->cbs.access_event.data = NULL; + handle->common->request.access_event = 0; + + if (handle->common->state != WIDGET_STATE_DELETE) { + if (ret == (int)WIDGET_ERROR_NOT_EXIST && handle->refcnt == 2) { + _widget_invoke_event_handler(handle, WIDGET_EVENT_DELETED); + _widget_unref(handle, 1); + } + } +} + +static int send_access_event(widget_h handle, const char *event, int x, int y, int type) +{ + struct packet *packet; + double timestamp; + + timestamp = util_timestamp(); + + packet = packet_create(event, "ssdiii", handle->common->pkgname, handle->common->id, timestamp, x, y, type); + if (!packet) { + ErrPrint("Failed to build packet\n"); + return WIDGET_ERROR_FAULT; + } + + return master_rpc_async_request(handle, packet, 0, access_ret_cb, NULL); +} + +static int send_key_event(widget_h handle, const char *event, unsigned int keycode) +{ + struct packet *packet; + double timestamp; + + timestamp = util_timestamp(); + packet = packet_create(event, "ssdi", handle->common->pkgname, handle->common->id, timestamp, keycode); + if (!packet) { + ErrPrint("Failed to build packet\n"); + return WIDGET_ERROR_FAULT; + } + + return master_rpc_async_request(handle, packet, 0, key_ret_cb, NULL); +} + +static int send_mouse_event(widget_h handle, const char *event, int x, int y) +{ + struct packet *packet; + double timestamp; + + timestamp = util_timestamp(); + packet = packet_create_noack(event, "ssdii", handle->common->pkgname, handle->common->id, timestamp, x, y); + if (!packet) { + ErrPrint("Failed to build param\n"); + return WIDGET_ERROR_FAULT; + } + + return master_rpc_request_only(handle, packet); +} + +static int initialize_widget(void *disp, int use_thread) +{ + int ret; +#if defined(FLOG) + char filename[BUFSIZ]; + snprintf(filename, sizeof(filename), "/tmp/%d.box.log", getpid()); + __file_log_fp = fopen(filename, "w+t"); + if (!__file_log_fp) { + __file_log_fp = fdopen(1, "w+t"); + } +#endif + ret = widget_service_init(); + if (ret != WIDGET_ERROR_NONE) { + return ret; + } + + ret = fb_init(disp); + if (ret != WIDGET_ERROR_NONE) { + widget_service_fini(); + return ret; + } + + ret = client_init(use_thread); + if (ret != WIDGET_ERROR_NONE) { + fb_fini(); + widget_service_fini(); + return ret; + } + + s_info.init_count++; + return ret; +} + +static inline char *_widget_pkgname(const char *pkgname) +{ + char *widget; + + widget = widget_service_get_widget_id(pkgname); + if (!widget) { + widget = strdup(pkgname); + } + + return widget; +} + +static gboolean job_execute_cb(void *data) +{ + struct job_item *item; + struct dlist *l; + + l = dlist_nth(s_info.job_list, 0); + if (!l) { + s_info.job_timer = 0; + return FALSE; + } + + item = dlist_data(l); + s_info.job_list = dlist_remove(s_info.job_list, l); + + if (item) { + item->cb(item->handle, item->ret, item->data); + _widget_unref(item->handle, 1); + free(item); + } + + return TRUE; +} + +static int job_add(widget_h handle, widget_ret_cb job_cb, int ret, void *data) +{ + struct job_item *item; + + if (!job_cb) { + ErrPrint("Invalid argument\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + item = malloc(sizeof(*item)); + if (!item) { + ErrPrint("Heap: %d\n", errno); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + item->handle = _widget_ref(handle); + item->cb = job_cb; + item->data = data; + item->ret = ret; + + s_info.job_list = dlist_append(s_info.job_list, item); + + if (!s_info.job_timer) { + s_info.job_timer = g_timeout_add(1, job_execute_cb, NULL); + if (!s_info.job_timer) { + ErrPrint("Failed to create a job timer\n"); + } + } + + return WIDGET_ERROR_NONE; +} + +static void new_ret_cb(widget_h handle, const struct packet *result, void *data) +{ + int ret; + struct cb_info *info = data; + widget_ret_cb cb; + void *cbdata; + + cb = info->cb; + cbdata = info->data; + _widget_destroy_cb_info(info); + + if (!result) { + ret = WIDGET_ERROR_FAULT; + } else if (packet_get(result, "i", &ret) != 1) { + ret = WIDGET_ERROR_INVALID_PARAMETER; + } + + if (ret >= 0) { + handle->cbs.created.cb = cb; + handle->cbs.created.data = cbdata; + + /*! + * \note + * Don't go anymore ;) + */ + return; + } else if (cb) { + /*! + * \note + * It means the current instance is not created, + * so user has to know about this. + * notice it to user using "deleted" event. + */ + cb(handle, ret, cbdata); + } + + _widget_unref(handle, 1); +} + +static int create_real_instance(widget_h handle, widget_ret_cb cb, void *data) +{ + struct cb_info *cbinfo; + struct packet *packet; + struct widget_common *common; + unsigned int cmd = CMD_NEW; + int ret; + + common = handle->common; + + packet = packet_create((const char *)&cmd, "dssssdii", + common->timestamp, common->pkgname, common->content, + common->cluster, common->category, + common->widget.period, common->widget.width, common->widget.height); + if (!packet) { + ErrPrint("Failed to create a new packet\n"); + set_last_result(WIDGET_ERROR_FAULT); + return WIDGET_ERROR_FAULT; + } + + cbinfo = _widget_create_cb_info(cb, data); + if (!cbinfo) { + ErrPrint("Failed to create a cbinfo\n"); + packet_destroy(packet); + set_last_result(WIDGET_ERROR_OUT_OF_MEMORY); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + /*! + * \note + * master_rpc_async_request will destroy the packet (decrease the refcnt) + * So be aware the packet object after return from master_rpc_async_request. + */ + ret = master_rpc_async_request(handle, packet, 0, new_ret_cb, cbinfo); + if (ret < 0) { + ErrPrint("Failed to send a new packet\n"); + _widget_destroy_cb_info(cbinfo); + set_last_result(WIDGET_ERROR_FAULT); + return WIDGET_ERROR_FAULT; + } + handle->common->request.created = 1; + return WIDGET_ERROR_NONE; +} + +static void create_cb(widget_h handle, int ret, void *data) +{ + struct cb_info *cbinfo = data; + + if (cbinfo->cb) { + cbinfo->cb(handle, ret, cbinfo->data); + } + + _widget_destroy_cb_info(cbinfo); + + /*! + * \note + * Forcely generate "updated" event + */ + _widget_invoke_event_handler(handle, WIDGET_EVENT_WIDGET_UPDATED); +} + +static int create_fake_instance(widget_h handle, widget_ret_cb cb, void *data) +{ + struct cb_info *cbinfo; + + cbinfo = _widget_create_cb_info(cb, data); + if (!cbinfo) { + ErrPrint("Failed to create a cbinfo\n"); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + if (job_add(handle, create_cb, WIDGET_ERROR_NONE, cbinfo) != WIDGET_ERROR_NONE) { + _widget_destroy_cb_info(cbinfo); + } + + return WIDGET_ERROR_NONE; +} + +static void refresh_for_paused_updating_cb(widget_h handle, int ret, void *data) +{ + if (handle->paused_updating == 0) { + DbgPrint("Paused updates are cleared\n"); + return; + } + + DbgPrint("Pending updates are found\n"); + _widget_invoke_event_handler(handle, WIDGET_EVENT_WIDGET_UPDATED); +} + +static int _widget_set_visibility(widget_h handle, widget_visible_state_e state) +{ + struct packet *packet; + int need_to_add_job = 0; + unsigned int cmd = CMD_CHANGE_VISIBILITY; + int ret; + + if (handle->common->visible != WIDGET_SHOW && state == WIDGET_SHOW) { + need_to_add_job = !!handle->paused_updating; + } else if (handle->common->visible == WIDGET_SHOW && state != WIDGET_SHOW) { + if (!!_widget_find_widget_in_show(handle->common)) { + return WIDGET_ERROR_NONE; + } + } else if (handle->common->visible == WIDGET_SHOW && state == WIDGET_SHOW && handle->paused_updating) { + if (job_add(handle, refresh_for_paused_updating_cb, WIDGET_ERROR_NONE, NULL) < 0) { + ErrPrint("Unable to add a new job for refreshing box\n"); + } + + return WIDGET_ERROR_NONE; + } else { + /*! + * \brief + * No need to send this to the master + */ + return WIDGET_ERROR_NONE; + } + + packet = packet_create_noack((const char *)&cmd, "ssi", handle->common->pkgname, handle->common->id, (int)state); + if (!packet) { + ErrPrint("Failed to create a packet\n"); + return WIDGET_ERROR_FAULT; + } + + ret = master_rpc_request_only(handle, packet); + if (ret == (int)WIDGET_ERROR_NONE) { + DbgPrint("[%s] visibility is changed 0x[%x]\n", handle->common->pkgname, state); + handle->common->visible = state; + + if (need_to_add_job) { + if (job_add(handle, refresh_for_paused_updating_cb, WIDGET_ERROR_NONE, NULL) < 0) { + ErrPrint("Unable to add a new job for refreshing box\n"); + } + } + } + + return ret; +} + +static void _widget_update_visibility(struct widget_common *old_common) +{ + widget_h item; + + item = _widget_find_widget_in_show(old_common); + if (!item) { + item = _widget_get_widget_nth(old_common, 0); + if (item) { + _widget_set_visibility(item, WIDGET_HIDE_WITH_PAUSE); + } else { + ErrPrint("Unable to get the valid handle from common handle\n"); + } + } else { + _widget_set_visibility(item, WIDGET_SHOW); + } +} + +/*! + * \note + * The second parameter should be the "return value", + * But in this case, we will use it for "type of deleting instance". + */ +static void _job_del_cb(widget_h handle, int type, void *data) +{ + struct cb_info *cbinfo = data; + widget_ret_cb cb; + + if (handle->visible == WIDGET_SHOW) { + _widget_update_visibility(handle->common); + } + + cb = cbinfo->cb; + data = cbinfo->data; + _widget_destroy_cb_info(cbinfo); + + if (handle->common->state != WIDGET_STATE_CREATE) { + DbgPrint("[%s] %d\n", handle->common->pkgname, handle->refcnt); + if (cb) { + cb(handle, WIDGET_ERROR_NONE, data); + } + + return; + } + + if (handle->common->refcnt == 1) { + handle->common->delete_type = type; + handle->common->state = WIDGET_STATE_DELETE; + + if (!handle->common->id) { + /*! + * \note + * The id is not determined yet. + * It means a user didn't receive created event yet. + * Then just stop to delete procedure from here. + * Because the "created" event handle will release this. + * By the way, if the user adds any callback for getting return status of this, + * call it at here. + */ + if (cb) { + cb(handle, WIDGET_ERROR_NONE, data); + } + } + + DbgPrint("Send delete request\n"); + _widget_send_delete(handle, type, cb, data); + } else { + if (cb) { + cb(handle, WIDGET_ERROR_NONE, data); + } + + DbgPrint("Before unref: %d\n", handle->common->refcnt); + _widget_unref(handle, 1); + } +} + +static void _resize_job_cb(widget_h handle, int ret, void *data) +{ + struct cb_info *info = data; + + if (info->cb) { + info->cb(handle, ret, info->data); + } + + free(info); + + /*! + * \note + * Forcely update the box + */ + _widget_invoke_event_handler(handle, WIDGET_EVENT_WIDGET_UPDATED); +} + +static void _turn_off_gbar_destroyed_flag_cb(widget_h handle, int ret, void *data) +{ + if (handle->common->request.gbar_destroyed) { + widget_ret_cb cb; + void *data; + + DbgPrint("gbar_destroyed request is canceled\n"); + handle->common->request.gbar_destroyed = 0; + cb = handle->cbs.gbar_destroyed.cb; + data = handle->cbs.gbar_destroyed.data; + handle->cbs.gbar_destroyed.cb = NULL; + handle->cbs.gbar_destroyed.data = NULL; + + if (cb) { + cb(handle, ret, data); + } + } +} + +static void _turn_off_gbar_created_flag_cb(widget_h handle, int ret, void *data) +{ + if (handle->common->request.gbar_created) { + widget_ret_cb cb; + void *data; + + DbgPrint("gbar_created request is canceled\n"); + handle->common->request.gbar_created = 0; + cb = handle->cbs.gbar_created.cb; + data = handle->cbs.gbar_created.data; + handle->cbs.gbar_created.cb = NULL; + handle->cbs.gbar_created.data = NULL; + + if (cb) { + cb(handle, ret, data); + } + } +} + +EAPI int widget_viewer_init(void *disp, int prevent_overwrite, double event_filter, int use_thread) +{ + if (s_info.init_count > 0) { + s_info.init_count++; + return WIDGET_ERROR_NONE; + } + + /*! + * \note + * Some application doesn't want to use the environment value. + * So set them using arguments. + */ + s_info.prevent_overwrite = prevent_overwrite; + conf_set_event_filter(event_filter); + + return initialize_widget(disp, use_thread); +} + +EAPI int widget_viewer_fini(void) +{ + if (s_info.init_count <= 0) { + ErrPrint("Doesn't initialized\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + s_info.init_count--; + if (s_info.init_count > 0) { + ErrPrint("init count : %d\n", s_info.init_count); + return WIDGET_ERROR_NONE; + } + + client_fini(); + fb_fini(); + widget_service_fini(); + return WIDGET_ERROR_NONE; +} + +EAPI widget_h widget_viewer_add_widget(const char *pkgname, const char *content, const char *cluster, const char *category, double period, widget_size_type_e type, widget_ret_cb cb, void *data) +{ + char *widgetid; + widget_h handle; + int w = 0; + int h = 0; + + if (!pkgname || !cluster || !category) { + ErrPrint("Invalid arguments: pkgname[%p], cluster[%p], category[%p]\n", + pkgname, cluster, category); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + widgetid = _widget_pkgname(pkgname); + if (!widgetid) { + ErrPrint("Invalid package: %s\n", pkgname); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + if (widget_service_is_enabled(widgetid) == 0) { + DbgPrint("Livebox [%s](%s) is disabled package\n", widgetid, pkgname); + free(widgetid); + set_last_result(WIDGET_ERROR_DISABLED); + return NULL; + } + + if (type != WIDGET_SIZE_TYPE_UNKNOWN) { + (void)widget_service_get_size(type, &w, &h); + } + + handle = calloc(1, sizeof(*handle)); + if (!handle) { + ErrPrint("Error: %d\n", errno); + free(widgetid); + set_last_result(WIDGET_ERROR_OUT_OF_MEMORY); + return NULL; + } + + if (!cb) { + cb = default_create_cb; + } + + handle->common = _widget_find_sharable_common_handle(widgetid, content, w, h, cluster, category); + if (!handle->common) { + handle->common = _widget_create_common_handle(handle, widgetid, cluster, category); + free(widgetid); + if (!handle->common) { + ErrPrint("Failed to find common handle\n"); + free(handle); + return NULL; + } + + if (!content || !strlen(content)) { + char *pc; + /** + * @note + * I know the content should not be modified. use it temporarly without "const" + */ + pc = widget_service_get_content_string(handle->common->pkgname); + _widget_set_content(handle->common, pc); + free(pc); + } else { + _widget_set_content(handle->common, content); + } + + _widget_set_period(handle->common, period); + _widget_set_size(handle->common, w, h); + _widget_common_ref(handle->common, handle); + + if (create_real_instance(handle, cb, data) < 0) { + if (_widget_common_unref(handle->common, handle) == 0) { + /*! + * Delete common + */ + _widget_destroy_common_handle(handle->common); + handle->common = NULL; + } + free(handle); + return NULL; + } + } else { + free(widgetid); + + _widget_common_ref(handle->common, handle); + + if (handle->common->request.created) { + /*! + * If a box is in creating, wait its result too + */ + handle->cbs.created.cb = cb; + handle->cbs.created.data = data; + } else { + /*! + * or fire the fake created_event + */ + if (create_fake_instance(handle, cb, data) < 0) { + if (_widget_common_unref(handle->common, handle) == 0) { + /*! + * Delete common + */ + _widget_destroy_common_handle(handle->common); + } + free(handle); + return NULL; + } + } + } + + handle->visible = WIDGET_HIDE_WITH_PAUSE; + handle->state = WIDGET_STATE_CREATE; + handle = _widget_ref(handle); + + return handle; +} + +EAPI int widget_viewer_get_period(widget_h handle, double *period) +{ + int ret = WIDGET_ERROR_NONE; + double result_period = -1.0f; + + if (!handle || handle->state != WIDGET_STATE_CREATE || period == NULL) { + ErrPrint("Handler is not valid\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + goto out; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Invalid handle\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + goto out; + } + + if (!handle->common->id) { + ErrPrint("Hnalder is not valid\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + goto out; + } + + result_period = handle->common->widget.period; + +out: + if (period) + *period = result_period; + + return ret; +} + +EAPI int widget_viewer_set_period(widget_h handle, double period, widget_ret_cb cb, void *data) +{ + struct packet *packet; + unsigned int cmd = CMD_SET_PERIOD; + int ret; + + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Invalid handle\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (handle->common->request.period_changed) { + ErrPrint("Previous request for changing period is not finished\n"); + return WIDGET_ERROR_RESOURCE_BUSY; + } + + if (!handle->common->is_user) { + ErrPrint("CA Livebox is not able to change the period\n"); + return WIDGET_ERROR_PERMISSION_DENIED; + } + + if (handle->common->widget.period == period) { + DbgPrint("No changes\n"); + return WIDGET_ERROR_ALREADY_EXIST; + } + + packet = packet_create((const char *)&cmd, "ssd", handle->common->pkgname, handle->common->id, period); + if (!packet) { + ErrPrint("Failed to build a packet %s\n", handle->common->pkgname); + return WIDGET_ERROR_FAULT; + } + + if (!cb) { + cb = default_period_changed_cb; + } + + ret = master_rpc_async_request(handle, packet, 0, period_ret_cb, NULL); + if (ret == (int)WIDGET_ERROR_NONE) { + handle->cbs.period_changed.cb = cb; + handle->cbs.period_changed.data = data; + handle->common->request.period_changed = 1; + } + + return ret; +} + +EAPI int widget_viewer_delete_widget(widget_h handle, widget_delete_type_e type, widget_ret_cb cb, void *data) +{ + struct cb_info *cbinfo; + + if (!handle) { + ErrPrint("Handler is NIL\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is already deleted\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + handle->state = WIDGET_STATE_DELETE; + + cbinfo = _widget_create_cb_info(cb, data); + if (!cbinfo) { + ErrPrint("Failed to create a cbinfo\n"); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + if (job_add(handle, _job_del_cb, type, cbinfo) != WIDGET_ERROR_NONE) { + ErrPrint("Failed to add a new job\n"); + _widget_destroy_cb_info(cbinfo); + return WIDGET_ERROR_FAULT; + } + + return WIDGET_ERROR_NONE; +} + +EAPI int widget_viewer_add_fault_handler(widget_fault_handler_cb widget_cb, void *data) +{ + if (!widget_cb) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + return _widget_add_fault_handler(widget_cb, data); +} + +EAPI void *widget_viewer_remove_fault_handler(widget_fault_handler_cb widget_cb) +{ + if (!widget_cb) { + return NULL; + } + + return _widget_remove_fault_handler(widget_cb); +} + +EAPI int widget_viewer_add_event_handler(widget_event_handler_cb widget_cb, void *data) +{ + if (!widget_cb) { + ErrPrint("Invalid argument widget_cb is nil\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + return _widget_add_event_handler(widget_cb, data); +} + +EAPI void *widget_viewer_remove_event_handler(widget_event_handler_cb widget_cb) +{ + if (!widget_cb) { + return NULL; + } + + return _widget_remove_event_handler(widget_cb); +} + +EAPI int widget_viewer_set_update_mode(widget_h handle, int active_update, widget_ret_cb cb, void *data) +{ + struct packet *packet; + unsigned int cmd = CMD_UPDATE_MODE; + int ret; + + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is Invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is Invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Handler is Invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (handle->common->request.update_mode) { + ErrPrint("Previous update_mode cb is not finished yet\n"); + return WIDGET_ERROR_RESOURCE_BUSY; + } + + if (handle->common->is_active_update == active_update) { + return WIDGET_ERROR_ALREADY_EXIST; + } + + if (!handle->common->is_user) { + return WIDGET_ERROR_PERMISSION_DENIED; + } + + packet = packet_create((const char *)&cmd, "ssi", handle->common->pkgname, handle->common->id, active_update); + if (!packet) { + return WIDGET_ERROR_FAULT; + } + + if (!cb) { + cb = default_update_mode_cb; + } + + ret = master_rpc_async_request(handle, packet, 0, update_mode_cb, NULL); + if (ret == (int)WIDGET_ERROR_NONE) { + handle->cbs.update_mode.cb = cb; + handle->cbs.update_mode.data = data; + handle->common->request.update_mode = 1; + } + + return ret; +} + +EAPI int widget_viewer_is_active_update(widget_h handle) +{ + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is Invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is Invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + return handle->common->is_active_update; +} + +EAPI int widget_viewer_resize_widget(widget_h handle, widget_size_type_e type, widget_ret_cb cb, void *data) +{ + struct widget_common *common; + int w; + int h; + int ret; + + /*! + * \TODO + * If this handle is host instance or link instance, + * Create a new instance or find another linkable instance. + */ + + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Invalid handle\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + /*! + * \note + * resize operation should be separated by each handle. + * If a handle is resizing, the other handle can request resize too. + * So we should not use the common->request.size_changed flag. + */ + if (handle->cbs.size_changed.cb) { + ErrPrint("Previous resize request is not finished yet\n"); + return WIDGET_ERROR_RESOURCE_BUSY; + } + + if (widget_service_get_size(type, &w, &h) != 0) { + ErrPrint("Invalid size type\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (handle->common->widget.width == w && handle->common->widget.height == h) { + DbgPrint("No changes\n"); + return WIDGET_ERROR_ALREADY_EXIST; + } + + if (!handle->common->is_user) { + ErrPrint("CA Livebox is not able to be resized\n"); + return WIDGET_ERROR_PERMISSION_DENIED; + } + + if (handle->common->refcnt <= 1) { + struct packet *packet; + unsigned int cmd = CMD_RESIZE; + + /* Only 1 instance */ + packet = packet_create((const char *)&cmd, "ssii", handle->common->pkgname, handle->common->id, w, h); + if (!packet) { + ErrPrint("Failed to build param\n"); + return WIDGET_ERROR_FAULT; + } + + if (!cb) { + cb = default_widget_size_changed_cb; + } + + ret = master_rpc_async_request(handle, packet, 0, resize_cb, NULL); + if (ret == (int)WIDGET_ERROR_NONE) { + handle->cbs.size_changed.cb = cb; + handle->cbs.size_changed.data = data; + handle->common->request.size_changed = 1; + } + } else { + common = _widget_find_sharable_common_handle(handle->common->pkgname, handle->common->content, w, h, handle->common->cluster, handle->common->category); + if (!common) { + struct widget_common *old_common; + /*! + * \note + * If the common handle is in resizing, + * if user tries to resize a hander, then simply create new one even if the requested size is same with this. + + if (handle->common->request.size_changed) { + } + + */ + + old_common = handle->common; + + common = _widget_create_common_handle(handle, old_common->pkgname, old_common->cluster, old_common->category); + if (!common) { + ErrPrint("Failed to create common handle\n"); + return WIDGET_ERROR_FAULT; + } + + _widget_set_size(common, w, h); + _widget_set_content(common, old_common->content); + _widget_set_period(common, old_common->widget.period); + + /*! + * \note + * Disconnecting from old one. + */ + if (_widget_common_unref(old_common, handle) == 0) { + /*! + * \note + * Impossible + */ + ErrPrint("Common has no associated handle\n"); + } + + _widget_common_ref(common, handle); + + /*! + * Connect to a new one + */ + handle->common = common; + + /*! + * \TODO + * Need to care, if it fails to create a common handle, + * the resize operation will be failed. + * in that case, we should reuse the old common handle + */ + ret = create_real_instance(handle, cb, data); + if (ret < 0) { + _widget_common_unref(common, handle); + _widget_destroy_common_handle(common); + + _widget_common_ref(old_common, handle); + handle->common = old_common; + } else { + /*! + * In this case, we should update visibility of old_common's widgetes + */ + if (handle->visible == WIDGET_SHOW) { + _widget_update_visibility(old_common); + } + } + } else { + struct cb_info *cbinfo; + + cbinfo = _widget_create_cb_info(cb, data); + if (!cbinfo) { + ErrPrint("Failed to create a cbinfo\n"); + ret = WIDGET_ERROR_OUT_OF_MEMORY; + } else { + ret = job_add(handle, _resize_job_cb, WIDGET_ERROR_NONE, cbinfo); + if (ret == (int)WIDGET_ERROR_NONE) { + struct widget_common *old_common; + + old_common = handle->common; + + if (_widget_common_unref(handle->common, handle) == 0) { + ErrPrint("Old common has no associated handle\n"); + } + + _widget_common_ref(common, handle); + handle->common = common; + + if (handle->visible == WIDGET_SHOW) { + _widget_update_visibility(old_common); /* To update visibility: Show --> Paused */ + _widget_update_visibility(common); /* To update visibility: Paused --> Show */ + } + } else { + _widget_destroy_cb_info(cbinfo); + } + } + } + } + + return ret; +} + +EAPI int widget_viewer_send_click_event(widget_h handle, double x, double y) +{ + struct packet *packet; + double timestamp; + unsigned int cmd = CMD_CLICKED; + int ret; + + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (handle->common->widget.auto_launch) { + if (s_info.launch.handle) { + ret = s_info.launch.handle(handle, handle->common->widget.auto_launch, s_info.launch.data); + if (ret < 0) { + ErrPrint("launch handle app %s (%d)\n", handle->common->widget.auto_launch, ret); + } + } + } + + timestamp = util_timestamp(); + DbgPrint("CLICKED: %lf\n", timestamp); + + packet = packet_create_noack((const char *)&cmd, "sssddd", handle->common->pkgname, handle->common->id, "clicked", timestamp, x, y); + if (!packet) { + ErrPrint("Failed to build param\n"); + return WIDGET_ERROR_FAULT; + } + + ret = master_rpc_request_only(handle, packet); + return ret; +} + +EAPI int widget_viewer_has_glance_bar(widget_h handle) +{ + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + return !!handle->common->gbar.fb; +} + +EAPI int widget_viewer_glance_bar_is_created(widget_h handle) +{ + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->gbar.fb || !handle->common->id) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + return handle->common->is_gbar_created; +} + +EAPI int widget_viewer_create_glance_bar(widget_h handle, double x, double y, widget_ret_cb cb, void *data) +{ + struct packet *packet; + unsigned int cmd = CMD_CREATE_GBAR; + int ret; + + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->gbar.fb || !handle->common->id) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + /*! + * \note + * Only one handle can have a GBAR + */ + if (handle->common->is_gbar_created) { + DbgPrint("GBAR is already created\n"); + return WIDGET_ERROR_NONE; + } + + if (handle->common->request.gbar_created) { + ErrPrint("Previous request is not completed yet\n"); + return WIDGET_ERROR_RESOURCE_BUSY; + } + + /*! + * \note + * Turn off the gbar_destroyed request flag + */ + if (handle->common->request.gbar_destroyed) { + if (job_add(handle, _turn_off_gbar_destroyed_flag_cb, WIDGET_ERROR_CANCELED, NULL) < 0) { + ErrPrint("Failed to add gbar_destroyed job\n"); + } + } + + packet = packet_create((const char *)&cmd, "ssdd", handle->common->pkgname, handle->common->id, x, y); + if (!packet) { + ErrPrint("Failed to build param\n"); + return WIDGET_ERROR_FAULT; + } + + if (!cb) { + cb = default_gbar_created_cb; + } + + DbgPrint("PERF_WIDGET\n"); + ret = master_rpc_async_request(handle, packet, 0, gbar_create_cb, NULL); + if (ret == (int)WIDGET_ERROR_NONE) { + handle->cbs.gbar_created.cb = cb; + handle->cbs.gbar_created.data = data; + handle->common->request.gbar_created = 1; + } + + return ret; +} + +EAPI int widget_viewer_move_glance_bar(widget_h handle, double x, double y) +{ + struct packet *packet; + unsigned int cmd = CMD_GBAR_MOVE; + + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->gbar.fb || !handle->common->id) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->is_gbar_created) { + ErrPrint("GBAR is not created\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + packet = packet_create_noack((const char *)&cmd, "ssdd", handle->common->pkgname, handle->common->id, x, y); + if (!packet) { + ErrPrint("Failed to build param\n"); + return WIDGET_ERROR_FAULT; + } + + return master_rpc_request_only(handle, packet); +} + +EAPI int widget_viewer_activate_faulted_widget(const char *pkgname, widget_ret_cb cb, void *data) +{ + struct packet *packet; + struct cb_info *cbinfo; + unsigned int cmd = CMD_ACTIVATE_PACKAGE; + int ret; + + if (!pkgname) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + packet = packet_create((const char *)&cmd, "s", pkgname); + if (!packet) { + ErrPrint("Failed to build a param\n"); + return WIDGET_ERROR_FAULT; + } + + cbinfo = _widget_create_cb_info(cb, data); + if (!cbinfo) { + ErrPrint("Unable to create cbinfo\n"); + packet_destroy(packet); + return WIDGET_ERROR_FAULT; + } + + ret = master_rpc_async_request(NULL, packet, 0, activated_cb, cbinfo); + if (ret < 0) { + _widget_destroy_cb_info(cbinfo); + } + + return ret; +} + +EAPI int widget_viewer_destroy_glance_bar(widget_h handle, widget_ret_cb cb, void *data) +{ + struct packet *packet; + struct cb_info *cbinfo; + unsigned int cmd = CMD_DESTROY_GBAR; + int ret; + + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->gbar.fb || !handle->common->id) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + /*! + * \FIXME + * Replace the callback check code. + * Use the flag instead of callback. + * the flag should be in the ADT "common" + */ + if (!handle->common->is_gbar_created && !handle->common->request.gbar_created) { + ErrPrint("GBAR is not created\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (handle->common->request.gbar_destroyed) { + ErrPrint("GBAR destroy request is already sent\n"); + return WIDGET_ERROR_ALREADY_EXIST; + } + + /*! + * \note + * Disable the gbar_created request flag + */ + if (handle->common->request.gbar_created) { + if (job_add(handle, _turn_off_gbar_created_flag_cb, WIDGET_ERROR_CANCELED, NULL) < 0) { + ErrPrint("Failed to add a new job\n"); + } + } + + DbgPrint("[%s]\n", handle->common->pkgname); + + packet = packet_create((const char *)&cmd, "ss", handle->common->pkgname, handle->common->id); + if (!packet) { + ErrPrint("Failed to build a param\n"); + return WIDGET_ERROR_FAULT; + } + + if (!cb) { + cb = default_gbar_destroyed_cb; + } + + cbinfo = _widget_create_cb_info(cb, data); + if (!cbinfo) { + packet_destroy(packet); + return WIDGET_ERROR_FAULT; + } + + ret = master_rpc_async_request(handle, packet, 0, gbar_destroy_cb, cbinfo); + if (ret < 0) { + _widget_destroy_cb_info(cbinfo); + } else { + handle->common->request.gbar_destroyed = 1; + } + + return ret; +} + +EAPI int widget_viewer_feed_access_event(widget_h handle, widget_access_event_type_e type, widget_access_event_info_s info, widget_ret_cb cb, void *data) +{ + int w = 1; + int h = 1; + unsigned int cmd; + int ret = 0; /* re-used for sending event type */ + + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (handle->common->request.access_event) { + ErrPrint("Previous access event is not yet done\n"); + return WIDGET_ERROR_RESOURCE_BUSY; + } + + if (type & WIDGET_ACCESS_EVENT_GBAR_MASK) { + if (!handle->common->is_gbar_created) { + ErrPrint("GBAR is not created\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + w = handle->common->gbar.width; + h = handle->common->gbar.height; + + switch (type & ~(WIDGET_ACCESS_EVENT_GBAR_MASK | WIDGET_ACCESS_EVENT_WIDGET_MASK)) { + case WIDGET_ACCESS_EVENT_HIGHLIGHT: + cmd = CMD_GBAR_ACCESS_HL; + ret = (int)info->type; + break; + case WIDGET_ACCESS_EVENT_ACTIVATE: + cmd = CMD_GBAR_ACCESS_ACTIVATE; + break; + case WIDGET_ACCESS_EVENT_ACTION: + cmd = CMD_GBAR_ACCESS_ACTION; + ret = (int)info->type; + break; + case WIDGET_ACCESS_EVENT_SCROLL: + cmd = CMD_GBAR_ACCESS_SCROLL; + ret = (int)info->type; + break; + case WIDGET_ACCESS_EVENT_VALUE_CHANGE: + cmd = CMD_GBAR_ACCESS_VALUE_CHANGE; + break; + case WIDGET_ACCESS_EVENT_MOUSE: + cmd = CMD_GBAR_ACCESS_MOUSE; + ret = (int)info->type; + break; + case WIDGET_ACCESS_EVENT_BACK: + cmd = CMD_GBAR_ACCESS_BACK; + break; + case WIDGET_ACCESS_EVENT_OVER: + cmd = CMD_GBAR_ACCESS_OVER; + break; + case WIDGET_ACCESS_EVENT_READ: + cmd = CMD_GBAR_ACCESS_READ; + break; + case WIDGET_ACCESS_EVENT_ENABLE: + cmd = CMD_GBAR_ACCESS_ENABLE; + ret = info->type; + break; + default: + return WIDGET_ERROR_INVALID_PARAMETER; + } + + } else if (type & WIDGET_ACCESS_EVENT_WIDGET_MASK) { + w = handle->common->widget.width; + h = handle->common->widget.height; + switch (type & ~(WIDGET_ACCESS_EVENT_GBAR_MASK | WIDGET_ACCESS_EVENT_WIDGET_MASK)) { + case WIDGET_ACCESS_EVENT_HIGHLIGHT: + cmd = CMD_WIDGET_ACCESS_HL; + ret = (int)info->type; + break; + case WIDGET_ACCESS_EVENT_ACTIVATE: + cmd = CMD_WIDGET_ACCESS_ACTIVATE; + break; + case WIDGET_ACCESS_EVENT_ACTION: + cmd = CMD_WIDGET_ACCESS_ACTION; + ret = (int)info->type; + break; + case WIDGET_ACCESS_EVENT_SCROLL: + cmd = CMD_WIDGET_ACCESS_SCROLL; + ret = (int)info->type; + break; + case WIDGET_ACCESS_EVENT_VALUE_CHANGE: + cmd = CMD_WIDGET_ACCESS_VALUE_CHANGE; + break; + case WIDGET_ACCESS_EVENT_MOUSE: + cmd = CMD_WIDGET_ACCESS_MOUSE; + ret = (int)info->type; + break; + case WIDGET_ACCESS_EVENT_BACK: + cmd = CMD_WIDGET_ACCESS_BACK; + break; + case WIDGET_ACCESS_EVENT_OVER: + cmd = CMD_WIDGET_ACCESS_OVER; + break; + case WIDGET_ACCESS_EVENT_READ: + cmd = CMD_WIDGET_ACCESS_READ; + break; + case WIDGET_ACCESS_EVENT_ENABLE: + cmd = CMD_WIDGET_ACCESS_ENABLE; + ret = info->type; + break; + default: + return WIDGET_ERROR_INVALID_PARAMETER; + } + } else { + ErrPrint("Invalid event type\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!cb) { + cb = default_access_event_cb; + } + + ret = send_access_event(handle, (const char *)&cmd, info->x * w, info->y * h, ret); + if (ret == (int)WIDGET_ERROR_NONE) { + handle->cbs.access_event.cb = cb; + handle->cbs.access_event.data = data; + handle->common->request.access_event = 1; + } + + return ret; +} + +EAPI int widget_viewer_feed_mouse_event(widget_h handle, widget_mouse_event_type_e type, widget_mouse_event_info_s info) +{ + int w = 1; + int h = 1; + unsigned int cmd; + + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!(type & WIDGET_MOUSE_EVENT_MASK)) { + ErrPrint("Invalid content event is used\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (type & WIDGET_MOUSE_EVENT_GBAR_MASK) { + int flag = 1; + + if (!handle->common->is_gbar_created) { + ErrPrint("GBAR is not created\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->gbar.fb) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (type & WIDGET_MOUSE_EVENT_MOVE) { + if (fabs(info->x - handle->common->gbar.x) < conf_event_filter() && fabs(info->y - handle->common->gbar.y) < conf_event_filter()) { + return WIDGET_ERROR_RESOURCE_BUSY; + } + } else if (type & WIDGET_MOUSE_EVENT_SET) { + flag = 0; + } + + if (flag) { + handle->common->gbar.x = info->x; + handle->common->gbar.y = info->y; + w = handle->common->gbar.width; + h = handle->common->gbar.height; + } + + switch ((type & ~(WIDGET_MOUSE_EVENT_GBAR_MASK | WIDGET_MOUSE_EVENT_WIDGET_MASK))) { + case WIDGET_MOUSE_EVENT_ENTER | WIDGET_MOUSE_EVENT_MASK: + cmd = CMD_GBAR_MOUSE_ENTER; + break; + case WIDGET_MOUSE_EVENT_LEAVE | WIDGET_MOUSE_EVENT_MASK: + cmd = CMD_GBAR_MOUSE_LEAVE; + break; + case WIDGET_MOUSE_EVENT_UP | WIDGET_MOUSE_EVENT_MASK: + cmd = CMD_GBAR_MOUSE_UP; + break; + case WIDGET_MOUSE_EVENT_DOWN | WIDGET_MOUSE_EVENT_MASK: + cmd = CMD_GBAR_MOUSE_DOWN; + break; + case WIDGET_MOUSE_EVENT_MOVE | WIDGET_MOUSE_EVENT_MASK: + cmd = CMD_GBAR_MOUSE_MOVE; + break; + case WIDGET_MOUSE_EVENT_SET | WIDGET_MOUSE_EVENT_MASK: + cmd = CMD_GBAR_MOUSE_SET; + break; + case WIDGET_MOUSE_EVENT_UNSET | WIDGET_MOUSE_EVENT_MASK: + cmd = CMD_GBAR_MOUSE_UNSET; + break; + case WIDGET_MOUSE_EVENT_ON_SCROLL | WIDGET_MOUSE_EVENT_MASK: + cmd = CMD_GBAR_MOUSE_ON_SCROLL; + break; + case WIDGET_MOUSE_EVENT_ON_HOLD | WIDGET_MOUSE_EVENT_MASK: + cmd = CMD_GBAR_MOUSE_ON_HOLD; + break; + case WIDGET_MOUSE_EVENT_OFF_SCROLL | WIDGET_MOUSE_EVENT_MASK: + cmd = CMD_GBAR_MOUSE_OFF_SCROLL; + break; + case WIDGET_MOUSE_EVENT_OFF_HOLD | WIDGET_MOUSE_EVENT_MASK: + cmd = CMD_GBAR_MOUSE_OFF_HOLD; + break; + default: + ErrPrint("Invalid event type\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + } else if (type & WIDGET_MOUSE_EVENT_WIDGET_MASK) { + int flag = 1; + + if (!handle->common->widget.fb) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (type & WIDGET_MOUSE_EVENT_MOVE) { + if (fabs(info->x - handle->common->widget.x) < conf_event_filter() && fabs(info->y - handle->common->widget.y) < conf_event_filter()) { + return WIDGET_ERROR_RESOURCE_BUSY; + } + } else if (type & WIDGET_MOUSE_EVENT_SET) { + flag = 0; + } + + if (flag) { + handle->common->widget.x = info->x; + handle->common->widget.y = info->y; + w = handle->common->widget.width; + h = handle->common->widget.height; + } + + switch ((type & ~(WIDGET_MOUSE_EVENT_GBAR_MASK | WIDGET_MOUSE_EVENT_WIDGET_MASK))) { + case WIDGET_MOUSE_EVENT_ENTER | WIDGET_MOUSE_EVENT_MASK: + cmd = CMD_WIDGET_MOUSE_ENTER; + break; + case WIDGET_MOUSE_EVENT_LEAVE | WIDGET_MOUSE_EVENT_MASK: + cmd = CMD_WIDGET_MOUSE_LEAVE; + break; + case WIDGET_MOUSE_EVENT_UP | WIDGET_MOUSE_EVENT_MASK: + cmd = CMD_WIDGET_MOUSE_UP; + break; + case WIDGET_MOUSE_EVENT_DOWN | WIDGET_MOUSE_EVENT_MASK: + cmd = CMD_WIDGET_MOUSE_DOWN; + break; + case WIDGET_MOUSE_EVENT_MOVE | WIDGET_MOUSE_EVENT_MASK: + if (!handle->common->widget.mouse_event) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + cmd = CMD_WIDGET_MOUSE_MOVE; + break; + case WIDGET_MOUSE_EVENT_SET | WIDGET_MOUSE_EVENT_MASK: + if (!handle->common->widget.mouse_event) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + cmd = CMD_WIDGET_MOUSE_SET; + break; + case WIDGET_MOUSE_EVENT_UNSET | WIDGET_MOUSE_EVENT_MASK: + if (!handle->common->widget.mouse_event) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + cmd = CMD_WIDGET_MOUSE_UNSET; + break; + case WIDGET_MOUSE_EVENT_ON_SCROLL | WIDGET_MOUSE_EVENT_MASK: + cmd = CMD_WIDGET_MOUSE_ON_SCROLL; + break; + case WIDGET_MOUSE_EVENT_ON_HOLD | WIDGET_MOUSE_EVENT_MASK: + cmd = CMD_WIDGET_MOUSE_ON_HOLD; + break; + case WIDGET_MOUSE_EVENT_OFF_SCROLL | WIDGET_MOUSE_EVENT_MASK: + cmd = CMD_WIDGET_MOUSE_OFF_SCROLL; + break; + case WIDGET_MOUSE_EVENT_OFF_HOLD | WIDGET_MOUSE_EVENT_MASK: + cmd = CMD_WIDGET_MOUSE_OFF_HOLD; + break; + default: + ErrPrint("Invalid event type\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + } else { + ErrPrint("Invalid event type\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + return send_mouse_event(handle, (const char *)&cmd, info->x * w, info->y * h); +} + +EAPI int widget_viewer_feed_key_event(widget_h handle, widget_key_event_type_e type, widget_key_event_info_s info, widget_ret_cb cb, void *data) +{ + int ret; + unsigned int cmd; + + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!(type & WIDGET_KEY_EVENT_MASK)) { + ErrPrint("Invalid key event is used\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (handle->common->request.key_event) { + ErrPrint("Previous key event is not completed yet\n"); + return WIDGET_ERROR_RESOURCE_BUSY; + } + + if (type & WIDGET_MOUSE_EVENT_GBAR_MASK) { + if (!handle->common->is_gbar_created) { + ErrPrint("GBAR is not created\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->gbar.fb) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (type & WIDGET_KEY_EVENT_DOWN) { + /*! + * \TODO + * filtering the reproduced events if it is too fast + */ + } else if (type & WIDGET_KEY_EVENT_SET) { + /*! + * \TODO + * What can I do for this case? + */ + } + + /*! + * Must be short than 29 bytes. + */ + switch ((type & ~(WIDGET_MOUSE_EVENT_GBAR_MASK | WIDGET_MOUSE_EVENT_WIDGET_MASK))) { + case WIDGET_KEY_EVENT_FOCUS_IN | WIDGET_KEY_EVENT_MASK: + cmd = CMD_GBAR_KEY_FOCUS_IN; + break; + case WIDGET_KEY_EVENT_FOCUS_OUT | WIDGET_KEY_EVENT_MASK: + cmd = CMD_GBAR_KEY_FOCUS_OUT; + break; + case WIDGET_KEY_EVENT_UP | WIDGET_KEY_EVENT_MASK: + cmd = CMD_GBAR_KEY_UP; + break; + case WIDGET_KEY_EVENT_DOWN | WIDGET_KEY_EVENT_MASK: + cmd = CMD_GBAR_KEY_DOWN; + break; + case WIDGET_KEY_EVENT_SET | WIDGET_KEY_EVENT_MASK: + cmd = CMD_GBAR_KEY_SET; + break; + case WIDGET_KEY_EVENT_UNSET | WIDGET_KEY_EVENT_MASK: + cmd = CMD_GBAR_KEY_UNSET; + break; + default: + ErrPrint("Invalid event type\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + } else if (type & WIDGET_MOUSE_EVENT_WIDGET_MASK) { + if (!handle->common->widget.fb) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (type & WIDGET_KEY_EVENT_DOWN) { + /*! + * \TODO + * filtering the reproduced events if it is too fast + */ + } else if (type & WIDGET_KEY_EVENT_SET) { + /*! + * What can I do for this case? + */ + } + + switch ((type & ~(WIDGET_MOUSE_EVENT_GBAR_MASK | WIDGET_MOUSE_EVENT_WIDGET_MASK))) { + case WIDGET_KEY_EVENT_FOCUS_IN | WIDGET_KEY_EVENT_MASK: + cmd = CMD_WIDGET_KEY_FOCUS_IN; + break; + case WIDGET_KEY_EVENT_FOCUS_OUT | WIDGET_KEY_EVENT_MASK: + cmd = CMD_WIDGET_KEY_FOCUS_OUT; + break; + case WIDGET_KEY_EVENT_UP | WIDGET_KEY_EVENT_MASK: + cmd = CMD_WIDGET_KEY_UP; + break; + case WIDGET_KEY_EVENT_DOWN | WIDGET_KEY_EVENT_MASK: + cmd = CMD_WIDGET_KEY_DOWN; + break; + case WIDGET_KEY_EVENT_SET | WIDGET_KEY_EVENT_MASK: + cmd = CMD_WIDGET_KEY_SET; + break; + case WIDGET_KEY_EVENT_UNSET | WIDGET_KEY_EVENT_MASK: + cmd = CMD_WIDGET_KEY_UNSET; + break; + default: + ErrPrint("Invalid event type\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + } else { + ErrPrint("Invalid event type\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!cb) { + cb = default_key_event_cb; + } + + ret = send_key_event(handle, (const char *)&cmd, info->keycode); + if (ret == (int)WIDGET_ERROR_NONE) { + handle->cbs.key_event.cb = cb; + handle->cbs.key_event.data = data; + handle->common->request.key_event = 1; + } + + return ret; +} + +EAPI const char *widget_viewer_get_filename(widget_h handle) +{ + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return NULL; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return NULL; + } + + if (!handle->common->id) { + ErrPrint("Handler is not valid\n"); + return NULL; + } + + if (handle->common->filename) { + return handle->common->filename; + } + + /* Oooops */ + set_last_result(WIDGET_ERROR_NONE); + return util_uri_to_path(handle->common->id); +} + +EAPI int widget_viewer_get_glance_bar_size(widget_h handle, int *w, int *h) +{ + int _w; + int _h; + + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!w) { + w = &_w; + } + if (!h) { + h = &_h; + } + + if (!handle->common->is_gbar_created) { + *w = handle->common->gbar.default_width; + *h = handle->common->gbar.default_height; + } else { + *w = handle->common->gbar.width; + *h = handle->common->gbar.height; + } + + return WIDGET_ERROR_NONE; +} + +EAPI int widget_viewer_get_size_type(widget_h handle, widget_size_type_e *size_type) +{ + int w; + int h; + int ret = WIDGET_ERROR_NONE; + widget_size_type_e result_size_type = WIDGET_SIZE_TYPE_UNKNOWN; + + if (!handle || handle->state != WIDGET_STATE_CREATE || size_type == NULL) { + ErrPrint("Handler is invalid\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + goto out; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + goto out; + } + + if (!handle->common->id) { + ErrPrint("Handler is not valid\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + goto out; + } + + w = handle->common->widget.width; + h = handle->common->widget.height; + + switch (handle->common->widget.type) { + case WIDGET_TYPE_BUFFER: + case WIDGET_TYPE_SCRIPT: + if (!fb_is_created(handle->common->widget.fb)) { + w = 0; + h = 0; + ret = WIDGET_ERROR_NOT_EXIST; + } + break; + default: + break; + } + + if ((ret = widget_service_get_size_type(w, h, &result_size_type)) != WIDGET_ERROR_NONE) { + ErrPrint("widget_service_get_size_type failed : %d\n", ret); + goto out; + } + +out: + + if (size_type) + *size_type = result_size_type; + + return ret; +} + +EAPI int widget_viewer_set_group(widget_h handle, const char *cluster, const char *category, widget_ret_cb cb, void *data) +{ + struct packet *packet; + unsigned int cmd = CMD_CHANGE_GROUP; + int ret; + + if (!handle) { + ErrPrint("Handler is NIL\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!cluster || !category || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Invalid argument\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Invalid argument\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Invalid argument\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (handle->common->request.group_changed) { + ErrPrint("Previous group changing request is not finished yet\n"); + return WIDGET_ERROR_RESOURCE_BUSY; + } + + if (!handle->common->is_user) { + ErrPrint("CA Livebox is not able to change the group\n"); + return WIDGET_ERROR_PERMISSION_DENIED; + } + + if (!strcmp(handle->common->cluster, cluster) && !strcmp(handle->common->category, category)) { + DbgPrint("No changes\n"); + return WIDGET_ERROR_ALREADY_EXIST; + } + + packet = packet_create((const char *)&cmd, "ssss", handle->common->pkgname, handle->common->id, cluster, category); + if (!packet) { + ErrPrint("Failed to build a param\n"); + return WIDGET_ERROR_FAULT; + } + + if (!cb) { + cb = default_group_changed_cb; + } + + ret = master_rpc_async_request(handle, packet, 0, set_group_ret_cb, NULL); + if (ret == (int)WIDGET_ERROR_NONE) { + handle->cbs.group_changed.cb = cb; + handle->cbs.group_changed.data = data; + handle->common->request.group_changed = 1; + } + + return ret; +} + +EAPI int widget_viewer_get_group(widget_h handle, const char **cluster, const char **category) +{ + if (!handle) { + ErrPrint("Handler is NIL\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!cluster || !category || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Invalid argument\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Invalid argument\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Invalid argument\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + *cluster = handle->common->cluster; + *category = handle->common->category; + return WIDGET_ERROR_NONE; +} + +EAPI int widget_viewer_get_supported_sizes(widget_h handle, int *cnt, widget_size_type_e *size_list) +{ + register int i; + register int j; + + if (!handle || !size_list) { + ErrPrint("Invalid argument, handle(%p), size_list(%p)\n", handle, size_list); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!cnt || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + for (j = i = 0; i < WIDGET_COUNT_OF_SIZE_TYPE; i++) { + if (handle->common->widget.size_list & (0x01 << i)) { + if (j == *cnt) { + break; + } + + size_list[j++] = (widget_size_type_e)(0x01 << i); + } + } + + *cnt = j; + return WIDGET_ERROR_NONE; +} + +EAPI const char *widget_viewer_get_pkgname(widget_h handle) +{ + if (!handle) { + ErrPrint("Handler is NIL\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + if (handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is not valid\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is not valid\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + set_last_result(WIDGET_ERROR_NONE); + return handle->common->pkgname; +} + +EAPI int widget_viewer_get_priority(widget_h handle, double *priority) +{ + int ret = WIDGET_ERROR_NONE; + double result_priority = -1.0f; + + if (!handle || handle->state != WIDGET_STATE_CREATE || priority == NULL) { + ErrPrint("Handler is invalid\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + goto out; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + goto out; + } + + if (!handle->common->id) { + ErrPrint("Handler is not valid (%p)\n", handle); + ret = WIDGET_ERROR_INVALID_PARAMETER; + goto out; + } + + result_priority = handle->common->widget.priority; + +out: + if (priority) + *priority = result_priority; + + return ret; +} + +EAPI int widget_delete_cluster(const char *cluster, widget_ret_cb cb, void *data) +{ + struct packet *packet; + struct cb_info *cbinfo; + unsigned int cmd = CMD_DELETE_CLUSTER; + int ret; + + packet = packet_create((const char *)&cmd, "s", cluster); + if (!packet) { + ErrPrint("Failed to build a param\n"); + return WIDGET_ERROR_FAULT; + } + + cbinfo = _widget_create_cb_info(cb, data); + if (!cbinfo) { + packet_destroy(packet); + return WIDGET_ERROR_FAULT; + } + + ret = master_rpc_async_request(NULL, packet, 0, _delete_cluster_cb, cbinfo); + if (ret < 0) { + _widget_destroy_cb_info(cbinfo); + } + + return ret; +} + +EAPI int widget_delete_category(const char *cluster, const char *category, widget_ret_cb cb, void *data) +{ + struct packet *packet; + struct cb_info *cbinfo; + unsigned int cmd = CMD_DELETE_CATEGORY; + int ret; + + packet = packet_create((const char *)&cmd, "ss", cluster, category); + if (!packet) { + ErrPrint("Failed to build a param\n"); + return WIDGET_ERROR_FAULT; + } + + cbinfo = _widget_create_cb_info(cb, data); + if (!cbinfo) { + packet_destroy(packet); + return WIDGET_ERROR_FAULT; + } + + ret = master_rpc_async_request(NULL, packet, 0, _delete_category_cb, cbinfo); + if (ret < 0) { + _widget_destroy_cb_info(cbinfo); + } + + return ret; +} + +EAPI int widget_viewer_get_type(widget_h handle, int gbar, widget_type_e *widget_type) +{ + int ret = WIDGET_ERROR_INVALID_PARAMETER; + widget_type_e result_widget_type = WIDGET_CONTENT_TYPE_INVALID; + + if (!handle || handle->state != WIDGET_STATE_CREATE || widget_type == NULL) { + ErrPrint("Handler is invalid\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + result_widget_type = WIDGET_CONTENT_TYPE_INVALID; + goto out; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + result_widget_type = WIDGET_CONTENT_TYPE_INVALID; + goto out; + } + + if (!handle->common->id) { + ErrPrint("Handler is not valid\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + result_widget_type = WIDGET_CONTENT_TYPE_INVALID; + goto out; + } + + if (gbar) { + switch (handle->common->gbar.type) { + case GBAR_TYPE_TEXT: + result_widget_type = WIDGET_CONTENT_TYPE_TEXT; + break; + case GBAR_TYPE_BUFFER: + case GBAR_TYPE_SCRIPT: + { + const char *id; + id = fb_id(handle->common->gbar.fb); + if (id && !strncasecmp(id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP))) { + result_widget_type = WIDGET_CONTENT_TYPE_RESOURCE_ID; + break; + } + } + result_widget_type = WIDGET_CONTENT_TYPE_BUFFER; + break; + case GBAR_TYPE_UIFW: + result_widget_type = WIDGET_CONTENT_TYPE_UIFW; + break; + default: + break; + } + } else { + switch (handle->common->widget.type) { + case WIDGET_TYPE_FILE: + result_widget_type = WIDGET_CONTENT_TYPE_IMAGE; + break; + case WIDGET_TYPE_BUFFER: + case WIDGET_TYPE_SCRIPT: + { + const char *id; + id = fb_id(handle->common->widget.fb); + if (id && !strncasecmp(id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP))) { + result_widget_type = WIDGET_CONTENT_TYPE_RESOURCE_ID; + break; + } + } + result_widget_type = WIDGET_CONTENT_TYPE_BUFFER; + break; + case WIDGET_TYPE_TEXT: + result_widget_type = WIDGET_CONTENT_TYPE_TEXT; + break; + case WIDGET_TYPE_UIFW: + result_widget_type = WIDGET_CONTENT_TYPE_UIFW; + break; + default: + break; + } + } + +out: + if (widget_type) + *widget_type = result_widget_type; + return ret; +} + +EAPI int widget_viewer_set_text_handler(widget_h handle, int gbar, struct widget_script_operators *ops) +{ + if (!handle) { + ErrPrint("Handler is NIL\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (gbar) { + memcpy(&handle->cbs.gbar_ops, ops, sizeof(*ops)); + } else { + memcpy(&handle->cbs.widget_ops, ops, sizeof(*ops)); + } + + return WIDGET_ERROR_NONE; +} + +EAPI int widget_viewer_acquire_extra_resource_id(widget_h handle, int gbar, int idx, widget_ret_cb cb, void *data) +{ + if (idx < 0) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Invalid handle\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (gbar) { + /** + * This can be called from extra_resource_created event. + * and it can be called before get the created event. + * then we didn't know this handle's buffer type yet + * so we cannot use its type to validate handle + * + * handle->common.gbar.type == unknown + */ + if (!handle->common->gbar.extra_buffer) { + return WIDGET_ERROR_NOT_EXIST; + } + + if (idx >= conf_extra_buffer_count()) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + return widget_acquire_gbar_extra_pixmap(handle, idx, cb, data); + } else { + /** + * This can be called from extra_resource_created event. + * and it can be called before get the created event. + * then we didn't know this handle's buffer type yet + * so we cannot use its type to validate handle + * + * handle->common.widget.type == unknown + */ + if (!handle->common->widget.extra_buffer) { + ErrPrint("Extra buffer is not prepared\n"); + return WIDGET_ERROR_NOT_EXIST; + } + + if (idx >= conf_extra_buffer_count()) { + ErrPrint("Invalid parameter: %d / %d\n", idx, conf_extra_buffer_count()); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + return widget_acquire_widget_extra_pixmap(handle, idx, cb, data); + } +} + +EAPI int widget_viewer_acquire_resource_id(widget_h handle, int gbar, widget_ret_cb cb, void *data) +{ + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Invalid handle\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (gbar) { + if (handle->common->gbar.type != GBAR_TYPE_SCRIPT && handle->common->gbar.type != GBAR_TYPE_BUFFER) { + ErrPrint("Handler is not valid type\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + return widget_acquire_gbar_pixmap(handle, cb, data); + } else { + if (handle->common->widget.type != WIDGET_TYPE_SCRIPT && handle->common->widget.type != WIDGET_TYPE_BUFFER) { + ErrPrint("Handler is not valid type\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + return _widget_acquire_widget_pixmap(handle, cb, data); + } +} + +/*! + * \note + * Do not check the state of handle and common-handle. + * If this function is used in the deleted callback, + * the handle and common-handle's state would be DELETE + * if this function check the state of handles, + * user cannot release the pixmap. + */ +EAPI int widget_viewer_release_resource_id(widget_h handle, int gbar, unsigned int resource_id) +{ + struct packet *packet; + const char *pkgname; + const char *id; + unsigned int cmd; + + if (resource_id == 0 /* || handle->state != WIDGET_STATE_CREATE */) { + ErrPrint("Pixmap is invalid [%d]\n", resource_id); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (gbar) { + if (!handle) { + /*! + * \note + * Even though the handle is NULL, we should send the release request to the master. + * Because the resource_id resource can be released after the handle is destroyed. + * Pixmap resource is used by client. and it cannot be guaranteed to release resource_id. + * In some cases, the resource_id can be released after the handle is deleted. + * + * Its implementation is up to the viewer app. + * But we cannot force it to use only with valid handle. + */ + DbgPrint("Using NULL handle\n"); + pkgname = NULL; + id = NULL; + /*! + * \note + * Master will try to find the buffer handle using given resource_id. if the pkgname and id is not valid. + */ + } else { + if (!handle->common /* || handle-common->state != WIDGET_STATE_CREATE */) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Invalid handle\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + /** + * This can be called from extra_resource_created event. + * and it can be called before get the created event. + * then we didn't know this handle's buffer type yet + * so we cannot use its type to validate handle + * + * handle->common.gbar.type == unknown + */ + + pkgname = handle->common->pkgname; + id = handle->common->id; + } + + cmd = CMD_GBAR_RELEASE_PIXMAP; + } else { + if (!handle) { + /*! + * \note + * Even though the handle is NULL, we should send the release request to the master. + * Because the resource_id resource can be released after the handle is destroyed. + * Pixmap resource is used by client. and it cannot be guaranteed to release resource_id. + * In some cases, the resource_id can be released after the handle is deleted. + * + * Its implementation is up to the viewer app. + * But we cannot force it to use only with valid handle. + */ + DbgPrint("Using NULL handle\n"); + pkgname = NULL; + id = NULL; + /*! + * \note + * Master will try to find the buffer handle using given resource_id. if the pkgname and id is not valid. + */ + } else { + if (!handle->common /* || handle->common->state != WIDGET_STATE_CREATE */) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Invalid handle\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + /** + * This can be called from extra_resource_created event. + * and it can be called before get the created event. + * then we didn't know this handle's buffer type yet + * so we cannot use its type to validate handle + * + * handle->common.widget.type == unknown + */ + + pkgname = handle->common->pkgname; + id = handle->common->id; + } + + cmd = CMD_WIDGET_RELEASE_PIXMAP; + } + + packet = packet_create_noack((const char *)&cmd, "ssi", pkgname, id, resource_id); + if (!packet) { + ErrPrint("Failed to build a param\n"); + return WIDGET_ERROR_FAULT; + } + + return master_rpc_request_only(handle, packet); +} + +EAPI unsigned int widget_extra_resource_id(const widget_h handle, int gbar, int idx) +{ + if (idx < 0) { + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return 0u; + } + + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return 0u; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return 0u; + } + + if (!handle->common->id) { + ErrPrint("Invalid handle\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return 0u; + } + + if (gbar) { + /** + * This can be called from extra_resource_created event. + * and it can be called before get the created event. + * then we didn't know this handle's buffer type yet + * so we cannot use its type to validate handle + * + * handle->common.gbar.type == unknown + */ + + if (!handle->common->gbar.extra_buffer || handle->common->gbar.last_extra_buffer_idx < 0) { + set_last_result(WIDGET_ERROR_NOT_EXIST); + return 0u; + } + + return handle->common->gbar.extra_buffer[handle->common->gbar.last_extra_buffer_idx]; + } else { + /** + * This can be called from extra_resource_created event. + * and it can be called before get the created event. + * then we didn't know this handle's buffer type yet + * so we cannot use its type to validate handle + * + * handle->common.widget.type == unknown + */ + + if (!handle->common->widget.extra_buffer || handle->common->widget.last_extra_buffer_idx < 0) { + set_last_result(WIDGET_ERROR_NOT_EXIST); + return 0u; + } + + return handle->common->widget.extra_buffer[handle->common->widget.last_extra_buffer_idx]; + } +} + +EAPI int widget_viewer_get_resource_id(const widget_h handle, int gbar, unsigned int *resouce_id) +{ + const char *id; + unsigned int pixmap = 0u; + int ret = WIDGET_ERROR_NONE; + + if (!handle || handle->state != WIDGET_STATE_CREATE || resouce_id == NULL) { + ErrPrint("Handler is invalid\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + goto out; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + goto out; + } + + if (!handle->common->id) { + ErrPrint("Invalid handle\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + goto out; + } + + if (gbar) { + if (handle->common->gbar.type != GBAR_TYPE_SCRIPT && handle->common->gbar.type != GBAR_TYPE_BUFFER) { + ErrPrint("Invalid handle\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + goto out; + } + + id = fb_id(handle->common->gbar.fb); + if (id && sscanf(id, SCHEMA_PIXMAP "%u", &pixmap) != 1) { + ErrPrint("PIXMAP Id is not valid\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + goto out; + } + } + else { + if (handle->common->widget.type != WIDGET_TYPE_SCRIPT && handle->common->widget.type != WIDGET_TYPE_BUFFER) { + ErrPrint("Invalid handle\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + goto out; + } + + id = fb_id(handle->common->widget.fb); + if (id && sscanf(id, SCHEMA_PIXMAP "%u", &pixmap) != 1) { + ErrPrint("PIXMAP Id is not valid\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + goto out; + } + } +out: + if (resouce_id) + *resouce_id = pixmap; + + return ret; +} + +EAPI void *widget_viewer_acquire_buffer(widget_h handle, int gbar) +{ + if (gbar) { + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + if (!handle->common->id) { + ErrPrint("Invalid handle\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + if (handle->common->gbar.type != GBAR_TYPE_SCRIPT && handle->common->gbar.type != GBAR_TYPE_BUFFER) { + ErrPrint("Handler is not valid type\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + return fb_acquire_buffer(handle->common->gbar.fb); + } else { + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + if (!handle->common->id) { + ErrPrint("Invalid handle\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + if (handle->common->widget.type != WIDGET_TYPE_SCRIPT && handle->common->widget.type != WIDGET_TYPE_BUFFER) { + ErrPrint("Handler is not valid type\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + return fb_acquire_buffer(handle->common->widget.fb); + } +} + +EAPI int widget_viewer_release_buffer(void *buffer) +{ + return fb_release_buffer(buffer); +} + +EAPI int widget_viewer_get_buffer_reference_count(void *buffer) +{ + return fb_refcnt(buffer); +} + +EAPI int widget_viewer_get_buffer_size(widget_h handle, int gbar) +{ + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Invalid handle\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (gbar) { + return fb_size(handle->common->gbar.fb); + } else { + return fb_size(handle->common->widget.fb); + } +} + +EAPI int widget_viewer_is_created_by_user(widget_h handle) +{ + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Invalid handle\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + return handle->common->is_user; +} + +EAPI int widget_viewer_set_pinup(widget_h handle, int flag, widget_ret_cb cb, void *data) +{ + struct packet *packet; + unsigned int cmd = CMD_PINUP_CHANGED; + int ret; + + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Invalid handle\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (handle->common->request.pinup) { + ErrPrint("Previous pinup request is not finished\n"); + return WIDGET_ERROR_RESOURCE_BUSY; + } + + if (handle->common->is_pinned_up == flag) { + DbgPrint("No changes\n"); + return WIDGET_ERROR_ALREADY_EXIST; + } + + packet = packet_create((const char *)&cmd, "ssi", handle->common->pkgname, handle->common->id, flag); + if (!packet) { + ErrPrint("Failed to build a param\n"); + return WIDGET_ERROR_FAULT; + } + + if (!cb) { + cb = default_pinup_cb; + } + + ret = master_rpc_async_request(handle, packet, 0, pinup_done_cb, NULL); + if (ret == (int)WIDGET_ERROR_NONE) { + handle->cbs.pinup.cb = cb; + handle->cbs.pinup.data = data; + handle->common->request.pinup = 1; + } + + return ret; +} + +EAPI int widget_viewer_is_pinned_up(widget_h handle) +{ + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Invalid handle\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + return handle->common->is_pinned_up; +} + +EAPI int widget_viewer_has_pinup(widget_h handle) +{ + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Invalid handle\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + return handle->common->widget.pinup_supported; +} + +EAPI int widget_viewer_set_data(widget_h handle, void *data) +{ + if (!handle) { + ErrPrint("Handler is NIL\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + handle->data = data; + return WIDGET_ERROR_NONE; +} + +EAPI void *widget_viewer_get_data(widget_h handle) +{ + if (!handle) { + ErrPrint("Handler is NIL\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + if (handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + return handle->data; +} + +EAPI const char *widget_viewer_get_content_string(widget_h handle) +{ + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Invalid handle\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + set_last_result(WIDGET_ERROR_NONE); + return handle->common->content; +} + +EAPI const char *widget_viewer_get_title_string(widget_h handle) +{ + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Invalid handle\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + set_last_result(WIDGET_ERROR_NONE); + return handle->common->title; +} + +EAPI int widget_viewer_emit_text_signal(widget_h handle, widget_text_signal_s event_info, widget_ret_cb cb, void *data) +{ + struct packet *packet; + struct cb_info *cbinfo; + unsigned int cmd = CMD_TEXT_SIGNAL; + int ret; + const char *signal_name; + const char *source; + + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (handle->common->widget.type != WIDGET_TYPE_TEXT && handle->common->gbar.type != GBAR_TYPE_TEXT) { + DbgPrint("Not a text box, but send signal\n"); + } + + if (!handle->common->id) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!event_info) { + ErrPrint("Invalid event info\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + signal_name = event_info->signal_name; + if (!signal_name) { + signal_name = ""; + } + + source = event_info->source; + if (!source) { + source = ""; + } + + packet = packet_create((const char *)&cmd, "ssssdddd", + handle->common->pkgname, handle->common->id, + signal_name, source, + event_info->geometry.sx, event_info->geometry.sy, + event_info->geometry.ex, event_info->geometry.ey); + if (!packet) { + ErrPrint("Failed to build a param\n"); + return WIDGET_ERROR_FAULT; + } + + cbinfo = _widget_create_cb_info(cb, data); + if (!cbinfo) { + packet_destroy(packet); + return WIDGET_ERROR_FAULT; + } + + ret = master_rpc_async_request(handle, packet, 0, text_signal_cb, cbinfo); + if (ret < 0) { + _widget_destroy_cb_info(cbinfo); + } + + return ret; +} + +EAPI int widget_viewer_subscribe_group(const char *cluster, const char *category) +{ + struct packet *packet; + unsigned int cmd = CMD_SUBSCRIBE; + + /*! + * \todo + * Validate the group info using DB + * If the group info is not valid, do not send this request + */ + + packet = packet_create_noack((const char *)&cmd, "ss", cluster ? cluster : "", category ? category : ""); + if (!packet) { + ErrPrint("Failed to create a packet\n"); + return WIDGET_ERROR_FAULT; + } + + return master_rpc_request_only(NULL, packet); +} + +EAPI int widget_viewer_unsubscribe_group(const char *cluster, const char *category) +{ + struct packet *packet; + unsigned int cmd = CMD_UNSUBSCRIBE; + + /*! + * \todo + * Validate the group info using DB + * If the group info is not valid, do not send this request + * AND Check the subscribed or not too + */ + + packet = packet_create_noack((const char *)&cmd, "ss", cluster ? cluster : "", category ? category : ""); + if (!packet) { + ErrPrint("Failed to create a packet\n"); + return WIDGET_ERROR_FAULT; + } + + return master_rpc_request_only(NULL, packet); +} + +EAPI int widget_viewer_subscribe_category(const char *category) +{ + struct packet *packet; + unsigned int cmd = CMD_SUBSCRIBE_CATEGORY; + + if (!category) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + packet = packet_create_noack((const char *)&cmd, "s", category); + if (!packet) { + ErrPrint("Failed to create a packet\n"); + return WIDGET_ERROR_FAULT; + } + + return master_rpc_request_only(NULL, packet); +} + +EAPI int widget_viewer_unsubscribe_category(const char *category) +{ + struct packet *packet; + unsigned int cmd = CMD_UNSUBSCRIBE_CATEGORY; + + if (!category) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + packet = packet_create_noack((const char *)&cmd, "s", category); + if (!packet) { + ErrPrint("Failed to create a packet\n"); + return WIDGET_ERROR_FAULT; + } + + return master_rpc_request_only(NULL, packet); +} + +EAPI int widget_viewer_refresh(widget_h handle, int force) +{ + struct packet *packet; + unsigned int cmd = CMD_UPDATE; + + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + packet = packet_create_noack((const char *)&cmd, "ssi", handle->common->pkgname, handle->common->id, force); + if (!packet) { + ErrPrint("Failed to create a packet\n"); + return WIDGET_ERROR_FAULT; + } + + return master_rpc_request_only(handle, packet); +} + +EAPI int widget_viewer_refresh_group(const char *cluster, const char *category, int force) +{ + struct packet *packet; + unsigned int cmd = CMD_REFRESH_GROUP; + + if (!cluster || !category) { + ErrPrint("Invalid argument\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + packet = packet_create_noack((const char *)&cmd, "ssi", cluster, category, force); + if (!packet) { + ErrPrint("Failed to create a packet\n"); + return WIDGET_ERROR_FAULT; + } + + return master_rpc_request_only(NULL, packet); +} + +EAPI int widget_viewer_set_visibility(widget_h handle, widget_visible_state_e state) +{ + int old_state; + int ret; + + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->is_user) { + /* System cluster widget cannot be changed its visible states */ + if (state == WIDGET_HIDE_WITH_PAUSE) { + ErrPrint("CA Livebox is not able to change the visibility\n"); + return WIDGET_ERROR_PERMISSION_DENIED; + } + } + + if (handle->visible == state) { + DbgPrint("%s has no changes\n", handle->common->pkgname); + return WIDGET_ERROR_ALREADY_EXIST; + } + + old_state = handle->visible; + handle->visible = state; + + ret = _widget_set_visibility(handle, state); + if (ret < 0) { + handle->visible = old_state; + } + + return ret; +} + +EAPI widget_visible_state_e widget_viewer_get_visibility(widget_h handle) +{ + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is invalid\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return WIDGET_VISIBLE_ERROR; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is not valid\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return WIDGET_VISIBLE_ERROR; + } + + if (!handle->common->id) { + ErrPrint("Handler is not valid\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return WIDGET_VISIBLE_ERROR; + } + + return handle->visible; +} + +EAPI int widget_viewer_notify_paused_status_of_viewer(void) +{ + struct packet *packet; + unsigned int cmd = CMD_CLIENT_PAUSED; + + packet = packet_create_noack((const char *)&cmd, "d", util_timestamp()); + if (!packet) { + ErrPrint("Failed to create a pause packet\n"); + return WIDGET_ERROR_FAULT; + } + + return master_rpc_request_only(NULL, packet); +} + +EAPI int widget_viewer_notify_resumed_status_of_viewer(void) +{ + struct packet *packet; + unsigned int cmd = CMD_CLIENT_RESUMED; + + packet = packet_create_noack((const char *)&cmd, "d", util_timestamp()); + if (!packet) { + ErrPrint("Failed to create a resume packet\n"); + return WIDGET_ERROR_FAULT; + } + + return master_rpc_request_only(NULL, packet); +} + +EAPI int widget_viewer_notify_orientation_of_viewer(int orientation) +{ + struct packet *packet; + unsigned int cmd = CMD_ORIENTATION; + + if (orientation < 0 || orientation > 360) { + ErrPrint("Invalid parameter: %d\n", orientation); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + packet = packet_create_noack((const char *)&cmd, "di", util_timestamp(), orientation); + if (!packet) { + ErrPrint("Failed to create a orientation packet\n"); + return WIDGET_ERROR_FAULT; + } + + return master_rpc_request_only(NULL, packet); +} + +EAPI int widget_viewer_sync_buffer(widget_h handle, int gbar) +{ + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Invalid handle\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Invalid handle\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Invalid handle\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (gbar) { + return _widget_sync_gbar_fb(handle->common); + } else { + return _widget_sync_widget_fb(handle->common); + } +} + +EAPI const char *widget_viewer_get_alternative_icon(widget_h handle) +{ + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is not valid[%p]\n", handle); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is not valid\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + return handle->common->alt.icon; +} + +EAPI const char *widget_viewer_get_alternative_name(widget_h handle) +{ + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is not valid[%p]\n", handle); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is not valid\n"); + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + return NULL; + } + + return handle->common->alt.name; +} + +EAPI int widget_viewer_acquire_buffer_lock(widget_h handle, int is_gbar) +{ + int ret = WIDGET_ERROR_NONE; + + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is not valid[%p]\n", handle); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Handler is not valid\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Handler is not valid[%p]\n", handle); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (is_gbar) { + ret = widget_service_acquire_lock(handle->common->gbar.lock); + } else { + ret = widget_service_acquire_lock(handle->common->widget.lock); + } + + return ret == 0 ? WIDGET_ERROR_NONE : WIDGET_ERROR_FAULT; +} + +EAPI int widget_viewer_release_buffer_lock(widget_h handle, int is_gbar) +{ + int ret = WIDGET_ERROR_NONE; + + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Invalid handle\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Invalid handle\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Handler is not valid[%p]\n", handle); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (is_gbar) { + ret = widget_service_release_lock(handle->common->gbar.lock); + } else { + ret = widget_service_release_lock(handle->common->widget.lock); + } + + return ret == 0 ? WIDGET_ERROR_NONE : WIDGET_ERROR_FAULT; +} + +EAPI int widget_viewer_set_option(widget_option_type_e option, int state) +{ + int ret = WIDGET_ERROR_NONE; + + switch (option) { + case WIDGET_OPTION_MANUAL_SYNC: + conf_set_manual_sync(state); + break; + case WIDGET_OPTION_FRAME_DROP_FOR_RESIZE: + conf_set_frame_drop_for_resizing(state); + break; + case WIDGET_OPTION_SHARED_CONTENT: + conf_set_shared_content(state); + break; + case WIDGET_OPTION_DIRECT_UPDATE: + if (s_info.init_count) { + DbgPrint("Already intialized, this option is not applied\n"); + } + conf_set_direct_update(state); + break; + case WIDGET_OPTION_EXTRA_BUFFER_CNT: + ErrPrint("Permission denied\n"); + ret = WIDGET_ERROR_PERMISSION_DENIED; + break; + default: + ret = WIDGET_ERROR_INVALID_PARAMETER; + break; + } + + return ret; +} + +EAPI int widget_viewer_get_option(widget_option_type_e option) +{ + int ret; + + set_last_result(WIDGET_ERROR_NONE); + switch (option) { + case WIDGET_OPTION_MANUAL_SYNC: + ret = conf_manual_sync(); + break; + case WIDGET_OPTION_FRAME_DROP_FOR_RESIZE: + ret = conf_frame_drop_for_resizing(); + break; + case WIDGET_OPTION_SHARED_CONTENT: + ret = conf_shared_content(); + break; + case WIDGET_OPTION_DIRECT_UPDATE: + ret = conf_direct_update(); + break; + case WIDGET_OPTION_EXTRA_BUFFER_CNT: + ret = conf_extra_buffer_count(); + break; + default: + ret = WIDGET_ERROR_INVALID_PARAMETER; + set_last_result(WIDGET_ERROR_INVALID_PARAMETER); + break; + } + + return ret; +} + +EAPI int widget_viewer_set_auto_launch_handler(widget_auto_launch_handler_cb widget_launch_handler, void *data) +{ + s_info.launch.handle = widget_launch_handler; + s_info.launch.data = data; + + return WIDGET_ERROR_NONE; +} + +EAPI int widget_viewer_get_damaged_region(widget_h handle, int gbar, const widget_damage_region_s *region) +{ + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Invalid handle\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Invalid handle\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Handler is not valid[%p]\n", handle); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (gbar) { + region = &handle->common->widget.last_damage; + } else { + region = &handle->common->gbar.last_damage; + } + + return WIDGET_ERROR_NONE; +} + +EAPI int widget_viewer_get_affected_extra_buffer(widget_h handle, int gbar, int *idx, unsigned int *resource_id) +{ + int _idx; + unsigned int _resource_id; + + if (!handle || handle->state != WIDGET_STATE_CREATE) { + ErrPrint("Invalid handle\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Invalid handle\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Handler is not valid[%p]\n", handle); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!idx) { + idx = &_idx; + } + + if (!resource_id) { + resource_id = &_resource_id; + } + + if (gbar) { + if (!handle->common->gbar.extra_buffer || handle->common->gbar.last_extra_buffer_idx < 0) { + return WIDGET_ERROR_NOT_EXIST; + } + + *idx = handle->common->gbar.last_extra_buffer_idx; + *resource_id = handle->common->gbar.extra_buffer[*idx]; + } else { + if (!handle->common->widget.extra_buffer || handle->common->widget.last_extra_buffer_idx < 0) { + return WIDGET_ERROR_NOT_EXIST; + } + + *idx = handle->common->widget.last_extra_buffer_idx; + *resource_id = handle->common->widget.extra_buffer[*idx]; + } + + return WIDGET_ERROR_NONE; +} + +EAPI int widget_viewer_get_instance_id(widget_h handle, char **instance_id) +{ + if (!handle || handle->state != WIDGET_STATE_CREATE || !instance_id) { + ErrPrint("Invalid handle\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common || handle->common->state != WIDGET_STATE_CREATE) { + ErrPrint("Invalid handle\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (!handle->common->id) { + ErrPrint("Handler is not valid[%p]\n", handle); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + *instance_id = strdup(handle->common->id); + if (!*instance_id) { + ErrPrint("Out of memory: %d\n", errno); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + return WIDGET_ERROR_NONE; +} + +/* End of a file */ diff --git a/widget_viewer/src/widget_internal.c b/widget_viewer/src/widget_internal.c new file mode 100755 index 0000000..e556e08 --- /dev/null +++ b/widget_viewer/src/widget_internal.c @@ -0,0 +1,1061 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include "dlist.h" +#include "debug.h" +#include "widget_viewer.h" +#include "widget_viewer_internal.h" +#include "fb.h" +#include "conf.h" +#include "util.h" +#include "master_rpc.h" + +int errno; + +typedef enum event_state { + INFO_STATE_CALLBACK_IN_IDLE = 0x00, + INFO_STATE_CALLBACK_IN_PROCESSING = 0x01 +} event_state_e; + +struct event_info { + int is_deleted; + int (*handler)(widget_h handler, widget_event_type_e event, void *data); + void *user_data; +}; + +struct fault_info { + int is_deleted; + int (*handler)(widget_fault_type_e event, const char *pkgname, const char *filename, const char *func, void *data); + void *user_data; +}; + +static struct info { + struct dlist *widget_common_list; + struct dlist *widget_list; + struct dlist *event_list; + struct dlist *fault_list; + event_state_e event_state; + event_state_e fault_state; +} s_info = { + .widget_common_list = NULL, + .widget_list = NULL, + .event_list = NULL, + .fault_list = NULL, + .event_state = INFO_STATE_CALLBACK_IN_IDLE, + .fault_state = INFO_STATE_CALLBACK_IN_IDLE, +}; + +static inline void default_delete_cb(widget_h handler, int ret, void *data) +{ + DbgPrint("Default deleted event handler: %d\n", ret); +} + +static void del_ret_cb(widget_h handler, const struct packet *result, void *data) +{ + struct cb_info *info = data; + int ret; + widget_ret_cb cb; + void *cbdata; + + cb = info->cb; + cbdata = info->data; + _widget_destroy_cb_info(info); + + if (!result) { + ErrPrint("Connection lost?\n"); + ret = WIDGET_ERROR_FAULT; + } else if (packet_get(result, "i", &ret) != 1) { + ErrPrint("Invalid argument\n"); + ret = WIDGET_ERROR_INVALID_PARAMETER; + } + + if (ret == 0) { + handler->cbs.deleted.cb = cb; + handler->cbs.deleted.data = cbdata; + } else if (cb) { + cb(handler, ret, cbdata); + } + + /*! + * \note + * Do not call the deleted callback from here. + * master will send the "deleted" event. + * Then invoke this callback. + * + * if (handler->cbs.deleted.cb) + * handler->cbs.deleted.cb(handler, ret, handler->cbs.deleted.data); + */ +} + +struct widget_common *_widget_create_common_handle(widget_h handle, const char *pkgname, const char *cluster, const char *category) +{ + struct widget_common *common; + + common = calloc(1, sizeof(*common)); + if (!common) { + ErrPrint("Heap: %d\n", errno); + set_last_result(WIDGET_ERROR_OUT_OF_MEMORY); + return NULL; + } + + common->pkgname = strdup(pkgname); + if (!common->pkgname) { + free(common); + set_last_result(WIDGET_ERROR_OUT_OF_MEMORY); + return NULL; + } + + common->cluster = strdup(cluster); + if (!common->cluster) { + ErrPrint("Error: %d\n", errno); + free(common->pkgname); + free(common); + set_last_result(WIDGET_ERROR_OUT_OF_MEMORY); + return NULL; + } + + common->category = strdup(category); + if (!common->category) { + ErrPrint("Error: %d\n", errno); + free(common->cluster); + free(common->pkgname); + free(common); + set_last_result(WIDGET_ERROR_OUT_OF_MEMORY); + return NULL; + } + + /* Data provider will set this */ + common->widget.type = WIDGET_TYPE_FILE; + common->gbar.type = GBAR_TYPE_SCRIPT; + + /* Used for handling the mouse event on a box */ + common->widget.mouse_event = 0; + + /* Cluster infomration is not determined yet */ + common->nr_of_sizes = 0x01; + + common->timestamp = util_timestamp(); + common->is_user = 1; + common->delete_type = WIDGET_DELETE_PERMANENTLY; + + common->gbar.lock = NULL; + common->gbar.last_extra_buffer_idx = WIDGET_UNKNOWN_BUFFER; + + common->widget.lock = NULL; + common->widget.last_extra_buffer_idx = WIDGET_UNKNOWN_BUFFER; + + common->state = WIDGET_STATE_CREATE; + common->visible = WIDGET_HIDE_WITH_PAUSE; + + s_info.widget_common_list = dlist_append(s_info.widget_common_list, common); + return common; +} + +int _widget_destroy_common_handle(struct widget_common *common) +{ + dlist_remove_data(s_info.widget_common_list, common); + + common->state = WIDGET_STATE_DESTROYED; + + if (common->filename) { + (void)util_unlink(common->filename); + } + + free(common->cluster); + free(common->category); + free(common->id); + free(common->pkgname); + free(common->filename); + free(common->widget.auto_launch); + free(common->alt.icon); + free(common->alt.name); + + if (common->widget.fb) { + fb_destroy(common->widget.fb); + common->widget.fb = NULL; + } + + if (common->gbar.fb) { + fb_destroy(common->gbar.fb); + common->gbar.fb = NULL; + } + + return 0; +} + +int _widget_common_ref(struct widget_common *common, widget_h handle) +{ + common->widget_list = dlist_append(common->widget_list, handle); + common->refcnt++; + + return common->refcnt; +} + +int _widget_common_unref(struct widget_common *common, widget_h handle) +{ + int refcnt; + dlist_remove_data(common->widget_list, handle); + refcnt = --common->refcnt; + + return refcnt; +} + +int _widget_set_group(struct widget_common *common, const char *cluster, const char *category) +{ + void *pc = NULL; + void *ps = NULL; + + if (cluster) { + pc = strdup(cluster); + if (!pc) { + ErrPrint("Heap: %d (cluster: %s)\n", errno, cluster); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + } + + if (category) { + ps = strdup(category); + if (!ps) { + ErrPrint("Heap: %d (category: %s)\n", errno, category); + free(pc); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + } + + if (common->cluster) { + free(common->cluster); + } + + if (common->category) { + free(common->category); + } + + common->cluster = pc; + common->category = ps; + + return WIDGET_ERROR_NONE; +} + +void _widget_set_size(struct widget_common *common, int w, int h) +{ + widget_size_type_e size_type; + + common->widget.width = w; + common->widget.height = h; + + widget_service_get_size_type(w, h, &size_type); + if (size_type != WIDGET_SIZE_TYPE_UNKNOWN) { + widget_service_get_need_of_mouse_event(common->pkgname, size_type, (bool*)&common->widget.mouse_event); + } +} + +void _widget_set_update_mode(struct widget_common *common, int active_mode) +{ + common->is_active_update = active_mode; +} + +void _widget_set_gbarsize(struct widget_common *common, int w, int h) +{ + common->gbar.width = w; + common->gbar.height = h; +} + +void _widget_set_default_gbarsize(struct widget_common *common, int w, int h) +{ + common->gbar.default_width = w; + common->gbar.default_height = h; +} + +void _widget_invoke_fault_handler(widget_fault_type_e event, const char *pkgname, const char *file, const char *func) +{ + struct dlist *l; + struct dlist *n; + struct fault_info *info; + + s_info.fault_state = INFO_STATE_CALLBACK_IN_PROCESSING; + + dlist_foreach_safe(s_info.fault_list, l, n, info) { + if (!info->is_deleted && info->handler(event, pkgname, file, func, info->user_data) == EXIT_FAILURE) { + info->is_deleted = 1; + } + + if (info->is_deleted) { + s_info.fault_list = dlist_remove(s_info.fault_list, l); + free(info); + } + } + + s_info.fault_state &= ~INFO_STATE_CALLBACK_IN_PROCESSING; +} + +void _widget_invoke_event_handler(widget_h handler, widget_event_type_e event) +{ + struct dlist *l; + struct dlist *n; + struct event_info *info; + + if (event == WIDGET_EVENT_WIDGET_UPDATED && handler->common->refcnt > 1) { + if (handler->visible != WIDGET_SHOW) { + DbgPrint("Update requested(pending) - %s\n", handler->common->pkgname); + handler->paused_updating++; + return; + } else { + handler->paused_updating = 0; + } + } + + s_info.event_state = INFO_STATE_CALLBACK_IN_PROCESSING; + + dlist_foreach_safe(s_info.event_list, l, n, info) { + if (!info->is_deleted && info->handler(handler, event, info->user_data) == EXIT_FAILURE) { + DbgPrint("Event handler returns EXIT_FAILURE\n"); + info->is_deleted = 1; + } + + if (info->is_deleted) { + s_info.event_list = dlist_remove(s_info.event_list, l); + free(info); + } + } + + s_info.event_state &= ~INFO_STATE_CALLBACK_IN_PROCESSING; +} + +struct widget_common *_widget_find_common_handle(const char *pkgname, const char *id) +{ + struct dlist *l; + struct widget_common *common; + + dlist_foreach(s_info.widget_common_list, l, common) { + if (!common->id) { + continue; + } + + if (!strcmp(common->pkgname, pkgname) && !strcmp(common->id, id)) { + return common; + } + } + + return NULL; +} + +struct widget_common *_widget_find_common_handle_by_timestamp(double timestamp) +{ + struct dlist *l; + struct widget_common *common; + + dlist_foreach(s_info.widget_common_list, l, common) { + if (common->timestamp == timestamp) { + return common; + } + } + + return NULL; +} + +widget_h _widget_new_widget(const char *pkgname, const char *id, double timestamp, const char *cluster, const char *category) +{ + widget_h handler; + + handler = calloc(1, sizeof(*handler)); + if (!handler) { + ErrPrint("Failed to create a new widget\n"); + return NULL; + } + + handler->common = _widget_create_common_handle(handler, pkgname, cluster, category); + if (!handler->common) { + ErrPrint("Heap: %d\n", errno); + free(handler); + return NULL; + } + + _widget_common_ref(handler->common, handler); + _widget_set_id(handler->common, id); + handler->common->timestamp = timestamp; + handler->common->state = WIDGET_STATE_CREATE; + handler->visible = WIDGET_HIDE_WITH_PAUSE; + handler->state = WIDGET_STATE_CREATE; + handler = _widget_ref(handler); + s_info.widget_list = dlist_append(s_info.widget_list, handler); + + return _widget_ref(handler); +} + +int _widget_delete_all(void) +{ + struct dlist *l; + struct dlist *n; + widget_h handler; + + dlist_foreach_safe(s_info.widget_list, l, n, handler) { + _widget_invoke_event_handler(handler, WIDGET_EVENT_DELETED); + _widget_unref(handler, 1); + } + + return WIDGET_ERROR_NONE; +} + +int _widget_set_content(struct widget_common *common, const char *content) +{ + char *pc = NULL; + + if (content) { + pc = strdup(content); + if (!pc) { + ErrPrint("heap: %d [%s]\n", errno, content); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + } + + free(common->content); + common->content = pc; + return WIDGET_ERROR_NONE; +} + +int _widget_set_title(struct widget_common *common, const char *title) +{ + char *pt = NULL; + + if (title) { + pt = strdup(title); + if (!pt) { + ErrPrint("heap: %d [%s]\n", errno, title); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + } + + free(common->title); + common->title = pt; + return WIDGET_ERROR_NONE; +} + +void _widget_set_size_list(struct widget_common *common, int size_list) +{ + common->widget.size_list = size_list; +} + +void _widget_set_auto_launch(struct widget_common *common, const char *auto_launch) +{ + char *pa = NULL; + + if (!auto_launch || !strlen(auto_launch)) { + return; + } + + pa = strdup(auto_launch); + if (!pa) { + ErrPrint("heap: %d, [%s]\n", errno, auto_launch); + return; + } + + free(common->widget.auto_launch); + common->widget.auto_launch = pa; +} + +void _widget_set_priority(struct widget_common *common, double priority) +{ + common->widget.priority = priority; +} + +void _widget_set_id(struct widget_common *common, const char *id) +{ + char *pi = NULL; + + if (id) { + pi = strdup(id); + if (!pi) { + ErrPrint("heap: %d [%s]\n", errno, pi); + return; + } + } + + free(common->id); + common->id = pi; +} + +void _widget_unlink_filename(struct widget_common *common) +{ + if (common->widget.type == WIDGET_TYPE_FILE || common->widget.type == WIDGET_TYPE_TEXT) { + if (common->filename && common->filename[0] && unlink(common->filename) < 0) { + ErrPrint("unlink: %d (%s)\n", errno, common->filename); + } + } +} + +void _widget_set_filename(struct widget_common *common, const char *filename) +{ + if (common->filename) { + free(common->filename); + } + + common->filename = strdup(filename); + if (!common->filename) { + ErrPrint("Heap: %d\n", errno); + } +} + +void _widget_set_alt_icon(struct widget_common *common, const char *icon) +{ + char *_icon = NULL; + + if (icon && strlen(icon)) { + _icon = strdup(icon); + if (!_icon) { + ErrPrint("Heap: %d\n", errno); + } + } + + free(common->alt.icon); + common->alt.icon = _icon; +} + +void _widget_set_alt_name(struct widget_common *common, const char *name) +{ + char *_name = NULL; + + if (name && strlen(name)) { + _name = strdup(name); + if (!_name) { + ErrPrint("Heap: %d\n", errno); + } + } + + free(common->alt.name); + common->alt.name = _name; +} + +int _widget_set_widget_fb(struct widget_common *common, const char *filename) +{ + struct fb_info *fb; + + if (!common) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + fb = common->widget.fb; + if (fb && !strcmp(fb_id(fb), filename)) { /*!< BUFFER is not changed, */ + return WIDGET_ERROR_NONE; + } + + common->widget.fb = NULL; + + if (!filename || filename[0] == '\0') { + if (fb) { + fb_destroy(fb); + } + return WIDGET_ERROR_NONE; + } + + common->widget.fb = fb_create(filename, common->widget.width, common->widget.height); + if (!common->widget.fb) { + ErrPrint("Faield to create a FB\n"); + if (fb) { + fb_destroy(fb); + } + return WIDGET_ERROR_FAULT; + } + + if (fb) { + fb_destroy(fb); + } + + return WIDGET_ERROR_NONE; +} + +int _widget_set_gbar_fb(struct widget_common *common, const char *filename) +{ + struct fb_info *fb; + + if (!common || common->state != WIDGET_STATE_CREATE) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + fb = common->gbar.fb; + if (fb && !strcmp(fb_id(fb), filename)) { + /* BUFFER is not changed, just update the content */ + return WIDGET_ERROR_ALREADY_EXIST; + } + common->gbar.fb = NULL; + + if (!filename || filename[0] == '\0') { + if (fb) { + fb_destroy(fb); + } + return WIDGET_ERROR_NONE; + } + + common->gbar.fb = fb_create(filename, common->gbar.width, common->gbar.height); + if (!common->gbar.fb) { + ErrPrint("Failed to create a FB\n"); + if (fb) { + fb_destroy(fb); + } + return WIDGET_ERROR_FAULT; + } + + if (fb) { + fb_destroy(fb); + } + return WIDGET_ERROR_NONE; +} + +struct fb_info *_widget_get_widget_fb(struct widget_common *common) +{ + return common->widget.fb; +} + +struct fb_info *_widget_get_gbar_fb(struct widget_common *common) +{ + return common->gbar.fb; +} + +void _widget_set_user(struct widget_common *common, int user) +{ + common->is_user = user; +} + +void _widget_set_pinup(struct widget_common *common, int pinup_supported) +{ + common->widget.pinup_supported = pinup_supported; +} + +void _widget_set_text_widget(struct widget_common *common) +{ + common->widget.type = WIDGET_TYPE_TEXT; +} + +void _widget_set_text_gbar(struct widget_common *common) +{ + common->gbar.type = GBAR_TYPE_TEXT; +} + +int _widget_text_widget(struct widget_common *common) +{ + return common->widget.type == WIDGET_TYPE_TEXT; +} + +int _widget_text_gbar(struct widget_common *common) +{ + return common->gbar.type == GBAR_TYPE_TEXT; +} + +void _widget_set_period(struct widget_common *common, double period) +{ + common->widget.period = period; +} + +widget_h _widget_ref(widget_h handler) +{ + if (!handler) { + return NULL; + } + + handler->refcnt++; + return handler; +} + +widget_h _widget_unref(widget_h handler, int destroy_common) +{ + if (!handler) { + return NULL; + } + + handler->refcnt--; + if (handler->refcnt > 0) { + return handler; + } + + if (handler->cbs.created.cb) { + handler->cbs.created.cb(handler, WIDGET_ERROR_FAULT, handler->cbs.created.data); + handler->cbs.created.cb = NULL; + handler->cbs.created.data = NULL; + } + + if (handler->cbs.deleted.cb) { + handler->cbs.deleted.cb(handler, WIDGET_ERROR_FAULT, handler->cbs.deleted.data); + handler->cbs.deleted.cb = NULL; + handler->cbs.deleted.data = NULL; + } + + if (handler->cbs.pinup.cb) { + handler->cbs.pinup.cb(handler, WIDGET_ERROR_FAULT, handler->cbs.pinup.data); + handler->cbs.pinup.cb = NULL; + handler->cbs.pinup.data = NULL; + } + + if (handler->cbs.group_changed.cb) { + handler->cbs.group_changed.cb(handler, WIDGET_ERROR_FAULT, handler->cbs.group_changed.data); + handler->cbs.group_changed.cb = NULL; + handler->cbs.group_changed.data = NULL; + } + + if (handler->cbs.period_changed.cb) { + handler->cbs.period_changed.cb(handler, WIDGET_ERROR_FAULT, handler->cbs.period_changed.data); + handler->cbs.period_changed.cb = NULL; + handler->cbs.period_changed.data = NULL; + } + + if (handler->cbs.size_changed.cb) { + handler->cbs.size_changed.cb(handler, WIDGET_ERROR_FAULT, handler->cbs.size_changed.data); + handler->cbs.size_changed.cb = NULL; + handler->cbs.size_changed.data = NULL; + } + + if (handler->cbs.gbar_created.cb) { + handler->cbs.gbar_created.cb(handler, WIDGET_ERROR_FAULT, handler->cbs.gbar_created.data); + handler->cbs.gbar_created.cb = NULL; + handler->cbs.gbar_created.data = NULL; + } + + if (handler->cbs.gbar_destroyed.cb) { + handler->cbs.gbar_destroyed.cb(handler, WIDGET_ERROR_FAULT, handler->cbs.gbar_destroyed.data); + handler->cbs.gbar_destroyed.cb = NULL; + handler->cbs.gbar_destroyed.data = NULL; + } + + if (handler->cbs.update_mode.cb) { + handler->cbs.update_mode.cb(handler, WIDGET_ERROR_FAULT, handler->cbs.update_mode.data); + handler->cbs.update_mode.cb = NULL; + handler->cbs.update_mode.data = NULL; + } + + if (handler->cbs.access_event.cb) { + handler->cbs.access_event.cb(handler, WIDGET_ACCESS_STATUS_ERROR, handler->cbs.access_event.data); + handler->cbs.access_event.cb = NULL; + handler->cbs.access_event.data = NULL; + } + + if (handler->cbs.key_event.cb) { + handler->cbs.key_event.cb(handler, WIDGET_KEY_STATUS_ERROR, handler->cbs.key_event.data); + handler->cbs.key_event.cb = NULL; + handler->cbs.key_event.data = NULL; + } + + dlist_remove_data(s_info.widget_list, handler); + + handler->state = WIDGET_STATE_DESTROYED; + if (_widget_common_unref(handler->common, handler) == 0) { + if (destroy_common) { + /*! + * \note + * Lock file should be deleted after all callbacks are processed. + */ + (void)widget_service_destroy_lock(handler->common->widget.lock); + handler->common->widget.lock = NULL; + _widget_destroy_common_handle(handler->common); + } + } + free(handler); + DbgPrint("Handler is released\n"); + return NULL; +} + +int _widget_send_delete(widget_h handler, int type, widget_ret_cb cb, void *data) +{ + struct packet *packet; + struct cb_info *cbinfo; + int ret; + + if (handler->common->request.deleted) { + ErrPrint("Already in-progress\n"); + if (cb) { + cb(handler, WIDGET_ERROR_NONE, data); + } + return WIDGET_ERROR_RESOURCE_BUSY; + } + + if (!cb) { + cb = default_delete_cb; + } + + packet = packet_create("delete", "ssid", handler->common->pkgname, handler->common->id, type, handler->common->timestamp); + if (!packet) { + ErrPrint("Failed to build a param\n"); + if (cb) { + cb(handler, WIDGET_ERROR_FAULT, data); + } + + return WIDGET_ERROR_FAULT; + } + + cbinfo = _widget_create_cb_info(cb, data); + if (!cbinfo) { + packet_destroy(packet); + ErrPrint("Failed to create cbinfo\n"); + if (cb) { + cb(handler, WIDGET_ERROR_FAULT, data); + } + + return WIDGET_ERROR_FAULT; + } + + ret = master_rpc_async_request(handler, packet, 0, del_ret_cb, cbinfo); + if (ret < 0) { + /*! + * Packet is destroyed by master_rpc_async_request. + */ + _widget_destroy_cb_info(cbinfo); + + if (cb) { + cb(handler, WIDGET_ERROR_FAULT, data); + } + } else { + handler->common->request.deleted = 1; + } + + return ret; +} + +int _widget_sync_widget_fb(struct widget_common *common) +{ + int ret; + + if (fb_type(_widget_get_widget_fb(common)) == WIDGET_FB_TYPE_FILE) { + (void)widget_service_acquire_lock(common->widget.lock); + ret = fb_sync(_widget_get_widget_fb(common), common->widget.last_damage.x, common->widget.last_damage.y, common->widget.last_damage.w, common->widget.last_damage.h); + (void)widget_service_release_lock(common->widget.lock); + } else { + ret = fb_sync(_widget_get_widget_fb(common), common->widget.last_damage.x, common->widget.last_damage.y, common->widget.last_damage.w, common->widget.last_damage.h); + } + + return ret; +} + +int _widget_sync_gbar_fb(struct widget_common *common) +{ + int ret; + + if (fb_type(_widget_get_gbar_fb(common)) == WIDGET_FB_TYPE_FILE) { + (void)widget_service_acquire_lock(common->gbar.lock); + ret = fb_sync(_widget_get_gbar_fb(common), common->gbar.last_damage.x, common->gbar.last_damage.y, common->gbar.last_damage.w, common->gbar.last_damage.h); + (void)widget_service_release_lock(common->gbar.lock); + } else { + ret = fb_sync(_widget_get_gbar_fb(common), common->gbar.last_damage.x, common->gbar.last_damage.y, common->gbar.last_damage.w, common->gbar.last_damage.h); + } + + return ret; +} + +struct widget_common *_widget_find_sharable_common_handle(const char *pkgname, const char *content, int w, int h, const char *cluster, const char *category) +{ + struct dlist *l; + struct widget_common *common; + + if (!conf_shared_content()) { + /*! + * Shared content option is turnned off. + */ + return NULL; + } + + dlist_foreach(s_info.widget_common_list, l, common) { + if (common->state != WIDGET_STATE_CREATE) { + continue; + } + + if (strcmp(common->pkgname, pkgname)) { + continue; + } + + if (strcmp(common->cluster, cluster)) { + DbgPrint("Cluster mismatched\n"); + continue; + } + + if (strcmp(common->category, category)) { + DbgPrint("Category mismatched\n"); + continue; + } + + if (common->content && content) { + if (strcmp(common->content, content)) { + DbgPrint("%s Content ([%s] <> [%s])\n", common->pkgname, common->content, content); + continue; + } + } else { + int c1_len; + int c2_len; + + /*! + * \note + * We assumes "" (ZERO length string) to NULL + */ + c1_len = common->content ? strlen(common->content) : 0; + c2_len = content ? strlen(content) : 0; + if (c1_len != c2_len) { + DbgPrint("%s Content %p <> %p\n", common->pkgname, common->content, content); + continue; + } + } + + if (common->request.size_changed) { + DbgPrint("Changing size\n"); + /*! + * \note + * Do not re-use resizing instance. + * We will not use predicted size. + */ + continue; + } + + if (common->request.created) { + DbgPrint("Creating now but re-use it (%s)\n", common->pkgname); + } + + if (common->widget.width != w || common->widget.height != h) { + DbgPrint("Size mismatched\n"); + continue; + } + + DbgPrint("common handle is found: %p\n", common); + return common; + } + + return NULL; +} + +widget_h _widget_find_widget_in_show(struct widget_common *common) +{ + struct dlist *l; + widget_h item; + + dlist_foreach(common->widget_list, l, item) { + if (item->visible == WIDGET_SHOW) { + DbgPrint("%s visibility is not changed\n", common->pkgname); + return item; + } + } + + return NULL; +} + +widget_h _widget_get_widget_nth(struct widget_common *common, int nth) +{ + widget_h item; + struct dlist *l; + + l = dlist_nth(common->widget_list, nth); + item = dlist_data(l); + + return item; +} + +int _widget_add_event_handler(widget_event_handler_cb widget_cb, void *data) +{ + struct event_info *info; + info = malloc(sizeof(*info)); + if (!info) { + ErrPrint("Heap: %d\n", errno); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + info->handler = widget_cb; + info->user_data = data; + info->is_deleted = 0; + + s_info.event_list = dlist_append(s_info.event_list, info); + return WIDGET_ERROR_NONE; +} + +void *_widget_remove_event_handler(widget_event_handler_cb widget_cb) +{ + struct event_info *info; + struct dlist *l; + + dlist_foreach(s_info.event_list, l, info) { + if (info->handler == widget_cb) { + void *data; + + data = info->user_data; + + if (s_info.event_state == INFO_STATE_CALLBACK_IN_PROCESSING) { + info->is_deleted = 1; + } else { + s_info.event_list = dlist_remove(s_info.event_list, l); + free(info); + } + + return data; + } + } + + return NULL; +} + +int _widget_add_fault_handler(widget_fault_handler_cb widget_cb, void *data) +{ + struct fault_info *info; + info = malloc(sizeof(*info)); + if (!info) { + ErrPrint("Heap: %d\n", errno); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + info->handler = widget_cb; + info->user_data = data; + info->is_deleted = 0; + + s_info.fault_list = dlist_append(s_info.fault_list, info); + return WIDGET_ERROR_NONE; +} + +void *_widget_remove_fault_handler(widget_fault_handler_cb widget_cb) +{ + struct fault_info *info; + struct dlist *l; + + dlist_foreach(s_info.fault_list, l, info) { + if (info->handler == widget_cb) { + void *data; + + data = info->user_data; + + if (s_info.fault_state == INFO_STATE_CALLBACK_IN_PROCESSING) { + info->is_deleted = 1; + } else { + s_info.fault_list = dlist_remove(s_info.fault_list, l); + free(info); + } + + return data; + } + } + + return NULL; +} + +struct cb_info *_widget_create_cb_info(widget_ret_cb cb, void *data) +{ + struct cb_info *info; + + info = malloc(sizeof(*info)); + if (!info) { + ErrPrint("Heap: %d\n", errno); + return NULL; + } + + info->cb = cb; + info->data = data; + return info; +} + +void _widget_destroy_cb_info(struct cb_info *info) +{ + free(info); +} + +/* End of a file */ diff --git a/widget_viewer/widget_viewer.pc.in b/widget_viewer/widget_viewer.pc.in new file mode 100755 index 0000000..8e78cb2 --- /dev/null +++ b/widget_viewer/widget_viewer.pc.in @@ -0,0 +1,12 @@ +prefix=@PREFIX@ +exec_prefix=@EXEC_PREFIX@ +libdir=@LIBDIR@ +includedir=@INCLUDEDIR@ + +Name: widget-viewer +Description: Support development of the widget Viewer +Version: @VERSION@ +Requires: widget_service +Libs: -L${libdir} -lwidget_viewer +Cflags: -I${includedir} +cppflags: -I${includedir} diff --git a/widget_viewer_evas/CMakeLists.txt b/widget_viewer_evas/CMakeLists.txt new file mode 100644 index 0000000..492e1dd --- /dev/null +++ b/widget_viewer_evas/CMakeLists.txt @@ -0,0 +1,57 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(widget_viewer_evas C) + +SET(PREFIX "${CMAKE_INSTALL_PREFIX}") +SET(EXEC_PREFIX "\${prefix}") +SET(PROJECT_NAME "${PROJECT_NAME}") +SET(LIBDIR "\${exec_prefix}/lib") +SET(INCLUDEDIR "\${prefix}/include/${PROJECT_NAME}") +SET(VERSION_MAJOR 1) +SET(VERSION "${VERSION_MAJOR}.0.0") +SET(EDJDIR "/usr/share/${PROJECT_NAME}/res/edje") +SET(IMGDIR "/usr/share/${PROJECT_NAME}/res/image") + +INCLUDE(FindPkgConfig) +pkg_check_modules(viewer_evas REQUIRED + dlog + widget_service + elementary +) + +SET(BUILD_SOURCE + src/widget_viewer_evas.c +) + +FOREACH(flag ${viewer_evas_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden -Wall -Werror -Winline -g") + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") +SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") +SET(CMAKE_C_FLAGS_RELEASE "-O2") + +ADD_DEFINITIONS("-DWIDGET_EVAS_RESOURCE_EDJ=\"${EDJDIR}/widget_viewer_evas.edj\"") +ADD_DEFINITIONS("-DWIDGET_EVAS_RESOURCE_PD=\"gbar\"") +ADD_DEFINITIONS("-DWIDGET_EVAS_RESOURCE_LB=\"widget\"") +ADD_DEFINITIONS("-DWIDGET_EVAS_RESOURCE_IMG=\"widget,image\"") + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include) +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/widget_viewer/include) + +ADD_LIBRARY(${PROJECT_NAME} SHARED ${BUILD_SOURCE}) +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${VERSION_MAJOR}) +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES VERSION ${VERSION}) + +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${viewer_evas_LDFLAGS} "-lpthread") + +CONFIGURE_FILE(${PROJECT_NAME}.pc.in ${PROJECT_NAME}.pc @ONLY) +SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${PROJECT_NAME}.pc") + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION lib) +INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc DESTINATION lib/pkgconfig) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/${PROJECT_NAME}.h DESTINATION include/${PROJECT_NAME}) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/${PROJECT_NAME}_internal.h DESTINATION include/${PROJECT_NAME}) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE DESTINATION /usr/share/license RENAME "lib${PROJECT_NAME}") + +ADD_SUBDIRECTORY(res) diff --git a/widget_viewer_evas/LICENSE b/widget_viewer_evas/LICENSE new file mode 100644 index 0000000..571fe79 --- /dev/null +++ b/widget_viewer_evas/LICENSE @@ -0,0 +1,206 @@ +Flora License + +Version 1.1, April, 2013 + +http://floralicense.org/license/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, +and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by +the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and +all other entities that control, are controlled by, or are +under common control with that entity. For the purposes of +this definition, "control" means (i) the power, direct or indirect, +to cause the direction or management of such entity, +whether by contract or otherwise, or (ii) ownership of fifty percent (50%) +or more of the outstanding shares, or (iii) beneficial ownership of +such entity. + +"You" (or "Your") shall mean an individual or Legal Entity +exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, +including but not limited to software source code, documentation source, +and configuration files. + +"Object" form shall mean any form resulting from mechanical +transformation or translation of a Source form, including but +not limited to compiled object code, generated documentation, +and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, +made available under the License, as indicated by a copyright notice +that is included in or attached to the work (an example is provided +in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, +that is based on (or derived from) the Work and for which the editorial +revisions, annotations, elaborations, or other modifications represent, +as a whole, an original work of authorship. For the purposes of this License, +Derivative Works shall not include works that remain separable from, +or merely link (or bind by name) to the interfaces of, the Work and +Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original +version of the Work and any modifications or additions to that Work or +Derivative Works thereof, that is intentionally submitted to Licensor +for inclusion in the Work by the copyright owner or by an individual or +Legal Entity authorized to submit on behalf of the copyright owner. +For the purposes of this definition, "submitted" means any form of +electronic, verbal, or written communication sent to the Licensor or +its representatives, including but not limited to communication on +electronic mailing lists, source code control systems, and issue +tracking systems that are managed by, or on behalf of, the Licensor +for the purpose of discussing and improving the Work, but excluding +communication that is conspicuously marked or otherwise designated +in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity +on behalf of whom a Contribution has been received by Licensor and +subsequently incorporated within the Work. + +"Tizen Certified Platform" shall mean a software platform that complies +with the standards set forth in the Tizen Compliance Specification +and passes the Tizen Compliance Tests as defined from time to time +by the Tizen Technical Steering Group and certified by the Tizen +Association or its designated agent. + +2. Grant of Copyright License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the +Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +(except as stated in this section) patent license to make, have made, +use, offer to sell, sell, import, and otherwise transfer the Work +solely as incorporated into a Tizen Certified Platform, where such +license applies only to those patent claims licensable by such +Contributor that are necessarily infringed by their Contribution(s) +alone or by combination of their Contribution(s) with the Work solely +as incorporated into a Tizen Certified Platform to which such +Contribution(s) was submitted. If You institute patent litigation +against any entity (including a cross-claim or counterclaim +in a lawsuit) alleging that the Work or a Contribution incorporated +within the Work constitutes direct or contributory patent infringement, +then any patent licenses granted to You under this License for that +Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the +Work or Derivative Works thereof pursuant to the copyright license +above, in any medium, with or without modifications, and in Source or +Object form, provided that You meet the following conditions: + + 1. You must give any other recipients of the Work or Derivative Works + a copy of this License; and + 2. You must cause any modified files to carry prominent notices stating + that You changed the files; and + 3. You must retain, in the Source form of any Derivative Works that + You distribute, all copyright, patent, trademark, and attribution + notices from the Source form of the Work, excluding those notices + that do not pertain to any part of the Derivative Works; and + 4. If the Work includes a "NOTICE" text file as part of its distribution, + then any Derivative Works that You distribute must include a readable + copy of the attribution notices contained within such NOTICE file, + excluding those notices that do not pertain to any part of + the Derivative Works, in at least one of the following places: + within a NOTICE text file distributed as part of the Derivative Works; + within the Source form or documentation, if provided along with the + Derivative Works; or, within a display generated by the Derivative Works, + if and wherever such third-party notices normally appear. + The contents of the NOTICE file are for informational purposes only + and do not modify the License. You may add Your own attribution notices + within Derivative Works that You distribute, alongside or as an addendum + to the NOTICE text from the Work, provided that such additional attribution + notices cannot be construed as modifying the License. You may add Your own + copyright statement to Your modifications and may provide additional or + different license terms and conditions for use, reproduction, or + distribution of Your modifications, or for any such Derivative Works + as a whole, provided Your use, reproduction, and distribution of + the Work otherwise complies with the conditions stated in this License + and your own copyright statement or terms and conditions do not conflict + the conditions stated in the License including section 3. + +5. Submission of Contributions. Unless You explicitly state otherwise, +any Contribution intentionally submitted for inclusion in the Work +by You to the Licensor shall be under the terms and conditions of +this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify +the terms of any separate license agreement you may have executed +with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade +names, trademarks, service marks, or product names of the Licensor, +except as required for reasonable and customary use in describing the +origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or +agreed to in writing, Licensor provides the Work (and each +Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied, including, without limitation, any warranties or conditions +of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any +risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, +whether in tort (including negligence), contract, or otherwise, +unless required by applicable law (such as deliberate and grossly +negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, +incidental, or consequential damages of any character arising as a +result of this License or out of the use or inability to use the +Work (including but not limited to damages for loss of goodwill, +work stoppage, computer failure or malfunction, or any and all +other commercial damages or losses), even if such Contributor +has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing +the Work or Derivative Works thereof, You may choose to offer, +and charge a fee for, acceptance of support, warranty, indemnity, +or other liability obligations and/or rights consistent with this +License. However, in accepting such obligations, You may act only +on Your own behalf and on Your sole responsibility, not on behalf +of any other Contributor, and only if You agree to indemnify, +defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason +of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Flora License to your work + +To apply the Flora License to your work, attach the following +boilerplate notice, with the fields enclosed by brackets "[]" +replaced with your own identifying information. (Don't include +the brackets!) The text should be enclosed in the appropriate +comment syntax for the file format. We also recommend that a +file or class name and description of purpose be included on the +same "printed page" as the copyright notice for easier +identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Flora License, Version 1.1 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://floralicense.org/license/ + + 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. + diff --git a/widget_viewer_evas/include/widget_viewer_evas.h b/widget_viewer_evas/include/widget_viewer_evas.h new file mode 100755 index 0000000..8d032e1 --- /dev/null +++ b/widget_viewer_evas/include/widget_viewer_evas.h @@ -0,0 +1,393 @@ +/* + * Samsung API + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Flora License, Version 1.1 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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. + */ + +#ifndef __WIDGET_VIEWER_EVAS_H +#define __WIDGET_VIEWER_EVAS_H + +#include "widget_service.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @since_tizen 2.3.1 + * @brief Default refresh interval of widgets. + * @see #widget_viewer_evas_add_widget + */ +#define WIDGET_VIEWER_EVAS_DEFAULT_PERIOD -1.0f /**< Default Update Period */ + +/** + * @since_tizen 2.3.1 + * @brief Event names for smart callback of widget events. You can listen some events from widget by calling evas_object_smart_callback_add. + * @see #widget_evas_event_info_s + * @see evas_object_smart_callback_add + */ +#define WIDGET_SMART_SIGNAL_WIDGET_CREATE_ABORTED "widget,create,aborted" /**< Widget creation is aborted */ +#define WIDGET_SMART_SIGNAL_WIDGET_CREATED "widget,created" /**< Widget is created */ +#define WIDGET_SMART_SIGNAL_WIDGET_RESIZE_ABORTED "widget,resize,aborted" /**< Resizing widget is aborted */ +#define WIDGET_SMART_SIGNAL_WIDGET_RESIZED "widget,resized" /**< Widget is resized */ +#define WIDGET_SMART_SIGNAL_WIDGET_FAULTED "widget,faulted" /**< Widget has faulted */ +#define WIDGET_SMART_SIGNAL_UPDATED "updated" /**< Widget content is updated */ +#define WIDGET_SMART_SIGNAL_EXTRA_INFO_UPDATED "info,updated" /**< Widget extra info is updated */ +#define WIDGET_SMART_SIGNAL_PROVIDER_DISCONNECTED "provider,disconnected" /**< Provider is disconnected */ +#define WIDGET_SMART_SIGNAL_CONTROL_SCROLLER "control,scroller" /**< Control Scroller */ +#define WIDGET_SMART_SIGNAL_WIDGET_DELETED "widget,deleted" /**< Widget is deleted */ +#define WIDGET_SMART_SIGNAL_PERIOD_CHANGED "widget,period,changed" /**< Period is changed */ + +/** + * @since_tizen 2.3.1 + * @brief Data structure which will be sent as a parameter of smart callback for signals WIDGET_SMART_SIGNAL_XXX + * @see #WIDGET_SMART_SIGNAL_WIDGET_CREATE_ABORTED + * @see #WIDGET_SMART_SIGNAL_WIDGET_CREATED + * @see #WIDGET_SMART_SIGNAL_WIDGET_RESIZE_ABORTED + * @see #WIDGET_SMART_SIGNAL_WIDGET_RESIZED + * @see #WIDGET_SMART_SIGNAL_WIDGET_FAULTED + * @see #WIDGET_SMART_SIGNAL_UPDATED + * @see #WIDGET_SMART_SIGNAL_EXTRA_INFO_UPDATED + * @see #WIDGET_SMART_SIGNAL_PROVIDER_DISCONNECTED + * @see #WIDGET_SMART_SIGNAL_CONTROL_SCROLLER + * @see #WIDGET_SMART_SIGNAL_WIDGET_DELETED + * @see #WIDGET_SMART_SIGNAL_PERIOD_CHANGED + */ +typedef struct widget_evas_event_info { + const char *widget_app_id; /**< Widget application id */ + widget_event_type_e event; /**< Event type for detail event information - WIDGET_EVENT_XXX, refer the widget_serivce.h */ + int error; /**< Error type - WIDGET_ERROR_XXX, refer the widget_errno.h */ +} widget_evas_event_info_s; + +/** + * @brief Enumerations for setting visibility status of a widget. + * @since_tizen 2.3.1 + * @see #widget_viewer_evas_freeze_visibility + */ +typedef enum widget_visibility_status { + WIDGET_VISIBILITY_STATUS_SHOW_FIXED = 1, + WIDGET_VISIBILITY_STATUS_HIDE_FIXED = 2 +} widget_visibility_status_e; + +/** + * @brief Configuration keys + * @since_tizen 2.3.1 + * @see #widget_viewer_evas_set_option + */ +typedef enum widget_evas_conf { + WIDGET_VIEWER_EVAS_MANUAL_PAUSE_RESUME = 0x0001, /**< Visibility will be changed manually. 1 : on, 0 : off */ + WIDGET_VIEWER_EVAS_USE_FIXED_SIZE = 0x0008, /**< Widget will be resized to specific size only. 1 : on, 0 : off */ + WIDGET_VIEWER_EVAS_EASY_MODE = 0x0010, /**< Easy mode on/off. 1 : on, 0 : off */ + WIDGET_VIEWER_EVAS_SCROLL_X = 0x0020, /**< Box will be scrolled from left to right vice versa. 1 : on, 0 : off */ + WIDGET_VIEWER_EVAS_SCROLL_Y = 0x0040, /**< Box will be scrolled from top to bottom vice versa. 1 : on, 0 : off */ + WIDGET_VIEWER_EVAS_EVENT_AUTO_FEED = 0x0080, /**< Feeds event automatically from the master provider. 1 : on, 0 : off */ + WIDGET_VIEWER_EVAS_DELAYED_RESUME = 0x0100, /**< Delaying the pause/resume when it is automatically changed. 1 : on, 0 : off */ + WIDGET_VIEWER_EVAS_SENSITIVE_MOVE = 0x0200, /**< Force feeds mouse up event if the box is moved. 1 : on, 0 : off */ + WIDGET_VIEWER_EVAS_AUTO_RENDER_SELECTION = 0x0400, /**< Select render automatically, if a box moved, do not sync using animator, or use the animator. 1 : on, 0 : off */ + WIDGET_VIEWER_EVAS_DIRECT_UPDATE = 0x0800, /**< Enable direct update path. 1 : on, 0 : off */ + WIDGET_VIEWER_EVAS_USE_RENDER_ANIMATOR = 0x1000, /**< Use the render animator or not. 1 : on, 0 : off */ + WIDGET_VIEWER_EVAS_SKIP_ACQUIRE = 0x2000, /**< Even if the viewer cannot get acquired resource id, try to update using default one. 1 : on, 0 : off */ + WIDGET_VIEWER_EVAS_UNKNOWN = 0xFFFF +} widget_evas_conf_e; + +/** + * @brief Initializes the widget system + * @since_tizen 2.3.1 + * @param[in] win Window object + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_NONE If success + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER + * @retval #WIDGET_ERROR_PERMISSION_DENIED Permission denied + * @see #widget_viewer_evas_fini + */ +extern int widget_viewer_evas_init(Evas_Object *win); + +/** + * @brief Finalizes the widget system + * @since_tizen 2.3.1 + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_NONE If success + * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred + * @see #widget_viewer_evas_init + */ +extern int widget_viewer_evas_fini(void); + +/** + * @brief Creates a new widget object + * @since_tizen 2.3.1 + * @param[in] parent Evas Object of parent + * @param[in] widget_id widget id + * @param[in] content_info Contents that will be given to the widget instance + * @param[in] period Update period (@c WIDGET_DEFAULT_PERIOD can be used for this; this argument will be used to specify the period of updating contents of a widget) + * @return Widget Object + * @retval NULL if it fails to create a new widget object and you can get the reason of failure using get_last_result() + * @see #widget_service_get_widget_id + * @see #widget_service_get_content_string + * @see #widget_service_get_category + */ +extern Evas_Object *widget_viewer_evas_add_widget(Evas_Object *parent, const char *widget_id, const char *content_info, double period); + +/** + * @brief Notifies the status of the viewer to all providers + * @details If you call this, all providers will gets "resumed" event. + * @since_tizen 2.3.1 + * @privlevel public + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_NONE if success + * @retval #WIDGET_ERROR_FAULT if it failed to send state (paused) info + * @retval #WIDGET_ERROR_PERMISSION_DENIED Permission denied + * @see widget_viewer_evas_notify_paused_status_of_viewer() + */ +extern int widget_viewer_evas_notify_resumed_status_of_viewer(void); + +/** + * @brief Notifies the status of the viewer to all providers + * @detail If you call this, all providers will gets "paused" event. + * @since_tizen 2.3.1 + * @privlevel public + * @privilege %http://tizen.org/privilege/widget.viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_NONE if success + * @retval #WIDGET_ERROR_FAULT if it failed to send state (resumed) info + * @retval #WIDGET_ERROR_PERMISSION_DENIED Permission denied + * @see widget_viewer_evas_notify_resumed_status_of_viewer() + */ +extern int widget_viewer_evas_notify_paused_status_of_viewer(void); + +/** + * @brief Notifies the orientation of the viewer to all providers + * @detail If you call this, all providers will gets "rotated" event. + * @since_tizen 2.3.1 + * @privlevel public + * @privilege %http://tizen.org/privilege/widget.viewer + * @param[in] orientation orientation of viewer + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_NONE if success + * @retval #WIDGET_ERROR_FAULT if it failed to send state (resumed) info + * @retval #WIDGET_ERROR_PERMISSION_DENIED Permission denied + */ +extern int widget_viewer_evas_notify_orientation_of_viewer(int orientation); + +/** + * @brief Pauses given widget. + * @since_tizen 2.3.1 + * @privlevel public + * @privilege %http://tizen.org/privilege/widget.viewer + * @param[in] widget a widget object + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_NONE if success + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_ERROR_PERMISSION_DENIED Permission denied + * @retval #WIDGET_ERROR_FAULT if it failed to send state (resumed) info + */ +extern int widget_viewer_evas_pause_widget(Evas_Object *widget); + +/** + * @brief Resume given widget. + * @since_tizen 2.3.1 + * @privlevel public + * @privilege %http://tizen.org/privilege/widget.viewer + * @param[in] widget a widget object + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_NONE if success + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_ERROR_FAULT if it failed to send state (resumed) info + * @retval #WIDGET_ERROR_PERMISSION_DENIED Permission denied + */ +extern int widget_viewer_evas_resume_widget(Evas_Object *widget); + +/** + * @brief Changes the configurable values of widget system + * @since_tizen 2.3.1 + * @param[in] type Configuration item + * @param[in] value Its value + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_NONE if success + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @see #widget_evas_conf + */ +extern int widget_viewer_evas_set_option(widget_evas_conf_e type, int value); + +/** + * @brief Gets content string of widget + * @details This string can be used for creating contents of widget again after reboot a device or recovered from crash(abnormal status) + * @Remarks Returned string should not be freed. + * @since_tizen 2.3.1 + * @param[in] widget a widget object + * @return content string to be recognize content of the widget + * @retval NULL if there is no specific content string. + * @post Returned string should not be freed + */ +extern const char *widget_viewer_evas_get_content_info(Evas_Object *widget); + +/** + * @brief Gets summarized string of the widget content for accessibility. + * @details If the accessibility feature is turned on, a viewer can use this text to describe the widget. + * @Remarks Returned string should not be freed. + * @since_tizen 2.3.1 + * @param[in] widget a widget object + * @return title string to be used for summarizing the widget + * @retval NULL if there is no summarized text for content of given widget. + */ +extern const char *widget_viewer_evas_get_title_string(Evas_Object *widget); + +/** + * @brief Gets the id of the widget + * @Remarks Returned string should not be freed. + * @since_tizen 2.3.1 + * @param[in] widget a widget object + * @return widget id + * @retval NULL if an error occurred and you can get the reason of failure using get_last_result() + */ +extern const char *widget_viewer_evas_get_widget_id(Evas_Object *widget); + +/** + * @brief Gets the update period of the widget. + * @since_tizen 2.3.1 + * @param[in] widget a widget object + * @return period the update period of the widget. + * @retval the update interval of the widget + */ +extern double widget_viewer_evas_get_period(Evas_Object *widget); + +/** + * @brief Cancels click event procedure. + * @details If you call this function after feed the mouse_down(or mouse_set) event, the widget will get ON_HOLD events.\n + * If a widget gets ON_HOLD event, it will not do anything even if you feed mouse_up(or mouse_unset) event.\n + * @since_tizen 2.3.1 + * @param[in] widget a widget object + * + */ +extern void widget_viewer_evas_cancel_click_event(Evas_Object *widget); + +/* + * @brief Hides the preview of the widget + * @remarks This function should be called right after create the widget object before resizing it + * @since_tizen 2.3.1 + * @param[in] widget a widget object + */ +extern void widget_viewer_evas_disable_preview(Evas_Object *widget); + +/** + * @brief Hides the help text of the widget + * @details While loading a box, hide the help text + * @since_tizen 2.3.1 + * @param[in] widget a widget object + */ +extern void widget_viewer_evas_disable_overlay_text(Evas_Object *widget); + +/** + * @brief Hides the loading message of the widget + * @details if you disable it, there is no preview & help text while creating a widget object + * @since_tizen 2.3.1 + * @param[in] widget a widget object + */ +extern void widget_viewer_evas_disable_loading(Evas_Object *widget); + +/** + * @brief Feeds the mouse_up event to the provider of the widget + * @details This is very similar with widget_viewer_evas_cancel_click(), but this will sends mouse_up event explicitly.\n + * Also feed the ON_HOLD event before feeds mouse_up event. + * @since_tizen 2.3.1 + * @privlevel public + * @privilege %http://tizen.org/privilege/widget.viewer + * @param[in] widget a widget object + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_NONE if success + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @retval #WIDGET_ERROR_PERMISSION_DENIED Permission denied + */ +extern int widget_viewer_evas_feed_mouse_up_event(Evas_Object *widget); + +/** + * @brief Activate a widget in faulted state. + * @details A widget in faulted state MUST be activated before adding the widget. + * @since_tizen 2.3.1 + * @privlevel public + * @privilege %http://tizen.org/privilege/widget.viewer + * @param[in] widget a widget object faulted + */ +extern void widget_viewer_evas_activate_faulted_widget(Evas_Object *widget); + +/** + * @brief Check whether the widget is faulted. + * @since_tizen 2.3.1 + * @param[in] widget a widget object + * @return faulted state of the widget + * @retval 1 for faulted state + * @retval 0 for not faulted state + */ +extern int widget_viewer_evas_is_faulted(Evas_Object *widget); + +/** + * @brief Fixes visibility of the widget + * @details If you don't want to change the visibility automatically, freeze it.\n + * The visibility will not be changed even though a box disappeared(hidden)/displayed(shown) from/on the screen. + * @since_tizen 2.3.1 + * @param[in] widget a widget object + * @param[in] status a visibility status of the widget + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_NONE if success + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + * @see #widget_visibility_status_e + */ +extern int widget_viewer_evas_freeze_visibility(Evas_Object *widget, widget_visibility_status_e status); + +/** + * @brief Unfixes visibility of the widget + * @details If you want to let the visibility change automatically again, call this function. + * @since_tizen 2.3.1 + * @param[in] widget a widget object + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_NONE if success + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid argument + */ +extern int widget_viewer_evas_thaw_visibility(Evas_Object *widget); + +/** + * @brief Get the fixed state of visibility option. + * @since_tizen 2.3.1 + * @param[in] widget a widget object + * @return fixed state of visibility + * @retval 1 for fixed state + * @retval 0 for not fixed state + */ +extern int widget_viewer_evas_get_freeze_visibility(Evas_Object *widget); + +/** + * @brief Validate the object, whether it is a widget object or not + * @since_tizen 2.3.1 + * @param[in] widget a widget object + * @return result of validation + * @retval 1 this is a widget + * @retval 0 this is not a widget + */ +extern int widget_viewer_evas_is_widget(Evas_Object *widget); + +/** + * @brief Before delete a widget, set the deletion mode + * @since_tizen 2.3.1 + * @param[in] widget a widget object which will be deleted soon + * @param[in] flag Pass 1 if you delete this widget instance permanently, or pass 0 if you want to keep it and it will be re-created soon. + */ +extern void widget_viewer_evas_set_permanent_delete(Evas_Object *widget, int flag); + +#ifdef __cplusplus +} +#endif + +#endif + +/* End of a file */ diff --git a/widget_viewer_evas/include/widget_viewer_evas_internal.h b/widget_viewer_evas/include/widget_viewer_evas_internal.h new file mode 100755 index 0000000..819723e --- /dev/null +++ b/widget_viewer_evas/include/widget_viewer_evas_internal.h @@ -0,0 +1,252 @@ +/* + * Samsung API + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Flora License, Version 1.1 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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. + */ + +#ifndef __WIDGET_VIEWER_EVAS_INTERNAL_H +#define __WIDGET_VIEWER_EVAS_INTERNAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "widget_viewer_evas.h" + +#define WIDGET_SMART_SIGNAL_GBAR_DESTROYED "gbar,destroyed" /**< GBAR is destroyed */ +#define WIDGET_SMART_SIGNAL_GBAR_ABORTED "gbar,aborted" /**< GBAR creation is aborted */ +#define WIDGET_SMART_SIGNAL_GBAR_CREATED "gbar,created" /**< GBAR is created */ +#define WIDGET_SMART_SIGNAL_FLICKDOWN_CANCELLED "flickdown,cancelled" /**< Flick down is canceld */ + + +#define WIDGET_VIEWER_EVAS_SHARED_CONTENT 0x0002 /**< Multiple instances will share the content of one real instance */ +#define WIDGET_VIEWER_EVAS_SUPPORT_GBAR 0x0004 /**< GBAR will be used */ + +typedef enum widget_access_result { + WIDGET_ACCESS_RESULT_DONE = 0x00, + WIDGET_ACCESS_RESULT_FIRST = 0x01, + WIDGET_ACCESS_RESULT_LAST = 0x02, + WIDGET_ACCESS_RESULT_READ = 0x04, + WIDGET_ACCESS_RESULT_ERROR = 0x80, + WIDGET_ACCESS_RESULT_UNKNOWN = 0xFF +} widget_access_result_e; + +/** + * @since_tizen 2.3.1 + * @brief event type for evas raw event + */ +typedef enum widget_evas_raw_event_type { + WIDGET_VIEWER_EVAS_RAW_DELETE = 0x00, + WIDGET_VIEWER_EVAS_RAW_CREATE = 0x02, + WIDGET_VIEWER_EVAS_RAW_MAX = 0xff, +} widget_evas_raw_event_type_e; + +/** + * @since_tizen 2.3.1 + * @brief Options for each widget. + */ +typedef enum widget_option_widget_type { + WIDGET_OPTION_WIDGET_DELAYED_RESUME = 0x01, /* 0: Follow the global configuration, 1: Disable the Delayed Pause Resume, 2: Enable the Delayed Pause Resume */ + WIDGET_OPTION_UNKNOWN = 0xFF +} widget_option_widget_e; + +/** + * @since_tizen 2.3.1 + * @brief Data structure for smart callback user parameter + */ +typedef struct widget_evas_raw_event_info { + const char *pkgname; + enum widget_evas_raw_event_type type; + int error; + Evas_Object *widget; +} widget_evas_raw_event_info_s; + +/** + * @brief Close the Glance Bar if it is opened + * @since_tizen 2.3.1 + * @param[in] widget widget object + * @return 0 on success, otherwise a negative error value + */ +extern int widget_viewer_evas_destroy_glance_bar(Evas_Object *widget); + +/** + * @brief Set the viewe port of given widget + * @since_tizen 2.3.1 + * @param[in] widget + * @param[in] x + * @param[in] y + * @param[in] w + * @param[in] h + * @return 0 on success, otherwise a negative error value + */ +extern int widget_viewer_evas_set_view_port(Evas_Object *widget, int x, int y, int w, int h); + +/** + * @brief Get the current view port of given widget + * @since_tizen 2.3.1 + * @param[in] widget + * @param[out] x + * @param[out] y + * @param[out] w + * @param[out] h + * @return 0 on success, otherwise a negative error value + */ +extern int widget_viewer_evas_get_view_port(Evas_Object *widget, int *x, int *y, int *w, int *h); + + +/** + * @brief Feeds accessibility events + * @since_tizen 2.3.1 + * @param[in] widget + * @param[in] type + * @param[in] info + * @param[in] ret_cb + * @param[in] dta + * @return 0 on success, otherwise a negative error value + */ +extern int widget_viewer_evas_feed_access_event(Evas_Object *widget, int type, void *info, void (*ret_cb)(Evas_Object *obj, int ret, void *data), void *data); + +/** + * @brief Dump a contents of widget to a given filename. + * @since_tizen 2.3.1 + * @param[in] widget widget object + * @param[in] filename Filename will be used for saving content of a widget + * @return 0 on success, otherwise a negative error value + */ +extern int widget_viewer_evas_dump_to_file(Evas_Object *widget, const char *filename); + + +/** + * @brief Subscribes an event for widgets only in a given cluster and sub-cluster. + * @details If you wrote a view-only client, + * you can receive the event of specific widgets which belong to a given cluster/category. + * But you cannot modify their attributes (such as size, ...). + * @since_tizen 2.3.1 + * @privlevel public + * @privilege %http://tizen.org/privilege/widget.viewer + * @param[in] cluster Cluster ("*" can be used for subscribe all cluster's widgets event; If you use the "*", value in the category will be ignored) + * @param[in] category Category ("*" can be used for subscribe widgets events of all category(sub-cluster) in a given "cluster") + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_ERROR_FAULT Unrecoverable error occurred + * @retval #WIDGET_ERROR_NONE Successfully requested + * @see widget_viewer_evas_unsubscribe_group() + */ +extern int widget_viewer_evas_subscribe_group(const char *cluster, const char *sub_cluster); + + +/** + * @brief Unsubscribes an event for the widgets, but you will receive already added widgets events. + * @since_tizen 2.3.1 + * @privlevel public + * @privilege %http://tizen.org/privilege/widget.viewer + * @param[in] cluster Cluster("*" can be used for subscribe all cluster's widgets event; If you use the "*", value in the category will be ignored) + * @param[in] category Category ("*" can be used for subscribe all sub-cluster's widgets event in a given "cluster") + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_ERROR_FAULT Unrecoverable error occurred + * @retval #WIDGET_ERROR_NONE Successfully requested + * @see widget_subscribe_group() + */ +extern int widget_viewer_evas_unsubscribe_group(const char *cluster, const char *sub_cluster); + +/** + * @brief Subscribes events of widgets which is categorized by given "category" string. + * "category" is written in the XML file of each widget manifest file. + * After subscribe the category, the master will send created event for all created widgets, + * Also it will notify client when a new widget is created. + * @since_tizen 2.3.1 + * @privlevel public + * @privilege %http://tizen.org/privilege/widget.viewer + * @param[in] category Category name + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_ERROR_FAULT Unrecoverable error occurred + * @retval #WIDGET_ERROR_NONE Successfully requested + * @see widget_viewer_evas_unsubscribe_category() + */ +extern int widget_viewer_evas_subscribe_category(const char *category); + +/** + * @brief Unsubscribes events of widgets. + * @since_tizen 2.3.1 + * @privlevel public + * @privilege %http://tizen.org/privilege/widget.viewer + * @param[in] category Category name + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_ERROR_FAULT Unrecoverable error occurred + * @retval #WIDGET_ERROR_NONE Successfully requested + * @see widget_viewer_evas_subscribe_category() + */ +extern int widget_viewer_evas_unsubscribe_category(const char *category); + +/** + * @brief Callback function for handling raw event + * @since_tizen 2.3.1 + * @param[in] info + * @param[in] data + */ +typedef void (*raw_event_cb)(widget_evas_raw_event_info_s *info, void *data); + +/** + * @brief Register a callback function for subscribing raw event. + * @since_tizen 2.3.1 + * @param[in] type + * @param[in] cb + * @param[in] data + */ +extern int widget_viewer_evas_set_raw_event_callback(widget_evas_raw_event_type_e type, raw_event_cb cb, void *data); + +/** + * @brief Unregister a callback function for subscribing raw event. + * @since_tizen 2.3.1 + * @param[in] type + * @param[in] cb + * @param[in] data + * @return 0 on success, otherwise a negative error value + */ +extern int widget_viewer_evas_unset_raw_event_callback(widget_evas_raw_event_type_e type, raw_event_cb cb, void *data); + +extern int widget_viewer_evas_get_instance_id(Evas_Object *widget, char **instance_id); + +extern int widget_viewer_evas_set_widget_option(Evas_Object *widget, widget_option_widget_e option, int value); + +/** + * @brief Emits a text signal to the given widget + * @since_tizen 2.3.1 + * @privlevel public + * @privilege %http://tizen.org/privilege/widget.viewer + * @remarks + * This is an ASYNCHRONOUS API. + * This function is Asynchronous, so you will get the result from @a smart callback, if you failed to send a text signal, + * this function will returns proper error code. + * @param[in] widget a widget object + * @param[in] event_info.signal_name name of text signal + * @param[in] event_info.source source string + * @param[in] event_info.sx Start X + * @param[in] event_info.sy Start Y + * @param[in] event_info.ex End X + * @param[in] event_info.ey End Y + * @return 0 on success, otherwise a negative error value + * @retval #WIDGET_STATUS_ERROR_NONE Successfully emitted + * @retval #WIDGET_STATUS_ERROR_INVALID_PARAMETER Invalid parameters + * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred + * @see #widget_text_signal_s + * @see #WIDGET_TEXT_SIGNAL_NAME_EDIT_MODE_ON + * @see #WIDGET_TEXT_SIGNAL_NAME_EDIT_MODE_OFF + */ +extern int widget_viewer_evas_emit_text_signal(Evas_Object *widget, widget_text_signal_s event_info, void *data); + +#ifdef __cplusplus +} +#endif + +#endif /* __WIDGET_VIEWER_EVAS_INTERNAL_H */ diff --git a/widget_viewer_evas/res/CMakeLists.txt b/widget_viewer_evas/res/CMakeLists.txt new file mode 100644 index 0000000..7e43a68 --- /dev/null +++ b/widget_viewer_evas/res/CMakeLists.txt @@ -0,0 +1,11 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) + +# install edj +ADD_CUSTOM_TARGET(widget_viewer_evas.edj + COMMAND edje_cc -id ${CMAKE_CURRENT_SOURCE_DIR}/images ${EDJE_CFLAGS} + ${CMAKE_CURRENT_SOURCE_DIR}/widget_viewer_evas.edc widget_viewer_evas.edj + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/widget_viewer_evas.edc +) +ADD_DEPENDENCIES(${PROJECT_NAME} widget_viewer_evas.edj) +INSTALL(FILES widget_viewer_evas.edj DESTINATION ${EDJDIR}) +INSTALL(FILES unknown.png DESTINATION ${IMGDIR}) diff --git a/widget_viewer_evas/res/unknown.png b/widget_viewer_evas/res/unknown.png new file mode 100644 index 0000000..535db60 Binary files /dev/null and b/widget_viewer_evas/res/unknown.png differ diff --git a/widget_viewer_evas/res/widget_viewer_evas.edc b/widget_viewer_evas/res/widget_viewer_evas.edc new file mode 100644 index 0000000..0ced01c --- /dev/null +++ b/widget_viewer_evas/res/widget_viewer_evas.edc @@ -0,0 +1,430 @@ +/* + * Samsung API + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Flora License, Version 1.1 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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. + */ + +#if !defined(_WIDGET_INCLUDED) +collections { +#endif + styles { + style { + name: "overlay,text"; + base: "font=Tizen text_class=tizen font_size=30 align=center color=#FFFFFF ellipsis=1.0 wrap=char"; + tag: "br" "\n"; + tag: "hilight" "+ font=Tizen:style=Bold"; + tag: "b" "+ font=Tizen:style=Bold"; + tag: "tab" "\t"; + } + } + + group + { + name: "overlay"; + parts + { + part { + name: "preview"; + type: SWALLOW; + description { + state: "default" 0.0; + rel1 { relative: 0.0 0.0; } + rel2 { relative: 1.0 1.0; } + } + } + + part { + name: "bg,img"; + type: RECT; + description { + state: "default" 0.0; + rel1 { relative: 0.0 0.0; } + rel2 { relative: 1.0 1.0; } + color: 100 100 100 100; + } + description { + state: "hide" 0.0; + inherit: "default" 0.0; + visible: 0; + } + } + + part { + name: "text"; + type: TEXTBLOCK; + description { + state: "default" 0.0; + rel1 { relative: 20/320 200/320; } + rel2 { relative: 300/320 320/320; } + max: 280 -1; + text { + style: "overlay,text"; + min: 0 0; + } + } + description { + state: "hide" 0.0; + inherit: "default" 0.0; + visible: 0; + } + } + } + + programs { + program { + name: "disable,text"; + signal: "disable"; + source: "text"; + action: STATE_SET "hide" 0.0; + target: "text"; + target: "bg,img"; + } + + program { + name: "enable,text"; + signal: "enable"; + source: "text"; + action: STATE_SET "default" 0.0; + target: "text"; + target: "bg,img"; + } + } + } + + group + { + name: "widget,image"; + parts + { + part { + name: "front"; + type: RECT; + description { + state: "default" 0.0; + rel1 { relative: 0.0 0.0; } + rel2 { relative: 1.0 1.0; } + visible: 1; + } + description { + state: "to,back" 0.0; + inherit: "default" 0.0; + visible: 0; + } + } + + part { + name: "front,content"; + type: SWALLOW; + clip_to: "front"; + description { + state: "default" 0.0; + rel1 { relative: 0.0 0.0; } + rel2 { relative: 1.0 1.0; } + } + } + + part { + name: "back"; + type: RECT; + description { + state: "default" 0.0; + rel1 { relative: 0.0 0.0; } + rel2 { relative: 1.0 1.0; } + visible: 0; + } + description { + state: "to,back" 0.0; + inherit: "default" 0.0; + visible: 1; + } + } + + part { + name: "back,content"; + type: SWALLOW; + clip_to: "back"; + description { + state: "default" 0.0; + rel1 { relative: 0.0 0.0; } + rel2 { relative: 1.0 1.0; } + } + } + } + + programs + { + program { + name: "turn,to,back,front"; + signal: "to,back"; + source: "turn"; + action: STATE_SET "to,back" 0.0; + target: "front"; + target: "back"; + transition: LINEAR 0.5; + after: "play,end"; + } + + program { + name: "turn,to,front"; + signal: "to,front"; + source: "turn"; + action: STATE_SET "default" 0.0; + target: "front"; + target: "back"; + transition: LINEAR 0.5; + after: "play,end"; + } + + program { + name: "play,end"; + action: SIGNAL_EMIT "done" "turn"; + } + } + } + + group + { + name: "widget"; + parts + { + part { + name: "widget,content"; + type: SWALLOW; + description { + state: "default" 0.0; + rel1 { relative: 0.0 0.0; } + rel2 { relative: 1.0 1.0; } + map { + on: 0; + } + } + description { + state: "tilt" 0.0; + inherit: "default" 0.0; + map { + on: 1; + rotation { + x: 30.0; + } + } + } + description { + state: "move,down" 0.0; + inherit: "default" 0.0; + rel1 { relative: 0.0 0.2; } + rel2 { relative: 1.0 1.2; } + } + } + + part { + name: "scroller"; + mouse_events: 1; + repeat_events: 1; + type: SWALLOW; + description { + state: "default" 0.0; + rel1 { relative: 0.0 0.0; } + rel2 { relative: 1.0 1.0; } + } + } + + part { + name: "overlay"; + mouse_events: 1; + type: RECT; + description { + state: "default" 0.0; + rel1 { relative: 0.0 0.0; } + rel2 { relative: 1.0 1.0; } + color: 255 255 255 255; + visible: 1; + } + description { + state: "disable,overlay" 0.0; + inherit: "default" 0.0; + color: 0 0 0 0; + visible: 0; + } + } + + part { + name: "overlay,content"; + mouse_events: 1; + type: SWALLOW; + clip_to: "overlay"; + description { + state: "default" 0.0; + rel1 { relative: 0.0 0.0; } + rel2 { relative: 1.0 1.0; } + } + } + } + + programs + { + program { + name: "reset,overlay"; + signal: "reset"; + source: "overlay"; + action: STATE_SET "disable,overlay" 0.0; + target: "overlay"; + } + program { + name: "enable,overlay"; + signal: "enable"; + source: "overlay"; + action: STATE_SET "default" 0.0; + target: "overlay"; + transition: LINEAR 0.5; + after: "animation,done"; + } + + program { + name: "disable,overlay"; + signal: "disable"; + source: "overlay"; + action: STATE_SET "disable,overlay" 0.0; + target: "overlay"; + transition: LINEAR 0.5; + after: "animation,done"; + } + + program { + name: "tilt,start"; + signal: "tilt"; + source: "content"; + action: STATE_SET "tilt" 0.0; + target: "widget,content"; + transition: LINEAR 0.15; + after: "tilt,end"; + } + + program { + name: "tilt,end"; + action: STATE_SET "default" 0.0; + target: "widget,content"; + transition: LINEAR 0.15; + after: "animation,done"; + } + + program { + name: "move,down,start"; + signal: "move,down"; + source: "content"; + action: STATE_SET "move,down" 0.0; + target: "widget,content"; + transition: LINEAR 0.15; + after: "move,down,end"; + } + + program { + name: "move,down,end"; + action: STATE_SET "default" 0.0; + target: "widget,content"; + transition: LINEAR 0.15; + after: "animation,done"; + } + + program { + name: "animation,done"; + action: SIGNAL_EMIT "finished" "animation"; + } + } + } + + group + { + name: "gbar"; + parts + { + part { + name: "gbar,content"; + type: SWALLOW; + description { + state: "default" 0.0; + rel1 { relative: 0.0 0.0; } + rel2 { relative: 1.0 1.0; } + } + } + + part { + name: "overlay"; + type: RECT; + description { + state: "default" 0.0; + rel1 { relative: 0.0 0.0; } + rel2 { relative: 1.0 1.0; } + color: 255 255 255 255; + visible: 1; + } + description { + state: "disable,overlay" 0.0; + inherit: "default" 0.0; + color: 0 0 0 0; + visible: 0; + } + } + + part { + name: "overlay,content"; + type: SWALLOW; + clip_to: "overlay"; + description { + state: "default" 0.0; + rel1 { relative: 0.0 0.0; } + rel2 { relative: 1.0 1.0; } + } + } + } + + programs + { + program { + name: "reset,overlay"; + signal: "reset"; + source: "overlay"; + action: STATE_SET "disable,overlay" 0.0; + target: "overlay"; + } + program { + name: "enable,overlay"; + signal: "enable"; + source: "overlay"; + action: STATE_SET "default" 0.0; + target: "overlay"; + transition: LINEAR 0.15; + after: "animation,done"; + } + + program { + name: "disable,overlay"; + signal: "disable"; + source: "overlay"; + action: STATE_SET "disable,overlay" 0.0; + target: "overlay"; + transition: LINEAR 0.15; + after: "animation,done"; + } + + program { + name: "animation,done"; + action: SIGNAL_EMIT "finished" "animation"; + } + } + } +#if !defined(_WIDGET_INCLUDED) +} +#endif + +/* End of a file */ diff --git a/widget_viewer_evas/src/widget_viewer_evas.c b/widget_viewer_evas/src/widget_viewer_evas.c new file mode 100755 index 0000000..4c483e7 --- /dev/null +++ b/widget_viewer_evas/src/widget_viewer_evas.c @@ -0,0 +1,7190 @@ +/* + * Samsung API + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Flora License, Version 1.1 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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 + + +#if defined(LOG_TAG) +#undef LOG_TAG +#endif +#define LOG_TAG "WIDGET_EVAS" +#include + +#include "widget_viewer_evas.h" +#include "widget_viewer_evas_internal.h" + +#if !defined(WIDGET_COUNT_OF_SIZE_TYPE) + #define WIDGET_COUNT_OF_SIZE_TYPE 13 +#endif + +#if !defined(SECURE_LOGD) +#define SECURE_LOGD LOGD +#endif + +#if !defined(SECURE_LOGW) +#define SECURE_LOGW LOGW +#endif + +#if !defined(SECURE_LOGE) +#define SECURE_LOGE LOGE +#endif + +#if !defined(S_) +#define S_(str) dgettext("sys_string", str) +#endif + +#if !defined(T_) +#define T_(str) dgettext(PACKAGE, str) +#endif + +#if !defined(N_) +#define N_(str) (str) +#endif + +#if !defined(_) +#define _(str) gettext(str) +#endif + + +#if !defined(DbgPrint) +#define DbgPrint(format, arg...) SECURE_LOGD(format, ##arg) +#endif + +#if !defined(ErrPrint) +#define ErrPrint(format, arg...) SECURE_LOGE(format, ##arg) +#endif + +#if !defined(WarnPrint) +#define WarnPrint(format, arg...) SECURE_LOGW(format, ##arg) +#endif + +#if !defined(WIDGET_VIEWER_EVAS_RESOURCE_EDJ) +#define WIDGET_VIEWER_EVAS_RESOURCE_EDJ "/usr/share/widget_viewer_evas/res/edje/widget_viewer_evas.edj" +#endif + +#if !defined(WIDGET_VIEWER_EVAS_UNKNOWN) +#define WIDGET_VIEWER_EVAS_UNKNOWN "/usr/share/widget_viewer_evas/res/image/unknown.png" +#endif + +#if !defined(WIDGET_VIEWER_EVAS_RESOURCE_GBAR) +#define WIDGET_VIEWER_EVAS_RESOURCE_GBAR "gbar" +#endif + +#if !defined(WIDGET_VIEWER_EVAS_RESOURCE_LB) +#define WIDGET_VIEWER_EVAS_RESOURCE_LB "widget" +#endif + +#if !defined(WIDGET_VIEWER_EVAS_RESOURCE_IMG) +#define WIDGET_VIEWER_EVAS_RESOURCE_IMG "widget,image" +#endif + +#if !defined(WIDGET_VIEWER_EVAS_RESOURCE_OVERLAY_LOADING) +#define WIDGET_VIEWER_EVAS_RESOURCE_OVERLAY_LOADING "overlay" +#endif + +#define DEFAULT_OVERLAY_COUNTER 2 +#define DEFAULT_OVERLAY_WAIT_TIME 1.0f + +#define WIDGET_CLASS_NAME "widget" + +#define WIDGET_KEEP_BUFFER -2 + +#define DEFAULT_CLUSTER "user,created" +#define DEFAULT_CATEGORY "default" + +// Enable this to apply shadow effect to image object (for text widget) +// #define SUPPORT_IMAGE_EFFECT + +int errno; + +/*! + * \note + * Detect click event if the pointer does moved in this region (x , y < 5 pixels) + */ +#define CLICK_REGION 22 + +static struct { + Evas_Smart_Class sc; + Evas_Smart *smart; + Eina_List *list; + struct { + Eina_List *delete_list; + Eina_List *create_list; + } raw_event; + int screen_width; + int screen_height; + + union _conf { + struct _field { + unsigned int user_view_port: 1; + unsigned int force_to_buffer: 1; + unsigned int support_gbar: 1; + unsigned int manual_pause_resume: 1; + unsigned int use_fixed_size: 1; + unsigned int easy_mode: 1; + unsigned int is_scroll_x: 1; + unsigned int is_scroll_y: 1; + unsigned int auto_feed: 1; + unsigned int delayed_resume: 1; + unsigned int sensitive_move: 1; + unsigned int render_animator: 1; + unsigned int auto_render_selector: 1; + unsigned int skip_acquire: 1; + + unsigned int reserved: 18; + } field; + unsigned int mask; + } conf; + + Evas_Object *win; + Ecore_Animator *renderer; + Eina_List *widget_dirty_objects; + Eina_List *gbar_dirty_objects; + Eina_List *subscribed_category_list; + Eina_List *subscribed_group_list; + + int initialized; +} s_info = { + .sc = EVAS_SMART_CLASS_INIT_NAME_VERSION(WIDGET_CLASS_NAME), + .smart = NULL, + .list = NULL, + .raw_event = { + .delete_list = NULL, + .create_list = NULL, + }, + .conf = { + .mask = 0, + }, + .screen_width = 720, + .screen_height = 1280, + .win = NULL, + .renderer = NULL, + .widget_dirty_objects = NULL, + .gbar_dirty_objects = NULL, + .subscribed_category_list = NULL, + .subscribed_group_list = NULL, + .initialized = 0, +}; + +struct subscribe_group { + char *cluster; + char *sub_cluster; +}; + +struct subscribe_category { + char *category; +}; + +struct access_ret_cb_data { + Evas_Object *obj; + void (*ret_cb)(Evas_Object *, int, void *); + void *data; +}; + +struct acquire_data { + struct widget_data *data; + Evas_Object *content; + int w; + int h; +}; + +enum CANCEL_CLICK { + CANCEL_DISABLED = 0x0, + CANCEL_USER = 0x01, + CANCEL_PROCESSED = 0x02 +}; + +struct widget_data { + enum { + WIDGET_DATA_CREATED = 0x00beef00, + WIDGET_DATA_DELETED = 0x0d0e0a0d, + } state; + struct widget *handle; + Evas *e; + Evas_Object *stage; /*!< Do not resize this directly, it should be resized via XX_update_geometry */ + Evas_Object *parent; + + Evas_Object *widget_layout; /*!< Layout of widget content part */ + Evas_Object *gbar_layout; /*!< Layout of GBAR content part */ + + Evas_Object *widget; /*!< Container object */ + + struct view_port { + int x; + int y; + int w; + int h; + } view_port; + + char *widget_id; + char *content; + char *cluster; + char *category; + double period; + + void *widget_fb; + void *gbar_fb; + + unsigned int gbar_pixmap; + unsigned int widget_pixmap; + + unsigned int *gbar_extra; + unsigned int *widget_extra; + int gbar_extra_cnt; + int widget_extra_cnt; + + int widget_latest_idx; /* -1 = primary buffer, 0 ~ = extra buffer */ + int gbar_latest_idx; /* -1 = primary buffer, 0 ~ = extra buffer */ + + struct down { + int x; + int y; + + struct { + int x; + int y; + int w; + int h; + } geo; + } down; + + int x; + int y; + + int widget_width; + int widget_height; + widget_size_type_e size_type; + + union { + struct { + unsigned int pressed: 1; /**< Mouse is pressed */ + unsigned int touch_effect: 1; /**< Requires to play touch effect */ + unsigned int mouse_event: 1; /**< Requires to feed mouse event */ + unsigned int scroll_x: 1; /**< */ + unsigned int scroll_y: 1; + unsigned int faulted: 1; + unsigned int flick_down: 1; + unsigned int gbar_created: 1; + + unsigned int created: 1; + unsigned int deleted: 1; + unsigned int widget_pixmap_acquire_requested: 1; + unsigned int gbar_pixmap_acquire_requested: 1; + unsigned int cancel_scroll_x: 1; + unsigned int cancel_scroll_y: 1; + unsigned int cancel_click: 2; + unsigned int disable_preview: 1; + unsigned int disable_loading: 1; + unsigned int disable_text: 1; + unsigned int widget_overlay_loaded: 1; + unsigned int gbar_overlay_loaded: 1; + + unsigned int freeze_visibility: 1; + + unsigned int widget_dirty: 1; + unsigned int gbar_dirty: 1; + + unsigned int send_delete: 1; + unsigned int permanent_delete: 1; + + unsigned int delayed_resume: 2; + + unsigned int reserved: 4; + } field; /* Do we really have the performance loss because of bit fields? */ + + unsigned int flags; + } is; + + int refcnt; + int overlay_update_counter; + Ecore_Timer *overlay_timer; + widget_visibility_status_e freezed_visibility; + + Eina_List *gbar_script_object_list; + Eina_List *widget_script_object_list; + + Ecore_Timer *delayed_resume_timer; +}; + +struct script_object { + char *id; + Evas_Object *obj; + Evas_Object *parent; /* Swallowee object : Before delete 'obj', it should be unswallowed from this object */ +}; + +enum EFFECT_MASK { + EFFECT_NONE = 0x0, + EFFECT_WIDTH = 0x01, + EFFECT_HEIGHT = 0x02, + EFFECT_BOTH = 0x03, + EFFECT_MOVE = 0x10 +}; + +struct animation_data { + Ecore_Timer *timer; + Evas_Object *obj; + + unsigned int effect_mask; + int w; + int h; + int x; + int y; +}; + +struct raw_event_cbdata { + void (*cb)(struct widget_evas_raw_event_info *info, void *data); + void *data; +}; + +struct image_option { + int orient; + int aspect; + enum { + FILL_DISABLE, + FILL_IN_SIZE, + FILL_OVER_SIZE, + FILL_FIT_SIZE + } fill; + + struct shadow { + int enabled; + int angle; + int offset; + int softness; + int color; + } shadow; + + int width; + int height; +}; + +static int widget_fault_handler(enum widget_fault_type fault, const char *pkgname, const char *filename, const char *funcname, void *data); +static int widget_event_handler(struct widget *handle, enum widget_event_type event, void *data); + +static int widget_system_created(struct widget *handle, struct widget_data *data); +static void __widget_created_cb(struct widget *handle, int ret, void *cbdata); +static void __widget_overlay_loading(struct widget_data *data); +static void __widget_overlay_faulted(struct widget_data *data); +static void __widget_overlay_disable(struct widget_data *data, int no_timer); + +static void gbar_overlay_loading(struct widget_data *data); +static void gbar_overlay_disable(struct widget_data *data); + +static void update_widget_geometry(struct acquire_data *acquire_data); +static void update_gbar_geometry(struct acquire_data *acquire_data); +static void update_stage_geometry(struct acquire_data *acquire_data); +static void animator_del_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_info); + +static void remove_widget_dirty_object_list(struct widget_data *data); +static void remove_gbar_dirty_object_list(struct widget_data *data); +static void append_widget_dirty_object_list(struct widget_data *data, int idx); +static void append_gbar_dirty_object_list(struct widget_data *data, int idx); +static void __widget_event_widget_updated(struct widget_data *data); +static void __widget_event_gbar_updated(struct widget_data *data); + +static struct widget_data *get_smart_data(Evas_Object *widget) +{ + if (widget && evas_object_smart_type_check(widget, WIDGET_CLASS_NAME)) { + struct widget_data *data; + + data = evas_object_smart_data_get(widget); + if (data) { + if (data->state == WIDGET_DATA_CREATED) { + return data; + } + + ErrPrint("smart data is not valid\n"); + } else { + ErrPrint("smart data is not exists\n"); + } + } + + return NULL; +} + +static struct widget_data *get_smart_data_from_handle(widget_h handle) +{ + Evas_Object *widget; + // struct widget_data *data; + + widget = widget_viewer_get_data(handle); + if (!widget) { + return NULL; + } + + return get_smart_data(widget); +} + +static Evas_Object *find_script_object(struct widget_data *data, int gbar, const char *id) +{ + Eina_List *script_object_list; + struct script_object *so; + Eina_List *l; + + if (gbar) { + if (!data->gbar_layout) { + return NULL; + } + + script_object_list = data->gbar_script_object_list; + } else { + if (!data->widget_layout) { + return NULL; + } + + script_object_list = data->widget_script_object_list; + } + + if (!id) { + so = eina_list_nth(script_object_list, 0); + return so ? so->obj : NULL; + } + + EINA_LIST_FOREACH(script_object_list, l, so) { + if (so->id && !strcmp(so->id, id)) { + return so->obj; + } + } + + return NULL; +} + +static void gbar_script_del_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_info) +{ + struct widget_data *data = cbdata; + Eina_List *l; + Eina_List *n; + struct script_object *so; + + EINA_LIST_FOREACH_SAFE(data->gbar_script_object_list, l, n, so) { + if (so->obj == obj) { + data->gbar_script_object_list = eina_list_remove(data->gbar_script_object_list, so); + free(so->id); + free(so); + break; + } + } +} + +static void __widget_script_del_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_info) +{ + struct widget_data *data = cbdata; + Eina_List *l; + Eina_List *n; + struct script_object *so; + + EINA_LIST_FOREACH_SAFE(data->widget_script_object_list, l, n, so) { + if (so->obj == obj) { + data->widget_script_object_list = eina_list_remove(data->widget_script_object_list, so); + free(so->id); + free(so); + break; + } + } +} + +static void script_signal_forwarder(void *cbdata, Evas_Object *obj, const char *signal_name, const char *source) +{ + struct widget_data *data = cbdata; + struct widget_text_signal event_info = { + .signal_name = signal_name, + .source = source, + .geometry = { + .sx = 0.0f, + .sy = 0.0f, + .ex = 1.0f, + .ey = 1.0f, + } + }; + + widget_viewer_emit_text_signal(data->handle, &event_info, NULL, NULL); +} + +static int append_script_object(struct widget_data *data, int gbar, const char *id, Evas_Object *parent, Evas_Object *child) +{ + struct script_object *so; + + so = malloc(sizeof(*so)); + if (!so) { + ErrPrint("malloc: %d\n", errno); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + if (id) { + so->id = strdup(id); + if (!so->id) { + ErrPrint("strdup: %d\n", errno); + free(so); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + } else { + so->id = NULL; + } + + so->obj = child; + so->parent = parent; + + if (gbar) { + data->gbar_script_object_list = eina_list_append(data->gbar_script_object_list, so); + evas_object_event_callback_add(child, EVAS_CALLBACK_DEL, gbar_script_del_cb, data); + } else { + data->widget_script_object_list = eina_list_append(data->widget_script_object_list, so); + evas_object_event_callback_add(child, EVAS_CALLBACK_DEL, __widget_script_del_cb, data); + } + + elm_object_signal_callback_add(child, "*", "*", script_signal_forwarder, data); + return WIDGET_ERROR_NONE; +} + +static inline void reset_scroller(struct widget_data *data) +{ + Evas_Object *scroller; + + if (!data->widget_layout) { + return; + } + + scroller = elm_object_part_content_get(data->widget_layout, "scroller"); + if (!scroller) { + return; + } + + elm_scroller_region_show(scroller, 0, data->widget_height >> 1, data->widget_width, data->widget_height); +} + +static int invoke_raw_event_callback(enum widget_evas_raw_event_type type, const char *pkgname, Evas_Object *widget, int error) +{ + struct widget_evas_raw_event_info info; + struct raw_event_cbdata *cbdata; + Eina_List *l; + Eina_List *n; + int cnt = 0; + + info.pkgname = pkgname; + info.widget = widget; + info.error = error; + info.type = type; + + switch (type) { + case WIDGET_VIEWER_EVAS_RAW_DELETE: + EINA_LIST_FOREACH_SAFE(s_info.raw_event.delete_list, l, n, cbdata) { + if (cbdata->cb) { + cbdata->cb(&info, cbdata->data); + cnt++; + } + } + break; + case WIDGET_VIEWER_EVAS_RAW_CREATE: + EINA_LIST_FOREACH_SAFE(s_info.raw_event.create_list, l, n, cbdata) { + if (cbdata->cb) { + cbdata->cb(&info, cbdata->data); + cnt++; + } + } + break; + default: + break; + } + + return cnt; +} + +static widget_size_type_e find_size_type(struct widget_data *data, int w, int h) +{ + int cnt = WIDGET_COUNT_OF_SIZE_TYPE; + int i; + int *_w; + int *_h; + widget_size_type_e type = WIDGET_SIZE_TYPE_UNKNOWN; + int find; + int ret_type = WIDGET_SIZE_TYPE_UNKNOWN; + int delta; + + if (widget_service_get_supported_sizes(data->widget_id, &cnt, &_w, &_h) < 0) { + ErrPrint("No available sizes: %s\n", data->widget_id); + return WIDGET_SIZE_TYPE_UNKNOWN; + } + + find = 0x7FFFFFFF; + for (i = 0; i < cnt; i++) { + widget_service_get_size_type(_w[i], _h[i], &type); + + if (!s_info.conf.field.easy_mode) { + switch (type) { + case WIDGET_SIZE_TYPE_EASY_1x1: + case WIDGET_SIZE_TYPE_EASY_3x1: + case WIDGET_SIZE_TYPE_EASY_3x3: + continue; + default: + break; + } + } else { + switch (type) { + case WIDGET_SIZE_TYPE_EASY_1x1: + case WIDGET_SIZE_TYPE_EASY_3x1: + case WIDGET_SIZE_TYPE_EASY_3x3: + break; + default: + continue; + } + } + + delta = abs(_w[i] - w) + abs(_h[i] - h); + if (delta < find) { + find = delta; + ret_type = type; + } + } + + if (_w) + free(_w); + if (_h) + free(_h); + + return ret_type; +} + +static Eina_Bool effect_animator_cb(void *_data) +{ + struct animation_data *data = _data; + int w; + int h; + int x; + int y; + int move_x = 0; + int move_y = 0; + + evas_object_geometry_get(data->obj, &x, &y, &w, &h); + if (data->w == w && data->h == h) { + evas_object_event_callback_del(data->obj, EVAS_CALLBACK_DEL, animator_del_cb); + evas_object_data_del(data->obj, "animation"); + free(data); + return ECORE_CALLBACK_CANCEL; + } + + if (data->effect_mask & EFFECT_WIDTH) { + if (w < data->w) { + if (data->w - w > 100) { + w += 20; + move_x = 20; + } else if (data->w - w > 10) { + w += 8; + move_x = 8; + } else { + w++; + move_x = 1; + } + } else if (w > data->w) { + if (w - data->w > 100) { + w -= 20; + move_x = -20; + } else if (w - data->w > 10) { + w -= 8; + move_x = -8; + } else { + w--; + move_x = -1; + } + } + } else { + w = data->w; + } + + if (data->effect_mask & EFFECT_HEIGHT) { + if (h < data->h) { + if (data->h - h > 100) { + h += 20; + move_y = 20; + } else if (data->h - h > 10) { + h += 8; + move_y = 8; + } else { + h++; + move_y = 1; + } + } else if (h > data->h) { + if (h - data->h > 100) { + h -= 20; + move_y = -20; + } else if (h - data->h > 10) { + h -= 8; + move_y = -8; + } else { + h--; + move_y = -1; + } + } + } else { + h = data->h; + } + + if (data->effect_mask & EFFECT_MOVE) { + if (move_x) { + x -= move_x; + } + if (move_y) { + y -= move_y; + } + evas_object_move(data->obj, x, y); + } + + evas_object_resize(data->obj, w, h); + return ECORE_CALLBACK_RENEW; +} + +static void animator_del_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_info) +{ + struct animation_data *data; + + data = evas_object_data_del(obj, "animation"); + if (data) { + ecore_timer_del(data->timer); + free(data); + } +} + +static void effect_size_get(Evas_Object *obj, int *w, int *h) +{ + struct animation_data *data; + + data = evas_object_data_get(obj, "animation"); + if (data) { + *w = data->w; + *h = data->h; + } else { + evas_object_geometry_get(obj, NULL, NULL, w, h); + } +} + +static void effect_resize(Evas_Object *obj, int w, int h, unsigned int effect_mask) +{ + struct animation_data *data; + int ow; + int oh; + int ox; + int oy; + + evas_object_geometry_get(obj, &ox, &oy, &ow, &oh); + + data = evas_object_data_get(obj, "animation"); + if (data) { + if (ow == w && oh == h) { + evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, animator_del_cb); + evas_object_data_del(obj, "animation"); + free(data); + return; + } + /*! + * \note + * Update to new size + */ + data->w = w; + data->h = h; + return; + } else if (ow == w && oh == h) { + return; + } + + data = malloc(sizeof(*data)); + if (!data) { + ErrPrint("Heap: %d\n", errno); + return; + } + + data->obj = obj; + data->w = w; + data->h = h; + data->x = ox; + data->y = oy; + data->effect_mask = effect_mask; + + data->timer = ecore_timer_add(1.0f/60.0f, effect_animator_cb, data); + if (!data->timer) { + free(data); + return; + } + + evas_object_data_set(obj, "animation", data); + evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, animator_del_cb, data); +} + +struct widget_data *widget_ref(struct widget_data *data) +{ + data->refcnt++; + return data; +} + +static void dump_handle_list(void) +{ + Eina_List *l = NULL; + Eina_List *n; + Evas_Object *widget; + struct widget_data *data; + + DbgPrint("============== DUMP ==============="); + EINA_LIST_FOREACH_SAFE(s_info.list, l, n, widget) { + data = evas_object_smart_data_get(widget); + if (!data) { + continue; + } + + DbgPrint("data[%p] %s (%s)\n", data, data->widget_id, data->is.field.faulted ? "faulted" : "loaded"); + } + DbgPrint("==================================="); +} + +struct widget_data *widget_unref(struct widget_data *data) +{ + data->refcnt--; + DbgPrint("refcnt: %d (%s)\n", data->refcnt, data->widget_id); + if (data->refcnt != 0) { + return data; + } + + DbgPrint("Destroy widget data %p(%s)\n", data, data->widget_id); + free(data->content); + free(data->widget_id); + free(data->cluster); + free(data->category); + + if (data->overlay_timer) { + ecore_timer_del(data->overlay_timer); + data->overlay_timer = NULL; + } + + if (data->stage) { + DbgPrint("Remove Stage\n"); + evas_object_del(data->stage); + } + + if (data->widget_layout) { + Evas_Object *content; + + content = elm_object_part_content_unset(data->widget_layout, "widget,content"); + if (content) { + Evas_Object *front; + + front = elm_object_part_content_unset(content, "front,content"); + if (front) { + DbgPrint("Front image object is deleted\n"); + evas_object_del(front); + } + + DbgPrint("Content object deleted\n"); + evas_object_del(content); + } + + content = elm_object_part_content_unset(data->widget_layout, "overlay,content"); + if (content) { + DbgPrint("Overlay is deleted\n"); + evas_object_del(content); + } + + + DbgPrint("Remove WIDGET Layout\n"); + evas_object_del(data->widget_layout); + } + + if (data->gbar_layout) { + Evas_Object *content; + content = elm_object_part_content_get(data->gbar_layout, "gbar,content"); + if (content) { + Evas_Object *overlay; + overlay = elm_object_part_content_unset(content, "overlay,content"); + if (overlay) { + DbgPrint("Overlay is deleted\n"); + evas_object_del(overlay); + } + } + DbgPrint("Remove GBAR Layout\n"); + evas_object_del(data->gbar_layout); + } + + if (data->widget_fb) { + widget_viewer_release_buffer(data->widget_fb); + data->widget_fb = NULL; + } + + if (data->gbar_fb) { + widget_viewer_release_buffer(data->gbar_fb); + data->gbar_fb = NULL; + } + + data->state = WIDGET_DATA_DELETED; + free(data); + dump_handle_list(); + return NULL; +} + +static void gbar_down_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_info) +{ + Evas_Event_Mouse_Down *down = event_info; + struct widget_data *data = cbdata; + struct widget_mouse_event_info minfo; + + if (data->state != WIDGET_DATA_CREATED) { + ErrPrint("Invalid widget data: %p\n", data); + return; + } + + evas_object_geometry_get(obj, &data->down.geo.x, &data->down.geo.y, &data->down.geo.w, &data->down.geo.h); + + data->x = data->down.x = down->canvas.x; + data->y = data->down.y = down->canvas.y; + data->is.field.pressed = 1; + if (s_info.conf.field.auto_render_selector) { + DbgPrint("Change to direct render\n"); + s_info.conf.field.render_animator = 0; + } + + if (s_info.conf.field.auto_feed) { + minfo.x = (double)data->down.geo.x; + minfo.y = (double)data->down.geo.y; + widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_SET, &minfo); + } else { + minfo.x = (double)(down->canvas.x - data->down.geo.x) / (double)data->down.geo.w; + minfo.y = (double)(down->canvas.y - data->down.geo.y) / (double)data->down.geo.h; + widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_ENTER, &minfo); + widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_DOWN, &minfo); + } +} + +static void gbar_move_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_info) +{ + Evas_Event_Mouse_Move *move = event_info; + struct widget_data *data = cbdata; + Evas_Coord x, y, w, h; + struct widget_mouse_event_info minfo; + + if (data->state != WIDGET_DATA_CREATED) { + ErrPrint("Invalid widget data: %p\n", data); + return; + } + + if (!data->is.field.pressed) { + return; + } + + evas_object_geometry_get(obj, &x, &y, &w, &h); + + data->x = move->cur.canvas.x; + data->y = move->cur.canvas.y; + + if (data->is.field.cancel_click != CANCEL_DISABLED || !s_info.conf.field.auto_feed) { + minfo.x = (double)(move->cur.canvas.x - x) / (double)w; + minfo.y = (double)(move->cur.canvas.y - y) / (double)h; + + if (data->is.field.cancel_click == CANCEL_USER) { + widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_ON_HOLD, &minfo); + data->is.field.cancel_click = CANCEL_PROCESSED; + } + + if (!s_info.conf.field.auto_feed) { + widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_MOVE, &minfo); + } + + if (s_info.conf.field.auto_render_selector) { + DbgPrint("Change to direct render\n"); + s_info.conf.field.render_animator = 0; + } + } + +} + +static void __widget_pixmap_del_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_info) +{ + struct widget_data *data = cbdata; + + if (data->widget_pixmap) { + if (!s_info.conf.field.skip_acquire) { + widget_viewer_release_resource_id(data->handle, 0, data->widget_pixmap); + } + data->widget_pixmap = 0; + } + + if (data->widget_extra) { + int idx; + + for (idx = 0; idx < widget_viewer_get_option(WIDGET_OPTION_EXTRA_BUFFER_CNT); idx++) { + if (data->widget_extra[idx] != 0u) { + if (!s_info.conf.field.skip_acquire) { + if (widget_viewer_release_resource_id(data->handle, 0, data->widget_extra[idx]) < 0) { + ErrPrint("Failed to release %u\n", data->widget_extra[idx]); + } + } + data->widget_extra[idx] = 0u; + } + } + + free(data->widget_extra); + data->widget_extra = NULL; + } +} + +static void gbar_pixmap_del_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_info) +{ + struct widget_data *data = cbdata; + + if (data->gbar_pixmap) { + if (!s_info.conf.field.skip_acquire) { + widget_viewer_release_resource_id(data->handle, 1, data->gbar_pixmap); + } + data->gbar_pixmap = 0; + } + + if (data->gbar_extra) { + int idx; + + for (idx = 0; idx < widget_viewer_get_option(WIDGET_OPTION_EXTRA_BUFFER_CNT); idx++) { + if (data->gbar_extra[idx] != 0u) { + if (!s_info.conf.field.skip_acquire) { + if (widget_viewer_release_resource_id(data->handle, 0, data->gbar_extra[idx]) < 0) { + ErrPrint("Failed to release %u\n", data->gbar_extra[idx]); + } + } + data->gbar_extra[idx] = 0u; + } + } + + free(data->gbar_extra); + data->gbar_extra = NULL; + } +} + +static void gbar_up_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_info) +{ + Evas_Event_Mouse_Up *up = event_info; + struct widget_data *data = cbdata; + Evas_Coord x, y, w, h; + struct widget_mouse_event_info minfo; + + if (data->state != WIDGET_DATA_CREATED) { + ErrPrint("Invalid widget data: %p\n", data); + return; + } + + if (!data->is.field.pressed) { + return; + } + + evas_object_geometry_get(obj, &x, &y, &w, &h); + + if (s_info.conf.field.auto_feed) { + /** + * @note + * UNSET will subtract object.x and object.y by master + * so we just send original touch position based on screen + */ + minfo.x = (double)up->canvas.x / (double)w; + minfo.y = (double)up->canvas.y / (double)h; + widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_UNSET, &minfo); + } else { + minfo.x = (double)(up->canvas.x - x) / (double)w; + minfo.y = (double)(up->canvas.y - y) / (double)h; + + if (data->down.geo.x != x || data->down.geo.y != y || data->is.field.cancel_click == CANCEL_USER) { + widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_ON_HOLD, &minfo); + data->is.field.cancel_click = CANCEL_PROCESSED; + } + + widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_UP, &minfo); + widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_LEAVE, &minfo); + } + + data->is.field.cancel_click = CANCEL_DISABLED; +} + +static void __widget_down_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_info) +{ + Evas_Event_Mouse_Down *down = event_info; + struct widget_data *data = cbdata; + + if (data->state != WIDGET_DATA_CREATED) { + ErrPrint("Invalid widget data: %p\n", data); + return; + } + + if (s_info.conf.field.support_gbar && !data->is.field.gbar_created) { + data->is.field.flick_down = 1; + } + + data->down.x = data->x = down->canvas.x; + data->down.y = data->y = down->canvas.y; + data->is.field.pressed = 1; + data->is.field.scroll_x = 0; + data->is.field.scroll_y = 0; + data->is.field.cancel_scroll_x = 0; + data->is.field.cancel_scroll_y = 0; + + if (s_info.conf.field.auto_render_selector) { + DbgPrint("Change to direct render\n"); + s_info.conf.field.render_animator = 0; + } + + evas_object_geometry_get(obj, &data->down.geo.x, &data->down.geo.y, &data->down.geo.w, &data->down.geo.h); + + if (s_info.conf.field.sensitive_move && (data->down.geo.x != data->view_port.x || data->down.geo.y != data->view_port.y)) { + data->is.field.pressed = 0; + if (s_info.conf.field.auto_render_selector) { + DbgPrint("Change to render animator\n"); + s_info.conf.field.render_animator = 1; + } + return; + } + + if (data->handle && !data->is.field.faulted) { + struct widget_mouse_event_info minfo; + + if (s_info.conf.field.auto_feed && data->is.field.mouse_event) { + minfo.x = (double)data->down.geo.x; + minfo.y = (double)data->down.geo.y; + widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_SET, &minfo); + } else { + minfo.x = (double)(data->x - data->down.geo.x) / (double)data->down.geo.w; + minfo.y = (double)(data->y - data->down.geo.y) / (double)data->down.geo.h; + + widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_ENTER, &minfo); + widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_DOWN, &minfo); + widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_MOVE, &minfo); + } + } +} + +static void smart_callback_call(struct widget_data *data, const char *signal, void *cbdata) +{ + if (data->is.field.deleted || !data->widget) { + DbgPrint("widget is deleted, ignore smart callback call\n"); + return; + } + + evas_object_smart_callback_call(data->widget, signal, cbdata); +} + +static void __widget_destroy_gbar_cb(struct widget *handle, int ret, void *cbdata) +{ + struct widget_data *data = cbdata; + Evas_Object *gbar_content; + struct widget_evas_event_info info; + + if (data->state != WIDGET_DATA_CREATED) { + ErrPrint("Invalid widget data: %p\n", data); + return; + } + + data->is.field.gbar_created = 0; + + info.error = ret; + info.event = WIDGET_EVENT_GBAR_DESTROYED; + info.widget_app_id = data->widget_id; + smart_callback_call(data, WIDGET_SMART_SIGNAL_GBAR_DESTROYED, &info); + + DbgPrint("ret: %d\n", ret); + gbar_content = elm_object_part_content_unset(data->gbar_layout, "gbar,content"); + if (gbar_content) { + Evas_Native_Surface *surface; + unsigned int pixmap; + widget_type_e widget_type; + + widget_viewer_get_type(data->handle, 1, &widget_type); + + switch (widget_type) { + case WIDGET_CONTENT_TYPE_RESOURCE_ID: + if (!s_info.conf.field.force_to_buffer) { + surface = evas_object_image_native_surface_get(gbar_content); + if (!surface) { + ErrPrint("surface is NULL\n"); + evas_object_del(gbar_content); + break; + } + + pixmap = surface->data.x11.pixmap; + evas_object_del(gbar_content); + + if (!s_info.conf.field.skip_acquire) { + widget_viewer_release_resource_id(data->handle, 1, (int)pixmap); + } + + if (pixmap == data->gbar_pixmap) { + data->gbar_pixmap = 0; + } + break; + } + case WIDGET_CONTENT_TYPE_BUFFER: + if (data->gbar_fb) { + widget_viewer_release_buffer(data->gbar_fb); + data->gbar_fb = NULL; + } + evas_object_del(gbar_content); + break; + case WIDGET_CONTENT_TYPE_TEXT: + break; + case WIDGET_CONTENT_TYPE_UIFW: + break; + case WIDGET_CONTENT_TYPE_INVALID: + default: + break; + } + } + + if (data->gbar_layout) { + evas_object_del(data->gbar_layout); + data->gbar_layout = NULL; + } + + remove_gbar_dirty_object_list(data); + widget_unref(data); +} + +static void gbar_animation_done_cb(void *cbdata, Evas_Object *obj, const char *signal_name, const char *source) +{ + Evas_Object *rect; + struct widget_data *data = cbdata; + + if (data->state != WIDGET_DATA_CREATED) { + ErrPrint("Invalid widget data: %p\n", data); + return; + } + + rect = elm_object_part_content_unset(obj, "overlay,content"); + if (rect) { + evas_object_del(rect); + } +} + +static void gbar_create_buffer_object(struct widget_data *data) +{ + Evas_Object *gbar_content; + + gbar_content = elm_object_part_content_get(data->gbar_layout, "gbar,content"); + if (!gbar_content) { + gbar_content = evas_object_image_filled_add(data->e); + if (!gbar_content) { + ErrPrint("Failed to create an image object\n"); + } else { + evas_object_image_colorspace_set(gbar_content, EVAS_COLORSPACE_ARGB8888); + evas_object_image_alpha_set(gbar_content, EINA_TRUE); + + elm_object_part_content_set(data->gbar_layout, "gbar,content", gbar_content); + } + } +} + +static int do_text_update_color(Evas_Object *layout, const char *part, const char *data) +{ + int ret; + int r[3], g[3], b[3], a[3]; + ret = sscanf(data, "%d %d %d %d %d %d %d %d %d %d %d %d", + r, g, b, a, /* OBJECT */ + r + 1, g + 1, b + 1, a + 1, /* OUTLINE */ + r + 2, g + 2, b + 2, a + 2); /* SHADOW */ + if (ret != 12) { + DbgPrint("part[%s] rgba[%s]\n", part, data); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + ret = edje_object_color_class_set(elm_layout_edje_get(layout), part, + r[0], g[0], b[0], a[0], /* OBJECT */ + r[1], g[1], b[1], a[1], /* OUTLINE */ + r[2], g[2], b[2], a[2]); /* SHADOW */ + + return WIDGET_ERROR_NONE; +} + +static void update_focus_chain(Evas_Object *parent, Evas_Object *ao) +{ + const Eina_List *list; + + list = elm_object_focus_custom_chain_get(parent); + if (!eina_list_data_find(list, ao)) { + DbgPrint("Append again to the focus chain\n"); + elm_object_focus_custom_chain_append(parent, ao, NULL); + } +} + +static void activate_cb(void *data, Evas_Object *part_obj, Elm_Object_Item *item) +{ + Evas *e; + int x; + int y; + int w; + int h; + double timestamp; + + e = evas_object_evas_get(part_obj); + evas_object_geometry_get(part_obj, &x, &y, &w, &h); + x += w / 2; + y += h / 2; + +#if defined(_USE_ECORE_TIME_GET) + timestamp = ecore_time_get(); +#else + struct timeval tv; + if (gettimeofday(&tv, NULL) < 0) { + ErrPrint("Failed to get time\n"); + timestamp = 0.0f; + } else { + timestamp = (double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0f); + } +#endif + + DbgPrint("Cursor is on %dx%d\n", x, y); + evas_event_feed_mouse_move(e, x, y, timestamp * 1000, NULL); + evas_event_feed_mouse_down(e, 1, EVAS_BUTTON_NONE, (timestamp + 0.01f) * 1000, NULL); + evas_event_feed_mouse_move(e, x, y, (timestamp + 0.02f) * 1000, NULL); + evas_event_feed_mouse_up(e, 1, EVAS_BUTTON_NONE, (timestamp + 0.03f) * 1000, NULL); +} + +static int do_text_update_access(Evas_Object *parent, Evas_Object *layout, const char *part, const char *text, const char *option) +{ + Evas_Object *edje_part; + + elm_object_part_text_set(layout, part, text ? text : ""); + + edje_part = (Evas_Object *)edje_object_part_object_get(elm_layout_edje_get(layout), part); + if (edje_part) { + Evas_Object *ao; + char *utf8; + + ao = evas_object_data_get(edje_part, "ao"); + if (!ao) { + ao = elm_access_object_register(edje_part, parent); + if (!ao) { + ErrPrint("Unable to register an access object(%s)\n", part); + return WIDGET_ERROR_NONE; + } + + evas_object_data_set(edje_part, "ao", ao); + elm_access_activate_cb_set(ao, activate_cb, NULL); + elm_object_focus_custom_chain_append(parent, ao, NULL); + + DbgPrint("[%s] Register access info: (%s) to, %p\n", part, text, parent); + } + + if (!text || !strlen(text)) { + /*! + * \note + * Delete callback will be called + */ + DbgPrint("[%s] Remove access object(%p)\n", part, ao); + elm_access_object_unregister(ao); + + return WIDGET_ERROR_NONE; + } + + utf8 = elm_entry_markup_to_utf8(text); + if ((!utf8 || !strlen(utf8))) { + free(utf8); + /*! + * \note + * Delete callback will be called + */ + DbgPrint("[%s] Remove access object(%p)\n", part, ao); + elm_access_object_unregister(ao); + + return WIDGET_ERROR_NONE; + } + + elm_access_info_set(ao, ELM_ACCESS_INFO, utf8); + free(utf8); + + update_focus_chain(parent, ao); + } else { + ErrPrint("Unable to get text part[%s]\n", part); + } + + return WIDGET_ERROR_NONE; +} + +static void parse_aspect(struct image_option *img_opt, const char *value, int len) +{ + while (len > 0 && *value == ' ') { + value++; + len--; + } + + if (len < 4) { + return; + } + + img_opt->aspect = !strncasecmp(value, "true", 4); + DbgPrint("Parsed ASPECT: %d (%s)\n", img_opt->aspect, value); +} + +static void parse_orient(struct image_option *img_opt, const char *value, int len) +{ + while (len > 0 && *value == ' ') { + value++; + len--; + } + + if (len < 4) { + return; + } + + img_opt->orient = !strncasecmp(value, "true", 4); + DbgPrint("Parsed ORIENT: %d (%s)\n", img_opt->orient, value); +} + +static void parse_size(struct image_option *img_opt, const char *value, int len) +{ + int width; + int height; + char *buf; + + while (len > 0 && *value == ' ') { + value++; + len--; + } + + buf = strndup(value, len); + if (!buf) { + ErrPrint("Heap: %d\n", errno); + return; + } + + if (sscanf(buf, "%dx%d", &width, &height) == 2) { + img_opt->width = width; + img_opt->height = height; + DbgPrint("Parsed size : %dx%d (%s)\n", width, height, buf); + } else { + DbgPrint("Invalid size tag[%s]\n", buf); + } + + free(buf); +} + +static void parse_shadow(struct image_option *img_opt, const char *value, int len) +{ + int angle; + int offset; + int softness; + int color; + + if (sscanf(value, "%d,%d,%d,%x", &angle, &offset, &softness, &color) != 4) { + ErrPrint("Invalid shadow [%s]\n", value); + } else { + img_opt->shadow.enabled = 1; + img_opt->shadow.angle = angle; + img_opt->shadow.offset = offset; + img_opt->shadow.softness = softness; + img_opt->shadow.color = color; + } +} + +static void parse_fill(struct image_option *img_opt, const char *value, int len) +{ + while (len > 0 && *value == ' ') { + value++; + len--; + } + + if (!strncasecmp(value, "in-size", len)) { + img_opt->fill = FILL_IN_SIZE; + } else if (!strncasecmp(value, "over-size", len)) { + img_opt->fill = FILL_OVER_SIZE; + } else if (!strncasecmp(value, "fit-size", len)) { + img_opt->fill = FILL_FIT_SIZE; + } else { + img_opt->fill = FILL_DISABLE; + } + + DbgPrint("Parsed FILL: %d (%s)\n", img_opt->fill, value); +} + +static inline void parse_image_option(const char *option, struct image_option *img_opt) +{ + const char *ptr; + const char *cmd; + const char *value; + struct { + const char *cmd; + void (*handler)(struct image_option *img_opt, const char *value, int len); + } cmd_list[] = { + { + .cmd = "aspect", /* Keep the aspect ratio */ + .handler = parse_aspect, + }, + { + .cmd = "orient", /* Keep the orientation value: for the rotated images */ + .handler = parse_orient, + }, + { + .cmd = "fill", /* Fill the image to its container */ + .handler = parse_fill, /* Value: in-size, over-size, disable(default) */ + }, + { + .cmd = "size", + .handler = parse_size, + }, + { + .cmd = "shadow", + .handler = parse_shadow, + }, + }; + enum { + STATE_START, + STATE_TOKEN, + STATE_DATA, + STATE_IGNORE, + STATE_ERROR, + STATE_END + } state; + int idx; + int tag; + + if (!option || !*option) { + return; + } + + state = STATE_START; + /*! + * \note + * GCC 4.7 warnings uninitialized idx and tag value. + * But it will be initialized by the state machine. :( + * Anyway, I just reset idx and tag for reducing the GCC4.7 complains. + */ + idx = 0; + tag = 0; + cmd = NULL; + value = NULL; + + for (ptr = option; state != STATE_END; ptr++) { + switch (state) { + case STATE_START: + if (*ptr == '\0') { + state = STATE_END; + continue; + } + + if (isalpha(*ptr)) { + state = STATE_TOKEN; + ptr--; + } + tag = 0; + idx = 0; + + cmd = cmd_list[tag].cmd; + break; + case STATE_IGNORE: + if (*ptr == '=') { + state = STATE_DATA; + value = ptr; + } else if (*ptr == '\0') { + state = STATE_END; + } + break; + case STATE_TOKEN: + if (cmd[idx] == '\0' && (*ptr == ' ' || *ptr == '\t' || *ptr == '=')) { + if (*ptr == '=') { + value = ptr; + state = STATE_DATA; + } else { + state = STATE_IGNORE; + } + idx = 0; + } else if (*ptr == '\0') { + state = STATE_END; + } else if (cmd[idx] == *ptr) { + idx++; + } else { + ptr -= (idx + 1); + + tag++; + if (tag == sizeof(cmd_list) / sizeof(cmd_list[0])) { + tag = 0; + state = STATE_ERROR; + } else { + cmd = cmd_list[tag].cmd; + } + idx = 0; + } + break; + case STATE_DATA: + if (*ptr == ';' || *ptr == '\0') { + cmd_list[tag].handler(img_opt, value + 1, idx); + state = *ptr ? STATE_START : STATE_END; + } else { + idx++; + } + break; + case STATE_ERROR: + if (*ptr == ';') { + state = STATE_START; + } else if (*ptr == '\0') { + state = STATE_END; + } + break; + default: + break; + } + } +} + +static inline void apply_shadow_effect(struct image_option *img_opt, Evas_Object *img) +{ +#if defined(SUPPORT_IMAGE_EFFECT) + ea_effect_h *ea_effect; + + if (!img_opt->shadow.enabled) { + return; + } + + ea_effect = ea_image_effect_create(); + if (!ea_effect) { + return; + } + + // -90, 2, 4, 0x99000000 + ea_image_effect_add_outer_shadow(ea_effect, img_opt->shadow.angle, img_opt->shadow.offset, img_opt->shadow.softness, img_opt->shadow.color); + ea_object_image_effect_set(img, ea_effect); + + ea_image_effect_destroy(ea_effect); +#endif +} + +static Evas_Object *crop_image(Evas_Object *img, const char *path, int part_w, int part_h, int w, int h, struct image_option *img_opt) +{ + Ecore_Evas *ee; + Evas *e; + Evas_Object *src_img; + Evas_Coord rw, rh; + const void *data; + Evas_Load_Error err; + Evas_Object *_img; + + ee = ecore_evas_buffer_new(part_w, part_h); + if (!ee) { + ErrPrint("Failed to create a EE\n"); + return img; + } + + ecore_evas_alpha_set(ee, EINA_TRUE); + + e = ecore_evas_get(ee); + if (!e) { + ErrPrint("Unable to get Evas\n"); + ecore_evas_free(ee); + return img; + } + + src_img = evas_object_image_filled_add(e); + if (!src_img) { + ErrPrint("Unable to add an image\n"); + ecore_evas_free(ee); + return img; + } + + evas_object_image_alpha_set(src_img, EINA_TRUE); + evas_object_image_colorspace_set(src_img, EVAS_COLORSPACE_ARGB8888); + evas_object_image_smooth_scale_set(src_img, EINA_TRUE); + evas_object_image_load_orientation_set(src_img, img_opt->orient); + evas_object_image_file_set(src_img, path, NULL); + err = evas_object_image_load_error_get(src_img); + if (err != EVAS_LOAD_ERROR_NONE) { + ErrPrint("Load error: %s\n", evas_load_error_str(err)); + evas_object_del(src_img); + ecore_evas_free(ee); + return img; + } + evas_object_image_size_get(src_img, &rw, &rh); + evas_object_image_fill_set(src_img, 0, 0, rw, rh); + evas_object_resize(src_img, w, h); + evas_object_move(src_img, -(w - part_w) / 2, -(h - part_h) / 2); + evas_object_show(src_img); + + data = ecore_evas_buffer_pixels_get(ee); + if (!data) { + ErrPrint("Unable to get pixels\n"); + evas_object_del(src_img); + ecore_evas_free(ee); + return img; + } + + e = evas_object_evas_get(img); + _img = evas_object_image_filled_add(e); + if (!_img) { + evas_object_del(src_img); + ecore_evas_free(ee); + return img; + } + + evas_object_image_colorspace_set(_img, EVAS_COLORSPACE_ARGB8888); + evas_object_image_smooth_scale_set(_img, EINA_TRUE); + evas_object_image_alpha_set(_img, EINA_TRUE); + evas_object_image_data_set(_img, NULL); + evas_object_image_size_set(_img, part_w, part_h); + evas_object_resize(_img, part_w, part_h); + evas_object_image_data_copy_set(_img, (void *)data); + evas_object_image_fill_set(_img, 0, 0, part_w, part_h); + evas_object_image_data_update_add(_img, 0, 0, part_w, part_h); + + evas_object_del(src_img); + ecore_evas_free(ee); + + evas_object_del(img); + return _img; +} + +static int do_text_update_text(Evas_Object *parent, Evas_Object *layout, const char *part, const char *text) +{ + Evas_Object *edje_part; + + DbgPrint("Part[%s], Text[%s]\n", part, text); + elm_object_part_text_set(layout, part, text ? text : ""); + + edje_part = (Evas_Object *)edje_object_part_object_get(elm_layout_edje_get(layout), part); + if (edje_part) { + Evas_Object *ao; + char *utf8; + + ao = evas_object_data_get(edje_part, "ao"); + if (!ao) { + ao = elm_access_object_register(edje_part, parent); + if (!ao) { + ErrPrint("Unable to register an access object(%s)\n", part); + return WIDGET_ERROR_NONE; + } + + evas_object_data_set(edje_part, "ao", ao); + elm_access_activate_cb_set(ao, activate_cb, NULL); + elm_object_focus_custom_chain_append(parent, ao, NULL); + + DbgPrint("[%s] Register access info: (%s) to, %p\n", part, text, parent); + } + + if (!text || !strlen(text)) { + /*! + * \note + * Delete callback will be called + */ + DbgPrint("[%s] Remove access object(%p)\n", part, ao); + elm_access_object_unregister(ao); + + return WIDGET_ERROR_NONE; + } + + utf8 = elm_entry_markup_to_utf8(text); + if ((!utf8 || !strlen(utf8))) { + free(utf8); + /*! + * \note + * Delete callback will be called + */ + DbgPrint("[%s] Remove access object(%p)\n", part, ao); + elm_access_object_unregister(ao); + + return WIDGET_ERROR_NONE; + } + + elm_access_info_set(ao, ELM_ACCESS_INFO, utf8); + free(utf8); + + update_focus_chain(parent, ao); + } else { + ErrPrint("Unable to get text part[%s]\n", part); + } + + return WIDGET_ERROR_NONE; +} + +static int do_text_update_image(Evas_Object *layout, const char *part, const char *data, const char *option) +{ + Evas_Object *content; + Evas_Load_Error err; + Evas_Coord w; + Evas_Coord h; + struct image_option img_opt = { + .aspect = 0, + .orient = 0, + .fill = FILL_DISABLE, + .width = -1, + .height = -1, + .shadow = { + .enabled = 0, + }, + }; + + content = elm_object_part_content_unset(layout, part); + if (content) { + evas_object_del(content); + } + + if (!data || !strlen(data) || access(data, R_OK) != 0) { + ErrPrint("Skip image: %s, deleted\n", part); + return WIDGET_ERROR_NONE; + } + + content = evas_object_image_add(evas_object_evas_get(layout)); + if (!content) { + ErrPrint("Failed to add an image object\n"); + return WIDGET_ERROR_FAULT; + } + + evas_object_image_preload(content, EINA_FALSE); + parse_image_option(option, &img_opt); + evas_object_image_load_orientation_set(content, img_opt.orient); + + evas_object_image_file_set(content, data, NULL); + err = evas_object_image_load_error_get(content); + if (err != EVAS_LOAD_ERROR_NONE) { + ErrPrint("Load error: %s\n", evas_load_error_str(err)); + evas_object_del(content); + return WIDGET_ERROR_IO_ERROR; + } + + apply_shadow_effect(&img_opt, content); + + evas_object_image_size_get(content, &w, &h); + if (img_opt.aspect) { + if (img_opt.fill == FILL_OVER_SIZE) { + Evas_Coord part_w; + Evas_Coord part_h; + + if (img_opt.width >= 0 && img_opt.height >= 0) { + part_w = img_opt.width; + part_h = img_opt.height; + } else { + part_w = 0; + part_h = 0; + edje_object_part_geometry_get(elm_layout_edje_get(layout), part, NULL, NULL, &part_w, &part_h); + } + DbgPrint("Original %dx%d (part: %dx%d)\n", w, h, part_w, part_h); + + if (part_w > w || part_h > h) { + double fw; + double fh; + + fw = (double)part_w / (double)w; + fh = (double)part_h / (double)h; + + if (fw > fh) { + w = part_w; + h = (double)h * fw; + } else { + h = part_h; + w = (double)w * fh; + } + } + + if (!part_w || !part_h || !w || !h) { + evas_object_del(content); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + content = crop_image(content, data, part_w, part_h, w, h, &img_opt); + } else if (img_opt.fill == FILL_IN_SIZE) { + Evas_Coord part_w; + Evas_Coord part_h; + + if (img_opt.width >= 0 && img_opt.height >= 0) { + part_w = img_opt.width * elm_config_scale_get(); + part_h = img_opt.height * elm_config_scale_get(); + } else { + part_w = 0; + part_h = 0; + edje_object_part_geometry_get(elm_layout_edje_get(layout), part, NULL, NULL, &part_w, &part_h); + } + DbgPrint("Original %dx%d (part: %dx%d)\n", w, h, part_w, part_h); + + if (w > part_w || h > part_h) { + double fw; + double fh; + + fw = (double)part_w / (double)w; + fh = (double)part_h / (double)h; + + if (fw > fh) { + h = part_h; + w = (double)w * fh; + } else { + w = part_w; + h = (double)h * fw; + } + } + + if (!part_w || !part_h || !w || !h) { + evas_object_del(content); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + content = crop_image(content, data, part_w, part_h, w, h, &img_opt); + } else if (img_opt.fill == FILL_FIT_SIZE) { + Evas_Coord part_w; + Evas_Coord part_h; + double fw; + double fh; + + if (img_opt.width >= 0 && img_opt.height >= 0) { + part_w = img_opt.width * elm_config_scale_get(); + part_h = img_opt.height * elm_config_scale_get(); + } else { + part_w = 0; + part_h = 0; + edje_object_part_geometry_get(elm_layout_edje_get(layout), part, NULL, NULL, &part_w, &part_h); + } + DbgPrint("Original %dx%d (part: %dx%d)\n", w, h, part_w, part_h); + + fw = (double)part_w / (double)w; + fh = (double)part_h / (double)h; + + if (fw < fh) { + h = part_h; + w = (double)w * fh; + } else { + w = part_w; + h = (double)h * fw; + } + + if (!part_w || !part_h || !w || !h) { + evas_object_del(content); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + content = crop_image(content, data, part_w, part_h, w, h, &img_opt); + } else { + evas_object_image_fill_set(content, 0, 0, w, h); + evas_object_size_hint_fill_set(content, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_size_hint_aspect_set(content, EVAS_ASPECT_CONTROL_BOTH, w, h); + } + + apply_shadow_effect(&img_opt, content); + } else { + if (img_opt.width >= 0 && img_opt.height >= 0) { + w = img_opt.width; + h = img_opt.height; + DbgPrint("Using given image size: %dx%d\n", w, h); + } + + evas_object_image_fill_set(content, 0, 0, w, h); + evas_object_size_hint_fill_set(content, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_size_hint_weight_set(content, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_image_filled_set(content, EINA_TRUE); + } + + + /*! + * \note + * object will be shown by below statement automatically + */ + DbgPrint("%s part swallow image %p (%dx%d)\n", part, content, w, h); + elm_object_part_content_set(layout, part, content); + + /*! + * \note + * This object is not registered as an access object. + * So the developer should add it to access list manually, using DESC_ACCESS block. + */ + return WIDGET_ERROR_NONE; +} + +static int do_text_update_script(struct widget_data *data, int gbar, Evas_Object *layout, const char *id, const char *part, const char *file, const char *group) +{ + Evas_Object *content; + int ret; + + content = elm_object_part_content_unset(layout, part); + if (content) { + evas_object_del(content); + } + + if (!file || !strlen(file) || access(file, R_OK) != 0) { + ErrPrint("path: %s (%d), Delete old object\n", file, errno); + return WIDGET_ERROR_NONE; + } + + content = elm_layout_add(layout); + if (!content) { + return WIDGET_ERROR_FAULT; + } + + if (elm_layout_file_set(content, file, group) == EINA_FALSE) { + evas_object_del(content); + return WIDGET_ERROR_FAULT; + } + + ret = append_script_object(data, gbar, id, layout, content); + if (ret != WIDGET_ERROR_NONE) { + evas_object_del(content); + return ret; + } + + elm_object_part_content_set(layout, part, content); + /** + * @note + * Do we need to send all script event to the provider? + * + * elm_object_signal_callback_add(obj, "*", "*", script_signal_cb, handle); + */ + return WIDGET_ERROR_NONE; +} + +static int do_text_operate_access(Evas_Object *layout, const char *part, const char *operation, const char *option) +{ + Elm_Access_Action_Info action_info; + int ret; + + memset(&action_info, 0, sizeof(action_info)); + + /* OPERATION is defined in libwidget package */ + if (!strcasecmp(operation, "set,hl")) { + if (part) { + Evas_Object *content; + Evas_Coord x; + Evas_Coord y; + Evas_Coord w; + Evas_Coord h; + + content = elm_object_part_content_get(layout, part); + if (!content) { + ErrPrint("Invalid part: %s\n", part); + return WIDGET_ERROR_NONE; + } + + evas_object_geometry_get(content, &x, &y, &w, &h); + + action_info.x = x + w / 2; + action_info.y = x + h / 2; + } else if (option && sscanf(option, "%dx%d", &action_info.x, &action_info.y) == 2) { + } else { + ErrPrint("Insufficient info for HL\n"); + return WIDGET_ERROR_NONE; + } + + DbgPrint("TXxTY: %dx%d\n", action_info.x, action_info.y); + ret = elm_access_action(layout, ELM_ACCESS_ACTION_HIGHLIGHT, &action_info); + if (ret == EINA_FALSE) { + ErrPrint("Action error\n"); + } + } else if (!strcasecmp(operation, "unset,hl")) { + ret = elm_access_action(layout, ELM_ACCESS_ACTION_UNHIGHLIGHT, &action_info); + if (ret == EINA_FALSE) { + ErrPrint("Action error\n"); + } + } else if (!strcasecmp(operation, "next,hl")) { + action_info.highlight_cycle = (!!option) && (!!strcasecmp(option, "no,cycle")); + + ret = elm_access_action(layout, ELM_ACCESS_ACTION_HIGHLIGHT_NEXT, &action_info); + if (ret == EINA_FALSE) { + ErrPrint("Action error\n"); + } + } else if (!strcasecmp(operation, "prev,hl")) { + action_info.highlight_cycle = EINA_TRUE; + ret = elm_access_action(layout, ELM_ACCESS_ACTION_HIGHLIGHT_PREV, &action_info); + if (ret == EINA_FALSE) { + ErrPrint("Action error\n"); + } + } else if (!strcasecmp(operation, "reset,focus")) { + DbgPrint("Reset Focus\n"); + elm_object_focus_custom_chain_set(layout, NULL); + } + return WIDGET_ERROR_NONE; +} + +static int gbar_text_update_begin(widget_h handle) +{ + struct widget_data *data; + data = get_smart_data_from_handle(handle); + if (!data) { + return WIDGET_ERROR_FAULT; + } + + DbgPrint("Begin text update: [%s]\n", data->widget_id); + + return WIDGET_ERROR_NONE; +} + +static int gbar_text_update_end(widget_h handle) +{ + struct widget_data *data; + data = get_smart_data_from_handle(handle); + if (!data) { + return WIDGET_ERROR_FAULT; + } + + DbgPrint("End text update: [%s]\n", data->widget_id); + + return WIDGET_ERROR_NONE; +} + +static int gbar_text_update_text(widget_h handle, const char *id, const char *part, const char *data) +{ + struct widget_data *widget_data; + Evas_Object *layout; + + widget_data = get_smart_data_from_handle(handle); + if (!widget_data) { + return WIDGET_ERROR_FAULT; + } + + layout = find_script_object(widget_data, 1, id); + if (!layout) { + ErrPrint("Target[%s] is not exists\n", id); + return WIDGET_ERROR_NOT_EXIST; + } + + return do_text_update_text(widget_data->parent, layout, part, data); +} + +static int gbar_text_update_image(widget_h handle, const char *id, const char *part, const char *data, const char *option) +{ + struct widget_data *widget_data; + Evas_Object *layout; + + widget_data = get_smart_data_from_handle(handle); + if (!widget_data) { + return WIDGET_ERROR_FAULT; + } + + layout = find_script_object(widget_data, 1, id); + if (!layout) { + ErrPrint("Target[%s] is not exists\n", id); + return WIDGET_ERROR_NOT_EXIST; + } + + return do_text_update_image(layout, part, data, option); +} + +static int gbar_text_update_script(widget_h handle, const char *id, const char *new_id, const char *part, const char *file, const char *group) +{ + struct widget_data *data; + Evas_Object *layout; + + data = get_smart_data_from_handle(handle); + if (!data) { + return WIDGET_ERROR_FAULT; + } + + layout = find_script_object(data, 1, id); + if (!layout) { + ErrPrint("Target[%s] is not exists\n", id); + return WIDGET_ERROR_NOT_EXIST; + } + + return do_text_update_script(data, 1, layout, new_id, part, file, group); +} + +static int gbar_text_update_signal(widget_h handle, const char *id, const char *signal_name, const char *signal) +{ + struct widget_data *data; + Evas_Object *layout; + + data = get_smart_data_from_handle(handle); + if (!data) { + return WIDGET_ERROR_FAULT; + } + + layout = find_script_object(data, 1, id); + if (!layout) { + ErrPrint("Target[%s] is not exists\n", id); + return WIDGET_ERROR_NOT_EXIST; + } + + elm_object_signal_emit(layout, signal, signal_name); + return WIDGET_ERROR_NONE; +} + +static int gbar_text_update_drag(widget_h handle, const char *id, const char *part, double dx, double dy) +{ + struct widget_data *data; + Evas_Object *layout; + + data = get_smart_data_from_handle(handle); + if (!data) { + return WIDGET_ERROR_FAULT; + } + + layout = find_script_object(data, 1, id); + if (!layout) { + ErrPrint("Target[%s] is not exists\n", id); + return WIDGET_ERROR_NOT_EXIST; + } + + edje_object_part_drag_value_set(elm_layout_edje_get(layout), part, dx, dy); + return WIDGET_ERROR_NONE; +} + +static int gbar_text_update_info_size(widget_h handle, const char *id, int w, int h) +{ + struct widget_data *data; + Evas_Object *layout; + + data = get_smart_data_from_handle(handle); + if (!data) { + return WIDGET_ERROR_FAULT; + } + + layout = find_script_object(data, 1, id); + if (!layout) { + ErrPrint("Target[%s] is not exists\n", id); + return WIDGET_ERROR_NOT_EXIST; + } + + DbgPrint("Resize to %dx%d\n", w, h); + evas_object_resize(layout, w, h); + + return WIDGET_ERROR_NONE; +} + +static int gbar_text_update_info_category(widget_h handle, const char *id, const char *category) +{ + struct widget_data *data; + Evas_Object *layout; + + data = get_smart_data_from_handle(handle); + if (!data) { + return WIDGET_ERROR_FAULT; + } + + layout = find_script_object(data, 1, id); + if (!layout) { + ErrPrint("Target[%s] is not exists\n", id); + return WIDGET_ERROR_NOT_EXIST; + } + + DbgPrint("Update category: %s\n", category); + + return WIDGET_ERROR_NONE; +} + +static int gbar_text_update_access(widget_h handle, const char *id, const char *part, const char *text, const char *option) +{ + struct widget_data *data; + Evas_Object *layout; + + data = get_smart_data_from_handle(handle); + if (!data) { + return WIDGET_ERROR_FAULT; + } + + layout = find_script_object(data, 1, id); + if (!layout) { + ErrPrint("Target[%s] is not exists\n", id); + return WIDGET_ERROR_NOT_EXIST; + } + + return do_text_update_access(data->parent, layout, part, text, option); +} + +static int gbar_text_operate_access(widget_h handle, const char *id, const char *part, const char *operation, const char *option) +{ + struct widget_data *data; + Evas_Object *layout; + + data = get_smart_data_from_handle(handle); + if (!data) { + return WIDGET_ERROR_FAULT; + } + + layout = find_script_object(data, 1, id); + if (!layout) { + ErrPrint("Target[%s] is not exists\n", id); + return WIDGET_ERROR_NOT_EXIST; + } + + return do_text_operate_access(layout, part, operation, option); +} + +static int gbar_text_update_color(widget_h handle, const char *id, const char *part, const char *data) +{ + struct widget_data *widget_data; + Evas_Object *layout; + + widget_data = get_smart_data_from_handle(handle); + if (!widget_data) { + return WIDGET_ERROR_FAULT; + } + + layout = find_script_object(widget_data, 1, id); + if (!layout) { + ErrPrint("Target[%s] is not exists\n", id); + return WIDGET_ERROR_NOT_EXIST; + } + + return do_text_update_color(layout, part, data); +} + +static void gbar_create_text_object(struct widget_data *data) +{ + Evas_Object *gbar_content; + + gbar_content = elm_object_part_content_get(data->gbar_layout, "gbar,content"); + if (!gbar_content) { + char *script_file; + char *script_group; + struct widget_script_operators operator = { + .update_begin = gbar_text_update_begin, + .update_end = gbar_text_update_end, + + .update_text = gbar_text_update_text, + .update_image = gbar_text_update_image, + .update_script = gbar_text_update_script, + .update_signal = gbar_text_update_signal, + .update_drag = gbar_text_update_drag, + .update_info_size = gbar_text_update_info_size, + .update_info_category = gbar_text_update_info_category, + .update_access = gbar_text_update_access, + .operate_access = gbar_text_operate_access, + .update_color = gbar_text_update_color, + }; + int ret; + + gbar_content = elm_layout_add(data->gbar_layout); + if (!gbar_content) { + ErrPrint("Failed to create a layout object\n"); + return; + } + + script_file = widget_service_get_gbar_script_path(data->widget_id); + script_group = widget_service_get_gbar_script_group(data->widget_id); + if (!script_file || !script_group) { + ErrPrint("Invalid script info ([%s] - [%s])\n", script_file, script_group); + free(script_file); + free(script_group); + evas_object_del(gbar_content); + return; + } + + if (access(script_file, R_OK) != 0) { + ErrPrint("Unable to access [%s] - %d\n", script_file, errno); + free(script_file); + free(script_group); + evas_object_del(gbar_content); + return; + } + + ret = elm_layout_file_set(gbar_content, script_file, script_group); + DbgPrint("Load (%s)(%s)\n", script_file, script_group); + free(script_file); + free(script_group); + if (ret == EINA_FALSE) { + ErrPrint("Failed to load an edje file\n"); + evas_object_del(gbar_content); + return; + } + + if (widget_viewer_set_text_handler(data->handle, 1, &operator) != WIDGET_ERROR_NONE) { + ErrPrint("Failed to set text handler for [%s]\n", data->widget_id); + evas_object_del(gbar_content); + return; + } + + ret = append_script_object(data, 1, NULL, NULL, gbar_content); + if (ret != WIDGET_ERROR_NONE) { + ErrPrint("Failed to append this to script object list\n"); + evas_object_del(gbar_content); + return; + } + + elm_object_part_content_set(data->gbar_layout, "gbar,content", gbar_content); + } +} + +static void gbar_create_pixmap_object(struct widget_data *data) +{ + Evas_Object *gbar_content; + + gbar_content = elm_object_part_content_get(data->gbar_layout, "gbar,content"); + if (!gbar_content) { + gbar_content = evas_object_image_filled_add(data->e); + if (!gbar_content) { + ErrPrint("Failed to create an image object\n"); + return; + } + + evas_object_image_colorspace_set(gbar_content, EVAS_COLORSPACE_ARGB8888); + evas_object_image_alpha_set(gbar_content, EINA_TRUE); + elm_object_part_content_set(data->gbar_layout, "gbar,content", gbar_content); + + evas_object_event_callback_add(gbar_content, EVAS_CALLBACK_MOUSE_DOWN, gbar_down_cb, data); + evas_object_event_callback_add(gbar_content, EVAS_CALLBACK_MOUSE_MOVE, gbar_move_cb, data); + evas_object_event_callback_add(gbar_content, EVAS_CALLBACK_MOUSE_UP, gbar_up_cb, data); + evas_object_event_callback_add(gbar_content, EVAS_CALLBACK_DEL, gbar_pixmap_del_cb, data); + } +} + +static void __widget_create_gbar_cb(struct widget *handle, int ret, void *cbdata) +{ + struct widget_data *data = cbdata; + struct widget_evas_event_info info; + widget_type_e widget_type; + + if (data->state != WIDGET_DATA_CREATED) { + ErrPrint("Invalid widget data: %p\n", data); + return; + } + + if (ret != WIDGET_ERROR_NONE) { + DbgPrint("Create GBAR: 0x%X\n", ret); + info.error = ret; + info.event = WIDGET_EVENT_GBAR_CREATED; + info.widget_app_id = data->widget_id; + smart_callback_call(data, WIDGET_SMART_SIGNAL_GBAR_ABORTED, &info); + widget_unref(data); + return; + } + + if (data->is.field.deleted) { + /** + * Evas Object is deleted. + * Do not proceed this process anymore and destroy GBAR too + */ + if (widget_viewer_destroy_glance_bar(data->handle, NULL, NULL) != WIDGET_ERROR_NONE) { + DbgPrint("widget_viewer_destroy_glance_bar failed\n"); + } + return; + } + + DbgPrint("GBAR is created\n"); + + if (!data->gbar_layout) { + data->gbar_layout = elm_layout_add(data->parent); + if (!data->gbar_layout) { + ErrPrint("Failed to add an edje\n"); + info.error = WIDGET_ERROR_FAULT; + info.event = WIDGET_EVENT_GBAR_CREATED; + info.widget_app_id = data->widget_id; + smart_callback_call(data, WIDGET_SMART_SIGNAL_GBAR_ABORTED, &info); + + ret = widget_viewer_destroy_glance_bar(data->handle, __widget_destroy_gbar_cb, widget_ref(data)); + if (ret < 0) { + /*! + * \note + * PREVENT detect this. but it is FALSE POSITIVE + * + * widget_ref will increase the refcnt of data. + * and it is called when calling the widget_destroy_glance_bar function (via the last param) + * So this function call will not release the data. + */ + widget_unref(data); + } + + widget_unref(data); + return; + } + + if (elm_layout_file_set(data->gbar_layout, WIDGET_VIEWER_EVAS_RESOURCE_EDJ, WIDGET_VIEWER_EVAS_RESOURCE_GBAR) == EINA_FALSE) { + ErrPrint("Failed to load edje object: %s(%s)\n", WIDGET_VIEWER_EVAS_RESOURCE_EDJ, WIDGET_VIEWER_EVAS_RESOURCE_GBAR); + evas_object_del(data->gbar_layout); + data->gbar_layout = NULL; + + info.error = WIDGET_ERROR_IO_ERROR; + info.event = WIDGET_EVENT_GBAR_CREATED; + info.widget_app_id = data->widget_id; + smart_callback_call(data, WIDGET_SMART_SIGNAL_GBAR_ABORTED, &info); + + ret = widget_viewer_destroy_glance_bar(data->handle, __widget_destroy_gbar_cb, widget_ref(data)); + if (ret < 0) { + /*! + * \note + * PREVENT detect this. but it is FALSE POSITIVE + * + * widget_ref will increase the refcnt of data. + * and it is called when calling the widget_destroy_glance_bar function (via the last param) + * So this function call will not release the data. + */ + widget_unref(data); + } + + widget_unref(data); + return; + } + + evas_object_smart_member_add(data->gbar_layout, data->widget); + evas_object_clip_set(data->gbar_layout, data->stage); + elm_object_signal_callback_add(data->gbar_layout, "finished", "animation", gbar_animation_done_cb, data); + evas_object_show(data->gbar_layout); + } + gbar_overlay_loading(data); + + widget_viewer_get_type(data->handle, 1, &widget_type); + + switch (widget_type) { + case WIDGET_CONTENT_TYPE_RESOURCE_ID: + if (!s_info.conf.field.force_to_buffer) { + gbar_create_pixmap_object(data); + break; + } + case WIDGET_CONTENT_TYPE_BUFFER: + gbar_create_buffer_object(data); + break; + case WIDGET_CONTENT_TYPE_TEXT: + gbar_create_text_object(data); + break; + case WIDGET_CONTENT_TYPE_UIFW: + ErrPrint("Not implemented - TYPE_UIFW for GBAR\n"); + default: + info.error = WIDGET_ERROR_INVALID_PARAMETER; + info.event = WIDGET_EVENT_GBAR_CREATED; + info.widget_app_id = data->widget_id; + ret = widget_viewer_destroy_glance_bar(data->handle, __widget_destroy_gbar_cb, widget_ref(data)); + if (ret < 0) { + /*! + * \note + * PREVENT detect this. but it is FALSE POSITIVE + * + * widget_ref will increase the refcnt of data. + * and it is called when calling the widget_destroy_glance_bar function (via the last param) + * So this function call will not release the data. + */ + data = widget_unref(data); + } + ErrPrint("Failed to create a GBAR, unknown type\n"); + if (data) { + smart_callback_call(data, WIDGET_SMART_SIGNAL_GBAR_ABORTED, &info); + data = widget_unref(data); + } + return; + } + + data->is.field.gbar_created = 1; + info.error = WIDGET_ERROR_NONE; + info.event = WIDGET_EVENT_GBAR_CREATED; + info.widget_app_id = data->widget_id; + smart_callback_call(data, WIDGET_SMART_SIGNAL_GBAR_CREATED, &info); + widget_unref(data); +} + +static void update_scroll_flag(struct widget_data *data, int x, int y) +{ + if (s_info.conf.field.is_scroll_x && !s_info.conf.field.is_scroll_y) { + if (!data->is.field.scroll_x && abs(y - data->down.y) > CLICK_REGION && (abs(x - data->down.x) <= CLICK_REGION)) { + data->is.field.cancel_scroll_x = 1; + } + } + + if (s_info.conf.field.is_scroll_y && !s_info.conf.field.is_scroll_x) { + if (!data->is.field.scroll_y && abs(x - data->down.x) > CLICK_REGION && (abs(y - data->down.y) <= CLICK_REGION)) { + data->is.field.cancel_scroll_y = 1; + } + } + + data->is.field.scroll_x = s_info.conf.field.is_scroll_x && (!!(data->is.field.scroll_x || (abs(x - data->down.x) > CLICK_REGION))); + data->is.field.scroll_y = s_info.conf.field.is_scroll_y && (!!(data->is.field.scroll_y || (abs(y - data->down.y) > CLICK_REGION))); + data->is.field.scroll_x = !data->is.field.cancel_scroll_x && data->is.field.scroll_x; + data->is.field.scroll_y = !data->is.field.cancel_scroll_y && data->is.field.scroll_y; +} + +static void __widget_up_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_info) +{ + Evas_Event_Mouse_Up *up = event_info; + struct widget_evas_event_info info; + struct widget_data *data = cbdata; + Evas_Coord x, y, w, h; + int ret = 0; + widget_size_type_e size_type; + + if (data->state != WIDGET_DATA_CREATED) { + ErrPrint("Invalid widget data: %p\n", data); + return; + } + + if (!data->is.field.pressed) { + return; + } + + update_scroll_flag(data, up->canvas.x, up->canvas.y); + + data->x = up->canvas.x; + data->y = up->canvas.y; + data->is.field.pressed = 0; + + if (s_info.conf.field.auto_render_selector) { + DbgPrint("Change to render animator\n"); + s_info.conf.field.render_animator = 1; + } + + info.widget_app_id = data->widget_id; + info.event = WIDGET_EVENT_GBAR_CREATED; + + if (s_info.conf.field.support_gbar && data->is.field.flick_down && data->y - data->down.y < CLICK_REGION) { + DbgPrint("Flick down is canceled\n"); + data->is.field.flick_down = 0; + info.error = WIDGET_ERROR_CANCELED; + smart_callback_call(data, WIDGET_SMART_SIGNAL_FLICKDOWN_CANCELLED, &info); + } + + evas_object_geometry_get(data->widget, &x, &y, &w, &h); + + if (data->is.field.flick_down) { + data->is.field.flick_down = 0; + if (!data->handle || data->is.field.faulted || !widget_viewer_has_glance_bar(data->handle)) { + if (!data->is.field.gbar_created && s_info.conf.field.support_gbar) { + elm_object_signal_emit(data->widget_layout, "tilt", "content"); + } + DbgPrint("Flick down is canceled\n"); + info.error = WIDGET_ERROR_CANCELED; + smart_callback_call(data, WIDGET_SMART_SIGNAL_FLICKDOWN_CANCELLED, &info); + } else if (s_info.conf.field.support_gbar && !data->is.field.gbar_created) { + double rx; + double ry; + int gbar_w; + int gbar_h; + + if (widget_viewer_get_glance_bar_size(data->handle, &gbar_w, &gbar_h) != WIDGET_ERROR_NONE) { + gbar_w = 0; + gbar_h = 0; + } + + elm_object_signal_emit(data->widget_layout, "move,down", "content"); + + rx = ((double)x + (double)w / 2.0f) / (double)s_info.screen_width; + DbgPrint("x[%d], w[%d], rx[%lf]\n", x, w, rx); + // 0.0 0.125 0.25 0.375 0.5 0.625 0.75 0.875 1.0 + widget_viewer_get_size_type(data->handle, &size_type); + switch (size_type) { + case WIDGET_SIZE_TYPE_1x1: + if (rx < 0.25f) { + rx = 0.125f; + } else if (rx < 0.5f) { + rx = 0.375f; + } else if (rx < 0.75f) { + rx = 0.625f; + } else if (rx < 1.0f) { + rx = 0.875f; + } + break; + case WIDGET_SIZE_TYPE_2x1: + case WIDGET_SIZE_TYPE_2x2: + if (rx < 0.5f) { + rx = 0.25f; + } else if (rx < 0.625f) { + rx = 0.5f; + } else { + rx = 0.75f; + } + break; + default: + rx = 0.5f; + break; + } + + if (y + h + gbar_h <= s_info.screen_height) { + ry = 0.0f; + } else { + ry = 1.0f; + } + + DbgPrint("converted rx[%lf], ry[%lf]\n", rx, ry); + + ret = widget_viewer_create_glance_bar(data->handle, rx, ry, __widget_create_gbar_cb, widget_ref(data)); + if (ret < 0) { + widget_unref(data); + DbgPrint("Flick down is canceled\n"); + info.error = WIDGET_ERROR_CANCELED; + smart_callback_call(data, WIDGET_SMART_SIGNAL_FLICKDOWN_CANCELLED, &info); + } + DbgPrint("Create GBAR: %d (%lfx%lf)\n", ret, rx, ry); + } + } + + if (data->handle && !data->is.field.faulted) { + struct widget_mouse_event_info minfo; + + minfo.x = (double)(data->x - x) / (double)w; + minfo.y = (double)(data->y - y) / (double)h; + + evas_object_geometry_get(obj, &x, &y, NULL, NULL); + + reset_scroller(data); + + if (s_info.conf.field.auto_feed && data->is.field.mouse_event) { + struct widget_mouse_event_info _minfo; + + if (data->down.geo.x != x || data->down.geo.y != y || data->is.field.scroll_x || data->is.field.scroll_y || data->is.field.cancel_click == CANCEL_USER) { + widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_ON_HOLD, &minfo); + data->is.field.cancel_click = CANCEL_PROCESSED; + } + + /** + * @note + * UNSET will subtract object.x and object.y by master + * so we just send original touch position based on screen + */ + _minfo.x = (double)up->canvas.x / (double)data->down.geo.w; + _minfo.y = (double)up->canvas.y / (double)data->down.geo.h; + widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_UNSET, &_minfo); + } else { + if (!data->is.field.mouse_event) { + /* We have to keep the first position of touch down */ + minfo.x = (double)(data->down.x - x) / (double)w; + minfo.y = (double)(data->down.y - y) / (double)h; + if (data->down.geo.x != x || data->down.geo.y != y || data->is.field.scroll_x || data->is.field.scroll_y || data->is.field.cancel_click == CANCEL_USER || abs(data->x - data->down.x) > CLICK_REGION || abs(data->y - data->down.y) > CLICK_REGION) { + widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_ON_HOLD, &minfo); + data->is.field.cancel_click = CANCEL_PROCESSED; + } + } else { + if (data->down.geo.x != x || data->down.geo.y != y || data->is.field.scroll_x || data->is.field.scroll_y || data->is.field.cancel_click == CANCEL_USER) { + widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_ON_HOLD, &minfo); + data->is.field.cancel_click = CANCEL_PROCESSED; + } + } + + widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_UP, &minfo); + widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_LEAVE, &minfo); + } + + if (!data->is.field.flick_down) { + ret = WIDGET_ERROR_INVALID_PARAMETER; + if (data->is.field.gbar_created) { + ret = widget_viewer_destroy_glance_bar(data->handle, __widget_destroy_gbar_cb, widget_ref(data)); + if (ret < 0) + data = widget_unref(data); + } else if (data->is.field.cancel_click == CANCEL_DISABLED) { + ret = widget_viewer_send_click_event(data->handle, minfo.x, minfo.y); + } + } + + if (data) { + DbgPrint("Up: %lfx%lf [x:%d/%d/%d] [y:%d/%d/%d], ret: 0x%X, cancel: 0x%x\n", + minfo.x, minfo.y, + data->is.field.scroll_x, s_info.conf.field.is_scroll_x, data->is.field.cancel_scroll_x, + data->is.field.scroll_y, s_info.conf.field.is_scroll_y, data->is.field.cancel_scroll_y, + ret, data->is.field.cancel_click); + data->is.field.cancel_click = CANCEL_DISABLED; + } + } +} + +static void __widget_move_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_info) +{ + Evas_Event_Mouse_Move *move = event_info; + struct widget_data *data = cbdata; + + if (data->state != WIDGET_DATA_CREATED) { + ErrPrint("Invalid widget data: %p\n", data); + return; + } + + if (!data->is.field.pressed) { + return; + } + + if (s_info.conf.field.support_gbar && data->is.field.flick_down && data->y - move->cur.canvas.y > 0) { + struct widget_evas_event_info info; + + DbgPrint("Flick down is canceled\n"); + data->is.field.flick_down = 0; + info.widget_app_id = data->widget_id; + info.event = WIDGET_EVENT_GBAR_CREATED; + info.error = WIDGET_ERROR_CANCELED; + + smart_callback_call(data, WIDGET_SMART_SIGNAL_FLICKDOWN_CANCELLED, &info); + } + + update_scroll_flag(data, move->cur.canvas.x, move->cur.canvas.y); + + data->x = move->cur.canvas.x; + data->y = move->cur.canvas.y; + + if (data->handle && !data->is.field.faulted) { + if (data->is.field.cancel_click == CANCEL_USER) { + struct widget_mouse_event_info minfo; + Evas_Coord x, y, w, h; + + evas_object_geometry_get(obj, &x, &y, &w, &h); + + minfo.x = (double)(data->x - x) / (double)w; + minfo.y = (double)(data->y - y) / (double)h; + widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_ON_HOLD, &minfo); + + /* + * Reset the clicked event + */ + data->is.field.cancel_click = CANCEL_PROCESSED; + + if (s_info.conf.field.auto_render_selector) { + DbgPrint("Change to render animator\n"); + s_info.conf.field.render_animator = 1; + } + } + + if (!s_info.conf.field.auto_feed) { + struct widget_mouse_event_info minfo; + Evas_Coord x, y, w, h; + + evas_object_geometry_get(obj, &x, &y, &w, &h); + + minfo.x = (double)(data->x - x) / (double)w; + minfo.y = (double)(data->y - y) / (double)h; + widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_MOVE, &minfo); + } + + if (s_info.conf.field.support_gbar && data->is.field.flick_down && abs(data->y - data->down.y) > CLICK_REGION) { + struct widget_evas_event_info info; + data->is.field.flick_down = 0; + info.widget_app_id = data->widget_id; + info.event = WIDGET_EVENT_GBAR_CREATED; + info.error = WIDGET_ERROR_CANCELED; + smart_callback_call(data, WIDGET_SMART_SIGNAL_FLICKDOWN_CANCELLED, &info); + DbgPrint("Flick down is canceled\n"); + } + + } else { + if (s_info.conf.field.auto_render_selector) { + s_info.conf.field.render_animator = 1; + } + } +} + +static char *get_package_icon(struct widget_data *data) +{ + char *icon; + + if (data->size_type == WIDGET_SIZE_TYPE_UNKNOWN) { + icon = widget_service_get_icon(data->widget_id, NULL); + } else { + icon = widget_service_get_preview_image_path(data->widget_id, data->size_type); + } + + if (icon && access(icon, R_OK) == 0) { + return icon; + } + + if (icon) { + ErrPrint("Failed to access an icon file: [%s]\n", icon); + free(icon); + } + + icon = strdup(WIDGET_VIEWER_EVAS_UNKNOWN); + if (!icon) { + ErrPrint("strdup: %d\n", errno); + } + + return icon; +} + +static void activate_ret_cb(struct widget *handle, int ret, void *cbdata) +{ + struct widget_data *data = cbdata; + + if (data->state != WIDGET_DATA_CREATED) { + ErrPrint("Invalid widget data: %p\n", data); + return; + } + + data->overlay_update_counter = 0; + __widget_overlay_disable(data, 1); + + DbgPrint("Activated (%s): %d\n", data->widget_id, ret); + if (!data->is.field.deleted && (ret == WIDGET_ERROR_NONE || ret == WIDGET_ERROR_INVALID_PARAMETER)) { + widget_size_type_e type; + Evas_Coord w, h; + struct acquire_data acquire_data = { + .data = data, + }; + + evas_object_geometry_get(data->widget_layout, NULL, NULL, &w, &h); + + type = find_size_type(data, w, h); + if (type == WIDGET_SIZE_TYPE_UNKNOWN) { + ErrPrint("Failed to find a proper size type: %dx%d\n", w, h); + type = WIDGET_SIZE_TYPE_1x1; + } + + data->is.field.faulted = 0; + data->is.field.created = 0; + data->is.field.send_delete = 1; + update_widget_geometry(&acquire_data); + data->handle = widget_viewer_add_widget(data->widget_id, data->content, + data->cluster, data->category, + data->period, type, + __widget_created_cb, widget_ref(data)); + if (!data->handle) { + ErrPrint("Failed to send add request\n"); + widget_unref(data); + return; + } + + DbgPrint("Added Handle: (%p) %p\n", data->handle, data); + widget_viewer_set_data(data->handle, data->widget); + __widget_overlay_loading(data); + } + + data->is.field.deleted = 0; + widget_unref(data); +} + +static void __widget_animation_done_cb(void *cbdata, Evas_Object *obj, const char *signal_name, const char *source) +{ + struct widget_data *data = cbdata; + + if (data->state != WIDGET_DATA_CREATED) { + ErrPrint("Invalid widget data: %p\n", data); + return; + } + + if (widget_viewer_has_glance_bar(data->handle)) { + } else { + DbgPrint("Animation finished\n"); + } +} + +static void __widget_turn_done_cb(void *cbdata, Evas_Object *obj, const char *signal_name, const char *source) +{ + struct widget_data *data = cbdata; + Evas_Object *overlay; + + if (data->state != WIDGET_DATA_CREATED) { + ErrPrint("Invalid widget data: %p\n", data); + return; + } + + overlay = elm_object_part_content_unset(data->widget_layout, "overlay,content"); + if (overlay) { + evas_object_del(overlay); + data->is.field.widget_overlay_loaded = 0; + } +} + +static void __widget_overlay_clicked_cb(void *cbdata, Evas_Object *obj, const char *signal_name, const char *source) +{ + struct widget_data *data = cbdata; + + if (data->state != WIDGET_DATA_CREATED) { + ErrPrint("Invalid widget data: %p\n", data); + return; + } + + DbgPrint("Overlay is clicked: (%s) (%s)\n", signal_name, source); + if (!data->is.field.faulted) { + /*! + * \todo + * Reload + */ + DbgPrint("Package [%s] is not faulted one\n", data->widget_id); + } else { + DbgPrint("Activate: [%s]\n", data->widget_id); + if (widget_viewer_activate_faulted_widget(data->widget_id, activate_ret_cb, widget_ref(data)) < 0) { + ErrPrint("Failed to activate %s\n", data->widget_id); + widget_unref(data); + } + } +} + +static void __widget_data_setup(struct widget_data *data) +{ + data->e = evas_object_evas_get(data->widget); + if (!data->e) { + ErrPrint("Failed to get Evas object\n"); + data->state = WIDGET_DATA_DELETED; + free(data); + return; + } + + data->stage = evas_object_rectangle_add(data->e); + if (!data->stage) { + ErrPrint("Failed to add stage object\n"); + data->state = WIDGET_DATA_DELETED; + free(data); + return; + } + + evas_object_color_set(data->stage, 255, 255, 255, 255); + + data->widget_layout = elm_layout_add(data->parent); + if (!data->widget_layout) { + ErrPrint("Failed to add edje object\n"); + evas_object_del(data->stage); + data->state = WIDGET_DATA_DELETED; + free(data); + return; + } + + if (elm_layout_file_set(data->widget_layout, WIDGET_VIEWER_EVAS_RESOURCE_EDJ, WIDGET_VIEWER_EVAS_RESOURCE_LB) == EINA_FALSE) { + ErrPrint("Failed to load edje object: %s(%s)\n", WIDGET_VIEWER_EVAS_RESOURCE_EDJ, WIDGET_VIEWER_EVAS_RESOURCE_LB); + evas_object_del(data->widget_layout); + evas_object_del(data->stage); + data->state = WIDGET_DATA_DELETED; + free(data); + return; + } + + Evas_Object *scroller; + scroller = elm_scroller_add(data->parent); + if (scroller) { + Evas_Object *box; + + elm_scroller_bounce_set(scroller, EINA_FALSE, EINA_FALSE); + elm_scroller_policy_set(scroller, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF); + elm_scroller_single_direction_set(scroller, ELM_SCROLLER_SINGLE_DIRECTION_HARD); + //elm_object_scroll_lock_x_set(scroller, EINA_TRUE); + + box = evas_object_rectangle_add(data->e); + if (box) { + int height; + + height = s_info.screen_height << 1; + + evas_object_color_set(box, 0, 0, 0, 0); + evas_object_resize(box, s_info.screen_width, height); + evas_object_size_hint_min_set(box, s_info.screen_width, height); + evas_object_show(box); + } + + elm_object_content_set(scroller, box); + elm_object_part_content_set(data->widget_layout, "scroller", scroller); + } else { + ErrPrint("Failed to create a scroller\n"); + } + + evas_object_show(data->widget_layout); + + elm_object_signal_callback_add(data->widget_layout, "mouse,clicked,1", "overlay,content", __widget_overlay_clicked_cb, data); + elm_object_signal_callback_add(data->widget_layout, "done", "turn", __widget_turn_done_cb, data); + elm_object_signal_callback_add(data->widget_layout, "finished", "animation", __widget_animation_done_cb, data); + + evas_object_event_callback_add(data->widget_layout, EVAS_CALLBACK_MOUSE_DOWN, __widget_down_cb, data); + evas_object_event_callback_add(data->widget_layout, EVAS_CALLBACK_MOUSE_MOVE, __widget_move_cb, data); + evas_object_event_callback_add(data->widget_layout, EVAS_CALLBACK_MOUSE_UP, __widget_up_cb, data); + + evas_object_smart_member_add(data->stage, data->widget); + evas_object_smart_member_add(data->widget_layout, data->widget); + evas_object_clip_set(data->widget_layout, data->stage); + +} + +static Eina_Bool renderer_cb(void *_data) +{ + struct widget_data *data; + + EINA_LIST_FREE(s_info.widget_dirty_objects, data) { + __widget_event_widget_updated(data); + } + + EINA_LIST_FREE(s_info.gbar_dirty_objects, data) { + __widget_event_gbar_updated(data); + } + + s_info.renderer = NULL; + return ECORE_CALLBACK_CANCEL; +} + +static void remove_widget_dirty_object_list(struct widget_data *data) +{ + s_info.widget_dirty_objects = eina_list_remove(s_info.widget_dirty_objects, data); +} + +static void remove_gbar_dirty_object_list(struct widget_data *data) +{ + s_info.gbar_dirty_objects = eina_list_remove(s_info.gbar_dirty_objects, data); +} + +static void append_widget_dirty_object_list(struct widget_data *data, int idx) +{ + data->is.field.widget_dirty = 1; + + if (idx != WIDGET_KEEP_BUFFER) { + data->widget_latest_idx = idx; + } + + if (widget_viewer_get_visibility(data->handle) != WIDGET_SHOW) { + DbgPrint("Box is not visible\n"); + return; + } + + if (s_info.conf.field.render_animator) { + if (eina_list_data_find(s_info.widget_dirty_objects, data)) { + return; + } + + if (!s_info.renderer) { + s_info.renderer = ecore_animator_add(renderer_cb, NULL); + if (!s_info.renderer) { + ErrPrint("Failed to create a renderer\n"); + } + } + + s_info.widget_dirty_objects = eina_list_append(s_info.widget_dirty_objects, data); + } else { + if (s_info.renderer) { + ecore_animator_del(s_info.renderer); + s_info.renderer = NULL; + } + + /* Need a choice + * Do we have to discard these all changes? or just flush them? + struct widget_data *item; + EINA_LIST_FREE(s_info.widget_dirty_objects, item) { + __widget_event_widget_updated(item); + } + */ + eina_list_free(s_info.widget_dirty_objects); + s_info.widget_dirty_objects = NULL; + __widget_event_widget_updated(data); + } +} + +static void append_gbar_dirty_object_list(struct widget_data *data, int idx) +{ + data->is.field.gbar_dirty = 1; + + if (idx != WIDGET_KEEP_BUFFER) { + data->gbar_latest_idx = idx; + } + + if (widget_viewer_get_visibility(data->handle) != WIDGET_SHOW) { + return; + } + + if (s_info.conf.field.render_animator) { + if (eina_list_data_find(s_info.gbar_dirty_objects, data)) { + return; + } + + if (!s_info.renderer) { + s_info.renderer = ecore_animator_add(renderer_cb, NULL); + if (!s_info.renderer) { + ErrPrint("Failed to create a renderer\n"); + } + } + + s_info.gbar_dirty_objects = eina_list_append(s_info.gbar_dirty_objects, data); + } else { + if (s_info.renderer) { + ecore_animator_del(s_info.renderer); + s_info.renderer = NULL; + } + + /* Need a choice + * Do we have to discard these all changes? or just flush them? + struct widget_data *item; + EINA_LIST_FREE(s_info.gbar_dirty_objects, item) { + __widget_event_gbar_updated(item); + } + */ + eina_list_free(s_info.gbar_dirty_objects); + s_info.gbar_dirty_objects = NULL; + __widget_event_gbar_updated(data); + } +} + +static void __widget_add(Evas_Object *widget) +{ + struct widget_data *data; + + data = calloc(1, sizeof(*data)); + if (!data) { + ErrPrint("Heap: %d\n", errno); + return; + } + + data->state = WIDGET_DATA_CREATED; + data->widget = widget; + data->is.field.permanent_delete = 0; + data->widget_latest_idx = WIDGET_PRIMARY_BUFFER; + data->gbar_latest_idx = WIDGET_PRIMARY_BUFFER; + evas_object_smart_data_set(data->widget, data); + widget_ref(data); + + s_info.list = eina_list_append(s_info.list, widget); + return; +} + +static Evas_Object *create_image_object(struct widget_data *data) +{ + Evas_Object *img; + + img = evas_object_image_filled_add(data->e); + if (!img) { + ErrPrint("Failed to create an image object\n"); + } else { + evas_object_image_colorspace_set(img, EVAS_COLORSPACE_ARGB8888); + evas_object_image_alpha_set(img, EINA_TRUE); + } + + return img; +} + +static void replace_widget_pixmap_with_image(struct widget_data *data) +{ + Evas_Object *img; + Evas_Object *widget_viewer_get_content_string; + + widget_viewer_get_content_string = elm_object_part_content_unset(data->widget_layout, "widget,content"); + if (!widget_viewer_get_content_string) { + ErrPrint("Failed to get content object\n"); + return; + } + + img = create_image_object(data); + if (img) { + Evas_Coord w; + Evas_Coord h; + void *content; + + evas_object_image_size_get(widget_viewer_get_content_string, &w, &h); + evas_object_image_size_set(img, w, h); + + content = evas_object_image_data_get(widget_viewer_get_content_string, 0); + if (content) { + evas_object_image_data_copy_set(img, content); + } + + evas_object_image_fill_set(img, 0, 0, w, h); + evas_object_image_pixels_dirty_set(img, EINA_TRUE); + evas_object_image_data_update_add(img, 0, 0, w, h); + + elm_object_part_content_set(data->widget_layout, "widget,content", img); + } else { + ErrPrint("Failed to create an image object\n"); + } + + evas_object_del(widget_viewer_get_content_string); +} + +static void replace_gbar_pixmap_with_image(struct widget_data *data) +{ + Evas_Object *img; + Evas_Object *gbar_content; + + gbar_content = elm_object_part_content_unset(data->widget_layout, "gbar,content"); + if (!gbar_content) { + ErrPrint("Failed to get content object\n"); + return; + } + + img = create_image_object(data); + if (img) { + Evas_Coord w; + Evas_Coord h; + void *content; + + evas_object_image_size_get(gbar_content, &w, &h); + evas_object_image_size_set(img, w, h); + + content = evas_object_image_data_get(gbar_content, 0); + if (content) { + evas_object_image_data_copy_set(img, content); + } + + evas_object_image_fill_set(img, 0, 0, w, h); + evas_object_image_pixels_dirty_set(img, EINA_TRUE); + evas_object_image_data_update_add(img, 0, 0, w, h); + + elm_object_part_content_set(data->widget_layout, "gbar,content", img); + } else { + ErrPrint("Failed to create an image object\n"); + } + + evas_object_del(gbar_content); +} + +static void __widget_destroy_widget_cb(widget_h handle, int ret, void *_data) +{ + struct widget_data *data = _data; + + if (data->state != WIDGET_DATA_CREATED) { + ErrPrint("Invalid widget data: %p\n", data); + return; + } + + if (data->widget_pixmap) { + replace_widget_pixmap_with_image(data); + } + + if (data->gbar_pixmap) { + replace_gbar_pixmap_with_image(data); + } + + data->is.field.send_delete = 0; + DbgPrint("Invoke raw delete %s\n", data->widget_id); + (void)invoke_raw_event_callback(WIDGET_VIEWER_EVAS_RAW_DELETE, data->widget_id, NULL, ret); + remove_widget_dirty_object_list(data); + remove_gbar_dirty_object_list(data); /* for the safety */ + widget_unref(data); +} + +static void __widget_del(Evas_Object *widget) +{ + struct widget_data *data = NULL; + + data = evas_object_smart_data_get(widget); + if (!data) { + ErrPrint("Invalid object\n"); + return; + } + + if (data->state != WIDGET_DATA_CREATED) { + ErrPrint("Invalid widget data: %p\n", data); + return; + } + + if (data->is.field.deleted == 1) { + DbgPrint("Already deleted: %s\n", data->widget_id); + return; + } + + data->is.field.deleted = 1; + + if (data->delayed_resume_timer) { + ecore_timer_del(data->delayed_resume_timer); + data->delayed_resume_timer = NULL; + } + + s_info.list = eina_list_remove(s_info.list, widget); + + if (data->handle) { + widget_viewer_set_data(data->handle, NULL); + + if (data->is.field.send_delete) { + widget_delete_type_e delete_type; + + if (data->is.field.permanent_delete) { + delete_type = WIDGET_DELETE_PERMANENTLY; + } else { + delete_type = WIDGET_DELETE_TEMPORARY; + } + DbgPrint("Send delete request (0x%X)\n", delete_type); + + if (data->is.field.created) { + if (widget_viewer_delete_widget(data->handle, delete_type, __widget_destroy_widget_cb, widget_ref(data)) < 0) { + widget_unref(data); + data = NULL; + } + } else { + DbgPrint("Not created yet. this will be canceld by created callback, ignore delete callback\n"); + if (widget_viewer_delete_widget(data->handle, delete_type, NULL, NULL) < 0) { + DbgPrint("Unref %p\n", data); + } + } + } else { + DbgPrint("Skip delete request\n"); + } + } else { + DbgPrint("Handle is not created: %s\n", data->widget_id); + } + + /** + * From now, the widget object is not valid + */ + if (data) { + data->widget = NULL; + widget_unref(data); + } +} + +static Eina_Bool delayed_resume_timer_cb(void *_data) +{ + struct widget_data *data = _data; + + (void)widget_viewer_set_visibility(data->handle, WIDGET_SHOW); + + if (data->is.field.widget_dirty) { + /** + * If the object has dirty flag, pumping it up again + * To updates its content + */ + append_widget_dirty_object_list(data, WIDGET_KEEP_BUFFER); + } + + data->delayed_resume_timer = NULL; + return ECORE_CALLBACK_CANCEL; +} + +static void update_visibility(struct widget_data *data) +{ + int is_visible = 0; + int delay; + + if (!data->handle || !data->is.field.created) { + return; + } + + if (data->is.field.freeze_visibility) { + DbgPrint("Freezed visibility: %X (%s)\n", data->freezed_visibility, widget_viewer_get_pkgname(data->handle)); + + if (data->freezed_visibility == WIDGET_VISIBILITY_STATUS_SHOW_FIXED) { + if (data->delayed_resume_timer) { + (void)ecore_timer_del(data->delayed_resume_timer); + data->delayed_resume_timer = NULL; + } + (void)widget_viewer_set_visibility(data->handle, WIDGET_SHOW); + } else if (data->freezed_visibility == WIDGET_VISIBILITY_STATUS_HIDE_FIXED) { + if (data->delayed_resume_timer) { + (void)ecore_timer_del(data->delayed_resume_timer); + data->delayed_resume_timer = NULL; + } + (void)widget_viewer_set_visibility(data->handle, WIDGET_HIDE_WITH_PAUSE); + } + return; + } + + is_visible = evas_object_visible_get(data->stage); + + if (is_visible) { + Evas_Coord x, y, w, h; + + evas_object_geometry_get(data->widget_layout, &x, &y, &w, &h); + + if (!s_info.conf.field.user_view_port) { + Ecore_Evas *ee; + + ee = ecore_evas_ecore_evas_get(data->e); + if (ee) { + ecore_evas_geometry_get(ee, &data->view_port.x, &data->view_port.y, &data->view_port.w, &data->view_port.h); + } else { + data->view_port.x = 0; + data->view_port.y = 0; + ecore_x_window_size_get(0, &data->view_port.w, &data->view_port.h); + ErrPrint("Failed to get view port info (Fallback: %dx%d - %dx%d\n", + data->view_port.x, data->view_port.y, data->view_port.w, data->view_port.h); + } + } + + if (x + w <= data->view_port.x || x >= data->view_port.x + data->view_port.w || y + h <= data->view_port.y || y >= data->view_port.y + data->view_port.h) { + is_visible = 0; + } else { + is_visible = 1; + } + } + + if (data->is.field.delayed_resume == 0) { /* Follow the global configuration */ + delay = s_info.conf.field.delayed_resume; + } else { /* Ignore the global configuration */ + // 1 : Disable Delayed Pause Resume + // 2 : Enable Delayed Pause Resume + delay = (data->is.field.delayed_resume == 2); + } + + if (delay) { + if (is_visible) { + if (data->delayed_resume_timer) { + DbgPrint("Reset timer\n"); + ecore_timer_reset(data->delayed_resume_timer); + } else if (WIDGET_CONF_VISIBILITY_CHANGE_DELAY > 0.0f) { + DbgPrint("Add timer (%lf)\n", WIDGET_CONF_VISIBILITY_CHANGE_DELAY); + data->delayed_resume_timer = ecore_timer_add(WIDGET_CONF_VISIBILITY_CHANGE_DELAY, delayed_resume_timer_cb, data); + if (!data->delayed_resume_timer) { + ErrPrint("Failed to add a timer\n"); + delayed_resume_timer_cb(data); + } + } else { + DbgPrint("Direct update\n"); + delayed_resume_timer_cb(data); + } + } else { + if (data->delayed_resume_timer) { + ecore_timer_del(data->delayed_resume_timer); + data->delayed_resume_timer = NULL; + } + + widget_viewer_set_visibility(data->handle, WIDGET_HIDE_WITH_PAUSE); + } + } else { + /** + * @note + * In this case, if there is any registered timer, + * this function should clear it. + * Timer means that the delayed_resume mode is changed. + */ + if (data->delayed_resume_timer) { + ecore_timer_del(data->delayed_resume_timer); + data->delayed_resume_timer = NULL; + DbgPrint("Clear delayed resume timer\n"); + } + + DbgPrint("Direct update\n"); + if (is_visible) { + delayed_resume_timer_cb(data); + } else { + widget_viewer_set_visibility(data->handle, WIDGET_HIDE_WITH_PAUSE); + } + } +} + +static int do_force_mouse_up(struct widget_data *data) +{ + struct widget_mouse_event_info minfo; + Evas_Coord x, y, w, h; + struct widget_evas_event_info info; + + if (s_info.conf.field.auto_render_selector && s_info.conf.field.render_animator == 0) { + DbgPrint("Change to render animator\n"); + s_info.conf.field.render_animator = 1; + } + + if (!data->is.field.pressed) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + evas_object_geometry_get(data->widget, &x, &y, &w, &h); + + minfo.x = (double)(data->x - x) / (double)w; + minfo.y = (double)(data->y - y) / (double)h; + + data->is.field.pressed = 0; + + reset_scroller(data); + + if (s_info.conf.field.auto_feed && data->is.field.mouse_event) { + DbgPrint("%x\n", data->is.field.cancel_click); + if (data->is.field.cancel_click != CANCEL_PROCESSED) { + DbgPrint("ON_HOLD send\n"); + widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_ON_HOLD, &minfo); + data->is.field.cancel_click = CANCEL_PROCESSED; + } + + /** + * @note + * UNSET will subtract object.x and object.y by master + * so we just send original touch position based on screen + */ + minfo.x = (double)data->x / (double)data->down.geo.w; + minfo.y = (double)data->y / (double)data->down.geo.h; + widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_UNSET, &minfo); + } else { + if (!data->is.field.mouse_event) { + /* We have to keep the first position of touch down */ + minfo.x = (double)(data->down.x - x) / (double)w; + minfo.y = (double)(data->down.y - y) / (double)h; + } + + DbgPrint("%x\n", data->is.field.cancel_click); + if (data->is.field.cancel_click != CANCEL_PROCESSED) { + DbgPrint("ON_HOLD send\n"); + widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_ON_HOLD, &minfo); + data->is.field.cancel_click = CANCEL_PROCESSED; + } + + widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_UP, &minfo); + widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_LEAVE, &minfo); + } + + data->is.field.cancel_click = CANCEL_DISABLED; + data->is.field.flick_down = 0; + info.widget_app_id = data->widget_id; + info.event = WIDGET_EVENT_GBAR_CREATED; + info.error = WIDGET_ERROR_CANCELED; + smart_callback_call(data, WIDGET_SMART_SIGNAL_FLICKDOWN_CANCELLED, &info); + DbgPrint("Flick down is canceled\n"); + return WIDGET_ERROR_NONE; +} + +static void __widget_move(Evas_Object *widget, Evas_Coord x, Evas_Coord y) +{ + struct widget_data *data; + Evas_Coord w, h; + + data = evas_object_smart_data_get(widget); + if (!data) { + ErrPrint("Invalid object\n"); + return; + } + + if (data->state != WIDGET_DATA_CREATED) { + ErrPrint("Invalid widget data: %p\n", data); + return; + } + + if (data->gbar_layout) { + Evas_Coord gbar_x, gbar_y, gbar_h; + Evas_Coord prev_x, prev_y; + Evas_Coord widget_w, widget_h; + double rx; + double ry; + + evas_object_geometry_get(data->widget_layout, &prev_x, &prev_y, &widget_w, &widget_h); + evas_object_geometry_get(data->gbar_layout, &gbar_x, &gbar_y, NULL, &gbar_h); + + gbar_x += (x - prev_x); + gbar_y += (y - prev_y); + + evas_object_move(data->gbar_layout, gbar_x, gbar_y); + + rx = ((double)x + (double)widget_w / 2.0f) / s_info.screen_width; + switch (find_size_type(data, widget_w, widget_h)) { + case WIDGET_SIZE_TYPE_1x1: + if (rx < 0.25f) { + rx = 0.125f; + } else if (rx < 0.5f) { + rx = 0.375f; + } else if (rx < 0.75f) { + rx = 0.625f; + } else if (rx < 1.0f) { + rx = 0.875f; + } + break; + case WIDGET_SIZE_TYPE_2x1: + case WIDGET_SIZE_TYPE_2x2: + if (rx < 0.5f) { + rx = 0.25f; + } else if (rx < 0.75f) { + rx = 0.5f; + } else { + rx = 0.75f; + } + break; + default: + rx = 0.5f; + break; + } + if (prev_y + widget_h + gbar_h > s_info.screen_height) { + ry = 1.0f; + } else { + ry = 0.0f; + } + + if (data->is.field.gbar_created) { + widget_viewer_move_glance_bar(data->handle, rx, ry); + } + } + + evas_object_move(data->stage, x, y); + evas_object_move(data->widget_layout, x, y); + evas_object_geometry_get(data->widget_layout, NULL, NULL, &w, &h); + + if (!s_info.conf.field.manual_pause_resume) { + update_visibility(data); + } + + if (s_info.conf.field.sensitive_move) { + do_force_mouse_up(data); + } +} + +static int widget_create_plug_object(struct widget_data *data) +{ + struct acquire_data acquire_data = { + .w = 0, + .h = 0, + .content = NULL, + .data = data, + }; + + DbgPrint("Plug type created\n"); + + acquire_data.content = elm_object_part_content_unset(data->widget_layout, "widget,content"); + if (acquire_data.content) { + DbgPrint("widget Content is already prepared: %s\n", widget_viewer_get_filename(data->handle)); + evas_object_del(acquire_data.content); + } + + acquire_data.content = elm_plug_add(s_info.win); + if (!acquire_data.content) { + ErrPrint("Failed to add a plug object\n"); + return WIDGET_ERROR_FAULT; + } + + DbgPrint("Try to connect to %s\n", widget_viewer_get_filename(data->handle)); + if (!elm_plug_connect(acquire_data.content, widget_viewer_get_filename(data->handle), 0, EINA_TRUE)) { + ErrPrint("Cannot connect plug[%s]", widget_viewer_get_filename(data->handle)); + evas_object_del(acquire_data.content); + return WIDGET_ERROR_FAULT; + } + + elm_object_part_content_set(data->widget_layout, "widget,content", acquire_data.content); + + acquire_data.w = data->widget_width; + acquire_data.h = data->widget_height; + update_widget_geometry(&acquire_data); + return WIDGET_ERROR_NONE; +} + +static int widget_create_image_object(struct widget_data *data) +{ + Evas_Object *front_image; + struct acquire_data acquire_data = { + .w = 0, + .h = 0, + .content = NULL, + .data = data, + }; + + DbgPrint("Image type created\n"); + + acquire_data.content = elm_object_part_content_get(data->widget_layout, "widget,content"); + if (!acquire_data.content) { + acquire_data.content = elm_layout_add(data->parent); + if (!acquire_data.content) { + ErrPrint("Failed to create an edje object\n"); + return WIDGET_ERROR_FAULT; + } + + if (elm_layout_file_set(acquire_data.content, WIDGET_VIEWER_EVAS_RESOURCE_EDJ, WIDGET_VIEWER_EVAS_RESOURCE_IMG) == EINA_FALSE) { + ErrPrint("Failed to load edje object: %s(%s)\n", WIDGET_VIEWER_EVAS_RESOURCE_EDJ, WIDGET_VIEWER_EVAS_RESOURCE_IMG); + evas_object_del(acquire_data.content); + return WIDGET_ERROR_IO_ERROR; + } + + front_image = elm_image_add(acquire_data.content); + if (!front_image) { + ErrPrint("Failed to add front_image object\n"); + evas_object_del(acquire_data.content); + return WIDGET_ERROR_FAULT; + } + + DbgPrint("Default size %dx%d\n", data->widget_width, data->widget_height); + + elm_object_part_content_set(acquire_data.content, "front,content", front_image); + elm_object_part_content_set(data->widget_layout, "widget,content", acquire_data.content); + } else { + front_image = elm_object_part_content_get(acquire_data.content, "front,content"); + if (!front_image) { + ErrPrint("Unable to get front,content object\n"); + front_image = elm_image_add(acquire_data.content); + if (!front_image) { + ErrPrint("Failed to add front_image object\n"); + return WIDGET_ERROR_FAULT; + } + + elm_object_part_content_set(acquire_data.content, "front,content", front_image); + } + } + + /* + evas_object_geometry_get(data->widget, NULL, NULL, &acquire_data.w, &acquire_data.h); + DbgPrint("Default size %dx%d\n", acquire_data.w, acquire_data.h); + DbgPrint("Image size: %dx%d\n", acquire_data.w, acquire_data.h); + */ + acquire_data.w = data->widget_width; + acquire_data.h = data->widget_height; + update_widget_geometry(&acquire_data); + return WIDGET_ERROR_NONE; +} + +static int widget_create_buffer_object(struct widget_data *data) +{ + Evas_Object *widget_viewer_get_content_string; + + widget_viewer_get_content_string = elm_object_part_content_get(data->widget_layout, "widget,content"); + if (!widget_viewer_get_content_string) { + widget_viewer_get_content_string = evas_object_image_filled_add(data->e); + if (!widget_viewer_get_content_string) { + ErrPrint("Failed to create an image object\n"); + return WIDGET_ERROR_FAULT; + } + + evas_object_image_colorspace_set(widget_viewer_get_content_string, EVAS_COLORSPACE_ARGB8888); + evas_object_image_alpha_set(widget_viewer_get_content_string, EINA_TRUE); + elm_object_part_content_set(data->widget_layout, "widget,content", widget_viewer_get_content_string); + } + + return WIDGET_ERROR_NONE; +} + +static int widget_text_update_begin(widget_h handle) +{ + struct widget_data *data; + data = get_smart_data_from_handle(handle); + if (!data) { + return WIDGET_ERROR_FAULT; + } + + DbgPrint("Begin text update: [%s]\n", data->widget_id); + + return WIDGET_ERROR_NONE; +} + +static int widget_text_update_end(widget_h handle) +{ + struct widget_data *data; + data = get_smart_data_from_handle(handle); + if (!data) { + return WIDGET_ERROR_FAULT; + } + + DbgPrint("End text update: [%s]\n", data->widget_id); + + return WIDGET_ERROR_NONE; +} + +static int widget_text_update_text(widget_h handle, const char *id, const char *part, const char *data) +{ + struct widget_data *widget_data; + Evas_Object *layout; + + widget_data = get_smart_data_from_handle(handle); + if (!widget_data) { + return WIDGET_ERROR_FAULT; + } + + layout = find_script_object(widget_data, 0, id); + if (!layout) { + ErrPrint("Target[%s] is not exists\n", id); + return WIDGET_ERROR_NOT_EXIST; + } + + return do_text_update_text(widget_data->parent, layout, part, data); +} + +static int widget_text_update_image(widget_h handle, const char *id, const char *part, const char *data, const char *option) +{ + struct widget_data *widget_data; + Evas_Object *layout; + + widget_data = get_smart_data_from_handle(handle); + if (!widget_data) { + return WIDGET_ERROR_FAULT; + } + + layout = find_script_object(widget_data, 0, id); + if (!layout) { + ErrPrint("Target[%s] is not exists\n", id); + return WIDGET_ERROR_NOT_EXIST; + } + + return do_text_update_image(layout, part, data, option); +} + +static int widget_text_update_script(widget_h handle, const char *id, const char *new_id, const char *part, const char *file, const char *group) +{ + struct widget_data *data; + Evas_Object *layout; + + data = get_smart_data_from_handle(handle); + if (!data) { + return WIDGET_ERROR_FAULT; + } + + layout = find_script_object(data, 0, id); + if (!layout) { + ErrPrint("Target[%s] is not exists\n", id); + return WIDGET_ERROR_NOT_EXIST; + } + + return do_text_update_script(data, 0, layout, new_id, part, file, group); +} + +static int widget_text_update_signal(widget_h handle, const char *id, const char *signal_name, const char *signal) +{ + struct widget_data *data; + Evas_Object *layout; + + data = get_smart_data_from_handle(handle); + if (!data) { + return WIDGET_ERROR_FAULT; + } + + layout = find_script_object(data, 0, id); + if (!layout) { + ErrPrint("Target[%s] is not exists\n", id); + return WIDGET_ERROR_NOT_EXIST; + } + + elm_object_signal_emit(layout, signal, signal_name); + return WIDGET_ERROR_NONE; +} + +static int widget_text_update_drag(widget_h handle, const char *id, const char *part, double dx, double dy) +{ + struct widget_data *data; + Evas_Object *layout; + + data = get_smart_data_from_handle(handle); + if (!data) { + return WIDGET_ERROR_FAULT; + } + + layout = find_script_object(data, 0, id); + if (!layout) { + ErrPrint("Target[%s] is not exists\n", id); + return WIDGET_ERROR_NOT_EXIST; + } + + edje_object_part_drag_value_set(elm_layout_edje_get(layout), part, dx, dy); + return WIDGET_ERROR_NONE; +} + +static int widget_text_update_info_size(widget_h handle, const char *id, int w, int h) +{ + struct widget_data *data; + Evas_Object *layout; + + data = get_smart_data_from_handle(handle); + if (!data) { + return WIDGET_ERROR_FAULT; + } + + layout = find_script_object(data, 0, id); + if (!layout) { + ErrPrint("Target[%s] is not exists\n", id); + return WIDGET_ERROR_NOT_EXIST; + } + + DbgPrint("Resize to %dx%d\n", w, h); + evas_object_resize(layout, w, h); + + return WIDGET_ERROR_NONE; +} + +static int widget_text_update_info_category(widget_h handle, const char *id, const char *category) +{ + struct widget_data *data; + Evas_Object *layout; + + data = get_smart_data_from_handle(handle); + if (!data) { + return WIDGET_ERROR_FAULT; + } + + layout = find_script_object(data, 0, id); + if (!layout) { + ErrPrint("Target[%s] is not exists\n", id); + return WIDGET_ERROR_NOT_EXIST; + } + + DbgPrint("Update category: %s\n", category); + + return WIDGET_ERROR_NONE; +} + +static int widget_text_update_access(widget_h handle, const char *id, const char *part, const char *text, const char *option) +{ + struct widget_data *data; + Evas_Object *layout; + + data = get_smart_data_from_handle(handle); + if (!data) { + return WIDGET_ERROR_FAULT; + } + + layout = find_script_object(data, 0, id); + if (!layout) { + ErrPrint("Target[%s] is not exists\n", id); + return WIDGET_ERROR_NOT_EXIST; + } + + return do_text_update_access(data->parent, layout, part, text, option); +} + +static int widget_text_operate_access(widget_h handle, const char *id, const char *part, const char *operation, const char *option) +{ + struct widget_data *data; + Evas_Object *layout; + + data = get_smart_data_from_handle(handle); + if (!data) { + return WIDGET_ERROR_FAULT; + } + + layout = find_script_object(data, 0, id); + if (!layout) { + ErrPrint("Target[%s] is not exists\n", id); + return WIDGET_ERROR_NOT_EXIST; + } + + return do_text_operate_access(layout, part, operation, option); +} + +static int widget_text_update_color(widget_h handle, const char *id, const char *part, const char *data) +{ + struct widget_data *widget_data; + Evas_Object *layout; + + widget_data = get_smart_data_from_handle(handle); + if (!widget_data) { + return WIDGET_ERROR_FAULT; + } + + layout = find_script_object(widget_data, 0, id); + if (!layout) { + ErrPrint("Target[%s] is not exists\n", id); + return WIDGET_ERROR_NOT_EXIST; + } + + return do_text_update_color(layout, part, data); +} +static int widget_create_text_object(struct widget_data *data) +{ + Evas_Object *content; + + content = elm_object_part_content_get(data->widget_layout, "widget,content"); + if (!content) { + int ret; + char *script_file; + char *script_group; + struct widget_script_operators operator = { + .update_begin = widget_text_update_begin, + .update_end = widget_text_update_end, + + .update_text = widget_text_update_text, + .update_image = widget_text_update_image, + .update_script = widget_text_update_script, + .update_signal = widget_text_update_signal, + .update_drag = widget_text_update_drag, + .update_info_size = widget_text_update_info_size, + .update_info_category = widget_text_update_info_category, + .update_access = widget_text_update_access, + .operate_access = widget_text_operate_access, + .update_color = widget_text_update_color, + }; + + content = elm_layout_add(data->widget_layout); + if (!content) { + ErrPrint("Failed to create a layout object\n"); + return WIDGET_ERROR_FAULT; + } + + script_file = widget_service_get_widget_script_path(data->widget_id); + script_group = widget_service_get_widget_script_group(data->widget_id); + if (!script_file || !script_group) { + ErrPrint("Invalid script info ([%s] - [%s])\n", script_file, script_group); + free(script_file); + free(script_group); + evas_object_del(content); + return WIDGET_ERROR_FAULT; + } + + if (access(script_file, R_OK) != 0) { + ErrPrint("Unable to access [%s] - %d\n", script_file, errno); + free(script_file); + free(script_group); + evas_object_del(content); + return WIDGET_ERROR_FAULT; + } + + ret = elm_layout_file_set(content, script_file, script_group); + DbgPrint("Load edje file ([%s] - [%s])\n", script_file, script_group); + free(script_file); + free(script_group); + if (ret == EINA_FALSE) { + ErrPrint("Failed to load EDJE\n"); + evas_object_del(content); + return WIDGET_ERROR_FAULT; + } + + ret = widget_viewer_set_text_handler(data->handle, 0, &operator); + if (ret != WIDGET_ERROR_NONE) { + ErrPrint("Failed to set text handler for [%s]\n", data->widget_id); + evas_object_del(content); + return ret; + } + + ret = append_script_object(data, 0, NULL, NULL, content); + if (ret != WIDGET_ERROR_NONE) { + ErrPrint("Failed to append this to script object list\n"); + evas_object_del(content); + return ret; + } + + elm_object_part_content_set(data->widget_layout, "widget,content", content); + } + + return WIDGET_ERROR_NONE; +} + +static int widget_create_pixmap_object(struct widget_data *data) +{ + Evas_Object *widget_viewer_get_content_string; + + widget_viewer_get_content_string = elm_object_part_content_get(data->widget_layout, "widget,content"); + if (!widget_viewer_get_content_string) { + widget_viewer_get_content_string = evas_object_image_filled_add(data->e); + if (!widget_viewer_get_content_string) { + ErrPrint("Failed to create an image object\n"); + return WIDGET_ERROR_FAULT; + } + + evas_object_image_colorspace_set(widget_viewer_get_content_string, EVAS_COLORSPACE_ARGB8888); + evas_object_image_alpha_set(widget_viewer_get_content_string, EINA_TRUE); + evas_object_event_callback_add(widget_viewer_get_content_string, EVAS_CALLBACK_DEL, __widget_pixmap_del_cb, data); + + elm_object_part_content_set(data->widget_layout, "widget,content", widget_viewer_get_content_string); + } + + return WIDGET_ERROR_NONE; +} + +static void __widget_resize_pixmap_object(struct widget_data *data) +{ + DbgPrint("widget resize request is succssfully sent\n"); +} + +static void update_widget_pixmap(Evas_Object *content, int w, int h) +{ + evas_object_image_pixels_dirty_set(content, EINA_TRUE); + evas_object_image_data_update_add(content, 0, 0, w, h); + evas_object_show(content); +} + +static void acquire_widget_extra_resource_cb(struct widget *handle, int pixmap, void *cbdata) +{ + DbgPrint("Acquired: %u\n", (unsigned int)pixmap); +} + +static void acquire_gbar_extra_resource_cb(struct widget *handle, int pixmap, void *cbdata) +{ + DbgPrint("Acquired: %u\n", (unsigned int)pixmap); +} + +static void replace_pixmap(struct widget *handle, int gbar, Evas_Object *content, unsigned int pixmap) +{ + Evas_Native_Surface *old_surface; + Evas_Native_Surface surface; + + surface.version = EVAS_NATIVE_SURFACE_VERSION; + surface.type = EVAS_NATIVE_SURFACE_X11; + surface.data.x11.pixmap = pixmap; + + old_surface = evas_object_image_native_surface_get(content); + if (!old_surface) { + surface.data.x11.visual = ecore_x_default_visual_get(ecore_x_display_get(), ecore_x_default_screen_get()); + + evas_object_image_native_surface_set(content, &surface); + + DbgPrint("Created: %u\n", surface.data.x11.pixmap); + } else { + unsigned int old_pixmap; + + old_pixmap = old_surface->data.x11.pixmap; + + if (old_pixmap != pixmap) { + surface.data.x11.visual = old_surface->data.x11.visual; + evas_object_image_native_surface_set(content, &surface); + + if (old_pixmap && handle) { + if (!s_info.conf.field.skip_acquire) { + widget_viewer_release_resource_id(handle, gbar, old_pixmap); + } + } + + DbgPrint("Replaced: %u (%u)\n", pixmap, old_pixmap); + } else { + DbgPrint("Same resource, reuse it [%u]\n", pixmap); + } + } +} + +static void acquire_widget_pixmap_cb(struct widget *handle, int pixmap, void *cbdata) +{ + struct acquire_data *acquire_data = cbdata; + struct widget_data *data = acquire_data->data; + + data->is.field.widget_pixmap_acquire_requested = 0; + __widget_overlay_disable(data, 0); + + if (pixmap == 0) { + DbgPrint("Pixmap gotten (0)\n"); + if (!s_info.conf.field.skip_acquire) { + free(acquire_data); + } + widget_unref(data); + return; + } + + evas_object_image_size_set(acquire_data->content, acquire_data->w, acquire_data->h); + evas_object_image_fill_set(acquire_data->content, 0, 0, acquire_data->w, acquire_data->h); + DbgPrint("fillset: %dx%d\n", acquire_data->w, acquire_data->h); + + replace_pixmap(handle, 0, acquire_data->content, (unsigned int)pixmap); + + data->widget_pixmap = pixmap; + + append_widget_dirty_object_list(data, WIDGET_KEEP_BUFFER); + update_widget_geometry(acquire_data); + + widget_unref(data); + if (!s_info.conf.field.skip_acquire) { + free(acquire_data); + } +} + +static void __widget_update_pixmap_object(struct widget_data *data, Evas_Object *widget_content, int w, int h) +{ + int ret; + struct acquire_data *acquire_data; + + if (data->widget_latest_idx == WIDGET_PRIMARY_BUFFER) { + unsigned int resource_id; + + widget_viewer_get_resource_id(data->handle, 0, &resource_id); + if (data->widget_pixmap == resource_id) { + if (data->widget_extra) { + /* Just replace the pixmap in this case, do not release old pixmap */ + replace_pixmap(NULL, 0, widget_content, data->widget_pixmap); + } + + update_widget_pixmap(widget_content, w, h); + return; + } + + if (s_info.conf.field.skip_acquire && resource_id != 0) { + struct acquire_data local_acquire_data = { + .data = widget_ref(data), + .content = widget_content, + .w = w, + .h = h, + }; + + acquire_widget_pixmap_cb(data->handle, resource_id, &local_acquire_data); + return; + } + + if (data->is.field.widget_pixmap_acquire_requested) { + DbgPrint("Pixmap is not acquired\n"); + return; + } + + acquire_data = malloc(sizeof(*acquire_data)); + if (!acquire_data) { + ErrPrint("malloc: %d\n", errno); + return; + } + + acquire_data->data = widget_ref(data); + acquire_data->content = widget_content; + acquire_data->w = w; + acquire_data->h = h; + + ret = widget_viewer_acquire_resource_id(data->handle, 0, acquire_widget_pixmap_cb, acquire_data); + if (ret != WIDGET_ERROR_NONE) { + widget_unref(data); + free(acquire_data); + } else { + data->is.field.widget_pixmap_acquire_requested = 1; + } + } else { + if (!data->widget_extra) { + ErrPrint("Extra buffer is not prepared yet\n"); + return; + } + + replace_pixmap(NULL, 0, widget_content, data->widget_extra[data->widget_latest_idx]); + update_widget_pixmap(widget_content, w, h); + } +} + +static int widget_system_created(struct widget *handle, struct widget_data *data) +{ + int ret; + struct widget_evas_event_info info; + widget_type_e widget_type; + + if (data->state != WIDGET_DATA_CREATED) { + ErrPrint("Invalid widget data: %p, %s\n", data, widget_viewer_get_pkgname(handle)); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + widget_viewer_get_size_type(handle, &data->size_type); + + if (data->size_type == WIDGET_SIZE_TYPE_UNKNOWN || widget_service_get_size(data->size_type, &data->widget_width, &data->widget_height) < 0) { + ErrPrint("Failed to get size info: %s\n", widget_viewer_get_pkgname(handle)); + + } else { + DbgPrint("System created WIDGET size is (%d)%dx%d\n", data->size_type, data->widget_width, data->widget_height); + } + + widget_viewer_get_type(handle, 0, &widget_type); + + switch (widget_type) { + case WIDGET_CONTENT_TYPE_IMAGE: + ret = widget_create_image_object(data); + break; + case WIDGET_CONTENT_TYPE_RESOURCE_ID: + if (!s_info.conf.field.force_to_buffer) { + ret = widget_create_pixmap_object(data); + break; + } + case WIDGET_CONTENT_TYPE_BUFFER: + ret = widget_create_buffer_object(data); + break; + case WIDGET_CONTENT_TYPE_TEXT: + ret = widget_create_text_object(data); + break; + case WIDGET_CONTENT_TYPE_UIFW: + ret = widget_create_plug_object(data); + break; + case WIDGET_CONTENT_TYPE_INVALID: + default: + ret = WIDGET_ERROR_INVALID_PARAMETER; + break; + } + + if (ret == WIDGET_ERROR_NONE) { + info.error = WIDGET_ERROR_NONE; + info.widget_app_id = data->widget_id; + info.event = WIDGET_EVENT_CREATED; + + data->is.field.created = 1; + + update_visibility(data); + smart_callback_call(data, WIDGET_SMART_SIGNAL_WIDGET_CREATED, &info); + + /** + * In case of using the direct update path, + * sometimes the provider can send the updated event faster than created event. + * In that case, the viewer cannot recognize the updated content of a widget. + * So for the safety, I added this to forcely update the widget at the first time + * Right after creating its instance. + */ + append_widget_dirty_object_list(data, WIDGET_PRIMARY_BUFFER); + } + + return ret; +} + +static void __widget_created_cb(struct widget *handle, int ret, void *cbdata) +{ + struct widget_data *data = cbdata; + struct widget_evas_event_info info; + widget_type_e widget_type; + + if (data->state != WIDGET_DATA_CREATED) { + ErrPrint("Invalid widget data: %p (%d), %s\n", data, ret, widget_viewer_get_pkgname(handle)); + return; + } + + if (ret != WIDGET_ERROR_NONE) { + DbgPrint("Failed to create: %X\n", ret); + data->handle = NULL; + + if (!data->is.field.deleted) { + struct widget_evas_event_info fault_event; + + fault_event.error = ret; + fault_event.widget_app_id = data->widget_id; + fault_event.event = WIDGET_EVENT_CREATED; + + if (!data->is.field.faulted) { + data->is.field.faulted = 1; + __widget_overlay_faulted(data); + } + + DbgPrint("Display tap to load (%p) [%s]\n", data, data->widget_id); + smart_callback_call(data, WIDGET_SMART_SIGNAL_WIDGET_CREATE_ABORTED, &fault_event); + + ret = WIDGET_ERROR_FAULT; + } else { + ret = WIDGET_ERROR_CANCELED; + } + + data->is.field.send_delete = 0; + DbgPrint("Invoke raw delete %s\n", data->widget_id); + (void)invoke_raw_event_callback(WIDGET_VIEWER_EVAS_RAW_DELETE, data->widget_id, data->widget, ret); + widget_unref(data); + return; + } + + widget_viewer_get_type(handle, 0, &widget_type); + + switch (widget_type) { + case WIDGET_CONTENT_TYPE_IMAGE: + ret = widget_create_image_object(data); + break; + case WIDGET_CONTENT_TYPE_RESOURCE_ID: + if (!s_info.conf.field.force_to_buffer) { + ret = widget_create_pixmap_object(data); + break; + } + case WIDGET_CONTENT_TYPE_BUFFER: + ret = widget_create_buffer_object(data); + break; + case WIDGET_CONTENT_TYPE_TEXT: + ret = widget_create_text_object(data); + break; + case WIDGET_CONTENT_TYPE_UIFW: + ret = widget_create_plug_object(data); + break; + case WIDGET_CONTENT_TYPE_INVALID: + default: + ret = WIDGET_ERROR_INVALID_PARAMETER; + break; + } + + if (ret == WIDGET_ERROR_NONE) { + info.error = WIDGET_ERROR_NONE; + info.widget_app_id = data->widget_id; + info.event = WIDGET_EVENT_CREATED; + + data->is.field.created = 1; + + update_visibility(data); + smart_callback_call(data, WIDGET_SMART_SIGNAL_WIDGET_CREATED, &info); + DbgPrint("Invoke raw create %s\n", data->widget_id); + (void)invoke_raw_event_callback(WIDGET_VIEWER_EVAS_RAW_CREATE, data->widget_id, data->widget, ret); + + /** + * In case of using the direct update path, + * sometimes the provider can send the updated event faster than created event. + * In that case, the viewer cannot recognize the updated content of a widget. + * So for the safety, I added this to forcely update the widget at the first time + * Right after creating its instance. + */ + append_widget_dirty_object_list(data, WIDGET_KEEP_BUFFER); + } else { + info.error = ret; + info.widget_app_id = data->widget_id; + info.event = WIDGET_EVENT_CREATED; + smart_callback_call(data, WIDGET_SMART_SIGNAL_WIDGET_CREATE_ABORTED, &info); + data->is.field.send_delete = 0; + DbgPrint("Invoke raw delete %s\n", data->widget_id); + (void)invoke_raw_event_callback(WIDGET_VIEWER_EVAS_RAW_DELETE, data->widget_id, data->widget, ret); + } + + widget_unref(data); +} + +static void __widget_resize_image_object(struct widget_data *data) +{ + DbgPrint("widget resize request is succssfully sent\n"); +} + +static void __widget_resize_buffer_object(struct widget_data *data) +{ + DbgPrint("widget resize request is succssfully sent\n"); +} + +static void __widget_resize_text_object(struct widget_data *data) +{ + DbgPrint("widget resize request is succssfully sent\n"); +} + +static void __widget_resize_cb(struct widget *handle, int ret, void *cbdata) +{ + struct widget_data *data = cbdata; + struct widget_evas_event_info info; + widget_type_e widget_type; + + if (data->state != WIDGET_DATA_CREATED) { + ErrPrint("Invalid widget data: %p\n", data); + return; + } + + if (ret != WIDGET_ERROR_NONE) { + info.error = ret; + info.event = WIDGET_EVENT_WIDGET_SIZE_CHANGED; + info.widget_app_id = data->widget_id; + smart_callback_call(data, WIDGET_SMART_SIGNAL_WIDGET_RESIZE_ABORTED, &info); + widget_unref(data); + return; + } + widget_viewer_get_type(handle, 0, &widget_type); + switch (widget_type) { + case WIDGET_CONTENT_TYPE_IMAGE: + __widget_resize_image_object(data); + break; + case WIDGET_CONTENT_TYPE_RESOURCE_ID: + if (!s_info.conf.field.force_to_buffer) { + __widget_resize_pixmap_object(data); + break; + } + case WIDGET_CONTENT_TYPE_BUFFER: + __widget_resize_buffer_object(data); + break; + case WIDGET_CONTENT_TYPE_TEXT: + __widget_resize_text_object(data); + break; + case WIDGET_CONTENT_TYPE_UIFW: + break; + case WIDGET_CONTENT_TYPE_INVALID: + break; + default: + break; + } + + info.error = ret; + info.event = WIDGET_EVENT_WIDGET_SIZE_CHANGED; + info.widget_app_id = data->widget_id; + smart_callback_call(data, WIDGET_SMART_SIGNAL_WIDGET_RESIZED, &info); + widget_unref(data); +} + +static void gbar_overlay_disable(struct widget_data *data) +{ + if (!data->gbar_layout) { + return; + } + + if (!data->is.field.gbar_overlay_loaded) { + return; + } + + elm_object_signal_emit(data->gbar_layout, "disable", "overlay"); + data->is.field.gbar_overlay_loaded = 0; +} + +static void gbar_overlay_loading(struct widget_data *data) +{ + Evas_Object *rect; + + if (data->is.field.gbar_overlay_loaded) { + ErrPrint("Already loaded"); + return; + } + + rect = elm_object_part_content_unset(data->gbar_layout, "overlay,content"); + if (rect) { + evas_object_del(rect); + } + + rect = evas_object_rectangle_add(data->e); + evas_object_color_set(rect, 0, 0, 0, 0); + evas_object_show(rect); + /*! + * \todo + * Overlay for loading a GBAR + */ + + elm_object_part_content_set(data->gbar_layout, "overlay,content", rect); + elm_object_signal_emit(data->gbar_layout, "enable", "overlay"); + + data->is.field.gbar_overlay_loaded = 1; +} + +static Evas_Object *widget_load_overlay_edje(struct widget_data *data) +{ + Evas_Object *overlay; + + overlay = elm_layout_add(data->parent); + if (!overlay) { + ErrPrint("Failed to create a overlay\n"); + return NULL; + } + + if (elm_layout_file_set(overlay, WIDGET_VIEWER_EVAS_RESOURCE_EDJ, WIDGET_VIEWER_EVAS_RESOURCE_OVERLAY_LOADING) == EINA_FALSE) { + ErrPrint("Failed to load overlay file\n"); + evas_object_del(overlay); + return NULL; + } + + elm_object_part_content_set(data->widget_layout, "overlay,content", overlay); + return overlay; +} + +static Eina_Bool delayed_overlay_disable_cb(void *_data) +{ + struct widget_data *data = _data; + + elm_object_signal_emit(data->widget_layout, "disable", "overlay"); + + data->is.field.widget_overlay_loaded = 0; + data->overlay_update_counter = DEFAULT_OVERLAY_COUNTER; + data->overlay_timer = NULL; + return ECORE_CALLBACK_CANCEL; +} + +static void __widget_overlay_disable(struct widget_data *data, int no_timer) +{ + if (!data->widget_layout) { + return; + } + + if (!data->is.field.widget_overlay_loaded) { + return; + } + + data->overlay_update_counter--; + if (data->overlay_update_counter <= 0) { + if (no_timer) { + if (data->overlay_timer) { + ecore_timer_del(data->overlay_timer); + data->overlay_timer = NULL; + } + delayed_overlay_disable_cb(data); + } else { + if (data->overlay_timer) { + ecore_timer_del(data->overlay_timer); + data->overlay_timer = NULL; + delayed_overlay_disable_cb(data); + } else { + return; + } + } + } + + if (!no_timer && !data->overlay_timer) { + data->overlay_timer = ecore_timer_add(DEFAULT_OVERLAY_WAIT_TIME, delayed_overlay_disable_cb, data); + if (!data->overlay_timer) { + ErrPrint("Failed to create a timer\n"); + delayed_overlay_disable_cb(data); + } + } +} + +static void __widget_overlay_loading(struct widget_data *data) +{ + struct acquire_data acquire_data; + Evas_Object *overlay; + + if (data->is.field.disable_loading == 1) { + DbgPrint("Loading overlay is disabled"); + return; + } + + if (data->is.field.widget_overlay_loaded == 1) { + DbgPrint("Overlay is already loaded"); + return; + } + + overlay = elm_object_part_content_get(data->widget_layout, "overlay,content"); + if (!overlay) { + overlay = widget_load_overlay_edje(data); + if (!overlay) { + return; + } + } + + if (!data->is.field.disable_preview) { + char *icon; + + icon = get_package_icon(data); + if (icon) { + Evas_Object *preview; + + preview = elm_object_part_content_get(overlay, "preview"); + if (!preview) { + preview = elm_image_add(overlay); + } + + if (preview) { + elm_image_file_set(preview, icon, NULL); + elm_object_part_content_set(overlay, "preview", preview); + } + + free(icon); + } + + DbgPrint("Set overlay loading (%p) %s\n", data, data->widget_id); + } else { + DbgPrint("Overlay is disabled (%s)\n", data->widget_id); + } + + elm_object_part_text_set(overlay, "text", _("IDS_IDLE_POP_LOADING_ING")); + if (data->is.field.disable_text) { + elm_object_signal_emit(overlay, "disable", "text"); + } + + elm_object_signal_emit(data->widget_layout, "reset", "overlay"); + elm_object_signal_emit(data->widget_layout, "enable", "overlay"); + + evas_object_geometry_get(data->widget, NULL, NULL, &acquire_data.w, &acquire_data.h); + acquire_data.content = NULL; + acquire_data.data = data; + update_widget_geometry(&acquire_data); + + data->is.field.widget_overlay_loaded = 1; + data->overlay_update_counter = DEFAULT_OVERLAY_COUNTER; +} + +static void __widget_overlay_faulted(struct widget_data *data) +{ + struct acquire_data acquire_data; + Evas_Object *overlay; + widget_type_e widget_type; + + if (data->is.field.widget_overlay_loaded) { + data->overlay_update_counter = 0; + __widget_overlay_disable(data, 1); + } + + overlay = elm_object_part_content_get(data->widget_layout, "overlay,content"); + if (!overlay) { + overlay = widget_load_overlay_edje(data); + if (!overlay) { + return; + } + } + + widget_viewer_get_type(data->handle, 0, &widget_type); + if (widget_type != WIDGET_CONTENT_TYPE_IMAGE) { + Evas_Object *preview; + + preview = elm_object_part_content_get(overlay, "preview"); + if (!preview) { + char *icon; + + icon = widget_service_get_preview_image_path(data->widget_id, data->size_type); + if (icon) { + preview = elm_image_add(data->widget_layout); + if (preview) { + elm_image_file_set(preview, icon, NULL); + elm_object_part_content_set(overlay, "preview", preview); + } + + free(icon); + } + } + } + + DbgPrint("Set overlay fault (%p) %s\n", data, data->widget_id); + elm_object_part_text_set(overlay, "text", _("IDS_HS_BODY_UNABLE_TO_LOAD_DATA_TAP_TO_RETRY")); + elm_object_signal_emit(overlay, "enable", "text"); + elm_object_signal_emit(data->widget_layout, "reset", "overlay"); + elm_object_signal_emit(data->widget_layout, "enable", "overlay"); + + evas_object_geometry_get(data->widget, NULL, NULL, &acquire_data.w, &acquire_data.h); + acquire_data.content = NULL; + acquire_data.data = data; + update_widget_geometry(&acquire_data); + data->is.field.widget_overlay_loaded = 1; +} + +static void __widget_resize(Evas_Object *widget, Evas_Coord w, Evas_Coord h) +{ + struct widget_data *data; + widget_size_type_e type; + bool need_of_touch_effect = false; + bool need_of_mouse_event = false; + + data = evas_object_smart_data_get(widget); + if (!data) { + ErrPrint("Invalid object\n"); + return; + } + + if (data->state != WIDGET_DATA_CREATED) { + ErrPrint("Invalid widget data: %p\n", data); + return; + } + + type = find_size_type(data, w, h); + if (type == WIDGET_SIZE_TYPE_UNKNOWN) { + ErrPrint("Invalid size: %dx%d\n", w, h); + //return; + } else if (s_info.conf.field.use_fixed_size) { + if (widget_service_get_size(type, &w, &h) < 0) { + ErrPrint("Failed to get box size\n"); + } + } + + if (!widget_viewer_is_created_by_user(data->handle)) { + /** + * Viewer should not be able to resize the box + */ + ErrPrint("System created Widget is not able to be resized (%s)\n", widget_viewer_get_pkgname(data->handle)); + + /* But update its size by handle's size */ + widget_viewer_get_size_type(data->handle, &data->size_type); + + if (data->size_type == WIDGET_SIZE_TYPE_UNKNOWN || widget_service_get_size(data->size_type, &data->widget_width, &data->widget_height)) { + ErrPrint("Unable to get default size from handle\n"); + /* + * In this case, just depends on user's request. + * Because, there is no other information which we can use. + */ + data->size_type = type; + data->widget_width = w; + data->widget_height = h; + } + } else { + data->widget_width = w; + data->widget_height = h; + data->size_type = type; + } + + if (data->is.field.faulted) { + evas_object_resize(data->widget_layout, data->widget_width, data->widget_height); + ErrPrint("Faulted widget, skip resizing (%s)\n", data->widget_id); + return; + } + + if (!data->handle) { + struct acquire_data acquire_data = { + .data = data, + }; + DbgPrint("Create new handle: %dx%d, (%s, %s), %s/%s\n", data->widget_width, data->widget_height, + data->widget_id, data->content, + data->cluster, data->category); + if (widget_viewer_activate_faulted_widget(data->widget_id, NULL, NULL) < 0) { + ErrPrint("Activate: %s\n", data->widget_id); + } + data->is.field.created = 0; + data->is.field.send_delete = 1; + update_widget_geometry(&acquire_data); + + data->handle = widget_viewer_add_widget(data->widget_id, data->content, + data->cluster, data->category, + data->period, type, + __widget_created_cb, widget_ref(data)); + if (!data->handle) { + ErrPrint("Failed to send add request\n"); + DbgPrint("Unref %p %s\n", data, data->widget_id); + widget_unref(data); + return; + } + + DbgPrint("Added handle: %p (%p)\n", data->handle, data); + widget_viewer_set_data(data->handle, widget); + __widget_overlay_loading(data); + widget_service_get_need_of_touch_effect(data->widget_id, type, (bool*)&need_of_touch_effect); + data->is.field.touch_effect = need_of_touch_effect; + widget_service_get_need_of_mouse_event(data->widget_id, type, (bool*)&need_of_mouse_event); + data->is.field.mouse_event = need_of_mouse_event; + } else { + int ret; + + DbgPrint("Resize to %dx%d\n", w, h); + + if (type > 0 && type != WIDGET_SIZE_TYPE_UNKNOWN) { + ret = widget_viewer_resize_widget(data->handle, type, __widget_resize_cb, widget_ref(data)); + } else { + ret = WIDGET_ERROR_INVALID_PARAMETER; + /* This will be decreased soon ... */ + widget_ref(data); + } + + evas_object_resize(data->widget_layout, data->widget_width, data->widget_height); + if (ret == WIDGET_ERROR_ALREADY_EXIST) { + DbgPrint("Same size\n"); + widget_unref(data); + } else if (ret == WIDGET_ERROR_NONE) { + DbgPrint("Resize request is successfully sent\n"); + widget_service_get_need_of_touch_effect(data->widget_id, type, (bool*)&need_of_touch_effect); + data->is.field.touch_effect = need_of_touch_effect; + widget_service_get_need_of_mouse_event(data->widget_id, type, (bool*)&need_of_mouse_event); + data->is.field.mouse_event = need_of_mouse_event; + } else { + widget_unref(data); + } + } +} + +static void __widget_show(Evas_Object *widget) +{ + struct widget_data *data; + + data = evas_object_smart_data_get(widget); + if (!data) { + ErrPrint("Invalid object\n"); + return; + } + + if (data->state != WIDGET_DATA_CREATED) { + ErrPrint("Invalid widget data: %p\n", data); + return; + } + + evas_object_show(data->stage); + evas_object_show(data->widget_layout); + + if (!s_info.conf.field.manual_pause_resume) { + update_visibility(data); + } +} + +static void __widget_hide(Evas_Object *widget) +{ + struct widget_data *data; + + data = evas_object_smart_data_get(widget); + if (!data) { + ErrPrint("Invalid object\n"); + return; + } + + if (data->state != WIDGET_DATA_CREATED) { + ErrPrint("Invalid widget data: %p\n", data); + return; + } + + evas_object_hide(data->stage); + evas_object_hide(data->widget_layout); + + if (!s_info.conf.field.manual_pause_resume) { + update_visibility(data); + } +} + +static void __widget_color_set(Evas_Object *widget, int r, int g, int b, int a) +{ + struct widget_data *data; + + data = evas_object_smart_data_get(widget); + if (!data) { + ErrPrint("Invalid object\n"); + return; + } + + if (data->state != WIDGET_DATA_CREATED) { + ErrPrint("Invalid widget data: %p\n", data); + return; + } + + evas_object_color_set(data->stage, r, g, b, a); +} + +static void __widget_clip_set(Evas_Object *widget, Evas_Object *clip) +{ + struct widget_data *data; + + data = evas_object_smart_data_get(widget); + if (!data) { + ErrPrint("Invalid object\n"); + return; + } + + if (data->state != WIDGET_DATA_CREATED) { + ErrPrint("Invalid widget data: %p\n", data); + return; + } + + evas_object_clip_set(data->stage, clip); +} + +static void __widget_clip_unset(Evas_Object *widget) +{ + struct widget_data *data; + + data = evas_object_smart_data_get(widget); + if (!data) { + ErrPrint("Invalid object\n"); + return; + } + + if (data->state != WIDGET_DATA_CREATED) { + ErrPrint("Invalid widget data: %p\n", data); + return; + } + + evas_object_clip_unset(data->stage); +} + +/*! + * This must be called before update_gbar_geometry + */ +static void update_stage_geometry(struct acquire_data *acquire_data) +{ + Evas_Coord widget_x, widget_y, widget_w, widget_h; + Evas_Coord stage_w, stage_h; + + evas_object_geometry_get(acquire_data->data->widget_layout, &widget_x, &widget_y, &widget_w, &widget_h); + + const int delta_y_top = (acquire_data->h - widget_y); + const int delta_y_bottom = (acquire_data->h - (s_info.screen_height - widget_y - widget_h)); + + stage_w = widget_w > acquire_data->w ? widget_w : acquire_data->w; + stage_h = widget_h + acquire_data->h;// - delta_y_top; + + if(delta_y_top >= delta_y_bottom) + { + evas_object_move(acquire_data->data->stage, 0, widget_y); + } + else + { + evas_object_move(acquire_data->data->stage, 0, widget_y - acquire_data->h); + } + + evas_object_resize(acquire_data->data->stage, stage_w, stage_h); +} + +static void update_gbar_geometry(struct acquire_data *acquire_data) +{ + Evas_Coord widget_x, widget_y, widget_w, widget_h; + + evas_object_geometry_get(acquire_data->data->widget_layout, &widget_x, &widget_y, &widget_w, &widget_h); + + //How much of the GBAR is outside the screen + const int delta_y_top = (acquire_data->h - widget_y) < 0 ? 0 : acquire_data->h - widget_y; + const int delta_y_bottom = (acquire_data->h - (s_info.screen_height - widget_y - widget_h)) < 0 ? 0 : (acquire_data->h - (s_info.screen_height - widget_y - widget_h)); + + //If more of the GBAR is outside the top side draw at the bottom, otherwise draw at the top + if(delta_y_top >= delta_y_bottom) + { + evas_object_move(acquire_data->data->gbar_layout, 0, widget_y + widget_h - delta_y_bottom); + effect_resize(acquire_data->data->gbar_layout, acquire_data->w, acquire_data->h, EFFECT_HEIGHT); + } + else + { + evas_object_move(acquire_data->data->gbar_layout, 0, widget_y + delta_y_top); + effect_resize(acquire_data->data->gbar_layout, acquire_data->w, acquire_data->h, EFFECT_HEIGHT|EFFECT_MOVE); + } +} + +static void update_widget_geometry(struct acquire_data *acquire_data) +{ + Evas_Coord widget_x, widget_y, widget_w, widget_h; + Evas_Coord stage_w, stage_h; + struct widget_data *data = acquire_data->data; + + evas_object_resize(data->widget_layout, data->widget_width, data->widget_height); + evas_object_geometry_get(data->widget_layout, &widget_x, &widget_y, &widget_w, &widget_h); + + if (data->gbar_layout) { + Evas_Coord gbar_x, gbar_y, gbar_w, gbar_h; + + evas_object_geometry_get(data->gbar_layout, &gbar_x, &gbar_y, &gbar_w, &gbar_h); + if (widget_y + widget_h + gbar_h > s_info.screen_height) { + evas_object_move(data->gbar_layout, 0, widget_y - gbar_h); + evas_object_move(data->stage, 0, widget_y - gbar_h); + } else { + evas_object_move(data->gbar_layout, 0, widget_y + widget_h); + evas_object_move(data->stage, 0, widget_y); + } + + stage_w = gbar_w > widget_w ? gbar_w : widget_w; + stage_h = widget_h + gbar_h; + } else { + stage_w = widget_w; + if (s_info.conf.field.support_gbar) { + stage_h = widget_h + 100; /* Reserve 100 px for effect */ + } else { + stage_h = widget_h; + } + + evas_object_move(data->stage, widget_x, widget_y); + } + + evas_object_resize(data->stage, stage_w, stage_h); +} + +static void __widget_update_image_object(struct widget_data *data, Evas_Object *widget_content, int w, int h) +{ + Evas_Object *front_image; + + front_image = elm_object_part_content_get(widget_content, "front,content"); + if (front_image) { + elm_image_file_set(front_image, widget_viewer_get_filename(data->handle), NULL); + } else { + ErrPrint("Image object not found\n"); + } +} + +static void __widget_update_buffer_object(struct widget_data *data, Evas_Object *widget_content, int w, int h) +{ + struct acquire_data acquire_data = { + .w = w, + .h = h, + .content = widget_content, + .data = data, + }; + + if (data->widget_fb) { + widget_viewer_release_buffer(data->widget_fb); + data->widget_fb = NULL; + } + + data->widget_fb = widget_viewer_acquire_buffer(data->handle, 0); + if (!data->widget_fb) { + ErrPrint("Failed to get fb\n"); + return; + } + + evas_object_image_size_set(widget_content, w, h); + + if (widget_viewer_acquire_buffer_lock(data->handle, 0) < 0) { + ErrPrint("Failed to acquire lock\n"); + } + evas_object_image_data_copy_set(widget_content, data->widget_fb); + if (widget_viewer_release_buffer_lock(data->handle, 0) < 0) { + ErrPrint("Failed to release lock\n"); + } + + evas_object_image_fill_set(widget_content, 0, 0, w, h); + evas_object_image_pixels_dirty_set(widget_content, EINA_TRUE); + evas_object_image_data_update_add(widget_content, 0, 0, w, h); + update_widget_geometry(&acquire_data); +} + +static void __widget_update_text_object(struct widget_data *data, Evas_Object *widget_content, int w, int h) +{ + struct acquire_data acquire_data = { + .w = w, + .h = h, + .content = widget_content, + .data = data, + }; + + update_widget_geometry(&acquire_data); +} + +static void __widget_event_extra_info_updated(struct widget_data *data) +{ + struct widget_evas_event_info info; + const char *content_info; + char *tmp; + + if (data->is.field.deleted) { + DbgPrint("Box is %s, ignore update\n", data->is.field.deleted ? "deleted" : "faulted"); + return; + } + + content_info = widget_viewer_get_content_string(data->handle); + if (content_info && data->content) { + if (!strcmp(content_info, data->content)) { + /* Nothing chnaged */ + } else { + tmp = strdup(content_info); + if (!tmp) { + ErrPrint("Heap: %d\n", errno); + return; + } + + free(data->content); + data->content = tmp; + } + } else if (content_info) { + tmp = strdup(content_info); + if (!tmp) { + ErrPrint("Heap: %d\n", errno); + return; + } + data->content = tmp; + } else if (data->content) { + free(data->content); + data->content = NULL; + } else { + /* Nothing changed */ + } + + info.widget_app_id = data->widget_id; + info.event = WIDGET_EVENT_EXTRA_INFO_UPDATED; + info.error = WIDGET_ERROR_NONE; + smart_callback_call(data, WIDGET_SMART_SIGNAL_EXTRA_INFO_UPDATED, &info); +} + +/*! + * Event handlers + */ +static void __widget_event_widget_updated(struct widget_data *data) +{ + Evas_Object *widget_viewer_get_content_string; + widget_size_type_e type; + widget_type_e widget_type; + int w, h; + struct widget_evas_event_info info; + + data->is.field.widget_dirty = 0; + + if (data->is.field.deleted) { + DbgPrint("Box is %s, ignore update\n", data->is.field.deleted ? "deleted" : "faulted"); + return; + } + + widget_viewer_get_content_string = elm_object_part_content_get(data->widget_layout, "widget,content"); + if (!widget_viewer_get_content_string) { + ErrPrint("Failed to get content object\n"); + return; + } + + widget_viewer_get_size_type(data->handle, &type); + if (type < 0 || type == WIDGET_SIZE_TYPE_UNKNOWN) { + ErrPrint("Size is not valid %X\n", type); + return; + } + + w = data->widget_width; + h = data->widget_height; + + widget_viewer_get_type(data->handle, 0, &widget_type); + + switch (widget_type) { + case WIDGET_CONTENT_TYPE_IMAGE: + __widget_update_image_object(data, widget_viewer_get_content_string, w, h); + __widget_overlay_disable(data, 0); + break; + case WIDGET_CONTENT_TYPE_RESOURCE_ID: + if (!s_info.conf.field.force_to_buffer) { + __widget_update_pixmap_object(data, widget_viewer_get_content_string, w, h); + break; + } + case WIDGET_CONTENT_TYPE_BUFFER: + __widget_update_buffer_object(data, widget_viewer_get_content_string, w, h); + __widget_overlay_disable(data, 0); + break; + case WIDGET_CONTENT_TYPE_TEXT: + __widget_update_text_object(data, widget_viewer_get_content_string, w, h); + __widget_overlay_disable(data, 0); + break; + case WIDGET_CONTENT_TYPE_UIFW: + break; + case WIDGET_CONTENT_TYPE_INVALID: + default: + break; + } + + info.widget_app_id = data->widget_id; + info.event = WIDGET_EVENT_WIDGET_UPDATED; + info.error = WIDGET_ERROR_NONE; + smart_callback_call(data, WIDGET_SMART_SIGNAL_UPDATED, &info); +} + +static void gbar_update_buffer_object(struct widget_data *data, Evas_Object *gbar_content, int w, int h) +{ + struct acquire_data acquire_data = { + .data = data, + .content = gbar_content, + .w = w, + .h = h, + }; + + if (data->gbar_fb) { + widget_viewer_release_buffer(data->gbar_fb); + data->gbar_fb = NULL; + } else { + // This is first time + gbar_overlay_disable(data); + } + + data->gbar_fb = widget_viewer_acquire_buffer(data->handle, 1); + if (!data->gbar_fb) { + ErrPrint("Failed to get fb\n"); + return; + } + + evas_object_image_size_set(gbar_content, w, h); + + if (widget_viewer_acquire_buffer_lock(data->handle, 1) < 0) { + ErrPrint("Failed to acquire lock\n"); + } + evas_object_image_data_copy_set(gbar_content, data->gbar_fb); + if (widget_viewer_release_buffer_lock(data->handle, 1) < 0) { + ErrPrint("Failed to release lock\n"); + } + + evas_object_image_fill_set(gbar_content, 0, 0, w, h); + evas_object_image_pixels_dirty_set(gbar_content, EINA_TRUE); + evas_object_image_data_update_add(gbar_content, 0, 0, w, h); + + update_stage_geometry(&acquire_data); + update_gbar_geometry(&acquire_data); +} + +static void gbar_update_text_object(struct widget_data *data, Evas_Object *gbar_content, int w, int h) +{ + struct acquire_data acquire_data = { + .data = data, + .content = gbar_content, + .w = w, + .h = h, + }; + + ErrPrint("Text type is updated\n"); + gbar_overlay_disable(data); + + update_stage_geometry(&acquire_data); + update_gbar_geometry(&acquire_data); +} + +static void update_gbar_pixmap(Evas_Object *content, int w, int h) +{ + evas_object_image_pixels_dirty_set(content, EINA_TRUE); + evas_object_image_data_update_add(content, 0, 0, w, h); + evas_object_show(content); +} + +static void acquire_gbar_pixmap_cb(struct widget *handle, int pixmap, void *cbdata) +{ + struct acquire_data *acquire_data = cbdata; + struct widget_data *data = acquire_data->data; + Evas_Native_Surface *old_surface; + Evas_Native_Surface surface; + + data->is.field.gbar_pixmap_acquire_requested = 0; + + if (pixmap == 0) { + ErrPrint("Failed to acquire pixmap\n"); + DbgPrint("Unref %p %s\n", data, data->widget_id); + widget_unref(data); + if (!s_info.conf.field.skip_acquire) { + free(acquire_data); + } + return; + } + + evas_object_image_size_set(acquire_data->content, acquire_data->w, acquire_data->h); + evas_object_image_fill_set(acquire_data->content, 0, 0, acquire_data->w, acquire_data->h); + + surface.version = EVAS_NATIVE_SURFACE_VERSION; + surface.type = EVAS_NATIVE_SURFACE_X11; + surface.data.x11.pixmap = (unsigned int)pixmap; + + old_surface = evas_object_image_native_surface_get(acquire_data->content); + if (!old_surface) { + gbar_overlay_disable(data); + surface.data.x11.visual = ecore_x_default_visual_get(ecore_x_display_get(), ecore_x_default_screen_get()); + evas_object_image_native_surface_set(acquire_data->content, &surface); + } else { + unsigned int old_pixmap = 0u; + old_pixmap = old_surface->data.x11.pixmap; + surface.data.x11.visual = old_surface->data.x11.visual; + evas_object_image_native_surface_set(acquire_data->content, &surface); + + if (old_pixmap) { + if (!s_info.conf.field.skip_acquire) { + widget_viewer_release_resource_id(data->handle, 1, old_pixmap); + } + } + } + + data->gbar_pixmap = (unsigned int)pixmap; + + append_gbar_dirty_object_list(data, WIDGET_KEEP_BUFFER); + update_stage_geometry(acquire_data); + update_gbar_geometry(acquire_data); + + if (!s_info.conf.field.skip_acquire) { + free(acquire_data); + } + DbgPrint("Unref %p %s\n", data, data->widget_id); + widget_unref(data); +} + +static void gbar_update_pixmap_object(struct widget_data *data, Evas_Object *gbar_content, int w, int h) +{ + struct acquire_data *acquire_data; + int ret; + unsigned int resource_id; + + if (data->gbar_latest_idx == WIDGET_PRIMARY_BUFFER) { + widget_viewer_get_resource_id(data->handle, 1, &resource_id); + if (data->gbar_pixmap == resource_id) { + int ow; + int oh; + + effect_size_get(gbar_content, &ow, &oh); + + if (data->gbar_extra) { + replace_pixmap(NULL, 1, gbar_content, data->gbar_pixmap); + } + update_gbar_pixmap(gbar_content, w, h); + + if (ow != w || oh != h) { + struct acquire_data adata = { + .data = data, + .content = gbar_content, + .w = w, + .h = h, + }; + + update_stage_geometry(&adata); + } + return; + } + + if (s_info.conf.field.skip_acquire && resource_id != 0) { + struct acquire_data local_acquire_data = { + .data = widget_ref(data), + .content = gbar_content, + .w = w, + .h = h, + }; + + acquire_gbar_pixmap_cb(data->handle, resource_id, &local_acquire_data); + return; + } + + if (data->is.field.gbar_pixmap_acquire_requested) { + return; + } + + acquire_data = malloc(sizeof(*acquire_data)); + if (!acquire_data) { + ErrPrint("Heap: %d\n", errno); + return; + } + + acquire_data->content = gbar_content; + acquire_data->w = w; + acquire_data->h = h; + acquire_data->data = widget_ref(data); + + ret = widget_viewer_acquire_resource_id(data->handle, 1, acquire_gbar_pixmap_cb, acquire_data); + if (ret != WIDGET_ERROR_NONE) { + ErrPrint("Failed to acquire gbar resource id\n"); + free(acquire_data); + DbgPrint("Unref %p %s\n", data, data->widget_id); + widget_unref(data); + } else { + data->is.field.gbar_pixmap_acquire_requested = 1; + } + } else { + int ow; + int oh; + + if (!data->gbar_extra) { + DbgPrint("Extra GBar is not prepared yet\n"); + return; + } + + effect_size_get(gbar_content, &ow, &oh); + + replace_pixmap(NULL, 1, gbar_content, data->gbar_extra[data->gbar_latest_idx]); + update_gbar_pixmap(gbar_content, w, h); + + if (ow != w || oh != h) { + struct acquire_data adata = { + .data = data, + .content = gbar_content, + .w = w, + .h = h, + }; + + update_stage_geometry(&adata); + } + } +} + +static void __widget_event_gbar_updated(struct widget_data *data) +{ + Evas_Object *gbar_content; + int w, h; + widget_type_e widget_type; + + data->is.field.gbar_dirty = 0; + + if (data->is.field.deleted) { + DbgPrint("Box is deleted, ignore update\n"); + return; + } + + gbar_content = elm_object_part_content_get(data->gbar_layout, "gbar,content"); + if (!gbar_content) { + ErrPrint("Failed to get content object\n"); + return; + } + + if (widget_viewer_get_glance_bar_size(data->handle, &w, &h) != WIDGET_ERROR_NONE) { + ErrPrint("Failed to get gbar_size\n"); + w = 0; + h = 0; + } + + widget_viewer_get_type(data->handle, 1, &widget_type); + + switch (widget_type) { + case WIDGET_CONTENT_TYPE_RESOURCE_ID: + if (!s_info.conf.field.force_to_buffer) { + gbar_update_pixmap_object(data, gbar_content, w, h); + break; + } + case WIDGET_CONTENT_TYPE_BUFFER: + gbar_update_buffer_object(data, gbar_content, w, h); + break; + case WIDGET_CONTENT_TYPE_TEXT: + gbar_update_text_object(data, gbar_content, w, h); + break; + case WIDGET_CONTENT_TYPE_UIFW: + break; + case WIDGET_CONTENT_TYPE_INVALID: + default: + ErrPrint("Invalid pd type\n"); + break; + } +} + +static void __widget_event_deleted(struct widget_data *data) +{ + struct widget_evas_event_info info; + + if (data->widget_fb) { + widget_viewer_release_buffer(data->widget_fb); + data->widget_fb = NULL; + } + + if (data->gbar_fb) { + widget_viewer_release_buffer(data->gbar_fb); + data->gbar_fb = NULL; + } + + if (data->widget_pixmap) { + replace_widget_pixmap_with_image(data); + } + + if (data->gbar_pixmap) { + replace_gbar_pixmap_with_image(data); + } + + DbgPrint("widget is deleted: %p (emit signal)\n", data); + data->is.field.send_delete = 0; + info.widget_app_id = data->widget_id; + info.event = WIDGET_EVENT_DELETED; + info.error = data->is.field.faulted ? WIDGET_ERROR_FAULT : WIDGET_ERROR_NONE; + + /** + * Even if the widget object tries to be deleted from WIDGET_DELETED event callback, + * widget data should not be released while processing RAW_DELETE event handling + */ + widget_ref(data); + + smart_callback_call(data, WIDGET_SMART_SIGNAL_WIDGET_DELETED, &info); + DbgPrint("Invoke raw delete %s\n", data->widget_id); + (void)invoke_raw_event_callback(WIDGET_VIEWER_EVAS_RAW_DELETE, data->widget_id, data->widget, info.error); + + remove_widget_dirty_object_list(data); + remove_gbar_dirty_object_list(data); /* For the safety */ + + data->handle = NULL; + + /** + * All event handler is handled correctly, + * Then decrease the refcnt of it. + */ + widget_unref(data); +} + +static void __widget_event_request_close_gbar(struct widget_data *data) +{ + int ret; + + ret = widget_viewer_destroy_glance_bar(data->handle, __widget_destroy_gbar_cb, widget_ref(data)); + if (ret < 0) { + ErrPrint("Failed to close a GBAR: %x\n", ret); + DbgPrint("Unref %p %s\n", data, data->widget_id); + widget_unref(data); + } +} + +static void __widget_event_group_changed(struct widget_data *data) +{ + DbgPrint("Group is changed\n"); +} + +static void __widget_event_pinup_changed(struct widget_data *data) +{ + DbgPrint("Pinup is changed\n"); +} + +static void __widget_event_period_changed(struct widget_data *data) +{ + struct widget_evas_event_info info; + + widget_viewer_get_period(data->handle, &(data->period)); + DbgPrint("Update period is changed to (%lf)\n", data->period); + + info.widget_app_id = data->widget_id; + info.event = WIDGET_EVENT_PERIOD_CHANGED; + info.error = WIDGET_ERROR_NONE; + smart_callback_call(data, WIDGET_SMART_SIGNAL_PERIOD_CHANGED, &info); +} + +static void __widget_event_widget_size_changed(struct widget_data *data) +{ + DbgPrint("widget LB size is changed\n"); +} + +static void __widget_event_gbar_size_changed(struct widget_data *data) +{ + DbgPrint("widget GBAR size is changed\n"); +} + +static void __widget_event_gbar_created(struct widget_data *data) +{ + DbgPrint("widget GBAR is created\n"); +} + +static void __widget_event_gbar_destroyed(struct widget_data *data) +{ + DbgPrint("widget GBAR is destroyed\n"); + remove_gbar_dirty_object_list(data); +} + +static void __widget_event_hold_scroll(struct widget_data *data) +{ + struct widget_evas_event_info info; + DbgPrint("widget hold scroll\n"); + + info.widget_app_id = data->widget_id; + info.event = WIDGET_EVENT_HOLD_SCROLL; + info.error = WIDGET_ERROR_NONE; + smart_callback_call(data, WIDGET_SMART_SIGNAL_CONTROL_SCROLLER, &info); +} + +static void __widget_event_release_scroll(struct widget_data *data) +{ + struct widget_evas_event_info info; + DbgPrint("widget release scroll\n"); + + info.widget_app_id = data->widget_id; + info.event = WIDGET_EVENT_RELEASE_SCROLL; + info.error = WIDGET_ERROR_NONE; + smart_callback_call(data, WIDGET_SMART_SIGNAL_CONTROL_SCROLLER, &info); +} + +static void __widget_event_widget_update_begin(struct widget_data *data) +{ + DbgPrint("WIDGET Update Begin\n"); +} + +static void __widget_event_widget_update_end(struct widget_data *data) +{ + DbgPrint("WIDGET Update End\n"); +} + +static void __widget_event_gbar_update_begin(struct widget_data *data) +{ + DbgPrint("GBAR Update Begin\n"); +} + +static void __widget_event_gbar_update_end(struct widget_data *data) +{ + DbgPrint("GBAR Update End\n"); +} + +static void __widget_event_update_mode_changed(struct widget_data *data) +{ + DbgPrint("Update mode changed\n"); +} + +static void __widget_event_ignored(struct widget_data *data) +{ + DbgPrint("Request is ignored\n"); +} + +static Evas_Object *create_widget_object(struct widget *handle) +{ + struct widget_data *data; + const char *cluster; + const char *sub_cluster; + Evas_Object *widget; + double period; + + if (widget_viewer_get_group(handle, &cluster, &sub_cluster) != WIDGET_ERROR_NONE) { + ErrPrint("Unable to get the group info\n"); + } + + /** + * \TODO: Create a widget evas object + */ + + widget_viewer_get_period(handle, &period); + + widget = widget_viewer_evas_add_widget(s_info.win, + widget_viewer_get_pkgname(handle), widget_viewer_get_content_string(handle), + period); + + data = evas_object_smart_data_get(widget); + if (data) { + widget_size_type_e type; + int w = 0; + int h = 0; + + data->handle = handle; + + widget_viewer_get_size_type(handle, &type); + widget_service_get_size(type, &w, &h); + DbgPrint("Size: %dx%d\n", w, h); + evas_object_resize(widget, w, h); + } + + return widget; +} + +static inline int handle_subscribed_group(struct widget *handle) +{ + const char *cluster = NULL; + const char *sub_cluster = NULL; + Eina_List *l; + struct subscribe_group *group; + + if (widget_viewer_get_group(handle, &cluster, &sub_cluster) != WIDGET_ERROR_NONE) { + return WIDGET_ERROR_FAULT; + } + + if (!cluster || !sub_cluster) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + EINA_LIST_FOREACH(s_info.subscribed_group_list, l, group) { + if (!strcasecmp(group->cluster, cluster) && !strcasecmp(group->sub_cluster, sub_cluster)) { + int nr; + Evas_Object *widget; + struct widget_data *temp_widget_data = NULL; + + DbgPrint("Subscribed Group: (%s)(%s)\n", cluster, sub_cluster); + + /* Subscribed object, Create this */ + widget = create_widget_object(handle); + if (!widget) { + ErrPrint("Failed to create a widget object\n"); + (void)widget_viewer_delete_widget(handle, WIDGET_DELETE_PERMANENTLY, NULL, NULL); + return WIDGET_ERROR_FAULT; + } + + widget_viewer_set_data(handle, widget); + + /* Emit RAW_CREATE event */ + nr = invoke_raw_event_callback(WIDGET_VIEWER_EVAS_RAW_CREATE, widget_viewer_get_pkgname(handle), widget, WIDGET_ERROR_NONE); + + if ( (temp_widget_data = get_smart_data(widget)) == NULL) { + ErrPrint("Failed to get widget data\n"); + (void)widget_viewer_delete_widget(handle, WIDGET_DELETE_PERMANENTLY, NULL, NULL); + return WIDGET_ERROR_FAULT; + } + + if (nr <= 0 || widget_system_created(handle, temp_widget_data) != WIDGET_ERROR_NONE) { + /* + * Deleting evas object will invoke delete callback. + * Then it will invoke the RAW_DELETE event and execute the proper procedures for deleting object + */ + widget_viewer_evas_set_permanent_delete(widget, EINA_TRUE); + evas_object_del(widget); + } + + return WIDGET_ERROR_NONE; + } + } + + return WIDGET_ERROR_NOT_EXIST; +} + +static inline int handle_subscribed_category(struct widget *handle) +{ + char *category; + Eina_List *l; + struct subscribe_category *info; + + category = widget_service_get_category(widget_viewer_get_pkgname(handle)); + if (!category) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + EINA_LIST_FOREACH(s_info.subscribed_category_list, l, info) { + if (!strcmp(category, info->category)) { + int nr; + Evas_Object *widget; + struct widget_data *temp_widget_data; + + DbgPrint("Subscribed Category: (%s)(%s)\n", category, info->category); + + widget = create_widget_object(handle); + if (!widget) { + ErrPrint("Failed to create a widget object\n"); + (void)widget_viewer_delete_widget(handle, WIDGET_DELETE_PERMANENTLY, NULL, NULL); + free(category); + return WIDGET_ERROR_FAULT; + } + + widget_viewer_set_data(handle, widget); + + /* Subscribed object, Create this */ + nr = invoke_raw_event_callback(WIDGET_VIEWER_EVAS_RAW_CREATE, widget_viewer_get_pkgname(handle), widget, WIDGET_ERROR_NONE); + + temp_widget_data = get_smart_data(widget); + if (!temp_widget_data) { + ErrPrint("Failed to get widget data\n"); + (void)widget_viewer_delete_widget(handle, WIDGET_DELETE_PERMANENTLY, NULL, NULL); + evas_object_del(widget); + free(category); + return WIDGET_ERROR_FAULT; + } + + if (nr <= 0 || widget_system_created(handle, temp_widget_data) != WIDGET_ERROR_NONE) { + /* Delete widget, if no one cares it */ + DbgPrint("No one cares\n"); + widget_viewer_evas_set_permanent_delete(widget, EINA_TRUE); + evas_object_del(widget); + } + + free(category); + return WIDGET_ERROR_NONE; + } + } + + free(category); + return WIDGET_ERROR_NOT_EXIST; +} + +static int widget_event_handler(struct widget *handle, enum widget_event_type event, void *cbdata) +{ + Evas_Object *widget; + struct widget_data *data; + int idx; + unsigned int resource_id; + int status; + + widget = widget_viewer_get_data(handle); + if (widget) { + data = get_smart_data(widget); + } else { + data = NULL; + DbgPrint("widget Object is not exists, create it?\n"); + } + + if (!widget || !data || data->is.field.deleted) { + widget_viewer_set_data(handle, NULL); + + if (event == WIDGET_EVENT_CREATED) { + if (handle_subscribed_group(handle) == WIDGET_ERROR_NONE) { + return 0; + } + + if (handle_subscribed_category(handle) == WIDGET_ERROR_NONE) { + return 0; + } + + DbgPrint("System created widget is not supported\n"); + (void)widget_viewer_delete_widget(handle, WIDGET_DELETE_PERMANENTLY, NULL, NULL); + } else { + ErrPrint("Failed to get smart data\n"); + } + + return 0; + } + + switch ((int)event) { + case WIDGET_EVENT_WIDGET_EXTRA_BUFFER_CREATED: + widget_viewer_get_affected_extra_buffer(handle, 0, &idx, &resource_id); + DbgPrint("Extra buffer created for WIDGET: %d (%u)\n", idx, resource_id); + + status = widget_viewer_acquire_extra_resource_id(handle, 0, idx, acquire_widget_extra_resource_cb, data); + if (status < 0) { + ErrPrint("Failed to acquire resource: %u (0x%X)\n", resource_id, status); + break; + } + + if (!data->widget_extra) { + data->widget_extra = calloc(widget_viewer_get_option(WIDGET_OPTION_EXTRA_BUFFER_CNT), sizeof(*data->widget_extra)); + if (!data->widget_extra) { + ErrPrint("calloc: %d\n", errno); + } + } + + data->widget_extra[idx] = resource_id; + data->widget_extra_cnt++; + break; + case WIDGET_EVENT_WIDGET_EXTRA_BUFFER_DESTROYED: + widget_viewer_get_affected_extra_buffer(handle, 0, &idx, &resource_id); + DbgPrint("Extra buffer destroyed for WIDGET: %d (%u)\n", idx, resource_id); + if (data->widget_extra[idx] != resource_id) { + DbgPrint("Resource Id mismatched\n"); + if (data->widget_extra[idx] == 0u) { + DbgPrint("Not acquired resourced\n"); + break; + } + } + + data->widget_extra[idx] = 0u; + data->widget_extra_cnt--; + if (!data->widget_extra_cnt) { + DbgPrint("Release widget array\n"); + free(data->widget_extra); + data->widget_extra = NULL; + } + + if (!s_info.conf.field.skip_acquire) { + if (widget_viewer_release_resource_id(handle, 0, resource_id) < 0) { + ErrPrint("Failed to release resource: %u\n", resource_id); + } + } + break; + case WIDGET_EVENT_GBAR_EXTRA_BUFFER_CREATED: + widget_viewer_get_affected_extra_buffer(handle, 1, &idx, &resource_id); + DbgPrint("Extra buffer destroyed for GBAR: %d (%u)\n", idx, resource_id); + if (!data->gbar_extra) { + data->gbar_extra = calloc(widget_viewer_get_option(WIDGET_OPTION_EXTRA_BUFFER_CNT), sizeof(*data->gbar_extra)); + if (!data->gbar_extra) { + ErrPrint("calloc: %d\n", errno); + break; + } + } + + data->gbar_extra[idx] = resource_id; + data->gbar_extra_cnt++; + + if (widget_viewer_acquire_extra_resource_id(handle, 1, idx, acquire_gbar_extra_resource_cb, data) < 0) { + ErrPrint("Failed to acquire resource: %u\n", resource_id); + } + break; + case WIDGET_EVENT_GBAR_EXTRA_BUFFER_DESTROYED: + widget_viewer_get_affected_extra_buffer(handle, 1, &idx, &resource_id); + DbgPrint("Extra buffer destroyed for GBAR: %d (%u)\n", idx, resource_id); + if (data->gbar_extra[idx] != resource_id) { + DbgPrint("Resource Id mismatched\n"); + } + data->gbar_extra[idx] = 0u; + data->gbar_extra_cnt--; + if (!data->gbar_extra_cnt) { + DbgPrint("Release gbar array\n"); + free(data->gbar_extra); + data->gbar_extra = NULL; + } + + if (!s_info.conf.field.skip_acquire) { + if (widget_viewer_release_resource_id(handle, 1, resource_id) < 0) { + ErrPrint("Failed to release resource: %u\n", resource_id); + } + } + break; + case WIDGET_EVENT_WIDGET_EXTRA_UPDATED: + widget_viewer_get_affected_extra_buffer(handle, 0, &idx, &resource_id); + if (!data->widget_extra) { + ErrPrint("Extra buffer is not prepared yet\n"); + } else { + if (data->widget_extra[idx] != resource_id) { + ErrPrint("Resource ID mismatched\n"); + } + append_widget_dirty_object_list(data, idx); + } + break; + case WIDGET_EVENT_GBAR_EXTRA_UPDATED: + widget_viewer_get_affected_extra_buffer(handle, 1, &idx, &resource_id); + if (!data->gbar_extra) { + ErrPrint("Extra buffer is not prepared yet\n"); + } else { + if (data->gbar_extra[idx] != resource_id) { + ErrPrint("Resource ID mismatched\n"); + } + append_gbar_dirty_object_list(data, idx); + } + break; + case WIDGET_EVENT_WIDGET_UPDATED: + append_widget_dirty_object_list(data, WIDGET_PRIMARY_BUFFER); + break; + case WIDGET_EVENT_GBAR_UPDATED: + append_gbar_dirty_object_list(data, WIDGET_PRIMARY_BUFFER); + break; + case WIDGET_EVENT_EXTRA_INFO_UPDATED: + __widget_event_extra_info_updated(data); + break; + + case WIDGET_EVENT_DELETED: + __widget_event_deleted(data); + break; + + case WIDGET_EVENT_GROUP_CHANGED: + __widget_event_group_changed(data); + break; + case WIDGET_EVENT_PINUP_CHANGED: + __widget_event_pinup_changed(data); + break; + case WIDGET_EVENT_PERIOD_CHANGED: + __widget_event_period_changed(data); + break; + + case WIDGET_EVENT_WIDGET_SIZE_CHANGED: + __widget_event_widget_size_changed(data); + break; + case WIDGET_EVENT_GBAR_SIZE_CHANGED: + __widget_event_gbar_size_changed(data); + break; + + case WIDGET_EVENT_GBAR_CREATED: + __widget_event_gbar_created(data); + break; + case WIDGET_EVENT_GBAR_DESTROYED: + __widget_event_gbar_destroyed(data); + break; + + case WIDGET_EVENT_HOLD_SCROLL: + __widget_event_hold_scroll(data); + break; + case WIDGET_EVENT_RELEASE_SCROLL: + __widget_event_release_scroll(data); + break; + + case WIDGET_EVENT_WIDGET_UPDATE_BEGIN: + __widget_event_widget_update_begin(data); + break; + case WIDGET_EVENT_WIDGET_UPDATE_END: + __widget_event_widget_update_end(data); + break; + + case WIDGET_EVENT_GBAR_UPDATE_BEGIN: + __widget_event_gbar_update_begin(data); + break; + case WIDGET_EVENT_GBAR_UPDATE_END: + __widget_event_gbar_update_end(data); + break; + + case WIDGET_EVENT_UPDATE_MODE_CHANGED: + __widget_event_update_mode_changed(data); + break; + + case WIDGET_EVENT_REQUEST_CLOSE_GBAR: + __widget_event_request_close_gbar(data); + break; + + case WIDGET_EVENT_IGNORED: + __widget_event_ignored(data); + break; + default: + break; + } + + return 0; +} + +static int widget_fault_handler(enum widget_fault_type fault, const char *pkgname, const char *filename, const char *funcname, void *cbdata) +{ + Eina_List *l = NULL; + Evas_Object *widget; + struct widget_data *data; + struct widget_evas_event_info info; + + switch (fault) { + case WIDGET_FAULT_DEACTIVATED: + EINA_LIST_FOREACH(s_info.list, l, widget) { + data = get_smart_data(widget); + if (!data) { + continue; + } + + if (!strcmp(data->widget_id, pkgname)) { + DbgPrint("Faulted: %s (%p)\n", pkgname, data); + data->is.field.faulted = 1; + __widget_overlay_faulted(data); + info.error = WIDGET_ERROR_FAULT; + info.widget_app_id = data->widget_id; + info.event = WIDGET_FAULT_DEACTIVATED; + smart_callback_call(data, WIDGET_SMART_SIGNAL_WIDGET_FAULTED, &info); + } + } + break; + case WIDGET_FAULT_PROVIDER_DISCONNECTED: + EINA_LIST_FOREACH(s_info.list, l, widget) { + data = get_smart_data(widget); + if (!data) { + continue; + } + + if (!strcmp(data->widget_id, pkgname)) { + DbgPrint("Disconnected: %s (%p)\n", pkgname, data); + data->is.field.faulted = 1; + __widget_overlay_faulted(data); + info.error = WIDGET_ERROR_FAULT; + info.widget_app_id = data->widget_id; + info.event = WIDGET_FAULT_PROVIDER_DISCONNECTED; + smart_callback_call(data, WIDGET_SMART_SIGNAL_PROVIDER_DISCONNECTED, &info); + } + } + break; + default: + break; + } + return 0; +} + +EAPI int widget_viewer_evas_init(Evas_Object *win) +{ + int ret; + + ecore_x_window_size_get(0, &s_info.screen_width, &s_info.screen_height); + + s_info.conf.field.render_animator = 0; // By default, use render animator for updating + + ret = widget_viewer_init(ecore_x_display_get(), 1, 0.001f, 1); + if (ret < 0) { + return ret; + } + + ret = widget_viewer_add_event_handler(widget_event_handler, NULL); + if (ret != WIDGET_ERROR_NONE) { + ErrPrint("Failed to set handler\n"); + widget_viewer_fini(); + } else { + DbgPrint("Event handler registered\n"); + ret = widget_viewer_add_fault_handler(widget_fault_handler, NULL); + if (ret != WIDGET_ERROR_NONE) { + ErrPrint("Failed to set fault handler\n"); + widget_viewer_remove_event_handler(widget_event_handler); + widget_viewer_fini(); + } else { + DbgPrint("Fault handler is registered\n"); + s_info.initialized = 1; + widget_conf_init(); + widget_conf_load(); + } + } + + /* s_info.conf.field.force_to_buffer = force_to_buffer; */ + s_info.conf.field.force_to_buffer = 0; + s_info.win = win; + + return ret; +} + +EAPI int widget_viewer_evas_fini(void) +{ + if (s_info.initialized) { + widget_viewer_remove_event_handler(widget_event_handler); + widget_viewer_remove_fault_handler(widget_fault_handler); + widget_viewer_fini(); + widget_conf_reset(); + s_info.initialized = 0; + } + return 0; +} + +EAPI int widget_viewer_evas_notify_resumed_status_of_viewer(void) +{ + return widget_viewer_notify_resumed_status_of_viewer(); +} + +EAPI int widget_viewer_evas_notify_paused_status_of_viewer(void) +{ + return widget_viewer_notify_paused_status_of_viewer(); +} + +EAPI int widget_viewer_evas_notify_orientation_of_viewer(int orientation) +{ + return widget_viewer_notify_orientation_of_viewer(orientation); +} + +EAPI Evas_Object *widget_viewer_evas_add_widget(Evas_Object *parent, const char *widget_id, const char *content_info, double period) +{ + struct widget_data *data; + Evas_Object *widget; + char *_widget_id; + char *_content_info; + char *_cluster; + char *_category; + char *cluster = DEFAULT_CLUSTER; + char *category = DEFAULT_CATEGORY; + + if (!parent || !widget_id) { + return NULL; + } + + _cluster = strdup(cluster); + if (!_cluster) { + ErrPrint("Heap: %d\n", errno); + return NULL; + } + + _category = strdup(category); + if (!_category) { + ErrPrint("Heap: %d\n", errno); + free(_cluster); + return NULL; + } + + _widget_id = strdup(widget_id); + if (!_widget_id) { + ErrPrint("Heap: %d\n", errno); + free(_category); + free(_cluster); + return NULL; + } + + if (content_info) { + _content_info = strdup(content_info); + if (!_content_info) { + ErrPrint("Heap: %d\n", errno); + free(_widget_id); + free(_category); + free(_cluster); + return NULL; + } + } else { + _content_info = NULL; + } + + if (!s_info.smart) { + s_info.sc.add = __widget_add; + s_info.sc.del = __widget_del; + s_info.sc.move = __widget_move; + s_info.sc.resize = __widget_resize; + s_info.sc.show = __widget_show; + s_info.sc.hide = __widget_hide; + s_info.sc.color_set = __widget_color_set; + s_info.sc.clip_set = __widget_clip_set; + s_info.sc.clip_unset = __widget_clip_unset; + + s_info.smart = evas_smart_class_new(&s_info.sc); + } + + widget = evas_object_smart_add(evas_object_evas_get(parent), s_info.smart); + + data = evas_object_smart_data_get(widget); + if (data) { + data->parent = parent; + data->widget_id = _widget_id; + data->content = _content_info; + data->cluster = _cluster; + data->category = _category; + data->is.field.mouse_event = 0; + data->period = period; + + __widget_data_setup(data); + } else { + ErrPrint("Failed to get smart data\n"); + free(_widget_id); + free(_content_info); + free(_cluster); + free(_category); + } + + return widget; +} + +EAPI int widget_viewer_evas_set_view_port(Evas_Object *widget, int x, int y, int w, int h) +{ + struct widget_data *data; + + data = get_smart_data(widget); + if (!data) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + data->view_port.x = x; + data->view_port.y = y; + data->view_port.w = w; + data->view_port.h = h; + s_info.conf.field.user_view_port = 1; + return WIDGET_ERROR_NONE; +} + +EAPI int widget_viewer_evas_get_view_port(Evas_Object *widget, int *x, int *y, int *w, int *h) +{ + struct widget_data *data; + + data = get_smart_data(widget); + if (!data) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (x) { + *x = data->view_port.x; + } + + if (y) { + *y = data->view_port.y; + } + + if (w) { + *w = data->view_port.w; + } + + if (h) { + *h = data->view_port.h; + } + + return WIDGET_ERROR_NONE; +} + +EAPI int widget_viewer_evas_set_option(widget_evas_conf_e type, int value) +{ + switch ((int)type) { + case WIDGET_VIEWER_EVAS_SENSITIVE_MOVE: + s_info.conf.field.sensitive_move = value; + break; + case WIDGET_VIEWER_EVAS_EVENT_AUTO_FEED: + s_info.conf.field.auto_feed = value; + break; + case WIDGET_VIEWER_EVAS_EASY_MODE: + s_info.conf.field.easy_mode = value; + break; + case WIDGET_VIEWER_EVAS_USE_FIXED_SIZE: + s_info.conf.field.use_fixed_size = value; + break; + case WIDGET_VIEWER_EVAS_MANUAL_PAUSE_RESUME: + s_info.conf.field.manual_pause_resume = value; + break; + case WIDGET_VIEWER_EVAS_SHARED_CONTENT: + (void)widget_viewer_set_option(WIDGET_OPTION_SHARED_CONTENT, value); + break; + case WIDGET_VIEWER_EVAS_SUPPORT_GBAR: + s_info.conf.field.support_gbar = value; + break; + case WIDGET_VIEWER_EVAS_SCROLL_X: + s_info.conf.field.is_scroll_x = value; + break; + case WIDGET_VIEWER_EVAS_SCROLL_Y: + s_info.conf.field.is_scroll_y = value; + break; + case WIDGET_VIEWER_EVAS_DELAYED_RESUME: + s_info.conf.field.delayed_resume = value; + break; + case WIDGET_VIEWER_EVAS_AUTO_RENDER_SELECTION: + s_info.conf.field.auto_render_selector = value; + break; + case WIDGET_VIEWER_EVAS_DIRECT_UPDATE: + (void)widget_viewer_set_option(WIDGET_OPTION_DIRECT_UPDATE, !!value); + break; + case WIDGET_VIEWER_EVAS_USE_RENDER_ANIMATOR: + if (s_info.conf.field.auto_render_selector) { + DbgPrint("Auto selector enabled, this render_animator option will be changed automatically\n"); + } + + s_info.conf.field.render_animator = !!value; + DbgPrint("Turn %s render animator\n", s_info.conf.field.render_animator ? "on" : "off"); + break; + case WIDGET_VIEWER_EVAS_SKIP_ACQUIRE: + s_info.conf.field.skip_acquire = !!value; + DbgPrint("Turn %s skip-acquire option\n", s_info.conf.field.skip_acquire ? "on" : "off"); + break; + default: + break; + } + + return WIDGET_ERROR_NONE; +} + +EAPI int widget_viewer_evas_pause_widget(Evas_Object *widget) +{ + struct widget_data *data; + + data = get_smart_data(widget); + if (!data || !data->is.field.created || !data->handle) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (data->delayed_resume_timer) { + (void)ecore_timer_del(data->delayed_resume_timer); + data->delayed_resume_timer = NULL; + } + return widget_viewer_set_visibility(data->handle, WIDGET_HIDE_WITH_PAUSE); +} + +EAPI int widget_viewer_evas_resume_widget(Evas_Object *widget) +{ + struct widget_data *data; + + data = get_smart_data(widget); + if (!data || !data->is.field.created || !data->handle) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + if (data->delayed_resume_timer) { + (void)ecore_timer_del(data->delayed_resume_timer); + data->delayed_resume_timer = NULL; + } + return widget_viewer_set_visibility(data->handle, WIDGET_SHOW); +} + +EAPI int widget_viewer_evas_destroy_glance_bar(Evas_Object *widget) +{ + struct widget_data *data; + int ret; + + data = get_smart_data(widget); + if (!data || data->state != WIDGET_DATA_CREATED || !data->is.field.created || !data->handle || !data->is.field.gbar_created) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + ret = widget_viewer_destroy_glance_bar(data->handle, __widget_destroy_gbar_cb, widget_ref(data)); + if (ret < 0) { + widget_unref(data); + } + + return ret; +} + +EAPI const char *widget_viewer_evas_get_content_info(Evas_Object *widget) +{ + struct widget_data *data; + + data = get_smart_data(widget); + if (!data || !data->is.field.created || !data->handle) { + return NULL; + } + + return widget_viewer_get_content_string(data->handle); +} + +EAPI const char *widget_viewer_evas_get_title_string(Evas_Object *widget) +{ + struct widget_data *data; + + data = get_smart_data(widget); + if (!data || !data->is.field.created || !data->handle) { + return NULL; + } + + return widget_viewer_get_title_string(data->handle); +} + +EAPI const char *widget_viewer_evas_get_widget_id(Evas_Object *widget) +{ + struct widget_data *data; + + data = get_smart_data(widget); + if (!data || data->state != WIDGET_DATA_CREATED) { + return NULL; + } + + return data->widget_id; +} + +EAPI double widget_viewer_evas_get_period(Evas_Object *widget) +{ + struct widget_data *data; + + data = get_smart_data(widget); + if (!data || !data->is.field.created || !data->handle) { + return 0.0f; + } + + return data->period; +} + +EAPI void widget_viewer_evas_cancel_click_event(Evas_Object *widget) +{ + struct widget_data *data; + + data = get_smart_data(widget); + if (!data || !data->is.field.created || !data->handle) { + return; + } + + if (!data->is.field.pressed) { + DbgPrint("Cancel ignored\n"); + return; + } + + if (data->is.field.cancel_click == CANCEL_DISABLED) { + data->is.field.cancel_click = CANCEL_USER; + } +} + +static void access_ret_cb(struct widget *handle, int ret, void *data) +{ + struct access_ret_cb_data *cb_data = data; + + switch (ret) { + case WIDGET_ACCESS_STATUS_ERROR: + ret = WIDGET_ACCESS_RESULT_ERROR; + break; + case WIDGET_ACCESS_STATUS_DONE: + ret = WIDGET_ACCESS_RESULT_DONE; + break; + case WIDGET_ACCESS_STATUS_FIRST: + ret = WIDGET_ACCESS_RESULT_FIRST; + break; + case WIDGET_ACCESS_STATUS_LAST: + ret = WIDGET_ACCESS_RESULT_LAST; + break; + case WIDGET_ACCESS_STATUS_READ: + ret = WIDGET_ACCESS_RESULT_READ; + break; + default: + ret = WIDGET_ACCESS_RESULT_UNKNOWN; + break; + } + + if (cb_data->ret_cb) { + cb_data->ret_cb(cb_data->obj, ret, cb_data->data); + } + + free(cb_data); +} + +EAPI int widget_viewer_evas_feed_mouse_up_event(Evas_Object *widget) +{ + struct widget_data *data; + + data = get_smart_data(widget); + if (!data || !data->is.field.created || !data->handle) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + return do_force_mouse_up(data); +} + +EAPI int widget_viewer_evas_feed_access_event(Evas_Object *widget, int type, void *_info, void (*ret_cb)(Evas_Object *obj, int ret, void *data), void *cbdata) +{ + struct widget_data *data; + Elm_Access_Action_Info *info = _info; + int w; + int h; + struct access_ret_cb_data *cb_data; + int ret; + struct widget_access_event_info ainfo; + + data = get_smart_data(widget); + if (!data || !data->is.field.created || !data->handle) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + evas_object_geometry_get(data->widget_layout, NULL, NULL, &w, &h); + ainfo.x = (double)info->x / (double)w; + ainfo.y = (double)info->y / (double)h; + ainfo.info = 0; + + switch (type) { + case ELM_ACCESS_ACTION_HIGHLIGHT: /* highlight an object */ + DbgPrint("Highlight %dx%d ignored\n", info->x, info->y); + break; + case ELM_ACCESS_ACTION_READ: + cb_data = calloc(1, sizeof(*cb_data)); + if (!cb_data) { + ErrPrint("Heap: %d\n", errno); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + cb_data->ret_cb = ret_cb; + cb_data->data = cbdata; + cb_data->obj = widget; + + ainfo.type = WIDGET_ACCESS_TYPE_HIGHLIGHT; + ret = widget_viewer_feed_access_event(data->handle, WIDGET_ACCESS_HIGHLIGHT, &ainfo, access_ret_cb, cb_data); + if (ret != WIDGET_ERROR_NONE) { + free(cb_data); + } + break; + case ELM_ACCESS_ACTION_UNHIGHLIGHT: /* unhighlight an object */ + cb_data = calloc(1, sizeof(*cb_data)); + if (!cb_data) { + ErrPrint("Heap: %d\n", errno); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + cb_data->ret_cb = ret_cb; + cb_data->data = cbdata; + cb_data->obj = widget; + + ainfo.type = WIDGET_ACCESS_TYPE_UNHIGHLIGHT; + ret = widget_viewer_feed_access_event(data->handle, WIDGET_ACCESS_HIGHLIGHT, &ainfo, access_ret_cb, cb_data); + if (ret != WIDGET_ERROR_NONE) { + free(cb_data); + } + break; + case ELM_ACCESS_ACTION_HIGHLIGHT_NEXT: /* set highlight to next object */ + cb_data = calloc(1, sizeof(*cb_data)); + if (!cb_data) { + ErrPrint("Heap: %d\n", errno); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + cb_data->ret_cb = ret_cb; + cb_data->data = cbdata; + cb_data->obj = widget; + + ainfo.type = WIDGET_ACCESS_TYPE_HIGHLIGHT_NEXT; + ret = widget_viewer_feed_access_event(data->handle, WIDGET_ACCESS_HIGHLIGHT, &ainfo, access_ret_cb, cb_data); + if (ret != WIDGET_ERROR_NONE) { + free(cb_data); + } + break; + case ELM_ACCESS_ACTION_HIGHLIGHT_PREV: /* set highlight to previous object */ + cb_data = calloc(1, sizeof(*cb_data)); + if (!cb_data) { + ErrPrint("Heap: %d\n", errno); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + cb_data->ret_cb = ret_cb; + cb_data->data = cbdata; + cb_data->obj = widget; + + ainfo.type = WIDGET_ACCESS_TYPE_HIGHLIGHT_NEXT; + ret = widget_viewer_feed_access_event(data->handle, WIDGET_ACCESS_HIGHLIGHT, &ainfo, access_ret_cb, cb_data); + if (ret != WIDGET_ERROR_NONE) { + free(cb_data); + } + break; + case ELM_ACCESS_ACTION_ACTIVATE: /* activate a highlight object */ + cb_data = calloc(1, sizeof(*cb_data)); + if (!cb_data) { + ErrPrint("Heap: %d\n", errno); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + cb_data->ret_cb = ret_cb; + cb_data->data = cbdata; + cb_data->obj = widget; + + ainfo.type = WIDGET_ACCESS_TYPE_NONE; /* meaningless */ + ret = widget_viewer_feed_access_event(data->handle, WIDGET_ACCESS_ACTIVATE, &ainfo, access_ret_cb, cb_data); + if (ret != WIDGET_ERROR_NONE) { + free(cb_data); + } + break; + case ELM_ACCESS_ACTION_SCROLL: /* scroll if one of highlight object parents * is scrollable */ + cb_data = calloc(1, sizeof(*cb_data)); + if (!cb_data) { + ErrPrint("Heap: %d\n", errno); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + cb_data->ret_cb = ret_cb; + cb_data->data = cbdata; + cb_data->obj = widget; + + switch (info->mouse_type) { + case 0: + ainfo.type = WIDGET_ACCESS_TYPE_DOWN; + ret = widget_viewer_feed_access_event(data->handle, WIDGET_ACCESS_SCROLL, &ainfo, access_ret_cb, cb_data); + if (ret != WIDGET_ERROR_NONE) { + free(cb_data); + } + break; + case 1: + ainfo.type = WIDGET_ACCESS_TYPE_MOVE; + ret = widget_viewer_feed_access_event(data->handle, WIDGET_ACCESS_SCROLL, &ainfo, access_ret_cb, cb_data); + if (ret != WIDGET_ERROR_NONE) { + free(cb_data); + } + break; + case 2: + ainfo.type = WIDGET_ACCESS_TYPE_UP; + ret = widget_viewer_feed_access_event(data->handle, WIDGET_ACCESS_SCROLL, &ainfo, access_ret_cb, cb_data); + if (ret != WIDGET_ERROR_NONE) { + free(cb_data); + } + break; + default: + ret = WIDGET_ERROR_INVALID_PARAMETER; + free(cb_data); + break; + } + break; + case ELM_ACCESS_ACTION_MOUSE: /* give mouse event to highlight object */ + cb_data = calloc(1, sizeof(*cb_data)); + if (!cb_data) { + ErrPrint("Heap: %d\n", errno); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + cb_data->ret_cb = ret_cb; + cb_data->data = cbdata; + cb_data->obj = widget; + ainfo.type = WIDGET_ACCESS_TYPE_NONE; + ret = widget_viewer_feed_access_event(data->handle, WIDGET_ACCESS_MOUSE, &ainfo, access_ret_cb, cb_data); + if (ret != WIDGET_ERROR_NONE) { + free(cb_data); + } + break; + case ELM_ACCESS_ACTION_UP: /* change value up of highlight object */ + cb_data = calloc(1, sizeof(*cb_data)); + if (!cb_data) { + ErrPrint("Heap: %d\n", errno); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + cb_data->ret_cb = ret_cb; + cb_data->data = cbdata; + cb_data->obj = widget; + ainfo.type = WIDGET_ACCESS_TYPE_UP; + ret = widget_viewer_feed_access_event(data->handle, WIDGET_ACCESS_ACTION, &ainfo, access_ret_cb, cb_data); + if (ret != WIDGET_ERROR_NONE) { + free(cb_data); + } + break; + case ELM_ACCESS_ACTION_DOWN: /* change value down of highlight object */ + cb_data = calloc(1, sizeof(*cb_data)); + if (!cb_data) { + ErrPrint("Heap: %d\n", errno); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + cb_data->ret_cb = ret_cb; + cb_data->data = cbdata; + cb_data->obj = widget; + + ainfo.type = WIDGET_ACCESS_TYPE_DOWN; + ret = widget_viewer_feed_access_event(data->handle, WIDGET_ACCESS_ACTION, &ainfo, access_ret_cb, cb_data); + if (ret != WIDGET_ERROR_NONE) { + free(cb_data); + } + break; + case ELM_ACCESS_ACTION_VALUE_CHANGE: /* TODO: deprecate this */ + cb_data = calloc(1, sizeof(*cb_data)); + if (!cb_data) { + ErrPrint("Heap: %d\n", errno); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + cb_data->ret_cb = ret_cb; + cb_data->data = cbdata; + cb_data->obj = widget; + + ainfo.type = WIDGET_ACCESS_TYPE_NONE; + ret = widget_viewer_feed_access_event(data->handle, WIDGET_ACCESS_VALUE_CHANGE, &ainfo, access_ret_cb, cb_data); + if (ret != WIDGET_ERROR_NONE) { + free(cb_data); + } + break; + case ELM_ACCESS_ACTION_BACK: /* go back to a previous view ex: pop naviframe item */ + cb_data = calloc(1, sizeof(*cb_data)); + if (!cb_data) { + ErrPrint("Heap: %d\n", errno); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + cb_data->ret_cb = ret_cb; + cb_data->data = cbdata; + cb_data->obj = widget; + + ainfo.type = WIDGET_ACCESS_TYPE_NONE; + ret = widget_viewer_feed_access_event(data->handle, WIDGET_ACCESS_BACK, &ainfo, access_ret_cb, cb_data); + if (ret != WIDGET_ERROR_NONE) { + free(cb_data); + } + break; + case ELM_ACCESS_ACTION_OVER: /* mouse over an object */ + cb_data = calloc(1, sizeof(*cb_data)); + if (!cb_data) { + ErrPrint("Heap: %d\n", errno); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + cb_data->ret_cb = ret_cb; + cb_data->data = cbdata; + cb_data->obj = widget; + + ainfo.type = WIDGET_ACCESS_TYPE_NONE; + ret = widget_viewer_feed_access_event(data->handle, WIDGET_ACCESS_OVER, &ainfo, access_ret_cb, cb_data); + if (ret != WIDGET_ERROR_NONE) { + free(cb_data); + } + break; + case ELM_ACCESS_ACTION_ENABLE: /* enable highlight and read ability */ + cb_data = calloc(1, sizeof(*cb_data)); + if (!cb_data) { + ErrPrint("Heap: %d\n", errno); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + cb_data->ret_cb = ret_cb; + cb_data->data = cbdata; + cb_data->obj = widget; + + ainfo.type = WIDGET_ACCESS_TYPE_ENABLE; + ret = widget_viewer_feed_access_event(data->handle, WIDGET_ACCESS_ENABLE, &ainfo, access_ret_cb, cb_data); + if (ret != WIDGET_ERROR_NONE) { + free(cb_data); + } + break; + case ELM_ACCESS_ACTION_DISABLE: /* disable highlight and read ability */ + cb_data = calloc(1, sizeof(*cb_data)); + if (!cb_data) { + ErrPrint("Heap: %d\n", errno); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + cb_data->ret_cb = ret_cb; + cb_data->data = cbdata; + cb_data->obj = widget; + + ainfo.type = WIDGET_ACCESS_TYPE_DISABLE; + ret = widget_viewer_feed_access_event(data->handle, WIDGET_ACCESS_ENABLE, &ainfo, access_ret_cb, cb_data); + if (ret != WIDGET_ERROR_NONE) { + free(cb_data); + } + break; + default: + ret = WIDGET_ERROR_INVALID_PARAMETER; + break; + } + + return ret; +} + +EAPI void widget_viewer_evas_disable_preview(Evas_Object *widget) +{ + struct widget_data *data; + + data = get_smart_data(widget); + if (!data) { + ErrPrint("Invalid object\n"); + return; + } + + data->is.field.disable_preview = 1; +} + +EAPI void widget_viewer_evas_disable_overlay_text(Evas_Object *widget) +{ + struct widget_data *data; + + data = get_smart_data(widget); + if (!data) { + ErrPrint("Invalid object\n"); + return; + } + + data->is.field.disable_text = 1; +} + +EAPI void widget_viewer_evas_disable_loading(Evas_Object *widget) +{ + struct widget_data *data; + + data = get_smart_data(widget); + if (!data) { + ErrPrint("Invalid object\n"); + return; + } + + data->is.field.disable_loading = 1; +} + +EAPI void widget_viewer_evas_activate_faulted_widget(Evas_Object *widget) +{ + struct widget_data *data; + + data = get_smart_data(widget); + if (!data) { + ErrPrint("Invalid object\n"); + return; + } + + if (data->is.field.faulted) { + elm_object_signal_emit(data->widget_layout, "mouse,clicked,1", "overlay,content"); + } else { + DbgPrint("widget is not faulted\n"); + } +} + +EAPI int widget_viewer_evas_is_faulted(Evas_Object *widget) +{ + struct widget_data *data; + + data = get_smart_data(widget); + if (!data) { + ErrPrint("Invalid object\n"); + return 0; + } + + return data->is.field.faulted; +} + +EAPI int widget_viewer_evas_set_raw_event_callback(widget_evas_raw_event_type_e type, raw_event_cb cb, void *data) +{ + struct raw_event_cbdata *cbdata; + + cbdata = calloc(1, sizeof(*cbdata)); + if (!cbdata) { + ErrPrint("calloc: %d\n", errno); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + cbdata->cb = cb; + cbdata->data = data; + + switch (type) { + case WIDGET_VIEWER_EVAS_RAW_DELETE: + s_info.raw_event.delete_list = eina_list_append(s_info.raw_event.delete_list, cbdata); + break; + case WIDGET_VIEWER_EVAS_RAW_CREATE: + s_info.raw_event.create_list = eina_list_append(s_info.raw_event.create_list, cbdata); + break; + default: + free(cbdata); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + return WIDGET_ERROR_NONE; +} + +EAPI int widget_viewer_evas_unset_raw_event_callback(widget_evas_raw_event_type_e type, raw_event_cb cb, void *data) +{ + Eina_List *l; + Eina_List *n; + struct raw_event_cbdata *cbdata; + + switch (type) { + case WIDGET_VIEWER_EVAS_RAW_DELETE: + EINA_LIST_FOREACH_SAFE(s_info.raw_event.delete_list, l, n, cbdata) { + if (cbdata->cb == cb && cbdata->data == data) { + s_info.raw_event.delete_list = eina_list_remove(s_info.raw_event.delete_list, cbdata); + break; + } + } + break; + case WIDGET_VIEWER_EVAS_RAW_CREATE: + EINA_LIST_FOREACH_SAFE(s_info.raw_event.create_list, l, n, cbdata) { + if (cbdata->cb == cb && cbdata->data == data) { + s_info.raw_event.create_list = eina_list_remove(s_info.raw_event.create_list, cbdata); + break; + } + } + break; + default: + break; + } + + return WIDGET_ERROR_NONE; +} + +EAPI int widget_viewer_evas_freeze_visibility(Evas_Object *widget, widget_visibility_status_e status) +{ + struct widget_data *data; + + data = get_smart_data(widget); + if (!data) { + ErrPrint("Invalid object\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + data->is.field.freeze_visibility = 1; + data->freezed_visibility = status; + return WIDGET_ERROR_NONE; +} + +EAPI int widget_viewer_evas_thaw_visibility(Evas_Object *widget) +{ + struct widget_data *data; + + data = get_smart_data(widget); + if (!data) { + ErrPrint("Invalid object\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + data->is.field.freeze_visibility = 0; + + return WIDGET_ERROR_NONE; +} + +EAPI int widget_viewer_evas_get_freeze_visibility(Evas_Object *widget) +{ + struct widget_data *data; + + data = get_smart_data(widget); + if (!data) { + ErrPrint("Invalid object\n"); + return 0; + } + + return data->is.field.freeze_visibility; +} + +EAPI int widget_viewer_evas_dump_to_file(Evas_Object *widget, const char *filename) +{ + struct widget_data *data; + FILE *fp; + + data = get_smart_data(widget); + if (!data) { + ErrPrint("Invalid object\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + fp = fopen(filename, "w+"); + if (fp) { + Evas_Object *image; + image = elm_object_part_content_get(data->widget_layout, "widget,content"); + if (image) { + void *data; + Evas_Coord w, h; + evas_object_geometry_get(image, NULL, NULL, &w, &h); + + data = evas_object_image_data_get(image, 0); + if (data) { + fwrite(data, w * h, sizeof(int), fp); + } + } + fclose(fp); + } + + return WIDGET_ERROR_NONE; +} + +EAPI int widget_viewer_evas_is_widget(Evas_Object *widget) +{ + struct widget_data *data; + + data = get_smart_data(widget); + if (!data) { + ErrPrint("Invalid object\n"); + return 0; + } + + return 1; +} + +EAPI void widget_viewer_evas_set_permanent_delete(Evas_Object *widget, int flag) +{ + struct widget_data *data; + + data = get_smart_data(widget); + if (!data) { + ErrPrint("Invalid object\n"); + return; + } + + data->is.field.permanent_delete = !!flag; +} + +EAPI int widget_viewer_evas_subscribe_group(const char *cluster, const char *sub_cluster) +{ + struct subscribe_group *group; + Eina_List *l; + int ret; + + if (!cluster || !sub_cluster) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + EINA_LIST_FOREACH(s_info.subscribed_group_list, l, group) { + if (!strcasecmp(group->cluster, cluster) && !strcasecmp(group->sub_cluster, sub_cluster)) { + return WIDGET_ERROR_ALREADY_EXIST; + } + } + + group = calloc(1, sizeof(*group)); + if (!group) { + ErrPrint("calloc: %d\n", errno); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + group->cluster = strdup(cluster); + if (!group->cluster) { + ErrPrint("strdup: %d\n", errno); + free(group); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + group->sub_cluster = strdup(sub_cluster); + if (!group->sub_cluster) { + ErrPrint("strdup: %d\n", errno); + free(group->cluster); + free(group); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + ret = widget_viewer_subscribe_group(cluster, sub_cluster); + if (ret != WIDGET_ERROR_NONE) { + free(group->sub_cluster); + free(group->cluster); + free(group); + return ret; + } + + s_info.subscribed_group_list = eina_list_append(s_info.subscribed_group_list, group); + + return WIDGET_ERROR_NONE; +} + +EAPI int widget_viewer_evas_unsubscribe_group(const char *cluster, const char *sub_cluster) +{ + struct subscribe_group *group; + Eina_List *l; + Eina_List *n; + + if (!cluster || !sub_cluster) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + EINA_LIST_FOREACH_SAFE(s_info.subscribed_group_list, l, n, group) { + if (!strcasecmp(group->cluster, cluster) && !strcasecmp(group->sub_cluster, sub_cluster)) { + s_info.subscribed_group_list = eina_list_remove(s_info.subscribed_group_list, group); + free(group->cluster); + free(group->sub_cluster); + free(group); + return widget_viewer_unsubscribe_group(cluster, sub_cluster); + } + } + + return WIDGET_ERROR_NOT_EXIST; +} + +EAPI int widget_viewer_evas_subscribe_category(const char *category) +{ + struct subscribe_category *item; + Eina_List *l; + int ret; + + if (!category) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + EINA_LIST_FOREACH(s_info.subscribed_category_list, l, item) { + if (!strcmp(category, item->category)) { + return WIDGET_ERROR_ALREADY_EXIST; + } + } + + item = calloc(1, sizeof(*item)); + if (!item) { + ErrPrint("calloc: %d\n", errno); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + item->category = strdup(category); + if (!item->category) { + ErrPrint("strdup: %d\n", errno); + free(item); + return WIDGET_ERROR_OUT_OF_MEMORY; + } + + ret = widget_viewer_subscribe_category(category); + if (ret != WIDGET_ERROR_NONE) { + free(item->category); + free(item); + return ret; + } + + s_info.subscribed_category_list = eina_list_append(s_info.subscribed_category_list, item); + return WIDGET_ERROR_NONE; +} + +EAPI int widget_viewer_evas_unsubscribe_category(const char *category) +{ + Eina_List *l; + Eina_List *n; + struct subscribe_category *item; + + if (!category) { + return WIDGET_ERROR_INVALID_PARAMETER; + } + + EINA_LIST_FOREACH_SAFE(s_info.subscribed_category_list, l, n, item) { + if (!strcmp(item->category, category)) { + s_info.subscribed_category_list = eina_list_remove(s_info.subscribed_category_list, item); + free(item->category); + free(item); + return widget_viewer_unsubscribe_category(category); + } + } + + return WIDGET_ERROR_NOT_EXIST; +} + +static void text_signal_cb(widget_h handle, int ret, void *data) +{ + /* TODO : add codes to invoke smart event callback function */ +} + +EAPI int widget_viewer_evas_emit_text_signal(Evas_Object *widget, widget_text_signal_s event_info, void *data) +{ + struct widget_data *widget_data_from_evas; + + widget_data_from_evas = get_smart_data(widget); + + if (!widget_data_from_evas) { + ErrPrint("Invalid object\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + return widget_viewer_emit_text_signal(widget_data_from_evas->handle, event_info, text_signal_cb, data); +} + +EAPI int widget_viewer_evas_get_instance_id(Evas_Object *widget, char **instance_id) +{ + struct widget_data *data; + + data = get_smart_data(widget); + if (!data) { + ErrPrint("Invalid object\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + return widget_viewer_get_instance_id(data->handle, instance_id); +} + +EAPI int widget_viewer_evas_set_widget_option(Evas_Object *widget, widget_option_widget_e option, int value) +{ + struct widget_data *data; + + data = get_smart_data(widget); + if (!data) { + ErrPrint("Invalid object\n"); + return WIDGET_ERROR_INVALID_PARAMETER; + } + + switch (option) { + case WIDGET_OPTION_WIDGET_DELAYED_RESUME: + data->is.field.delayed_resume = (value & 0x03); + break; + default: + return WIDGET_ERROR_INVALID_PARAMETER; + } + + return WIDGET_ERROR_NONE; +} + +/* End of a file */ diff --git a/widget_viewer_evas/widget_viewer_evas.pc.in b/widget_viewer_evas/widget_viewer_evas.pc.in new file mode 100644 index 0000000..87ee6a6 --- /dev/null +++ b/widget_viewer_evas/widget_viewer_evas.pc.in @@ -0,0 +1,12 @@ +prefix=@PREFIX@ +exec_prefix=@EXEC_PREFIX@ +libdir=@LIBDIR@ +includedir=@INCLUDEDIR@ + +Name: widget_viewer_evas +Description: Support development of the widget Viewer EVAS Frontend library +Version: @VERSION@ +Requires: widget_service widget_viewer +Libs: -L${libdir} -lwidget_viewer_evas +Cflags: -I${includedir} +cppflags: -I${includedir}