From fc9c4e058e23ef37d0caa155016a3d6f792c2938 Mon Sep 17 00:00:00 2001 From: "duna.oh" Date: Tue, 12 Jul 2022 01:26:50 +0900 Subject: [PATCH 01/16] devicemgr: implement pointer_warp Change-Id: Ia3054efdedc15b04b93f4b3e089fa1491c87f981 --- clients/simple-tbm.c | 19 ++++++- examples/tinyds-tdm-libinput.c | 101 ++++++++++++++++++++++++++++++---- include/libds-tizen/input_devicemgr.h | 13 +++++ src/input_devicemgr/input_devicemgr.c | 61 +++++++++++++++++++- src/input_devicemgr/input_devicemgr.h | 1 + 5 files changed, 182 insertions(+), 13 deletions(-) diff --git a/clients/simple-tbm.c b/clients/simple-tbm.c index c82349f..f68fedb 100644 --- a/clients/simple-tbm.c +++ b/clients/simple-tbm.c @@ -56,6 +56,7 @@ struct display { struct tizen_input_device_manager *devicemgr; int notified; bool blocked; + struct wl_surface *entered_surface; }; struct window { @@ -338,8 +339,21 @@ static const struct xdg_wm_base_listener xdg_wm_base_listener = { static void pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { + struct display *d = data; + static int warp_x = 0, warp_y = 0; + if (state == WL_POINTER_BUTTON_STATE_PRESSED) { fprintf(stderr, "pointer_handle_button: PRESSED\n"); + + warp_x += 10; + warp_y += 10; + tizen_input_device_manager_pointer_warp(d->devicemgr, + d->entered_surface, + wl_fixed_from_int(warp_x), + wl_fixed_from_int(warp_y)); + fprintf(stderr, "requesting pointer_warp: surface:%p sx: %d sy: %d\n", + d->entered_surface, + warp_x, warp_y); } else { fprintf(stderr, "pointer_handle_button: RELEASED\n"); @@ -350,8 +364,11 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { + struct display *d = data; + fprintf(stderr, "pointer_handle_enter surface_x:%d, surface_y:%d\n", wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y)); + d->entered_surface = surface; } static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer, @@ -508,7 +525,7 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, } if ((caps & WL_SEAT_CAPABILITY_POINTER)) { struct wl_pointer *pointer = wl_seat_get_pointer(wl_seat); - wl_pointer_add_listener(pointer, &pointer_listener, NULL); + wl_pointer_add_listener(pointer, &pointer_listener, d); fprintf(stderr, "seat_handle_capabilities: pointer\n"); } if ((caps & WL_SEAT_CAPABILITY_TOUCH)) { diff --git a/examples/tinyds-tdm-libinput.c b/examples/tinyds-tdm-libinput.c index b1974f1..10c02bb 100644 --- a/examples/tinyds-tdm-libinput.c +++ b/examples/tinyds-tdm-libinput.c @@ -40,6 +40,7 @@ #define TINYDS_UNUSED __attribute__((unused)) struct tinyds_keyboard; +struct tinyds_pointer; struct tinyds_output { @@ -87,8 +88,11 @@ struct tinyds_server struct wl_listener new_output; struct wl_listener new_input; struct wl_listener new_xdg_surface; + struct wl_listener devicemgr_destroy; + struct wl_listener pointer_warp; - struct tinyds_keyboard *keyboard; + struct wl_list keyboards; + struct wl_list pointers; }; struct tinyds_view @@ -119,6 +123,7 @@ struct tinyds_pointer struct wl_listener motion; //relative struct wl_listener button; struct wl_listener frame; + struct wl_list link; //tinyds_server::pointers }; struct tinyds_keyboard @@ -128,6 +133,7 @@ struct tinyds_keyboard struct wl_listener destroy; struct wl_listener key; + struct wl_list link; //tinyds_server::keyboards }; struct tinyds_touch @@ -169,6 +175,10 @@ static void server_add_pointer(struct tinyds_server *server, static void server_add_touch(struct tinyds_server *server, struct ds_input_device *dev); +static struct tinyds_view * +server_view_at(struct tinyds_server *server, double lx, double ly, + double *sx, double *sy); + int main(void) { @@ -214,16 +224,19 @@ view_handle_xdg_surface_map(struct wl_listener *listener, { struct tinyds_view *view; struct ds_keyboard *keyboard; + struct tinyds_keyboard *kbd; view = wl_container_of(listener, view, xdg_surface_map); view->mapped = true; - if (!view->server->keyboard) return; - keyboard = ds_input_device_get_keyboard(view->server->keyboard->dev); - if (keyboard != NULL) { - ds_seat_keyboard_notify_enter(view->server->seat, - ds_xdg_surface_get_surface(view->xdg_surface), - keyboard->keycodes, keyboard->num_keycodes, - &keyboard->modifiers); + wl_list_for_each(kbd, &view->server->keyboards, link) { + keyboard = ds_input_device_get_keyboard(kbd->dev); + if (keyboard != NULL) { + ds_seat_keyboard_notify_enter(view->server->seat, + ds_xdg_surface_get_surface(view->xdg_surface), + keyboard->keycodes, keyboard->num_keycodes, + &keyboard->modifiers); + return; + } } } @@ -306,6 +319,8 @@ server_new_xdg_surface(struct wl_listener *listener, void *data) view->x = rand() % 1000; view->y = rand() % 500; + + ds_inf("view at (%d, %d)", view->x, view->y); } static void @@ -444,6 +459,55 @@ devicemgr_set_keymap(struct ds_tizen_input_devicemgr *devicemgr) devicemgr_remove_keymap_data(&keymap_list, 458); } +static void +devicemgr_handle_pointer_warp(struct wl_listener *listener, void *data) +{ + struct tinyds_server *server; + struct tinyds_pointer *pointer; + struct ds_tizen_input_devicemgr_event_pointer_warp *event = data; + double sx = 0.f, sy = 0.f; + struct tinyds_view *view = NULL; + + server = wl_container_of(listener, server, pointer_warp); + + ds_inf("Pointer warp: surface(%p) x(%.2f) y(%.2f)", event->surface, + event->x, event->y); + + wl_list_for_each(pointer, &server->pointers, link){ + if (!pointer->focused_view) continue; + view = pointer->focused_view; + } + if (!view) return; + + if (event->surface != ds_xdg_surface_get_surface(view->xdg_surface)) { + ds_inf("Pointer is not on the requested surface"); + return; + } + + server->output_x = view->x + (event->x * server->output->width); + server->output_y = view->y + (event->y * server->output->height); + + server_view_at(server, server->output_x, server->output_y, &sx, &sy); + + ds_inf("notify motion: sx:%.2f sy:%.2f, output_x:%.1f, output_y:%.1f", + sx, sy, server->output_x, server->output_y); + + ds_seat_pointer_notify_motion(server->seat, + event->time_msec, sx, sy); +} + +static void +devicemgr_handle_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED) +{ + struct tinyds_server *server = + wl_container_of(listener, server, devicemgr_destroy); + + wl_list_remove(&server->devicemgr_destroy.link); + wl_list_remove(&server->pointer_warp.link); + + server->devicemgr = NULL; +} + static bool init_server(struct tinyds_server *server, struct wl_display *display) { @@ -468,6 +532,8 @@ init_server(struct tinyds_server *server, struct wl_display *display) ds_backend_add_new_output_listener(server->backend, &server->new_output); + wl_list_init(&server->keyboards); + wl_list_init(&server->pointers); server->new_input.notify = backend_handle_new_input; ds_backend_add_new_input_listener(server->input_backend, &server->new_input); @@ -499,6 +565,15 @@ init_server(struct tinyds_server *server, struct wl_display *display) } devicemgr_set_keymap(server->devicemgr); + + server->devicemgr_destroy.notify = devicemgr_handle_destroy; + ds_tizen_input_devicemgr_add_destroy_listener(server->devicemgr, + &server->devicemgr_destroy); + + server->pointer_warp.notify = devicemgr_handle_pointer_warp; + ds_tizen_input_devicemgr_add_pointer_warp_listener(server->devicemgr, + &server->pointer_warp); + return true; err: @@ -762,8 +837,7 @@ keyboard_handle_device_destroy(struct wl_listener *listener, void *data) wl_list_remove(&kbd->destroy.link); wl_list_remove(&kbd->key.link); - - kbd->server->keyboard = NULL; + wl_list_remove(&kbd->link); free(kbd); } @@ -852,7 +926,7 @@ server_add_keyboard(struct tinyds_server *server, struct ds_input_device *dev) kbd->key.notify = keyboard_handle_key; ds_keyboard_add_key_listener(ds_input_device_get_keyboard(dev), &kbd->key); - server->keyboard = kbd; + wl_list_insert(&server->keyboards, &kbd->link); ds_inf("Keyboard(%p) added", kbd); } @@ -1007,6 +1081,7 @@ pointer_handle_device_destroy(struct wl_listener *listener, void *data) wl_list_remove(&pointer->motion.link); wl_list_remove(&pointer->button.link); wl_list_remove(&pointer->frame.link); + wl_list_remove(&pointer->link); free(pointer); } @@ -1123,5 +1198,9 @@ server_add_pointer(struct tinyds_server *server, struct ds_input_device *dev) ds_pointer_add_frame_listener(ds_input_device_get_pointer(dev), &pointer->frame); + pointer->focused_view = NULL; + + wl_list_insert(&server->pointers, &pointer->link); + ds_inf("Pointer(%p) added", pointer); } diff --git a/include/libds-tizen/input_devicemgr.h b/include/libds-tizen/input_devicemgr.h index fc1060e..458d581 100644 --- a/include/libds-tizen/input_devicemgr.h +++ b/include/libds-tizen/input_devicemgr.h @@ -2,6 +2,7 @@ #define LIBDS_TIZEN_INPUT_DEVICEMGR_H #include +#include #ifdef __cplusplus extern "C" { @@ -19,6 +20,13 @@ struct ds_tizen_input_devicemgr_keymap_data struct wl_list link; }; +struct ds_tizen_input_devicemgr_event_pointer_warp +{ + uint32_t time_msec; + struct ds_surface *surface; + double x, y; +}; + struct ds_tizen_input_devicemgr * ds_tizen_input_devicemgr_create(struct ds_backend *backend, struct ds_seat *seat); @@ -28,6 +36,11 @@ ds_tizen_input_devicemgr_add_destroy_listener( struct ds_tizen_input_devicemgr *devicemgr, struct wl_listener *listener); +void +ds_tizen_input_devicemgr_add_pointer_warp_listener( + struct ds_tizen_input_devicemgr *devicemgr, + struct wl_listener *listener); + bool ds_tizen_input_devicemgr_set_keymap_list( struct ds_tizen_input_devicemgr *devicemgr, diff --git a/src/input_devicemgr/input_devicemgr.c b/src/input_devicemgr/input_devicemgr.c index f690fe7..00c99b0 100644 --- a/src/input_devicemgr/input_devicemgr.c +++ b/src/input_devicemgr/input_devicemgr.c @@ -64,6 +64,10 @@ device_manager_handle_generate_pointer(struct wl_client *client, struct wl_resource *resource, uint32_t type, uint32_t x, uint32_t y, uint32_t button); static void +device_manager_handle_pointer_warp(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *surface, + wl_fixed_t x, wl_fixed_t y); +static void device_manager_handle_destroy(struct wl_client *client, struct wl_resource *resource); @@ -169,6 +173,7 @@ ds_tizen_input_devicemgr_create(struct ds_backend *backend, } wl_signal_init(&tz_devicemgr->events.destroy); + wl_signal_init(&tz_devicemgr->events.pointer_warp); wl_list_init(&tz_devicemgr->clients); wl_list_init(&tz_devicemgr->devices.kbd->key.pressed); wl_list_init(&tz_devicemgr->keymap_list); @@ -205,6 +210,14 @@ ds_tizen_input_devicemgr_add_destroy_listener( wl_signal_add(&tz_devicemgr->events.destroy, listener); } +WL_EXPORT void +ds_tizen_input_devicemgr_add_pointer_warp_listener( + struct ds_tizen_input_devicemgr *tz_devicemgr, + struct wl_listener *listener) +{ + wl_signal_add(&tz_devicemgr->events.pointer_warp, listener); +} + WL_EXPORT bool ds_tizen_input_devicemgr_set_keymap_list( struct ds_tizen_input_devicemgr *tz_devicemgr, struct wl_list *list) @@ -347,7 +360,7 @@ static const struct tizen_input_device_manager_interface _devicemgr_impl = { .generate_key = device_manager_handle_generate_key, .generate_pointer = device_manager_handle_generate_pointer, .generate_touch = device_manager_handle_generate_touch, - .pointer_warp = NULL, + .pointer_warp = device_manager_handle_pointer_warp, .init_generator_with_name = device_manager_handle_init_generator_with_name, // v2 .destroy = device_manager_handle_destroy, // v3 @@ -767,6 +780,52 @@ finish: } static void +device_manager_handle_pointer_warp(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *surface, + wl_fixed_t x, wl_fixed_t y) +{ + struct ds_tizen_input_devicemgr *tz_devicemgr; + int ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_SYSTEM_RESOURCES; + int32_t new_x, new_y; + double transformed_x = .0, transformed_y = .0; + struct ds_tizen_input_devicemgr_event_pointer_warp ds_event; + struct timeval time; + unsigned int timestamp; + + tz_devicemgr = wl_resource_get_user_data(resource); + + if (!tz_devicemgr->devices.ptr || + !tz_devicemgr->devices.ptr->input_device) { + ds_err("Pointer device is not initialized\n"); + goto finish; + } + + new_x = wl_fixed_to_int(x); + new_y = wl_fixed_to_int(y); + + if (tz_devicemgr->output.width != 0 && tz_devicemgr->output.height != 0) { + transformed_x = new_x / (double)tz_devicemgr->output.width; + transformed_y = new_y / (double)tz_devicemgr->output.height; + } + + gettimeofday(&time, NULL); + timestamp = time.tv_sec * 1000 + time.tv_usec / 1000; + + ds_event.time_msec = timestamp; + ds_event.surface = ds_surface_from_resource(surface); + ds_event.x = transformed_x; + ds_event.y = transformed_y; + ds_inf("Pointer warp. surface:%p, x:%.2f, y:%.2f", ds_event.surface, + ds_event.x, ds_event.y); + + wl_signal_emit(&tz_devicemgr->events.pointer_warp, &ds_event); + ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE; + +finish: + tizen_input_device_manager_send_error(resource, ret); +} + +static void device_manager_handle_destroy(struct wl_client *client, struct wl_resource *resource) { diff --git a/src/input_devicemgr/input_devicemgr.h b/src/input_devicemgr/input_devicemgr.h index a4428ee..f773fc1 100644 --- a/src/input_devicemgr/input_devicemgr.h +++ b/src/input_devicemgr/input_devicemgr.h @@ -36,6 +36,7 @@ struct ds_tizen_input_devicemgr { struct { struct wl_signal destroy; + struct wl_signal pointer_warp; //ds_tizen_input_devicemgr_event_pointer_warp } events; struct wl_listener new_input; -- 2.7.4 From 776c8e08e66e1f5a354f811462ca074359c76bce Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Thu, 7 Jul 2022 19:28:26 +0900 Subject: [PATCH 02/16] impelement libds-tizen-indicator This is the server implementation for tizen_indicator protocol. Change-Id: I97efef30d5f9e5c540d51b92bcac43808b53951a --- include/libds-tizen/indicator.h | 75 ++++++ packaging/libds-tizen.spec | 29 +++ src/indicator/indicator.c | 499 ++++++++++++++++++++++++++++++++++++++++ src/indicator/meson.build | 29 +++ src/meson.build | 1 + 5 files changed, 633 insertions(+) create mode 100644 include/libds-tizen/indicator.h create mode 100644 src/indicator/indicator.c create mode 100644 src/indicator/meson.build diff --git a/include/libds-tizen/indicator.h b/include/libds-tizen/indicator.h new file mode 100644 index 0000000..69fc82e --- /dev/null +++ b/include/libds-tizen/indicator.h @@ -0,0 +1,75 @@ +#ifndef LIBDS_TIZEN_INDICATOR_H +#define LIBDS_TIZEN_INDICATOR_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ds_tizen_indicator; + +enum ds_tizen_indicator_state +{ + DS_TIZEN_INDICATOR_STATE_UNKNOWN, + DS_TIZEN_INDICATOR_STATE_OFF, + DS_TIZEN_INDICATOR_STATE_ON, +}; + +enum ds_tizen_indicator_opacity_mode +{ + DS_TIZEN_INDICATOR_OPACITY_MODE_UNKNOWN, + DS_TIZEN_INDICATOR_OPACITY_MODE_OPAQUE, + DS_TIZEN_INDICATOR_OPACITY_MODE_TRANSLUCENT, + DS_TIZEN_INDICATOR_OPACITY_MODE_TRANSPARENT, + DS_TIZEN_INDICATOR_OPACITY_MODE_BG_TRANSPARENT, +}; + +enum ds_tizen_indicator_visible_type +{ + DS_TIZEN_INDICATOR_VISIBLE_TYPE_HIDDEN, + DS_TIZEN_INDICATOR_VISIBLE_TYPE_SHOWN, +}; + +struct ds_tizen_indicator * +ds_tizen_indicator_create(struct wl_display *display); + +void +ds_tizen_indicator_add_destroy_listener(struct ds_tizen_indicator *indicator, + struct wl_listener *listener); + +void +ds_tizen_indicator_add_change_state_listener( + struct ds_tizen_indicator *indicator, struct wl_listener *listener); + +void +ds_tizen_indicator_add_change_opacity_mode_listener( + struct ds_tizen_indicator *indicator, struct wl_listener *listener); + +void +ds_tizen_indicator_add_change_visible_type_listener( + struct ds_tizen_indicator *indicator, struct wl_listener *listener); + +enum ds_tizen_indicator_state +ds_tizen_indicator_get_state(struct ds_tizen_indicator *indicator, + struct ds_surface *surface); + +enum ds_tizen_indicator_opacity_mode +ds_tizen_indicator_get_opacity_mode(struct ds_tizen_indicator *indicator, + struct ds_surface *surface); + +enum ds_tizen_indicator_visible_type +ds_tizen_indicator_get_visible_type(struct ds_tizen_indicator *indicator, + struct ds_surface *surface); + +void +ds_tizen_indicator_send_flick(struct ds_tizen_indicator *indicator, + struct ds_surface *surface); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packaging/libds-tizen.spec b/packaging/libds-tizen.spec index c5e0623..34b918c 100644 --- a/packaging/libds-tizen.spec +++ b/packaging/libds-tizen.spec @@ -122,6 +122,21 @@ Group: Development/Libraries %description dpms-devel Development package for tizen dpms +## libds-tizen-indicator +%package indicator +Summary: Library for tizen indicator +Group: Development/Libraries + +%description indicator +Library for tizen indicator + +%package indicator-devel +Summary: Development package for tizen indicator +Group: Development/Libraries + +%description indicator-devel +Development package for tizen indicator + %prep %setup -q cp %{SOURCE1001} . @@ -232,3 +247,17 @@ ninja -C builddir install %{_libdir}/libds-tizen-dpms.so %{_bindir}/tinyds-tdm-dpms %{_bindir}/ds-simple-dpms + +%files indicator +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_libdir}/libds-tizen-indicator.so.* + +%files indicator-devel +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_includedir}/libds-tizen/indicator.h +%{_libdir}/pkgconfig/libds-tizen-indicator.pc +%{_libdir}/libds-tizen-indicator.so diff --git a/src/indicator/indicator.c b/src/indicator/indicator.c new file mode 100644 index 0000000..23f0e9f --- /dev/null +++ b/src/indicator/indicator.c @@ -0,0 +1,499 @@ +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "libds-tizen/indicator.h" + +#define TIZEN_INDICATOR_VERSION 1 + +struct ds_tizen_indicator +{ + struct wl_global *global; + + struct wl_list clients; + + struct wl_listener destroy; + + struct { + struct wl_signal destroy; + struct wl_signal change_state; + struct wl_signal change_opacity_mode; + struct wl_signal change_visible_type; + } events; +}; + +struct ds_tizen_indicator_client +{ + struct ds_tizen_indicator *indicator; + + struct wl_resource *resource; + struct wl_client *wl_client; + + struct wl_list infos; + + struct wl_list link; // ds_tizen_indicator::clients +}; + +struct ds_tizen_indicator_info +{ + struct ds_surface *surface; + + int32_t state; + int32_t opacity_mode; + int32_t visible_type; + + struct wl_list link; // ds_tizen_indicator_client::infos +}; + +static void indicator_handle_display_destroy(struct wl_listener *listener, + void *data); + +static void indicator_bind(struct wl_client *wl_client, void *data, + uint32_t version, uint32_t id); + +static struct ds_tizen_indicator_client *tizen_indicator_find_client( + struct ds_tizen_indicator *indicator, + struct ds_surface *surface); + +static struct ds_tizen_indicator_info *tizen_indicator_find_info( + struct ds_tizen_indicator *indicator, + struct ds_surface *surface); + +static struct ds_tizen_indicator_info *tizen_indicator_client_find_info( + struct ds_tizen_indicator_client *client, + struct ds_surface *surface); + +static struct ds_tizen_indicator_info *tizen_indicator_client_get_info( + struct ds_tizen_indicator_client *client, + struct ds_surface *surface); + +WL_EXPORT struct ds_tizen_indicator * +ds_tizen_indicator_create(struct wl_display *display) +{ + struct ds_tizen_indicator *indicator; + + indicator = calloc(1, sizeof *indicator); + if (!indicator) { + ds_err("calloc() failed."); + return NULL; + } + + indicator->global = wl_global_create(display, &tizen_indicator_interface, + 1, indicator, indicator_bind); + if (!indicator->global) { + ds_err("wl_global_create() failed. tizen_indicator_interface"); + free(indicator); + return NULL; + } + + wl_list_init(&indicator->clients); + + indicator->destroy.notify = indicator_handle_display_destroy; + wl_display_add_destroy_listener(display, &indicator->destroy); + + wl_signal_init(&indicator->events.destroy); + wl_signal_init(&indicator->events.change_state); + wl_signal_init(&indicator->events.change_opacity_mode); + wl_signal_init(&indicator->events.change_visible_type); + + ds_inf("Global created: tizen_indicator(%p)", indicator); + + return indicator; +} + +WL_EXPORT void +ds_tizen_indicator_add_destroy_listener(struct ds_tizen_indicator *indicator, + struct wl_listener *listener) +{ + wl_signal_add(&indicator->events.destroy, listener); +} + +WL_EXPORT void +ds_tizen_indicator_add_change_state_listener( + struct ds_tizen_indicator *indicator, struct wl_listener *listener) +{ + wl_signal_add(&indicator->events.change_state, listener); +} + +WL_EXPORT void +ds_tizen_indicator_add_change_opacity_mode_listener( + struct ds_tizen_indicator *indicator, struct wl_listener *listener) +{ + wl_signal_add(&indicator->events.change_opacity_mode, listener); +} + +WL_EXPORT void +ds_tizen_indicator_add_change_visible_type_listener( + struct ds_tizen_indicator *indicator, struct wl_listener *listener) +{ + wl_signal_add(&indicator->events.change_visible_type, listener); +} + +WL_EXPORT enum ds_tizen_indicator_state +ds_tizen_indicator_get_state(struct ds_tizen_indicator *indicator, + struct ds_surface *surface) +{ + struct ds_tizen_indicator_info *info; + + info = tizen_indicator_find_info(indicator, surface); + if (info == NULL) { + ds_err("tizen_indicator: tizen_indicator_find_info() failed."); + return DS_TIZEN_INDICATOR_STATE_UNKNOWN; + } + + return info->state; +} + +WL_EXPORT enum ds_tizen_indicator_opacity_mode +ds_tizen_indicator_get_opacity_mode(struct ds_tizen_indicator *indicator, + struct ds_surface *surface) +{ + struct ds_tizen_indicator_info *info; + + info = tizen_indicator_find_info(indicator, surface); + if (info == NULL) { + ds_err("tizen_indicator: tizen_indicator_find_info() failed."); + return DS_TIZEN_INDICATOR_OPACITY_MODE_UNKNOWN; + } + + return info->opacity_mode; +} + +WL_EXPORT enum ds_tizen_indicator_visible_type +ds_tizen_indicator_get_visible_type(struct ds_tizen_indicator *indicator, + struct ds_surface *surface) +{ + struct ds_tizen_indicator_info *info; + + info = tizen_indicator_find_info(indicator, surface); + if (info == NULL) { + ds_err("tizen_indicator: tizen_indicator_find_info() failed."); + return DS_TIZEN_INDICATOR_VISIBLE_TYPE_HIDDEN; + } + + return info->visible_type; +} + +WL_EXPORT void +ds_tizen_indicator_send_flick(struct ds_tizen_indicator *indicator, + struct ds_surface *surface) +{ + struct ds_tizen_indicator_client *client; + + client = tizen_indicator_find_client(indicator, surface); + if (client == NULL) { + ds_err("tizen_indicator: tizen_indicator_find_client() failed."); + return; + } + + tizen_indicator_send_flick(client->resource, + ds_surface_get_wl_resource(surface), 0); +} + +static struct ds_tizen_indicator_client * +tizen_indicator_find_client(struct ds_tizen_indicator *indicator, + struct ds_surface *surface) +{ + struct ds_tizen_indicator_info *info; + struct ds_tizen_indicator_client *client; + + wl_list_for_each(client, &indicator->clients, link) { + info = tizen_indicator_client_find_info(client, surface); + if (info != NULL) + return client; + } + + return NULL; +} + +static struct ds_tizen_indicator_info * +tizen_indicator_find_info(struct ds_tizen_indicator *indicator, + struct ds_surface *surface) +{ + struct ds_tizen_indicator_info *info; + struct ds_tizen_indicator_client *client; + + wl_list_for_each(client, &indicator->clients, link) { + info = tizen_indicator_client_find_info(client, surface); + if (info != NULL) + return info; + } + + return NULL; +} + +static struct ds_tizen_indicator_info * +tizen_indicator_client_find_info(struct ds_tizen_indicator_client *client, + struct ds_surface *surface) +{ + struct ds_tizen_indicator_info *info; + + wl_list_for_each(info, &client->infos, link) { + if (surface == info->surface) + return info; + } + + return NULL; +} + +static struct ds_tizen_indicator_info * +tizen_indicator_client_get_info(struct ds_tizen_indicator_client *client, + struct ds_surface *surface) +{ + struct ds_tizen_indicator_info *info; + + info = tizen_indicator_client_find_info(client, surface); + if (info) + return info; + + info = calloc(1, sizeof *info); + if (info == NULL) { + ds_err("calloc() failed. tizen_indicator"); + return NULL; + } + + info->surface = surface; + + // The initial values of state, opacity_mode and visible_type are not + // each value of enum ds_tizen_indicator_state, + // enum ds_tizen_indicator_opacity_mode and + // enum ds_tizen_indicator_opacity_mode + // because of the first signal emit for change_state signal. + info->state = -1; + info->opacity_mode = -1; + info->visible_type = -1; + + wl_list_insert(&client->infos, &info->link); + + return info; +} + +static void +indicator_handle_display_destroy(struct wl_listener *listener, void *data) +{ + struct ds_tizen_indicator *indicator; + + indicator = wl_container_of(listener, indicator, destroy); + + ds_inf("Global destroy: indicator(%p)", indicator); + + wl_signal_emit(&indicator->events.destroy, indicator); + wl_list_remove(&indicator->destroy.link); + wl_global_destroy(indicator->global); + free(indicator); +} + +static void +indicator_handle_destroy(struct wl_client *wl_client, + struct wl_resource *resource) +{ + struct ds_tizen_indicator_client *client; + + client = wl_resource_get_user_data(resource); + + if (!wl_list_empty(&client->infos)) { + ds_err("tizen_indicator was destroyed before children"); + return; + } + + wl_resource_destroy(resource); +} + +static void +indicator_handle_set_state(struct wl_client *wl_client, + struct wl_resource *resource, struct wl_resource *surface_resource, + int32_t state) +{ + struct ds_tizen_indicator_client *client; + struct ds_tizen_indicator_info *info; + struct ds_surface *surface; + enum ds_tizen_indicator_state indicator_state; + + ds_inf("tizen_indicator: set_state : state %d", state); + + client = wl_resource_get_user_data(resource); + surface = ds_surface_from_resource(surface_resource); + + info = tizen_indicator_client_get_info(client, surface); + if (info == NULL) { + ds_err("tizen_indicator_client_get_info() failed. tizen_indicator"); + wl_client_post_no_memory(wl_client); + return; + } + + switch (state) { + case TIZEN_INDICATOR_STATE_OFF: + indicator_state = DS_TIZEN_INDICATOR_STATE_OFF; + break; + case TIZEN_INDICATOR_STATE_ON: + indicator_state = DS_TIZEN_INDICATOR_STATE_ON; + break; + default: + indicator_state = DS_TIZEN_INDICATOR_STATE_UNKNOWN; + break; + } + + if (info->state != indicator_state) { + ds_inf("tizen_indicator: surface : %p, change_state : %d -> %d", + surface, info->state, indicator_state); + info->state = indicator_state; + + wl_signal_emit(&client->indicator->events.change_state, surface); + } +} + +static void +indicator_handle_set_opacity_mode(struct wl_client *wl_client, + struct wl_resource *resource, struct wl_resource *surface_resource, + int32_t mode) +{ + struct ds_tizen_indicator_client *client; + struct ds_tizen_indicator_info *info; + struct ds_surface *surface; + enum ds_tizen_indicator_opacity_mode opacity_mode; + + ds_inf("tizen_indicator: set_opacity_mode : opacity_mode %d", mode); + + client = wl_resource_get_user_data(resource); + surface = ds_surface_from_resource(surface_resource); + + info = tizen_indicator_client_get_info(client, surface); + if (info == NULL) { + ds_err("tizen_indicator_client_get_info() failed. tizen_indicator"); + wl_client_post_no_memory(wl_client); + return; + } + + switch (mode) { + case TIZEN_INDICATOR_OPACITY_MODE_OPAQUE: + opacity_mode = DS_TIZEN_INDICATOR_OPACITY_MODE_OPAQUE; + break; + case TIZEN_INDICATOR_OPACITY_MODE_TRANSLUCENT: + opacity_mode = DS_TIZEN_INDICATOR_OPACITY_MODE_TRANSLUCENT; + break; + case TIZEN_INDICATOR_OPACITY_MODE_TRANSPARENT: + opacity_mode = DS_TIZEN_INDICATOR_OPACITY_MODE_TRANSPARENT; + break; + case TIZEN_INDICATOR_OPACITY_MODE_BG_TRANSPARENT: + opacity_mode = DS_TIZEN_INDICATOR_OPACITY_MODE_BG_TRANSPARENT; + break; + default: + opacity_mode = DS_TIZEN_INDICATOR_OPACITY_MODE_UNKNOWN; + break; + } + + if (info->opacity_mode != opacity_mode) { + ds_inf("tizen_indicator: surface : %p, change_opacity_mode : %d -> %d", + surface, info->opacity_mode, opacity_mode); + info->opacity_mode = opacity_mode; + + wl_signal_emit(&client->indicator->events.change_opacity_mode, surface); + } +} + +static void +indicator_handle_set_visible_type(struct wl_client *wl_client, + struct wl_resource *resource, struct wl_resource *surface_resource, + int32_t type) +{ + struct ds_tizen_indicator_client *client; + struct ds_tizen_indicator_info *info; + struct ds_surface *surface; + enum ds_tizen_indicator_visible_type visible_type; + + ds_inf("tizen_indicator: set_visible_type : visible_type %d", type); + + client = wl_resource_get_user_data(resource); + surface = ds_surface_from_resource(surface_resource); + + info = tizen_indicator_client_get_info(client, surface); + if (info == NULL) { + ds_err("tizen_indicator_client_get_info() failed. tizen_indicator"); + wl_client_post_no_memory(wl_client); + return; + } + + switch (type) { + case TIZEN_INDICATOR_VISIBLE_TYPE_SHOWN: + visible_type = DS_TIZEN_INDICATOR_VISIBLE_TYPE_SHOWN; + break; + default: + visible_type = DS_TIZEN_INDICATOR_VISIBLE_TYPE_HIDDEN; + break; + } + + if (info->visible_type != visible_type) { + ds_inf("tizen_indicator: surface : %p, change_visible_type : %d -> %d", + surface, info->visible_type, visible_type); + info->visible_type = visible_type; + + wl_signal_emit(&client->indicator->events.change_visible_type, surface); + } +} + +static const struct tizen_indicator_interface indicator_impl = +{ + indicator_handle_destroy, + indicator_handle_set_state, + indicator_handle_set_opacity_mode, + indicator_handle_set_visible_type, +}; + +static void +_tizen_indicator_client_handle_destroy(struct wl_resource *resource) +{ + struct ds_tizen_indicator_client *client; + struct ds_tizen_indicator_info *info, *tmp; + + client = wl_resource_get_user_data(resource); + + ds_inf("_tizen_indicator_client_handle_destroy (client:%p)", client); + + wl_list_for_each_safe(info, tmp, &client->infos, link) { + wl_list_remove(&info->link); + free(info); + } + + wl_list_remove(&client->link); + free(client); +} + +static void +indicator_bind(struct wl_client *wl_client, void *data, uint32_t version, + uint32_t id) +{ + struct ds_tizen_indicator *indicator = data; + struct ds_tizen_indicator_client *client; + + client = calloc(1, sizeof *client); + if (client == NULL) { + ds_err("calloc() failed. tizen_indicator"); + wl_client_post_no_memory(wl_client); + return; + } + + ds_inf("tizen_indicator_client binds. (client:%p)", client); + + client->indicator = indicator; + client->wl_client = wl_client; + + wl_list_init(&client->infos); + + client->resource = wl_resource_create(wl_client, &tizen_indicator_interface, + MIN(version, TIZEN_INDICATOR_VERSION), id); + if (client->resource == NULL) { + ds_err("tizen_indicator : wl_resource_create() failed."); + free(client); + wl_client_post_no_memory(wl_client); + return; + } + + wl_resource_set_implementation(client->resource, &indicator_impl, client, + _tizen_indicator_client_handle_destroy); + + wl_list_insert(&indicator->clients, &client->link); +} diff --git a/src/indicator/meson.build b/src/indicator/meson.build new file mode 100644 index 0000000..a87c690 --- /dev/null +++ b/src/indicator/meson.build @@ -0,0 +1,29 @@ +libds_tizen_indicator_files = [ + 'indicator.c', +] + +libds_tizen_indicator_deps = [ + deps_libds_tizen, + dependency('tizen-extension-server', required: true), +] + +lib_libds_tizen_indicator = shared_library('ds-tizen-indicator', libds_tizen_indicator_files, + dependencies: libds_tizen_indicator_deps, + include_directories: [ common_inc, include_directories('.'), include_directories('..') ], + version: meson.project_version(), + install: true +) + +deps_libds_tizen_indicator = declare_dependency( + link_with: lib_libds_tizen_indicator, + dependencies: libds_tizen_indicator_deps, + include_directories: [ common_inc, include_directories('.') ], +) + +pkgconfig = import('pkgconfig') +pkgconfig.generate(lib_libds_tizen_indicator, + version: meson.project_version(), + filebase: 'libds-tizen-indicator', + name: 'libds-tizen-indicator', + description: 'tizen indicator extension of libds-tizen for tizen platform', +) diff --git a/src/meson.build b/src/meson.build index 46d807d..09a7f1a 100644 --- a/src/meson.build +++ b/src/meson.build @@ -33,3 +33,4 @@ subdir('backend') subdir('keyrouter') subdir('input_devicemgr') subdir('dpms') +subdir('indicator') -- 2.7.4 From 477ee0aa51b96b54ad4e63e994c281b36e999c22 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Sun, 10 Jul 2022 13:46:59 +0900 Subject: [PATCH 03/16] add mock client/compositor This is the mock classes for testing request/event interaction between client and server. Change-Id: Ide1366d47f3cae83944520c8459a62bf4d737a1f --- tests/mockclient.cpp | 70 ++++++++++++++++++++++ tests/mockclient.h | 48 +++++++++++++++ tests/mockcompositor.cpp | 149 +++++++++++++++++++++++++++++++++++++++++++++++ tests/mockcompositor.h | 80 +++++++++++++++++++++++++ 4 files changed, 347 insertions(+) create mode 100644 tests/mockclient.cpp create mode 100644 tests/mockclient.h create mode 100644 tests/mockcompositor.cpp create mode 100644 tests/mockcompositor.h diff --git a/tests/mockclient.cpp b/tests/mockclient.cpp new file mode 100644 index 0000000..f9f9581 --- /dev/null +++ b/tests/mockclient.cpp @@ -0,0 +1,70 @@ +/************************************************************************** + * + * Copyright 2022 Samsung Electronics co., Ltd. All Rights Reserved. + * + * Contact: SooChan Lim + * + * 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 above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * 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 PRECISION INSIGHT 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. + * +**************************************************************************/ + +#include "mockclient.h" +#include + +MockClient::MockClient() +{ + display = wl_display_connect("test-ds-tizen"); + if (!display) + ds_err("wl_display_connect() filed."); + + registry = wl_display_get_registry(display); + if (!registry) + ds_err("wl_display_get_registry() filed."); +} + +MockClient::MockClient(const struct wl_registry_listener *registry_listener, void *data) +{ + int ret; + display = wl_display_connect("test-ds-tizen"); + if (!display) + ds_err("wl_display_connect() filed."); + + registry = wl_display_get_registry(display); + if (!registry) + ds_err("wl_display_get_registry() filed."); + + ret = wl_registry_add_listener(registry, registry_listener, data); + if (ret) + ds_err("wl_registry_add_listener() filed."); + + wl_display_roundtrip(display); +} + +MockClient::~MockClient() +{ + wl_registry_destroy(registry); + wl_display_disconnect(display); +} + +void MockClient::RoundTrip() +{ + wl_display_roundtrip(display); +} \ No newline at end of file diff --git a/tests/mockclient.h b/tests/mockclient.h new file mode 100644 index 0000000..178b9bc --- /dev/null +++ b/tests/mockclient.h @@ -0,0 +1,48 @@ +/************************************************************************** + * + * Copyright 2022 Samsung Electronics co., Ltd. All Rights Reserved. + * + * Contact: SooChan Lim + * + * 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 above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * 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 PRECISION INSIGHT 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. + * +**************************************************************************/ + +#ifndef _MOCKCLIENT_H_ +#define _MOCKCLIENT_H_ + +#include +#include + +class MockClient +{ +public: + MockClient(); + MockClient(const struct wl_registry_listener *registry_listener, void *data); + virtual ~MockClient(); + void RoundTrip(); + +private: + struct wl_display *display; + struct wl_registry *registry; +}; + +#endif diff --git a/tests/mockcompositor.cpp b/tests/mockcompositor.cpp new file mode 100644 index 0000000..62fc779 --- /dev/null +++ b/tests/mockcompositor.cpp @@ -0,0 +1,149 @@ +/************************************************************************** + * + * Copyright 2020 Samsung Electronics co., Ltd. All Rights Reserved. + * + * Contact: SooChan Lim + * + * 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 above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * 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 PRECISION INSIGHT 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. + * +**************************************************************************/ + +#include "mockcompositor.h" +#include + +static void +logger_func(void *user_data, enum wl_protocol_logger_type type, + const struct wl_protocol_logger_message *message) +{ + //Compositor *c = static_cast(user_data); +#if 0 + std::cout << "res:" << wl_resource_get_class(message->resource) << " " + << "op:" << message->message_opcode << " " + << "name:" << message->message->name << "\n"; +#endif +} + +Compositor::Compositor() + : display(wl_display_create()), + loop(wl_display_get_event_loop(display)), + logger(wl_display_add_protocol_logger(display, logger_func, this)) +{ + int ret; + + ret = wl_display_add_socket(display, "test-ds-tizen"); + if (ret != 0) + ds_err("wl_display_add_socket() filed."); + + ret = wl_display_init_shm(display); + if (ret != 0) + ds_err("wl_display_init_shm() filed."); + + compositor = ds_compositor_create(display); + if (compositor == nullptr) + ds_err("ds_compositor_create() filed."); +} + +Compositor::~Compositor () +{ + wl_list *clients = wl_display_get_client_list(display); + wl_client *client = nullptr; + + wl_client_for_each(client, clients) { + wl_client_destroy(client); + } + + wl_protocol_logger_destroy(logger); + wl_display_destroy(display); +} + +void Compositor::DispatchEvents() +{ + /* flush any pending client events */ + wl_display_flush_clients(display); + /* dispatch any pending main loop events */ + wl_event_loop_dispatch(loop, 0); +} + +MockCompositor::MockCompositor() + : compositor(nullptr) +{ + th = std::thread([this](){ + Compositor c; + compositor = &c; + + // mockcompositor is ready + ready = true; + cv.notify_one(); + + while (alive) { + // mockcompositor process the events in every 40 milliseconds + std::this_thread::sleep_for(std::chrono::milliseconds(40)); + Process(); + } + }); + + // wait until the child thread(mockcompositor) is ready + { + std::unique_lock lock(m); + cv.wait(lock, [this]{return ready;}); + } +} + +MockCompositor::MockCompositor(ds_test_setup_func_t setup_func, void *data) + : compositor(nullptr) +{ + th = std::thread([this, setup_func, data](){ + Compositor c; + compositor = &c; + + // call test setup_function + setup_func(data); + + // mockcompositor is ready + ready = true; + cv.notify_one(); + + while (alive) { + // mockcompositor process the events in every 40 milliseconds + std::this_thread::sleep_for(std::chrono::milliseconds(40)); + + Process(); + } + }); + + // wait until the child thread(mockcompositor) is ready + { + std::unique_lock lock(m); + cv.wait(lock, [this]{return ready;}); + } +} + +MockCompositor::~MockCompositor() { + // finish the child thread(mockcompositor). + alive = false; + th.join(); +} + +void MockCompositor::Process() +{ + std::lock_guard lock(m); + compositor->DispatchEvents(); +} diff --git a/tests/mockcompositor.h b/tests/mockcompositor.h new file mode 100644 index 0000000..2b03f46 --- /dev/null +++ b/tests/mockcompositor.h @@ -0,0 +1,80 @@ +/************************************************************************** + * + * Copyright 2020 Samsung Electronics co., Ltd. All Rights Reserved. + * + * Contact: SooChan Lim + * + * 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 above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * 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 PRECISION INSIGHT 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. + * +**************************************************************************/ + +#ifndef _MOCKCOMPOSITOR_H_ +#define _MOCKCOMPOSITOR_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ds_listener test function call +typedef void (*ds_test_setup_func_t)(void *data); + +class Compositor +{ +public: + Compositor(); + ~Compositor(); + void DispatchEvents(); + +public: + struct wl_display *display; + struct wl_event_loop *loop; + struct wl_protocol_logger *logger; + struct ds_compositor *compositor; +}; + +class MockCompositor +{ +public: + MockCompositor(); + MockCompositor(ds_test_setup_func_t setup_func, void *data); + virtual ~MockCompositor(); + + void Process(); + +protected: + Compositor *compositor; + +private: + std::thread th; + std::mutex m; + std::condition_variable cv; + + bool alive = true; + bool ready = false; +}; + +#endif -- 2.7.4 From 5ccdb3a9e3de42970111f84d166e21c1dc55727c Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Sun, 10 Jul 2022 13:48:27 +0900 Subject: [PATCH 04/16] add indicator test cases Change-Id: I6c755aff6ca1764b73289b64991544b26bed08fb --- packaging/libds-tizen.spec | 1 + tests/meson.build | 26 +++ tests/tc_indicator.cpp | 505 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 532 insertions(+) create mode 100644 tests/tc_indicator.cpp diff --git a/packaging/libds-tizen.spec b/packaging/libds-tizen.spec index 34b918c..8935d5d 100644 --- a/packaging/libds-tizen.spec +++ b/packaging/libds-tizen.spec @@ -261,3 +261,4 @@ ninja -C builddir install %{_includedir}/libds-tizen/indicator.h %{_libdir}/pkgconfig/libds-tizen-indicator.pc %{_libdir}/libds-tizen-indicator.so +%{_bindir}/libds-tizen-indicator-tests diff --git a/tests/meson.build b/tests/meson.build index 1d8158c..8cff406 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -4,6 +4,12 @@ deps_test_common = [ dependency('wayland-client', required: true), ] +tc_mock_files = [ + 'mockclient.cpp', + 'mockcompositor.cpp' +] + +## allcoator_tbm tests tc_allocator_tbm_files = [ 'tc_main.cpp', 'tc_allocator_tbm.cpp', @@ -19,3 +25,23 @@ executable('libds-tizen-allocator-tbm-tests', install_dir: libds_tizen_bindir, install : true ) + +## indicator tests +tc_indicator_files = [ + 'tc_main.cpp', + 'tc_indicator.cpp', +] + +executable('libds-tizen-indicator-tests', + [ + tc_mock_files, + tc_indicator_files + ], + dependencies: [ + deps_test_common, + deps_libds_tizen_indicator, + dependency('libdrm', required: true), + ], + install_dir: libds_tizen_bindir, + install : true +) diff --git a/tests/tc_indicator.cpp b/tests/tc_indicator.cpp new file mode 100644 index 0000000..c589ef3 --- /dev/null +++ b/tests/tc_indicator.cpp @@ -0,0 +1,505 @@ +#include "tc_main.h" +#include "mockclient.h" +#include "mockcompositor.h" +#include +#include + +class MockIndicatorCompositor : public MockCompositor +{ +public: + MockIndicatorCompositor() + : MockCompositor(&MockIndicatorCompositor::TestSetup, this) + { + ds_inf("%s : this(%p)", __func__, this); + + // initialize the flags to check + bSurfaceDestroyed = false; + + bDestroyed = false; + + bStateOn = false; + bStateOff = false; + + bOpacityModeOpque = false; + bOpacityModeTranslucent = false; + bOpacityModeTransparent = false; + bOpacityModeBgTransparent = false; + + bVisibleTypeHidden = false; + bVisibleTypeShown = false; + } + + ~MockIndicatorCompositor() + { + ds_inf("%s : this(%p)", __func__, this); + } + + static void TestSetup(void *data) + { + MockIndicatorCompositor *mockComp = + static_cast(data); + Compositor *comp = mockComp->compositor; + + ds_inf("%s: mockComp(%p)", __func__, mockComp); + + // new surface listener + mockComp->mNewSurfaceListener.notify = + MockIndicatorCompositor::NewSurfaceCallback; + mockComp->mNewSurfaceListener.parent = mockComp; + ds_compositor_add_new_surface_listener(comp->compositor, + &mockComp->mNewSurfaceListener); + + mockComp->mIndicator = ds_tizen_indicator_create(comp->display); + + // destroy listener + mockComp->mDestroyListener.notify = + MockIndicatorCompositor::DestroyCallback; + mockComp->mDestroyListener.parent = mockComp; + ds_tizen_indicator_add_destroy_listener(mockComp->mIndicator, + &mockComp->mDestroyListener); + + // change_state listener + mockComp->mChangeStateListener.notify = + MockIndicatorCompositor::ChangeStateCallback; + mockComp->mChangeStateListener.parent = mockComp; + ds_tizen_indicator_add_change_state_listener(mockComp->mIndicator, + &mockComp->mChangeStateListener); + + // change_opacity_mode listener + mockComp->mChangeOpacityModeListener.notify = + MockIndicatorCompositor::ChangeOpacityModeCallback; + mockComp->mChangeOpacityModeListener.parent = mockComp; + ds_tizen_indicator_add_change_opacity_mode_listener( + mockComp->mIndicator, + &mockComp->mChangeOpacityModeListener); + + // change_visible_type listener + mockComp->mChangeVisibleTypeListener.notify = + MockIndicatorCompositor::ChangeVisibleTypeCallback; + mockComp->mChangeVisibleTypeListener.parent = mockComp; + ds_tizen_indicator_add_change_visible_type_listener( + mockComp->mIndicator, + &mockComp->mChangeVisibleTypeListener); + } + + static void NewSurfaceCallback(struct wl_listener *listener, void *data) + { + MockIndicatorCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_surface *surface = static_cast(data); + + ds_inf("%s: mockComp(%p), surface(%p)", __func__, mockComp, surface); + + mockComp->mSurface = surface; + + // del surface listener + mockComp->mDelSurfaceListener.notify = + MockIndicatorCompositor::DelSurfaceCallback; + mockComp->mDelSurfaceListener.parent = mockComp; + ds_surface_add_destroy_listener(surface, + &mockComp->mDelSurfaceListener); + } + + static void DelSurfaceCallback(struct wl_listener *listener, void *data) + { + MockIndicatorCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_surface *surface = static_cast(data); + + ds_inf("%s: mockComp(%p), surface(%p)", __func__, mockComp, surface); + + if (ds_surface_get_wl_resource(mockComp->mSurface) == + ds_surface_get_wl_resource(surface)) { + ds_inf("%s: surface is deleted.", __func__); + mockComp->bSurfaceDestroyed = true; + } + } + + static void DestroyCallback(struct wl_listener *listener, void *data) + { + ds_inf("%s", __func__); + + MockIndicatorCompositor *mockComp = + reinterpret_cast(listener)->parent; + + mockComp->bDestroyed = true; + } + + static void ChangeStateCallback(struct wl_listener *listener, void *data) + { + ds_inf("%s", __func__); + + MockIndicatorCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_surface *surface = static_cast(data); + enum ds_tizen_indicator_state state; + + ds_inf("%s: mockComp(%p), surface(%p)", __func__, mockComp, surface); + + state = ds_tizen_indicator_get_state(mockComp->mIndicator, + mockComp->mSurface); + + if (state == DS_TIZEN_INDICATOR_STATE_ON) + mockComp->bStateOn = true; + if (state == DS_TIZEN_INDICATOR_STATE_OFF) + mockComp->bStateOff = true; + } + + static void ChangeOpacityModeCallback(struct wl_listener *listener, + void *data) + { + ds_inf("%s", __func__); + + MockIndicatorCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_surface *surface = static_cast(data); + enum ds_tizen_indicator_opacity_mode opacity_mode; + + ds_inf("%s: mockComp(%p), surface(%p)", __func__, mockComp, surface); + + opacity_mode = ds_tizen_indicator_get_opacity_mode(mockComp->mIndicator, + mockComp->mSurface); + + if (opacity_mode == DS_TIZEN_INDICATOR_OPACITY_MODE_OPAQUE) + mockComp->bOpacityModeOpque = true; + if (opacity_mode == DS_TIZEN_INDICATOR_OPACITY_MODE_TRANSLUCENT) + mockComp->bOpacityModeTranslucent = true; + if (opacity_mode == DS_TIZEN_INDICATOR_OPACITY_MODE_TRANSPARENT) + mockComp->bOpacityModeTransparent = true; + if (opacity_mode == DS_TIZEN_INDICATOR_OPACITY_MODE_BG_TRANSPARENT) + mockComp->bOpacityModeBgTransparent = true; + } + + static void ChangeVisibleTypeCallback(struct wl_listener *listener, + void *data) + { + ds_inf("%s", __func__); + + MockIndicatorCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_surface *surface = static_cast(data); + enum ds_tizen_indicator_visible_type visible_type; + + ds_inf("%s: mockComp(%p), surface(%p)", __func__, mockComp, surface); + + visible_type = ds_tizen_indicator_get_visible_type(mockComp->mIndicator, + mockComp->mSurface); + + if (visible_type == DS_TIZEN_INDICATOR_VISIBLE_TYPE_HIDDEN) + mockComp->bVisibleTypeHidden = true; + if (visible_type == DS_TIZEN_INDICATOR_VISIBLE_TYPE_SHOWN) + mockComp->bVisibleTypeShown = true; + } + + void SendFlick() + { + ds_inf("%s", __func__); + + ds_tizen_indicator_send_flick(mIndicator, mSurface); + } + +public: + bool bSurfaceDestroyed; + bool bDestroyed; + bool bStateOn; + bool bStateOff; + bool bOpacityModeOpque; + bool bOpacityModeTranslucent; + bool bOpacityModeTransparent; + bool bOpacityModeBgTransparent; + bool bVisibleTypeHidden; + bool bVisibleTypeShown; + +private: + struct ds_surface *mSurface; + struct NewSurfaceListener : ::wl_listener { + MockIndicatorCompositor *parent; + }; + NewSurfaceListener mNewSurfaceListener; + struct DelSurfaceListener : ::wl_listener { + MockIndicatorCompositor *parent; + }; + NewSurfaceListener mDelSurfaceListener; + + struct ds_tizen_indicator *mIndicator; + struct DestroyListener : ::wl_listener { + MockIndicatorCompositor *parent; + }; + NewSurfaceListener mDestroyListener; + struct ChangeStateListener : ::wl_listener { + MockIndicatorCompositor *parent; + }; + NewSurfaceListener mChangeStateListener; + struct ChangeOpacityModeListener : ::wl_listener { + MockIndicatorCompositor *parent; + }; + NewSurfaceListener mChangeOpacityModeListener; + struct ChangeVisibleTypeListener : ::wl_listener { + MockIndicatorCompositor *parent; + }; + NewSurfaceListener mChangeVisibleTypeListener; +}; + +class MockIndicatorClient : public MockClient +{ +public: + MockIndicatorClient() + : bFlickEvent(false), + compositor_res(nullptr), + tizen_indicator(nullptr) + {} + MockIndicatorClient(const struct wl_registry_listener *listener) + : MockClient(listener, this) + { + ds_inf("%s", __func__); + + bFlickEvent = false; + } + ~MockIndicatorClient() + { + ds_inf("%s", __func__); + } + + void SetWlCompositor(struct wl_compositor *global_res) + { + ds_inf("%s", __func__); + + compositor_res = global_res; + } + + struct wl_compositor *GetWlCompositor() + { + ds_inf("%s", __func__); + + return compositor_res; + } + + void SetTizenIndicator(struct tizen_indicator *global_res) + { + ds_inf("%s", __func__); + + tizen_indicator = global_res; + } + + struct tizen_indicator *GetTizenIndicator() + { + ds_inf("%s", __func__); + + return tizen_indicator; + } + +public: + bool bFlickEvent; + +private: + struct wl_compositor *compositor_res; + struct tizen_indicator *tizen_indicator; +}; + +static void +client_tizen_indicator_cb_flick(void *data, struct tizen_indicator *indicator, + struct wl_surface *surface, int32_t type) +{ + ds_inf("%s", __func__); + + MockIndicatorClient *client = static_cast(data); + + client->bFlickEvent = true; +} + +static const struct tizen_indicator_listener indicator_cb_listener = { + .flick = client_tizen_indicator_cb_flick +}; + +static void +client_registry_cb_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) +{ + ds_inf("%s", __func__); + + MockIndicatorClient *client = static_cast(data); + struct wl_compositor *compositor_res; + struct tizen_indicator *tizen_indicator; + + if (!strcmp(interface, "wl_compositor")) { + compositor_res = (struct wl_compositor *)wl_registry_bind(registry, + name, &wl_compositor_interface, 1); + if (compositor_res == nullptr) { + ds_err("wl_registry_bind() failed. wl_compositor resource."); + return; + } + client->SetWlCompositor(compositor_res); + } else if (!strcmp(interface, "tizen_indicator")) { + tizen_indicator = (struct tizen_indicator *)wl_registry_bind(registry, + name, &tizen_indicator_interface, 1); + if (tizen_indicator == nullptr) { + ds_err("wl_registry_bind() failed. tizen_indicator resource."); + return; + } + client->SetTizenIndicator(tizen_indicator); + + tizen_indicator_add_listener(tizen_indicator, &indicator_cb_listener, + client); + } +} + +static void +client_registry_cb_global_remove(void *data, struct wl_registry *registry, + uint32_t name) +{ + ds_inf("%s", __func__); + + MockIndicatorClient *client = static_cast(data); + struct wl_compositor *compositor_res = client->GetWlCompositor(); + struct tizen_indicator *indicator_res = client->GetTizenIndicator(); + + tizen_indicator_destroy(indicator_res); + wl_compositor_destroy(compositor_res); +} + +static const struct wl_registry_listener registry_listener = { + .global = client_registry_cb_global, + .global_remove = client_registry_cb_global_remove +}; + +class IndicatorTest : public ::testing::Test +{ +public: + void SetUp(void) override; + void TearDown(void) override; + + MockIndicatorCompositor *comp; + MockIndicatorClient *client; + struct wl_compositor *compositor_res; + struct tizen_indicator *indicator_res; + struct wl_surface *surface_res; +}; + +void +IndicatorTest::SetUp(void) +{ + //ds_log_init(DS_DBG, NULL); + + ds_inf("%s", __func__); + + comp = new MockIndicatorCompositor(); + client = new MockIndicatorClient(®istry_listener); + compositor_res = client->GetWlCompositor(); + indicator_res = client->GetTizenIndicator(); + surface_res = wl_compositor_create_surface(compositor_res); + + client->RoundTrip(); +} + +void +IndicatorTest::TearDown(void) +{ + ds_inf("%s", __func__); + + wl_surface_destroy(surface_res); + client->RoundTrip(); + EXPECT_TRUE(comp->bSurfaceDestroyed); + + delete client; + delete comp; +} + + +TEST_F(IndicatorTest, Create_P) +{ + EXPECT_TRUE(true); +} + +TEST_F(IndicatorTest, Req_TizenIndicatorStateOn) +{ + tizen_indicator_set_state(indicator_res, surface_res, + TIZEN_INDICATOR_STATE_ON); + client->RoundTrip(); + EXPECT_TRUE(comp->bStateOn); + EXPECT_FALSE(comp->bStateOff); +} + +TEST_F(IndicatorTest, Req_TizenIndicatorStateOff) +{ + tizen_indicator_set_state(indicator_res, surface_res, + TIZEN_INDICATOR_STATE_OFF); + client->RoundTrip(); + EXPECT_FALSE(comp->bStateOn); + EXPECT_TRUE(comp->bStateOff); +} + +TEST_F(IndicatorTest, Req_TizenIndicatorOpacityModeOpaque) +{ + tizen_indicator_set_opacity_mode(indicator_res, surface_res, + TIZEN_INDICATOR_OPACITY_MODE_OPAQUE); + client->RoundTrip(); + EXPECT_TRUE(comp->bOpacityModeOpque); + EXPECT_FALSE(comp->bOpacityModeTranslucent); + EXPECT_FALSE(comp->bOpacityModeTransparent); + EXPECT_FALSE(comp->bOpacityModeBgTransparent); +} + +TEST_F(IndicatorTest, Req_TizenIndicatorOpacityModeTranslucent) +{ + tizen_indicator_set_opacity_mode(indicator_res, surface_res, + TIZEN_INDICATOR_OPACITY_MODE_TRANSLUCENT); + client->RoundTrip(); + EXPECT_FALSE(comp->bOpacityModeOpque); + EXPECT_TRUE(comp->bOpacityModeTranslucent); + EXPECT_FALSE(comp->bOpacityModeTransparent); + EXPECT_FALSE(comp->bOpacityModeBgTransparent); +} + +TEST_F(IndicatorTest, Req_TizenIndicatorOpacityModeTransparent) +{ + tizen_indicator_set_opacity_mode(indicator_res, surface_res, + TIZEN_INDICATOR_OPACITY_MODE_TRANSPARENT); + client->RoundTrip(); + EXPECT_FALSE(comp->bOpacityModeOpque); + EXPECT_FALSE(comp->bOpacityModeTranslucent); + EXPECT_TRUE(comp->bOpacityModeTransparent); + EXPECT_FALSE(comp->bOpacityModeBgTransparent); +} + +TEST_F(IndicatorTest, Req_TizenIndicatorOpacityModeBgTransparent) +{ + tizen_indicator_set_opacity_mode(indicator_res, surface_res, + TIZEN_INDICATOR_OPACITY_MODE_BG_TRANSPARENT); + client->RoundTrip(); + EXPECT_FALSE(comp->bOpacityModeOpque); + EXPECT_FALSE(comp->bOpacityModeTranslucent); + EXPECT_FALSE(comp->bOpacityModeTransparent); + EXPECT_TRUE(comp->bOpacityModeBgTransparent); +} + +TEST_F(IndicatorTest, Req_TizenIndicatorVisibleTypeHidden) +{ + tizen_indicator_set_visible_type(indicator_res, surface_res, + TIZEN_INDICATOR_VISIBLE_TYPE_HIDDEN); + client->RoundTrip(); + EXPECT_TRUE(comp->bVisibleTypeHidden); + EXPECT_FALSE(comp->bVisibleTypeShown); +} + +TEST_F(IndicatorTest, Req_TizenIndicatorVisibleTypeShown) +{ + tizen_indicator_set_visible_type(indicator_res, surface_res, + TIZEN_INDICATOR_VISIBLE_TYPE_SHOWN); + client->RoundTrip(); + EXPECT_FALSE(comp->bVisibleTypeHidden); + EXPECT_TRUE(comp->bVisibleTypeShown); +} + +TEST_F(IndicatorTest, Ev_TizenIndicatorFlick) +{ + tizen_indicator_set_state(indicator_res, surface_res, + TIZEN_INDICATOR_STATE_ON); + client->RoundTrip(); + EXPECT_TRUE(comp->bStateOn); + + comp->SendFlick(); + comp->Process(); + + client->RoundTrip(); + EXPECT_TRUE(client->bFlickEvent); +} -- 2.7.4 From d63e154e2c3427e6d0f1f4509eaddd99638bff38 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Wed, 20 Jul 2022 16:11:22 +0900 Subject: [PATCH 05/16] impelement libds-tizen-clipboard This is the server implementation for tizen_clipboard protocol. Change-Id: Idb03da717fd867bb9fd31e8bf9878e1006553ada --- include/libds-tizen/clipboard.h | 50 ++++++ packaging/libds-tizen.spec | 29 ++++ src/clipboard/clipboard.c | 366 ++++++++++++++++++++++++++++++++++++++++ src/clipboard/meson.build | 29 ++++ src/meson.build | 1 + 5 files changed, 475 insertions(+) create mode 100644 include/libds-tizen/clipboard.h create mode 100644 src/clipboard/clipboard.c create mode 100644 src/clipboard/meson.build diff --git a/include/libds-tizen/clipboard.h b/include/libds-tizen/clipboard.h new file mode 100644 index 0000000..697c9e7 --- /dev/null +++ b/include/libds-tizen/clipboard.h @@ -0,0 +1,50 @@ +#ifndef LIBDS_TIZEN_CLIPBOARD_H +#define LIBDS_TIZEN_CLIPBOARD_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ds_tizen_clipboard; +struct ds_tizen_clipboard_client; + +struct ds_tizen_clipboard * +ds_tizen_clipboard_create(struct wl_display *display); + +void +ds_tizen_clipboard_add_destroy_listener(struct ds_tizen_clipboard *clipboard, + struct wl_listener *listener); + +void +ds_tizen_clipboard_add_show_listener( + struct ds_tizen_clipboard *clipboard, struct wl_listener *listener); + +void +ds_tizen_clipboard_add_hide_listener( + struct ds_tizen_clipboard *clipboard, struct wl_listener *listener); + +void +ds_tizen_clipboard_add_set_data_only_listener( + struct ds_tizen_clipboard *clipboard, struct wl_listener *listener); + +uint32_t +ds_tizen_clipboard_client_get_data_only( + struct ds_tizen_clipboard_client *client); + +void +ds_tizen_clipboard_send_data_selected(struct ds_tizen_clipboard *clipboard, + struct ds_surface *surface); + +void +ds_tizen_clipboard_client_send_allowed_data_only( + struct ds_tizen_clipboard_client *client, uint32_t allowed); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packaging/libds-tizen.spec b/packaging/libds-tizen.spec index 8935d5d..bb5c681 100644 --- a/packaging/libds-tizen.spec +++ b/packaging/libds-tizen.spec @@ -137,6 +137,21 @@ Group: Development/Libraries %description indicator-devel Development package for tizen indicator +## libds-tizen-clipboard +%package clipboard +Summary: Library for tizen clipboard +Group: Development/Libraries + +%description clipboard +Library for tizen clipboard + +%package clipboard-devel +Summary: Development package for tizen clipboard +Group: Development/Libraries + +%description clipboard-devel +Development package for tizen clipboard + %prep %setup -q cp %{SOURCE1001} . @@ -262,3 +277,17 @@ ninja -C builddir install %{_libdir}/pkgconfig/libds-tizen-indicator.pc %{_libdir}/libds-tizen-indicator.so %{_bindir}/libds-tizen-indicator-tests + +%files clipboard +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_libdir}/libds-tizen-clipboard.so.* + +%files clipboard-devel +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_includedir}/libds-tizen/clipboard.h +%{_libdir}/pkgconfig/libds-tizen-clipboard.pc +%{_libdir}/libds-tizen-clipboard.so diff --git a/src/clipboard/clipboard.c b/src/clipboard/clipboard.c new file mode 100644 index 0000000..bfa9595 --- /dev/null +++ b/src/clipboard/clipboard.c @@ -0,0 +1,366 @@ +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "libds-tizen/clipboard.h" + +#define TIZEN_CLIPBOARD_VERSION 2 + +struct ds_tizen_clipboard +{ + struct wl_global *global; + + struct wl_list clients; + + struct wl_listener destroy; + + struct { + struct wl_signal destroy; + struct wl_signal show; + struct wl_signal hide; + struct wl_signal set_data_only; + } events; +}; + +struct ds_tizen_clipboard_client +{ + struct ds_tizen_clipboard *clipboard; + + struct wl_resource *resource; + struct wl_client *wl_client; + + struct wl_list infos; + + uint32_t data_only; + + struct wl_list link; // ds_tizen_clipboard::clients +}; + +struct ds_tizen_clipboard_info +{ + struct ds_surface *surface; + + struct wl_list link; // ds_tizen_clipboard_client::infos +}; + +static void clipboard_handle_display_destroy(struct wl_listener *listener, + void *data); + +static void clipboard_bind(struct wl_client *wl_client, void *data, + uint32_t version, uint32_t id); + +static struct ds_tizen_clipboard_client *tizen_clipboard_find_client( + struct ds_tizen_clipboard *clipboard, + struct ds_surface *surface); + +static struct ds_tizen_clipboard_info *tizen_clipboard_client_find_info( + struct ds_tizen_clipboard_client *client, + struct ds_surface *surface); + +static struct ds_tizen_clipboard_info *tizen_clipboard_client_get_info( + struct ds_tizen_clipboard_client *client, + struct ds_surface *surface); + +WL_EXPORT struct ds_tizen_clipboard * +ds_tizen_clipboard_create(struct wl_display *display) +{ + struct ds_tizen_clipboard *clipboard; + + clipboard = calloc(1, sizeof *clipboard); + if (!clipboard) { + ds_err("calloc() failed."); + return NULL; + } + + clipboard->global = wl_global_create(display, &tizen_clipboard_interface, + TIZEN_CLIPBOARD_VERSION, clipboard, clipboard_bind); + if (!clipboard->global) { + ds_err("wl_global_create() failed. tizen_clipboard_interface"); + free(clipboard); + return NULL; + } + + wl_list_init(&clipboard->clients); + + clipboard->destroy.notify = clipboard_handle_display_destroy; + wl_display_add_destroy_listener(display, &clipboard->destroy); + + wl_signal_init(&clipboard->events.destroy); + wl_signal_init(&clipboard->events.show); + wl_signal_init(&clipboard->events.hide); + wl_signal_init(&clipboard->events.set_data_only); + + ds_inf("Global created: tizen_clipboard(%p)", clipboard); + + return clipboard; +} + +WL_EXPORT void +ds_tizen_clipboard_add_destroy_listener(struct ds_tizen_clipboard *clipboard, + struct wl_listener *listener) +{ + wl_signal_add(&clipboard->events.destroy, listener); +} + +WL_EXPORT void +ds_tizen_clipboard_add_show_listener( + struct ds_tizen_clipboard *clipboard, struct wl_listener *listener) +{ + wl_signal_add(&clipboard->events.show, listener); +} + +WL_EXPORT void +ds_tizen_clipboard_add_hide_listener( + struct ds_tizen_clipboard *clipboard, struct wl_listener *listener) +{ + wl_signal_add(&clipboard->events.hide, listener); +} + +WL_EXPORT void +ds_tizen_clipboard_add_set_data_only_listener( + struct ds_tizen_clipboard *clipboard, struct wl_listener *listener) +{ + wl_signal_add(&clipboard->events.set_data_only, listener); +} + +WL_EXPORT uint32_t +ds_tizen_clipboard_client_get_data_only( + struct ds_tizen_clipboard_client *client) +{ + return client->data_only; +} + +WL_EXPORT void +ds_tizen_clipboard_send_data_selected(struct ds_tizen_clipboard *clipboard, + struct ds_surface *surface) +{ + struct ds_tizen_clipboard_client *client; + + client = tizen_clipboard_find_client(clipboard, surface); + if (client == NULL) { + ds_err("tizen_clipboard: tizen_clipboard_find_client() failed."); + return; + } + + tizen_clipboard_send_data_selected(client->resource, + ds_surface_get_wl_resource(surface)); +} + +WL_EXPORT void +ds_tizen_clipboard_client_send_allowed_data_only( + struct ds_tizen_clipboard_client *client, uint32_t allowed) +{ + tizen_clipboard_send_allowed_data_only(client->resource, allowed); +} + +static struct ds_tizen_clipboard_client * +tizen_clipboard_find_client(struct ds_tizen_clipboard *clipboard, + struct ds_surface *surface) +{ + struct ds_tizen_clipboard_info *info; + struct ds_tizen_clipboard_client *client; + + wl_list_for_each(client, &clipboard->clients, link) { + info = tizen_clipboard_client_find_info(client, surface); + if (info != NULL) + return client; + } + + return NULL; +} + +static struct ds_tizen_clipboard_info * +tizen_clipboard_client_find_info(struct ds_tizen_clipboard_client *client, + struct ds_surface *surface) +{ + struct ds_tizen_clipboard_info *info; + + wl_list_for_each(info, &client->infos, link) { + if (surface == info->surface) + return info; + } + + return NULL; +} + +static struct ds_tizen_clipboard_info * +tizen_clipboard_client_get_info(struct ds_tizen_clipboard_client *client, + struct ds_surface *surface) +{ + struct ds_tizen_clipboard_info *info; + + info = tizen_clipboard_client_find_info(client, surface); + if (info) + return info; + + info = calloc(1, sizeof *info); + if (info == NULL) { + ds_err("calloc() failed. tizen_clipboard"); + return NULL; + } + + info->surface = surface; + + wl_list_insert(&client->infos, &info->link); + + return info; +} + +static void +clipboard_handle_display_destroy(struct wl_listener *listener, void *data) +{ + struct ds_tizen_clipboard *clipboard; + + clipboard = wl_container_of(listener, clipboard, destroy); + + ds_inf("Global destroy: clipboard(%p)", clipboard); + + wl_signal_emit(&clipboard->events.destroy, clipboard); + wl_list_remove(&clipboard->destroy.link); + wl_global_destroy(clipboard->global); + free(clipboard); +} + +static void +clipboard_handle_destroy(struct wl_client *wl_client, + struct wl_resource *resource) +{ + struct ds_tizen_clipboard_client *client; + + client = wl_resource_get_user_data(resource); + + if (!wl_list_empty(&client->infos)) { + ds_err("tizen_clipboard was destroyed before children"); + return; + } + + wl_resource_destroy(resource); +} + +static void +clipboard_handle_show(struct wl_client *wl_client, + struct wl_resource *resource, struct wl_resource *surface_resource) +{ + struct ds_tizen_clipboard_client *client; + struct ds_tizen_clipboard_info *info; + struct ds_surface *surface; + + ds_inf("tizen_clipboard: show"); + + client = wl_resource_get_user_data(resource); + surface = ds_surface_from_resource(surface_resource); + + info = tizen_clipboard_client_get_info(client, surface); + if (info == NULL) { + ds_err("tizen_clipboard_client_get_info() failed. tizen_clipboard"); + wl_client_post_no_memory(wl_client); + return; + } + + wl_signal_emit(&client->clipboard->events.show, surface); +} + +static void +clipboard_handle_hide(struct wl_client *wl_client, + struct wl_resource *resource, struct wl_resource *surface_resource) +{ + struct ds_tizen_clipboard_client *client; + struct ds_tizen_clipboard_info *info; + struct ds_surface *surface; + + ds_inf("tizen_clipboard: hide"); + + client = wl_resource_get_user_data(resource); + surface = ds_surface_from_resource(surface_resource); + + info = tizen_clipboard_client_get_info(client, surface); + if (info == NULL) { + ds_err("tizen_clipboard_client_get_info() failed. tizen_clipboard"); + wl_client_post_no_memory(wl_client); + return; + } + + wl_signal_emit(&client->clipboard->events.hide, surface); +} + +static void +clipboard_handle_set_data_only(struct wl_client *wl_client, + struct wl_resource *resource, uint32_t set) +{ + struct ds_tizen_clipboard_client *client; + + ds_inf("tizen_clipboard: set_data_only. set(%d)", set); + + client = wl_resource_get_user_data(resource); + client->data_only = set; + + wl_signal_emit(&client->clipboard->events.set_data_only, client); +} + +static const struct tizen_clipboard_interface clipboard_impl = +{ + clipboard_handle_destroy, + clipboard_handle_show, + clipboard_handle_hide, + clipboard_handle_set_data_only, +}; + +static void +_tizen_clipboard_client_handle_destroy(struct wl_resource *resource) +{ + struct ds_tizen_clipboard_client *client; + struct ds_tizen_clipboard_info *info, *tmp; + + client = wl_resource_get_user_data(resource); + + ds_inf("_tizen_clipboard_client_handle_destroy (client:%p)", client); + + wl_list_for_each_safe(info, tmp, &client->infos, link) { + wl_list_remove(&info->link); + free(info); + } + + wl_list_remove(&client->link); + free(client); +} + +static void +clipboard_bind(struct wl_client *wl_client, void *data, uint32_t version, + uint32_t id) +{ + struct ds_tizen_clipboard *clipboard = data; + struct ds_tizen_clipboard_client *client; + + client = calloc(1, sizeof *client); + if (client == NULL) { + ds_err("calloc() failed. tizen_clipboard"); + wl_client_post_no_memory(wl_client); + return; + } + + ds_inf("tizen_clipboard_client binds. (client:%p)", client); + + client->clipboard = clipboard; + client->wl_client = wl_client; + + wl_list_init(&client->infos); + + client->resource = wl_resource_create(wl_client, &tizen_clipboard_interface, + MIN(version, TIZEN_CLIPBOARD_VERSION), id); + + if (client->resource == NULL) { + ds_err("tizen_clipboard : wl_resource_create() failed."); + free(client); + wl_client_post_no_memory(wl_client); + return; + } + + wl_resource_set_implementation(client->resource, &clipboard_impl, client, + _tizen_clipboard_client_handle_destroy); + + wl_list_insert(&clipboard->clients, &client->link); +} diff --git a/src/clipboard/meson.build b/src/clipboard/meson.build new file mode 100644 index 0000000..2889c22 --- /dev/null +++ b/src/clipboard/meson.build @@ -0,0 +1,29 @@ +libds_tizen_clipboard_files = [ + 'clipboard.c', +] + +libds_tizen_clipboard_deps = [ + deps_libds_tizen, + dependency('tizen-extension-server', required: true), +] + +lib_libds_tizen_clipboard = shared_library('ds-tizen-clipboard', libds_tizen_clipboard_files, + dependencies: libds_tizen_clipboard_deps, + include_directories: [ common_inc, include_directories('.'), include_directories('..') ], + version: meson.project_version(), + install: true +) + +deps_libds_tizen_clipboard = declare_dependency( + link_with: lib_libds_tizen_clipboard, + dependencies: libds_tizen_clipboard_deps, + include_directories: [ common_inc, include_directories('.') ], +) + +pkgconfig = import('pkgconfig') +pkgconfig.generate(lib_libds_tizen_clipboard, + version: meson.project_version(), + filebase: 'libds-tizen-clipboard', + name: 'libds-tizen-clipboard', + description: 'tizen clipboard extension of libds-tizen for tizen platform', +) diff --git a/src/meson.build b/src/meson.build index 09a7f1a..73c169c 100644 --- a/src/meson.build +++ b/src/meson.build @@ -34,3 +34,4 @@ subdir('keyrouter') subdir('input_devicemgr') subdir('dpms') subdir('indicator') +subdir('clipboard') -- 2.7.4 From 80dd61f50c67535a2093118e8c9102063204ea7f Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Wed, 20 Jul 2022 17:13:47 +0900 Subject: [PATCH 06/16] add test cases for ds_tizen_clipboard These are unit testcases. Change-Id: I17d0d392c3c8af7041fe93752b5facb6be7e41b5 --- packaging/libds-tizen.spec | 1 + tests/meson.build | 20 ++ tests/tc_clipboard.cpp | 457 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 478 insertions(+) create mode 100644 tests/tc_clipboard.cpp diff --git a/packaging/libds-tizen.spec b/packaging/libds-tizen.spec index bb5c681..16e6ce7 100644 --- a/packaging/libds-tizen.spec +++ b/packaging/libds-tizen.spec @@ -291,3 +291,4 @@ ninja -C builddir install %{_includedir}/libds-tizen/clipboard.h %{_libdir}/pkgconfig/libds-tizen-clipboard.pc %{_libdir}/libds-tizen-clipboard.so +%{_bindir}/libds-tizen-clipboard-tests diff --git a/tests/meson.build b/tests/meson.build index 8cff406..eb8d221 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -45,3 +45,23 @@ executable('libds-tizen-indicator-tests', install_dir: libds_tizen_bindir, install : true ) + +## clipboard tests +tc_clipboard_files = [ + 'tc_main.cpp', + 'tc_clipboard.cpp', +] + +executable('libds-tizen-clipboard-tests', + [ + tc_mock_files, + tc_clipboard_files + ], + dependencies: [ + deps_test_common, + deps_libds_tizen_clipboard, + dependency('libdrm', required: true), + ], + install_dir: libds_tizen_bindir, + install : true +) diff --git a/tests/tc_clipboard.cpp b/tests/tc_clipboard.cpp new file mode 100644 index 0000000..710495a --- /dev/null +++ b/tests/tc_clipboard.cpp @@ -0,0 +1,457 @@ +#include "tc_main.h" +#include "mockclient.h" +#include "mockcompositor.h" +#include +#include + +#define TIZEN_CLIPBOARD_VERSION 2 + +class MockClipboardCompositor : public MockCompositor +{ +public: + MockClipboardCompositor() + : MockCompositor(&MockClipboardCompositor::TestSetup, this) + { + ds_inf("%s : this(%p)", __func__, this); + + // initialize the flags to check + bSurfaceDestroyed = false; + + bDestroyed = false; + bShow = false; + bHide = false; + mSetDataOnly = 0; + + mAllowed = 0; + } + + ~MockClipboardCompositor() + { + ds_inf("%s : this(%p)", __func__, this); + } + + static void TestSetup(void *data) + { + MockClipboardCompositor *mockComp = + static_cast(data); + Compositor *comp = mockComp->compositor; + + ds_inf("%s: mockComp(%p)", __func__, mockComp); + + // new surface listener + mockComp->mNewSurfaceListener.notify = + MockClipboardCompositor::NewSurfaceCallback; + mockComp->mNewSurfaceListener.parent = mockComp; + ds_compositor_add_new_surface_listener(comp->compositor, + &mockComp->mNewSurfaceListener); + + mockComp->mClipboard = ds_tizen_clipboard_create(comp->display); + + // destroy listener + mockComp->mDestroyListener.notify = + MockClipboardCompositor::DestroyCallback; + mockComp->mDestroyListener.parent = mockComp; + ds_tizen_clipboard_add_destroy_listener(mockComp->mClipboard, + &mockComp->mDestroyListener); + + // show listener + mockComp->mShowListener.notify = + MockClipboardCompositor::ShowCallback; + mockComp->mShowListener.parent = mockComp; + ds_tizen_clipboard_add_show_listener(mockComp->mClipboard, + &mockComp->mShowListener); + + // hide listener + mockComp->mHideListener.notify = + MockClipboardCompositor::HideCallback; + mockComp->mHideListener.parent = mockComp; + ds_tizen_clipboard_add_hide_listener( + mockComp->mClipboard, + &mockComp->mHideListener); + + // set_data_only listener + mockComp->mSetDataOnlyListener.notify = + MockClipboardCompositor::SetDataOnlyCallback; + mockComp->mSetDataOnlyListener.parent = mockComp; + ds_tizen_clipboard_add_set_data_only_listener( + mockComp->mClipboard, + &mockComp->mSetDataOnlyListener); + } + + static void NewSurfaceCallback(struct wl_listener *listener, void *data) + { + MockClipboardCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_surface *surface = static_cast(data); + + ds_inf("%s: mockComp(%p), surface(%p)", __func__, mockComp, surface); + + mockComp->mSurface = surface; + + // del surface listener + mockComp->mDelSurfaceListener.notify = + MockClipboardCompositor::DelSurfaceCallback; + mockComp->mDelSurfaceListener.parent = mockComp; + ds_surface_add_destroy_listener(surface, + &mockComp->mDelSurfaceListener); + } + + static void DelSurfaceCallback(struct wl_listener *listener, void *data) + { + MockClipboardCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_surface *surface = static_cast(data); + + ds_inf("%s: mockComp(%p), surface(%p)", __func__, mockComp, surface); + + if (ds_surface_get_wl_resource(mockComp->mSurface) == + ds_surface_get_wl_resource(surface)) { + ds_inf("%s: surface is deleted.", __func__); + mockComp->bSurfaceDestroyed = true; + } + } + + static void DestroyCallback(struct wl_listener *listener, void *data) + { + ds_inf("%s", __func__); + + MockClipboardCompositor *mockComp = + reinterpret_cast(listener)->parent; + + mockComp->bDestroyed = true; + } + + static void ShowCallback(struct wl_listener *listener, void *data) + { + ds_inf("%s", __func__); + + MockClipboardCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_surface *surface = static_cast(data); + + ds_inf("%s: mockComp(%p), surface(%p)", __func__, mockComp, surface); + + mockComp->bShow = true; + } + + static void HideCallback(struct wl_listener *listener, + void *data) + { + ds_inf("%s", __func__); + + MockClipboardCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_surface *surface = static_cast(data); + + ds_inf("%s: mockComp(%p), surface(%p)", __func__, mockComp, surface); + + mockComp->bHide = true; + } + + static void SetDataOnlyCallback(struct wl_listener *listener, + void *data) + { + ds_inf("%s", __func__); + + MockClipboardCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_tizen_clipboard_client *client = + static_cast(data); + + ds_inf("%s: mockComp(%p), client(%p)", __func__, mockComp, client); + + mockComp->mSetDataOnly = + ds_tizen_clipboard_client_get_data_only(client); + + ds_tizen_clipboard_client_send_allowed_data_only(client, + mockComp->mAllowed); + } + + void SendDataSelected() + { + ds_inf("%s", __func__); + + ds_tizen_clipboard_send_data_selected(mClipboard, mSurface); + } + + void SetAllowedDataOnly(uint32_t allowed) + { + ds_inf("%s", __func__); + + mAllowed = allowed; + } + +public: + bool bSurfaceDestroyed; + bool bDestroyed; + bool bShow; + bool bHide; + uint32_t mSetDataOnly; + + uint32_t mAllowed; + +private: + struct ds_surface *mSurface; + struct NewSurfaceListener : ::wl_listener { + MockClipboardCompositor *parent; + }; + NewSurfaceListener mNewSurfaceListener; + struct DelSurfaceListener : ::wl_listener { + MockClipboardCompositor *parent; + }; + DelSurfaceListener mDelSurfaceListener; + + struct ds_tizen_clipboard *mClipboard; + struct DestroyListener : ::wl_listener { + MockClipboardCompositor *parent; + }; + DestroyListener mDestroyListener; + struct ShowListener : ::wl_listener { + MockClipboardCompositor *parent; + }; + ShowListener mShowListener; + struct HideListener : ::wl_listener { + MockClipboardCompositor *parent; + }; + HideListener mHideListener; + struct SetDataOnlyListener : ::wl_listener { + MockClipboardCompositor *parent; + }; + SetDataOnlyListener mSetDataOnlyListener; +}; + +class MockClipboardClient : public MockClient +{ +public: + MockClipboardClient() + : bDataSelectedEvent(false), + mAllowedDataOnly(0), + compositor_res(nullptr), + tizen_clipboard(nullptr) + {} + MockClipboardClient(const struct wl_registry_listener *listener) + : MockClient(listener, this) + { + ds_inf("%s", __func__); + + bDataSelectedEvent = false; + mAllowedDataOnly = 0; + } + ~MockClipboardClient() + { + ds_inf("%s", __func__); + } + + void SetWlCompositor(struct wl_compositor *global_res) + { + ds_inf("%s", __func__); + + compositor_res = global_res; + } + + struct wl_compositor *GetWlCompositor() + { + ds_inf("%s", __func__); + + return compositor_res; + } + + void SetTizenClipboard(struct tizen_clipboard *global_res) + { + ds_inf("%s", __func__); + + tizen_clipboard = global_res; + } + + struct tizen_clipboard *GetTizenClipboard() + { + ds_inf("%s", __func__); + + return tizen_clipboard; + } + +public: + bool bDataSelectedEvent; + uint32_t mAllowedDataOnly; + +private: + struct wl_compositor *compositor_res; + struct tizen_clipboard *tizen_clipboard; +}; + +static void +client_tizen_clipboard_cb_data_selected(void *data, + struct tizen_clipboard *clipboard, struct wl_surface *surface) +{ + ds_inf("%s", __func__); + + MockClipboardClient *client = static_cast(data); + + client->bDataSelectedEvent = true; +} + +static void +client_tizen_clipboard_cb_allowed_data_only(void *data, + struct tizen_clipboard *clipboard, uint32_t allowed) +{ + ds_inf("%s", __func__); + + MockClipboardClient *client = static_cast(data); + + client->mAllowedDataOnly = allowed; +} + +static const struct tizen_clipboard_listener clipboard_cb_listener = { + .data_selected = client_tizen_clipboard_cb_data_selected, + .allowed_data_only = client_tizen_clipboard_cb_allowed_data_only +}; + +static void +client_registry_cb_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) +{ + ds_inf("%s", __func__); + + MockClipboardClient *client = static_cast(data); + struct wl_compositor *compositor_res; + struct tizen_clipboard *tizen_clipboard; + + if (!strcmp(interface, "wl_compositor")) { + compositor_res = (struct wl_compositor *)wl_registry_bind(registry, + name, &wl_compositor_interface, 1); + if (compositor_res == nullptr) { + ds_err("wl_registry_bind() failed. wl_compositor resource."); + return; + } + client->SetWlCompositor(compositor_res); + } else if (!strcmp(interface, "tizen_clipboard")) { + tizen_clipboard = (struct tizen_clipboard *)wl_registry_bind(registry, + name, &tizen_clipboard_interface, TIZEN_CLIPBOARD_VERSION); + if (tizen_clipboard == nullptr) { + ds_err("wl_registry_bind() failed. tizen_clipboard resource."); + return; + } + client->SetTizenClipboard(tizen_clipboard); + + tizen_clipboard_add_listener(tizen_clipboard, &clipboard_cb_listener, + client); + } +} + +static void +client_registry_cb_global_remove(void *data, struct wl_registry *registry, + uint32_t name) +{ + ds_inf("%s", __func__); + + MockClipboardClient *client = static_cast(data); + struct wl_compositor *compositor_res = client->GetWlCompositor(); + struct tizen_clipboard *clipboard_res = client->GetTizenClipboard(); + + tizen_clipboard_destroy(clipboard_res); + wl_compositor_destroy(compositor_res); +} + +static const struct wl_registry_listener registry_listener = { + .global = client_registry_cb_global, + .global_remove = client_registry_cb_global_remove +}; + +class ClipboardTest : public ::testing::Test +{ +public: + void SetUp(void) override; + void TearDown(void) override; + + MockClipboardCompositor *comp; + MockClipboardClient *client; + struct wl_compositor *compositor_res; + struct tizen_clipboard *clipboard_res; + struct wl_surface *surface_res; +}; + +void +ClipboardTest::SetUp(void) +{ + //ds_log_init(DS_DBG, NULL); + + ds_inf("%s", __func__); + + comp = new MockClipboardCompositor(); + client = new MockClipboardClient(®istry_listener); + compositor_res = client->GetWlCompositor(); + clipboard_res = client->GetTizenClipboard(); + surface_res = wl_compositor_create_surface(compositor_res); + + client->RoundTrip(); +} + +void +ClipboardTest::TearDown(void) +{ + ds_inf("%s", __func__); + + wl_surface_destroy(surface_res); + client->RoundTrip(); + EXPECT_TRUE(comp->bSurfaceDestroyed); + + delete client; + delete comp; +} + +TEST_F(ClipboardTest, Create_P) +{ + EXPECT_TRUE(true); +} + +TEST_F(ClipboardTest, Req_TizenClipboardShow) +{ + tizen_clipboard_show(clipboard_res, surface_res); + client->RoundTrip(); + EXPECT_TRUE(comp->bShow); + EXPECT_FALSE(comp->bHide); +} + +TEST_F(ClipboardTest, Req_TizenClipboardHide) +{ + tizen_clipboard_hide(clipboard_res, surface_res); + client->RoundTrip(); + EXPECT_FALSE(comp->bShow); + EXPECT_TRUE(comp->bHide); +} + +TEST_F(ClipboardTest, Req_TizenClipboardSetDataOnly) +{ + tizen_clipboard_set_data_only(clipboard_res, 1); + client->RoundTrip(); + EXPECT_TRUE(comp->mSetDataOnly == 1); +} + +TEST_F(ClipboardTest, Ev_TizenClipboardDataSelected) +{ + tizen_clipboard_show(clipboard_res, surface_res); + client->RoundTrip(); + EXPECT_TRUE(comp->bShow); + + comp->SendDataSelected(); + comp->Process(); + + client->RoundTrip(); + EXPECT_TRUE(client->bDataSelectedEvent); +} + +TEST_F(ClipboardTest, Ev_TizenClipboardAllowedDataOnly) +{ + // set the value of allowed to be 1 at compositor + comp->SetAllowedDataOnly(1); + + // send a client's request + tizen_clipboard_set_data_only(clipboard_res, 1); + client->RoundTrip(); + EXPECT_TRUE(comp->mSetDataOnly); + + comp->Process(); + + client->RoundTrip(); + EXPECT_TRUE(client->mAllowedDataOnly == 1); +} -- 2.7.4 From e9c16b49a848b2f7ee81c38907d85da975916a3e Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Thu, 21 Jul 2022 08:27:35 +0900 Subject: [PATCH 07/16] fix the typo Change-Id: I8a9325b59e7f6cf4e372554bde71386ca9d15514 --- tests/tc_indicator.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/tc_indicator.cpp b/tests/tc_indicator.cpp index c589ef3..7585496 100644 --- a/tests/tc_indicator.cpp +++ b/tests/tc_indicator.cpp @@ -219,25 +219,25 @@ private: struct DelSurfaceListener : ::wl_listener { MockIndicatorCompositor *parent; }; - NewSurfaceListener mDelSurfaceListener; + DelSurfaceListener mDelSurfaceListener; struct ds_tizen_indicator *mIndicator; struct DestroyListener : ::wl_listener { MockIndicatorCompositor *parent; }; - NewSurfaceListener mDestroyListener; + DestroyListener mDestroyListener; struct ChangeStateListener : ::wl_listener { MockIndicatorCompositor *parent; }; - NewSurfaceListener mChangeStateListener; + ChangeStateListener mChangeStateListener; struct ChangeOpacityModeListener : ::wl_listener { MockIndicatorCompositor *parent; }; - NewSurfaceListener mChangeOpacityModeListener; + ChangeOpacityModeListener mChangeOpacityModeListener; struct ChangeVisibleTypeListener : ::wl_listener { MockIndicatorCompositor *parent; }; - NewSurfaceListener mChangeVisibleTypeListener; + ChangeVisibleTypeListener mChangeVisibleTypeListener; }; class MockIndicatorClient : public MockClient -- 2.7.4 From 6413a0a4cdd781569f759eaf5f3c8ab6b586d81c Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Thu, 21 Jul 2022 08:30:20 +0900 Subject: [PATCH 08/16] indicator: create and bind global resource with version info Change-Id: Iaa20162c9a2d6a918e72e5071f7f7d809902f33e --- src/indicator/indicator.c | 2 +- tests/tc_indicator.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/indicator/indicator.c b/src/indicator/indicator.c index 23f0e9f..b08dae5 100644 --- a/src/indicator/indicator.c +++ b/src/indicator/indicator.c @@ -83,7 +83,7 @@ ds_tizen_indicator_create(struct wl_display *display) } indicator->global = wl_global_create(display, &tizen_indicator_interface, - 1, indicator, indicator_bind); + TIZEN_INDICATOR_VERSION, indicator, indicator_bind); if (!indicator->global) { ds_err("wl_global_create() failed. tizen_indicator_interface"); free(indicator); diff --git a/tests/tc_indicator.cpp b/tests/tc_indicator.cpp index 7585496..837aa3a 100644 --- a/tests/tc_indicator.cpp +++ b/tests/tc_indicator.cpp @@ -4,6 +4,7 @@ #include #include +#define TIZEN_INDICATOR_VERSION 1 class MockIndicatorCompositor : public MockCompositor { public: @@ -331,7 +332,7 @@ client_registry_cb_global(void *data, struct wl_registry *registry, client->SetWlCompositor(compositor_res); } else if (!strcmp(interface, "tizen_indicator")) { tizen_indicator = (struct tizen_indicator *)wl_registry_bind(registry, - name, &tizen_indicator_interface, 1); + name, &tizen_indicator_interface, TIZEN_INDICATOR_VERSION); if (tizen_indicator == nullptr) { ds_err("wl_registry_bind() failed. tizen_indicator resource."); return; -- 2.7.4 From 8c8a08f2a79bbd614f47da139fcd2e31637248e2 Mon Sep 17 00:00:00 2001 From: "duna.oh" Date: Fri, 22 Jul 2022 02:41:29 +0900 Subject: [PATCH 09/16] launch: implement appinfo interface Change-Id: I6afd36726e16ed967bffc6f9b24c772c1740bab8 --- include/libds-tizen/launch/appinfo.h | 42 +++ packaging/libds-tizen.spec | 32 ++ src/launch/appinfo.c | 579 +++++++++++++++++++++++++++++++++++ src/launch/meson.build | 29 ++ src/meson.build | 1 + tests/meson.build | 19 ++ tests/tc_launch_appinfo.cpp | 421 +++++++++++++++++++++++++ 7 files changed, 1123 insertions(+) create mode 100644 include/libds-tizen/launch/appinfo.h create mode 100644 src/launch/appinfo.c create mode 100644 src/launch/meson.build create mode 100644 tests/tc_launch_appinfo.cpp diff --git a/include/libds-tizen/launch/appinfo.h b/include/libds-tizen/launch/appinfo.h new file mode 100644 index 0000000..bd62e9b --- /dev/null +++ b/include/libds-tizen/launch/appinfo.h @@ -0,0 +1,42 @@ +#ifndef LIBDS_TIZEN_APPINFO_H +#define LIBDS_TIZEN_APPINFO_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ds_tizen_appinfo_mgr; +struct ds_tizen_appinfo; + +struct ds_tizen_appinfo_mgr * +ds_tizen_appinfo_mgr_create(struct wl_display *display); + +void +ds_tizen_appinfo_mgr_add_destroy_listener( + struct ds_tizen_appinfo_mgr *appinfo_mgr, struct wl_listener *listener); + +void +ds_tizen_appinfo_mgr_add_set_pid_listener( + struct ds_tizen_appinfo_mgr *appinfo_mgr, struct wl_listener *listener); + +void +ds_tizen_appinfo_mgr_add_set_appid_listener( + struct ds_tizen_appinfo_mgr *appinfo_mgr, struct wl_listener *listener); + +void +ds_tizen_appinfo_mgr_add_metadata_ready_listener( + struct ds_tizen_appinfo_mgr *appinfo_mgr, struct wl_listener *listener); + +//for gtest +struct wl_resource * +ds_tizen_appinfo_mgr_get_appinfo_resource( + struct ds_tizen_appinfo_mgr *appinfo_mgr); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packaging/libds-tizen.spec b/packaging/libds-tizen.spec index 16e6ce7..27af91c 100644 --- a/packaging/libds-tizen.spec +++ b/packaging/libds-tizen.spec @@ -14,6 +14,8 @@ BuildRequires: pkgconfig(wayland-client) BuildRequires: pkgconfig(wayland-protocols) BuildRequires: pkgconfig(tizen-extension-server) BuildRequires: pkgconfig(tizen-extension-client) +BuildRequires: pkgconfig(tizen-launch-server) +BuildRequires: pkgconfig(tizen-launch-client) BuildRequires: pkgconfig(pixman-1) BuildRequires: pkgconfig(libdrm) BuildRequires: pkgconfig(xkbcommon) @@ -152,6 +154,21 @@ Group: Development/Libraries %description clipboard-devel Development package for tizen clipboard +## libds-tizen-launch +%package launch +Summary: Library for tizen launch +Group: Development/Libraries + +%description launch +Library for tizen launch + +%package launch-devel +Summary: Development package for tizen launch +Group: Development/Libraries + +%description launch-devel +Development package for tizen launch + %prep %setup -q cp %{SOURCE1001} . @@ -292,3 +309,18 @@ ninja -C builddir install %{_libdir}/pkgconfig/libds-tizen-clipboard.pc %{_libdir}/libds-tizen-clipboard.so %{_bindir}/libds-tizen-clipboard-tests + +%files launch +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_libdir}/libds-tizen-launch.so.* + +%files launch-devel +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_includedir}/libds-tizen/launch/appinfo.h +%{_libdir}/pkgconfig/libds-tizen-launch.pc +%{_libdir}/libds-tizen-launch.so +%{_bindir}/libds-tizen-launch-appinfo-tests diff --git a/src/launch/appinfo.c b/src/launch/appinfo.c new file mode 100644 index 0000000..0b6c8c2 --- /dev/null +++ b/src/launch/appinfo.c @@ -0,0 +1,579 @@ +#include +#include +#include +#include + +#include "util.h" +#include + +#define TIZEN_APPINFO_VERSION 1 + +struct ds_tizen_appinfo_mgr +{ + struct wl_global *global; + + struct wl_list clients; + struct wl_list infos; + + struct wl_listener destroy; + + struct { + struct wl_signal destroy; + struct wl_signal set_pid; + struct wl_signal set_appid; + struct wl_signal metadata_ready; + } events; + + struct wl_resource *resource; //for gtest +}; + +struct ds_tizen_appinfo_client +{ + struct ds_tizen_appinfo_mgr *appinfo_mgr; + + struct wl_resource *resource; + struct wl_client *wl_client; + + struct wl_list link; // ds_tizen_appinfo_mgr::clients +}; + +enum ds_tizen_appinfo_owner +{ + DS_TIZEN_APPINFO_OWNER_SERVER, + DS_TIZEN_APPINFO_OWNER_CLIENT, +}; + +struct ds_tizen_appinfo +{ + struct ds_tizen_appinfo_mgr *appinfo_mgr; + + pid_t pid; + char *appid; + bool base_output_available; + int base_output_width; + int base_output_height; + enum ds_tizen_appinfo_owner owner; + + struct wl_list link; //ds_tizen_appinfo_mgr::infos; +}; + +static void appinfo_mgr_handle_display_destroy(struct wl_listener *listener, + void *data); + +static void appinfo_mgr_bind(struct wl_client *wl_client, void *data, + uint32_t version, uint32_t id); + +WL_EXPORT struct ds_tizen_appinfo_mgr * +ds_tizen_appinfo_mgr_create(struct wl_display *display) +{ + struct ds_tizen_appinfo_mgr *appinfo_mgr; + + appinfo_mgr = calloc(1, sizeof *appinfo_mgr); + if (!appinfo_mgr) { + ds_err("calloc() failed."); + return NULL; + } + + appinfo_mgr->global = wl_global_create(display, &tizen_launch_appinfo_interface, + TIZEN_APPINFO_VERSION, appinfo_mgr, appinfo_mgr_bind); + if (!appinfo_mgr->global) { + ds_err("wl_global_create() failed. tizen_launch_appinfo_interface"); + free(appinfo_mgr); + return NULL; + } + + wl_list_init(&appinfo_mgr->clients); + wl_list_init(&appinfo_mgr->infos); + + appinfo_mgr->destroy.notify = appinfo_mgr_handle_display_destroy; + wl_display_add_destroy_listener(display, &appinfo_mgr->destroy); + + wl_signal_init(&appinfo_mgr->events.destroy); + wl_signal_init(&appinfo_mgr->events.set_pid); + wl_signal_init(&appinfo_mgr->events.set_appid); + wl_signal_init(&appinfo_mgr->events.metadata_ready); + + ds_inf("Global create: tizen_launch_appinfo. appinfo_mgr(%p)", appinfo_mgr); + + return appinfo_mgr; +} + +WL_EXPORT void +ds_tizen_appinfo_mgr_add_destroy_listener( + struct ds_tizen_appinfo_mgr *appinfo_mgr, struct wl_listener *listener) +{ + wl_signal_add(&appinfo_mgr->events.destroy, listener); +} + +WL_EXPORT void +ds_tizen_appinfo_mgr_add_set_pid_listener( + struct ds_tizen_appinfo_mgr *appinfo_mgr, struct wl_listener *listener) +{ + wl_signal_add(&appinfo_mgr->events.set_pid, listener); +} + +WL_EXPORT void +ds_tizen_appinfo_mgr_add_set_appid_listener( + struct ds_tizen_appinfo_mgr *appinfo_mgr, struct wl_listener *listener) +{ + wl_signal_add(&appinfo_mgr->events.set_appid, listener); +} + +WL_EXPORT void +ds_tizen_appinfo_mgr_add_metadata_ready_listener( + struct ds_tizen_appinfo_mgr *appinfo_mgr, struct wl_listener *listener) +{ + wl_signal_add(&appinfo_mgr->events.metadata_ready, listener); +} + +static void +appinfo_mgr_handle_display_destroy(struct wl_listener *listener, void *data) +{ + struct ds_tizen_appinfo_mgr *appinfo_mgr; + struct ds_tizen_appinfo_client *client, *tmp_client; + struct ds_tizen_appinfo *info, *tmp_info; + + appinfo_mgr = wl_container_of(listener, appinfo_mgr, destroy); + + ds_inf("Global destroy: appinfo_mgr(%p)", appinfo_mgr); + + wl_signal_emit(&appinfo_mgr->events.destroy, appinfo_mgr); + wl_list_remove(&appinfo_mgr->destroy.link); + + wl_list_for_each_safe(client, tmp_client, &appinfo_mgr->clients, link) { + wl_list_remove(&client->link); + free(client); + } + + wl_list_for_each_safe(info, tmp_info, &appinfo_mgr->infos, link) { + wl_list_remove(&info->link); + free(info->appid); + free(info); + } + + wl_global_destroy(appinfo_mgr->global); + free(appinfo_mgr); +} + +static void +appinfo_handle_destroy(struct wl_client *wl_client, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static struct ds_tizen_appinfo * +appinfo_mgr_find_with_pid(struct ds_tizen_appinfo_mgr *appinfo_mgr, + pid_t pid) +{ + struct ds_tizen_appinfo *info; + + wl_list_for_each(info, &appinfo_mgr->infos, link) { + if (pid == info->pid) + return info; + } + + return NULL; +} + +static struct ds_tizen_appinfo * +appinfo_mgr_find_with_appid(struct ds_tizen_appinfo_mgr *appinfo_mgr, + const char *appid) +{ + struct ds_tizen_appinfo *info; + + wl_list_for_each(info, &appinfo_mgr->infos, link) { + if (appid && !strcmp(appid, info->appid)) + return info; + } + + return NULL; +} +static struct ds_tizen_appinfo * +appinfo_mgr_get_info(struct ds_tizen_appinfo_mgr *appinfo_mgr, + pid_t pid, const char *appid) +{ + struct ds_tizen_appinfo *info = NULL; + + if (pid > 0) + info = appinfo_mgr_find_with_pid(appinfo_mgr, pid); + else if (appid) + info = appinfo_mgr_find_with_appid(appinfo_mgr, appid); + + if (info) { + return info; + } + + info = calloc(1, sizeof *info); + if (info == NULL) { + ds_err("calloc() failed. tizen_appinfo"); + return NULL; + } + + if (pid > 0) + info->pid = pid; + else if (appid) + info->appid = strdup(appid); + + info->appinfo_mgr = appinfo_mgr; + + wl_list_insert(&appinfo_mgr->infos, &info->link); + + return info; +} + +static void +appinfo_destroy(struct ds_tizen_appinfo *info) +{ + wl_list_remove(&info->link); + free(info->appid); + free(info); +} + +static bool +appinfo_set_pid(struct ds_tizen_appinfo *info, pid_t pid) +{ + struct ds_tizen_appinfo_mgr *appinfo_mgr; + struct ds_tizen_appinfo *info2, *tmp; + + if (!info) return false; + if (pid < 0) return false; + + appinfo_mgr = info->appinfo_mgr; + + wl_list_for_each_safe(info2, tmp, &appinfo_mgr->infos, link) { + if ((info2->pid == pid) && (info2 != info)) { + ds_inf("removed duplicated appinfo"); + + if (!info->appid) info->appid = strdup(info2->appid); + if (!info->base_output_available && info2->base_output_available) { + ds_inf("copy base_output variable into appinfo."); + info->base_output_available = true; + info->base_output_width = info2->base_output_width; + info->base_output_height = info2->base_output_height; + } + appinfo_destroy(info2); + } + } + + info->pid = pid; + ds_inf("appinfo(%p) set pid(%u)", info, pid); + + wl_signal_emit(&appinfo_mgr->events.set_pid, info); + + return true; +} + +static bool +appinfo_set_appid(struct ds_tizen_appinfo *info, const char *appid) +{ + struct ds_tizen_appinfo_mgr *appinfo_mgr; + struct ds_tizen_appinfo *info2, *tmp; + + if (!info) return false; + if (!appid) return false; + + appinfo_mgr = info->appinfo_mgr; + + wl_list_for_each_safe(info2, tmp, &appinfo_mgr->infos, link) { + if ((info2->appid && !strcmp(info2->appid, appid)) && + (info2 != info)) { + ds_inf("removed duplicated appinfo"); + + if (info->pid < 0) info->pid = info2->pid; + if (!info->base_output_available && info2->base_output_available) + { + ds_inf("copy base_output variable into appinfo."); + info->base_output_available = true; + info->base_output_width = info2->base_output_width; + info->base_output_height = info2->base_output_height; + } + appinfo_destroy(info2); + } + } + + free(info->appid); + info->appid = strdup(appid); + ds_inf("appinfo(%p) set appid(%u)", info, appid); + + wl_signal_emit(&appinfo_mgr->events.set_appid, info); + + return true; +} + +static bool +appinfo_get_base_output_resolution(struct ds_tizen_appinfo *info, int *width, int *height) +{ + if (!info) return false; + if (!width) return false; + if (!height) return false; + + if (!info->base_output_available) { + *width = 0; + *height = 0; + return false; + } + *width = info->base_output_width; + *height = info->base_output_height; + + return true; +} + +static void +appinfo_set_owner(struct ds_tizen_appinfo *info, enum ds_tizen_appinfo_owner owner) +{ + if (!info) return; + + info->owner = owner; +} + +static void +appinfo_handle_register_pid(struct wl_client *wl_client, + struct wl_resource *resource, uint32_t pid) +{ + struct ds_tizen_appinfo_client *client; + struct ds_tizen_appinfo *info; + + client = wl_resource_get_user_data(resource); + + if (pid <= 0) { + ds_err("tizen_appinfo: pid is invalid. pid:%u", pid); + return; + } + + info = appinfo_mgr_get_info(client->appinfo_mgr, pid, NULL); + if (info == NULL) { + ds_err("appinfo_mgr_get_info() failed. tizen_appinfo"); + wl_client_post_no_memory(wl_client); + return; + } + + appinfo_set_pid(info, pid); + appinfo_set_owner(info, DS_TIZEN_APPINFO_OWNER_CLIENT); +} + + +static void +appinfo_handle_deregister_pid(struct wl_client *wl_client, + struct wl_resource *resource, uint32_t pid) +{ + struct ds_tizen_appinfo_client *client; + struct ds_tizen_appinfo *info; + + client = wl_resource_get_user_data(resource); + + info = appinfo_mgr_find_with_pid(client->appinfo_mgr, pid); + if (info == NULL) { + ds_err("tizen_appinfo: no appinfo found by pid(%u)", pid); + return; + } + + appinfo_destroy(info); +} + +static void +appinfo_handle_set_appid(struct wl_client *wl_client, + struct wl_resource *resource, uint32_t pid, const char *appid) +{ + struct ds_tizen_appinfo_client *client; + struct ds_tizen_appinfo *info; + + client = wl_resource_get_user_data(resource); + + if (pid <= 0) { + ds_err("tizen_appinfo: pid is invalid. pid:%u", pid); + return; + } + + info = appinfo_mgr_find_with_pid(client->appinfo_mgr, pid); + if (info == NULL) { + ds_err("tizen_appinfo: no appinfo found by pid(%u)", pid); + return; + } + + appinfo_set_appid(info, appid); + + /* TODO: base output resolution */ +} + +//for gtest +WL_EXPORT struct wl_resource * +ds_tizen_appinfo_mgr_get_appinfo_resource( + struct ds_tizen_appinfo_mgr *appinfo_mgr) +{ + return appinfo_mgr->resource; +} + +static void +appinfo_handle_get_base_output_resolution(struct wl_client *wl_client, + struct wl_resource *resource, uint32_t pid) +{ + struct ds_tizen_appinfo_client *client; + struct ds_tizen_appinfo *info; + int width = 0, height = 0; + + client = wl_resource_get_user_data(resource); + + if (pid <= 0) { + ds_err("tizen_appinfo: pid is invalid. pid:%u", pid); + goto finish; + } + + info = appinfo_mgr_find_with_pid(client->appinfo_mgr, pid); + if (info == NULL) { + ds_err("tizen_appinfo: no appinfo found by pid(%u)", pid); + goto finish; + } + + appinfo_get_base_output_resolution(info, &width, &height); + + client->appinfo_mgr->resource = resource; + +finish: + if (width == 0 && height == 0) { + width = 1080; //e_config->configured_output_resolution.w; + height = 1920; //e_config->configured_output_resolution.h; + } + + ds_inf("send base_output_resolution. size(%d x %d). pid(%u)", width, height, pid); + tizen_launch_appinfo_send_base_output_resolution_done(resource, pid, width, height); +} + +static void +appinfo_handle_register_appid(struct wl_client *wl_client, struct wl_resource *resource, + const char *appid) +{ + struct ds_tizen_appinfo_client *client; + struct ds_tizen_appinfo *info; + + client = wl_resource_get_user_data(resource); + + info = appinfo_mgr_get_info(client->appinfo_mgr, -1, appid); + if (info == NULL) { + ds_err("appinfo_mgr_get_info() failed. tizen_appinfo"); + wl_client_post_no_memory(wl_client); + return; + } + + appinfo_set_appid(info, appid); + appinfo_set_owner(info, DS_TIZEN_APPINFO_OWNER_CLIENT); +} + +static void +appinfo_handle_deregister_appid(struct wl_client *wl_client, + struct wl_resource *resource, const char *appid) +{ + struct ds_tizen_appinfo_client *client; + struct ds_tizen_appinfo *info; + + client = wl_resource_get_user_data(resource); + + info = appinfo_mgr_find_with_appid(client->appinfo_mgr, appid); + if (info == NULL) { + ds_err("tizen_appinfo: no appinfo found by appid(%u)", appid); + return; + } + + appinfo_destroy(info); +} + +static void +appinfo_handle_set_pid(struct wl_client *wl_client, + struct wl_resource *resource, const char *appid, uint32_t pid) +{ + struct ds_tizen_appinfo_client *client; + struct ds_tizen_appinfo *info; + + client = wl_resource_get_user_data(resource); + + info = appinfo_mgr_find_with_appid(client->appinfo_mgr, appid); + if (info == NULL) { + ds_err("tizen_appinfo: no appinfo found by appid(%u)", appid); + return; + } + + appinfo_set_pid(info, pid); +} + +static void +appinfo_handle_ready_metadata(struct wl_client *wl_client, + struct wl_resource *resource, const char *appid, uint32_t pid) +{ + struct ds_tizen_appinfo_client *client; + struct ds_tizen_appinfo *info; + + client = wl_resource_get_user_data(resource); + + info = appinfo_mgr_find_with_appid(client->appinfo_mgr, appid); + if (info == NULL) { + ds_err("tizen_appinfo: no appinfo found by appid(%u)", appid); + return; + } + + if (info->pid != pid) + appinfo_set_pid(info, pid); + + wl_signal_emit(&client->appinfo_mgr->events.metadata_ready, info); + + /* TODO: base output resolution */ +} + +static const struct tizen_launch_appinfo_interface appinfo_impl = +{ + appinfo_handle_destroy, + appinfo_handle_register_pid, + appinfo_handle_deregister_pid, + appinfo_handle_set_appid, + appinfo_handle_get_base_output_resolution, + appinfo_handle_register_appid, + appinfo_handle_deregister_appid, + appinfo_handle_set_pid, + appinfo_handle_ready_metadata, +}; + +static void +_tizen_appinfo_client_handle_destroy(struct wl_resource *resource) +{ + struct ds_tizen_appinfo_client *client; + + client = wl_resource_get_user_data(resource); + + ds_inf("_tizen_appinfo_client_handle_destroy (client:%p)", client); + + wl_list_remove(&client->link); + free(client); +} + +static void appinfo_mgr_bind(struct wl_client *wl_client, void *data, + uint32_t version, uint32_t id) +{ + struct ds_tizen_appinfo_mgr *appinfo_mgr = data; + struct ds_tizen_appinfo_client *client; + + client = calloc(1, sizeof *client); + if (client == NULL) { + ds_err("calloc() failed. tizen_appinfo"); + wl_client_post_no_memory(wl_client); + return; + } + + ds_inf("tizen_appinfo_client_binds. (client:%p)", client); + + client->appinfo_mgr = appinfo_mgr; + client->wl_client = wl_client; + + client->resource = wl_resource_create(wl_client, + &tizen_launch_appinfo_interface, + MIN(version, TIZEN_APPINFO_VERSION), id); + + if (client->resource == NULL) { + ds_err("tizen_appinfo : wl_resource_create() failed."); + free(client); + wl_client_post_no_memory(wl_client); + return; + } + + wl_resource_set_implementation(client->resource, &appinfo_impl, client, + _tizen_appinfo_client_handle_destroy); + + wl_list_insert(&appinfo_mgr->clients, &client->link); +} diff --git a/src/launch/meson.build b/src/launch/meson.build new file mode 100644 index 0000000..b3e2efd --- /dev/null +++ b/src/launch/meson.build @@ -0,0 +1,29 @@ +libds_tizen_launch_files = [ + 'appinfo.c', +] + +libds_tizen_launch_deps = [ + deps_libds_tizen, + dependency('tizen-launch-server', required: true), +] + +lib_libds_tizen_launch = shared_library('ds-tizen-launch', libds_tizen_launch_files, + dependencies: libds_tizen_launch_deps, + include_directories: [ common_inc, include_directories('.'), include_directories('..') ], + version: meson.project_version(), + install: true +) + +deps_libds_tizen_launch = declare_dependency( + link_with: lib_libds_tizen_launch, + dependencies: libds_tizen_launch_deps, + include_directories: [ common_inc, include_directories('.') ], +) + +pkgconfig = import('pkgconfig') +pkgconfig.generate(lib_libds_tizen_launch, + version: meson.project_version(), + filebase: 'libds-tizen-launch', + name: 'libds-tizen-launch', + description: 'tizen launch extension of libds-tizen for tizen platform', +) diff --git a/src/meson.build b/src/meson.build index 73c169c..3ea00d7 100644 --- a/src/meson.build +++ b/src/meson.build @@ -35,3 +35,4 @@ subdir('input_devicemgr') subdir('dpms') subdir('indicator') subdir('clipboard') +subdir('launch') diff --git a/tests/meson.build b/tests/meson.build index eb8d221..4b4686d 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -65,3 +65,22 @@ executable('libds-tizen-clipboard-tests', install_dir: libds_tizen_bindir, install : true ) + +## appinfo tests +tc_launch_appinfo_files = [ + 'tc_main.cpp', + 'tc_launch_appinfo.cpp', +] + +executable('libds-tizen-launch-appinfo-tests', + [ + tc_mock_files, + tc_launch_appinfo_files + ], + dependencies: [ + deps_test_common, + deps_libds_tizen_launch, + ], + install_dir: libds_tizen_bindir, + install : true +) diff --git a/tests/tc_launch_appinfo.cpp b/tests/tc_launch_appinfo.cpp new file mode 100644 index 0000000..9e7bab1 --- /dev/null +++ b/tests/tc_launch_appinfo.cpp @@ -0,0 +1,421 @@ +#include "tc_main.h" +#include "mockclient.h" +#include "mockcompositor.h" +#include +#include +#include + +#define TIZEN_APPINFO_VERSION 1 + +class MockAppinfoCompositor : public MockCompositor +{ +public: + MockAppinfoCompositor() + : MockCompositor(&MockAppinfoCompositor::TestSetup, this) + { + ds_inf("%s : this(%p)", __func__, this); + + // initialize the flags to check + bDestroyed = false; + + bSetPid = false; + bSetAppid = false; + bMetadataReady = false; + } + + ~MockAppinfoCompositor() + { + ds_inf("%s : this(%p)", __func__, this); + } + + static void TestSetup(void *data) + { + MockAppinfoCompositor *mockComp = + static_cast(data); + Compositor *comp = mockComp->compositor; + + ds_inf("%s: mockComp(%p)", __func__, mockComp); + + mockComp->mAppinfoMgr = ds_tizen_appinfo_mgr_create(comp->display); + + // destroy listener + mockComp->mDestroyListener.notify = + MockAppinfoCompositor::DestroyCallback; + mockComp->mDestroyListener.parent = mockComp; + ds_tizen_appinfo_mgr_add_destroy_listener(mockComp->mAppinfoMgr, + &mockComp->mDestroyListener); + + // set_pid listener + mockComp->mSetPidListener.notify = + MockAppinfoCompositor::SetPidCallback; + mockComp->mSetPidListener.parent = mockComp; + ds_tizen_appinfo_mgr_add_set_pid_listener(mockComp->mAppinfoMgr, + &mockComp->mSetPidListener); + + // set_appid listener + mockComp->mSetAppidListener.notify = + MockAppinfoCompositor::SetAppidCallback; + mockComp->mSetAppidListener.parent = mockComp; + ds_tizen_appinfo_mgr_add_set_appid_listener(mockComp->mAppinfoMgr, + &mockComp->mSetAppidListener); + + // metadata_ready listener + mockComp->mMetadataReadyListener.notify = + MockAppinfoCompositor::MetadataReadyCallback; + mockComp->mMetadataReadyListener.parent = mockComp; + ds_tizen_appinfo_mgr_add_metadata_ready_listener( + mockComp->mAppinfoMgr, + &mockComp->mMetadataReadyListener); + } + + static void DestroyCallback(struct wl_listener *listener, void *data) + { + ds_inf("%s", __func__); + + MockAppinfoCompositor *mockComp = + reinterpret_cast(listener)->parent; + + mockComp->bDestroyed = true; + } + + static void SetPidCallback(struct wl_listener *listener, void *data) + { + ds_inf("%s", __func__); + + MockAppinfoCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_tizen_appinfo *info = static_cast(data); + + ds_inf("%s: mockComp(%p), appinfo(%p)", __func__, mockComp, info); + + mockComp->bSetPid = true; + } + + static void SetAppidCallback(struct wl_listener *listener, void *data) + { + ds_inf("%s", __func__); + + MockAppinfoCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_tizen_appinfo *info = static_cast(data); + + ds_inf("%s: mockComp(%p), appinfo(%p)", __func__, mockComp, info); + + mockComp->bSetAppid = true; + } + + + static void MetadataReadyCallback(struct wl_listener *listener, void *data) + { + ds_inf("%s", __func__); + + MockAppinfoCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_tizen_appinfo *info = static_cast(data); + + ds_inf("%s: mockComp(%p), appinfo(%p)", __func__, mockComp, info); + + mockComp->bMetadataReady = true; + } + + void SendBaseOutputResolutionDone(uint32_t pid, uint32_t width, uint32_t height) + { + ds_inf("%s", __func__); + + wl_resource *res_appinfo = ds_tizen_appinfo_mgr_get_appinfo_resource(mAppinfoMgr); + + tizen_launch_appinfo_send_base_output_resolution_done(res_appinfo, pid, width, height); + } + +public: + bool bDestroyed; + bool bSetPid; + bool bSetAppid; + bool bMetadataReady; + +private: + struct ds_tizen_appinfo_mgr *mAppinfoMgr; + struct DestroyListener: ::wl_listener { + MockAppinfoCompositor *parent; + }; + DestroyListener mDestroyListener; + struct SetPidListener: ::wl_listener { + MockAppinfoCompositor *parent; + }; + SetPidListener mSetPidListener; + struct SetAppidListener: ::wl_listener { + MockAppinfoCompositor *parent; + }; + SetAppidListener mSetAppidListener; + struct MetadataReadyListener: ::wl_listener { + MockAppinfoCompositor *parent; + }; + MetadataReadyListener mMetadataReadyListener; +}; + +class MockAppinfoClient : public MockClient +{ +public: + MockAppinfoClient() + : bBaseOutputResolutionDone(false), + mBaseOutputResolutionWidth(0), + mBaseOutputResolutionHeight(0), + compositor_res(nullptr), + tizen_launch_appinfo(nullptr) + {} + MockAppinfoClient(const struct wl_registry_listener *listener) + : MockClient(listener, this) + { + ds_inf("%s", __func__); + + bBaseOutputResolutionDone = false; + mBaseOutputResolutionWidth = 0; + mBaseOutputResolutionHeight = 0; + } + ~MockAppinfoClient() + { + ds_inf("%s", __func__); + } + + void SetWlCompositor(struct wl_compositor *global_res) + { + ds_inf("%s", __func__); + + compositor_res = global_res; + } + + struct wl_compositor *GetWlCompositor() + { + ds_inf("%s", __func__); + + return compositor_res; + } + + void SetTizenAppinfo(struct tizen_launch_appinfo *global_res) + { + ds_inf("%s", __func__); + tizen_launch_appinfo = global_res; + } + + struct tizen_launch_appinfo *GetTizenAppinfo() + { + ds_inf("%s", __func__); + + return tizen_launch_appinfo; + } + +public: + bool bBaseOutputResolutionDone; + uint32_t mBaseOutputResolutionWidth; + uint32_t mBaseOutputResolutionHeight; + +private: + struct wl_compositor *compositor_res; + struct tizen_launch_appinfo *tizen_launch_appinfo; +}; + +static void +client_tizen_appinfo_cb_base_output_resolution_done(void *data, + struct tizen_launch_appinfo *appinfo, uint32_t pid, + uint32_t width, uint32_t height) +{ + ds_inf("%s", __func__); + + MockAppinfoClient *client = static_cast(data); + + client->bBaseOutputResolutionDone = true; + client->mBaseOutputResolutionWidth = width; + client->mBaseOutputResolutionHeight = height; +} + +static const struct tizen_launch_appinfo_listener appinfo_cb_listener = { + .base_output_resolution_done = client_tizen_appinfo_cb_base_output_resolution_done, +}; + +static void +client_registry_cb_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) +{ + ds_inf("%s", __func__); + + MockAppinfoClient *client = static_cast(data); + struct wl_compositor *compositor_res; + struct tizen_launch_appinfo *tizen_launch_appinfo; + + if (!strcmp(interface, "wl_compositor")) { + compositor_res = (struct wl_compositor *)wl_registry_bind(registry, + name, &wl_compositor_interface, 1); + if (compositor_res == nullptr) { + ds_err("wl_registry_bind() failed. wl_compositor resource."); + return; + } + client->SetWlCompositor(compositor_res); + } else if (!strcmp(interface, "tizen_launch_appinfo")) { + tizen_launch_appinfo = (struct tizen_launch_appinfo *)wl_registry_bind(registry, + name, &tizen_launch_appinfo_interface, TIZEN_APPINFO_VERSION); + if (tizen_launch_appinfo == nullptr) { + ds_err("wl_registry_bind() failed. tizen_launch_appinfo resource."); + return; + } + client->SetTizenAppinfo(tizen_launch_appinfo); + + tizen_launch_appinfo_add_listener(tizen_launch_appinfo, &appinfo_cb_listener, + client); + } +} + +static void +client_registry_cb_global_remove(void *data, struct wl_registry *registry, + uint32_t name) +{ + ds_inf("%s", __func__); + + MockAppinfoClient *client = static_cast(data); + struct wl_compositor *compositor_res = client->GetWlCompositor(); + struct tizen_launch_appinfo *appinfo_res = client->GetTizenAppinfo(); + + tizen_launch_appinfo_destroy(appinfo_res); + wl_compositor_destroy(compositor_res); +} + +static const struct wl_registry_listener registry_listener = { + .global = client_registry_cb_global, + .global_remove = client_registry_cb_global_remove +}; + +class AppinfoTest : public ::testing::Test +{ +public: + void SetUp(void) override; + void TearDown(void) override; + + MockAppinfoCompositor *comp; + MockAppinfoClient *client; + struct wl_compositor *compositor_res; + struct tizen_launch_appinfo *appinfo_res; +}; + +void +AppinfoTest::SetUp(void) +{ + ds_inf("%s", __func__); + + comp = new MockAppinfoCompositor(); + client = new MockAppinfoClient(®istry_listener); + compositor_res = client->GetWlCompositor(); + appinfo_res = client->GetTizenAppinfo(); + + client->RoundTrip(); +} + +void +AppinfoTest::TearDown(void) +{ + ds_inf("%s", __func__); + + client->RoundTrip(); + + delete client; + delete comp; +} + +TEST_F(AppinfoTest, Create_P) +{ + EXPECT_TRUE(true); +} + +TEST_F(AppinfoTest, Req_TizenAppinfoRegisterPid) +{ + uint32_t pid = 1234; + + tizen_launch_appinfo_register_pid(appinfo_res, pid); + client->RoundTrip(); + EXPECT_TRUE(comp->bSetPid); +} + +TEST_F(AppinfoTest, Req_TizenAppinfoSetAppid) +{ + uint32_t pid = 1234; + const char *appid = "org.tizen.libds-tizen-appinfo-test"; + + tizen_launch_appinfo_register_pid(appinfo_res, pid); + client->RoundTrip(); + EXPECT_TRUE(comp->bSetPid); + + tizen_launch_appinfo_set_appid(appinfo_res, pid, appid); + client->RoundTrip(); + EXPECT_TRUE(comp->bSetAppid); +} + +TEST_F(AppinfoTest, Req_TizenAppinfoRegisterAppid) +{ + const char *appid = "org.tizen.libds-tizen-appinfo-test"; + + tizen_launch_appinfo_register_appid(appinfo_res, appid); + client->RoundTrip(); + EXPECT_TRUE(comp->bSetAppid); +} + +TEST_F(AppinfoTest, Req_TizenAppinfoSetPid) +{ + uint32_t pid = 1234; + const char *appid = "org.tizen.libds-tizen-appinfo-test"; + + tizen_launch_appinfo_register_appid(appinfo_res, appid); + client->RoundTrip(); + EXPECT_TRUE(comp->bSetAppid); + + tizen_launch_appinfo_set_pid(appinfo_res, appid, pid); + client->RoundTrip(); + EXPECT_TRUE(comp->bSetPid); +} + +TEST_F(AppinfoTest, Req_TizenAppinfoMetadataReady) +{ + const char *appid = "org.tizen.libds-tizen-appinfo-test"; + uint32_t pid = 1234; + + tizen_launch_appinfo_register_appid(appinfo_res, appid); + client->RoundTrip(); + EXPECT_TRUE(comp->bSetAppid); + + tizen_launch_appinfo_ready_metadata(appinfo_res, appid, pid); + client->RoundTrip(); + EXPECT_TRUE(comp->bMetadataReady); +} + +TEST_F(AppinfoTest, Req_TizenAppinfoGetBaseOutputResolution) +{ + uint32_t pid = 1234; + + tizen_launch_appinfo_register_pid(appinfo_res, pid); + client->RoundTrip(); + EXPECT_TRUE(comp->bSetPid); + + tizen_launch_appinfo_get_base_output_resolution(appinfo_res, pid); + client->RoundTrip(); + + EXPECT_TRUE(client->bBaseOutputResolutionDone); + EXPECT_TRUE(client->mBaseOutputResolutionWidth == 1080); //default value + EXPECT_TRUE(client->mBaseOutputResolutionHeight == 1920); // default value +} + +TEST_F(AppinfoTest, Ev_TizenAppinfoBaseOutputResolutionDone) +{ + uint32_t pid = 1234, width = 1920, height = 1080; + + tizen_launch_appinfo_register_pid(appinfo_res, pid); + client->RoundTrip(); + EXPECT_TRUE(comp->bSetPid); + + tizen_launch_appinfo_get_base_output_resolution(appinfo_res, pid); + client->RoundTrip(); + + comp->SendBaseOutputResolutionDone(pid, width, height); + comp->Process(); + + client->RoundTrip(); + EXPECT_TRUE(client->bBaseOutputResolutionDone); + EXPECT_TRUE(client->mBaseOutputResolutionWidth == 1920); + EXPECT_TRUE(client->mBaseOutputResolutionHeight == 1080); +} -- 2.7.4 From adc35911d3d6860040e10c52e9d9616f1f1ba9b6 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Thu, 21 Jul 2022 13:54:34 +0900 Subject: [PATCH 10/16] impelement libds-tizen-display-policy This is the server implementation for tizen_display_policy protocol. Change-Id: Idfa58ce16a1e6183cd3f44b5ac31d5a94e78233c --- include/libds-tizen/display_policy.h | 56 +++++++ packaging/libds-tizen.spec | 30 ++++ src/display_policy/display_policy.c | 305 +++++++++++++++++++++++++++++++++++ src/display_policy/meson.build | 29 ++++ src/meson.build | 1 + 5 files changed, 421 insertions(+) create mode 100644 include/libds-tizen/display_policy.h create mode 100644 src/display_policy/display_policy.c create mode 100644 src/display_policy/meson.build diff --git a/include/libds-tizen/display_policy.h b/include/libds-tizen/display_policy.h new file mode 100644 index 0000000..e0ee118 --- /dev/null +++ b/include/libds-tizen/display_policy.h @@ -0,0 +1,56 @@ +#ifndef LIBDS_TIZEN_DISPLAY_POLICY_H +#define LIBDS_TIZEN_DISPLAY_POLICY_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ds_tizen_display_policy; +struct ds_tizen_display_policy_info; + +enum ds_tizen_display_policy_error_state +{ + DS_TIZEN_DISPLAY_POLICY_ERROR_STATE_NONE, + DS_TIZEN_DISPLAY_POLICY_ERROR_STATE_PERMISSION_DENIED, +}; + +struct ds_tizen_display_policy * +ds_tizen_display_policy_create(struct wl_display *display); + +void +ds_tizen_display_policy_add_destroy_listener( + struct ds_tizen_display_policy *display_policy, + struct wl_listener *listener); + +void +ds_tizen_display_policy_add_set_brightness_info_listener( + struct ds_tizen_display_policy *display_policy, + struct wl_listener *listener); + +void +ds_tizen_display_policy_info_add_destroy_listener( + struct ds_tizen_display_policy_info *info, + struct wl_listener *listener); + +struct ds_surface * +ds_tizen_display_policy_info_get_surface( + struct ds_tizen_display_policy_info *info); + +int32_t +ds_tizen_display_policy_info_get_brightness_value( + struct ds_tizen_display_policy_info *info); + +void +ds_tizen_display_policy_info_send_brightness_done( + struct ds_tizen_display_policy_info *info, + enum ds_tizen_display_policy_error_state error_state); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packaging/libds-tizen.spec b/packaging/libds-tizen.spec index 27af91c..372f0c3 100644 --- a/packaging/libds-tizen.spec +++ b/packaging/libds-tizen.spec @@ -169,6 +169,21 @@ Group: Development/Libraries %description launch-devel Development package for tizen launch +## libds-tizen-display-policy +%package display-policy +Summary: Library for tizen display-policy +Group: Development/Libraries + +%description display-policy +Library for tizen display-policy + +%package display-policy-devel +Summary: Development package for tizen display-policy +Group: Development/Libraries + +%description display-policy-devel +Development package for tizen display-policy + %prep %setup -q cp %{SOURCE1001} . @@ -310,6 +325,7 @@ ninja -C builddir install %{_libdir}/libds-tizen-clipboard.so %{_bindir}/libds-tizen-clipboard-tests +<<<<<<< HEAD %files launch %manifest %{name}.manifest %defattr(-,root,root,-) @@ -324,3 +340,17 @@ ninja -C builddir install %{_libdir}/pkgconfig/libds-tizen-launch.pc %{_libdir}/libds-tizen-launch.so %{_bindir}/libds-tizen-launch-appinfo-tests + +%files display-policy +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_libdir}/libds-tizen-display-policy.so.* + +%files display-policy-devel +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_includedir}/libds-tizen/display_policy.h +%{_libdir}/pkgconfig/libds-tizen-display-policy.pc +%{_libdir}/libds-tizen-display-policy.so diff --git a/src/display_policy/display_policy.c b/src/display_policy/display_policy.c new file mode 100644 index 0000000..e278888 --- /dev/null +++ b/src/display_policy/display_policy.c @@ -0,0 +1,305 @@ +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "libds-tizen/display_policy.h" + +#define TIZEN_DISPLAY_POLICY_VERSION 1 + +struct ds_tizen_display_policy +{ + struct wl_global *global; + + struct wl_list clients; + + struct wl_listener destroy; + + struct { + struct wl_signal destroy; + struct wl_signal set_brightness; + } events; +}; + +struct ds_tizen_display_policy_client +{ + struct ds_tizen_display_policy *display_policy; + + struct wl_resource *resource; + struct wl_client *wl_client; + + struct wl_list infos; + + struct { + struct wl_signal destroy; + } events; + + struct wl_list link; // ds_tizen_display_policy::clients +}; + +struct ds_tizen_display_policy_info +{ + struct ds_tizen_display_policy_client *client; + + struct ds_surface *surface; + + int32_t brightness_value; + + struct wl_list link; // ds_tizen_display_policy_client::infos +}; + +static void display_policy_handle_display_destroy(struct wl_listener *listener, + void *data); + +static void display_policy_bind(struct wl_client *wl_client, void *data, + uint32_t version, uint32_t id); + +static struct ds_tizen_display_policy_info *tizen_display_policy_client_find_info( + struct ds_tizen_display_policy_client *client, + struct ds_surface *surface); + +static struct ds_tizen_display_policy_info *tizen_display_policy_client_get_info( + struct ds_tizen_display_policy_client *client, + struct ds_surface *surface); + +WL_EXPORT struct ds_tizen_display_policy * +ds_tizen_display_policy_create(struct wl_display *display) +{ + struct ds_tizen_display_policy *display_policy; + + display_policy = calloc(1, sizeof *display_policy); + if (!display_policy) { + ds_err("calloc() failed."); + return NULL; + } + + display_policy->global = wl_global_create(display, &tizen_display_policy_interface, + TIZEN_DISPLAY_POLICY_VERSION, display_policy, display_policy_bind); + if (!display_policy->global) { + ds_err("wl_global_create() failed. tizen_display_policy_interface"); + free(display_policy); + return NULL; + } + + wl_list_init(&display_policy->clients); + + display_policy->destroy.notify = display_policy_handle_display_destroy; + wl_display_add_destroy_listener(display, &display_policy->destroy); + + wl_signal_init(&display_policy->events.destroy); + wl_signal_init(&display_policy->events.set_brightness); + + ds_inf("Global created: tizen_display_policy(%p)", display_policy); + + return display_policy; +} + +WL_EXPORT void +ds_tizen_display_policy_add_destroy_listener(struct ds_tizen_display_policy *display_policy, + struct wl_listener *listener) +{ + wl_signal_add(&display_policy->events.destroy, listener); +} + +WL_EXPORT void +ds_tizen_display_policy_add_set_brightness_info_listener( + struct ds_tizen_display_policy *display_policy, + struct wl_listener *listener) +{ + wl_signal_add(&display_policy->events.set_brightness, listener); +} + +WL_EXPORT void +ds_tizen_display_policy_info_add_destroy_listener( + struct ds_tizen_display_policy_info *info, + struct wl_listener *listener) +{ + wl_signal_add(&info->client->events.destroy, listener); +} + +WL_EXPORT struct ds_surface * +ds_tizen_display_policy_info_get_surface( + struct ds_tizen_display_policy_info *info) +{ + return info->surface; +} + +WL_EXPORT int32_t +ds_tizen_display_policy_info_get_brightness_value( + struct ds_tizen_display_policy_info *info) +{ + return info->brightness_value; +} + +WL_EXPORT void +ds_tizen_display_policy_info_send_brightness_done( + struct ds_tizen_display_policy_info *info, + enum ds_tizen_display_policy_error_state error_state) +{ + tizen_display_policy_send_window_brightness_done(info->client->resource, + ds_surface_get_wl_resource(info->surface), info->brightness_value, + error_state); +} + +static struct ds_tizen_display_policy_info * +tizen_display_policy_client_find_info(struct ds_tizen_display_policy_client *client, + struct ds_surface *surface) +{ + struct ds_tizen_display_policy_info *info; + + wl_list_for_each(info, &client->infos, link) { + if (surface == info->surface) + return info; + } + + return NULL; +} + +static struct ds_tizen_display_policy_info * +tizen_display_policy_client_get_info(struct ds_tizen_display_policy_client *client, + struct ds_surface *surface) +{ + struct ds_tizen_display_policy_info *info; + + info = tizen_display_policy_client_find_info(client, surface); + if (info) + return info; + + info = calloc(1, sizeof *info); + if (info == NULL) { + ds_err("calloc() failed. tizen_display_policy"); + return NULL; + } + + info->client = client; + info->surface = surface; + + wl_list_insert(&client->infos, &info->link); + + return info; +} + +static void +display_policy_handle_display_destroy(struct wl_listener *listener, void *data) +{ + struct ds_tizen_display_policy *display_policy; + + display_policy = wl_container_of(listener, display_policy, destroy); + + ds_inf("Global destroy: display_policy(%p)", display_policy); + + wl_signal_emit(&display_policy->events.destroy, display_policy); + wl_list_remove(&display_policy->destroy.link); + wl_global_destroy(display_policy->global); + free(display_policy); +} + +static void +display_policy_handle_destroy(struct wl_client *wl_client, + struct wl_resource *resource) +{ + struct ds_tizen_display_policy_client *client; + + client = wl_resource_get_user_data(resource); + + if (!wl_list_empty(&client->infos)) { + ds_err("tizen_display_policy was destroyed before children"); + return; + } + + wl_resource_destroy(resource); +} + +static void +display_policy_handle_set_brightness(struct wl_client *wl_client, + struct wl_resource *resource, struct wl_resource *surface_resource, + int32_t brightness_value) +{ + struct ds_tizen_display_policy_client *client; + struct ds_tizen_display_policy_info *info; + struct ds_surface *surface; + + ds_inf("tizen_display_policy: set_brightness"); + + client = wl_resource_get_user_data(resource); + surface = ds_surface_from_resource(surface_resource); + + info = tizen_display_policy_client_get_info(client, surface); + if (info == NULL) { + ds_err("tizen_display_policy_client_get_info() failed. tizen_display_policy"); + wl_client_post_no_memory(wl_client); + return; + } + + info->brightness_value = brightness_value; + + wl_signal_emit(&client->display_policy->events.set_brightness, info); +} + +static const struct tizen_display_policy_interface display_policy_impl = +{ + display_policy_handle_set_brightness, + display_policy_handle_destroy, +}; + +static void +_tizen_display_policy_client_handle_destroy(struct wl_resource *resource) +{ + struct ds_tizen_display_policy_client *client; + struct ds_tizen_display_policy_info *info, *tmp; + + client = wl_resource_get_user_data(resource); + + ds_inf("_tizen_display_policy_client_handle_destroy (client:%p)", client); + + wl_list_for_each_safe(info, tmp, &client->infos, link) { + wl_signal_emit(&client->events.destroy, info); + wl_list_remove(&info->link); + free(info); + } + + wl_list_remove(&client->link); + free(client); +} + +static void +display_policy_bind(struct wl_client *wl_client, void *data, uint32_t version, + uint32_t id) +{ + struct ds_tizen_display_policy *display_policy = data; + struct ds_tizen_display_policy_client *client; + + client = calloc(1, sizeof *client); + if (client == NULL) { + ds_err("calloc() failed. tizen_display_policy"); + wl_client_post_no_memory(wl_client); + return; + } + + ds_inf("tizen_display_policy_client binds. (client:%p)", client); + + client->display_policy = display_policy; + client->wl_client = wl_client; + + wl_list_init(&client->infos); + + client->resource = wl_resource_create(wl_client, &tizen_display_policy_interface, + MIN(version, TIZEN_DISPLAY_POLICY_VERSION), id); + + if (client->resource == NULL) { + ds_err("tizen_display_policy : wl_resource_create() failed."); + free(client); + wl_client_post_no_memory(wl_client); + return; + } + + wl_resource_set_implementation(client->resource, &display_policy_impl, client, + _tizen_display_policy_client_handle_destroy); + + wl_signal_init(&client->events.destroy); + + wl_list_insert(&display_policy->clients, &client->link); +} diff --git a/src/display_policy/meson.build b/src/display_policy/meson.build new file mode 100644 index 0000000..1ad17e9 --- /dev/null +++ b/src/display_policy/meson.build @@ -0,0 +1,29 @@ +libds_tizen_display_policy_files = [ + 'display_policy.c', +] + +libds_tizen_display_policy_deps = [ + deps_libds_tizen, + dependency('tizen-extension-server', required: true), +] + +lib_libds_tizen_display_policy = shared_library('ds-tizen-display-policy', libds_tizen_display_policy_files, + dependencies: libds_tizen_display_policy_deps, + include_directories: [ common_inc, include_directories('.'), include_directories('..') ], + version: meson.project_version(), + install: true +) + +deps_libds_tizen_display_policy = declare_dependency( + link_with: lib_libds_tizen_display_policy, + dependencies: libds_tizen_display_policy_deps, + include_directories: [ common_inc, include_directories('.') ], +) + +pkgconfig = import('pkgconfig') +pkgconfig.generate(lib_libds_tizen_display_policy, + version: meson.project_version(), + filebase: 'libds-tizen-display-policy', + name: 'libds-tizen-display-policy', + description: 'tizen display-policy extension of libds-tizen for tizen platform', +) diff --git a/src/meson.build b/src/meson.build index 3ea00d7..d0bb024 100644 --- a/src/meson.build +++ b/src/meson.build @@ -36,3 +36,4 @@ subdir('dpms') subdir('indicator') subdir('clipboard') subdir('launch') +subdir('display_policy') -- 2.7.4 From 04927cc7af66da6d42ee61e3c8f21d4ca856fd48 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Fri, 22 Jul 2022 08:45:13 +0900 Subject: [PATCH 11/16] add test cases for ds_tizen_display_policy Change-Id: I8a140320dbe5547b65c214f44095dae2bf0d1283 --- packaging/libds-tizen.spec | 1 + tests/meson.build | 20 +++ tests/tc_display_policy.cpp | 397 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 418 insertions(+) create mode 100644 tests/tc_display_policy.cpp diff --git a/packaging/libds-tizen.spec b/packaging/libds-tizen.spec index 372f0c3..5ec3a14 100644 --- a/packaging/libds-tizen.spec +++ b/packaging/libds-tizen.spec @@ -354,3 +354,4 @@ ninja -C builddir install %{_includedir}/libds-tizen/display_policy.h %{_libdir}/pkgconfig/libds-tizen-display-policy.pc %{_libdir}/libds-tizen-display-policy.so +%{_bindir}/libds-tizen-display-policy-tests diff --git a/tests/meson.build b/tests/meson.build index 4b4686d..4d63f58 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -84,3 +84,23 @@ executable('libds-tizen-launch-appinfo-tests', install_dir: libds_tizen_bindir, install : true ) + +## display-policy tests +tc_display_policy_files = [ + 'tc_main.cpp', + 'tc_display_policy.cpp', +] + +executable('libds-tizen-display-policy-tests', + [ + tc_mock_files, + tc_display_policy_files + ], + dependencies: [ + deps_test_common, + deps_libds_tizen_display_policy, + dependency('libdrm', required: true), + ], + install_dir: libds_tizen_bindir, + install : true +) diff --git a/tests/tc_display_policy.cpp b/tests/tc_display_policy.cpp new file mode 100644 index 0000000..fe165dc --- /dev/null +++ b/tests/tc_display_policy.cpp @@ -0,0 +1,397 @@ +#include "tc_main.h" +#include "mockclient.h" +#include "mockcompositor.h" +#include +#include + +#define TIZEN_DISPLAY_POLICY_VERSION 1 + +class MockDisplayPolicyCompositor : public MockCompositor +{ +public: + MockDisplayPolicyCompositor() + : MockCompositor(&MockDisplayPolicyCompositor::TestSetup, this) + { + ds_inf("%s : this(%p)", __func__, this); + + // initialize the flags to check + bSurfaceDestroyed = false; + + bDestroyed = false; + bSetBrightness = false; + mBrightnessValue = -1; + bDestroyDisplayPolicyInfo = false; + } + + ~MockDisplayPolicyCompositor() + { + ds_inf("%s : this(%p)", __func__, this); + } + + static void TestSetup(void *data) + { + MockDisplayPolicyCompositor *mockComp = + static_cast(data); + Compositor *comp = mockComp->compositor; + + ds_inf("%s: mockComp(%p)", __func__, mockComp); + + // new surface listener + mockComp->mNewSurfaceListener.notify = + MockDisplayPolicyCompositor::NewSurfaceCallback; + mockComp->mNewSurfaceListener.parent = mockComp; + ds_compositor_add_new_surface_listener(comp->compositor, + &mockComp->mNewSurfaceListener); + + mockComp->mDisplayPolicy = + ds_tizen_display_policy_create(comp->display); + + // destroy listener + mockComp->mDestroyListener.notify = + MockDisplayPolicyCompositor::DestroyCallback; + mockComp->mDestroyListener.parent = mockComp; + ds_tizen_display_policy_add_destroy_listener(mockComp->mDisplayPolicy, + &mockComp->mDestroyListener); + + // set_display_policy listener + mockComp->mSetDisplayPolicyListener.notify = + MockDisplayPolicyCompositor::SetBrightnessCallback; + mockComp->mSetDisplayPolicyListener.parent = mockComp; + ds_tizen_display_policy_add_set_brightness_info_listener( + mockComp->mDisplayPolicy, + &mockComp->mSetDisplayPolicyListener); + } + + static void NewSurfaceCallback(struct wl_listener *listener, void *data) + { + MockDisplayPolicyCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_surface *surface = static_cast(data); + + ds_inf("%s: mockComp(%p), surface(%p)", __func__, mockComp, surface); + + mockComp->mSurface = surface; + + // del surface listener + mockComp->mDelSurfaceListener.notify = + MockDisplayPolicyCompositor::DelSurfaceCallback; + mockComp->mDelSurfaceListener.parent = mockComp; + ds_surface_add_destroy_listener(surface, + &mockComp->mDelSurfaceListener); + } + + static void DelSurfaceCallback(struct wl_listener *listener, void *data) + { + MockDisplayPolicyCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_surface *surface = static_cast(data); + + ds_inf("%s: mockComp(%p), surface(%p)", __func__, mockComp, surface); + + if (ds_surface_get_wl_resource(mockComp->mSurface) == + ds_surface_get_wl_resource(surface)) { + ds_inf("%s: surface is deleted.", __func__); + mockComp->bSurfaceDestroyed = true; + } + } + + static void DestroyCallback(struct wl_listener *listener, void *data) + { + ds_inf("%s", __func__); + + MockDisplayPolicyCompositor *mockComp = + reinterpret_cast(listener)->parent; + + mockComp->bDestroyed = true; + } + + static void SetBrightnessCallback(struct wl_listener *listener, + void *data) + { + ds_inf("%s", __func__); + + MockDisplayPolicyCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_tizen_display_policy_info *info = + static_cast(data); + + ds_inf("%s: mockComp(%p), info(%p)", __func__, mockComp, info); + + mockComp->bSetBrightness = true; + + mockComp->mInfo = info; + mockComp->mSurface = + ds_tizen_display_policy_info_get_surface(mockComp->mInfo); + mockComp->mBrightnessValue = + ds_tizen_display_policy_info_get_brightness_value(mockComp->mInfo); + + // info destroy listener + mockComp->mDisplayPolicyInfoDestroyListener.notify = + MockDisplayPolicyCompositor::DisplayPolicyInfoDestroyCallback; + mockComp->mDisplayPolicyInfoDestroyListener.parent = mockComp; + ds_tizen_display_policy_info_add_destroy_listener(mockComp->mInfo, + &mockComp->mDisplayPolicyInfoDestroyListener); + } + + static void DisplayPolicyInfoDestroyCallback(struct wl_listener *listener, + void *data) + { + ds_inf("%s", __func__); + + MockDisplayPolicyCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_tizen_display_policy_info *info = + static_cast(data); + + ds_inf("%s: mockComp(%p), info(%p)", __func__, mockComp, info); + + if (mockComp->mInfo == info) { + ds_inf("%s: info is deleted.", __func__); + mockComp->bDestroyDisplayPolicyInfo = true; + } + } + + void SendDisplayPolicyDone(int32_t error_state) + { + ds_inf("%s", __func__); + + ds_tizen_display_policy_info_send_brightness_done( + mInfo, DS_TIZEN_DISPLAY_POLICY_ERROR_STATE_PERMISSION_DENIED); + } + +public: + bool bSurfaceDestroyed; + bool bDestroyed; + bool bSetBrightness; + int32_t mBrightnessValue; + bool bDestroyDisplayPolicyInfo; + +private: + struct ds_tizen_display_policy_info *mInfo; + struct ds_surface *mSurface; + struct NewSurfaceListener : ::wl_listener { + MockDisplayPolicyCompositor *parent; + }; + NewSurfaceListener mNewSurfaceListener; + struct DelSurfaceListener : ::wl_listener { + MockDisplayPolicyCompositor *parent; + }; + DelSurfaceListener mDelSurfaceListener; + + struct ds_tizen_display_policy *mDisplayPolicy; + struct DestroyListener : ::wl_listener { + MockDisplayPolicyCompositor *parent; + }; + DestroyListener mDestroyListener; + struct SetDisplayPolicyListener : ::wl_listener { + MockDisplayPolicyCompositor *parent; + }; + SetDisplayPolicyListener mSetDisplayPolicyListener; + struct DisplayPolicyInfoDestroyListener : ::wl_listener { + MockDisplayPolicyCompositor *parent; + }; + DisplayPolicyInfoDestroyListener mDisplayPolicyInfoDestroyListener; +}; + +class MockDisplayPolicyClient : public MockClient +{ +public: + MockDisplayPolicyClient() + : bBrightnessDoneEvent(false), + mBrightnessValue(-1), + mErrorState(0), + compositor_res(nullptr), + tizen_display_policy(nullptr) + {} + MockDisplayPolicyClient(const struct wl_registry_listener *listener) + : MockClient(listener, this) + { + ds_inf("%s", __func__); + + bBrightnessDoneEvent = false; + mBrightnessValue = -1; + mErrorState = 0; + } + ~MockDisplayPolicyClient() + { + ds_inf("%s", __func__); + } + + void SetWlCompositor(struct wl_compositor *global_res) + { + ds_inf("%s", __func__); + + compositor_res = global_res; + } + + struct wl_compositor *GetWlCompositor() + { + ds_inf("%s", __func__); + + return compositor_res; + } + + void SetTizenDisplayPolicy(struct tizen_display_policy *global_res) + { + ds_inf("%s", __func__); + + tizen_display_policy = global_res; + } + + struct tizen_display_policy *GetTizenDisplayPolicy() + { + ds_inf("%s", __func__); + + return tizen_display_policy; + } + +public: + bool bBrightnessDoneEvent; + int32_t mBrightnessValue; + uint32_t mErrorState; + +private: + struct wl_compositor *compositor_res; + struct tizen_display_policy *tizen_display_policy; +}; + +static void +client_tizen_display_policy_cb_window_brightness_done(void *data, + struct tizen_display_policy *display_policy, struct wl_surface *surface, + int32_t brightness_value, uint32_t error_state) +{ + ds_inf("%s", __func__); + + MockDisplayPolicyClient *client = static_cast(data); + + client->bBrightnessDoneEvent = true; + client->mBrightnessValue = brightness_value; + client->mErrorState = error_state; +} + +static const struct tizen_display_policy_listener display_policy_cb_listener = { + .window_brightness_done = client_tizen_display_policy_cb_window_brightness_done, +}; + +static void +client_registry_cb_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) +{ + ds_inf("%s", __func__); + + MockDisplayPolicyClient *client = static_cast(data); + struct wl_compositor *compositor_res; + struct tizen_display_policy *tizen_display_policy; + + if (!strcmp(interface, "wl_compositor")) { + compositor_res = (struct wl_compositor *)wl_registry_bind(registry, + name, &wl_compositor_interface, 1); + if (compositor_res == nullptr) { + ds_err("wl_registry_bind() failed. wl_compositor resource."); + return; + } + client->SetWlCompositor(compositor_res); + } else if (!strcmp(interface, "tizen_display_policy")) { + tizen_display_policy = (struct tizen_display_policy *)wl_registry_bind(registry, + name, &tizen_display_policy_interface, TIZEN_DISPLAY_POLICY_VERSION); + if (tizen_display_policy == nullptr) { + ds_err("wl_registry_bind() failed. tizen_display_policy resource."); + return; + } + client->SetTizenDisplayPolicy(tizen_display_policy); + + tizen_display_policy_add_listener(tizen_display_policy, + &display_policy_cb_listener, client); + } +} + +static void +client_registry_cb_global_remove(void *data, struct wl_registry *registry, + uint32_t name) +{ + ds_inf("%s", __func__); + + MockDisplayPolicyClient *client = static_cast(data); + struct wl_compositor *compositor_res = client->GetWlCompositor(); + struct tizen_display_policy *display_policy_res = client->GetTizenDisplayPolicy(); + + tizen_display_policy_destroy(display_policy_res); + wl_compositor_destroy(compositor_res); +} + +static const struct wl_registry_listener registry_listener = { + .global = client_registry_cb_global, + .global_remove = client_registry_cb_global_remove +}; + +class DisplayPolicyTest : public ::testing::Test +{ +public: + void SetUp(void) override; + void TearDown(void) override; + + MockDisplayPolicyCompositor *comp; + MockDisplayPolicyClient *client; + struct wl_compositor *compositor_res; + struct tizen_display_policy *display_policy_res; + struct wl_surface *surface_res; +}; + +void +DisplayPolicyTest::SetUp(void) +{ + //ds_log_init(DS_DBG, NULL); + + ds_inf("%s", __func__); + + comp = new MockDisplayPolicyCompositor(); + client = new MockDisplayPolicyClient(®istry_listener); + compositor_res = client->GetWlCompositor(); + display_policy_res = client->GetTizenDisplayPolicy(); + surface_res = wl_compositor_create_surface(compositor_res); + + client->RoundTrip(); +} + +void +DisplayPolicyTest::TearDown(void) +{ + ds_inf("%s", __func__); + + wl_surface_destroy(surface_res); + client->RoundTrip(); + EXPECT_TRUE(comp->bSurfaceDestroyed); + + delete client; + delete comp; +} + +TEST_F(DisplayPolicyTest, Create_P) +{ + EXPECT_TRUE(true); +} + +TEST_F(DisplayPolicyTest, Req_TizenDisplayPolicySetDisplayPolicy) +{ + tizen_display_policy_set_window_brightness(display_policy_res, surface_res, 10); + client->RoundTrip(); + EXPECT_TRUE(comp->bSetBrightness); + EXPECT_TRUE(comp->mBrightnessValue == 10); +} + +TEST_F(DisplayPolicyTest, Ev_TizenDisplayPolicyWindowDisplayPolicyDone) +{ + tizen_display_policy_set_window_brightness(display_policy_res, surface_res, 10); + client->RoundTrip(); + EXPECT_TRUE(comp->bSetBrightness); + EXPECT_TRUE(comp->mBrightnessValue == 10); + + comp->SendDisplayPolicyDone(DS_TIZEN_DISPLAY_POLICY_ERROR_STATE_PERMISSION_DENIED); + comp->Process(); + + client->RoundTrip(); + EXPECT_TRUE(client->bBrightnessDoneEvent); + EXPECT_TRUE(client->mBrightnessValue == 10); + EXPECT_TRUE(client->mErrorState == + DS_TIZEN_DISPLAY_POLICY_ERROR_STATE_PERMISSION_DENIED); +} -- 2.7.4 From 37cc0df45ca457624d751e907104bc9b008eff71 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Thu, 21 Jul 2022 15:41:35 +0900 Subject: [PATCH 12/16] impelement libds-tizen-memory-flusher This is the server implementation for tizen_surface_shm/tizen_surface_shm_flusher protocol. Change-Id: I0731be582066cd3085fb03da9000b6a1697e093b --- include/libds-tizen/memory_flusher.h | 49 +++++ packaging/libds-tizen.spec | 31 ++++ src/memory_flusher/memory_flusher.c | 341 +++++++++++++++++++++++++++++++++++ src/memory_flusher/meson.build | 29 +++ src/meson.build | 1 + 5 files changed, 451 insertions(+) create mode 100644 include/libds-tizen/memory_flusher.h create mode 100644 src/memory_flusher/memory_flusher.c create mode 100644 src/memory_flusher/meson.build diff --git a/include/libds-tizen/memory_flusher.h b/include/libds-tizen/memory_flusher.h new file mode 100644 index 0000000..0b72425 --- /dev/null +++ b/include/libds-tizen/memory_flusher.h @@ -0,0 +1,49 @@ +#ifndef LIBDS_TIZEN_MEMORY_FLUSHER_H +#define LIBDS_TIZEN_MEMORY_FLUSHER_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ds_tizen_memory_flusher; +struct ds_tizen_memory_flusher_info; + +struct ds_tizen_memory_flusher * +ds_tizen_memory_flusher_create(struct wl_display *display); + +void +ds_tizen_memory_flusher_add_destroy_listener( + struct ds_tizen_memory_flusher *memory_flusher, + struct wl_listener *listener); + +void +ds_tizen_memory_flusher_add_get_flusher_info_listener( + struct ds_tizen_memory_flusher *memory_flusher, + struct wl_listener *listener); + +void +ds_tizen_memory_flusher_info_add_destroy_listener( + struct ds_tizen_memory_flusher_info *info, + struct wl_listener *listener); + +struct ds_surface * +ds_tizen_memory_flusher_info_get_surface( + struct ds_tizen_memory_flusher_info *info); + +void +ds_tizen_memory_flusher_info_send_flush( + struct ds_tizen_memory_flusher_info *info); + +void +ds_tizen_memory_flusher_info_send_free_flush( + struct ds_tizen_memory_flusher_info *info); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packaging/libds-tizen.spec b/packaging/libds-tizen.spec index 5ec3a14..d1db0c9 100644 --- a/packaging/libds-tizen.spec +++ b/packaging/libds-tizen.spec @@ -26,6 +26,8 @@ BuildRequires: pkgconfig(wayland-tbm-server) BuildRequires: pkgconfig(wayland-tbm-client) BuildRequires: pkgconfig(tizen-dpms-server) BuildRequires: pkgconfig(tizen-dpms-client) +BuildRequires: pkgconfig(tizen-surface-server) +BuildRequires: pkgconfig(tizen-surface-client) BuildRequires: pkgconfig(cynara-client) BuildRequires: pkgconfig(cynara-session) BuildRequires: pkgconfig(libsmack) @@ -184,6 +186,21 @@ Group: Development/Libraries %description display-policy-devel Development package for tizen display-policy +## libds-tizen-memory-flusher +%package memory-flusher +Summary: Library for tizen memory flusher +Group: Development/Libraries + +%description memory-flusher +Library for tizen memory flusher + +%package memory-flusher-devel +Summary: Development package for tizen memory flusher +Group: Development/Libraries + +%description memory-flusher-devel +Development package for tizen memory flusher + %prep %setup -q cp %{SOURCE1001} . @@ -355,3 +372,17 @@ ninja -C builddir install %{_libdir}/pkgconfig/libds-tizen-display-policy.pc %{_libdir}/libds-tizen-display-policy.so %{_bindir}/libds-tizen-display-policy-tests + +%files memory-flusher +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_libdir}/libds-tizen-memory-flusher.so.* + +%files memory-flusher-devel +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_includedir}/libds-tizen/memory_flusher.h +%{_libdir}/pkgconfig/libds-tizen-memory-flusher.pc +%{_libdir}/libds-tizen-memory-flusher.so diff --git a/src/memory_flusher/memory_flusher.c b/src/memory_flusher/memory_flusher.c new file mode 100644 index 0000000..499e05d --- /dev/null +++ b/src/memory_flusher/memory_flusher.c @@ -0,0 +1,341 @@ +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "libds-tizen/memory_flusher.h" + +#define TIZEN_MEMORY_FLUSHER_VERSION 2 + +struct ds_tizen_memory_flusher +{ + struct wl_global *global; + + struct wl_list clients; + + struct wl_listener destroy; + + struct { + struct wl_signal destroy; + struct wl_signal get_flusher; + } events; +}; + +struct ds_tizen_memory_flusher_client +{ + struct ds_tizen_memory_flusher *memory_flusher; + + struct wl_resource *resource; + struct wl_client *wl_client; + + struct wl_list infos; + + struct { + struct wl_signal destroy; + } events; + + struct wl_list link; // ds_tizen_memory_flusher::clients +}; + +struct ds_tizen_memory_flusher_info +{ + struct ds_tizen_memory_flusher_client *client; + + struct wl_resource *resource; + + struct ds_surface *surface; + + struct wl_list link; // ds_tizen_memory_flusher_client::infos +}; + +static void memory_flusher_handle_display_destroy(struct wl_listener *listener, + void *data); + +static void memory_flusher_bind(struct wl_client *wl_client, void *data, + uint32_t version, uint32_t id); + +static struct ds_tizen_memory_flusher_info *tizen_memory_flusher_client_find_info( + struct ds_tizen_memory_flusher_client *client, + struct ds_surface *surface); + +static struct ds_tizen_memory_flusher_info *tizen_memory_flusher_client_get_info( + struct ds_tizen_memory_flusher_client *client, + struct ds_surface *surface); + +WL_EXPORT struct ds_tizen_memory_flusher * +ds_tizen_memory_flusher_create(struct wl_display *display) +{ + struct ds_tizen_memory_flusher *memory_flusher; + + memory_flusher = calloc(1, sizeof *memory_flusher); + if (!memory_flusher) { + ds_err("calloc() failed."); + return NULL; + } + + memory_flusher->global = wl_global_create(display, &tizen_surface_shm_interface, + TIZEN_MEMORY_FLUSHER_VERSION, memory_flusher, memory_flusher_bind); + if (!memory_flusher->global) { + ds_err("wl_global_create() failed. tizen_surface_shm_interface"); + free(memory_flusher); + return NULL; + } + + wl_list_init(&memory_flusher->clients); + + memory_flusher->destroy.notify = memory_flusher_handle_display_destroy; + wl_display_add_destroy_listener(display, &memory_flusher->destroy); + + wl_signal_init(&memory_flusher->events.destroy); + wl_signal_init(&memory_flusher->events.get_flusher); + + ds_inf("Global created: tizen_memory_flusher(%p)", memory_flusher); + + return memory_flusher; +} + +WL_EXPORT void +ds_tizen_memory_flusher_add_destroy_listener( + struct ds_tizen_memory_flusher *memory_flusher, + struct wl_listener *listener) +{ + wl_signal_add(&memory_flusher->events.destroy, listener); +} + +WL_EXPORT void +ds_tizen_memory_flusher_add_get_flusher_info_listener( + struct ds_tizen_memory_flusher *memory_flusher, + struct wl_listener *listener) +{ + wl_signal_add(&memory_flusher->events.get_flusher, listener); +} + +WL_EXPORT void +ds_tizen_memory_flusher_info_add_destroy_listener( + struct ds_tizen_memory_flusher_info *info, + struct wl_listener *listener) +{ + wl_signal_add(&info->client->events.destroy, listener); +} + +WL_EXPORT struct ds_surface * +ds_tizen_memory_flusher_info_get_surface( + struct ds_tizen_memory_flusher_info *info) +{ + return info->surface; +} + +WL_EXPORT void +ds_tizen_memory_flusher_info_send_flush( + struct ds_tizen_memory_flusher_info *info) +{ + tizen_surface_shm_flusher_send_flush(info->resource); +} + +WL_EXPORT void +ds_tizen_memory_flusher_info_send_free_flush( + struct ds_tizen_memory_flusher_info *info) +{ + tizen_surface_shm_flusher_send_free_flush(info->resource); +} + +static struct ds_tizen_memory_flusher_info * +tizen_memory_flusher_client_find_info(struct ds_tizen_memory_flusher_client *client, + struct ds_surface *surface) +{ + struct ds_tizen_memory_flusher_info *info; + + wl_list_for_each(info, &client->infos, link) { + if (surface == info->surface) + return info; + } + + return NULL; +} + +static struct ds_tizen_memory_flusher_info * +tizen_memory_flusher_client_get_info(struct ds_tizen_memory_flusher_client *client, + struct ds_surface *surface) +{ + struct ds_tizen_memory_flusher_info *info; + + info = tizen_memory_flusher_client_find_info(client, surface); + if (info) + return info; + + info = calloc(1, sizeof *info); + if (info == NULL) { + ds_err("calloc() failed. tizen_memory_flusher"); + return NULL; + } + + info->client = client; + info->surface = surface; + + wl_list_insert(&client->infos, &info->link); + + return info; +} + +static void +memory_flusher_handle_display_destroy(struct wl_listener *listener, void *data) +{ + struct ds_tizen_memory_flusher *memory_flusher; + + memory_flusher = wl_container_of(listener, memory_flusher, destroy); + + ds_inf("Global destroy: memory_flusher(%p)", memory_flusher); + + wl_signal_emit(&memory_flusher->events.destroy, memory_flusher); + wl_list_remove(&memory_flusher->destroy.link); + wl_global_destroy(memory_flusher->global); + free(memory_flusher); +} + +static void +flusher_handle_destroy(struct wl_client *wl_client, + struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static const struct tizen_surface_shm_flusher_interface flusher_impl = +{ + flusher_handle_destroy, +}; + +static void +_tizen_memory_flusher_info_handle_destroy(struct wl_resource *resource) +{ + struct ds_tizen_memory_flusher_info *info; + + info = wl_resource_get_user_data(resource); + + ds_inf("_tizen_memory_flusher_info_handle_destroy (info:%p)", info); + + wl_signal_emit(&info->client->events.destroy, info); + wl_list_remove(&info->link); + free(info); +} + +static void +memory_flusher_handle_get_flusher(struct wl_client *wl_client, + struct wl_resource *resource,uint32_t id, + struct wl_resource *surface_resource) +{ + struct ds_tizen_memory_flusher_client *client; + struct ds_tizen_memory_flusher_info *info; + struct ds_surface *surface; + + ds_inf("tizen_memory_flusher: get_flusher"); + + client = wl_resource_get_user_data(resource); + surface = ds_surface_from_resource(surface_resource); + + info = tizen_memory_flusher_client_get_info(client, surface); + if (info == NULL) { + ds_err("tizen_memory_flusher_client_get_info() failed."); + wl_client_post_no_memory(wl_client); + return; + } + + info->resource = wl_resource_create(wl_client, + &tizen_surface_shm_flusher_interface, wl_resource_get_version(resource), + id); + if (info->resource == NULL) { + ds_err("tizen_memory_flusher : wl_resource_create() failed."); + wl_list_remove(&info->link); + free(info); + wl_client_post_no_memory(wl_client); + return; + } + + wl_resource_set_implementation(info->resource, &flusher_impl, info, + _tizen_memory_flusher_info_handle_destroy); + + wl_signal_emit(&client->memory_flusher->events.get_flusher, info); +} + +static void +memory_flusher_handle_destroy(struct wl_client *wl_client, + struct wl_resource *resource) +{ + struct ds_tizen_memory_flusher_client *client; + + client = wl_resource_get_user_data(resource); + + if (!wl_list_empty(&client->infos)) { + ds_err("tizen_memory_flusher was destroyed before children"); + return; + } + + wl_resource_destroy(resource); +} + +static const struct tizen_surface_shm_interface memory_flusher_impl = +{ + memory_flusher_handle_get_flusher, + memory_flusher_handle_destroy, +}; + +static void +_tizen_memory_flusher_client_handle_destroy(struct wl_resource *resource) +{ + struct ds_tizen_memory_flusher_client *client; + struct ds_tizen_memory_flusher_info *info, *tmp; + + client = wl_resource_get_user_data(resource); + + ds_inf("_tizen_memory_flusher_client_handle_destroy (client:%p)", client); + + wl_list_for_each_safe(info, tmp, &client->infos, link) { + wl_signal_emit(&client->events.destroy, info); + wl_list_remove(&info->link); + free(info); + } + + wl_list_remove(&client->link); + free(client); +} + +static void +memory_flusher_bind(struct wl_client *wl_client, void *data, uint32_t version, + uint32_t id) +{ + struct ds_tizen_memory_flusher *memory_flusher = data; + struct ds_tizen_memory_flusher_client *client; + + client = calloc(1, sizeof *client); + if (client == NULL) { + ds_err("calloc() failed. tizen_memory_flusher"); + wl_client_post_no_memory(wl_client); + return; + } + + ds_inf("tizen_memory_flusher_client binds. (client:%p)", client); + + client->memory_flusher = memory_flusher; + client->wl_client = wl_client; + + wl_list_init(&client->infos); + + client->resource = wl_resource_create(wl_client, &tizen_surface_shm_interface, + MIN(version, TIZEN_MEMORY_FLUSHER_VERSION), id); + + if (client->resource == NULL) { + ds_err("tizen_memory_flusher : wl_resource_create() failed."); + free(client); + wl_client_post_no_memory(wl_client); + return; + } + + wl_resource_set_implementation(client->resource, &memory_flusher_impl, client, + _tizen_memory_flusher_client_handle_destroy); + + wl_signal_init(&client->events.destroy); + + wl_list_insert(&memory_flusher->clients, &client->link); +} diff --git a/src/memory_flusher/meson.build b/src/memory_flusher/meson.build new file mode 100644 index 0000000..440022a --- /dev/null +++ b/src/memory_flusher/meson.build @@ -0,0 +1,29 @@ +libds_tizen_memory_flusher_files = [ + 'memory_flusher.c', +] + +libds_tizen_memory_flusher_deps = [ + deps_libds_tizen, + dependency('tizen-surface-server', required: true), +] + +lib_libds_tizen_memory_flusher = shared_library('ds-tizen-memory-flusher', libds_tizen_memory_flusher_files, + dependencies: libds_tizen_memory_flusher_deps, + include_directories: [ common_inc, include_directories('.'), include_directories('..') ], + version: meson.project_version(), + install: true +) + +deps_libds_tizen_memory_flusher = declare_dependency( + link_with: lib_libds_tizen_memory_flusher, + dependencies: libds_tizen_memory_flusher_deps, + include_directories: [ common_inc, include_directories('.') ], +) + +pkgconfig = import('pkgconfig') +pkgconfig.generate(lib_libds_tizen_memory_flusher, + version: meson.project_version(), + filebase: 'libds-tizen-memory-flusher', + name: 'libds-tizen-memory-flusher', + description: 'tizen memory flusher extension of libds-tizen for tizen platform', +) diff --git a/src/meson.build b/src/meson.build index d0bb024..c1c88ac 100644 --- a/src/meson.build +++ b/src/meson.build @@ -37,3 +37,4 @@ subdir('indicator') subdir('clipboard') subdir('launch') subdir('display_policy') +subdir('memory_flusher') -- 2.7.4 From 725d9817053caa88693ed6f6dec1702e1130f7be Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Fri, 22 Jul 2022 10:51:10 +0900 Subject: [PATCH 13/16] add test cases for ds_tizen_memory_flusher Change-Id: I3ca0315e7c90f357079d46fc8cb8bd55cd22fa1b --- packaging/libds-tizen.spec | 1 + tests/meson.build | 21 +++ tests/tc_memory_flusher.cpp | 413 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 435 insertions(+) create mode 100644 tests/tc_memory_flusher.cpp diff --git a/packaging/libds-tizen.spec b/packaging/libds-tizen.spec index d1db0c9..9777876 100644 --- a/packaging/libds-tizen.spec +++ b/packaging/libds-tizen.spec @@ -386,3 +386,4 @@ ninja -C builddir install %{_includedir}/libds-tizen/memory_flusher.h %{_libdir}/pkgconfig/libds-tizen-memory-flusher.pc %{_libdir}/libds-tizen-memory-flusher.so +%{_bindir}/libds-tizen-memory-flusher-tests diff --git a/tests/meson.build b/tests/meson.build index 4d63f58..11af746 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -104,3 +104,24 @@ executable('libds-tizen-display-policy-tests', install_dir: libds_tizen_bindir, install : true ) + +## memory-flusher tests +tc_memory_flusher_files = [ + 'tc_main.cpp', + 'tc_memory_flusher.cpp', +] + +executable('libds-tizen-memory-flusher-tests', + [ + tc_mock_files, + tc_memory_flusher_files + ], + dependencies: [ + deps_test_common, + deps_libds_tizen_memory_flusher, + dependency('libdrm', required: true), + dependency('tizen-surface-client', required: true), + ], + install_dir: libds_tizen_bindir, + install : true +) diff --git a/tests/tc_memory_flusher.cpp b/tests/tc_memory_flusher.cpp new file mode 100644 index 0000000..7085445 --- /dev/null +++ b/tests/tc_memory_flusher.cpp @@ -0,0 +1,413 @@ +#include "tc_main.h" +#include "mockclient.h" +#include "mockcompositor.h" +#include +#include + +#define TIZEN_MEMORY_FLUSHER_VERSION 2 + +class MockMemoryFlusherCompositor : public MockCompositor +{ +public: + MockMemoryFlusherCompositor() + : MockCompositor(&MockMemoryFlusherCompositor::TestSetup, this) + { + ds_inf("%s : this(%p)", __func__, this); + + // initialize the flags to check + bSurfaceDestroyed = false; + + bDestroyed = false; + bGetFlusherInfo = false; + bDestroyFlusherInfo = false; + } + + ~MockMemoryFlusherCompositor() + { + ds_inf("%s : this(%p)", __func__, this); + } + + static void TestSetup(void *data) + { + MockMemoryFlusherCompositor *mockComp = + static_cast(data); + Compositor *comp = mockComp->compositor; + + ds_inf("%s: mockComp(%p)", __func__, mockComp); + + // new surface listener + mockComp->mNewSurfaceListener.notify = + MockMemoryFlusherCompositor::NewSurfaceCallback; + mockComp->mNewSurfaceListener.parent = mockComp; + ds_compositor_add_new_surface_listener(comp->compositor, + &mockComp->mNewSurfaceListener); + + mockComp->mMemoryFlusher = + ds_tizen_memory_flusher_create(comp->display); + + // destroy listener + mockComp->mDestroyListener.notify = + MockMemoryFlusherCompositor::DestroyCallback; + mockComp->mDestroyListener.parent = mockComp; + ds_tizen_memory_flusher_add_destroy_listener(mockComp->mMemoryFlusher, + &mockComp->mDestroyListener); + + // get_flusher_info listener + mockComp->mGetFlusherInfoListener.notify = + MockMemoryFlusherCompositor::GetFlusherInfoCallback; + mockComp->mGetFlusherInfoListener.parent = mockComp; + ds_tizen_memory_flusher_add_get_flusher_info_listener( + mockComp->mMemoryFlusher, + &mockComp->mGetFlusherInfoListener); + } + + static void NewSurfaceCallback(struct wl_listener *listener, void *data) + { + MockMemoryFlusherCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_surface *surface = static_cast(data); + + ds_inf("%s: mockComp(%p), surface(%p)", __func__, mockComp, surface); + + mockComp->mSurface = surface; + + // del surface listener + mockComp->mDelSurfaceListener.notify = + MockMemoryFlusherCompositor::DelSurfaceCallback; + mockComp->mDelSurfaceListener.parent = mockComp; + ds_surface_add_destroy_listener(surface, + &mockComp->mDelSurfaceListener); + } + + static void DelSurfaceCallback(struct wl_listener *listener, void *data) + { + MockMemoryFlusherCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_surface *surface = static_cast(data); + + ds_inf("%s: mockComp(%p), surface(%p)", __func__, mockComp, surface); + + if (ds_surface_get_wl_resource(mockComp->mSurface) == + ds_surface_get_wl_resource(surface)) { + ds_inf("%s: surface is deleted.", __func__); + mockComp->bSurfaceDestroyed = true; + } + } + + static void DestroyCallback(struct wl_listener *listener, void *data) + { + ds_inf("%s", __func__); + + MockMemoryFlusherCompositor *mockComp = + reinterpret_cast(listener)->parent; + + mockComp->bDestroyed = true; + } + + static void GetFlusherInfoCallback(struct wl_listener *listener, + void *data) + { + ds_inf("%s", __func__); + + MockMemoryFlusherCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_tizen_memory_flusher_info *info = + static_cast(data); + + ds_inf("%s: mockComp(%p), info(%p)", __func__, mockComp, info); + + mockComp->bGetFlusherInfo = true; + + mockComp->mInfo = info; + mockComp->mSurface = + ds_tizen_memory_flusher_info_get_surface(mockComp->mInfo); + + // info destroy listener + mockComp->mFlusherInfoDestroyListener.notify = + MockMemoryFlusherCompositor::FlusherInfoDestroyCallback; + mockComp->mFlusherInfoDestroyListener.parent = mockComp; + ds_tizen_memory_flusher_info_add_destroy_listener(mockComp->mInfo, + &mockComp->mFlusherInfoDestroyListener); + } + + static void FlusherInfoDestroyCallback(struct wl_listener *listener, + void *data) + { + ds_inf("%s", __func__); + + MockMemoryFlusherCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_tizen_memory_flusher_info *info = + static_cast(data); + + ds_inf("%s: mockComp(%p), info(%p)", __func__, mockComp, info); + + if (mockComp->mInfo == info) { + ds_inf("%s: info is deleted.", __func__); + mockComp->bDestroyFlusherInfo = true; + } + } + + void SendMemoryFlusherInfoFlush() + { + ds_inf("%s", __func__); + + ds_tizen_memory_flusher_info_send_flush(mInfo); + } + + void SendMemoryFlusherInfoFreeFlush() + { + ds_inf("%s", __func__); + + ds_tizen_memory_flusher_info_send_free_flush(mInfo); + } + +public: + bool bSurfaceDestroyed; + bool bDestroyed; + bool bGetFlusherInfo; + bool bDestroyFlusherInfo; + +private: + struct ds_tizen_memory_flusher_info *mInfo; + struct ds_surface *mSurface; + + struct NewSurfaceListener : ::wl_listener { + MockMemoryFlusherCompositor *parent; + }; + NewSurfaceListener mNewSurfaceListener; + + struct DelSurfaceListener : ::wl_listener { + MockMemoryFlusherCompositor *parent; + }; + DelSurfaceListener mDelSurfaceListener; + + struct ds_tizen_memory_flusher *mMemoryFlusher; + + struct DestroyListener : ::wl_listener { + MockMemoryFlusherCompositor *parent; + }; + DestroyListener mDestroyListener; + + struct GetFlusherInfoListener : ::wl_listener { + MockMemoryFlusherCompositor *parent; + }; + GetFlusherInfoListener mGetFlusherInfoListener; + + struct FlusherInfoDestroyListener : ::wl_listener { + MockMemoryFlusherCompositor *parent; + }; + FlusherInfoDestroyListener mFlusherInfoDestroyListener; +}; + +class MockMemoryFlusherClient : public MockClient +{ +public: + MockMemoryFlusherClient() + : bFlushEvent(false), + bFreeFlushEvent(false), + compositor_res(nullptr), + tizen_surface_shm(nullptr) + {} + MockMemoryFlusherClient(const struct wl_registry_listener *listener) + : MockClient(listener, this) + { + ds_inf("%s", __func__); + + bFlushEvent = false; + bFreeFlushEvent = false; + } + ~MockMemoryFlusherClient() + { + ds_inf("%s", __func__); + } + + void SetWlCompositor(struct wl_compositor *global_res) + { + ds_inf("%s", __func__); + + compositor_res = global_res; + } + + struct wl_compositor *GetWlCompositor() + { + ds_inf("%s", __func__); + + return compositor_res; + } + + void SetTizenSurfaceShm(struct tizen_surface_shm *global_res) + { + ds_inf("%s", __func__); + + tizen_surface_shm = global_res; + } + + struct tizen_surface_shm *GetTizenSurfaceShm() + { + ds_inf("%s", __func__); + + return tizen_surface_shm; + } + +public: + bool bFlushEvent; + bool bFreeFlushEvent; + +private: + struct wl_compositor *compositor_res; + struct tizen_surface_shm *tizen_surface_shm; +}; + +static void +client_registry_cb_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) +{ + ds_inf("%s", __func__); + + MockMemoryFlusherClient *client = static_cast(data); + struct wl_compositor *compositor_res; + struct tizen_surface_shm *surface_shm_res; + + if (!strcmp(interface, "wl_compositor")) { + compositor_res = (struct wl_compositor *)wl_registry_bind(registry, + name, &wl_compositor_interface, 1); + if (compositor_res == nullptr) { + ds_err("wl_registry_bind() failed. wl_compositor resource."); + return; + } + client->SetWlCompositor(compositor_res); + } else if (!strcmp(interface, "tizen_surface_shm")) { + surface_shm_res = (struct tizen_surface_shm *)wl_registry_bind(registry, + name, &tizen_surface_shm_interface, TIZEN_MEMORY_FLUSHER_VERSION); + if (surface_shm_res == nullptr) { + ds_err("wl_registry_bind() failed. tizen_surface_shm resource."); + return; + } + client->SetTizenSurfaceShm(surface_shm_res); + } +} + +static void +client_registry_cb_global_remove(void *data, struct wl_registry *registry, + uint32_t name) +{ + ds_inf("%s", __func__); + + MockMemoryFlusherClient *client = static_cast(data); + struct wl_compositor *compositor_res = client->GetWlCompositor(); + struct tizen_surface_shm *surface_shm_res = client->GetTizenSurfaceShm(); + + tizen_surface_shm_destroy(surface_shm_res); + wl_compositor_destroy(compositor_res); +} + +static const struct wl_registry_listener registry_listener = { + .global = client_registry_cb_global, + .global_remove = client_registry_cb_global_remove +}; + +static void +client_tizen_surface_shm_flusher_cb_flush(void *data, + struct tizen_surface_shm_flusher *surface_shm_flusher_res) +{ + ds_inf("%s", __func__); + + MockMemoryFlusherClient *client = static_cast(data); + + client->bFlushEvent = true; +} + +static void +client_tizen_surface_shm_flusher_cb_free_flush(void *data, + struct tizen_surface_shm_flusher *surface_shm_flusher_res) +{ + ds_inf("%s", __func__); + + MockMemoryFlusherClient *client = static_cast(data); + + client->bFreeFlushEvent = true; +} + +static const struct +tizen_surface_shm_flusher_listener surface_shm_flusher_cb_listener = { + .flush = client_tizen_surface_shm_flusher_cb_flush, + .free_flush = client_tizen_surface_shm_flusher_cb_free_flush, +}; + +class MemoryFlusherTest : public ::testing::Test +{ +public: + void SetUp(void) override; + void TearDown(void) override; + + MockMemoryFlusherCompositor *comp; + MockMemoryFlusherClient *client; + struct wl_compositor *compositor_res; + struct tizen_surface_shm *surface_shm_res; + struct wl_surface *surface_res; + struct tizen_surface_shm_flusher *surface_shm_flusher_res; +}; + +void +MemoryFlusherTest::SetUp(void) +{ + //ds_log_init(DS_DBG, NULL); + + ds_inf("%s", __func__); + + comp = new MockMemoryFlusherCompositor(); + client = new MockMemoryFlusherClient(®istry_listener); + compositor_res = client->GetWlCompositor(); + surface_shm_res = client->GetTizenSurfaceShm(); + surface_res = wl_compositor_create_surface(compositor_res); + + surface_shm_flusher_res = + tizen_surface_shm_get_flusher(surface_shm_res, surface_res); + + tizen_surface_shm_flusher_add_listener(surface_shm_flusher_res, + &surface_shm_flusher_cb_listener, client); + + client->RoundTrip(); +} + +void +MemoryFlusherTest::TearDown(void) +{ + ds_inf("%s", __func__); + + tizen_surface_shm_flusher_destroy(surface_shm_flusher_res); + client->RoundTrip(); + EXPECT_TRUE(comp->bDestroyFlusherInfo); + + wl_surface_destroy(surface_res); + client->RoundTrip(); + EXPECT_TRUE(comp->bSurfaceDestroyed); + + delete client; + delete comp; +} + +TEST_F(MemoryFlusherTest, Create_P) +{ + EXPECT_TRUE(true); + EXPECT_TRUE(comp->bGetFlusherInfo); +} + +TEST_F(MemoryFlusherTest, Ev_TizenSurfaceShmFlusherFlush) +{ + comp->SendMemoryFlusherInfoFlush(); + comp->Process(); + + client->RoundTrip(); + EXPECT_TRUE(client->bFlushEvent); +} + +TEST_F(MemoryFlusherTest, Ev_TizenSurfaceShmFlusherFreeFlush) +{ + comp->SendMemoryFlusherInfoFreeFlush(); + comp->Process(); + + client->RoundTrip(); + EXPECT_TRUE(client->bFreeFlushEvent); +} -- 2.7.4 From f5fbf8e54a44f3c0998c54e5c465a483d738eb53 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Thu, 21 Jul 2022 16:43:21 +0900 Subject: [PATCH 14/16] impelement libds-tizen-renderer This is the server implementation for tizen_renderer protocol. Change-Id: Id7d91034cf43e0ee201cc9ea3e92eb05305e2787 --- include/libds-tizen/renderer.h | 44 ++++++ packaging/libds-tizen.spec | 29 ++++ src/meson.build | 1 + src/renderer/meson.build | 29 ++++ src/renderer/renderer.c | 334 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 437 insertions(+) create mode 100644 include/libds-tizen/renderer.h create mode 100644 src/renderer/meson.build create mode 100644 src/renderer/renderer.c diff --git a/include/libds-tizen/renderer.h b/include/libds-tizen/renderer.h new file mode 100644 index 0000000..6f02ca0 --- /dev/null +++ b/include/libds-tizen/renderer.h @@ -0,0 +1,44 @@ +#ifndef LIBDS_TIZEN_RENDERER_H +#define LIBDS_TIZEN_RENDERER_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ds_tizen_renderer; +struct ds_tizen_renderer_info; + +struct ds_tizen_renderer * +ds_tizen_renderer_create(struct wl_display *display); + +void +ds_tizen_renderer_add_destroy_listener(struct ds_tizen_renderer *renderer, + struct wl_listener *listener); + +void +ds_tizen_renderer_add_get_renderer_surface_info_listener( + struct ds_tizen_renderer *renderer, + struct wl_listener *listener); + +void +ds_tizen_renderer_info_add_destroy_listener( + struct ds_tizen_renderer_info *info, + struct wl_listener *listener); + +struct ds_surface * +ds_tizen_renderer_info_get_surface( + struct ds_tizen_renderer_info *info); + +void +ds_tizen_renderer_info_send_redraw( + struct ds_tizen_renderer_info *info); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packaging/libds-tizen.spec b/packaging/libds-tizen.spec index 9777876..8eddf79 100644 --- a/packaging/libds-tizen.spec +++ b/packaging/libds-tizen.spec @@ -201,6 +201,21 @@ Group: Development/Libraries %description memory-flusher-devel Development package for tizen memory flusher +## libds-tizen-renderer +%package renderer +Summary: Library for tizen renderer +Group: Development/Libraries + +%description renderer +Library for tizen renderer + +%package renderer-devel +Summary: Development package for tizen renderer +Group: Development/Libraries + +%description renderer-devel +Development package for tizen renderer + %prep %setup -q cp %{SOURCE1001} . @@ -387,3 +402,17 @@ ninja -C builddir install %{_libdir}/pkgconfig/libds-tizen-memory-flusher.pc %{_libdir}/libds-tizen-memory-flusher.so %{_bindir}/libds-tizen-memory-flusher-tests + +%files renderer +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_libdir}/libds-tizen-renderer.so.* + +%files renderer-devel +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_includedir}/libds-tizen/renderer.h +%{_libdir}/pkgconfig/libds-tizen-renderer.pc +%{_libdir}/libds-tizen-renderer.so diff --git a/src/meson.build b/src/meson.build index c1c88ac..a8df30b 100644 --- a/src/meson.build +++ b/src/meson.build @@ -38,3 +38,4 @@ subdir('clipboard') subdir('launch') subdir('display_policy') subdir('memory_flusher') +subdir('renderer') diff --git a/src/renderer/meson.build b/src/renderer/meson.build new file mode 100644 index 0000000..fab95f3 --- /dev/null +++ b/src/renderer/meson.build @@ -0,0 +1,29 @@ +libds_tizen_renderer_files = [ + 'renderer.c', +] + +libds_tizen_renderer_deps = [ + deps_libds_tizen, + dependency('tizen-extension-server', required: true), +] + +lib_libds_tizen_renderer = shared_library('ds-tizen-renderer', libds_tizen_renderer_files, + dependencies: libds_tizen_renderer_deps, + include_directories: [ common_inc, include_directories('.'), include_directories('..') ], + version: meson.project_version(), + install: true +) + +deps_libds_tizen_renderer = declare_dependency( + link_with: lib_libds_tizen_renderer, + dependencies: libds_tizen_renderer_deps, + include_directories: [ common_inc, include_directories('.') ], +) + +pkgconfig = import('pkgconfig') +pkgconfig.generate(lib_libds_tizen_renderer, + version: meson.project_version(), + filebase: 'libds-tizen-renderer', + name: 'libds-tizen-renderer', + description: 'tizen renderer extension of libds-tizen for tizen platform', +) diff --git a/src/renderer/renderer.c b/src/renderer/renderer.c new file mode 100644 index 0000000..f1e0e84 --- /dev/null +++ b/src/renderer/renderer.c @@ -0,0 +1,334 @@ +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "libds-tizen/renderer.h" + +#define TIZEN_RENDERER_VERSION 1 + +struct ds_tizen_renderer +{ + struct wl_global *global; + + struct wl_list clients; + + struct wl_listener destroy; + + struct { + struct wl_signal destroy; + struct wl_signal get_renderer_surface; + } events; +}; + +struct ds_tizen_renderer_client +{ + struct ds_tizen_renderer *renderer; + + struct wl_resource *resource; + struct wl_client *wl_client; + + struct wl_list infos; + + struct { + struct wl_signal destroy; + } events; + + struct wl_list link; // ds_tizen_renderer::clients +}; + +struct ds_tizen_renderer_info +{ + struct ds_tizen_renderer_client *client; + + struct wl_resource *resource; + + struct ds_surface *surface; + + struct wl_list link; // ds_tizen_renderer_client::infos +}; + +static void renderer_handle_display_destroy(struct wl_listener *listener, + void *data); + +static void renderer_bind(struct wl_client *wl_client, void *data, + uint32_t version, uint32_t id); + +static struct ds_tizen_renderer_info *tizen_renderer_client_find_info( + struct ds_tizen_renderer_client *client, + struct ds_surface *surface); + +static struct ds_tizen_renderer_info *tizen_renderer_client_get_info( + struct ds_tizen_renderer_client *client, + struct ds_surface *surface); + +WL_EXPORT struct ds_tizen_renderer * +ds_tizen_renderer_create(struct wl_display *display) +{ + struct ds_tizen_renderer *renderer; + + renderer = calloc(1, sizeof *renderer); + if (!renderer) { + ds_err("calloc() failed."); + return NULL; + } + + renderer->global = wl_global_create(display, &tizen_renderer_interface, + TIZEN_RENDERER_VERSION, renderer, renderer_bind); + if (!renderer->global) { + ds_err("wl_global_create() failed. tizen_renderer_interface"); + free(renderer); + return NULL; + } + + wl_list_init(&renderer->clients); + + renderer->destroy.notify = renderer_handle_display_destroy; + wl_display_add_destroy_listener(display, &renderer->destroy); + + wl_signal_init(&renderer->events.destroy); + wl_signal_init(&renderer->events.get_renderer_surface); + + ds_inf("Global created: tizen_renderer(%p)", renderer); + + return renderer; +} + +WL_EXPORT void +ds_tizen_renderer_add_destroy_listener( + struct ds_tizen_renderer *renderer, + struct wl_listener *listener) +{ + wl_signal_add(&renderer->events.destroy, listener); +} + +WL_EXPORT void +ds_tizen_renderer_add_get_renderer_surface_info_listener( + struct ds_tizen_renderer *renderer, + struct wl_listener *listener) +{ + wl_signal_add(&renderer->events.get_renderer_surface, listener); +} + +WL_EXPORT void +ds_tizen_renderer_info_add_destroy_listener( + struct ds_tizen_renderer_info *info, + struct wl_listener *listener) +{ + wl_signal_add(&info->client->events.destroy, listener); +} + +WL_EXPORT struct ds_surface * +ds_tizen_renderer_info_get_surface( + struct ds_tizen_renderer_info *info) +{ + return info->surface; +} + +WL_EXPORT void +ds_tizen_renderer_info_send_redraw( + struct ds_tizen_renderer_info *info) +{ + tizen_renderer_surface_send_redraw_request(info->resource); +} + +static struct ds_tizen_renderer_info * +tizen_renderer_client_find_info(struct ds_tizen_renderer_client *client, + struct ds_surface *surface) +{ + struct ds_tizen_renderer_info *info; + + wl_list_for_each(info, &client->infos, link) { + if (surface == info->surface) + return info; + } + + return NULL; +} + +static struct ds_tizen_renderer_info * +tizen_renderer_client_get_info(struct ds_tizen_renderer_client *client, + struct ds_surface *surface) +{ + struct ds_tizen_renderer_info *info; + + info = tizen_renderer_client_find_info(client, surface); + if (info) + return info; + + info = calloc(1, sizeof *info); + if (info == NULL) { + ds_err("calloc() failed. tizen_renderer"); + return NULL; + } + + info->client = client; + info->surface = surface; + + wl_list_insert(&client->infos, &info->link); + + return info; +} + +static void +renderer_handle_display_destroy(struct wl_listener *listener, void *data) +{ + struct ds_tizen_renderer *renderer; + + renderer = wl_container_of(listener, renderer, destroy); + + ds_inf("Global destroy: renderer(%p)", renderer); + + wl_signal_emit(&renderer->events.destroy, renderer); + wl_list_remove(&renderer->destroy.link); + wl_global_destroy(renderer->global); + free(renderer); +} + +static void +renderer_surface_handle_destroy(struct wl_client *wl_client, + struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static const struct tizen_renderer_surface_interface renderer_surface_impl = +{ + renderer_surface_handle_destroy, +}; + +static void +_tizen_renderer_info_handle_destroy(struct wl_resource *resource) +{ + struct ds_tizen_renderer_info *info; + + info = wl_resource_get_user_data(resource); + + ds_inf("_tizen_renderer_info_handle_destroy (info:%p)", info); + + wl_signal_emit(&info->client->events.destroy, info); + wl_list_remove(&info->link); + free(info); +} + +static void +renderer_handle_get_renderer_surface(struct wl_client *wl_client, + struct wl_resource *resource,uint32_t id, + struct wl_resource *surface_resource) +{ + struct ds_tizen_renderer_client *client; + struct ds_tizen_renderer_info *info; + struct ds_surface *surface; + + ds_inf("tizen_renderer: get_renderer_surface"); + + client = wl_resource_get_user_data(resource); + surface = ds_surface_from_resource(surface_resource); + + info = tizen_renderer_client_get_info(client, surface); + if (info == NULL) { + ds_err("tizen_renderer_client_get_info() failed."); + wl_client_post_no_memory(wl_client); + return; + } + + info->resource = wl_resource_create(wl_client, + &tizen_renderer_surface_interface, wl_resource_get_version(resource), + id); + if (info->resource == NULL) { + ds_err("tizen_renderer : wl_resource_create() failed."); + wl_list_remove(&info->link); + free(info); + wl_client_post_no_memory(wl_client); + return; + } + + wl_resource_set_implementation(info->resource, &renderer_surface_impl, info, + _tizen_renderer_info_handle_destroy); + + wl_signal_emit(&client->renderer->events.get_renderer_surface, info); +} + +static void +renderer_handle_destroy(struct wl_client *wl_client, + struct wl_resource *resource) +{ + struct ds_tizen_renderer_client *client; + + client = wl_resource_get_user_data(resource); + + if (!wl_list_empty(&client->infos)) { + ds_err("tizen_renderer was destroyed before children"); + return; + } + + wl_resource_destroy(resource); +} + +static const struct tizen_renderer_interface renderer_impl = +{ + renderer_handle_get_renderer_surface, + renderer_handle_destroy, +}; + +static void +_tizen_renderer_client_handle_destroy(struct wl_resource *resource) +{ + struct ds_tizen_renderer_client *client; + struct ds_tizen_renderer_info *info, *tmp; + + client = wl_resource_get_user_data(resource); + + ds_inf("_tizen_renderer_client_handle_destroy (client:%p)", client); + + wl_list_for_each_safe(info, tmp, &client->infos, link) { + wl_signal_emit(&client->events.destroy, info); + wl_list_remove(&info->link); + free(info); + } + + wl_list_remove(&client->link); + free(client); +} + +static void +renderer_bind(struct wl_client *wl_client, void *data, uint32_t version, + uint32_t id) +{ + struct ds_tizen_renderer *renderer = data; + struct ds_tizen_renderer_client *client; + + client = calloc(1, sizeof *client); + if (client == NULL) { + ds_err("calloc() failed. tizen_renderer"); + wl_client_post_no_memory(wl_client); + return; + } + + ds_inf("tizen_renderer_client binds. (client:%p)", client); + + client->renderer = renderer; + client->wl_client = wl_client; + + wl_list_init(&client->infos); + + client->resource = wl_resource_create(wl_client, &tizen_renderer_interface, + MIN(version, TIZEN_RENDERER_VERSION), id); + + if (client->resource == NULL) { + ds_err("tizen_renderer : wl_resource_create() failed."); + free(client); + wl_client_post_no_memory(wl_client); + return; + } + + wl_resource_set_implementation(client->resource, &renderer_impl, client, + _tizen_renderer_client_handle_destroy); + + wl_signal_init(&client->events.destroy); + + wl_list_insert(&renderer->clients, &client->link); +} -- 2.7.4 From d889e114a4fa9a32af3c04550f3b123c27a37d1a Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Fri, 22 Jul 2022 11:15:18 +0900 Subject: [PATCH 15/16] add test cases for ds_tizen_renderer Change-Id: I4f669d3fcf727c7109f0b8a81d14a12c55d3edbe --- packaging/libds-tizen.spec | 1 + tests/meson.build | 21 +++ tests/tc_renderer.cpp | 382 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 404 insertions(+) create mode 100644 tests/tc_renderer.cpp diff --git a/packaging/libds-tizen.spec b/packaging/libds-tizen.spec index 8eddf79..38942c7 100644 --- a/packaging/libds-tizen.spec +++ b/packaging/libds-tizen.spec @@ -416,3 +416,4 @@ ninja -C builddir install %{_includedir}/libds-tizen/renderer.h %{_libdir}/pkgconfig/libds-tizen-renderer.pc %{_libdir}/libds-tizen-renderer.so +%{_bindir}/libds-tizen-renderer-tests diff --git a/tests/meson.build b/tests/meson.build index 11af746..b375f18 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -125,3 +125,24 @@ executable('libds-tizen-memory-flusher-tests', install_dir: libds_tizen_bindir, install : true ) + +## renderer tests +tc_renderer_files = [ + 'tc_main.cpp', + 'tc_renderer.cpp', +] + +executable('libds-tizen-renderer-tests', + [ + tc_mock_files, + tc_renderer_files + ], + dependencies: [ + deps_test_common, + deps_libds_tizen_renderer, + dependency('libdrm', required: true), + dependency('tizen-extension-client', required: true), + ], + install_dir: libds_tizen_bindir, + install : true +) diff --git a/tests/tc_renderer.cpp b/tests/tc_renderer.cpp new file mode 100644 index 0000000..078f782 --- /dev/null +++ b/tests/tc_renderer.cpp @@ -0,0 +1,382 @@ +#include "tc_main.h" +#include "mockclient.h" +#include "mockcompositor.h" +#include +#include + +#define TIZEN_RENDERER_VERSION 1 + +class MockRendererCompositor : public MockCompositor +{ +public: + MockRendererCompositor() + : MockCompositor(&MockRendererCompositor::TestSetup, this) + { + ds_inf("%s : this(%p)", __func__, this); + + // initialize the flags to check + bSurfaceDestroyed = false; + + bDestroyed = false; + bGetRendererSurface = false; + bDestroyRendererInfo = false; + } + + ~MockRendererCompositor() + { + ds_inf("%s : this(%p)", __func__, this); + } + + static void TestSetup(void *data) + { + MockRendererCompositor *mockComp = + static_cast(data); + Compositor *comp = mockComp->compositor; + + ds_inf("%s: mockComp(%p)", __func__, mockComp); + + // new surface listener + mockComp->mNewSurfaceListener.notify = + MockRendererCompositor::NewSurfaceCallback; + mockComp->mNewSurfaceListener.parent = mockComp; + ds_compositor_add_new_surface_listener(comp->compositor, + &mockComp->mNewSurfaceListener); + + mockComp->mRenderer = + ds_tizen_renderer_create(comp->display); + + // destroy listener + mockComp->mDestroyListener.notify = + MockRendererCompositor::DestroyCallback; + mockComp->mDestroyListener.parent = mockComp; + ds_tizen_renderer_add_destroy_listener(mockComp->mRenderer, + &mockComp->mDestroyListener); + + // get_flusher_info listener + mockComp->mGetFlusherInfoListener.notify = + MockRendererCompositor::GetRendererSurfaceCallback; + mockComp->mGetFlusherInfoListener.parent = mockComp; + ds_tizen_renderer_add_get_renderer_surface_info_listener( + mockComp->mRenderer, + &mockComp->mGetFlusherInfoListener); + } + + static void NewSurfaceCallback(struct wl_listener *listener, void *data) + { + MockRendererCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_surface *surface = static_cast(data); + + ds_inf("%s: mockComp(%p), surface(%p)", __func__, mockComp, surface); + + mockComp->mSurface = surface; + + // del surface listener + mockComp->mDelSurfaceListener.notify = + MockRendererCompositor::DelSurfaceCallback; + mockComp->mDelSurfaceListener.parent = mockComp; + ds_surface_add_destroy_listener(surface, + &mockComp->mDelSurfaceListener); + } + + static void DelSurfaceCallback(struct wl_listener *listener, void *data) + { + MockRendererCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_surface *surface = static_cast(data); + + ds_inf("%s: mockComp(%p), surface(%p)", __func__, mockComp, surface); + + if (ds_surface_get_wl_resource(mockComp->mSurface) == + ds_surface_get_wl_resource(surface)) { + ds_inf("%s: surface is deleted.", __func__); + mockComp->bSurfaceDestroyed = true; + } + } + + static void DestroyCallback(struct wl_listener *listener, void *data) + { + ds_inf("%s", __func__); + + MockRendererCompositor *mockComp = + reinterpret_cast(listener)->parent; + + mockComp->bDestroyed = true; + } + + static void GetRendererSurfaceCallback(struct wl_listener *listener, + void *data) + { + ds_inf("%s", __func__); + + MockRendererCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_tizen_renderer_info *info = + static_cast(data); + + ds_inf("%s: mockComp(%p), info(%p)", __func__, mockComp, info); + + mockComp->bGetRendererSurface = true; + + mockComp->mInfo = info; + mockComp->mSurface = + ds_tizen_renderer_info_get_surface(mockComp->mInfo); + + // info destroy listener + mockComp->mRendererInfoDestroyListener.notify = + MockRendererCompositor::RendererInfoDestroyCallback; + mockComp->mRendererInfoDestroyListener.parent = mockComp; + ds_tizen_renderer_info_add_destroy_listener(mockComp->mInfo, + &mockComp->mRendererInfoDestroyListener); + } + + static void RendererInfoDestroyCallback(struct wl_listener *listener, + void *data) + { + ds_inf("%s", __func__); + + MockRendererCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_tizen_renderer_info *info = + static_cast(data); + + ds_inf("%s: mockComp(%p), info(%p)", __func__, mockComp, info); + + if (mockComp->mInfo == info) { + ds_inf("%s: info is deleted.", __func__); + mockComp->bDestroyRendererInfo = true; + } + } + + void SendRendererInfoRedraw() + { + ds_inf("%s", __func__); + + ds_tizen_renderer_info_send_redraw(mInfo); + } + +public: + bool bSurfaceDestroyed; + bool bDestroyed; + bool bGetRendererSurface; + bool bDestroyRendererInfo; + +private: + struct ds_tizen_renderer_info *mInfo; + struct ds_surface *mSurface; + + struct NewSurfaceListener : ::wl_listener { + MockRendererCompositor *parent; + }; + NewSurfaceListener mNewSurfaceListener; + + struct DelSurfaceListener : ::wl_listener { + MockRendererCompositor *parent; + }; + DelSurfaceListener mDelSurfaceListener; + + struct ds_tizen_renderer *mRenderer; + + struct DestroyListener : ::wl_listener { + MockRendererCompositor *parent; + }; + DestroyListener mDestroyListener; + + struct GetFlusherInfoListener : ::wl_listener { + MockRendererCompositor *parent; + }; + GetFlusherInfoListener mGetFlusherInfoListener; + + struct FlusherInfoDestroyListener : ::wl_listener { + MockRendererCompositor *parent; + }; + FlusherInfoDestroyListener mRendererInfoDestroyListener; +}; + +class MockRendererClient : public MockClient +{ +public: + MockRendererClient() + : bRedrawEvent(false), + compositor_res(nullptr), + renderer_res(nullptr) + {} + MockRendererClient(const struct wl_registry_listener *listener) + : MockClient(listener, this) + { + ds_inf("%s", __func__); + + bRedrawEvent = false; + } + ~MockRendererClient() + { + ds_inf("%s", __func__); + } + + void SetWlCompositor(struct wl_compositor *global_res) + { + ds_inf("%s", __func__); + + compositor_res = global_res; + } + + struct wl_compositor *GetWlCompositor() + { + ds_inf("%s", __func__); + + return compositor_res; + } + + void SetTizenRenderer(struct tizen_renderer *resource) + { + ds_inf("%s", __func__); + + renderer_res = resource; + } + + struct tizen_renderer *GetTizenRenderer() + { + ds_inf("%s", __func__); + + return renderer_res; + } + +public: + bool bRedrawEvent; + +private: + struct wl_compositor *compositor_res; + struct tizen_renderer *renderer_res; +}; + +static void +client_registry_cb_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) +{ + ds_inf("%s", __func__); + + MockRendererClient *client = static_cast(data); + struct wl_compositor *compositor_res; + struct tizen_renderer *renderer_res; + + if (!strcmp(interface, "wl_compositor")) { + compositor_res = (struct wl_compositor *)wl_registry_bind(registry, + name, &wl_compositor_interface, 1); + if (compositor_res == nullptr) { + ds_err("wl_registry_bind() failed. wl_compositor resource."); + return; + } + client->SetWlCompositor(compositor_res); + } else if (!strcmp(interface, "tizen_renderer")) { + renderer_res = (struct tizen_renderer *)wl_registry_bind(registry, + name, &tizen_renderer_interface, TIZEN_RENDERER_VERSION); + if (renderer_res == nullptr) { + ds_err("wl_registry_bind() failed. tizen_renderer resource."); + return; + } + client->SetTizenRenderer(renderer_res); + } +} + +static void +client_registry_cb_global_remove(void *data, struct wl_registry *registry, + uint32_t name) +{ + ds_inf("%s", __func__); + + MockRendererClient *client = static_cast(data); + struct wl_compositor *compositor_res = client->GetWlCompositor(); + struct tizen_renderer *renderer_res = client->GetTizenRenderer(); + + tizen_renderer_destroy(renderer_res); + wl_compositor_destroy(compositor_res); +} + +static const struct wl_registry_listener registry_listener = { + .global = client_registry_cb_global, + .global_remove = client_registry_cb_global_remove +}; + +static void +client_tizen_renderer_surface_cb_redraw_request(void *data, + struct tizen_renderer_surface *renderer_surface_res) +{ + ds_inf("%s", __func__); + + MockRendererClient *client = static_cast(data); + + client->bRedrawEvent = true; +} + +static const struct +tizen_renderer_surface_listener renderer_surface_cb_listener = { + .redraw_request = client_tizen_renderer_surface_cb_redraw_request, +}; + +class RendererTest : public ::testing::Test +{ +public: + void SetUp(void) override; + void TearDown(void) override; + + MockRendererCompositor *comp; + MockRendererClient *client; + struct wl_compositor *compositor_res; + struct tizen_renderer *renderer_res; + struct wl_surface *surface_res; + struct tizen_renderer_surface *renderer_surface_res; +}; + +void +RendererTest::SetUp(void) +{ + //ds_log_init(DS_DBG, NULL); + + ds_inf("%s", __func__); + + comp = new MockRendererCompositor(); + client = new MockRendererClient(®istry_listener); + compositor_res = client->GetWlCompositor(); + renderer_res = client->GetTizenRenderer(); + surface_res = wl_compositor_create_surface(compositor_res); + + renderer_surface_res = + tizen_renderer_get_renderer_surface(renderer_res, surface_res); + + tizen_renderer_surface_add_listener(renderer_surface_res, + &renderer_surface_cb_listener, client); + + client->RoundTrip(); +} + +void +RendererTest::TearDown(void) +{ + ds_inf("%s", __func__); + + tizen_renderer_surface_destroy(renderer_surface_res); + client->RoundTrip(); + EXPECT_TRUE(comp->bDestroyRendererInfo); + + wl_surface_destroy(surface_res); + client->RoundTrip(); + EXPECT_TRUE(comp->bSurfaceDestroyed); + + delete client; + delete comp; +} + +TEST_F(RendererTest, Create_P) +{ + EXPECT_TRUE(true); + EXPECT_TRUE(comp->bGetRendererSurface); +} + +TEST_F(RendererTest, Ev_TizenRendererSurfaceRedraw) +{ + comp->SendRendererInfoRedraw(); + comp->Process(); + + client->RoundTrip(); + EXPECT_TRUE(client->bRedrawEvent); +} -- 2.7.4 From dfdd1dbbce29af320bc2a29f43ff5e082189ad45 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Thu, 21 Jul 2022 17:19:58 +0900 Subject: [PATCH 16/16] impelement libds-tizen-screen-rotation This is the server implementation for tizen_screen_rotation protocol. Change-Id: I5c7a71543edf8e6e12c6616cfaef8e7dec43fc01 --- include/libds-tizen/screen_rotation.h | 45 ++++++ packaging/libds-tizen.spec | 29 ++++ src/meson.build | 1 + src/screen_rotation/meson.build | 29 ++++ src/screen_rotation/screen_rotation.c | 294 ++++++++++++++++++++++++++++++++++ 5 files changed, 398 insertions(+) create mode 100644 include/libds-tizen/screen_rotation.h create mode 100644 src/screen_rotation/meson.build create mode 100644 src/screen_rotation/screen_rotation.c diff --git a/include/libds-tizen/screen_rotation.h b/include/libds-tizen/screen_rotation.h new file mode 100644 index 0000000..ad19b15 --- /dev/null +++ b/include/libds-tizen/screen_rotation.h @@ -0,0 +1,45 @@ +#ifndef LIBDS_TIZEN_SCREEN_ROTATION_H +#define LIBDS_TIZEN_SCREEN_ROTATION_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ds_tizen_screen_rotation; +struct ds_tizen_screen_rotation_info; + +struct ds_tizen_screen_rotation * +ds_tizen_screen_rotation_create(struct wl_display *display); + +void +ds_tizen_screen_rotation_add_destroy_listener( + struct ds_tizen_screen_rotation *screen_rotation, + struct wl_listener *listener); + +void +ds_tizen_screen_rotation_add_get_ignore_output_transform_info_listener( + struct ds_tizen_screen_rotation *screen_rotation, + struct wl_listener *listener); + +void +ds_tizen_screen_rotation_info_add_destroy_listener( + struct ds_tizen_screen_rotation_info *info, + struct wl_listener *listener); + +struct ds_surface * +ds_tizen_screen_rotation_info_get_surface( + struct ds_tizen_screen_rotation_info *info); + +void +ds_tizen_screen_rotation_send_ignore_output_transform( + struct ds_tizen_screen_rotation_info *info, uint32_t ignore); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packaging/libds-tizen.spec b/packaging/libds-tizen.spec index 38942c7..0dfbbd8 100644 --- a/packaging/libds-tizen.spec +++ b/packaging/libds-tizen.spec @@ -216,6 +216,21 @@ Group: Development/Libraries %description renderer-devel Development package for tizen renderer +## libds-tizen-screen-rotation +%package screen-rotation +Summary: Library for tizen screen rotation +Group: Development/Libraries + +%description screen-rotation +Library for tizen screen rotation + +%package screen-rotation-devel +Summary: Development package for tizen screen rotation +Group: Development/Libraries + +%description screen-rotation-devel +Development package for tizen screen rotation + %prep %setup -q cp %{SOURCE1001} . @@ -417,3 +432,17 @@ ninja -C builddir install %{_libdir}/pkgconfig/libds-tizen-renderer.pc %{_libdir}/libds-tizen-renderer.so %{_bindir}/libds-tizen-renderer-tests + +%files screen-rotation +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_libdir}/libds-tizen-screen-rotation.so.* + +%files screen-rotation-devel +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_includedir}/libds-tizen/screen_rotation.h +%{_libdir}/pkgconfig/libds-tizen-screen-rotation.pc +%{_libdir}/libds-tizen-screen-rotation.so diff --git a/src/meson.build b/src/meson.build index a8df30b..4fee86e 100644 --- a/src/meson.build +++ b/src/meson.build @@ -39,3 +39,4 @@ subdir('launch') subdir('display_policy') subdir('memory_flusher') subdir('renderer') +subdir('screen_rotation') diff --git a/src/screen_rotation/meson.build b/src/screen_rotation/meson.build new file mode 100644 index 0000000..4261a97 --- /dev/null +++ b/src/screen_rotation/meson.build @@ -0,0 +1,29 @@ +libds_tizen_screen_rotation_files = [ + 'screen_rotation.c', +] + +libds_tizen_screen_rotation_deps = [ + deps_libds_tizen, + dependency('tizen-extension-server', required: true), +] + +lib_libds_tizen_screen_rotation = shared_library('ds-tizen-screen-rotation', libds_tizen_screen_rotation_files, + dependencies: libds_tizen_screen_rotation_deps, + include_directories: [ common_inc, include_directories('.'), include_directories('..') ], + version: meson.project_version(), + install: true +) + +deps_libds_tizen_screen_rotation = declare_dependency( + link_with: lib_libds_tizen_screen_rotation, + dependencies: libds_tizen_screen_rotation_deps, + include_directories: [ common_inc, include_directories('.') ], +) + +pkgconfig = import('pkgconfig') +pkgconfig.generate(lib_libds_tizen_screen_rotation, + version: meson.project_version(), + filebase: 'libds-tizen-screen-rotation', + name: 'libds-tizen-screen-rotation', + description: 'tizen screen_rotation extension of libds-tizen for tizen platform', +) diff --git a/src/screen_rotation/screen_rotation.c b/src/screen_rotation/screen_rotation.c new file mode 100644 index 0000000..e4ddb6b --- /dev/null +++ b/src/screen_rotation/screen_rotation.c @@ -0,0 +1,294 @@ +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "libds-tizen/screen_rotation.h" + +#define TIZEN_SCREEN_ROTATION_VERSION 1 + +struct ds_tizen_screen_rotation +{ + struct wl_global *global; + + struct wl_list clients; + + struct wl_listener destroy; + + struct { + struct wl_signal destroy; + struct wl_signal get_ignore_output_transfrom; + } events; +}; + +struct ds_tizen_screen_rotation_client +{ + struct ds_tizen_screen_rotation *screen_rotation; + + struct wl_resource *resource; + struct wl_client *wl_client; + + struct wl_list infos; + + struct { + struct wl_signal destroy; + } events; + + struct wl_list link; // ds_tizen_screen_rotation::clients +}; + +struct ds_tizen_screen_rotation_info +{ + struct ds_tizen_screen_rotation_client *client; + + struct ds_surface *surface; + + struct wl_list link; // ds_tizen_screen_rotation_client::infos +}; + +static void screen_rotation_handle_display_destroy(struct wl_listener *listener, + void *data); + +static void screen_rotation_bind(struct wl_client *wl_client, void *data, + uint32_t version, uint32_t id); + +static struct ds_tizen_screen_rotation_info *tizen_screen_rotation_client_find_info( + struct ds_tizen_screen_rotation_client *client, + struct ds_surface *surface); + +static struct ds_tizen_screen_rotation_info *tizen_screen_rotation_client_get_info( + struct ds_tizen_screen_rotation_client *client, + struct ds_surface *surface); + +WL_EXPORT struct ds_tizen_screen_rotation * +ds_tizen_screen_rotation_create(struct wl_display *display) +{ + struct ds_tizen_screen_rotation *screen_rotation; + + screen_rotation = calloc(1, sizeof *screen_rotation); + if (!screen_rotation) { + ds_err("calloc() failed."); + return NULL; + } + + screen_rotation->global = wl_global_create(display, + &tizen_screen_rotation_interface, TIZEN_SCREEN_ROTATION_VERSION, + screen_rotation, screen_rotation_bind); + if (!screen_rotation->global) { + ds_err("wl_global_create() failed. tizen_screen_rotation_interface"); + free(screen_rotation); + return NULL; + } + + wl_list_init(&screen_rotation->clients); + + screen_rotation->destroy.notify = screen_rotation_handle_display_destroy; + wl_display_add_destroy_listener(display, &screen_rotation->destroy); + + wl_signal_init(&screen_rotation->events.destroy); + wl_signal_init(&screen_rotation->events.get_ignore_output_transfrom); + + ds_inf("Global created: tizen_screen_rotation(%p)", screen_rotation); + + return screen_rotation; +} + +WL_EXPORT void +ds_tizen_screen_rotation_add_destroy_listener( + struct ds_tizen_screen_rotation *screen_rotation, + struct wl_listener *listener) +{ + wl_signal_add(&screen_rotation->events.destroy, listener); +} + +WL_EXPORT void +ds_tizen_screen_rotation_add_get_ignore_output_transform_info_listener( + struct ds_tizen_screen_rotation *screen_rotation, + struct wl_listener *listener) +{ + wl_signal_add(&screen_rotation->events.get_ignore_output_transfrom, + listener); +} + +WL_EXPORT void +ds_tizen_screen_rotation_info_add_destroy_listener( + struct ds_tizen_screen_rotation_info *info, + struct wl_listener *listener) +{ + wl_signal_add(&info->client->events.destroy, listener); +} + +WL_EXPORT struct ds_surface * +ds_tizen_screen_rotation_info_get_surface( + struct ds_tizen_screen_rotation_info *info) +{ + return info->surface; +} + +WL_EXPORT void +ds_tizen_screen_rotation_send_ignore_output_transform( + struct ds_tizen_screen_rotation_info *info, uint32_t ignore) +{ + tizen_screen_rotation_send_ignore_output_transform(info->client->resource, + ds_surface_get_wl_resource(info->surface), ignore); +} + +static struct ds_tizen_screen_rotation_info * +tizen_screen_rotation_client_find_info(struct ds_tizen_screen_rotation_client *client, + struct ds_surface *surface) +{ + struct ds_tizen_screen_rotation_info *info; + + wl_list_for_each(info, &client->infos, link) { + if (surface == info->surface) + return info; + } + + return NULL; +} + +static struct ds_tizen_screen_rotation_info * +tizen_screen_rotation_client_get_info(struct ds_tizen_screen_rotation_client *client, + struct ds_surface *surface) +{ + struct ds_tizen_screen_rotation_info *info; + + info = tizen_screen_rotation_client_find_info(client, surface); + if (info) + return info; + + info = calloc(1, sizeof *info); + if (info == NULL) { + ds_err("calloc() failed. tizen_screen_rotation"); + return NULL; + } + + info->client = client; + info->surface = surface; + + wl_list_insert(&client->infos, &info->link); + + return info; +} + +static void +screen_rotation_handle_display_destroy(struct wl_listener *listener, void *data) +{ + struct ds_tizen_screen_rotation *screen_rotation; + + screen_rotation = wl_container_of(listener, screen_rotation, destroy); + + ds_inf("Global destroy: screen_rotation(%p)", screen_rotation); + + wl_signal_emit(&screen_rotation->events.destroy, screen_rotation); + wl_list_remove(&screen_rotation->destroy.link); + wl_global_destroy(screen_rotation->global); + free(screen_rotation); +} + +static void +screen_rotation_handle_destroy(struct wl_client *wl_client, + struct wl_resource *resource) +{ + struct ds_tizen_screen_rotation_client *client; + + client = wl_resource_get_user_data(resource); + + if (!wl_list_empty(&client->infos)) { + ds_err("tizen_screen_rotation was destroyed before children"); + return; + } + + wl_resource_destroy(resource); +} + +static void +screen_rotation_handle_get_ignore_output_transfrom(struct wl_client *wl_client, + struct wl_resource *resource, struct wl_resource *surface_resource) +{ + struct ds_tizen_screen_rotation_client *client; + struct ds_tizen_screen_rotation_info *info; + struct ds_surface *surface; + + ds_inf("tizen_screen_rotation: get_ignore_output_transfrom"); + + client = wl_resource_get_user_data(resource); + surface = ds_surface_from_resource(surface_resource); + + info = tizen_screen_rotation_client_get_info(client, surface); + if (info == NULL) { + ds_err("tizen_screen_rotation_client_get_info() failed. tizen_screen_rotation"); + wl_client_post_no_memory(wl_client); + return; + } + + wl_signal_emit(&client->screen_rotation->events.get_ignore_output_transfrom, info); +} + +static const struct tizen_screen_rotation_interface screen_rotation_impl = +{ + screen_rotation_handle_get_ignore_output_transfrom, + screen_rotation_handle_destroy, +}; + +static void +_tizen_screen_rotation_client_handle_destroy(struct wl_resource *resource) +{ + struct ds_tizen_screen_rotation_client *client; + struct ds_tizen_screen_rotation_info *info, *tmp; + + client = wl_resource_get_user_data(resource); + + ds_inf("_tizen_screen_rotation_client_handle_destroy (client:%p)", client); + + wl_list_for_each_safe(info, tmp, &client->infos, link) { + wl_signal_emit(&client->events.destroy, info); + wl_list_remove(&info->link); + free(info); + } + + wl_list_remove(&client->link); + free(client); +} + +static void +screen_rotation_bind(struct wl_client *wl_client, void *data, uint32_t version, + uint32_t id) +{ + struct ds_tizen_screen_rotation *screen_rotation = data; + struct ds_tizen_screen_rotation_client *client; + + client = calloc(1, sizeof *client); + if (client == NULL) { + ds_err("calloc() failed. tizen_screen_rotation"); + wl_client_post_no_memory(wl_client); + return; + } + + ds_inf("tizen_screen_rotation_client binds. (client:%p)", client); + + client->screen_rotation = screen_rotation; + client->wl_client = wl_client; + + wl_list_init(&client->infos); + + client->resource = wl_resource_create(wl_client, &tizen_screen_rotation_interface, + MIN(version, TIZEN_SCREEN_ROTATION_VERSION), id); + + if (client->resource == NULL) { + ds_err("tizen_screen_rotation : wl_resource_create() failed."); + free(client); + wl_client_post_no_memory(wl_client); + return; + } + + wl_resource_set_implementation(client->resource, &screen_rotation_impl, client, + _tizen_screen_rotation_client_handle_destroy); + + wl_signal_init(&client->events.destroy); + + wl_list_insert(&screen_rotation->clients, &client->link); +} -- 2.7.4