From 14da30e253112b0c2f96b1a7b0a9475dbaf156ee Mon Sep 17 00:00:00 2001 From: Sung-jae Park Date: Thu, 20 Dec 2012 17:18:50 +0900 Subject: [PATCH] Initialize the project. Change-Id: I47016bf1ca7d8e8dfbebd63ff6e24a52a2e0b921 --- CMakeLists.txt | 76 ++ LICENSE | 83 ++ include/debug.h | 21 + include/dlist.h | 43 + include/fb.h | 42 + include/provider.h | 305 ++++++ include/provider_buffer.h | 178 ++++ include/provider_buffer_internal.h | 55 ++ include/util.h | 30 + libprovider.manifest | 5 + packaging/libprovider.spec | 57 ++ provider.pc.in | 11 + sample/org.tizen.live-app/CMakeLists.txt | 45 + sample/org.tizen.live-app/include/CController.h | 53 + sample/org.tizen.live-app/include/CMain.h | 16 + sample/org.tizen.live-app/include/CModel.h | 34 + sample/org.tizen.live-app/include/CView.h | 35 + sample/org.tizen.live-app/include/CWindow.h | 58 ++ sample/org.tizen.live-app/include/debug.h | 28 + sample/org.tizen.live-app/org.tizen.live-app.conf | 12 + sample/org.tizen.live-app/org.tizen.live-app.xml | 10 + .../packaging/org.tizen.live-app.spec | 46 + .../res/image/org.zien.live-app.png | Bin 0 -> 25019 bytes sample/org.tizen.live-app/res/image/unknown.png | Bin 0 -> 53400 bytes sample/org.tizen.live-app/src/CController.cpp | 436 ++++++++ sample/org.tizen.live-app/src/CMain.cpp | 81 ++ sample/org.tizen.live-app/src/CModel.cpp | 118 +++ sample/org.tizen.live-app/src/CView.cpp | 117 +++ sample/org.tizen.live-app/src/CWindow.cpp | 226 +++++ sample/org.tizen.live-video/CMakeLists.txt | 52 + sample/org.tizen.live-video/include/CController.h | 53 + sample/org.tizen.live-video/include/CMain.h | 16 + sample/org.tizen.live-video/include/CModel.h | 33 + sample/org.tizen.live-video/include/CVideo.h | 68 ++ sample/org.tizen.live-video/include/CView.h | 25 + sample/org.tizen.live-video/include/CWindow.h | 58 ++ sample/org.tizen.live-video/include/debug.h | 28 + .../org.tizen.live-video/org.tizen.live-video.conf | 12 + .../org.tizen.live-video/org.tizen.live-video.xml | 10 + .../packaging/org.tizen.live-video.spec | 52 + .../res/image/org.tizen.live-video.png | Bin 0 -> 2782 bytes sample/org.tizen.live-video/res/image/unknown.png | Bin 0 -> 53400 bytes sample/org.tizen.live-video/src/CController.cpp | 462 +++++++++ sample/org.tizen.live-video/src/CMain.cpp | 81 ++ sample/org.tizen.live-video/src/CModel.cpp | 74 ++ sample/org.tizen.live-video/src/CVideo.cpp | 383 +++++++ sample/org.tizen.live-video/src/CView.cpp | 31 + sample/org.tizen.live-video/src/CWindow.cpp | 224 +++++ src/dlist.c | 180 ++++ src/fb.c | 869 ++++++++++++++++ src/provider.c | 1044 ++++++++++++++++++++ src/provider_buffer.c | 799 +++++++++++++++ src/util.c | 59 ++ 53 files changed, 6834 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 LICENSE create mode 100644 include/debug.h create mode 100644 include/dlist.h create mode 100644 include/fb.h create mode 100644 include/provider.h create mode 100644 include/provider_buffer.h create mode 100644 include/provider_buffer_internal.h create mode 100644 include/util.h create mode 100644 libprovider.manifest create mode 100644 packaging/libprovider.spec create mode 100644 provider.pc.in create mode 100644 sample/org.tizen.live-app/CMakeLists.txt create mode 100644 sample/org.tizen.live-app/include/CController.h create mode 100644 sample/org.tizen.live-app/include/CMain.h create mode 100644 sample/org.tizen.live-app/include/CModel.h create mode 100644 sample/org.tizen.live-app/include/CView.h create mode 100644 sample/org.tizen.live-app/include/CWindow.h create mode 100644 sample/org.tizen.live-app/include/debug.h create mode 100644 sample/org.tizen.live-app/org.tizen.live-app.conf create mode 100644 sample/org.tizen.live-app/org.tizen.live-app.xml create mode 100644 sample/org.tizen.live-app/packaging/org.tizen.live-app.spec create mode 100644 sample/org.tizen.live-app/res/image/org.zien.live-app.png create mode 100644 sample/org.tizen.live-app/res/image/unknown.png create mode 100644 sample/org.tizen.live-app/src/CController.cpp create mode 100644 sample/org.tizen.live-app/src/CMain.cpp create mode 100644 sample/org.tizen.live-app/src/CModel.cpp create mode 100644 sample/org.tizen.live-app/src/CView.cpp create mode 100644 sample/org.tizen.live-app/src/CWindow.cpp create mode 100644 sample/org.tizen.live-video/CMakeLists.txt create mode 100644 sample/org.tizen.live-video/include/CController.h create mode 100644 sample/org.tizen.live-video/include/CMain.h create mode 100644 sample/org.tizen.live-video/include/CModel.h create mode 100644 sample/org.tizen.live-video/include/CVideo.h create mode 100644 sample/org.tizen.live-video/include/CView.h create mode 100644 sample/org.tizen.live-video/include/CWindow.h create mode 100644 sample/org.tizen.live-video/include/debug.h create mode 100644 sample/org.tizen.live-video/org.tizen.live-video.conf create mode 100644 sample/org.tizen.live-video/org.tizen.live-video.xml create mode 100644 sample/org.tizen.live-video/packaging/org.tizen.live-video.spec create mode 100644 sample/org.tizen.live-video/res/image/org.tizen.live-video.png create mode 100644 sample/org.tizen.live-video/res/image/unknown.png create mode 100644 sample/org.tizen.live-video/src/CController.cpp create mode 100644 sample/org.tizen.live-video/src/CMain.cpp create mode 100644 sample/org.tizen.live-video/src/CModel.cpp create mode 100644 sample/org.tizen.live-video/src/CVideo.cpp create mode 100644 sample/org.tizen.live-video/src/CView.cpp create mode 100644 sample/org.tizen.live-video/src/CWindow.cpp create mode 100644 src/dlist.c create mode 100644 src/fb.c create mode 100644 src/provider.c create mode 100644 src/provider_buffer.c create mode 100644 src/util.c diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..d0d26d4 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,76 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(provider 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 0) +SET(VERSION "${VERSION_MAJOR}.0.1") + +set(CMAKE_SKIP_BUILD_RPATH true) + +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) + +INCLUDE(FindPkgConfig) +pkg_check_modules(pkgs REQUIRED + dlog + glib-2.0 + gio-2.0 + com-core + x11 + xext + libdri2 + libdrm + libdrm_slp + xfixes + dri2proto + xdamage +) + +FOREACH(flag ${pkgs_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("-Werror") +#ADD_DEFINITIONS("-Wall") +#ADD_DEFINITIONS("-Wextra") +#ADD_DEFINITIONS("-ansi") +#ADD_DEFINITIONS("-pedantic") + +ADD_DEFINITIONS("-DPREFIX=\"${PREFIX}\"") +ADD_DEFINITIONS("-DLOG_TAG=\"${PROJECT_NAME}\"") +ADD_DEFINITIONS("-DNDEBUG") +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_DEFINITIONS("-DFLOG") + +ADD_LIBRARY(${PROJECT_NAME} SHARED + src/provider_buffer.c + src/provider.c + src/util.c + src/fb.c + src/dlist.c +) + +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${VERSION_MAJOR}) +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES VERSION ${VERSION}) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_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_SOURCE_DIR}/include/provider.h DESTINATION include/${PROJECT_NAME}) +INSTALL(FILES ${CMAKE_SOURCE_DIR}/include/provider_buffer.h DESTINATION include/${PROJECT_NAME}) +INSTALL(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION /usr/share/license RENAME "lib${PROJECT_NAME}") + +#ADD_SUBDIRECTORY(data) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..27daa90 --- /dev/null +++ b/LICENSE @@ -0,0 +1,83 @@ +Flora License + +Version 1.0, May, 2012 + +http://www.tizenopensource.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 Compatibility Definition Document and passes the Compatibility Test Suite 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: + +You must give any other recipients of the Work or Derivative Works a copy of this License; and +You must cause any modified files to carry prominent notices stating that You changed the files; and +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 +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. +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.0 (the "License"); + + you may not use this file except in compliance with the License. + + You may obtain a copy of the License at + + + + http://www.tizenopensource.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/include/debug.h b/include/debug.h new file mode 100644 index 0000000..f6fd2ab --- /dev/null +++ b/include/debug.h @@ -0,0 +1,21 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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 DbgPrint(format, arg...) LOGD("[%s/%s:%d] " format, util_basename(__FILE__), __func__, __LINE__, ##arg) +#define ErrPrint(format, arg...) LOGE("[%s/%s:%d] " format "", util_basename(__FILE__), __func__, __LINE__, ##arg) +#define WarnPrint(format, arg...) LOGW("[%s/%s:%d] " format "", util_basename(__FILE__), __func__, __LINE__, ##arg) + +/* End of a file */ diff --git a/include/dlist.h b/include/dlist.h new file mode 100644 index 0000000..b4a5719 --- /dev/null +++ b/include/dlist.h @@ -0,0 +1,43 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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/include/fb.h b/include/fb.h new file mode 100644 index 0000000..8003c62 --- /dev/null +++ b/include/fb.h @@ -0,0 +1,42 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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_filename(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); +extern int fb_size(struct fb_info *info); +extern int fb_refcnt(void *data); +extern int fb_is_created(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); + +extern const char *fb_id(struct fb_info *info); + +extern int fb_create_gem(struct fb_info *info); +extern int fb_destroy_gem(struct fb_info *info); +extern void *fb_acquire_gem(struct fb_info *info); +extern int fb_release_gem(struct fb_info *info); +extern int fb_has_gem(struct fb_info *info); + +/* End of a file */ diff --git a/include/provider.h b/include/provider.h new file mode 100644 index 0000000..7711d58 --- /dev/null +++ b/include/provider.h @@ -0,0 +1,305 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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 __PROVIDER_H +#define __PROVIDER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * Text signal & Content event uses this data structure. + */ +struct event_info { + struct { + double x; /*!< X value of current mouse(touch) position */ + double y; /*!< Y value of current mouse(touch) position */ + int down; /*!< Is it pressed(1) or not(0) */ + } pointer; + + struct { + double sx; /*!< Pressed object's left top X */ + double sy; /*!< Pressed object's left top Y */ + double ex; /*!< Pressed object's right bottom X */ + double ey; /*!< Pressed object's right bottom Y */ + } part; +}; + +struct event_arg { + enum { + EVENT_NEW, /*!< Master will send this to create a new livebox instance */ + EVENT_RENEW, /*!< If the master detects any problems of your slave, it will terminate slave provider. + and after reactivating the provider slave, this request will be delievered to create + a livebox instance again */ + + EVENT_DELETE, /*!< Master will send this to delete a livebox instance */ + + EVENT_CONTENT_EVENT, /*!< Any events are generated from your livebox or PD, this event will be sent to you */ + EVENT_CLICKED, /*!< If a livebox is clicked, the master will send this event */ + EVENT_TEXT_SIGNAL, /*!< Text type livebox or PD will generate this event */ + + EVENT_RESIZE, /*!< If a livebox is resized, the master will send this event */ + EVENT_SET_PERIOD, /*!< To change the update period of a livebox */ + EVENT_CHANGE_GROUP, /*!< To change the group(cluster/sub-cluster) of a livebox */ + EVENT_PINUP, /*!< To make pin up of a livebox */ + + EVENT_UPDATE_CONTENT, /*!< It's time to update the content of a livebox */ + + EVENT_PAUSE, /*!< Freeze all timer and go to sleep mode */ + EVENT_RESUME, /*!< Thaw all timer and wake up */ + + EVENT_PD_CREATE, /*!< Only for the buffer type */ + EVENT_PD_DESTROY, /*!< Only for the buffer type */ + + EVENT_LB_PAUSE, /*!< Freeze the update timer of a specified livebox */ + EVENT_LB_RESUME, /*!< Thaw the update timer of a specified livebox */ + } type; + const char *pkgname; /*!< Package name of a livebox */ + const char *id; /*!< Instance Id of a livebox */ + + union { + struct { + int w; /*!< PD buffer is created with width "w" */ + int h; /*!< PD buffer is created with height "h" */ + + double x; /*!< Relative position of a livebox from this PD */ + double y; /*!< Relative position of a livebox from this PD */ + } pd_create; + + struct { + } pd_destroy; + + struct { + const char *content; /*!< Content info */ + int timeout; /*!< Timeout */ + int has_script; /*!< Livebox has script (buffer is created from the master) */ + double period; /*!< Update period */ + const char *cluster; /*!< Cluster ID of this livebox instance */ + const char *category; /*!< Sub-cluster ID of this livebox instance */ + int skip_need_to_create; /*!< Is this livebox need to check the "need_to_create"? */ + int width; /*!< Width of a livebox content */ + int height; /*!< Height of a livebox content */ + const char *abi; /*!< ABI tag of this livebox */ + char *out_content; /*!< Output content */ + char *out_title; /*!< Output title */ + int out_is_pinned_up; /*!< Is this pinned up? */ + } lb_create; /*!< "new" */ + + struct { + const char *content; + int timeout; + int has_script; + double period; + const char *cluster; + const char *category; + int width; /*!< Width of a livebox content */ + int height; /*!< Height of a livebox content */ + const char *abi; + char *out_content; /*!< Output content */ + char *out_title; /*!< Output title */ + int out_is_pinned_up; /*!< Is this pinned up? */ + } lb_recreate; /*!< renew */ + + struct { + } lb_destroy; /*!< delete */ + + struct { + const char *emission; /*!< Event string */ + const char *source; /*!< Object ID which makes event */ + struct event_info info; + } content_event; /*!< script */ + + struct { + const char *event; /*!< Event type, currently only "click" supported */ + double timestamp; /*!< Timestamp of event occurred */ + double x; /*!< X position of the click event */ + double y; /*!< Y position of the click event */ + } clicked; /*!< clicked */ + + struct { + const char *emission; /*!< Event string */ + const char *source; /*!< Object ID which makes event */ + struct event_info info; + } text_signal; /*!< text_signal */ + + struct { + int w; /*!< New width of a livebox */ + int h; /*!< New height of a livebox */ + } resize; /*!< resize */ + + struct { + double period; /*!< New period */ + } set_period; /*!< set_period */ + + struct { + const char *cluster; + const char *category; + } change_group; /*!< change_group */ + + struct { + int state; + char *content_info; /* out value */ + } pinup; /*!< pinup */ + + struct { + const char *cluster; + const char *category; + } update_content; /*! update_content */ + + struct { + double timestamp; + } pause; /*!< pause */ + + struct { + double timestamp; + } resume; /*!< resume */ + + struct { + /*!< */ + } lb_pause; + + struct { + /*!< */ + } lb_resume; + } info; +}; + +struct event_handler { + int (*lb_create)(struct event_arg *arg, int *width, int *height, double *priority, void *data); /* new */ + int (*lb_destroy)(struct event_arg *arg, void *data); /* delete */ + + /* Recover from the fault of slave */ + int (*lb_recreate)(struct event_arg *arg, void *data); + + int (*lb_pause)(struct event_arg *arg, void *data); + int (*lb_resume)(struct event_arg *arg, void *data); + + int (*content_event)(struct event_arg *arg, void *data); + int (*clicked)(struct event_arg *arg, void *data); + int (*text_signal)(struct event_arg *arg, void *data); + int (*resize)(struct event_arg *arg, void *data); + int (*set_period)(struct event_arg *arg, void *data); + int (*change_group)(struct event_arg *arg, void *data); + int (*pinup)(struct event_arg *arg, void *data); + int (*update_content)(struct event_arg *arg, void *data); + + int (*pause)(struct event_arg *arg, void *data); + int (*resume)(struct event_arg *arg, void *data); + + int (*disconnected)(struct event_arg *arg, void *data); + int (*connected)(struct event_arg *arg, void *data); + + /*! + * \note + * Only for the buffer type + */ + int (*pd_create)(struct event_arg *arg, void *data); + int (*pd_destroy)(struct event_arg *arg, void *data); +}; + +/*! + * \brief Initialize the provider service + * \param[in] disp XDisplay object, if you don't know what this is, set NULL + * \param[in] name Slave name which is given by the master provider. + * \param[in] table Event handler table + * \return int Success 0 otherwise errno < 0 + */ +extern int provider_init(void *disp, const char *name, struct event_handler *table, void *data); + +/*! + * \brief Finalize the provider service + */ +extern void *provider_fini(void); + +/*! + * \brief Send the hello signal to the master + * Master will activate connection of this only if you send this hello event. + * or the master will reject all requests from your provider. + * \return int Success 0 otherwise errno < 0 + */ +extern int provider_send_hello(void); + +/*! + * \brief Send the ping message to the master to notify that your provider is working properly. + * \return int Success 0 otherwise errno < 0 + */ +extern int provider_send_ping(void); + +/*! + * \brief Send the updated event to the master + * \param[in] pkgname Package name which of an updated livebox. + * \param[in] id Instance ID of an updated livebox. + * \param[in] w Width of an updated content + * \param[in] h Height of an updated content + * \param[in] priority Priority of an updated content + * \return int Success 0 otherwise errno < 0 + */ +extern int provider_send_updated(const char *pkgname, const char *id, int w, int h, double priority, const char *content, const char *title); + +/*! + * \brief Send the description data updated event to the master + * \param[in] pkgname Package name of an updated livebox. + * \param[in] id Instance ID of an updated livebox. + * \param[in] descfile The filename of a description file. + * \return int Success 0 otherwise errno < 0 + */ +extern int provider_send_desc_updated(const char *pkgname, const char *id, const char *descfile); + +/*! + * \brief Send the deleted event of specified livebox instance + * \param[in] pkgname Package name of the livebox + * \param[in] id Livebox instance ID + * \return int Success 0 otherwise errno < 0 + */ +extern int provider_send_deleted(const char *pkgname, const char *id); + +/*! + * \breif If you want to use the fault management service of the master provider, + * Before call any functions of a livebox, call this. + * \param[in] pkgname Package name of the livebox + * \param[in] id Instance ID of the livebox + * \param[in] funcname Function name which will be called + * \return int Success 0 otherwise errno < 0 + */ +extern int provider_send_ret(const char *pkgname, const char *id, const char *funcname); + +/*! + * \brief If you want to use the fault management service of the master provider, + * After call any functions of a livebox, call this. + * \param[in] pkgname Package name of the livebox + * \param[in] id Instance ID of the livebox + * \param[in] funcname Function name which is called by the slave + * \return int Success 0 otherwise errno < 0 + */ +extern int provider_send_call(const char *pkgname, const char *id, const char *funcname); + +/*! + * \brief If you want to send the fault event to the master provider, + * Use this API + * \param[in] pkgname Package name of the livebox + * \param[in] id ID of the livebox instance + * \param[in] funcname Reason of the fault error + * \return int Success 0 otherwise errno < 0 + */ +extern int provider_send_faulted(const char *pkgname, const char *id, const char *funcname); + +#ifdef __cplusplus +} +#endif + +#endif +/* End of a file */ diff --git a/include/provider_buffer.h b/include/provider_buffer.h new file mode 100644 index 0000000..b712f01 --- /dev/null +++ b/include/provider_buffer.h @@ -0,0 +1,178 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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 __PROVIDER_BUFFER_H +#define __PROVIDER_BUFFER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \NOTE + * This enumeration value has to be sync'd with the liblivebox interface. (only for inhouse livebox) + */ +enum target_type { + TYPE_LB, /*!< */ + TYPE_PD, /*!< */ + TYPE_ERROR, /*!< */ +}; + +/*! + * \NOTE + * This enumeration value should be sync'd with liblivebox interface. (only for inhouse livebox) + */ +enum buffer_event { + BUFFER_EVENT_ENTER, /*!< */ + BUFFER_EVENT_LEAVE, /*!< */ + BUFFER_EVENT_DOWN, /*!< */ + BUFFER_EVENT_MOVE, /*!< */ + BUFFER_EVENT_UP, /*!< */ +}; + +struct livebox_buffer; + +/*! + * \brief + * \param[in] type + * \param[in] pkgname + * \param[in] id + * \param[in] width + * \param[in] height + * \param[in] pixel_size + * \param[in] handler + * \param[in] data + */ +extern struct livebox_buffer *provider_buffer_acquire(enum target_type type, const char *pkgname, const char *id, int width, int height, int pixel_size, int (*handler)(struct livebox_buffer *, enum buffer_event, double, double, double, void *data), void *data); + +/*! + * \brief + * \param[in] info + * \param[in] w + * \param[in] h + * \return int + */ +extern int provider_buffer_resize(struct livebox_buffer *info, int w, int h); + +/*! + * \brief + * \param[in] info + * \return address + */ +extern void *provider_buffer_ref(struct livebox_buffer *info); + +/*! + * \brief + * \param[in] ptr + * \return int + */ +extern int provider_buffer_unref(void *ptr); + +/*! + * \brief + * \param[in] info + * \return int + */ +extern int provider_buffer_release(struct livebox_buffer *info); + +/*! + *\brief + \param[in] info + \return int + */ +extern int provider_buffer_sync(struct livebox_buffer *info); + +/*! + * \brief Get the buffer type + * \param[in] info + * \return target type PD or LB + */ +extern enum target_type provider_buffer_type(struct livebox_buffer *info); + +/*! + * \brief Get the package name + * \param[in] info + * \return pkgname + */ +extern const char *provider_buffer_pkgname(struct livebox_buffer *info); + +/*! + * \brief + * \param[in] info + * \return id + */ +extern const char *provider_buffer_id(struct livebox_buffer *info); + +/*! + * \brief + * \param[in] info + * \param[out] w + * \param[out] h + * \param[out] pixel_size + * \return int + */ +extern int provider_buffer_get_size(struct livebox_buffer *info, int *w, int *h, int *pixel_size); + +/*! + * \brief Getting the PIXMAP id of mapped on this livebox_buffer + * \param[in] info + * \return 0 if fails or pixmap ID + */ +extern unsigned long provider_buffer_pixmap_id(struct livebox_buffer *info); + +/*! + * \brief + * \param[in] disp + * \return int + */ +extern int provider_buffer_init(void *disp); + +/*! + * \brief + * \return int + */ +extern int provider_buffer_fini(void); + +/*! + */ +extern int provider_buffer_pixmap_is_support_hw(struct livebox_buffer *info); + +/*! + */ +extern int provider_buffer_pixmap_create_hw(struct livebox_buffer *info); + +/*! + */ +extern int provider_buffer_pixmap_destroy_hw(struct livebox_buffer *info); + +/*! + */ +extern void *provider_buffer_pixmap_hw_addr(struct livebox_buffer *info); + +/*! + */ +extern int provider_buffer_pre_render(struct livebox_buffer *info); + +/*! + */ +extern int provider_buffer_post_render(struct livebox_buffer *info); + +#ifdef __cplusplus +} +#endif + +#endif +/* End of a file */ diff --git a/include/provider_buffer_internal.h b/include/provider_buffer_internal.h new file mode 100644 index 0000000..b7add55 --- /dev/null +++ b/include/provider_buffer_internal.h @@ -0,0 +1,55 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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 livebox_buffer { + enum { + BUFFER_CREATED = 0x00beef00, + BUFFER_DESTROYED = 0x00dead00, + } state; + + enum target_type type; + + union { + int fd; /* File handle(descriptor) */ + int id; /* SHM handle(id) */ + } handle; + + char *pkgname; + char *id; + int width; + int height; + int pixel_size; + + struct fb_info *fb; + + int (*handler)(struct livebox_buffer *info, enum buffer_event event, double timestamp, double x, double y, void *data); + void *data; +}; + +extern struct livebox_buffer *provider_buffer_find_buffer(enum target_type type, const char *pkgname, const char *id); +extern struct packet *provider_buffer_lb_mouse_down(pid_t pid, int handle, const struct packet *packet); +extern struct packet *provider_buffer_lb_mouse_up(pid_t pid, int handle, const struct packet *packet); +extern struct packet *provider_buffer_lb_mouse_move(pid_t pid, int handle, const struct packet *packet); +extern struct packet *provider_buffer_lb_mouse_enter(pid_t pid, int handle, const struct packet *packet); +extern struct packet *provider_buffer_lb_mouse_leave(pid_t pid, int handle, const struct packet *packet); +extern struct packet *provider_buffer_pd_mouse_down(pid_t pid, int handle, const struct packet *packet); +extern struct packet *provider_buffer_pd_mouse_up(pid_t pid, int handle, const struct packet *packet); +extern struct packet *provider_buffer_pd_mouse_move(pid_t pid, int handle, const struct packet *packet); +extern struct packet *provider_buffer_pd_mouse_enter(pid_t pid, int handle, const struct packet *packet); +extern struct packet *provider_buffer_pd_mouse_leave(pid_t pid, int handle, const struct packet *packet); +extern const char *provider_name(void); + +/* End of a file */ diff --git a/include/util.h b/include/util.h new file mode 100644 index 0000000..c33c285 --- /dev/null +++ b/include/util.h @@ -0,0 +1,30 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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 double util_get_timestamp(void); +extern const char *util_basename(const char *name); +extern const char *util_uri_to_path(const char *uri); + +#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/libprovider.manifest b/libprovider.manifest new file mode 100644 index 0000000..a76fdba --- /dev/null +++ b/libprovider.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/packaging/libprovider.spec b/packaging/libprovider.spec new file mode 100644 index 0000000..b9c1ea1 --- /dev/null +++ b/packaging/libprovider.spec @@ -0,0 +1,57 @@ +Name: libprovider +Summary: Library for the development of a livebox data provider +Version: 0.5.6 +Release: 1 +Group: main/app +License: Flora License +Source0: %{name}-%{version}.tar.gz +BuildRequires: cmake, gettext-tools +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(gio-2.0) +BuildRequires: pkgconfig(com-core) +BuildRequires: pkgconfig(x11) +BuildRequires: pkgconfig(xext) +BuildRequires: pkgconfig(libdri2) +BuildRequires: pkgconfig(libdrm) +BuildRequires: pkgconfig(libdrm_slp) +BuildRequires: pkgconfig(xfixes) +BuildRequires: pkgconfig(dri2proto) +BuildRequires: pkgconfig(xdamage) + +%description +Livebox data provider development library + +%package devel +Summary: Files for livebox data provider development. +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description devel +Livebox data provider development library (dev) + +%prep +%setup -q + +%build +cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} +make %{?jobs:-j%jobs} + +%install +rm -rf %{buildroot} +%make_install +mkdir -p %{buildroot}/usr/share/license + +%post + +%files -n libprovider +%manifest libprovider.manifest +%defattr(-,root,root,-) +/usr/lib/*.so* +/usr/share/license/* + +%files devel +%defattr(-,root,root,-) +/usr/include/provider/provider.h +/usr/include/provider/provider_buffer.h +/usr/lib/pkgconfig/*.pc diff --git a/provider.pc.in b/provider.pc.in new file mode 100644 index 0000000..4fe7e6c --- /dev/null +++ b/provider.pc.in @@ -0,0 +1,11 @@ +prefix=@PREFIX@ +exec_prefix=@EXEC_PREFIX@ +libdir=@LIBDIR@ +includedir=@INCLUDEDIR@ + +Name: libprovider +Description: livebox supporting library +Version: @VERSION@ +Libs: -L${libdir} -lprovider +Cflags: -I${includedir} +cppflags: -I${includedir} diff --git a/sample/org.tizen.live-app/CMakeLists.txt b/sample/org.tizen.live-app/CMakeLists.txt new file mode 100644 index 0000000..1715456 --- /dev/null +++ b/sample/org.tizen.live-app/CMakeLists.txt @@ -0,0 +1,45 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(live-app CXX) + +INCLUDE(FindPkgConfig) +pkg_check_modules(pkg REQUIRED + dlog + glib-2.0 + gio-2.0 + appcore-efl + bundle + provider + aul + ecore-x +) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include) + +ADD_DEFINITIONS("-DNDEBUG") +ADD_DEFINITIONS("-DLOG_TAG=\"${PROJECT_NAME}\"") +ADD_DEFINITIONS("-DPKGNAME=\"org.tizen.${PROJECT_NAME}\"") +ADD_DEFINITIONS(${pkg_CFLAGS}) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Winline -Werror -g") + +ADD_EXECUTABLE(${PROJECT_NAME} + src/CMain.cpp + src/CWindow.cpp + src/CController.cpp + src/CView.cpp + src/CModel.cpp +) + +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkg_LDFLAGS} "-ldl") +INSTALL(FILES ${CMAKE_SOURCE_DIR}/org.tizen.${PROJECT_NAME}.xml DESTINATION /opt/share/packages) +INSTALL(FILES ${CMAKE_SOURCE_DIR}/org.tizen.${PROJECT_NAME}.conf DESTINATION + /opt/usr/live/org.tizen.${PROJECT_NAME}/etc) +INSTALL(FILES ${CMAKE_SOURCE_DIR}/res/image/unknown.png DESTINATION + /opt/usr/live/org.tizen.${PROJECT_NAME}/res/image) +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION + /opt/usr/apps/org.tizen.${PROJECT_NAME}/bin + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE) +INSTALL(FILES ${CMAKE_SOURCE_DIR}/res/image/org.tizen.${PROJECT_NAME}.png DESTINATION /opt/share/icons/default/small) +# End of a file diff --git a/sample/org.tizen.live-app/include/CController.h b/sample/org.tizen.live-app/include/CController.h new file mode 100644 index 0000000..7647676 --- /dev/null +++ b/sample/org.tizen.live-app/include/CController.h @@ -0,0 +1,53 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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. + */ + +class CController { +public: + static int Initialize(const char *name); + static int Finalize(void); + + static int s_CreateLB(struct event_arg *arg, int *width, int *height, double *priority, void *data); + static int s_RecreateLB(struct event_arg *arg, void *data); + static int s_DestroyLB(struct event_arg *arg, void *data); + static int s_ContentEvent(struct event_arg *arg, void *data); + static int s_Clicked(struct event_arg *arg, void *data); + static int s_TextEvent(struct event_arg *arg, void *data); + static int s_Resize(struct event_arg *arg, void *data); + static int s_SetPeriod(struct event_arg *arg, void *data); + static int s_ChangeGroup(struct event_arg *arg, void *data); + static int s_Pinup(struct event_arg *arg, void *data); + static int s_UpdateContent(struct event_arg *arg, void *data); + static int s_Pause(struct event_arg *arg, void *data); + static int s_Resume(struct event_arg *arg, void *data); + static int s_Disconnected(struct event_arg *arg, void *data); + static int s_Connected(struct event_arg *arg, void *data); + static int s_CreatePD(struct event_arg *arg, void *data); + static int s_DestroyPD(struct event_arg *arg, void *data); + static Eina_Bool s_PingHandler(void *data); + +private: + CController(void); + virtual ~CController(void); + + char *m_sName; + + static CController *m_pInstance; + static Ecore_Timer *m_pPing; + + static const double m_nPingInterval; +}; + +/* End of a file */ diff --git a/sample/org.tizen.live-app/include/CMain.h b/sample/org.tizen.live-app/include/CMain.h new file mode 100644 index 0000000..62077ae --- /dev/null +++ b/sample/org.tizen.live-app/include/CMain.h @@ -0,0 +1,16 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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/sample/org.tizen.live-app/include/CModel.h b/sample/org.tizen.live-app/include/CModel.h new file mode 100644 index 0000000..daf8f44 --- /dev/null +++ b/sample/org.tizen.live-app/include/CModel.h @@ -0,0 +1,34 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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. + */ + +class CModel { +public: + /*! \TODO: Fill me */ + static CModel *GetInstance(); + + void *GetTaggedObject(const char *tag); + int AddTaggedObject(const char *tag, void *object); + void *DelTaggedObject(const char *tag); + +private: + CModel(void); + virtual ~CModel(void); + + static CModel *m_pInstance; + Eina_List *m_pList; +}; + +/* End of a file */ diff --git a/sample/org.tizen.live-app/include/CView.h b/sample/org.tizen.live-app/include/CView.h new file mode 100644 index 0000000..df8852c --- /dev/null +++ b/sample/org.tizen.live-app/include/CView.h @@ -0,0 +1,35 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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. + */ + +class CView { +public: + /*! \TODO: fill me */ + static CView *Create(CWindow *win); + int Destroy(void); + + void ResetLayout(void); + +private: + CView(void); + virtual ~CView(void); + + int InitLayout(void); + + CWindow *m_pWindow; + Evas_Object *m_pScroller; +}; + +/* End of a file */ diff --git a/sample/org.tizen.live-app/include/CWindow.h b/sample/org.tizen.live-app/include/CWindow.h new file mode 100644 index 0000000..73a6084 --- /dev/null +++ b/sample/org.tizen.live-app/include/CWindow.h @@ -0,0 +1,58 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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. + */ + +class CWindow { +public: + static CWindow *Find(enum target_type type, const char *id); + static CWindow *Create(enum target_type type, const char *id, int w, int h); + + static void *s_AllocateCanvas(void *data, int size); + static void s_ReleaseCanvas(void *data, void *canvas); + static void s_PostRender(void *data, Evas *e, void *event_info); + static int s_BufferEventHandler(struct livebox_buffer *buffer, enum buffer_event event, double timestamp, double x, double y, void *data); + + int Destroy(void); + int Resize(int w, int h); + + void SetBuffer(struct livebox_buffer *pBuffer) { m_pBuffer = pBuffer; } + enum target_type Type(void) { return m_vType; } + int Width(void) { return m_nWidth; } + int Height(void) { return m_nHeight; } + struct livebox_buffer *Buffer(void) { return m_pBuffer; } + Evas_Object *Object(void) { return m_pObject; } + const char *Id(void) { return m_sID; } + Evas *EvasObject(void) { return m_pEvas; } + +private: + CWindow(enum target_type type, int width, int height); + virtual ~CWindow(void); + + enum target_type m_vType; + int m_nWidth; + int m_nHeight; + + struct livebox_buffer *m_pBuffer; + + Ecore_Evas *m_pEcoreEvas; + Evas *m_pEvas; + Evas_Object *m_pObject; + + char *m_sID; + + static Eina_List *s_pList; +}; + +/* End of a file */ diff --git a/sample/org.tizen.live-app/include/debug.h b/sample/org.tizen.live-app/include/debug.h new file mode 100644 index 0000000..6e436ce --- /dev/null +++ b/sample/org.tizen.live-app/include/debug.h @@ -0,0 +1,28 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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...) LOGD("[%s/%s:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg) +#define ErrPrint(format, arg...) LOGE("[%s/%s:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg) +#else +extern FILE *__file_log_fp; +#define DbgPrint(format, arg...) do { fprintf(__file_log_fp, "[LOG] [%s/%s:%d] " format, 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, basename(__FILE__), __func__, __LINE__, ##arg); fflush(__file_log_fp); } while (0) +#endif + +/* End of a file */ + diff --git a/sample/org.tizen.live-app/org.tizen.live-app.conf b/sample/org.tizen.live-app/org.tizen.live-app.conf new file mode 100644 index 0000000..6d29a22 --- /dev/null +++ b/sample/org.tizen.live-app/org.tizen.live-app.conf @@ -0,0 +1,12 @@ +timeout=60 +period=20.0 +network=1 +auto_launch=0 +size=700x700;700x172;700x348;348x348;348x172;172x172 +group=user,created{default} +pd_size=720x240 +secured=0 +pinup=1 +buffer_livebox=1 +buffer_pd=1 +abi=app diff --git a/sample/org.tizen.live-app/org.tizen.live-app.xml b/sample/org.tizen.live-app/org.tizen.live-app.xml new file mode 100644 index 0000000..deb99cc --- /dev/null +++ b/sample/org.tizen.live-app/org.tizen.live-app.xml @@ -0,0 +1,10 @@ + + + + Sung-jae Park + Sample for an application style livebox + + org.tizen.live-app.png + + + diff --git a/sample/org.tizen.live-app/packaging/org.tizen.live-app.spec b/sample/org.tizen.live-app/packaging/org.tizen.live-app.spec new file mode 100644 index 0000000..7f8c26b --- /dev/null +++ b/sample/org.tizen.live-app/packaging/org.tizen.live-app.spec @@ -0,0 +1,46 @@ +Name: org.tizen.live-app +Summary: App style livebox +Version: 0.0.1 +Release: 1 +Group: main/app +License: Flora License +Source0: %{name}-%{version}.tar.gz +BuildRequires: cmake, gettext-tools +BuildRequires: pkgconfig(appcore-efl) +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(gio-2.0) +BuildRequires: pkgconfig(bundle) +BuildRequires: pkgconfig(provider) +BuildRequires: pkgconfig(ecore-x) +BuildRequires: pkgconfig(aul) +BuildRequires: pkgconfig(mm-player) + +%description +App style livebox content provider + +%prep +%setup -q + +%build +cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} +#-fpie LDFLAGS="${LDFLAGS} -pie -O3" +CFLAGS="-Wall -Winline -Werror -p -g" make %{?jobs:-j%jobs} +#${CFLAGS} + +%install +rm -rf %{buildroot} +%make_install + +%post +mkdir -p /opt/usr/live/org.tizen.live-app/libexec +touch /opt/usr/live/org.tizen.live-app/libexec/liblive-org.tizen.live-app.so + +%files -n org.tizen.live-app +#%manifest org.tizen.data-provider-slave.manifest +%defattr(-,root,root,-) +/opt/usr/apps/org.tizen.live-app/bin/live-app +/opt/share/packages/*.xml +/opt/usr/live/org.tizen.live-app/etc/* +/opt/usr/live/org.tizen.live-app/res/image/* +/opt/share/icons/default/small/*.png diff --git a/sample/org.tizen.live-app/res/image/org.zien.live-app.png b/sample/org.tizen.live-app/res/image/org.zien.live-app.png new file mode 100644 index 0000000000000000000000000000000000000000..125a01e093baad38aff22f63867dc6aa3f7b8cb7 GIT binary patch literal 25019 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 +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "debug.h" +#include "CWindow.h" +#include "CController.h" +#include "CView.h" +#include "CModel.h" + +CController *CController::m_pInstance = NULL; +Ecore_Timer *CController::m_pPing = NULL; +const double CController::m_nPingInterval = 120.0f; + +int CController::s_CreateLB(struct event_arg *arg, int *width, int *height, double *priority, void *data) +{ + CWindow *win; + CView *view; + int ret; + + *width = 348; + *height = 348; + arg->info.lb_create.out_content = NULL; + arg->info.lb_create.out_title = NULL; + + win = CWindow::Create(TYPE_LB, arg->id, *width, *height); + if (!win) + return -EFAULT; + + view = CView::Create(win); + if (!view) { + win->Destroy(); + return -EFAULT; + } + + ret = CModel::GetInstance()->AddTaggedObject(arg->id, view); + if (ret < 0) { + view->Destroy(); + win->Destroy(); + return ret; + } + + return 0; +} + +int CController::s_RecreateLB(struct event_arg *arg, void *data) +{ + CWindow *win; + CView *view; + int ret; + + win = CWindow::Create(TYPE_LB, arg->id, arg->info.lb_recreate.width, arg->info.lb_recreate.height); + if (!win) { + ErrPrint("Failed to create a window %s\n", arg->id); + return -EFAULT; + } + + view = CView::Create(win); + if (!view) { + ErrPrint("Failed to create a view %s\n", arg->id); + win->Destroy(); + return -EFAULT; + } + + ret = CModel::GetInstance()->AddTaggedObject(arg->id, view); + if (ret < 0) { + ErrPrint("Failed to add a view %s\n", arg->id); + view->Destroy(); + win->Destroy(); + return ret; + } + + return 0; +} + +int CController::s_DestroyLB(struct event_arg *arg, void *data) +{ + CWindow *win; + CView *view; + + view = (CView *)CModel::GetInstance()->DelTaggedObject(arg->id); + if (view) + view->Destroy(); + + win = CWindow::Find(TYPE_LB, arg->id); + if (win) + win->Destroy(); + + return 0; +} + +int CController::s_ContentEvent(struct event_arg *arg, void *data) +{ + CWindow *win; + + win = CWindow::Find(TYPE_LB, arg->id); + if (!win) + return -ENOENT; + + return 0; +} + +int CController::s_Clicked(struct event_arg *arg, void *data) +{ + CWindow *win; + + win = CWindow::Find(TYPE_LB, arg->id); + if (!win) + return -ENOENT; + + return 0; +} + +int CController::s_TextEvent(struct event_arg *arg, void *data) +{ + CWindow *win; + + win = CWindow::Find(TYPE_LB, arg->id); + if (!win) + return -ENOENT; + + return 0; +} + +int CController::s_Resize(struct event_arg *arg, void *data) +{ + CWindow *win; + + win = CWindow::Find(TYPE_LB, arg->id); + if (!win) + return -ENOENT; + + win->Resize(arg->info.resize.w, arg->info.resize.h); + return 0; +} + +int CController::s_SetPeriod(struct event_arg *arg, void *data) +{ + CWindow *win; + + win = CWindow::Find(TYPE_LB, arg->id); + if (!win) + return -ENOENT; + + return 0; +} + +int CController::s_ChangeGroup(struct event_arg *arg, void *data) +{ + CWindow *win; + + win = CWindow::Find(TYPE_LB, arg->id); + if (!win) + return -ENOENT; + + return 0; +} + +int CController::s_Pinup(struct event_arg *arg, void *data) +{ + CWindow *win; + + win = CWindow::Find(TYPE_LB, arg->id); + if (!win) + return -ENOENT; + + return 0; +} + +int CController::s_UpdateContent(struct event_arg *arg, void *data) +{ + CWindow *win; + + win = CWindow::Find(TYPE_LB, arg->id); + if (!win) + return -ENOENT; + + return 0; +} + +int CController::s_Pause(struct event_arg *arg, void *data) +{ + if (m_pPing) + ecore_timer_freeze(m_pPing); + + return 0; +} + +int CController::s_Resume(struct event_arg *arg, void *data) +{ + if (m_pPing) + ecore_timer_thaw(m_pPing); + + return 0; +} + +int CController::s_Disconnected(struct event_arg *arg, void *data) +{ + if (m_pPing) { + ecore_timer_del(m_pPing); + m_pPing = NULL; + } + + delete m_pInstance; + aul_terminate_pid(getpid()); + return 0; +} + +Eina_Bool CController::s_PingHandler(void *data) +{ + DbgPrint("Send ping\n"); + provider_send_ping(); + return ECORE_CALLBACK_RENEW; +} + +int CController::s_Connected(struct event_arg *arg, void *data) +{ + int ret; + + if (m_pPing) { + DbgPrint("Already connected\n"); + return -EINVAL; + } + + /*! + * \note + * Phase 2. Send "hello" signal to master + * Add "ping" timer (Master will wait 240 seconds) + */ + ret = provider_send_hello(); + if (ret < 0) { + ErrPrint("Failed to send a ping(%d)\n", ret); + return -EFAULT; + } + + m_pPing = ecore_timer_add(m_nPingInterval, s_PingHandler, NULL); + if (!m_pPing) + ErrPrint("Failed to add a ping timer\n"); + + DbgPrint("Connected\n"); + return 0; +} + +int CController::s_CreatePD(struct event_arg *arg, void *data) +{ + CWindow *win; + CView *view; + int ret; + char *tagname; + + win = CWindow::Create(TYPE_PD, arg->id, arg->info.pd_create.w, arg->info.pd_create.h); + if (!win) { + ErrPrint("Failed to create a PD\n"); + return -EFAULT; + } + + view = CView::Create(win); + if (!view) { + ErrPrint("Failed to create a view\n"); + win->Destroy(); + return -EFAULT; + } + + ret = strlen(arg->id); /* reuse ret */ + tagname = (char *)malloc(ret + strlen(",pd,view") + 1); + if (!tagname) { + ErrPrint("Heap: %s\n", strerror(errno)); + win->Destroy(); + return -EFAULT; + } + + strcpy(tagname, arg->id); + strcpy(tagname + ret, ",pd,view"); + DbgPrint("TAGNAME: %s\n", tagname); + + ret = CModel::GetInstance()->AddTaggedObject(tagname, view); + free(tagname); + if (ret < 0) { + DbgPrint("Failed to add a tagged object\n"); + view->Destroy(); + win->Destroy(); + return ret; + } + + DbgPrint("PD is created\n"); + return 0; +} + +int CController::s_DestroyPD(struct event_arg *arg, void *data) +{ + CWindow *win; + CView *view; + int ret; + char *tagname; + + win = CWindow::Find(TYPE_PD, arg->id); + if (!win) { + ErrPrint("Failed to find a window (%s)\n", arg->id); + return -ENOENT; + } + + ret = strlen(arg->id); + tagname = (char *)malloc(ret + strlen(",pd,view") + 1); + if (!tagname) { + ErrPrint("Heap: %s\n", strerror(errno)); + return -ENOMEM; + } + + strcpy(tagname, arg->id); + strcpy(tagname + ret, ",pd,view"); + + view = (CView *)CModel::GetInstance()->DelTaggedObject(tagname); + free(tagname); + if (view) { + DbgPrint("Destroy VIEW\n"); + view->Destroy(); + } + + DbgPrint("Destroy WIN\n"); + win->Destroy(); + return 0; +} + +CController::CController(void) +: m_sName(NULL) +{ +} + +CController::~CController(void) +{ + free(m_sName); + m_sName = NULL; + + m_pInstance = NULL; + + if (m_pPing) { + ecore_timer_del(m_pPing); + m_pPing = NULL; + } +} + +int CController::Initialize(const char *name) +{ + int ret; + struct event_handler table; + + DbgPrint("Initialize %s\n", name); + + if (CController::m_pInstance) { + ErrPrint("Controller is already exists\n"); + return -EALREADY; + } + + try { + m_pInstance = new CController(); + } catch (...) { + ErrPrint("Failed to create a controller\n"); + return -ENOMEM; + } + + m_pInstance->m_sName = strdup(name); + if (!m_pInstance->m_sName) { + ErrPrint("Heap: %s\n", strerror(errno)); + delete m_pInstance; + return -ENOMEM; + } + + table.lb_create = CController::s_CreateLB; + table.lb_recreate = CController::s_RecreateLB; + table.lb_destroy = CController::s_DestroyLB; + table.content_event = CController::s_ContentEvent; + table.clicked = CController::s_Clicked; + table.text_signal = CController::s_TextEvent; + table.resize = CController::s_Resize; + table.set_period = CController::s_SetPeriod; + table.change_group = CController::s_ChangeGroup; + table.pinup = CController::s_Pinup; + table.update_content = CController::s_UpdateContent; + table.pause = CController::s_Pause; + table.resume = CController::s_Resume; + table.disconnected = CController::s_Disconnected; + table.connected = CController::s_Connected; + table.pd_create = CController::s_CreatePD; + table.pd_destroy = CController::s_DestroyPD; + + DbgPrint("Slave name is %s\n", m_pInstance->m_sName); + ret = provider_init(ecore_x_display_get(), m_pInstance->m_sName, &table, NULL); + if (ret < 0) { + ErrPrint("Failed to initialize the provider %d\n", ret); + delete m_pInstance; + return ret; + } + + return 0; +} + +int CController::Finalize(void) +{ + if (!m_pInstance) + return -EINVAL; + + provider_fini(); + delete m_pInstance; + return 0; +} + +/* End of a file */ diff --git a/sample/org.tizen.live-app/src/CMain.cpp b/sample/org.tizen.live-app/src/CMain.cpp new file mode 100644 index 0000000..815b085 --- /dev/null +++ b/sample/org.tizen.live-app/src/CMain.cpp @@ -0,0 +1,81 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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 "debug.h" +#include "CController.h" + +static int app_create(void *data) +{ + return 0; +} + +static int app_terminate(void *data) +{ + return CController::Finalize(); +} + +static int app_pause(void *data) +{ + return 0; +} + +static int app_resume(void *data) +{ + return 0; +} + +static int app_reset(bundle *b, void *data) +{ + const char *name; + + name = bundle_get_val(b, "name"); + if (!name) { + ErrPrint("Name is not valid\n"); + elm_exit(); + return -EINVAL; + } + + return CController::Initialize(name); +} + +int main(int argc, char *argv[]) +{ + struct appcore_ops ops; + + ops.create = app_create; + ops.terminate = app_terminate; + ops.pause = app_pause; + ops.resume = app_resume; + ops.reset = app_reset; + ops.data = NULL; + + return appcore_efl_main(basename(argv[0]), &argc, &argv, &ops); +} + +/* End of a file */ diff --git a/sample/org.tizen.live-app/src/CModel.cpp b/sample/org.tizen.live-app/src/CModel.cpp new file mode 100644 index 0000000..6869d1e --- /dev/null +++ b/sample/org.tizen.live-app/src/CModel.cpp @@ -0,0 +1,118 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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 "debug.h" +#include "CModel.h" + +struct TItem { +/* public: */ + char *tag; + void *data; +}; + +CModel *CModel::m_pInstance = NULL; + +CModel::CModel(void) +: m_pList(NULL) +{ +} + +CModel::~CModel(void) +{ +} + +CModel *CModel::GetInstance() +{ + if (m_pInstance) + return m_pInstance; + + try { + m_pInstance = new CModel(); + } catch (...) { + return NULL; + } + + return m_pInstance; +} + +void *CModel::GetTaggedObject(const char *tag) +{ + Eina_List *l; + void *ptr; + TItem *item; + + EINA_LIST_FOREACH(m_pList, l, ptr) { + item = (TItem *)ptr; + if (!strcmp(item->tag, tag)) + return item->data; + } + + return NULL; +} + +int CModel::AddTaggedObject(const char *tag, void *object) +{ + TItem *item; + + try { + item = new TItem(); + } catch (...) { + return -ENOMEM; + } + + item->tag = strdup(tag); + if (!item->tag) { + delete item; + return -ENOMEM; + } + + item->data = object; + + m_pList = eina_list_append(m_pList, item); + return 0; +} + +void *CModel::DelTaggedObject(const char *tag) +{ + Eina_List *l; + Eina_List *n; + void *ptr; + TItem *item; + + EINA_LIST_FOREACH_SAFE(m_pList, l, n, ptr) { + item = (TItem *)ptr; + if (!strcmp(item->tag, tag)) { + void *ret; + m_pList = eina_list_remove(m_pList, ptr); + + ret = item->data; + free(item->tag); + free(item); + + return ret; + } + } + + return NULL; +} + +/* End of a file */ diff --git a/sample/org.tizen.live-app/src/CView.cpp b/sample/org.tizen.live-app/src/CView.cpp new file mode 100644 index 0000000..7065bf0 --- /dev/null +++ b/sample/org.tizen.live-app/src/CView.cpp @@ -0,0 +1,117 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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 "debug.h" +#include "CWindow.h" +#include "CView.h" + +CView::CView(void) +: m_pWindow(NULL) +, m_pScroller(NULL) +{ +} + +CView::~CView(void) +{ +} + +static void del_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + CView *view = (CView *)data; + + view->ResetLayout(); +} + +void CView::ResetLayout(void) +{ + m_pScroller = NULL; +} + +int CView::InitLayout(void) +{ + Evas_Object *pScroller; + Evas_Object *pIcon; + char sTitle[256]; + int w; + int h; + int i; + + pScroller = elm_list_add(m_pWindow->Object()); + if (!pScroller) + return -EFAULT; + + evas_object_geometry_get(m_pWindow->Object(), NULL, NULL, &w, &h); + evas_object_size_hint_weight_set(pScroller, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_list_multi_select_set(pScroller, EINA_FALSE); + elm_list_mode_set(pScroller, ELM_LIST_COMPRESS); + elm_scroller_bounce_set(pScroller, EINA_TRUE, EINA_FALSE); + evas_object_resize(pScroller, w, h); + evas_object_move(pScroller, 0, 0); + evas_object_show(pScroller); + + for (i = 0; i < 100; i++) { + pIcon = elm_icon_add(m_pWindow->Object()); + elm_icon_file_set(pIcon, "/opt/usr/live/org.tizen.live-app/res/image/unknown.png", NULL); + elm_icon_resizable_set(pIcon, 1, 1); + snprintf(sTitle, sizeof(sTitle), "%d List item: %d", i, i); + elm_list_item_append(pScroller, sTitle, pIcon, NULL /* end */, NULL, NULL); + } + + elm_list_go(pScroller); + m_pScroller = pScroller; + evas_object_event_callback_add(m_pScroller, EVAS_CALLBACK_DEL, del_cb, this); + return 0; +} + +CView *CView::Create(CWindow *win) +{ + CView *pInst; + + if (!win) + return NULL; + + try { + pInst = new CView(); + } catch (...) { + return NULL; + } + + pInst->m_pWindow = win; + pInst->InitLayout(); + return pInst; +} + +int CView::Destroy(void) +{ + if (m_pScroller) { + evas_object_del(m_pScroller); + m_pScroller = NULL; + } + + delete this; + return 0; +} + +/* End of a file */ diff --git a/sample/org.tizen.live-app/src/CWindow.cpp b/sample/org.tizen.live-app/src/CWindow.cpp new file mode 100644 index 0000000..f1ae120 --- /dev/null +++ b/sample/org.tizen.live-app/src/CWindow.cpp @@ -0,0 +1,226 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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 "debug.h" +#include "CWindow.h" + +Eina_List *CWindow::s_pList = NULL; + +void *CWindow::s_AllocateCanvas(void *data, int size) +{ + CWindow *win = (CWindow *)data; + struct livebox_buffer *pBuffer; + void *canvas; + + pBuffer = provider_buffer_acquire(win->Type(), PKGNAME, win->Id(), + win->Width(), win->Height(), sizeof(int), + CWindow::s_BufferEventHandler, win); + + if (!pBuffer) + return NULL; + + win->SetBuffer(pBuffer); + canvas = provider_buffer_ref(win->Buffer()); + return canvas; +} + +void CWindow::s_ReleaseCanvas(void *data, void *canvas) +{ + int ret; + CWindow *win = (CWindow *)data; + + ret = provider_buffer_unref(canvas); + DbgPrint("Unref %d\n", ret); + + ret = provider_buffer_release(win->Buffer()); + DbgPrint("release %d\n", ret); + + win->SetBuffer(NULL); +} + +void CWindow::s_PostRender(void *data, Evas *e, void *event_info) +{ + CWindow *win = (CWindow *)data; + + if (win->EvasObject() != e) + return; + + switch (win->Type()) { + case TYPE_PD: + provider_buffer_sync(win->Buffer()); + provider_send_desc_updated(PKGNAME, win->Id(), NULL); + break; + case TYPE_LB: + provider_buffer_sync(win->Buffer()); + provider_send_updated(PKGNAME, win->Id(), win->Width(), win->Height(), 1.0f, NULL, NULL); + break; + default: + break; + } +} + +int CWindow::s_BufferEventHandler(struct livebox_buffer *buffer, enum buffer_event event, double timestamp, double x, double y, void *data) +{ + CWindow *win = (CWindow *)data; + int ix; + int iy; + + ix = win->Width() * x; + iy = win->Height() * y; + + DbgPrint("POS(%dx%d)\n", ix, iy); + + switch (event) { + case BUFFER_EVENT_ENTER: + evas_event_feed_mouse_in(win->EvasObject(), timestamp, NULL); + break; + case BUFFER_EVENT_LEAVE: + evas_event_feed_mouse_out(win->EvasObject(), timestamp, NULL); + break; + case BUFFER_EVENT_DOWN: + //evas_event_feed_mouse_in(win->EvasObject(), timestamp, NULL); + evas_event_feed_mouse_move(win->EvasObject(), ix, iy, timestamp + 0.01f, NULL); + evas_event_feed_mouse_down(win->EvasObject(), 1, EVAS_BUTTON_NONE, timestamp + 0.02f, NULL); + break; + case BUFFER_EVENT_MOVE: + evas_event_feed_mouse_move(win->EvasObject(), ix, iy, timestamp, NULL); + break; + case BUFFER_EVENT_UP: + evas_event_feed_mouse_up(win->EvasObject(), 1, EVAS_BUTTON_NONE, timestamp, NULL); + //evas_event_feed_mouse_out(win->EvasObject(), timestamp + 0.01f, NULL); + break; + default: + break; + } + + return 0; +} + +CWindow *CWindow::Create(enum target_type type, const char *id, int w, int h) +{ + CWindow *win; + + try { + win = new CWindow(type, w, h); + } catch (...) { + return NULL; + } + + win->m_sID = strdup(id); + if (!win->m_sID) { + win->Destroy(); + return NULL; + } + + win->m_pEcoreEvas = ecore_evas_buffer_allocfunc_new(win->m_nWidth, win->m_nHeight, CWindow::s_AllocateCanvas, CWindow::s_ReleaseCanvas, win); + if (!win->m_pEcoreEvas) { + ErrPrint("Failed to allocate a new EE\n"); + win->Destroy(); + return NULL; + } + + win->m_pEvas = ecore_evas_get(win->m_pEcoreEvas); + if (!win->m_pEvas) { + win->Destroy(); + return NULL; + } + + evas_event_callback_add(win->m_pEvas, EVAS_CALLBACK_RENDER_FLUSH_POST, s_PostRender, win); + + ecore_evas_alpha_set(win->m_pEcoreEvas, EINA_TRUE); + ecore_evas_manual_render_set(win->m_pEcoreEvas, EINA_FALSE); + ecore_evas_resize(win->m_pEcoreEvas, win->m_nWidth, win->m_nHeight); + ecore_evas_show(win->m_pEcoreEvas); + ecore_evas_activate(win->m_pEcoreEvas); + + win->m_pObject = evas_object_rectangle_add(win->m_pEvas); + evas_object_resize(win->m_pObject, win->m_nWidth, win->m_nHeight); + evas_object_color_set(win->m_pObject, 0, 0, 0, 255); + evas_object_show(win->m_pObject); + + s_pList = eina_list_append(s_pList, win); + return win; +} + +CWindow *CWindow::Find(enum target_type type, const char *id) +{ + Eina_List *l; + void *item; + CWindow *win; + + EINA_LIST_FOREACH(s_pList, l, item) { + win = (CWindow *)item; + + if (win->Type() == type && !strcmp(win->Id(), id)) + return win; + } + + return NULL; +} + +int CWindow::Destroy(void) +{ + s_pList = eina_list_remove(s_pList, this); + + if (m_pObject) + evas_object_del(m_pObject); + + if (m_pEcoreEvas) + ecore_evas_free(m_pEcoreEvas); + + free(m_sID); + delete this; + return 0; +} + +int CWindow::Resize(int w, int h) +{ + m_nWidth = w; + m_nHeight = h; + + if (m_pEcoreEvas) + ecore_evas_resize(m_pEcoreEvas, w, h); + + return 0; +} + +CWindow::CWindow(enum target_type type, int width, int height) +: m_vType(type) +, m_nWidth(width) +, m_nHeight(height) +, m_pBuffer(NULL) +, m_pEcoreEvas(NULL) +, m_pEvas(NULL) +, m_sID(NULL) +{ +} + +CWindow::~CWindow(void) +{ +} + +/* End of a file */ diff --git a/sample/org.tizen.live-video/CMakeLists.txt b/sample/org.tizen.live-video/CMakeLists.txt new file mode 100644 index 0000000..3d7832c --- /dev/null +++ b/sample/org.tizen.live-video/CMakeLists.txt @@ -0,0 +1,52 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(live-video CXX) + +INCLUDE(FindPkgConfig) +pkg_check_modules(pkg REQUIRED + dlog + glib-2.0 + gio-2.0 + appcore-efl + bundle + provider + aul + ecore-x + ecore + x11 + xdamage + mm-player + libdrm + libdrm_slp + libdri2 +) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include) + +ADD_DEFINITIONS("-DNDEBUG") +ADD_DEFINITIONS("-DLOG_TAG=\"${PROJECT_NAME}\"") +ADD_DEFINITIONS("-DPKGNAME=\"org.tizen.${PROJECT_NAME}\"") +ADD_DEFINITIONS(${pkg_CFLAGS}) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Winline -Werror -g") + +ADD_EXECUTABLE(${PROJECT_NAME} + src/CMain.cpp + src/CWindow.cpp + src/CController.cpp + src/CView.cpp + src/CModel.cpp + src/CVideo.cpp +) + +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkg_LDFLAGS} "-ldl") +INSTALL(FILES ${CMAKE_SOURCE_DIR}/org.tizen.${PROJECT_NAME}.xml DESTINATION /opt/share/packages) +INSTALL(FILES ${CMAKE_SOURCE_DIR}/org.tizen.${PROJECT_NAME}.conf DESTINATION /opt/usr/live/org.tizen.${PROJECT_NAME}/etc) +INSTALL(FILES ${CMAKE_SOURCE_DIR}/res/image/unknown.png DESTINATION /opt/usr/live/org.tizen.${PROJECT_NAME}/res/image) +INSTALL(FILES ${CMAKE_SOURCE_DIR}/res/image/org.tizen.live-video.png DESTINATION /opt/share/icons/default/small) +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION + /opt/usr/apps/org.tizen.${PROJECT_NAME}/bin + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE) + +# End of a file diff --git a/sample/org.tizen.live-video/include/CController.h b/sample/org.tizen.live-video/include/CController.h new file mode 100644 index 0000000..7647676 --- /dev/null +++ b/sample/org.tizen.live-video/include/CController.h @@ -0,0 +1,53 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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. + */ + +class CController { +public: + static int Initialize(const char *name); + static int Finalize(void); + + static int s_CreateLB(struct event_arg *arg, int *width, int *height, double *priority, void *data); + static int s_RecreateLB(struct event_arg *arg, void *data); + static int s_DestroyLB(struct event_arg *arg, void *data); + static int s_ContentEvent(struct event_arg *arg, void *data); + static int s_Clicked(struct event_arg *arg, void *data); + static int s_TextEvent(struct event_arg *arg, void *data); + static int s_Resize(struct event_arg *arg, void *data); + static int s_SetPeriod(struct event_arg *arg, void *data); + static int s_ChangeGroup(struct event_arg *arg, void *data); + static int s_Pinup(struct event_arg *arg, void *data); + static int s_UpdateContent(struct event_arg *arg, void *data); + static int s_Pause(struct event_arg *arg, void *data); + static int s_Resume(struct event_arg *arg, void *data); + static int s_Disconnected(struct event_arg *arg, void *data); + static int s_Connected(struct event_arg *arg, void *data); + static int s_CreatePD(struct event_arg *arg, void *data); + static int s_DestroyPD(struct event_arg *arg, void *data); + static Eina_Bool s_PingHandler(void *data); + +private: + CController(void); + virtual ~CController(void); + + char *m_sName; + + static CController *m_pInstance; + static Ecore_Timer *m_pPing; + + static const double m_nPingInterval; +}; + +/* End of a file */ diff --git a/sample/org.tizen.live-video/include/CMain.h b/sample/org.tizen.live-video/include/CMain.h new file mode 100644 index 0000000..62077ae --- /dev/null +++ b/sample/org.tizen.live-video/include/CMain.h @@ -0,0 +1,16 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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/sample/org.tizen.live-video/include/CModel.h b/sample/org.tizen.live-video/include/CModel.h new file mode 100644 index 0000000..1c879cf --- /dev/null +++ b/sample/org.tizen.live-video/include/CModel.h @@ -0,0 +1,33 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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. + */ + +class CModel { +public: + static CModel *GetInstance(void); + const char *VideoFilename(void); + int SetVideoFilename(const char *filename); + + /*! \TODO: Fill me */ + +private: + CModel(void); + virtual ~CModel(void); + + static CModel *m_pInstance; + char *m_sFilename; +}; + +/* End of a file */ diff --git a/sample/org.tizen.live-video/include/CVideo.h b/sample/org.tizen.live-video/include/CVideo.h new file mode 100644 index 0000000..fdccd8e --- /dev/null +++ b/sample/org.tizen.live-video/include/CVideo.h @@ -0,0 +1,68 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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. + */ + +class CVideo { +public: + enum TVideoState { + STOPPED = 0x00, + PLAYING = 0x01, + }; + + static CVideo *Find(enum target_type type, const char *id); + static CVideo *Create(enum target_type type, const char *id, int w, int h); + + static int s_BufferEventHandler(struct livebox_buffer *buffer, enum buffer_event event, double timestamp, double x, double y, void *data); + static Eina_Bool s_DamageEventHandler(void *data, int type, void *event); + static int s_MMMessageHandler(int message, void *_param, void *user_param); + + int Destroy(void); + int Resize(int w, int h); + + void SetBuffer(struct livebox_buffer *pBuffer); + enum target_type Type(void) { return m_vType; } + int Width(void) { return m_nWidth; } + int Height(void) { return m_nHeight; } + struct livebox_buffer *Buffer(void) { return m_pBuffer; } + const char *Id(void) { return m_sId; } + int PixmapId(void) { return m_nId; } + + int Play(const char *file); + int Stop(void); + enum TVideoState State(void); +private: + CVideo(enum target_type type, int width, int height); + virtual ~CVideo(void); + + int Update(void); + void Clear(void); + + enum TVideoState m_vState; + enum target_type m_vType; + int m_nWidth; + int m_nHeight; + + struct livebox_buffer *m_pBuffer; + + int m_nId; /*!< Pixmap ID */ + char *m_sId; + Ecore_X_Damage m_vDamage; + + char *m_sError; + MMHandleType m_vPlayer; + + static Eina_List *s_pList; + Ecore_Event_Handler *m_pDamageHandler; +}; diff --git a/sample/org.tizen.live-video/include/CView.h b/sample/org.tizen.live-video/include/CView.h new file mode 100644 index 0000000..8a63836 --- /dev/null +++ b/sample/org.tizen.live-video/include/CView.h @@ -0,0 +1,25 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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. + */ + +class CView { +public: + /*! \TODO: fill me */ +private: + CView(void); + virtual ~CView(void); +}; + +/* End of a file */ diff --git a/sample/org.tizen.live-video/include/CWindow.h b/sample/org.tizen.live-video/include/CWindow.h new file mode 100644 index 0000000..917d562 --- /dev/null +++ b/sample/org.tizen.live-video/include/CWindow.h @@ -0,0 +1,58 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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. + */ + +class CWindow { +public: + static CWindow *Find(enum target_type type, const char *id); + static CWindow *Create(enum target_type type, const char *id, int w, int h); + + static void *s_AllocateCanvas(void *data, int size); + static void s_ReleaseCanvas(void *data, void *canvas); + static void s_PostRender(void *data, Evas *e, void *event_info); + static int s_BufferEventHandler(struct livebox_buffer *buffer, enum buffer_event event, double timestamp, double x, double y, void *data); + + virtual ~CWindow(void); + int Destroy(void); + int Resize(int w, int h); + + void SetBuffer(struct livebox_buffer *pBuffer) { m_pBuffer = pBuffer; } + enum target_type Type(void) { return m_vType; } + int Width(void) { return m_nWidth; } + int Height(void) { return m_nHeight; } + struct livebox_buffer *Buffer(void) { return m_pBuffer; } + Evas_Object *Object(void) { return m_pObject; } + const char *Id(void) { return m_sID; } + Evas *EvasObject(void) { return m_pEvas; } + +private: + CWindow(enum target_type type, int width, int height); + + enum target_type m_vType; + int m_nWidth; + int m_nHeight; + + struct livebox_buffer *m_pBuffer; + + Ecore_Evas *m_pEcoreEvas; + Evas *m_pEvas; + Evas_Object *m_pObject; + + char *m_sID; + + static Eina_List *s_pList; +}; + +/* End of a file */ diff --git a/sample/org.tizen.live-video/include/debug.h b/sample/org.tizen.live-video/include/debug.h new file mode 100644 index 0000000..6e436ce --- /dev/null +++ b/sample/org.tizen.live-video/include/debug.h @@ -0,0 +1,28 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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...) LOGD("[%s/%s:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg) +#define ErrPrint(format, arg...) LOGE("[%s/%s:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg) +#else +extern FILE *__file_log_fp; +#define DbgPrint(format, arg...) do { fprintf(__file_log_fp, "[LOG] [%s/%s:%d] " format, 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, basename(__FILE__), __func__, __LINE__, ##arg); fflush(__file_log_fp); } while (0) +#endif + +/* End of a file */ + diff --git a/sample/org.tizen.live-video/org.tizen.live-video.conf b/sample/org.tizen.live-video/org.tizen.live-video.conf new file mode 100644 index 0000000..6d29a22 --- /dev/null +++ b/sample/org.tizen.live-video/org.tizen.live-video.conf @@ -0,0 +1,12 @@ +timeout=60 +period=20.0 +network=1 +auto_launch=0 +size=700x700;700x172;700x348;348x348;348x172;172x172 +group=user,created{default} +pd_size=720x240 +secured=0 +pinup=1 +buffer_livebox=1 +buffer_pd=1 +abi=app diff --git a/sample/org.tizen.live-video/org.tizen.live-video.xml b/sample/org.tizen.live-video/org.tizen.live-video.xml new file mode 100644 index 0000000..b2eedc7 --- /dev/null +++ b/sample/org.tizen.live-video/org.tizen.live-video.xml @@ -0,0 +1,10 @@ + + + + Sung-jae Park + Application based livebox media player + + org.tizen.live-video.png + + + diff --git a/sample/org.tizen.live-video/packaging/org.tizen.live-video.spec b/sample/org.tizen.live-video/packaging/org.tizen.live-video.spec new file mode 100644 index 0000000..199cf73 --- /dev/null +++ b/sample/org.tizen.live-video/packaging/org.tizen.live-video.spec @@ -0,0 +1,52 @@ +Name: org.tizen.live-video +Summary: Video playing livebox +Version: 0.0.1 +Release: 1 +Group: main/app +License: Flora License +Source0: %{name}-%{version}.tar.gz +BuildRequires: cmake, gettext-tools +BuildRequires: pkgconfig(appcore-efl) +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(gio-2.0) +BuildRequires: pkgconfig(bundle) +BuildRequires: pkgconfig(provider) +BuildRequires: pkgconfig(ecore-x) +BuildRequires: pkgconfig(aul) +BuildRequires: pkgconfig(mm-player) +BuildRequires: pkgconfig(ecore) +BuildRequires: pkgconfig(x11) +BuildRequires: pkgconfig(xdamage) +BuildRequires: pkgconfig(libdrm) +BuildRequires: pkgconfig(libdrm_slp) +BuildRequires: pkgconfig(libdri2) + +%description +App style livebox content provider (video) + +%prep +%setup -q + +%build +cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} +#-fpie LDFLAGS="${LDFLAGS} -pie -O3" +CFLAGS="-Wall -Winline -Werror -p -g" make %{?jobs:-j%jobs} +#${CFLAGS} + +%install +rm -rf %{buildroot} +%make_install + +%post +mkdir -p /opt/usr/live/org.tizen.live-video/libexec +touch /opt/usr/live/org.tizen.live-video/libexec/liblive-org.tizen.live-video.so + +%files -n org.tizen.live-video +#%manifest org.tizen.data-provider-slave.manifest +%defattr(-,root,root,-) +/opt/usr/apps/org.tizen.live-video/bin/live-video +/opt/share/packages/*.xml +/opt/usr/live/org.tizen.live-video/etc/* +/opt/usr/live/org.tizen.live-video/res/image/* +/opt/share/icons/default/small/*.png diff --git a/sample/org.tizen.live-video/res/image/org.tizen.live-video.png b/sample/org.tizen.live-video/res/image/org.tizen.live-video.png new file mode 100644 index 0000000000000000000000000000000000000000..b92ba1dad99b5bd7cd407ffc324f70c44b6b460e GIT binary patch literal 2782 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 literal 0 HcmV?d00001 diff --git a/sample/org.tizen.live-video/res/image/unknown.png b/sample/org.tizen.live-video/res/image/unknown.png new file mode 100644 index 0000000000000000000000000000000000000000..b3edcd8c326557d3a83c6a242a6c0831a7d8d933 GIT binary patch literal 53400 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include "debug.h" +#include "CVideo.h" +#include "CWindow.h" +#include "CController.h" +#include "CModel.h" + +CController *CController::m_pInstance = NULL; +Ecore_Timer *CController::m_pPing = NULL; +const double CController::m_nPingInterval = 120.0f; + +struct TWindowData { + Evas_Object *list; + char *id; +}; + +int CController::s_CreateLB(struct event_arg *arg, int *width, int *height, double *priority, void *data) +{ + CVideo *video; + + *width = 348; + *height = 348; + arg->info.lb_create.out_content = NULL; + arg->info.lb_create.out_title = NULL; + + DbgPrint("Content: %s\n", arg->info.lb_create.content); + + video = CVideo::Create(TYPE_LB, arg->id, *width, *height); + if (!video) + return -EFAULT; + + return 0; +} + +int CController::s_RecreateLB(struct event_arg *arg, void *data) +{ + CVideo *video; + + DbgPrint("Content: %s\n", arg->info.lb_recreate.content); + + video = CVideo::Create(TYPE_LB, arg->id, arg->info.lb_recreate.width, arg->info.lb_recreate.height); + if (!video) + return -EFAULT; + + return 0; +} + +int CController::s_DestroyLB(struct event_arg *arg, void *data) +{ + CVideo *video; + CWindow *win; + + video = CVideo::Find(TYPE_LB, arg->id); + if (video) + video->Destroy(); + + win = CWindow::Find(TYPE_PD, arg->id); + if (win) + win->Destroy(); + + return 0; +} + +int CController::s_ContentEvent(struct event_arg *arg, void *data) +{ + CVideo *video; + + video = CVideo::Find(TYPE_LB, arg->id); + if (!video) + return -ENOENT; + + return 0; +} + +int CController::s_Clicked(struct event_arg *arg, void *data) +{ + CVideo *video; + + video = CVideo::Find(TYPE_LB, arg->id); + if (!video) { + ErrPrint("Instance is not found: %s\n", arg->id); + return -ENOENT; + } + + switch (video->State()) { + case CVideo::PLAYING: + video->Stop(); + break; + case CVideo::STOPPED: + video->Play(CModel::GetInstance()->VideoFilename()); + break; + default: + break; + } + + return 0; +} + +int CController::s_TextEvent(struct event_arg *arg, void *data) +{ + CVideo *video; + + video = CVideo::Find(TYPE_LB, arg->id); + if (!video) + return -ENOENT; + + return 0; +} + +int CController::s_Resize(struct event_arg *arg, void *data) +{ + CVideo *video; + + video = CVideo::Find(TYPE_LB, arg->id); + if (!video) + return -ENOENT; + + video->Resize(arg->info.resize.w, arg->info.resize.h); + return 0; +} + +int CController::s_SetPeriod(struct event_arg *arg, void *data) +{ + CVideo *video; + + video = CVideo::Find(TYPE_LB, arg->id); + if (!video) + return -ENOENT; + + return 0; +} + +int CController::s_ChangeGroup(struct event_arg *arg, void *data) +{ + CVideo *video; + + video = CVideo::Find(TYPE_LB, arg->id); + if (!video) + return -ENOENT; + + return 0; +} + +int CController::s_Pinup(struct event_arg *arg, void *data) +{ + CVideo *video; + + video = CVideo::Find(TYPE_LB, arg->id); + if (!video) + return -ENOENT; + + return 0; +} + +int CController::s_UpdateContent(struct event_arg *arg, void *data) +{ + CVideo *video; + + video = CVideo::Find(TYPE_LB, arg->id); + if (!video) + return -ENOENT; + + return 0; +} + +int CController::s_Pause(struct event_arg *arg, void *data) +{ + if (m_pPing) + ecore_timer_freeze(m_pPing); + + return 0; +} + +int CController::s_Resume(struct event_arg *arg, void *data) +{ + if (m_pPing) + ecore_timer_thaw(m_pPing); + + return 0; +} + +int CController::s_Disconnected(struct event_arg *arg, void *data) +{ + if (m_pPing) { + ecore_timer_del(m_pPing); + m_pPing = NULL; + } + + aul_terminate_pid(getpid()); + return 0; +} + +Eina_Bool CController::s_PingHandler(void *data) +{ + provider_send_ping(); + return ECORE_CALLBACK_RENEW; +} + +int CController::s_Connected(struct event_arg *arg, void *data) +{ + if (m_pPing) + return -EINVAL; + + /*! + * \note + * Phase 2. Send "hello" signal to master + * Add "ping" timer (Master will wait 240 seconds) + */ + if (provider_send_hello() < 0) + return -EFAULT; + + m_pPing = ecore_timer_add(m_nPingInterval, s_PingHandler, NULL); + if (!m_pPing) + ErrPrint("Failed to add a ping timer\n"); + return 0; +} + +static void press_cb(void *data, Evas_Object *list, void *event_info) +{ + CVideo *video; + Elm_Object_Item *item; + const char *filename; + char *path; + int pathlen; + TWindowData *win_data = (TWindowData *)data; + + video = CVideo::Find(TYPE_LB, win_data->id); + if (!video) { + ErrPrint("Video is not exists\n"); + return; + } + + item = elm_list_selected_item_get(list); + if (!item) { + ErrPrint("Item is not selected\n"); + return; + } + + filename = elm_object_item_part_text_get(item, NULL); + if (!filename) { + ErrPrint("Selected item is not valid\n"); + return; + } + + pathlen = strlen(filename) + strlen("/opt/usr/media/Videos/") + 1; + path = (char *)malloc(pathlen); + if (!path) { + ErrPrint("Heap: %s\n", strerror(errno)); + return; + } + + snprintf(path, pathlen, "/opt/usr/media/Videos/%s", filename); + CModel::GetInstance()->SetVideoFilename(path); + DbgPrint("Updated Video file: %s\n", path); + free(path); + + if (video->State() == CVideo::PLAYING) + video->Stop(); + + video->Play(CModel::GetInstance()->VideoFilename()); +} + +int CController::s_CreatePD(struct event_arg *arg, void *data) +{ + Evas_Object *list; + TWindowData *win_data; + CWindow *win; + Evas_Object *parent; + int w; + int h; + + DIR *handle; + + win_data = (TWindowData *)malloc(sizeof(*win_data)); + if (!win_data) { + ErrPrint("Heap: %s\n", strerror(errno)); + return -ENOMEM; + } + + win = CWindow::Create(TYPE_PD, arg->id, arg->info.pd_create.w, arg->info.pd_create.h); + if (!win) { + ErrPrint("Window for PID is not able to create\n"); + free(win_data); + return -EFAULT; + } + + parent = win->Object(); + if (!parent) { + ErrPrint("Window is not valid\n"); + free(win_data); + return -EFAULT; + } + + list = elm_list_add(parent); + evas_object_geometry_get(parent, NULL, NULL, &w, &h); + evas_object_size_hint_weight_set(list, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_list_multi_select_set(list, EINA_FALSE); + elm_list_mode_set(list, ELM_LIST_COMPRESS); + elm_scroller_bounce_set(list, EINA_TRUE, EINA_FALSE); + evas_object_resize(list, w, h); + evas_object_move(list, 0, 0); + evas_object_show(list); + + handle = opendir("/opt/usr/media/Videos/"); + if (handle) { + struct dirent *ent; + + while ((ent = readdir(handle))) + elm_list_item_append(list, ent->d_name, NULL, NULL /* end */, press_cb, win_data); + + closedir(handle); + } + + elm_list_go(list); + + win_data->id = strdup(arg->id); + if (!win_data->id) { + evas_object_del(list); + free(win_data); + return -ENOMEM; + } + win_data->list = list; + + evas_object_data_set(parent, "win_data", win_data); + return 0; +} + +int CController::s_DestroyPD(struct event_arg *arg, void *data) +{ + CWindow *win; + TWindowData *win_data; + + win = CWindow::Find(TYPE_PD, arg->id); + if (!win) { + ErrPrint("PD Window for %s is not exists\n", arg->id); + return -ENOENT; + } + + win_data = (TWindowData *)evas_object_data_del(win->Object(), "win_data"); + if (win_data) { + evas_object_del(win_data->list); + free(win_data->id); + free(win_data); + } + + win->Destroy(); + return 0; +} + +CController::CController(void) +: m_sName(NULL) +{ +} + +CController::~CController(void) +{ + free(m_sName); + m_sName = NULL; + + m_pInstance = NULL; + + if (m_pPing) { + ecore_timer_del(m_pPing); + m_pPing = NULL; + } +} + +int CController::Initialize(const char *name) +{ + int ret; + struct event_handler table; + + if (CController::m_pInstance) + return -EALREADY; + + try { + m_pInstance = new CController(); + } catch (...) { + return -ENOMEM; + } + + m_pInstance->m_sName = strdup(name); + if (!m_pInstance->m_sName) { + delete m_pInstance; + return -ENOMEM; + } + + table.lb_create = CController::s_CreateLB; + table.lb_recreate = CController::s_RecreateLB; + table.lb_destroy = CController::s_DestroyLB; + table.content_event = CController::s_ContentEvent; + table.clicked = CController::s_Clicked; + table.text_signal = CController::s_TextEvent; + table.resize = CController::s_Resize; + table.set_period = CController::s_SetPeriod; + table.change_group = CController::s_ChangeGroup; + table.pinup = CController::s_Pinup; + table.update_content = CController::s_UpdateContent; + table.pause = CController::s_Pause; + table.resume = CController::s_Resume; + table.disconnected = CController::s_Disconnected; + table.connected = CController::s_Connected; + table.pd_create = CController::s_CreatePD; + table.pd_destroy = CController::s_DestroyPD; + + ret = provider_init(ecore_x_display_get(), m_pInstance->m_sName, &table, NULL); + if (ret < 0) { + delete m_pInstance; + return ret; + } + + return 0; +} + +int CController::Finalize(void) +{ + if (!m_pInstance) + return -EINVAL; + + provider_fini(); + + delete m_pInstance; + return 0; +} + +/* End of a file */ diff --git a/sample/org.tizen.live-video/src/CMain.cpp b/sample/org.tizen.live-video/src/CMain.cpp new file mode 100644 index 0000000..a5fd624 --- /dev/null +++ b/sample/org.tizen.live-video/src/CMain.cpp @@ -0,0 +1,81 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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 "debug.h" +#include "CController.h" + +static int app_create(void *data) +{ + return 0; +} + +static int app_terminate(void *data) +{ + return CController::Finalize(); +} + +static int app_pause(void *data) +{ + return 0; +} + +static int app_resume(void *data) +{ + return 0; +} + +static int app_reset(bundle *b, void *data) +{ + const char *name; + + name = bundle_get_val(b, "name"); + if (!name) { + ErrPrint("Name is not valid\n"); + elm_exit(); + return -EINVAL; + } + + return CController::Initialize(name); +} + +int main(int argc, char *argv[]) +{ + struct appcore_ops ops; + + ops.create = app_create; + ops.terminate = app_terminate; + ops.pause = app_pause; + ops.resume = app_resume; + ops.reset = app_reset; + ops.data = NULL; + + return appcore_efl_main(basename(argv[0]), &argc, &argv, &ops); +} + +/* End of a file */ diff --git a/sample/org.tizen.live-video/src/CModel.cpp b/sample/org.tizen.live-video/src/CModel.cpp new file mode 100644 index 0000000..cbcd064 --- /dev/null +++ b/sample/org.tizen.live-video/src/CModel.cpp @@ -0,0 +1,74 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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 "debug.h" +#include "CModel.h" + +CModel *CModel::m_pInstance = NULL; + +CModel::CModel(void) +{ + m_sFilename = strdup("/opt/usr/media/Videos/Helicopter.mp4"); + if (!m_sFilename) + throw -ENOMEM; +} + +CModel::~CModel(void) +{ + free(m_sFilename); +} + +CModel *CModel::GetInstance(void) +{ + if (!m_pInstance) { + try { + m_pInstance = new CModel(); + } catch (...) { + return NULL; + } + } + + return m_pInstance; +} + +const char *CModel::VideoFilename(void) +{ + return m_sFilename; +} + +int CModel::SetVideoFilename(const char *filename) +{ + char *tmp; + + tmp = strdup(filename); + if (!tmp) { + ErrPrint("Heap: %s\n", strerror(errno)); + return -ENOMEM; + } + + free(m_sFilename); + m_sFilename = tmp; + return 0; +} + +/* End of a file */ diff --git a/sample/org.tizen.live-video/src/CVideo.cpp b/sample/org.tizen.live-video/src/CVideo.cpp new file mode 100644 index 0000000..eec8341 --- /dev/null +++ b/sample/org.tizen.live-video/src/CVideo.cpp @@ -0,0 +1,383 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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 "debug.h" +#include "CWindow.h" +#include "CVideo.h" +#include "CModel.h" + +Eina_List *CVideo::s_pList = NULL; + + +CVideo *CVideo::Find(enum target_type type, const char *id) +{ + Eina_List *l; + void *item; + CVideo *video; + + EINA_LIST_FOREACH(s_pList, l, item) { + video = (CVideo *)item; + + if (video->Type() == type && !strcmp(video->Id(), id)) + return video; + } + + return NULL; +} + +CVideo *CVideo::Create(enum target_type type, const char *id, int w, int h) +{ + CVideo *video; + struct livebox_buffer *pBuffer; + + if (!ecore_x_damage_query()) { + ErrPrint("Damage event is not supported\n"); + return NULL; + } + + try { + video = new CVideo(type, w, h); + } catch (...) { + ErrPrint("Failed to create a video instance\n"); + return NULL; + } + + video->m_sId = strdup(id); + if (!video->m_sId) { + ErrPrint("Heap: %s\n", strerror(errno)); + video->Destroy(); + return NULL; + } + + pBuffer = provider_buffer_acquire(video->Type(), PKGNAME, video->Id(), + video->Width(), video->Height(), sizeof(int), + CVideo::s_BufferEventHandler, video); + if (!pBuffer) { + ErrPrint("Failed to acquire buffer handle\n"); + video->Destroy(); + return NULL; + } + + /*! + * \note + * this function must has to be called before add an item to the s_pList + */ + video->SetBuffer(pBuffer); + + s_pList = eina_list_append(s_pList, video); + return video; +} + +Eina_Bool CVideo::s_DamageEventHandler(void *data, int type, void *event) +{ + CVideo *video = (CVideo *)data; + Ecore_X_Event_Damage *e = (Ecore_X_Event_Damage *)event; + + if (e->drawable == video->PixmapId()) { + switch (video->Type()) { + case TYPE_LB: + provider_send_updated(PKGNAME, video->Id(), video->Width(), video->Height(), 1.0f, NULL, NULL); + break; + case TYPE_PD: + provider_send_desc_updated(PKGNAME, video->Id(), NULL); + break; + default: + ErrPrint("Unknown video type\n"); + break; + } + + video->Update(); + } + + return ECORE_CALLBACK_PASS_ON; +} + +int CVideo::Update(void) +{ + ecore_x_damage_subtract(m_vDamage, None, None); + return 0; +} + +void CVideo::SetBuffer(struct livebox_buffer *pBuffer) +{ + if (!pBuffer) { + if (m_pDamageHandler) + ecore_event_handler_del(m_pDamageHandler); + + m_pDamageHandler = NULL; + + if (m_vDamage) + ecore_x_damage_free(m_vDamage); + + m_vDamage = 0; + return; + } + + m_pBuffer = pBuffer; + + m_nId = provider_buffer_pixmap_id(m_pBuffer); + if (m_nId == 0) { + ErrPrint("Failed to get pixmap\n"); + return; + } + + m_pDamageHandler = ecore_event_handler_add(ECORE_X_EVENT_DAMAGE_NOTIFY, CVideo::s_DamageEventHandler, this); + if (!m_pDamageHandler) { + ErrPrint("Failed to add a event handler\n"); + return; + } + + m_vDamage = ecore_x_damage_new(m_nId, ECORE_X_DAMAGE_REPORT_RAW_RECTANGLES); + if (!m_vDamage) { + ErrPrint("Failed to create a new damage object\n"); + return; + } + + DbgPrint("Prepare callback\n"); + Clear(); +} + +int CVideo::s_BufferEventHandler(struct livebox_buffer *buffer, enum buffer_event event, double timestamp, double x, double y, void *data) +{ + CVideo *video = (CVideo *)data; + int ix; + int iy; + + ix = video->Width() * x; + iy = video->Height() * y; + + switch (event) { + case BUFFER_EVENT_ENTER: + break; + case BUFFER_EVENT_LEAVE: + break; + case BUFFER_EVENT_DOWN: + DbgPrint("Down: %dx%d\n", ix, iy); + break; + case BUFFER_EVENT_MOVE: + break; + case BUFFER_EVENT_UP: + DbgPrint("Up: %dx%d\n", ix, iy); + break; + default: + break; + } + + return 0; +} + +int CVideo::Destroy(void) +{ + int ret; + DbgPrint("Destroy a video object\n"); + + s_pList = eina_list_remove(s_pList, this); + + Stop(); /*!< Just try to stop playing */ + + if (m_nId) + ecore_x_damage_free(m_vDamage); + + if (m_pDamageHandler) + ecore_event_handler_del(m_pDamageHandler); + + free(m_sId); + + ret = provider_buffer_release(m_pBuffer); + DbgPrint("release: %d\n", ret); + delete this; + return 0; +} + +int CVideo::Resize(int w, int h) +{ + struct livebox_buffer *pBuffer; + + if (m_nWidth == w && m_nHeight == h) { + DbgPrint("Size has no changes\n"); + return 0; + } + + m_nWidth = w; + m_nHeight = h; + + if (!m_pBuffer) { + ErrPrint("Buffer is not available\n"); + return -EINVAL; + } + + SetBuffer(NULL); + + provider_buffer_release(m_pBuffer); + m_pBuffer = NULL; + + pBuffer = provider_buffer_acquire(m_vType, PKGNAME, + m_sId, m_nWidth, m_nHeight, sizeof(int), + CVideo::s_BufferEventHandler, this); + + SetBuffer(pBuffer); + + if (m_vState == PLAYING) { + const char *uri; + m_sError = NULL; + + uri = CModel::GetInstance()->VideoFilename(); + DbgPrint("Update PIXMAP: 0x%X (file: %s)\n", m_nId, uri); + mm_player_set_attribute(m_vPlayer, &m_sError, + "display_surface_type", MM_DISPLAY_SURFACE_X, + "display_width", m_nWidth, + "display_height", m_nHeight, + "display_overlay", &m_nId, sizeof(m_nId), + "profile_uri", uri, strlen(uri), + "display_rotation", MM_DISPLAY_ROTATION_NONE, + "profile_play_count", 1, + NULL); + if (m_sError) + ErrPrint("SetAttribute: %s\n", m_sError); + } + + return 0; +} + +int CVideo::s_MMMessageHandler(int message, void *_param, void *user_param) +{ + CVideo *video = (CVideo *)user_param; + // MMMessageParamType *param = (MMMessageParamType *)_param; + + switch (message) { + case MM_MESSAGE_END_OF_STREAM: + video->Stop(); + DbgPrint("End of stream\n"); + break; + default: + return FALSE; + } + + return TRUE; +} + +void CVideo::Clear(void) +{ + static unsigned int s_color = 0x00FF0000; + GC gc; + + gc = XCreateGC((Display *)ecore_x_display_get(), PixmapId(), 0, 0); + + XSetForeground((Display *)ecore_x_display_get(), gc, 0xFF000000 | s_color); + XFillRectangle((Display *)ecore_x_display_get(), PixmapId(), gc, 0, 0, Width(), Height()); + + XSync((Display *)ecore_x_display_get(), FALSE); + XFreeGC((Display *)ecore_x_display_get(), gc); + + s_color >>= 2; + if (s_color == 0) + s_color = 0xFF000000; +} + +int CVideo::Play(const char *uri) +{ + if (m_vState == PLAYING) + return -EBUSY; + + if (mm_player_create(&m_vPlayer) != MM_ERROR_NONE) { + ErrPrint("Failed to create a player\n"); + return -EFAULT; + } + + m_sError = NULL; + mm_player_set_attribute(m_vPlayer, &m_sError, + "display_surface_type", MM_DISPLAY_SURFACE_X, + "display_width", m_nWidth, + "display_height", m_nHeight, + "display_overlay", &m_nId, sizeof(m_nId), + "profile_uri", uri, strlen(uri), + "display_rotation", MM_DISPLAY_ROTATION_NONE, + "profile_play_count", 1, + NULL); + if (m_sError) + ErrPrint("SetAttribute: %s\n", m_sError); + + if (mm_player_realize(m_vPlayer) != MM_ERROR_NONE) { + ErrPrint("Failed to realize a player\n"); + mm_player_destroy(m_vPlayer); + m_vPlayer = 0; + return -EFAULT; + } + + mm_player_set_message_callback(m_vPlayer, CVideo::s_MMMessageHandler, this); + mm_player_start(m_vPlayer); + m_vState = PLAYING; + + DbgPrint("Play file %s on %d\n", uri, m_nId); + return 0; +} + +int CVideo::Stop(void) +{ + if (m_vState == STOPPED) + return -EALREADY; + + m_vState = STOPPED; + + if (m_vPlayer) { + mm_player_unrealize(m_vPlayer); + mm_player_destroy(m_vPlayer); + m_vPlayer = 0; + } + + DbgPrint("Stop playing\n"); + return 0; +} + +CVideo::CVideo(enum target_type type, int width, int height) +: m_vState(STOPPED) +, m_vType(type) +, m_nWidth(width) +, m_nHeight(height) +, m_pBuffer(NULL) +, m_nId(0) +, m_sId(NULL) +, m_sError(NULL) +, m_vPlayer(0) +{ +} + +CVideo::~CVideo(void) +{ +} + +CVideo::TVideoState CVideo::State(void) +{ + return m_vState; +} + +/* End of a file */ diff --git a/sample/org.tizen.live-video/src/CView.cpp b/sample/org.tizen.live-video/src/CView.cpp new file mode 100644 index 0000000..ab4cd22 --- /dev/null +++ b/sample/org.tizen.live-video/src/CView.cpp @@ -0,0 +1,31 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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 "debug.h" +#include "CView.h" + +CView::CView(void) +{ +} + +CView::~CView(void) +{ +} + +/* End of a file */ diff --git a/sample/org.tizen.live-video/src/CWindow.cpp b/sample/org.tizen.live-video/src/CWindow.cpp new file mode 100644 index 0000000..8ca600f --- /dev/null +++ b/sample/org.tizen.live-video/src/CWindow.cpp @@ -0,0 +1,224 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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 "debug.h" +#include "CWindow.h" + +Eina_List *CWindow::s_pList = NULL; + +void *CWindow::s_AllocateCanvas(void *data, int size) +{ + CWindow *win = (CWindow *)data; + struct livebox_buffer *pBuffer; + void *canvas; + + pBuffer = provider_buffer_acquire(win->Type(), PKGNAME, win->Id(), + win->Width(), win->Height(), sizeof(int), + CWindow::s_BufferEventHandler, win); + + if (!pBuffer) + return NULL; + + win->SetBuffer(pBuffer); + canvas = provider_buffer_ref(win->Buffer()); + return canvas; +} + +void CWindow::s_ReleaseCanvas(void *data, void *canvas) +{ + int ret; + CWindow *win = (CWindow *)data; + + ret = provider_buffer_unref(canvas); + DbgPrint("Unref %d\n", ret); + + ret = provider_buffer_release(win->Buffer()); + DbgPrint("release %d\n", ret); + + win->SetBuffer(NULL); +} + +void CWindow::s_PostRender(void *data, Evas *e, void *event_info) +{ + CWindow *win = (CWindow *)data; + + if (win->EvasObject() != e) + return; + + switch (win->Type()) { + case TYPE_PD: + provider_buffer_sync(win->Buffer()); + provider_send_desc_updated(PKGNAME, win->Id(), NULL); + break; + case TYPE_LB: + provider_buffer_sync(win->Buffer()); + provider_send_updated(PKGNAME, win->Id(), win->Width(), win->Height(), 1.0f, NULL, NULL); + break; + default: + break; + } +} + +int CWindow::s_BufferEventHandler(struct livebox_buffer *buffer, enum buffer_event event, double timestamp, double x, double y, void *data) +{ + CWindow *win = (CWindow *)data; + int ix; + int iy; + + ix = win->Width() * x; + iy = win->Height() * y; + + switch (event) { + case BUFFER_EVENT_ENTER: + evas_event_feed_mouse_in(win->EvasObject(), timestamp, NULL); + break; + case BUFFER_EVENT_LEAVE: + evas_event_feed_mouse_out(win->EvasObject(), timestamp, NULL); + break; + case BUFFER_EVENT_DOWN: + evas_event_feed_mouse_in(win->EvasObject(), timestamp, NULL); + evas_event_feed_mouse_move(win->EvasObject(), ix, iy, timestamp + 0.01f, NULL); + evas_event_feed_mouse_down(win->EvasObject(), 1, EVAS_BUTTON_NONE, timestamp + 0.02f, NULL); + break; + case BUFFER_EVENT_MOVE: + evas_event_feed_mouse_move(win->EvasObject(), ix, iy, timestamp, NULL); + break; + case BUFFER_EVENT_UP: + evas_event_feed_mouse_up(win->EvasObject(), 1, EVAS_BUTTON_NONE, timestamp, NULL); + evas_event_feed_mouse_out(win->EvasObject(), timestamp + 0.01f, NULL); + break; + default: + break; + } + + return 0; +} + +CWindow *CWindow::Create(enum target_type type, const char *id, int w, int h) +{ + CWindow *win; + + try { + win = new CWindow(type, w, h); + } catch (...) { + return NULL; + } + + win->m_sID = strdup(id); + if (!win->m_sID) { + win->Destroy(); + return NULL; + } + + win->m_pEcoreEvas = ecore_evas_buffer_allocfunc_new(win->m_nWidth, win->m_nHeight, CWindow::s_AllocateCanvas, CWindow::s_ReleaseCanvas, win); + if (!win->m_pEcoreEvas) { + ErrPrint("Failed to allocate a new EE\n"); + win->Destroy(); + return NULL; + } + + win->m_pEvas = ecore_evas_get(win->m_pEcoreEvas); + if (!win->m_pEvas) { + win->Destroy(); + return NULL; + } + + evas_event_callback_add(win->m_pEvas, EVAS_CALLBACK_RENDER_FLUSH_POST, s_PostRender, win); + + ecore_evas_alpha_set(win->m_pEcoreEvas, EINA_TRUE); + ecore_evas_manual_render_set(win->m_pEcoreEvas, EINA_FALSE); + ecore_evas_resize(win->m_pEcoreEvas, win->m_nWidth, win->m_nHeight); + ecore_evas_show(win->m_pEcoreEvas); + ecore_evas_activate(win->m_pEcoreEvas); + + win->m_pObject = evas_object_rectangle_add(win->m_pEvas); + evas_object_resize(win->m_pObject, win->m_nWidth, win->m_nHeight); + evas_object_color_set(win->m_pObject, 0, 0, 0, 255); + evas_object_show(win->m_pObject); + + s_pList = eina_list_append(s_pList, win); + return win; +} + +CWindow *CWindow::Find(enum target_type type, const char *id) +{ + Eina_List *l; + void *item; + CWindow *win; + + EINA_LIST_FOREACH(s_pList, l, item) { + win = (CWindow *)item; + + if (win->Type() == type && !strcmp(win->Id(), id)) + return win; + } + + return NULL; +} + +int CWindow::Destroy(void) +{ + s_pList = eina_list_remove(s_pList, this); + + if (m_pObject) + evas_object_del(m_pObject); + + if (m_pEcoreEvas) + ecore_evas_free(m_pEcoreEvas); + + free(m_sID); + delete this; + return 0; +} + +int CWindow::Resize(int w, int h) +{ + m_nWidth = w; + m_nHeight = h; + + if (m_pEcoreEvas) + ecore_evas_resize(m_pEcoreEvas, w, h); + + return 0; +} + +CWindow::CWindow(enum target_type type, int width, int height) +: m_vType(type) +, m_nWidth(width) +, m_nHeight(height) +, m_pBuffer(NULL) +, m_pEcoreEvas(NULL) +, m_pEvas(NULL) +, m_sID(NULL) +{ +} + +CWindow::~CWindow(void) +{ +} + +/* End of a file */ diff --git a/src/dlist.c b/src/dlist.c new file mode 100644 index 0000000..56ff060 --- /dev/null +++ b/src/dlist.c @@ -0,0 +1,180 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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/src/fb.c b/src/fb.c new file mode 100644 index 0000000..05000c2 --- /dev/null +++ b/src/fb.c @@ -0,0 +1,869 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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 +#include + +#include + +#include "debug.h" +#include "util.h" +#include "provider.h" +#include "fb.h" +#include "dlist.h" + +int errno; + +enum buffer_type { /*!< Must have to be sync with libprovider, liblivebox-viewer */ + BUFFER_TYPE_FILE, + BUFFER_TYPE_SHM, + BUFFER_TYPE_PIXMAP, + BUFFER_TYPE_ERROR, +}; + +struct buffer { /*!< Must has to be sync with slave & provider */ + enum { + CREATED = 0x00beef00, + DESTROYED = 0x00dead00, + } state; + enum buffer_type type; + int refcnt; + void *info; + char data[]; +}; + +struct gem_data { + DRI2Buffer *dri2_buffer; + unsigned int attachments[1]; + drm_slp_bo pixmap_bo; + int count; + int buf_count; + int w; + int h; + int depth; + Pixmap pixmap; + void *data; /* Gem layer */ + int refcnt; + + void *compensate_data; /* Check the pitch value, copy this to data */ +}; + +struct fb_info { + char *id; + int w; + int h; + int bufsz; + void *buffer; + + int handle; + + struct gem_data *gem; +}; + +static struct { + drm_slp_bufmgr slp_bufmgr; + int evt_base; + int err_base; + int fd; + struct dlist *pixmap_list; + + Display *disp; + int screen; + int depth; + Visual *visual; + int disp_is_opened; +} s_info = { + .slp_bufmgr = NULL, + .evt_base = 0, + .err_base = 0, + .fd = -1, + .pixmap_list = NULL, + + .disp = NULL, + .screen = 0, + .depth = 0, + .visual = NULL, + .disp_is_opened = 0, +}; + +int fb_init(void *disp) +{ + int dri2Major, dri2Minor; + char *driverName, *deviceName; + drm_magic_t magic; + Screen *screen; + + s_info.disp = disp; + if (!s_info.disp) { + s_info.disp = XOpenDisplay(NULL); + if (!s_info.disp) { + ErrPrint("Failed to open a display\n"); + return -EFAULT; + } + + s_info.disp_is_opened = 1; + } + + screen = DefaultScreenOfDisplay(s_info.disp); + s_info.screen = DefaultScreen(s_info.disp); + s_info.visual = DefaultVisualOfScreen(screen); + s_info.depth = sizeof(int); //DefaultDepthOfScreen(screen); + + if (!DRI2QueryExtension(s_info.disp, &s_info.evt_base, &s_info.err_base)) { + DbgPrint("DRI2 is not supported\n"); + return 0; + } + + if (!DRI2QueryVersion(s_info.disp, &dri2Major, &dri2Minor)) { + DbgPrint("DRI2 is not supported\n"); + s_info.evt_base = 0; + s_info.err_base = 0; + return 0; + } + + if (!DRI2Connect(s_info.disp, DefaultRootWindow(s_info.disp), &driverName, &deviceName)) { + DbgPrint("DRI2 is not supported\n"); + s_info.evt_base = 0; + s_info.err_base = 0; + return 0; + } + + s_info.fd = open(deviceName, O_RDWR); + free(deviceName); + free(driverName); + if (s_info.fd < 0) { + DbgPrint("Failed to open a drm device: (%s)\n", strerror(errno)); + s_info.evt_base = 0; + s_info.err_base = 0; + return 0; + } + + drmGetMagic(s_info.fd, &magic); + DbgPrint("DRM Magic: 0x%X\n", magic); + if (!DRI2Authenticate(s_info.disp, DefaultRootWindow(s_info.disp), (unsigned int)magic)) { + DbgPrint("Failed to do authenticate for DRI2\n"); + close(s_info.fd); + s_info.fd = -1; + s_info.evt_base = 0; + s_info.err_base = 0; + return 0; + } + + s_info.slp_bufmgr = drm_slp_bufmgr_init(s_info.fd, NULL); + if (!s_info.slp_bufmgr) { + DbgPrint("Failed to init bufmgr\n"); + close(s_info.fd); + s_info.fd = -1; + s_info.evt_base = 0; + s_info.err_base = 0; + return 0; + } + + return 0; +} + +int fb_fini(void) +{ + if (s_info.fd >= 0) { + close(s_info.fd); + s_info.fd = -1; + } + + if (s_info.slp_bufmgr) { + drm_slp_bufmgr_destroy(s_info.slp_bufmgr); + s_info.slp_bufmgr = NULL; + } + + if (s_info.disp_is_opened && s_info.disp) { + XCloseDisplay(s_info.disp); + s_info.disp = NULL; + } + + s_info.screen = 0; + s_info.visual = NULL; + s_info.depth = 0; + return 0; +} + +static inline int sync_for_file(struct fb_info *info) +{ + int fd; + struct buffer *buffer; + + buffer = info->buffer; + if (!buffer) { + DbgPrint("Buffer is NIL, skip sync\n"); + return 0; + } + + if (buffer->state != CREATED) { + ErrPrint("Invalid state of a FB\n"); + return -EINVAL; + } + + if (buffer->type != BUFFER_TYPE_FILE) { + DbgPrint("Ingore sync\n"); + return 0; + } + + fd = open(util_uri_to_path(info->id), O_WRONLY | O_CREAT, 0644); + if (fd < 0) { + ErrPrint("open %s: %s\n", util_uri_to_path(info->id), strerror(errno)); + return -EIO; + } + + if (write(fd, buffer->data, info->bufsz) != info->bufsz) { + ErrPrint("write: %s\n", strerror(errno)); + close(fd); + return -EIO; + } + + close(fd); + return 0; +} + +static inline int sync_for_pixmap(struct fb_info *info) +{ + struct buffer *buffer; + XShmSegmentInfo si; + XImage *xim; + GC gc; + + buffer = info->buffer; + if (!buffer) { + DbgPrint("Buffer is NIL, skip sync\n"); + return 0; + } + + if (buffer->state != CREATED) { + ErrPrint("Invalid state of a FB\n"); + return -EINVAL; + } + + if (buffer->type != BUFFER_TYPE_PIXMAP) { + DbgPrint("Invalid buffer\n"); + return 0; + } + + if (info->handle == 0) { + DbgPrint("Pixmap ID is not valid\n"); + return -EINVAL; + } + + if (info->bufsz == 0) { + DbgPrint("Nothing can be sync\n"); + return 0; + } + + si.shmid = shmget(IPC_PRIVATE, info->bufsz, IPC_CREAT | 0666); + if (si.shmid < 0) { + ErrPrint("shmget: %s\n", strerror(errno)); + return -EFAULT; + } + + 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: %s\n", strerror(errno)); + return -EFAULT; + } + + /*! + * \NOTE + * XCreatePixmap can only uses 24 bits depth only. + */ + xim = XShmCreateImage(s_info.disp, s_info.visual, 24/* (s_info.depth << 3) */, ZPixmap, NULL, &si, info->w, info->h); + if (xim == NULL) { + if (shmdt(si.shmaddr) < 0) + ErrPrint("shmdt: %s\n", strerror(errno)); + + if (shmctl(si.shmid, IPC_RMID, 0) < 0) + ErrPrint("shmctl: %s\n", strerror(errno)); + return -EFAULT; + } + + xim->data = si.shmaddr; + XShmAttach(s_info.disp, &si); + XSync(s_info.disp, False); + + gc = XCreateGC(s_info.disp, (Pixmap)info->handle, 0, NULL); + if (!gc) { + XShmDetach(s_info.disp, &si); + XDestroyImage(xim); + + if (shmdt(si.shmaddr) < 0) + ErrPrint("shmdt: %s\n", strerror(errno)); + + if (shmctl(si.shmid, IPC_RMID, 0) < 0) + ErrPrint("shmctl: %s\n", strerror(errno)); + + return -EFAULT; + } + + memcpy(xim->data, buffer->data, info->bufsz); + + /*! + * \note Do not send the event. + * Instead of X event, master will send the updated event to the viewer + */ + XShmPutImage(s_info.disp, (Pixmap)info->handle, gc, xim, 0, 0, 0, 0, info->w, info->h, False); + XSync(s_info.disp, False); + + XFreeGC(s_info.disp, gc); + XShmDetach(s_info.disp, &si); + XDestroyImage(xim); + + if (shmdt(si.shmaddr) < 0) + ErrPrint("shmdt: %s\n", strerror(errno)); + + if (shmctl(si.shmid, IPC_RMID, 0) < 0) + ErrPrint("shmctl: %s\n", strerror(errno)); + + return 0; +} + +int fb_sync(struct fb_info *info) +{ + if (!info) { + ErrPrint("FB Handle is not valid\n"); + return -EINVAL; + } + + if (!info->id || info->id[0] == '\0') { + DbgPrint("Ingore sync\n"); + return 0; + } + + if (!strncasecmp(info->id, SCHEMA_FILE, strlen(SCHEMA_FILE))) { + return sync_for_file(info); + } else if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP))) { + return sync_for_pixmap(info); + } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM))) { + return 0; + } + + DbgPrint("Invalid URI: [%s]\n", info->id); + return -EINVAL; +} + +static inline struct gem_data *find_gem_by_pixmap(Pixmap id) +{ + struct gem_data *gem; + struct dlist *l; + + gem = NULL; + dlist_foreach(s_info.pixmap_list, l, gem) { + if (gem->pixmap == id) + break; + + gem = NULL; + } + + return gem; +} + +static inline struct gem_data *find_gem_by_canvas(void *canvas) +{ + struct gem_data *gem; + struct dlist *l; + + gem = NULL; + dlist_foreach(s_info.pixmap_list, l, gem) { + if (gem->data == canvas || gem->compensate_data == canvas) + break; + + gem = NULL; + } + + return gem; +} + +static inline struct gem_data *create_gem(Pixmap pixmap, int w, int h, int depth) +{ + struct gem_data *gem; + gem = calloc(1, sizeof(*gem)); + if (!gem) { + ErrPrint("Heap: %s\n", strerror(errno)); + return NULL; + } + + gem->attachments[0] = DRI2BufferFrontLeft; + gem->count = 1; + gem->w = w; + gem->h = h; + gem->depth = depth; + gem->pixmap = pixmap; + + DRI2CreateDrawable(s_info.disp, gem->pixmap); + DbgPrint("DRI2CreateDrawable is done\n"); + + gem->dri2_buffer = DRI2GetBuffers(s_info.disp, gem->pixmap, + &gem->w, &gem->h, gem->attachments, + gem->count, &gem->buf_count); + + if (!gem->dri2_buffer || !gem->dri2_buffer->name) { + ErrPrint("Failed tog et gem buffer\n"); + DRI2DestroyDrawable(s_info.disp, gem->pixmap); + free(gem); + return NULL; + } + DbgPrint("dri2_buffer: %p, name: %p, %dx%d (%dx%d)\n", + gem->dri2_buffer, gem->dri2_buffer->name, + gem->w, gem->h, w, h); + DbgPrint("dri2_buffer->pitch : %d, buf_count: %d\n", + gem->dri2_buffer->pitch, gem->buf_count); + + gem->pixmap_bo = drm_slp_bo_import(s_info.slp_bufmgr, gem->dri2_buffer->name); + if (!gem->pixmap_bo) { + ErrPrint("Failed to import BO\n"); + DRI2DestroyDrawable(s_info.disp, gem->pixmap); + free(gem); + return NULL; + } + + if (gem->dri2_buffer->pitch != gem->w * gem->depth) { + gem->compensate_data = calloc(1, gem->w * gem->h * gem->depth); + if (!gem->compensate_data) { + ErrPrint("Failed to allocate heap\n"); + } else { + DbgPrint("Allocate compensate buffer %p(%dx%d %d\n", + gem->compensate_data, + gem->w, gem->h, gem->depth); + } + } + + DbgPrint("Return buffer: %p\n", gem); + s_info.pixmap_list = dlist_append(s_info.pixmap_list, gem); + return gem; +} + +static inline int destroy_gem(struct gem_data *gem) +{ + dlist_remove_data(s_info.pixmap_list, gem); + + if (gem->compensate_data) { + DbgPrint("Release compensate buffer %p\n", gem->compensate_data); + free(gem->compensate_data); + gem->compensate_data = NULL; + } + + if (gem->pixmap_bo) { + DbgPrint("unref pixmap bo\n"); + drm_slp_bo_unref(gem->pixmap_bo); + gem->pixmap_bo = NULL; + + DbgPrint("DRI2DestroyDrawable\n"); + DRI2DestroyDrawable(s_info.disp, gem->pixmap); + } + + free(gem); + return 0; +} + +static inline void *acquire_gem(struct gem_data *gem) +{ + if (!gem->data) { + gem->data = (void *)drm_slp_bo_map(gem->pixmap_bo, + DRM_SLP_DEVICE_CPU, + DRM_SLP_OPTION_READ|DRM_SLP_OPTION_WRITE); + if (!gem->data) + ErrPrint("Failed to get BO\n"); + } + + gem->refcnt++; + return gem->compensate_data ? gem->compensate_data : gem->data; +} + +static inline void release_gem(struct gem_data *gem) +{ + gem->refcnt--; + if (gem->refcnt == 0) { + if (gem->compensate_data) { + register int x; + register int y; + int *gem_pixel; + int *pixel; + int gap; + + pixel = gem->compensate_data; + gem_pixel = gem->data; + gap = gem->dri2_buffer->pitch - (gem->w * gem->depth); + + for (y = 0; y < gem->h; y++) { + for (x = 0; x < gem->w; x++) + *gem_pixel++ = *pixel++; + + gem_pixel = (int *)(((char *)gem_pixel) + gap); + } + } + drm_slp_bo_unmap(gem->pixmap_bo, DRM_SLP_DEVICE_CPU); + gem->data = NULL; + } else if (gem->refcnt < 0) { + ErrPrint("Invalid refcnt: %d (reset)\n", gem->refcnt); + gem->refcnt = 0; + } +} + +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: %s\n", strerror(errno)); + return NULL; + } + + info->id = strdup(id); + if (!info->id) { + ErrPrint("Heap: %s\n", strerror(errno)); + free(info); + return NULL; + } + + if (sscanf(info->id, SCHEMA_SHM "%d", &info->handle) == 1) { + DbgPrint("SHMID: %d\n", info->handle); + } else if (sscanf(info->id, SCHEMA_PIXMAP "%d", &info->handle) == 1) { + DbgPrint("PIXMAP: %d\n", info->handle); + } else if (!strncasecmp(info->id, SCHEMA_FILE, strlen(SCHEMA_FILE))) { + info->handle = -1; + } else { + ErrPrint("Unsupported schema: %s\n", info->id); + free(info); + return NULL; + } + + info->w = w; + info->h = h; + + return info; +} + +int fb_has_gem(struct fb_info *info) +{ + return (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP)) && s_info.fd >= 0); +} + +int fb_create_gem(struct fb_info *info) +{ + if (info->gem) { + DbgPrint("Already created\n"); + return 0; + } + + info->gem = create_gem(info->handle, info->w, info->h, sizeof(int)); + return info->gem ? 0 : -EFAULT; +} + +int fb_destroy_gem(struct fb_info *info) +{ + if (!info->gem) { + ErrPrint("GEM is not created\n"); + return -EINVAL; + } + + destroy_gem(info->gem); + info->gem = NULL; + return 0; +} + +void *fb_acquire_gem(struct fb_info *info) +{ + if (!info->gem) { + ErrPrint("Invalid FB info\n"); + return NULL; + } + + return acquire_gem(info->gem); +} + +int fb_release_gem(struct fb_info *info) +{ + if (!info->gem) { + ErrPrint("Invalid FB info\n"); + return -EINVAL; + } + + release_gem(info->gem); + return 0; +} + +int fb_destroy(struct fb_info *info) +{ + if (!info) { + ErrPrint("Handle is not valid\n"); + return -EINVAL; + } + + if (info->buffer) { + struct buffer *buffer; + buffer = info->buffer; + buffer->info = NULL; + } + + free(info->id); + free(info); + return 0; +} + +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: %s (%s)\n", strerror(errno), path); + } + } + + return 0; +} + +void *fb_acquire_buffer(struct fb_info *info) +{ + struct buffer *buffer; + + if (!info) + return NULL; + + if (!info->buffer) { + if (!strncasecmp(info->id, SCHEMA_PIXMAP, strlen(SCHEMA_PIXMAP))) { + /*! + * Use the S/W backend + */ + info->bufsz = info->w * info->h * s_info.depth; + buffer = calloc(1, sizeof(*buffer) + info->bufsz); + if (!buffer) { + ErrPrint("Heap: %s\n", strerror(errno)); + info->bufsz = 0; + return NULL; + } + + buffer->type = BUFFER_TYPE_PIXMAP; + buffer->refcnt = 0; + buffer->state = CREATED; + buffer->info = info; + info->buffer = buffer; + } else if (!strncasecmp(info->id, SCHEMA_FILE, strlen(SCHEMA_FILE))) { + info->bufsz = info->w * info->h * s_info.depth; + buffer = calloc(1, sizeof(*buffer) + info->bufsz); + if (!buffer) { + ErrPrint("Heap: %s\n", strerror(errno)); + info->bufsz = 0; + return NULL; + } + + buffer->type = BUFFER_TYPE_FILE; + buffer->refcnt = 0; + buffer->state = CREATED; + buffer->info = info; + info->buffer = buffer; + } else if (!strncasecmp(info->id, SCHEMA_SHM, strlen(SCHEMA_SHM))) { + buffer = shmat(info->handle, NULL, 0); + if (buffer == (void *)-1) { + ErrPrint("shmat: %s\n", strerror(errno)); + return NULL; + } + + return buffer->data; + } else { + DbgPrint("Buffer is NIL\n"); + return NULL; + } + } + + buffer = info->buffer; + switch (buffer->type) { + case BUFFER_TYPE_PIXMAP: + buffer->refcnt++; + break; + case BUFFER_TYPE_FILE: + buffer->refcnt++; + break; + default: + return NULL; + } + + return buffer->data; +} + +int fb_release_buffer(void *data) +{ + struct buffer *buffer; + + if (!data) + return 0; + + buffer = container_of(data, struct buffer, data); + + if (buffer->state != CREATED) { + ErrPrint("Invalid handle\n"); + return -EINVAL; + } + + switch (buffer->type) { + case BUFFER_TYPE_SHM: + /*! + * \note + * SHM can not use the "info" + * it is NULL + */ + if (shmdt(buffer) < 0) + ErrPrint("shmdt: %s\n", strerror(errno)); + break; + case BUFFER_TYPE_PIXMAP: + buffer->refcnt--; + if (buffer->refcnt == 0) { + struct fb_info *info; + info = buffer->info; + + buffer->state = DESTROYED; + free(buffer); + + if (info && info->buffer == buffer) + info->buffer = NULL; + } + break; + case BUFFER_TYPE_FILE: + buffer->refcnt--; + if (buffer->refcnt == 0) { + struct fb_info *info; + info = buffer->info; + + buffer->state = DESTROYED; + free(buffer); + + if (info && info->buffer == buffer) + info->buffer = NULL; + } + break; + default: + ErrPrint("Unknown type\n"); + return -EINVAL; + } + + return 0; +} + +int fb_refcnt(void *data) +{ + struct buffer *buffer; + struct shmid_ds buf; + int ret; + + if (!data) + return -EINVAL; + + buffer = container_of(data, struct buffer, data); + + if (buffer->state != CREATED) { + ErrPrint("Invalid handle\n"); + return -EINVAL; + } + + switch (buffer->type) { + case BUFFER_TYPE_SHM: + if (shmctl(buffer->refcnt, IPC_STAT, &buf) < 0) { + ErrPrint("shmctl: %s\n", strerror(errno)); + ret = -EFAULT; + break; + } + + ret = buf.shm_nattch; /*!< This means attached count of process */ + break; + case BUFFER_TYPE_PIXMAP: + ret = buffer->refcnt; + break; + case BUFFER_TYPE_FILE: + ret = buffer->refcnt; + break; + default: + ret = -EINVAL; + 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 -EINVAL; + } + + *w = info->w; + *h = info->h; + return 0; +} + +int fb_size(struct fb_info *info) +{ + if (!info) { + ErrPrint("Handle is not valid\n"); + return 0; + } + + info->bufsz = info->w * info->h * s_info.depth; + return info->bufsz; +} + +/* End of a file */ diff --git a/src/provider.c b/src/provider.c new file mode 100644 index 0000000..217261c --- /dev/null +++ b/src/provider.c @@ -0,0 +1,1044 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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 "dlist.h" +#include "util.h" +#include "provider.h" +#include "provider_buffer.h" +#include "provider_buffer_internal.h" +#include "debug.h" +#include "fb.h" + +static struct info { + int fd; + char *name; + struct event_handler table; + void *data; + int prevent_overwrite; +} s_info = { + .fd = -1, + .name = NULL, + .data = NULL, + .prevent_overwrite = 0, +}; + +#define EAPI __attribute__((visibility("default"))) + +/* pkgname, id, emission, source, sx, sy, ex, ey, x, y, down, ret */ +static struct packet *master_script(pid_t pid, int handle, const struct packet *packet) +{ + struct event_arg arg; + int ret; + + ret = packet_get(packet, "ssssddddddi", + &arg.pkgname, &arg.id, + &arg.info.content_event.emission, &arg.info.content_event.source, + &(arg.info.content_event.info.part.sx), &(arg.info.content_event.info.part.sy), + &(arg.info.content_event.info.part.ex), &(arg.info.content_event.info.part.ey), + &(arg.info.content_event.info.pointer.x), &(arg.info.content_event.info.pointer.y), + &(arg.info.content_event.info.pointer.down)); + if (ret != 11) { + ErrPrint("Parameter is not valid\n"); + ret = -EINVAL; + goto errout; + } + + arg.type = EVENT_CONTENT_EVENT; + + if (s_info.table.content_event) + ret = s_info.table.content_event(&arg, s_info.data); + else + ret = -ENOSYS; + +errout: + return NULL; +} + +/* pkgname, id, event, timestamp, x, y, ret */ +static struct packet *master_clicked(pid_t pid, int handle, const struct packet *packet) +{ + int ret; + struct event_arg arg; + + ret = packet_get(packet, "sssddd", + &arg.pkgname, &arg.id, + &arg.info.clicked.event, + &arg.info.clicked.timestamp, + &arg.info.clicked.x, &arg.info.clicked.y); + if (ret != 6) { + ErrPrint("Parameter is not valid\n"); + ret = -EINVAL; + goto errout; + } + + arg.type = EVENT_CLICKED; + + if (s_info.table.clicked) + ret = s_info.table.clicked(&arg, s_info.data); + else + ret = -ENOSYS; + +errout: + return NULL; +} + +/* pkgname, id, emission, source, x, y, ex, ey, ret */ +static struct packet *master_text_signal(pid_t pid, int handle, const struct packet *packet) +{ + struct event_arg arg; + int ret; + + ret = packet_get(packet, "ssssdddd", + &arg.pkgname, &arg.id, + &arg.info.text_signal.emission, &arg.info.text_signal.source, + &(arg.info.text_signal.info.part.sx), &(arg.info.text_signal.info.part.sy), + &(arg.info.text_signal.info.part.ex), &(arg.info.text_signal.info.part.ey)); + + if (ret != 8) { + ErrPrint("Parameter is not valid\n"); + ret = -EINVAL; + goto errout; + } + + arg.info.text_signal.info.pointer.x = 0.0f; + arg.info.text_signal.info.pointer.y = 0.0f; + arg.info.text_signal.info.pointer.down = 0; + arg.type = EVENT_TEXT_SIGNAL; + + if (s_info.table.text_signal) + ret = s_info.table.text_signal(&arg, s_info.data); + else + ret = -ENOSYS; + +errout: + return NULL; +} + +/* pkgname, id, ret */ +static struct packet *master_delete(pid_t pid, int handle, const struct packet *packet) +{ + struct packet *result; + struct event_arg arg; + int ret; + + ret = packet_get(packet, "ss", &arg.pkgname, &arg.id); + if (ret != 2) { + ErrPrint("Parameter is not valid\n"); + ret = -EINVAL; + goto errout; + } + + arg.type = EVENT_DELETE; + + if (s_info.table.lb_destroy) + ret = s_info.table.lb_destroy(&arg, s_info.data); + else + ret = -ENOSYS; + +errout: + result = packet_create_reply(packet, "i", ret); + return result; +} + +/* pkgname, id, w, h, ret */ +static struct packet *master_resize(pid_t pid, int handle, const struct packet *packet) +{ + struct event_arg arg; + int ret; + struct packet *result; + + ret = packet_get(packet, "ssii", &arg.pkgname, &arg.id, &arg.info.resize.w, &arg.info.resize.h); + if (ret != 4) { + ErrPrint("Parameter is not valid\n"); + ret = -EINVAL; + goto errout; + } + + arg.type = EVENT_RESIZE; + + if (s_info.table.resize) + ret = s_info.table.resize(&arg, s_info.data); + else + ret = -ENOSYS; + +errout: + result = packet_create_reply(packet, "i", ret); + return result; +} + +/* pkgname, id, content, timeout, has_Script, period, cluster, category, pinup, width, height, abi, ret */ +static struct packet *master_renew(pid_t pid, int handle, const struct packet *packet) +{ + struct event_arg arg; + int ret; + struct packet *result; + char *content; + char *title; + + arg.info.lb_recreate.out_title = NULL; + arg.info.lb_recreate.out_content = NULL; + arg.info.lb_recreate.out_is_pinned_up = 0; + + ret = packet_get(packet, "sssiidssiis", &arg.pkgname, &arg.id, + &arg.info.lb_recreate.content, + &arg.info.lb_recreate.timeout, + &arg.info.lb_recreate.has_script, + &arg.info.lb_recreate.period, + &arg.info.lb_recreate.cluster, &arg.info.lb_recreate.category, + &arg.info.lb_recreate.width, &arg.info.lb_recreate.height, + &arg.info.lb_recreate.abi); + if (ret != 11) { + ErrPrint("Parameter is not valid\n"); + ret = -EINVAL; + goto errout; + } + + arg.type = EVENT_RENEW; + + if (s_info.table.lb_recreate) + ret = s_info.table.lb_recreate(&arg, s_info.data); + else + ret = -ENOSYS; + +errout: + if (arg.info.lb_recreate.out_content) + content = arg.info.lb_recreate.out_content; + else + content = ""; + + if (arg.info.lb_recreate.out_title) + title = arg.info.lb_recreate.out_title; + else + title = ""; + + result = packet_create_reply(packet, "issi", ret, content, title, arg.info.lb_recreate.out_is_pinned_up); + /*! + * \note + * Release. + */ + free(arg.info.lb_recreate.out_title); + free(arg.info.lb_recreate.out_content); + return result; +} + +/* pkgname, id, content, timeout, has_script, period, cluster, category, pinup, skip_need_to_create, abi, result, width, height, priority */ +static struct packet *master_new(pid_t pid, int handle, const struct packet *packet) +{ + struct event_arg arg; + int ret; + struct packet *result; + int width = 0; + int height = 0; + double priority = 0.0f; + char *content; + char *title; + + arg.info.lb_create.out_content = NULL; + arg.info.lb_create.out_title = NULL; + arg.info.lb_create.out_is_pinned_up = 0; + + ret = packet_get(packet, "sssiidssisii", &arg.pkgname, &arg.id, + &arg.info.lb_create.content, + &arg.info.lb_create.timeout, + &arg.info.lb_create.has_script, + &arg.info.lb_create.period, + &arg.info.lb_create.cluster, &arg.info.lb_create.category, + &arg.info.lb_create.skip_need_to_create, + &arg.info.lb_create.abi, + &arg.info.lb_create.width, + &arg.info.lb_create.height); + if (ret != 12) { + ErrPrint("Parameter is not valid\n"); + ret = -EINVAL; + goto errout; + } + + arg.type = EVENT_NEW; + + if (s_info.table.lb_create) + ret = s_info.table.lb_create(&arg, &width, &height, &priority, s_info.data); + else + ret = -ENOSYS; + +errout: + if (arg.info.lb_create.out_content) + content = arg.info.lb_create.out_content; + else + content = ""; + + if (arg.info.lb_create.out_title) + title = arg.info.lb_create.out_title; + else + title = ""; + + result = packet_create_reply(packet, "iiidssi", ret, width, height, priority, content, title, arg.info.lb_create.out_is_pinned_up); + + /*! + * Note: + * Skip checking the address of out_content, out_title + */ + free(arg.info.lb_create.out_content); + free(arg.info.lb_create.out_title); + return result; +} + +/* pkgname, id, period, ret */ +static struct packet *master_set_period(pid_t pid, int handle, const struct packet *packet) +{ + struct event_arg arg; + int ret; + struct packet *result; + + ret = packet_get(packet, "ssd", &arg.pkgname, &arg.id, &arg.info.set_period.period); + if (ret != 3) { + ErrPrint("Parameter is not valid\n"); + ret = -EINVAL; + goto errout; + } + + arg.type = EVENT_SET_PERIOD; + + if (s_info.table.set_period) + ret = s_info.table.set_period(&arg, s_info.data); + else + ret = -ENOSYS; + +errout: + result = packet_create_reply(packet, "i", ret); + return result; +} + +/* pkgname, id, cluster, category, ret */ +static struct packet *master_change_group(pid_t pid, int handle, const struct packet *packet) +{ + struct event_arg arg; + int ret; + struct packet *result; + + ret = packet_get(packet, "ssss", &arg.pkgname, &arg.id, + &arg.info.change_group.cluster, &arg.info.change_group.category); + if (ret != 4) { + ErrPrint("Parameter is not valid\n"); + ret = -EINVAL; + goto errout; + } + + arg.type = EVENT_CHANGE_GROUP; + + if (s_info.table.change_group) + ret = s_info.table.change_group(&arg, s_info.data); + else + ret = -ENOSYS; + +errout: + result = packet_create_reply(packet, "i", ret); + return result; +} + +/* pkgname, id, pinup, ret */ +static struct packet *master_pinup(pid_t pid, int handle, const struct packet *packet) +{ + struct event_arg arg; + int ret; + struct packet *result; + const char *content; + + ret = packet_get(packet, "ssi", &arg.pkgname, &arg.id, &arg.info.pinup.state); + if (ret != 3) { + ErrPrint("Parameter is not valid\n"); + ret = -EINVAL; + goto errout; + } + + arg.type = EVENT_PINUP; + + if (s_info.table.pinup) + ret = s_info.table.pinup(&arg, s_info.data); + else + ret = -ENOSYS; + +errout: + content = "default"; + if (ret == 0 && arg.info.pinup.content_info) + content = arg.info.pinup.content_info; + + result = packet_create_reply(packet, "is", ret, content); + if (ret == 0) + free(arg.info.pinup.content_info); + return result; +} + +/* pkgname, id, cluster, category, ret */ +static struct packet *master_update_content(pid_t pid, int handle, const struct packet *packet) +{ + struct event_arg arg; + int ret; + + ret = packet_get(packet, "ssss", &arg.pkgname, &arg.id, &arg.info.update_content.cluster, &arg.info.update_content.category); + if (ret != 4) { + ErrPrint("Parameter is not valid\n"); + ret = -EINVAL; + goto errout; + } + + arg.type = EVENT_UPDATE_CONTENT; + + if (s_info.table.update_content) + ret = s_info.table.update_content(&arg, s_info.data); + else + ret = -ENOSYS; + +errout: + return NULL; +} + +static struct packet *master_lb_pause(pid_t pid, int handle, const struct packet *packet) +{ + struct event_arg arg; + int ret; + + ret = packet_get(packet, "ss", &arg.pkgname, &arg.id); + if (ret != 2) { + ErrPrint("Invalid parameter\n"); + return NULL; + } + + arg.type = EVENT_LB_PAUSE; + + if (s_info.table.lb_pause) + (void)s_info.table.lb_pause(&arg, s_info.data); + + return NULL; +} + +static struct packet *master_lb_resume(pid_t pid, int handle, const struct packet *packet) +{ + struct event_arg arg; + int ret; + + ret = packet_get(packet, "ss", &arg.pkgname, &arg.id); + if (ret != 2) { + ErrPrint("Invalid parameter\n"); + return NULL; + } + + arg.type = EVENT_LB_RESUME; + + if (s_info.table.lb_resume) + (void)s_info.table.lb_resume(&arg, s_info.data); + + return NULL; +} + +/* timestamp, ret */ +static struct packet *master_pause(pid_t pid, int handle, const struct packet *packet) +{ + struct event_arg arg; + struct packet *result; + int ret; + + ret = packet_get(packet, "d", &arg.info.pause.timestamp); + if (ret != 1) { + ErrPrint("Parameter is not valid\n"); + ret = -EINVAL; + goto errout; + } + arg.pkgname = NULL; + arg.id = NULL; + arg.type = EVENT_PAUSE; + + if (s_info.table.pause) + ret = s_info.table.pause(&arg, s_info.data); + else + ret = -ENOSYS; + +errout: + result = packet_create_reply(packet, "i", ret); + return result; +} + +/* timestamp, ret */ +static struct packet *master_resume(pid_t pid, int handle, const struct packet *packet) +{ + struct packet *result; + struct event_arg arg; + int ret; + + ret = packet_get(packet, "d", &arg.info.resume.timestamp); + if (ret != 1) { + ErrPrint("Parameter is not valid\n"); + ret = -EINVAL; + goto errout; + } + + arg.pkgname = NULL; + arg.id = NULL; + arg.type = EVENT_RESUME; + + if (s_info.table.resume) + ret = s_info.table.resume(&arg, s_info.data); + else + ret = -ENOSYS; + +errout: + result = packet_create_reply(packet, "i", ret); + if (!result) + ErrPrint("Failed to create result packet\n"); + return result; +} + +struct packet *master_pd_create(pid_t pid, int handle, const struct packet *packet) +{ + struct event_arg arg; + int ret; + + ret = packet_get(packet, "ssiidd", &arg.pkgname, &arg.id, &arg.info.pd_create.w, &arg.info.pd_create.h, &arg.info.pd_create.x, &arg.info.pd_create.y); + if (ret != 6) { + ErrPrint("Invalid packet\n"); + ret = -EINVAL; + goto out; + } + + arg.type = EVENT_PD_CREATE; + + if (s_info.table.pd_create) + ret = s_info.table.pd_create(&arg, s_info.data); + else + ret = -ENOSYS; + +out: + return NULL; +} + +struct packet *master_pd_destroy(pid_t pid, int handle, const struct packet *packet) +{ + struct event_arg arg; + int ret; + + ret = packet_get(packet, "ss", &arg.pkgname, &arg.id); + if (ret != 2) { + ErrPrint("Invalid packet\n"); + ret = -EINVAL; + goto out; + } + + arg.type = EVENT_PD_DESTROY; + if (s_info.table.pd_destroy) + ret = s_info.table.pd_destroy(&arg, s_info.data); + else + ret = -ENOSYS; + +out: + return NULL; +} + +static struct method s_table[] = { + /*!< For the buffer type */ + { + .cmd = "lb_mouse_move", + .handler = provider_buffer_lb_mouse_move, + }, + { + .cmd = "pd_mouse_move", + .handler = provider_buffer_pd_mouse_move, + }, + { + .cmd = "pd_show", + .handler = master_pd_create, + }, + { + .cmd = "pd_hide", + .handler = master_pd_destroy, + }, + { + .cmd = "pd_mouse_up", + .handler = provider_buffer_pd_mouse_up, + }, + { + .cmd = "pd_mouse_down", + .handler = provider_buffer_pd_mouse_down, + }, + { + .cmd = "pd_mouse_enter", + .handler = provider_buffer_pd_mouse_enter, + }, + { + .cmd = "pd_mouse_leave", + .handler = provider_buffer_pd_mouse_leave, + }, + { + .cmd = "lb_mouse_up", + .handler = provider_buffer_lb_mouse_up, + }, + { + .cmd = "lb_mouse_down", + .handler = provider_buffer_lb_mouse_down, + }, + { + .cmd = "lb_mouse_enter", + .handler = provider_buffer_lb_mouse_enter, + }, + { + .cmd = "lb_mouse_leave", + .handler = provider_buffer_lb_mouse_leave, + }, + { + .cmd = "lb_pause", + .handler = master_lb_pause, + }, + { + .cmd = "lb_resume", + .handler = master_lb_resume, + }, + { + .cmd = "script", + .handler = master_script, /* pkgname, id, emission, source, sx, sy, ex, ey, x, y, down, ret */ + }, + { + .cmd = "clicked", + .handler = master_clicked, /* pkgname, id, event, timestamp, x, y, ret */ + }, + { + .cmd = "text_signal", + .handler = master_text_signal, /* pkgname, id, emission, source, x, y, ex, ey, ret */ + }, + { + .cmd = "delete", + .handler = master_delete, /* pkgname, id, ret */ + }, + { + .cmd = "resize", + .handler = master_resize, /* pkgname, id, w, h, ret */ + }, + { + .cmd = "renew", + .handler = master_renew, /* pkgname, id, content, timeout, has_script, period, cluster, category, pinup, width, height, abi, ret */ + }, + { + .cmd = "new", + .handler = master_new, /* pkgname, id, content, timeout, has_script, period, cluster, category, pinup, skip_need_to_create, abi, result, width, height, priority */ + }, + { + .cmd = "set_period", + .handler = master_set_period, /* pkgname, id, period, ret */ + }, + { + .cmd = "change_group", + .handler = master_change_group, /* pkgname, id, cluster, category, ret */ + }, + { + .cmd = "pinup", + .handler = master_pinup, /* pkgname, id, pinup, ret */ + }, + { + .cmd = "update_content", + .handler = master_update_content, /* pkgname, cluster, category, ret */ + }, + { + .cmd = "pause", + .handler = master_pause, /* timestamp, ret */ + }, + { + .cmd = "resume", + .handler = master_resume, /* timestamp, ret */ + }, + { + .cmd = NULL, + .handler = NULL, + }, +}; + +static int connected_cb(int handle, void *data) +{ + DbgPrint("Connected (%p) %d\n", s_info.table.connected, handle); + + if (s_info.fd >= 0) { + ErrPrint("Already connected. Ignore this (%d)?\n", handle); + return 0; + } + + s_info.fd = handle; + + if (s_info.table.connected) + s_info.table.connected(NULL, s_info.data); + + return 0; +} + +static int disconnected_cb(int handle, void *data) +{ + if (s_info.fd != handle) { + DbgPrint("%d is not my favor (%d)\n", handle, s_info.fd); + return 0; + } + + DbgPrint("Disconnected (%d)\n", handle); + if (s_info.table.disconnected) + s_info.table.disconnected(NULL, s_info.data); + + /* Reset the FD */ + s_info.fd = -1; + return 0; +} + +EAPI int provider_init(void *disp, const char *name, struct event_handler *table, void *data) +{ + int ret; + const char *option; + + option = getenv("PROVIDER_DISABLE_PREVENT_OVERWRITE"); + if (option && !strcasecmp(option, "true")) + s_info.prevent_overwrite = 1; + + option = getenv("PROVIDER_COM_CORE_THREAD"); + if (option && !strcasecmp(option, "true")) + com_core_packet_use_thread(1); + + if (!name || !table) { + ErrPrint("Invalid argument\n"); + return -EINVAL; + } + + if (s_info.name) { + ErrPrint("Provider is already initialized\n"); + return -EALREADY; + } + + s_info.name = strdup(name); + if (!s_info.name) { + ErrPrint("Heap: %s\n", strerror(errno)); + return -ENOMEM; + } + + memcpy(&s_info.table, table, sizeof(*table)); + s_info.data = data; + + com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL); + com_core_add_event_callback(CONNECTOR_CONNECTED, connected_cb, NULL); + + ret = com_core_packet_client_init(SLAVE_SOCKET, 0, s_table); + if (ret < 0) { + ErrPrint("Failed to establish the connection with the master\n"); + return s_info.fd; + } + + provider_buffer_init(disp); + + DbgPrint("Slave is initialized\n"); + return 0; +} + +EAPI void *provider_fini(void) +{ + void *ret; + + if (!s_info.name) { + ErrPrint("Connection is not established (or cleared already)\n"); + return NULL; + } + + if (s_info.fd >= 0) { + com_core_packet_client_fini(s_info.fd); + s_info.fd = -1; + } + + com_core_del_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL); + com_core_del_event_callback(CONNECTOR_CONNECTED, connected_cb, NULL); + + provider_buffer_fini(); + + free(s_info.name); + s_info.name = NULL; + + ret = s_info.data; + s_info.data = NULL; + return ret; +} + +EAPI int provider_send_call(const char *pkgname, const char *id, const char *funcname) +{ + struct packet *packet; + int ret; + + if (!pkgname || !id || !funcname) { + ErrPrint("Invalid argument\n"); + return -EINVAL; + } + + packet = packet_create_noack("call", "ssss", s_info.name, pkgname, id, funcname); + if (!packet) { + ErrPrint("Failed to create a packet\n"); + return -EFAULT; + } + + ret = com_core_packet_send_only(s_info.fd, packet); + packet_destroy(packet); + return ret; +} + +EAPI int provider_send_ret(const char *pkgname, const char *id, const char *funcname) +{ + struct packet *packet; + int ret; + + if (!pkgname || !id || !funcname) { + ErrPrint("Invalid argument\n"); + return -EINVAL; + } + + packet = packet_create_noack("ret", "ssss", s_info.name, pkgname, id, funcname); + if (!packet) { + ErrPrint("Failed to create a packet\n"); + return -EFAULT; + } + + ret = com_core_packet_send_only(s_info.fd, packet); + packet_destroy(packet); + return ret; +} + +EAPI int provider_send_faulted(const char *pkgname, const char *id, const char *funcname) +{ + struct packet *packet; + int ret; + + if (!pkgname || !id || !funcname) { + ErrPrint("Invalid argument\n"); + return -EINVAL; + } + + packet = packet_create_noack("faulted", "ssss", s_info.name, pkgname, id, funcname); + if (!packet) { + ErrPrint("Failed to create a packet\n"); + return -EFAULT; + } + + ret = com_core_packet_send_only(s_info.fd, packet); + packet_destroy(packet); + return ret; +} + +EAPI int provider_send_hello(void) +{ + struct packet *packet; + int ret; + DbgPrint("name[%s]\n", s_info.name); + + if (!s_info.name) { + ErrPrint("Provider is not initialized\n"); + return -EINVAL; + } + + if (s_info.fd < 0) { + ErrPrint("Connection is not established\n"); + return -EINVAL; + } + + packet = packet_create_noack("hello", "s", s_info.name); + if (!packet) { + ErrPrint("Failed to create a packet\n"); + return -EFAULT; + } + + ret = com_core_packet_send_only(s_info.fd, packet); + packet_destroy(packet); + return ret; +} + +EAPI int provider_send_ping(void) +{ + struct packet *packet; + int ret; + + DbgPrint("name[%s]\n", s_info.name); + if (!s_info.name) { + ErrPrint("Provider is not initialized\n"); + return -EINVAL; + } + + if (s_info.fd < 0) { + ErrPrint("Connection is not established\n"); + return -EINVAL; + } + + packet = packet_create_noack("ping", "s", s_info.name); + if (!packet) { + ErrPrint("Failed to create a a packet\n"); + return -EFAULT; + } + + ret = com_core_packet_send_only(s_info.fd, packet); + packet_destroy(packet); + return ret; +} + +static inline void keep_file_in_safe(const char *id) +{ + const char *path; + int len; + int base_idx; + char *new_path; + + path = util_uri_to_path(id); + if (!path) { + ErrPrint("Invalid path\n"); + return; + } + + /*! + * \TODO: REMOVE ME + */ + if (s_info.prevent_overwrite) + return; + + if (access(path, R_OK | F_OK) != 0) + return; + + len = strlen(path); + base_idx = len - 1; + + while (base_idx > 0 && path[base_idx] != '/') base_idx--; + base_idx += (path[base_idx] == '/'); + + new_path = malloc(len + 10); /* for "tmp" */ + if (!new_path) { + ErrPrint("Heap: %s\n", strerror(errno)); + return; + } + + strncpy(new_path, path, base_idx); + snprintf(new_path + base_idx, len + 10 - base_idx, "reader/%s", path + base_idx); + + if (unlink(new_path) < 0) + ErrPrint("Unlink(%s): %s\n", new_path, strerror(errno)); + + if (rename(path, new_path) < 0) + ErrPrint("Failed to keep content in safe: %s (%s -> %s)\n", strerror(errno), path, new_path); + + free(new_path); +} + +EAPI int provider_send_updated(const char *pkgname, const char *id, int w, int h, double priority, const char *content_info, const char *title) +{ + struct packet *packet; + int ret; + + if (!pkgname || !id) { + ErrPrint("Invalid argument\n"); + return -EINVAL; + } + + if (!content_info) + content_info = ""; + + if (!title) + title = ""; + + if (s_info.fd < 0) { + ErrPrint("Connection is not established\n"); + return -EINVAL; + } + + keep_file_in_safe(id); + + packet = packet_create_noack("updated", "sssiidss", + s_info.name, pkgname, id, w, h, priority, content_info, title); + if (!packet) { + ErrPrint("failed to build a packet\n"); + return -EFAULT; + } + + ret = com_core_packet_send_only(s_info.fd, packet); + packet_destroy(packet); + return ret; +} + +EAPI int provider_send_desc_updated(const char *pkgname, const char *id, const char *descfile) +{ + struct packet *packet; + int ret; + + if (!pkgname || !id) { + ErrPrint("Invalid argument\n"); + return -EINVAL; + } + + if (s_info.fd < 0) { + ErrPrint("Connection is not established\n"); + return -EINVAL; + } + + if (!descfile) + descfile = util_uri_to_path(id); /* In case of the NULL descfilename, use the ID */ + + packet = packet_create_noack("desc_updated", "ssss", s_info.name, pkgname, id, descfile); + if (!packet) { + ErrPrint("Failed to build a packet\n"); + return -EFAULT; + } + + ret = com_core_packet_send_only(s_info.fd, packet); + packet_destroy(packet); + return ret; +} + +EAPI int provider_send_deleted(const char *pkgname, const char *id) +{ + struct packet *packet; + int ret; + + if (!pkgname || !id) { + ErrPrint("Invalid arguement\n"); + return -EINVAL; + } + + if (s_info.fd < 0) { + ErrPrint("Connection is not established\n"); + return -EINVAL; + } + + packet = packet_create_noack("deleted", "sss", s_info.name, pkgname, id); + if (!packet) { + ErrPrint("Failed to build a packet\n"); + return -EFAULT; + } + + ret = com_core_packet_send_only(s_info.fd, packet); + packet_destroy(packet); + return ret; +} + +const char *provider_name(void) +{ + return s_info.name; +} + +/* End of a file */ diff --git a/src/provider_buffer.c b/src/provider_buffer.c new file mode 100644 index 0000000..386217f --- /dev/null +++ b/src/provider_buffer.c @@ -0,0 +1,799 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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 "dlist.h" +#include "util.h" +#include "debug.h" +#include "fb.h" +#include "provider.h" +#include "provider_buffer.h" +#include "provider_buffer_internal.h" + +#define EAPI __attribute__((visibility("default"))) + +static struct { + struct dlist *buffer_list; +} s_info = { + .buffer_list = NULL, +}; + +static inline struct fb_info *send_acquire_request(enum target_type type, const char *pkgname, const char *id, int w, int h, int size) +{ + struct packet *packet; + struct packet *result; + const char *buffer_id; + struct fb_info *ret; + int status; + + packet = packet_create("acquire_buffer", "isssiii", type, provider_name(), pkgname, id, w, h, size); + if (!packet) { + ErrPrint("Failed to build a packet\n"); + return NULL; + } + + DbgPrint("type: 0x%X, name: %s, pkgname[%s], id[%s], w[%d], h[%d], size[%d]\n", type, provider_name(), pkgname, id, w, h, size); + + result = com_core_packet_oneshot_send(SLAVE_SOCKET, packet, 0.0f); + packet_destroy(packet); + + if (!result) { + ErrPrint("Failed to send a request\n"); + return NULL; + } + + if (packet_get(result, "is", &status, &buffer_id) != 2) { + ErrPrint("Failed to get a result packet\n"); + packet_unref(result); + return NULL; + } + + if (status != 0) { + ErrPrint("Failed to acquire buffer: %d\n", status); + packet_unref(result); + return NULL; + } + + ret = fb_create(buffer_id, w, h); + /*! + * \TODO: Implements me + */ + DbgPrint("buffer id[%s], fb[%p]\n", buffer_id, ret); + packet_unref(result); + + return ret; +} + +static inline int send_release_request(enum target_type type, const char *pkgname, const char *id) +{ + struct packet *packet; + struct packet *result; + int ret; + + packet = packet_create("release_buffer", "isss", type, provider_name(), pkgname, id); + if (!packet) { + ErrPrint("Failed to build a packet\n"); + return -EFAULT; + } + + result = com_core_packet_oneshot_send(SLAVE_SOCKET, packet, 0.0f); + packet_destroy(packet); + if (!result) { + ErrPrint("Failed to send a request\n"); + return -EFAULT; + } + + if (packet_get(result, "i", &ret) != 1) { + ErrPrint("Invalid result packet\n"); + ret = -EINVAL; + } + + packet_unref(result); + return ret; +} + +static inline struct fb_info *send_resize_request(enum target_type type, const char *pkgname, const char *id, int w, int h) +{ + struct packet *packet; + struct packet *result; + int ret; + const char *buffer_id; + struct fb_info *fb; + + packet = packet_create("resize_buffer", "isssii", type, provider_name(), pkgname, id, w, h); + if (!packet) { + ErrPrint("Faield to build a packet\n"); + return NULL; + } + + result = com_core_packet_oneshot_send(SLAVE_SOCKET, packet, 0.0f); + packet_destroy(packet); + if (!result) { + ErrPrint("Failed to send a request\n"); + return NULL; + } + + if (packet_get(result, "is", &ret, &buffer_id) != 2) { + ErrPrint("Invalid result packet\n"); + packet_unref(result); + return NULL; + } + + fb = (ret == 0) ? fb_create(buffer_id, w, h) : NULL; + packet_unref(result); + return fb; +} + +struct livebox_buffer *provider_buffer_find_buffer(enum target_type type, const char *pkgname, const char *id) +{ + struct dlist *l; + struct dlist *n; + struct livebox_buffer *info; + + dlist_foreach_safe(s_info.buffer_list, l, n, info) { + if (info->type != type) + continue; + + if (!strcmp(info->pkgname, pkgname) && !strcmp(info->id, id)) + return info; + } + + return NULL; +} + +EAPI struct livebox_buffer *provider_buffer_acquire(enum target_type type, const char *pkgname, const char *id, int width, int height, int pixel_size, int (*handler)(struct livebox_buffer *, enum buffer_event, double, double, double, void *), void *data) +{ + struct livebox_buffer *info; + + if (!pkgname) { + ErrPrint("Invalid parameter: pkgname is NIL\n"); + return NULL; + } + + if (!id) { + ErrPrint("Invalid ID: id is NIL\n"); + return NULL; + } + + if (!handler) + DbgPrint("Event handler is not speicified\n"); + + DbgPrint("acquire_buffer: [%s] %s, %dx%d, size: %d, handler: %p\n", + type == TYPE_LB ? "LB" : "PD", id, + width, height, pixel_size, handler); + + info = malloc(sizeof(*info)); + if (!info) { + ErrPrint("Heap: %s\n", strerror(errno)); + return NULL; + } + + info->pkgname = strdup(pkgname); + if (!info->pkgname) { + ErrPrint("Heap: %s\n", strerror(errno)); + free(info); + return NULL; + } + + info->id = strdup(id); + if (!info->id) { + ErrPrint("Heap: %s\n", strerror(errno)); + free(info->pkgname); + free(info); + return NULL; + } + + info->fb = send_acquire_request(type, pkgname, id, width, height, pixel_size); + if (!info->fb) { + ErrPrint("Failed to acquire a info\n"); + free(info->pkgname); + free(info->id); + free(info); + return NULL; + } + + info->width = width; + info->height = height; + info->pixel_size = pixel_size; + info->handler = handler; + info->type = type; + info->data = data; + info->state = BUFFER_CREATED; + + s_info.buffer_list = dlist_append(s_info.buffer_list, info); + return info; +} + +EAPI int provider_buffer_resize(struct livebox_buffer *info, int w, int h) +{ + struct fb_info *fb; + + if (!info || info->state != BUFFER_CREATED) { + ErrPrint("info is not valid\n"); + return -EINVAL; + } + + fb = send_resize_request(info->type, info->pkgname, info->id, w, h); + if (!fb) + return -EINVAL; + + /*! + * \note + * Even if we destroy the buffer object, + * if the user references it, it will not be destroyed, + * it only can be destroyed when there is no reference exists. + */ + info->fb = fb; + return 0; +} + +EAPI void *provider_buffer_ref(struct livebox_buffer *info) +{ + if (!info || info->state != BUFFER_CREATED) { + ErrPrint("info is not valid\n"); + return NULL; + } + + return fb_acquire_buffer(info->fb); +} + +EAPI int provider_buffer_unref(void *ptr) +{ + if (!ptr) { + ErrPrint("PTR is not valid\n"); + return -EINVAL; + } + + return fb_release_buffer(ptr); +} + +EAPI int provider_buffer_release(struct livebox_buffer *info) +{ + int ret; + + if (!info || info->state != BUFFER_CREATED) { + ErrPrint("Buffer handler is NULL\n"); + return -EINVAL; + } + + dlist_remove_data(s_info.buffer_list, info); + + ret = send_release_request(info->type, info->pkgname, info->id); + if (ret < 0) { + ErrPrint("Failed to send a release request\n"); + /*! + * \note + * But go ahead to destroy this buffer object + */ + } + + info->state = BUFFER_DESTROYED; + free(info->pkgname); + free(info->id); + free(info); + return 0; +} + +EAPI int provider_buffer_sync(struct livebox_buffer *info) +{ + if (!info || info->state != BUFFER_CREATED) { + ErrPrint("Buffer handler is NULL\n"); + return -EINVAL; + } + + return fb_sync(info->fb); +} + +EAPI enum target_type provider_buffer_type(struct livebox_buffer *info) +{ + if (!info || info->state != BUFFER_CREATED) { + ErrPrint("Buffer handler is NULL\n"); + return TYPE_ERROR; + } + + return info->type; +} + +EAPI const char *provider_buffer_pkgname(struct livebox_buffer *info) +{ + if (!info || info->state != BUFFER_CREATED) { + ErrPrint("Buffer handler is NULL\n"); + return NULL; + } + + return info->pkgname; +} + +/*! + * \brief + * Getting the URI of given buffer. + */ +EAPI const char *provider_buffer_id(struct livebox_buffer *info) +{ + if (!info || info->state != BUFFER_CREATED) { + ErrPrint("Buffer handler is NULL\n"); + return NULL; + } + + return info->id; +} + +EAPI int provider_buffer_get_size(struct livebox_buffer *info, int *w, int *h, int *pixel_size) +{ + if (!info || info->state != BUFFER_CREATED) { + ErrPrint("Buffer handler is NULL\n"); + return -EINVAL; + } + + if (w) + *w = info->width; + + if (h) + *h = info->height; + + if (pixel_size) + *pixel_size = info->pixel_size; + + return 0; +} + +/*! + * \brief + * If the given buffer is created as pixmap, + * This function returns pixmap ID. + */ +EAPI unsigned long provider_buffer_pixmap_id(struct livebox_buffer *info) +{ + const char *id; + unsigned long pixmap; + + if (!info || info->state != BUFFER_CREATED) { + ErrPrint("Buffer handler is NULL\n"); + return 0; + } + + id = fb_id(info->fb); + if (!id) + return 0; + + if (sscanf(id, SCHEMA_PIXMAP "%lu", &pixmap) != 1) { + ErrPrint("Invalid ID: %s\n", id); + return 0; + } + + return pixmap; +} + +EAPI int provider_buffer_pixmap_is_support_hw(struct livebox_buffer *info) +{ + return fb_has_gem(info->fb); +} + +EAPI int provider_buffer_pixmap_create_hw(struct livebox_buffer *info) +{ + if (!fb_has_gem(info->fb)) + return -EINVAL; + + return fb_create_gem(info->fb); +} + +EAPI int provider_buffer_pixmap_destroy_hw(struct livebox_buffer *info) +{ + if (!fb_has_gem(info->fb)) + return -EINVAL; + + return fb_destroy_gem(info->fb); +} + +EAPI void *provider_buffer_pixmap_hw_addr(struct livebox_buffer *info) +{ + void *addr; + + if (!fb_has_gem(info->fb)) + return NULL; + + addr = fb_acquire_gem(info->fb); + fb_release_gem(info->fb); + + DbgPrint("Canvas address is %p\n", addr); + return addr; +} + +EAPI int provider_buffer_pre_render(struct livebox_buffer *info) +{ + int ret = 0; + + if (fb_has_gem(info->fb)) + ret = fb_acquire_gem(info->fb) ? 0 : -EFAULT; + + return ret; +} + +EAPI int provider_buffer_post_render(struct livebox_buffer *info) +{ + int ret = 0; + + if (fb_has_gem(info->fb)) + ret = fb_release_gem(info->fb) ? 0 : -EFAULT; + + return ret; +} + +int provider_buffer_init(void *display) +{ + return fb_init(display); +} + +int provider_buffer_fini(void) +{ + return fb_fini(); +} + +struct packet *provider_buffer_lb_mouse_enter(pid_t pid, int handle, const struct packet *packet) +{ + const char *pkgname; + const char *id; + int w; + int h; + double x; + double y; + double timestamp; + int ret; + struct livebox_buffer *info; + + if (packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, ×tamp, &x, &y) != 7) { + ErrPrint("Invalid packet\n"); + ret = -EINVAL; + goto out; + } + + info = provider_buffer_find_buffer(TYPE_LB, pkgname, id); + if (!info) { + ErrPrint("Failed to find a buffer [%s:%s]\n", pkgname, id); + ret = -ENOENT; + goto out; + } + + if (info->handler) + ret = info->handler(info, BUFFER_EVENT_ENTER, timestamp, x, y, info->data); + else + ret = -ENOSYS; + +out: + return NULL; +} + +struct packet *provider_buffer_lb_mouse_leave(pid_t pid, int handle, const struct packet *packet) +{ + const char *pkgname; + const char *id; + int w; + int h; + double x; + double y; + double timestamp; + int ret; + struct livebox_buffer *info; + + if (packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, ×tamp, &x, &y) != 7) { + ErrPrint("Invalid packet\n"); + ret = -EINVAL; + goto out; + } + + info = provider_buffer_find_buffer(TYPE_LB, pkgname, id); + if (!info) { + ErrPrint("Failed to find a buffer [%s:%s]\n", pkgname, id); + ret = -ENOENT; + goto out; + } + + if (info->handler) + ret = info->handler(info, BUFFER_EVENT_LEAVE, timestamp, x, y, info->data); + else + ret = -ENOSYS; + +out: + return NULL; +} + +struct packet *provider_buffer_lb_mouse_down(pid_t pid, int handle, const struct packet *packet) +{ + const char *pkgname; + const char *id; + int w; + int h; + double x; + double y; + double timestamp; + int ret; + struct livebox_buffer *info; + + if (packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, ×tamp, &x, &y) != 7) { + ErrPrint("Invalid packet\n"); + ret = -EINVAL; + goto out; + } + + info = provider_buffer_find_buffer(TYPE_LB, pkgname, id); + if (!info) { + ErrPrint("Failed to find a buffer [%s:%s]\n", pkgname, id); + ret = -ENOENT; + goto out; + } + + if (info->handler) + ret = info->handler(info, BUFFER_EVENT_DOWN, timestamp, x, y, info->data); + else + ret = -ENOSYS; + +out: + return NULL; +} + +struct packet *provider_buffer_lb_mouse_up(pid_t pid, int handle, const struct packet *packet) +{ + const char *pkgname; + const char *id; + int w; + int h; + double x; + double y; + double timestamp; + int ret; + struct livebox_buffer *info; + + if (packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, ×tamp, &x, &y) != 7) { + ErrPrint("Invalid packet\n"); + ret = -EINVAL; + goto out; + } + + info = provider_buffer_find_buffer(TYPE_LB, pkgname, id); + if (!info) { + ErrPrint("Failed to find a buffer [%s:%s]\n", pkgname, id); + ret = -ENOENT; + goto out; + } + + if (info->handler) + ret = info->handler(info, BUFFER_EVENT_UP, timestamp, x, y, info->data); + else + ret = -ENOSYS; + +out: + return NULL; +} + +struct packet *provider_buffer_lb_mouse_move(pid_t pid, int handle, const struct packet *packet) +{ + const char *pkgname; + const char *id; + int w; + int h; + double x; + double y; + double timestamp; + int ret; + struct livebox_buffer *info; + + if (packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, ×tamp, &x, &y) != 7) { + ErrPrint("Invalid packet\n"); + ret = -EINVAL; + goto out; + } + + info = provider_buffer_find_buffer(TYPE_LB, pkgname, id); + if (!info) { + ErrPrint("Failed to find a buffer [%s:%s]\n", pkgname, id); + ret = -ENOENT; + goto out; + } + + if (info->handler) + ret = info->handler(info, BUFFER_EVENT_MOVE, timestamp, x, y, info->data); + else + ret = -ENOSYS; + +out: + return NULL; +} + +struct packet *provider_buffer_pd_mouse_enter(pid_t pid, int handle, const struct packet *packet) +{ + const char *pkgname; + const char *id; + int w; + int h; + double x; + double y; + double timestamp; + int ret; + struct livebox_buffer *info; + + if (packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, ×tamp, &x, &y) != 7) { + ErrPrint("Invalid packet\n"); + ret = -EINVAL; + goto out; + } + + info = provider_buffer_find_buffer(TYPE_PD, pkgname, id); + if (!info) { + ErrPrint("Failed to find a buffer [%s:%s]\n", pkgname, id); + ret = -ENOENT; + goto out; + } + + if (info->handler) + ret = info->handler(info, BUFFER_EVENT_ENTER, timestamp, x, y, info->data); + else + ret = -ENOSYS; + +out: + return NULL; +} + +struct packet *provider_buffer_pd_mouse_leave(pid_t pid, int handle, const struct packet *packet) +{ + const char *pkgname; + const char *id; + int w; + int h; + double x; + double y; + double timestamp; + int ret; + struct livebox_buffer *info; + + if (packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, ×tamp, &x, &y) != 7) { + ErrPrint("Invalid packet\n"); + ret = -EINVAL; + goto out; + } + + info = provider_buffer_find_buffer(TYPE_PD, pkgname, id); + if (!info) { + ErrPrint("Failed to find a buffer [%s:%s]\n", pkgname, id); + ret = -ENOENT; + goto out; + } + + if (info->handler) + ret = info->handler(info, BUFFER_EVENT_LEAVE, timestamp, x, y, info->data); + else + ret = -ENOSYS; + +out: + return NULL; +} + +struct packet *provider_buffer_pd_mouse_down(pid_t pid, int handle, const struct packet *packet) +{ + const char *pkgname; + const char *id; + int w; + int h; + double x; + double y; + double timestamp; + int ret; + struct livebox_buffer *info; + + if (packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, ×tamp, &x, &y) != 7) { + ErrPrint("Invalid packet\n"); + ret = -EINVAL; + goto out; + } + + info = provider_buffer_find_buffer(TYPE_PD, pkgname, id); + if (!info) { + ErrPrint("Failed to find a buffer [%s:%s]\n", pkgname, id); + ret = -ENOENT; + goto out; + } + + if (info->handler) + ret = info->handler(info, BUFFER_EVENT_DOWN, timestamp, x, y, info->data); + else + ret = -ENOSYS; + +out: + return NULL; +} + +struct packet *provider_buffer_pd_mouse_up(pid_t pid, int handle, const struct packet *packet) +{ + const char *pkgname; + const char *id; + int w; + int h; + double x; + double y; + double timestamp; + int ret; + struct livebox_buffer *info; + + if (packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, ×tamp, &x, &y) != 7) { + ErrPrint("Invalid packet\n"); + ret = -EINVAL; + goto out; + } + + info = provider_buffer_find_buffer(TYPE_PD, pkgname, id); + if (!info) { + ErrPrint("Failed to find a buffer [%s:%s]\n", pkgname, id); + ret = -ENOENT; + goto out; + } + + if (info->handler) + ret = info->handler(info, BUFFER_EVENT_UP, timestamp, x, y, info->data); + else + ret = -ENOSYS; + +out: + return NULL; +} + +struct packet *provider_buffer_pd_mouse_move(pid_t pid, int handle, const struct packet *packet) +{ + const char *pkgname; + const char *id; + int w; + int h; + double x; + double y; + double timestamp; + int ret; + struct livebox_buffer *info; + + ret = packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, ×tamp, &x, &y); + if (ret != 7) { + ErrPrint("Invalid packet\n"); + ret = -EINVAL; + goto out; + } + + info = provider_buffer_find_buffer(TYPE_PD, pkgname, id); + if (!info) { + ErrPrint("Failed to find a buffer [%s:%s]\n", pkgname, id); + ret = -ENOENT; + goto out; + } + + if (info->handler) + ret = info->handler(info, BUFFER_EVENT_MOVE, timestamp, x, y, info->data); + else + ret = -ENOSYS; + +out: + return NULL; +} + +/* End of a file */ diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..786d04b --- /dev/null +++ b/src/util.c @@ -0,0 +1,59 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.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 "util.h" +#include "debug.h" + +double util_get_timestamp(void) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + + return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0f; +} + +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; +} + +/* End of a file */ -- 2.7.4