From: Junkyeong Kim Date: Thu, 24 Aug 2023 08:09:52 +0000 (+0900) Subject: Init cbhm X-Git-Tag: accepted/tizen/unified/20230825.044228~2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f85a885b3ce933bfc90356a36a5e29fb10518c5a;p=platform%2Fcore%2Fuifw%2Fcbhm.git Init cbhm Change-Id: I832274762d3f8b988710d87cb08a098fe9cc52c9 Signed-off-by: Junkyeong Kim --- diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..c4134f9 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,13 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(cbhm C) + +INCLUDE(FindPkgConfig) + +SET(CLIENT "${PROJECT_NAME}") +SET(DAEMON "${PROJECT_NAME}-service") + +SET(PREFIX "${CMAKE_INSTALL_PREFIX}") +SET(VERSION ${FULLVER}) +SET(SHARED_DIR "${PREFIX}/shared") + +ADD_SUBDIRECTORY(src) diff --git a/LICENSE.APLv2 b/LICENSE.APLv2 new file mode 100644 index 0000000..572c853 --- /dev/null +++ b/LICENSE.APLv2 @@ -0,0 +1,178 @@ +Copyright (c) 2010 - 2015 Samsung Electronics Co., Ltd. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + 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. + + 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, + 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 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 in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) 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 + + (d) 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 diff --git a/packaging/cbhm.manifest b/packaging/cbhm.manifest new file mode 100644 index 0000000..a76fdba --- /dev/null +++ b/packaging/cbhm.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/packaging/cbhm.path b/packaging/cbhm.path new file mode 100644 index 0000000..56127ee --- /dev/null +++ b/packaging/cbhm.path @@ -0,0 +1,6 @@ +[Unit] +Description=Start the "cbhm" program + +[Path] +PathExists=/run/.wm_ready + diff --git a/packaging/cbhm.service b/packaging/cbhm.service new file mode 100644 index 0000000..4665410 --- /dev/null +++ b/packaging/cbhm.service @@ -0,0 +1,12 @@ +[Unit] +Description=Clipboard History Manager +After=enlightenment-user.service + +[Service] +ExecStart=/usr/bin/sh -c "while [ ! -f /run/.wm_ready ] ; do /usr/bin/sleep .1 ; done ; exec /usr/apps/org.tizen.cbhm/bin/cbhm-service" +EnvironmentFile=/run/tizen-system-env +Restart=on-failure +RestartSec=1 + +[Install] +WantedBy=delayed.target diff --git a/packaging/cbhm.spec b/packaging/cbhm.spec new file mode 100644 index 0000000..bce89ee --- /dev/null +++ b/packaging/cbhm.spec @@ -0,0 +1,89 @@ +Name: cbhm +Summary: Clipboard History Manager +Version: 2.0.0 +Release: 1 +Group: Graphics & UI Framework/Service +License: Apache-2.0 +URL: http://www.samsung.com/ +Source0: %{name}-%{version}.tar.gz +Source1: %{name}.service +Source1001: %{name}.manifest + +BuildRequires: cmake +BuildRequires: pkgconfig(wayland-client) +BuildRequires: pkgconfig(tizen-extension-client) +BuildRequires: pkgconfig(tizen-policy-ext-client) +BuildRequires: pkgconfig(gio-2.0) +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(libsystemd) +BuildRequires: pkgconfig(libtzplatform-config) +BuildRequires: pkgconfig(dlog) +Requires(post): /sbin/ldconfig, /usr/bin/systemctl +Requires(postun): /sbin/ldconfig, /usr/bin/systemctl + +%description +Tizen Clipboard History Manager Service + +%package devel +Summary: Library for Tizen Clipboard History Manager (Development) +Group: Graphics & UI Framework/Development +Requires: %{name} = %{version}-%{release} + +%description devel +Tizen Clipboard History Manager Service development kit + +%prep +%setup -q +chmod g-w %{_sourcedir}/* +cp %{SOURCE1001} ./%{name}.manifest + +%build +export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE" +export CFLAGS+=" -DEFL_BETA_API_SUPPORT" +export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE" +export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE" + +%define _pkg_dir %{TZ_SYS_RO_APP}/org.tizen.%{name} + +MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'` +rm -rf CMakeFiles CMackCache.txt && %cmake . -DMAJORVER=${MAJORVER} \ + -DFULLVER=%{version} -DCMAKE_INSTALL_PREFIX=%{_pkg_dir} \ + -DBIN_INSTALL_DIR:PATH=%{_bindir} \ + +make %{?jobs:-j%jobs} + +%install +%make_install + +## systemd +mkdir -p %{buildroot}%{_unitdir_user}/delayed.target.wants +install -m 0644 %SOURCE1 %{buildroot}%{_unitdir_user}/%{name}.service +ln -s ../%{name}.service %{buildroot}%{_unitdir_user}/delayed.target.wants/%{name}.service + +%post +systemctl daemon-reload +if [ $1 == 1 ]; then + systemctl restart %{name}.service +fi +/sbin/ldconfig + +%postun +if [ $1 == 0 ]; then + systemctl stop %{name}.service +fi +systemctl daemon-reload +/sbin/ldconfig + + +%files +%defattr(-,root,root,-) +%{_pkg_dir}/bin/%{name}-service +## systemd +%{_unitdir_user}/%{name}.service +%{_unitdir_user}/delayed.target.wants/%{name}.service +%manifest %{name}.manifest +%license LICENSE.APLv2 + +%files devel +%defattr(-,root,root,-) + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..910e34e --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,34 @@ +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + +FILE(GLOB DAEMON_SRCS ${DAEMON_SRCS} ${CMAKE_CURRENT_SOURCE_DIR}/*.c) + +INCLUDE(FindPkgConfig) +pkg_check_modules(pkgs REQUIRED + libsystemd + libtzplatform-config + glib-2.0 + gio-2.0 + wayland-client + tizen-extension-client + dlog +) + +INCLUDE_DIRECTORIES(SYSTEM ${pkgs_extra_INCLUDE_DIRS}) + +FOREACH(flag ${pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fvisibility=hidden -Wall -fPIC -g") + +SET(CMAKE_C_FLAGS_DEBUG "-O0 -g -fPIE") +SET(CMAKE_C_FLAGS_RELEASE "-O2 -g -fPIE") +SET(CMAKE_C_FLAGS_CCOV "-O2 -g --coverage -fPIE") + +SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -pie") + +ADD_EXECUTABLE(${DAEMON} ${DAEMON_SRCS}) + +TARGET_LINK_LIBRARIES(${DAEMON} ${pkgs_LDFLAGS} ${pkgs_extra_LDFLAGS}) + +INSTALL(TARGETS ${DAEMON} DESTINATION ${PREFIX}/bin) diff --git a/src/cbhm.c b/src/cbhm.c new file mode 100644 index 0000000..1db30a0 --- /dev/null +++ b/src/cbhm.c @@ -0,0 +1,950 @@ +/* + * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "list.h" +#include "cbhm_log.h" + +#define MIMETYPE_MAX 255 + +typedef struct { + char *mimetype; + + /* link of mime_type */ + struct list_head item_link; +} Cbhm_Mime_Type; + +typedef struct { + struct wl_data_offer *data_offer; + struct list_head offer_mimetype_list; +} Cbhm_Data_Offer; + +typedef struct { + void *data; + uint32_t len; +} Cbhm_Received_Data; + +typedef struct { + GSource gsource; + GPollFD gfd; + gboolean prepared; + GPollFD datafd; + + struct wl_display *wl_disp; + struct wl_registry *wl_registry; + struct wl_compositor *compositor; + struct wl_surface *surface; + struct wl_data_device_manager *data_device_mgr; + struct tizen_policy *tz_policy; + struct tizen_surface *tz_surf; + struct tizen_input_device_manager *tz_input_device_manager; + struct wl_seat *seat; + struct wl_data_device *data_device; + struct wl_data_source *data_source; + struct wl_array types; + uint32_t serial; + + Cbhm_Received_Data *received_data; + Cbhm_Data_Offer *cbhm_data_offer; + bool data_receive; + int pipe[2]; +} Cbhm_Glib_Info; + +static void +_cbhm_add_mime_type(Cbhm_Data_Offer *cbhm_data_offer, const char *type) +{ + Cbhm_Mime_Type *mime; + Cbhm_Mime_Type *temp; + uint32_t len; + bool type_match = false; + + if (!cbhm_data_offer) return; + if (!type) return; + + mime = calloc(1, sizeof(Cbhm_Mime_Type)); + if (!mime) { + ERR("[CBHM]_cbhm_add_mime_type: alloc fail\n"); + return; + } + + len = strlen(type); + if (len > MIMETYPE_MAX) { + ERR("[CBHM]_cbhm_add_mime_type: mime type max length error\n"); + free(mime); + return; + } + + mime->mimetype = calloc(1, (len + 1) * sizeof(char)); + if (!mime->mimetype) { + ERR("[CBHM]_cbhm_add_mime_type: alloc2 fail\n"); + free(mime); + return; + } + + memcpy(mime->mimetype, type, len); + mime->mimetype[len] = '\0'; + + if (LIST_IS_EMPTY(&cbhm_data_offer->offer_mimetype_list)) { + DBG("[CBHM]_cbhm_add_mime_type: %s\n", type); + LIST_ADDTAIL(&mime->item_link, &cbhm_data_offer->offer_mimetype_list); + } else { + LIST_FOR_EACH_ENTRY(temp, &cbhm_data_offer->offer_mimetype_list, item_link) { + if (!strcmp(temp->mimetype, type)) { + free(mime->mimetype); + free(mime); + type_match = true; + break; + } + } + + if (type_match == false) { + DBG("[CBHM]_cbhm_add_mime_type: %s\n", type); + LIST_ADDTAIL(&mime->item_link, &cbhm_data_offer->offer_mimetype_list); + } + } +} +#if 0 +static void +_cbhm_remove_mime_type(Cbhm_Data_Offer *cbhm_data_offer, const char *type) +{ + Cbhm_Mime_Type *mime; + Cbhm_Mime_Type *temp; + + if (!cbhm_data_offer) return; + if (!type) return; + + if (LIST_IS_EMPTY(&cbhm_data_offer->offer_mimetype_list)) return; + + LIST_FOR_EACH_ENTRY_SAFE(mime, temp, &cbhm_data_offer->offer_mimetype_list, item_link) { + if (!strcmp(mime->mimetype, type)) { + free(mime->mimetype); + LIST_DEL(&mime->item_link); + free(mime); + DBG("[CBHM]_cbhm_remove_mime_type: remove mime type : %s\n", type); + break; + } + } +} +#endif +static void +_cbhm_free_mime_type_list(Cbhm_Data_Offer *cbhm_data_offer) +{ + Cbhm_Mime_Type *mime; + Cbhm_Mime_Type *temp; + + if (LIST_IS_EMPTY(&cbhm_data_offer->offer_mimetype_list)) return; + + LIST_FOR_EACH_ENTRY_SAFE(mime, temp, &cbhm_data_offer->offer_mimetype_list, item_link) { + free(mime->mimetype); + LIST_DEL(&mime->item_link); + free(mime); + } + LIST_DELINIT(&cbhm_data_offer->offer_mimetype_list); +} + +static void +_cbhm_free_received_data(Cbhm_Received_Data *received_data) +{ + if (!received_data) return; + + if (received_data->data) + free(received_data->data); + free(received_data); +} + +static void +_data_source_target(void *data, struct wl_data_source *source, const char *mime_type) +{ +} + +static void +_data_source_send(void *data, struct wl_data_source *source, const char *mime_type, int32_t fd) +{ + Cbhm_Glib_Info *info = data; + Cbhm_Data_Offer *cbhm_data_offer; + char *buf = NULL, *cur_buf; + int ret, len_remained, size_ret, len_written = 0; + Cbhm_Mime_Type *mime; + + if (!info) return; + if (!info->cbhm_data_offer) return; + cbhm_data_offer = info->cbhm_data_offer; + + if (!info->received_data) { + WRN("[CBHM]_data_source_send: no saved data\n"); + buf = strdup("CLIPBOARD_EMPTY"); + } else { + LIST_FOR_EACH_ENTRY(mime, &cbhm_data_offer->offer_mimetype_list, item_link) { + if (!strcmp(mime->mimetype, mime_type)) { + buf = calloc(info->received_data->len, sizeof(char)); + strncpy(buf, info->received_data->data, info->received_data->len); + break; + } + } + } + + if (!buf) { + WRN("[CBHM]_data_source_send: type mismatch (%s)\n", mime_type); + buf = strdup("CLIPBOARD_EMPTY"); + } + + size_ret = strlen(buf) + 1; + len_remained = size_ret; + if (size_ret <= 1) { + ERR("[CBHM]_data_source_send: size_ret is not correct\n"); + free(buf); + return; + } + + cur_buf = buf; + DBG("[CBHM][SENDING] ====>> fd(%d), len(%d), data(%s)\n", fd, strlen(buf), buf); + while (len_written < size_ret) { + ret = write(fd, cur_buf, len_remained); + if (ret == -1) break; + cur_buf += ret; + len_written += ret; + len_remained -= ret; + DBG("[CBHM][SENT] ====>> remain(%d), sent(%d)\n", len_remained, ret); + } + cur_buf = NULL; + free(buf); + buf = NULL; + + close(fd); +} + +static void +_data_source_cancelled(void *data, struct wl_data_source *source) +{ + Cbhm_Glib_Info *info = data; + + if (info->data_source == source) + info->data_source = NULL; + + DBG("[CBHM]_data_source_cancelled: destroy(%p)\n", source); + + wl_data_source_destroy(source); +} + +static void +_data_source_dnd_drop_performed(void *data, struct wl_data_source *source) +{ +} + +static void +_data_source_dnd_finished(void *data, struct wl_data_source *source) +{ + Cbhm_Glib_Info *info = data; + + if (info->data_source == source) + info->data_source = NULL; + + DBG("[CBHM]_data_source_dnd_finished: destroy(%p)\n", source); + + wl_data_source_destroy(source); +} + +static void +_data_source_action(void *data, struct wl_data_source *source, uint32_t dnd_action) +{ +} + +static const struct wl_data_source_listener _data_source_listener = +{ + _data_source_target, + _data_source_send, + _data_source_cancelled, + _data_source_dnd_drop_performed, + _data_source_dnd_finished, + _data_source_action, +}; + +static void +_cbhm_set_selection(Cbhm_Glib_Info *info) +{ + Cbhm_Data_Offer *cbhm_data_offer; + Cbhm_Mime_Type *mime; + char **t; + + if (!info) return; + if (!info->cbhm_data_offer) return; + if (!info->data_device_mgr) return; + + cbhm_data_offer = info->cbhm_data_offer; + + if (info->types.data) { + wl_array_for_each(t, &info->types) + free(*t); + wl_array_release(&info->types); + wl_array_init(&info->types); + } + + info->data_source = wl_data_device_manager_create_data_source(info->data_device_mgr); + if (!info->data_source) { + ERR("[CBHM]_cbhm_set_selection: wl_data_device_manager_create_data_source fail\n"); + return; + } + + LIST_FOR_EACH_ENTRY(mime, &cbhm_data_offer->offer_mimetype_list, item_link) { + t = wl_array_add(&info->types, sizeof(*t)); + if (t) { + *t = strdup(mime->mimetype); + wl_data_source_offer(info->data_source, *t); + } + } + + wl_data_source_add_listener(info->data_source, &_data_source_listener, info); + wl_data_device_set_selection(info->data_device, info->data_source, info->serial++); +} + +static void +_cbhm_receive_data(Cbhm_Glib_Info *info) +{ + Cbhm_Received_Data *received_data; + char buffer[255]; + int len, old_len; + void *data; + + if (!info) return; + if (!info->data_device_mgr) return; + + received_data = calloc(1, sizeof(Cbhm_Received_Data)); + if (!received_data) { + ERR("[CBHM]_cbhm_receive_data: alloc fail \n"); + return; + } + info->received_data = received_data; + + while (1) { + len = read(info->datafd.fd, buffer, sizeof(buffer)); + if (len == -1) { + if (errno == EINTR || errno == EAGAIN) { + continue; + } else { + ERR("[CBHM]_cbhm_receive_data: read fail. %m\n"); + _cbhm_free_received_data(received_data); + info->received_data = NULL; + goto receive_data_done; + } + + } else if (len == 0) + break; + + old_len = received_data->len; + + received_data->len += len; + data = realloc(received_data->data, received_data->len); + if (data) { + received_data->data = data; + memcpy(((char *)received_data->data) + old_len, buffer, len); + } else { + ERR("[CBHM]_cbhm_receive_data: realloc fail\n"); + if (received_data->data != NULL) { + free(received_data->data); + received_data->data = NULL; + } + goto receive_data_done; + } + + if (len < 255) break; + } + + memcpy(buffer, ((char *)received_data->data) + received_data->len - 1, 1); + if (buffer[0] != '\0') { + buffer[0] = '\0'; + old_len = received_data->len; + received_data->len += 1; + data = realloc(received_data->data, received_data->len); + if (data) { + received_data->data = data; + memcpy(((char *)received_data->data) + old_len, buffer, 1); + } else { + ERR("[CBHM]_cbhm_receive_data: realloc fail\n"); + free(received_data->data); + received_data->data = NULL; + goto receive_data_done; + } + } + INF("[CBHM]_cbhm_receive_data: (%d) %s\n", received_data->len, (char *)received_data->data); + +receive_data_done: + g_source_remove_poll(&info->gsource, &info->datafd); + info->datafd.fd = -1; + info->data_receive = false; + close(info->pipe[1]); + + _cbhm_set_selection(info); +} + +static void +_data_offer_offer(void *data, struct wl_data_offer *wl_data_offer, const char *type) +{ + Cbhm_Glib_Info *info; + Cbhm_Data_Offer *cbhm_data_offer; + + info = data; + if (!info) return; + if (!info->cbhm_data_offer) return; + + cbhm_data_offer = info->cbhm_data_offer; + if (cbhm_data_offer->data_offer != wl_data_offer) { + ERR("[CBHM]_data_offer_offer : offer data is mismatch(saved:%p, current:%p)\n", cbhm_data_offer->data_offer, wl_data_offer); + return; + } + + if (type) + _cbhm_add_mime_type(cbhm_data_offer, type); + else + _cbhm_free_mime_type_list(cbhm_data_offer); +} + +static void +_data_offer_source_actions(void *data, struct wl_data_offer *wl_data_offer, uint32_t source_actions) +{ +} + +static void +_data_offer_action(void *data, struct wl_data_offer *wl_data_offer, uint32_t dnd_action) +{ +} + +static const struct wl_data_offer_listener _data_offer_listener = +{ + _data_offer_offer, + _data_offer_source_actions, + _data_offer_action +}; + +static void +_data_device_cb_offer(void *data, struct wl_data_device *data_device, struct wl_data_offer *offer) +{ + Cbhm_Glib_Info *info; + Cbhm_Data_Offer *cbhm_data_offer; + + info = data; + if (!info) return; + + cbhm_data_offer = info->cbhm_data_offer; + + if (cbhm_data_offer != NULL && cbhm_data_offer->data_offer == offer) { + DBG("[CBHM]_data_device_cb_offer : same offer called do nothing(%p)\n", offer); + return; + } + + if (cbhm_data_offer != NULL && cbhm_data_offer->data_offer != offer) { + DBG("[CBHM]_data_device_cb_offer : destroy previous offer %p\n", cbhm_data_offer->data_offer); + _cbhm_free_mime_type_list(cbhm_data_offer); + wl_data_offer_destroy(cbhm_data_offer->data_offer); + free(cbhm_data_offer); + info->cbhm_data_offer = NULL; + } + + cbhm_data_offer = calloc(1, sizeof(Cbhm_Data_Offer)); + if (cbhm_data_offer == NULL) { + ERR("[CBHM]_data_device_cb_offer : calloc fail\n"); + return; + } + DBG("[CBHM]_data_device_cb_offer : %p\n", offer); + + LIST_INITHEAD(&cbhm_data_offer->offer_mimetype_list); + cbhm_data_offer->data_offer = offer; + info->cbhm_data_offer = cbhm_data_offer; + + wl_data_offer_add_listener(offer, &_data_offer_listener, info); +} + +static void +_data_device_cb_enter(void *data, struct wl_data_device *data_device, uint32_t serial, struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *offer) +{ +} + +static void +_data_device_cb_leave(void *data, struct wl_data_device *data_device) +{ +} + +static void +_data_device_cb_motion(void *data, struct wl_data_device *data_device, uint32_t serial, wl_fixed_t x, wl_fixed_t y) +{ +} + +static void +_data_device_cb_drop(void *data, struct wl_data_device *data_device) +{ +} + +static void +_data_device_cb_selection(void *data, struct wl_data_device *data_device, struct wl_data_offer *offer) +{ + Cbhm_Glib_Info *info; + Cbhm_Data_Offer *cbhm_data_offer; + Cbhm_Mime_Type *mime = NULL; + char *mime_type; + int pipe[2]; + + info = data; + if (!info) return; + if (!info->cbhm_data_offer) return; + cbhm_data_offer = info->cbhm_data_offer; + + if (offer == NULL) { + INF("[CBHM]_data_device_cb_selection: previous selection cancelled\n"); + if (info->data_receive == true) { + WRN("[CBHM]_data_device_cb_selection: stop receive(%d, %d)\n", info->datafd.fd, info->pipe[1]); + g_source_remove_poll(&info->gsource, &info->datafd); + info->datafd.fd = -1; + info->data_receive = false; + close(info->pipe[1]); + } + } + if (cbhm_data_offer->data_offer != offer) { + ERR("[CBHM]_data_device_cb_selection: offer data is mismatch(saved:%p, current:%p)\n", cbhm_data_offer->data_offer, offer); + return; + } + + if (info->data_receive == true) { + ERR("[CBHM]_data_device_cb_selection: previous data receiving is not done\n"); + return; + } + + if (LIST_IS_EMPTY(&cbhm_data_offer->offer_mimetype_list)) { + ERR("[CBHM]_data_device_cb_selection: offer_mimetype_list empty\n"); + return; + } + + LIST_FOR_EACH_ENTRY(mime, &cbhm_data_offer->offer_mimetype_list, item_link) { + mime_type = strdup(mime->mimetype); + break; + } + DBG("[CBHM]_data_device_cb_selection: selected mime type : %s", mime_type); + + if (pipe2(pipe, O_CLOEXEC) == -1) { + ERR("[CBHM]_data_device_cb_selection: pipe2 fail\n"); + free(mime_type); + return; + } + + info->data_receive = true; + _cbhm_free_received_data(info->received_data); + info->received_data = NULL; + + wl_data_offer_receive(offer, (const char *)mime_type, pipe[1]); + + wl_display_flush(info->wl_disp); + + free(mime_type); + + info->datafd.fd = pipe[0]; + + info->datafd.events = G_IO_IN | G_IO_ERR; + info->datafd.revents = 0; + + g_source_add_poll(&info->gsource, &info->datafd); + DBG("[CBHM]_data_device_cb_selection: set datafd(%d, %d)\n", pipe[0], pipe[1]); + info->pipe[0] = pipe[0]; + info->pipe[1] = pipe[1]; +} + +static const struct wl_data_device_listener _data_device_listener = +{ + _data_device_cb_offer, + _data_device_cb_enter, + _data_device_cb_leave, + _data_device_cb_motion, + _data_device_cb_drop, + _data_device_cb_selection +}; + +static void +handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) +{ + Cbhm_Glib_Info *info = (Cbhm_Glib_Info *)data; + + if (!strcmp(interface, "wl_compositor")) { + struct wl_compositor *compositor; + compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 4); + if (!compositor) return; + info->compositor = compositor; + } else if (!strcmp(interface, "tizen_policy")) { + struct tizen_policy *tz_policy; + tz_policy = wl_registry_bind(registry, name, &tizen_policy_interface, 12); + if (!tz_policy) return; + info->tz_policy = tz_policy; + } else if (!strcmp(interface, "wl_data_device_manager")) { + struct wl_data_device_manager *data_device_mgr; + data_device_mgr = wl_registry_bind(registry, name, &wl_data_device_manager_interface, 3); + if (!data_device_mgr) return; + info->data_device_mgr = data_device_mgr; + } else if (!strcmp(interface, "wl_seat")) { + struct wl_seat *seat; + struct wl_data_device *data_device; + seat = wl_registry_bind(registry, name, &wl_seat_interface, 4); + if (!seat) return; + info->seat = seat; + if (!info->data_device_mgr) return; + data_device = wl_data_device_manager_get_data_device(info->data_device_mgr, seat); + if (!data_device) return; + info->data_device = data_device; + wl_data_device_add_listener(data_device, &_data_device_listener, info); + } +} + +static void +handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) +{ +} + +static const struct wl_registry_listener registry_listener = { + handle_global, + handle_global_remove +}; + +static int +cbhm_wayland_init(Cbhm_Glib_Info *info) +{ + struct wl_surface *surface; + int ret; + + info->wl_disp = wl_display_connect(NULL); + if (info->wl_disp == NULL) { + ERR("[CBHM]cbhm_wayland_init: wl_display_connect fail\n"); + return -1; + } + + info->wl_registry = wl_display_get_registry(info->wl_disp); + if (info->wl_registry == NULL) { + ERR("[CBHM]cbhm_wayland_init: wl_display_get_registry fail\n"); + return -1; + } + + ret = wl_registry_add_listener(info->wl_registry, ®istry_listener, info); + if (ret) { + ERR("[CBHM]cbhm_wayland_init: wl_registry_add_listener fail\n"); + return -1; + } + + ret = wl_display_roundtrip(info->wl_disp); + if (ret < 0) { + ERR("[CBHM]cbhm_wayland_init: wl_display_roundtrip fail(%d)\n", ret); + return -1; + } + + if (info->compositor == NULL) { + ERR("[CBHM]cbhm_wayland_init: wl_compositor fail\n"); + return -1; + } + + if (info->tz_policy == NULL) { + ERR("[CBHM]cbhm_wayland_init: tizen_policy fail\n"); + return -1; + } + + if (info->data_device_mgr == NULL) { + ERR("[CBHM]cbhm_wayland_init: wl_data_device_manager fail\n"); + return -1; + } + + if (info->seat == NULL) { + ERR("[CBHM]cbhm_wayland_init: wl_seat fail\n"); + return -1; + } + + if (info->data_device == NULL) { + ERR("[CBHM]cbhm_wayland_init: wl_data_device fail\n"); + return -1; + } + + surface = wl_compositor_create_surface(info->compositor); + if (surface == NULL) { + ERR("[CBHM]cbhm_wayland_init: wl_surface fail\n"); + return -1; + } + info->surface = surface; + + tizen_policy_set_role(info->tz_policy, info->surface, "cbhm"); + + return 0; +} + +static void +cbhm_wayland_shutdown(Cbhm_Glib_Info *info) +{ + if(!info) return; + + if (info->surface) { + wl_surface_destroy(info->surface); + info->surface = NULL; + } + + if (info->data_device) { + wl_data_device_destroy(info->data_device); + info->data_device = NULL; + } + + if (info->seat) { + wl_seat_destroy(info->seat); + info->seat = NULL; + } + + if (info->data_device_mgr) { + wl_data_device_manager_destroy(info->data_device_mgr); + info->data_device_mgr = NULL; + } + + if (info->tz_policy) { + tizen_policy_destroy(info->tz_policy); + info->tz_policy = NULL; + } + + if (info->compositor) { + wl_compositor_destroy(info->compositor); + info->compositor = NULL; + } + + if (info->wl_registry) { + wl_registry_destroy(info->wl_registry); + info->wl_registry = NULL; + } + + if (info->wl_disp) { + wl_display_disconnect(info->wl_disp); + info->wl_disp = NULL; + } +} + +static gboolean +cbhm_gsource_prepare(GSource *source, gint *time) +{ + Cbhm_Glib_Info *info = (Cbhm_Glib_Info *)source; + + /* If info is already prepared, do nothing in this function. */ + if (info->prepared == TRUE) + return FALSE; + + while (wl_display_prepare_read(info->wl_disp) != 0) { + if (wl_display_dispatch_pending(info->wl_disp) == -1) { + ERR("[CBHM]cbhm_gsource_prepare: wl_display_dispatch_pending fail\n"); + } + } + + info->prepared = TRUE; + + wl_display_flush(info->wl_disp); + *time = -1; + + return FALSE; +} + +static gboolean +cbhm_gsource_check(GSource *source) +{ + Cbhm_Glib_Info *info = (Cbhm_Glib_Info *)source; + gboolean ret = FALSE; + int wl_ret = 0; + + if (g_source_is_destroyed(source)) { + if (info && info->wl_disp && info->prepared) + wl_display_cancel_read(info->wl_disp); + ERR("[CBHM]cbhm_gsource_check: display source(%p) already destroyed\n", source); + return ret; + } + + if ((info->datafd.fd != -1) && (info->datafd.revents & G_IO_IN)) + _cbhm_receive_data(info); + + if (!info->prepared) + return ret; + + if (info->gfd.revents & (G_IO_HUP | G_IO_ERR)) { + wl_display_cancel_read(info->wl_disp); + goto err; + } + + if (info->gfd.revents & G_IO_IN) { + wl_ret = wl_display_read_events(info->wl_disp); + if (wl_ret == -1) { + ERR("[CBHM]cbhm_gsource_check: wl_display_read_events fail(%d)\n", wl_ret); + goto err; + } + ret = TRUE; + } else { + wl_display_cancel_read(info->wl_disp); + } + + info->prepared = FALSE; + + return ret; +err: + ERR("[CBHM]cbhm_gsource_check: error revent:0x%x, wl_err:%d\n", info->gfd.revents, wl_ret); + + info->prepared = FALSE; + g_source_destroy(source); + + return FALSE; +} + +static gboolean +cbhm_gsource_dispatch(GSource *source, GSourceFunc cb, gpointer data) +{ + Cbhm_Glib_Info *info = (Cbhm_Glib_Info *)source; + int wl_ret = 0; + + if (g_source_is_destroyed(source)) { + ERR("[CBHM]cbhm_gsource_dispatch: display source(%p) already destroyed\n", source); + return G_SOURCE_REMOVE; + } + + if (info->gfd.revents & (G_IO_HUP | G_IO_ERR)) + goto err; + + if (info->gfd.revents & G_IO_IN) { + wl_ret = wl_display_dispatch_pending(info->wl_disp); + if (wl_ret == -1) { + ERR("[CBHM]cbhm_gsource_dispatch: wl_display_read_events fail(%d)\n", wl_ret); + goto err; + } + } + + wl_ret = wl_display_flush(info->wl_disp); + if (wl_ret == -1) { + ERR("[CBHM]cbhm_gsource_dispatch: wl_display_flush fail(%d)\n", wl_ret); + goto err; + } + + return G_SOURCE_CONTINUE; +err: + ERR("[CBHM]cbhm_gsource_dispatch: error revent:0x%x, wl_err:%d\n", info->gfd.revents, wl_ret); + g_source_destroy(source); + + return G_SOURCE_REMOVE; +} + +static void +cbhm_gsource_finalize(GSource *source) +{ + Cbhm_Glib_Info *info = (Cbhm_Glib_Info *)source; + + INF("[CBHM]cbhm_gsource_finalize: revent:0x%x\n", info->gfd.revents); + if (info->received_data) + _cbhm_free_received_data(info->received_data); + info->received_data = NULL; + if (info->cbhm_data_offer) { + wl_data_offer_destroy(info->cbhm_data_offer->data_offer); + _cbhm_free_mime_type_list(info->cbhm_data_offer); + free(info->cbhm_data_offer); + } + info->cbhm_data_offer = NULL; + if (info->datafd.fd != -1) { + info->datafd.fd = -1; + close(info->pipe[1]); + } + cbhm_wayland_shutdown(info); + g_source_destroy(source); + + return; +} + +static GSourceFuncs cbhm_gsource_funcs = { + .prepare = cbhm_gsource_prepare, + .check = cbhm_gsource_check, + .dispatch = cbhm_gsource_dispatch, + .finalize = cbhm_gsource_finalize, +}; + +GSource * +cbhm_init(void) +{ + Cbhm_Glib_Info *info = NULL; + int ret; + + info = (Cbhm_Glib_Info *)g_source_new(&cbhm_gsource_funcs, sizeof(Cbhm_Glib_Info)); + if (info == NULL) { + ERR("[CBHM]cbhm_init: g_source_new fail\n"); + goto err; + } + + info->datafd.fd = -1; + + ret = cbhm_wayland_init(info); + if (ret) { + ERR("[CBHM]cbhm_init: cbhm_wayland_init fail\n"); + goto err; + } + + info->gfd.fd = wl_display_get_fd(info->wl_disp); + if (info->gfd.fd == -1) { + ERR("[CBHM]cbhm_init: wl_display_get_fd fail\n"); + goto err; + } + + info->gfd.events = G_IO_IN | G_IO_ERR; + info->gfd.revents = 0; + + g_source_add_poll(&info->gsource, &info->gfd); + g_source_attach(&info->gsource, NULL); + g_source_unref(&info->gsource); + + INF("[CBHM]cbhm_init: done\n"); + + return &info->gsource; +err: + if (info) { + cbhm_wayland_shutdown(info); + g_source_unref(&info->gsource); + } + return NULL; +} + +void +cbhm_shutdown(GSource *gsource) +{ + Cbhm_Glib_Info *info; + + if (!gsource) return; + + info = (Cbhm_Glib_Info *)gsource; + + if (info->received_data) + _cbhm_free_received_data(info->received_data); + info->received_data = NULL; + if (info->cbhm_data_offer) { + wl_data_offer_destroy(info->cbhm_data_offer->data_offer); + _cbhm_free_mime_type_list(info->cbhm_data_offer); + free(info->cbhm_data_offer); + } + info->cbhm_data_offer = NULL; + if (info->datafd.fd != -1) { + info->datafd.fd = -1; + close(info->pipe[1]); + } + cbhm_wayland_shutdown(info); + + INF("[CBHM]cbhm_shutdown: done\n"); +} + diff --git a/src/cbhm_log.h b/src/cbhm_log.h new file mode 100644 index 0000000..90c2f8c --- /dev/null +++ b/src/cbhm_log.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _CBHM_LOG_H_ +#define _CBHM_LOG_H_ + +#undef _DBG +#undef _INF +#undef _WRN +#undef _ERR + +#undef DBG +#undef INF +#undef WRN +#undef ERR + +#define LOG_TAG "CBHM" +#include + +#define _DBG(fmt, arg...) SLOGD(fmt, ##arg) +#define _INF(fmt, arg...) SLOGI(fmt, ##arg) +#define _WRN(fmt, arg...) SLOGW(fmt, ##arg) +#define _ERR(fmt, arg...) SLOGE(fmt, ##arg) + + +#define FN_CALL() _INF(">>>>>>>> called") +#define FN_END() _INF("<<<<<<<< ended") +#define DBG(fmt, arg...) _DBG(fmt, ##arg) +#define WRN(fmt, arg...) _WRN(fmt, ##arg) +#define ERR(fmt, arg...) _ERR(fmt, ##arg) +#define INF(fmt, arg...) _INF(fmt, ##arg) + + +#define RET_IF(expr) \ + do { \ + if (expr) { \ + ERR("(%s)", #expr); \ + return; \ + } \ + } while (0) + +#define RETV_IF(expr, val) \ + do { \ + if (expr) { \ + ERR("(%s)", #expr); \ + return (val); \ + } \ + } while (0) + +#define RETM_IF(expr, fmt, arg...) \ + do { \ + if (expr) { \ + ERR(fmt, ##arg); \ + return; \ + } \ + } while (0) + +#define RETVM_IF(expr, val, fmt, arg...) \ + do { \ + if (expr) { \ + ERR(fmt, ##arg); \ + return (val); \ + } \ + } while (0) + +#define ERR_IF(expr) \ + do { \ + if (expr) { \ + ERR("(%s)", #expr); \ + } \ + } while (0) + +#define WARN_IF(expr, fmt, arg...) \ + do { \ + if (expr) { \ + WARN(fmt, ##arg); \ + } \ + } while (0) + +#endif /* _CBHM_LOG_H_ */ diff --git a/src/list.h b/src/list.h new file mode 100644 index 0000000..2fbbc84 --- /dev/null +++ b/src/list.h @@ -0,0 +1,138 @@ +/* + * + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + */ + +/** + * \file + * List macros heavily inspired by the Linux kernel + * list handling. No list looping yet. + * + * Is not threadsafe, so common operations need to + * be protected using an external mutex. + */ +#ifndef _U_DOUBLE_LIST_H_ +#define _U_DOUBLE_LIST_H_ + +#include + +/* LCOV_EXCL_START */ +struct list_head { + struct list_head *prev; + struct list_head *next; +}; + +static void list_inithead(struct list_head *item) +{ + item->prev = item; + item->next = item; +} + +static inline void list_add(struct list_head *item, struct list_head *list) +{ + item->prev = list; + item->next = list->next; + list->next->prev = item; + list->next = item; +} + +static inline void list_addtail(struct list_head *item, struct list_head *list) +{ + item->next = list; + item->prev = list->prev; + list->prev->next = item; + list->prev = item; +} + +static inline void list_replace(struct list_head *from, struct list_head *to) +{ + to->prev = from->prev; + to->next = from->next; + from->next->prev = to; + from->prev->next = to; +} + +static inline void list_del(struct list_head *item) +{ + item->prev->next = item->next; + item->next->prev = item->prev; +} + +static inline void list_delinit(struct list_head *item) +{ + item->prev->next = item->next; + item->next->prev = item->prev; + item->next = item; + item->prev = item; +} + +#define LIST_INITHEAD(__item) list_inithead(__item) +#define LIST_ADD(__item, __list) list_add(__item, __list) +#define LIST_ADDTAIL(__item, __list) list_addtail(__item, __list) +#define LIST_REPLACE(__from, __to) list_replace(__from, __to) +#define LIST_DEL(__item) list_del(__item) +#define LIST_DELINIT(__item) list_delinit(__item) + +#define LIST_ENTRY(__type, __item, __field) \ + ((__type *)(((char *)(__item)) - offsetof(__type, __field))) + +#define LIST_IS_EMPTY(__list) \ + ((__list)->next == (__list)) + +#ifndef container_of +#define container_of(ptr, sample, member) \ + (void *)((char *)(ptr) \ + - ((char *)&(sample)->member - (char *)(sample))) +#endif + +#define LIST_FOR_EACH_ENTRY(pos, head, member) \ + for (pos = container_of((head)->next, pos, member); \ + &pos->member != (head); \ + pos = container_of(pos->member.next, pos, member)) + +#define LIST_FOR_EACH_ENTRY_SAFE(pos, storage, head, member) \ + for (pos = container_of((head)->next, pos, member), \ + storage = container_of(pos->member.next, pos, member); \ + &pos->member != (head); \ + pos = storage, storage = container_of(storage->member.next, storage, member)) + +#define LIST_FOR_EACH_ENTRY_SAFE_REV(pos, storage, head, member) \ + for (pos = container_of((head)->prev, pos, member), \ + storage = container_of(pos->member.prev, pos, member); \ + &pos->member != (head); \ + pos = storage, storage = container_of(storage->member.prev, storage, member)) + +#define LIST_FOR_EACH_ENTRY_FROM(pos, start, head, member) \ + for (pos = container_of((start), pos, member); \ + &pos->member != (head); \ + pos = container_of(pos->member.next, pos, member)) + +#define LIST_FOR_EACH_ENTRY_FROM_REV(pos, start, head, member) \ + for (pos = container_of((start), pos, member); \ + &pos->member != (head); \ + pos = container_of(pos->member.prev, pos, member)) + +#endif /*_U_DOUBLE_LIST_H_*/ +/* LCOV_EXCL_STOP */ diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..90d5a80 --- /dev/null +++ b/src/main.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include "cbhm_log.h" + +extern GSource *cbhm_init(void); +extern void cbhm_shutdown(GSource *gsource); + +static GSource *cbhm_glib_data = NULL; + + +static void +cbhm_glib_source_destroy_notify_cb(gpointer data) +{ + INF("[CBHM] cbhm_gsource_destroy info:%p\n", data); + cbhm_shutdown(cbhm_glib_data); + g_source_unref(cbhm_glib_data); + cbhm_glib_data = NULL; +} + +int main(int argc, char *argv[]) +{ + GMainLoop *mainloop; + + mainloop = g_main_loop_new(NULL, FALSE); + + cbhm_glib_data = cbhm_init(); + if (!cbhm_glib_data) { + ERR("[CBHM] cbhm_init fail\n"); + g_main_loop_unref(mainloop); + return 0; + } + g_source_ref(cbhm_glib_data); + g_source_set_callback(cbhm_glib_data, NULL, cbhm_glib_data, cbhm_glib_source_destroy_notify_cb); + + /* g_main_loop */ + g_main_loop_run(mainloop); + + /* exit */ + g_main_loop_unref(mainloop); + + return 0; +}