From 0f40c7fd5346b9f673b580b193ceaed1e4740239 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Wed, 7 Sep 2022 15:20:02 +0900 Subject: [PATCH 01/16] change get_subsurface_watcher to new_subsurface_watcher change the symbol names Change-Id: I05c21fedb75ebdc4fca9f23bad62df0a022de6c8 --- examples/tinyds-tdm.c | 20 ++++++++++---------- include/libds-tizen/policy.h | 4 ++-- src/policy/policy.c | 12 ++++++------ tests/tc_policy.cpp | 30 +++++++++++++++--------------- 4 files changed, 33 insertions(+), 33 deletions(-) diff --git a/examples/tinyds-tdm.c b/examples/tinyds-tdm.c index d0cac7d..2108efc 100644 --- a/examples/tinyds-tdm.c +++ b/examples/tinyds-tdm.c @@ -135,7 +135,7 @@ struct tinyds_policy_surface struct wl_listener set_floating_mode; struct wl_listener unset_floating_mode; struct wl_listener set_stack_mode; - struct wl_listener get_subsurface_watcher; + struct wl_listener new_subsurface_watcher; struct wl_listener set_parent; struct wl_listener ack_conformant_region; struct wl_listener set_video; @@ -2956,16 +2956,16 @@ policy_surface_handle_set_stack_mode(struct wl_listener *listener, void *data) } static void -policy_surface_handle_get_subsurface_watcher(struct wl_listener *listener, void *data) +policy_surface_handle_new_subsurface_watcher(struct wl_listener *listener, void *data) { struct tinyds_policy_surface *policy_surface; struct tinyds_policy_subsurface_watcher*subsurface_watcher; - struct ds_tizen_event_policy_surface_get_subsurface_watcher *event; + struct ds_tizen_event_policy_surface_new_subsurface_watcher *event; - policy_surface = wl_container_of(listener, policy_surface, get_subsurface_watcher); - event = (struct ds_tizen_event_policy_surface_get_subsurface_watcher *)data; + policy_surface = wl_container_of(listener, policy_surface, new_subsurface_watcher); + event = (struct ds_tizen_event_policy_surface_new_subsurface_watcher *)data; - ds_inf("Policy Info(%p) get_subsurface_watcher", policy_surface); + ds_inf("Policy Info(%p) new_subsurface_watcher", policy_surface); subsurface_watcher = calloc(1, sizeof *subsurface_watcher); if (!subsurface_watcher) @@ -3187,10 +3187,10 @@ policy_handle_new_surface(struct wl_listener *listener, void *data) ds_tizen_policy_surface_add_set_stack_mode_listener(policy_surface->policy_surface, &policy_surface->set_stack_mode); - policy_surface->get_subsurface_watcher.notify = - policy_surface_handle_get_subsurface_watcher; - ds_tizen_policy_surface_add_get_subsurface_watcher_listener( - policy_surface->policy_surface, &policy_surface->get_subsurface_watcher); + policy_surface->new_subsurface_watcher.notify = + policy_surface_handle_new_subsurface_watcher; + ds_tizen_policy_surface_add_new_subsurface_watcher_listener( + policy_surface->policy_surface, &policy_surface->new_subsurface_watcher); policy_surface->set_parent.notify = policy_surface_handle_set_parent; ds_tizen_policy_surface_add_set_parent_listener(policy_surface->policy_surface, diff --git a/include/libds-tizen/policy.h b/include/libds-tizen/policy.h index dd3d313..5066e41 100644 --- a/include/libds-tizen/policy.h +++ b/include/libds-tizen/policy.h @@ -295,7 +295,7 @@ struct ds_tizen_event_policy_surface_set_stack_mode enum ds_tizen_policy_stack_mode mode; }; -struct ds_tizen_event_policy_surface_get_subsurface_watcher +struct ds_tizen_event_policy_surface_new_subsurface_watcher { struct ds_tizen_policy_surface *policy_surface; struct ds_tizen_policy_subsurface_watcher *subsurface_watcher; @@ -538,7 +538,7 @@ ds_tizen_policy_surface_add_set_stack_mode_listener( struct wl_listener *listener); void -ds_tizen_policy_surface_add_get_subsurface_watcher_listener( +ds_tizen_policy_surface_add_new_subsurface_watcher_listener( struct ds_tizen_policy_surface *policy_surface, struct wl_listener *listener); diff --git a/src/policy/policy.c b/src/policy/policy.c index 87cd4a1..c2acb39 100644 --- a/src/policy/policy.c +++ b/src/policy/policy.c @@ -101,7 +101,7 @@ struct ds_tizen_policy_surface struct wl_signal set_floating_mode; struct wl_signal unset_floating_mode; struct wl_signal set_stack_mode; - struct wl_signal get_subsurface_watcher; + struct wl_signal new_subsurface_watcher; struct wl_signal set_parent; struct wl_signal ack_conformant_region; struct wl_signal set_video; @@ -521,11 +521,11 @@ ds_tizen_policy_surface_add_set_stack_mode_listener( } WL_EXPORT void -ds_tizen_policy_surface_add_get_subsurface_watcher_listener( +ds_tizen_policy_surface_add_new_subsurface_watcher_listener( struct ds_tizen_policy_surface *policy_surface, struct wl_listener *listener) { - wl_signal_add(&policy_surface->events.get_subsurface_watcher, listener); + wl_signal_add(&policy_surface->events.new_subsurface_watcher, listener); } WL_EXPORT void @@ -971,7 +971,7 @@ tizen_policy_client_get_surface(struct wl_resource *resource, wl_signal_init(&policy_surface->events.set_floating_mode); wl_signal_init(&policy_surface->events.unset_floating_mode); wl_signal_init(&policy_surface->events.set_stack_mode); - wl_signal_init(&policy_surface->events.get_subsurface_watcher); + wl_signal_init(&policy_surface->events.new_subsurface_watcher); wl_signal_init(&policy_surface->events.set_parent); wl_signal_init(&policy_surface->events.ack_conformant_region); wl_signal_init(&policy_surface->events.set_video); @@ -2018,11 +2018,11 @@ policy_handle_get_subsurface_watcher(struct wl_client *wl_client, &subsurface_watcher_impl, subsurface_watcher, _tizen_policy_subsurface_watcher_handle_destroy); - struct ds_tizen_event_policy_surface_get_subsurface_watcher event = { + struct ds_tizen_event_policy_surface_new_subsurface_watcher event = { .policy_surface = policy_surface, .subsurface_watcher = subsurface_watcher, }; - wl_signal_emit(&policy_surface->events.get_subsurface_watcher, &event); + wl_signal_emit(&policy_surface->events.new_subsurface_watcher, &event); } static void diff --git a/tests/tc_policy.cpp b/tests/tc_policy.cpp index dd2296f..d38152e 100644 --- a/tests/tc_policy.cpp +++ b/tests/tc_policy.cpp @@ -366,10 +366,10 @@ public: ds_tizen_policy_surface_add_set_stack_mode_listener(policy_surface, &mSetStackModeListener); - mGetSubsurfaceWatcherListener.notify = MockPolicySurface::GetSubsurfaceWatcherCallback; - mGetSubsurfaceWatcherListener.parent = this; - ds_tizen_policy_surface_add_get_subsurface_watcher_listener(policy_surface, - &mGetSubsurfaceWatcherListener); + mNewSubsurfaceWatcherListener.notify = MockPolicySurface::NewSubsurfaceWatcherCallback; + mNewSubsurfaceWatcherListener.parent = this; + ds_tizen_policy_surface_add_new_subsurface_watcher_listener(policy_surface, + &mNewSubsurfaceWatcherListener); mSetParentListener.notify = MockPolicySurface::SetParentCallback; mSetParentListener.parent = this; @@ -742,17 +742,17 @@ public: policySurface->mStackMode = event->mode; } - static void GetSubsurfaceWatcherCallback(struct wl_listener *listener, void *data) + static void NewSubsurfaceWatcherCallback(struct wl_listener *listener, void *data) { MockPolicySurface *policySurface = - reinterpret_cast(listener)->parent; - struct ds_tizen_event_policy_surface_get_subsurface_watcher *event = - static_cast(data); + reinterpret_cast(listener)->parent; + struct ds_tizen_event_policy_surface_new_subsurface_watcher *event = + static_cast(data); EXPECT_TRUE(policySurface->mPolicySurface == event->policy_surface); EXPECT_TRUE(event->subsurface_watcher != NULL); - policySurface->bGetSubsurfaceWatcher = true; + policySurface->bNewSubsurfaceWatcher = true; MockPolicySubsurfaceWatcher *policySubsurfaceWatcher = new MockPolicySubsurfaceWatcher(event->subsurface_watcher); @@ -850,7 +850,7 @@ public: return mPolicyPosition; } - MockPolicySubsurfaceWatcher*GetSubsurfaceWatcher() + MockPolicySubsurfaceWatcher*NewSubsurfaceWatcher() { return mPolicySubsurfaceWatcher; } @@ -922,7 +922,7 @@ public: bool bGetSupportedAuxHints; bool bSetFloatingMode; enum ds_tizen_policy_stack_mode mStackMode; - bool bGetSubsurfaceWatcher; + bool bNewSubsurfaceWatcher; struct ds_surface *mParentSurface; uint32_t mSerial; bool bVideo; @@ -1061,10 +1061,10 @@ private: }; SetStackModeListener mSetStackModeListener; - struct GetSubsurfaceWatcherListener : ::wl_listener { + struct NewSubsurfaceWatcherListener : ::wl_listener { MockPolicySurface *parent; }; - GetSubsurfaceWatcherListener mGetSubsurfaceWatcherListener; + NewSubsurfaceWatcherListener mNewSubsurfaceWatcherListener; struct SetParentListener : ::wl_listener { MockPolicySurface *parent; @@ -2718,7 +2718,7 @@ TEST_F(PolicyTest, Req_PolicySurfaceSetStackMode) EXPECT_TRUE(policy_surface->bSetFloatingMode == true); } -TEST_F(PolicyTest, Req_PolicySurfaceGetSubsurfaceWatcher) +TEST_F(PolicyTest, Req_PolicySurfaceNewSubsurfaceWatcher) { MockPolicySurface *policy_surface; uint32_t surface_res_id; @@ -2732,7 +2732,7 @@ TEST_F(PolicyTest, Req_PolicySurfaceGetSubsurfaceWatcher) surface_res_id = wl_proxy_get_id((struct wl_proxy *)surface_res); policy_surface = comp->FindPolicySurfaceWidthResId(surface_res_id); - EXPECT_TRUE(policy_surface->bGetSubsurfaceWatcher == true); + EXPECT_TRUE(policy_surface->bNewSubsurfaceWatcher == true); tizen_subsurface_watcher_destroy(subsuface_watcher_res); } -- 2.7.4 From 2249b48be116ebd6bac2b9a4fe72f51e63b2a540 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Wed, 7 Sep 2022 15:59:23 +0900 Subject: [PATCH 02/16] tizen_policy: check the client's version of TIZEN_POLICY_CONFORMANT_REGION event Change-Id: Iaa6cd9fcc7e99933f8ff6f4a4ed9eee039d564d9 --- src/policy/policy.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/policy/policy.c b/src/policy/policy.c index c2acb39..95b9e02 100644 --- a/src/policy/policy.c +++ b/src/policy/policy.c @@ -638,9 +638,17 @@ ds_tizen_policy_surface_send_conformant_area(struct ds_tizen_policy_surface *pol return; } - tizen_policy_send_conformant_area(policy_surface->client->resource, - ds_surface_get_wl_resource(policy_surface->surface), conformant_part, visible, - x, y, w, h); + if (wl_resource_get_version(policy_surface->client->resource) >= + TIZEN_POLICY_CONFORMANT_REGION_SINCE_VERSION) { + tizen_policy_send_conformant_area(policy_surface->client->resource, + ds_surface_get_wl_resource(policy_surface->surface), conformant_part, visible, + x, y, w, h); + } else { + ds_err("client does not support TIZEN_POLICY_CONFORMANT_REGION." + "client version(%d) < server version(%d)", + wl_resource_get_version(policy_surface->client->resource), + TIZEN_POLICY_CONFORMANT_REGION_SINCE_VERSION); + } } WL_EXPORT void -- 2.7.4 From 82fd81f9fb4a00b01ddbe79fb69813a3d7d07436 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Tue, 6 Sep 2022 16:43:38 +0900 Subject: [PATCH 03/16] example: check if a input_method_context is null. Change-Id: I284fec4336d6235e2f8c88985c8965a6448fd6e7 --- examples/tinyds-tdm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/tinyds-tdm.c b/examples/tinyds-tdm.c index 2108efc..a797ca2 100644 --- a/examples/tinyds-tdm.c +++ b/examples/tinyds-tdm.c @@ -2513,6 +2513,10 @@ add_new_input_method_context(struct tinyds_input_method *input_method, context->input = text_input; context->context = ds_tizen_input_method_create_context(input_method->input_method); + if (context->context == NULL) { + ds_err("ds_tizen_input_method_create_context() failed."); + return false; + } context->destroy.notify = context_handle_destroy; ds_tizen_input_method_context_add_destroy_listener(context->context, -- 2.7.4 From de708ef11ae0031b65bce4d1b8806218c659cf6d Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Tue, 6 Sep 2022 16:44:56 +0900 Subject: [PATCH 04/16] input_method: check if a resource of input_method is null. Change-Id: I5932828b6ca1fefbdb81c2d747856d0761e5bd5b --- src/input_method/input_method.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/input_method/input_method.c b/src/input_method/input_method.c index 138193f..0c16b28 100644 --- a/src/input_method/input_method.c +++ b/src/input_method/input_method.c @@ -227,7 +227,10 @@ ds_tizen_input_method_create_context(struct ds_tizen_input_method *input_method) } binding = input_method->resource; - if (!binding) return NULL; + if (!binding) { + ds_err("context. there is no wl_resource_create() failed."); + return NULL; + } context->resource = wl_resource_create(wl_resource_get_client(binding), &zwp_input_method_context_v1_interface, INPUT_METHOD_VERSION, 0); if (context->resource == NULL) { -- 2.7.4 From a1a2e37791799079e18dee03e952c2ab9ecc64e2 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Tue, 6 Sep 2022 16:46:30 +0900 Subject: [PATCH 05/16] text_input: add dummy implementation of tizen only handlers to avoid a crash from a client's request. Change-Id: Ie224f2437fa38aad83fa983e32feb088df1ecc7e --- src/text_input/text_input.c | 154 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 139 insertions(+), 15 deletions(-) diff --git a/src/text_input/text_input.c b/src/text_input/text_input.c index d25b1a4..ad4bcf2 100644 --- a/src/text_input/text_input.c +++ b/src/text_input/text_input.c @@ -354,6 +354,130 @@ text_input_handle_invoke_action(struct wl_client *client, wl_signal_emit(&text_input->events.invoke_action, &ds_event); } +static void +text_input_handle_set_return_key_type(struct wl_client *client, + struct wl_resource *resource, uint32_t return_key_type) +{ + // TODO: + ds_inf("Not Implemented. text_input_handle_set_return_key_type"); +} + +static void +text_input_handle_set_return_key_disabled(struct wl_client *client, + struct wl_resource *resource, uint32_t return_key_disabled) +{ + // TODO: + ds_inf("Not Implemented. text_input_handle_set_return_key_disabled"); +} + +static void +text_input_handle_set_input_panel_data(struct wl_client *client, + struct wl_resource *resource, const char *input_panel_data, + uint32_t input_panel_length) +{ + // TODO: + ds_inf("Not Implemented. text_input_handle_set_input_panel_data"); +} + +static void +text_input_handle_bidi_direction(struct wl_client *client, + struct wl_resource *resource, uint32_t direction) +{ + // TODO: + ds_inf("Not Implemented. text_input_handle_bidi_direction"); +} + +static void +text_input_handle_set_cursor_position(struct wl_client *client, + struct wl_resource *resource, uint32_t cursor_position) +{ + // TODO: + ds_inf("Not Implemented. text_input_handle_set_cursor_position"); +} + +static void +text_input_handle_process_input_device_event(struct wl_client *client, + struct wl_resource *resource, uint32_t event_type, const char *event_data, + uint32_t event_length) +{ + // TODO: + ds_inf("Not Implemented. text_input_handle_process_input_device_event"); +} + +static void +text_input_handle_filter_key_event(struct wl_client *client, + struct wl_resource *resource, uint32_t serial, uint32_t time, + const char *keyname, uint32_t modifiers, const char *dev_name, + uint32_t dev_class, uint32_t dev_subclass, uint32_t keycode) +{ + // TODO: + ds_inf("Not Implemented. text_input_handle_filter_key_event"); +} + +static void +text_input_handle_get_hide_permission(struct wl_client *client, + struct wl_resource *resource) +{ + // TODO: + ds_inf("Not Implemented. text_input_handle_get_hide_permission"); +} + +static void +text_input_handle_set_capital_mode(struct wl_client *client, + struct wl_resource *resource, uint32_t mode) +{ + // TODO: + ds_inf("Not Implemented. text_input_handle_set_capital_mode"); +} + +static void +text_input_handle_prediction_hint(struct wl_client *client, + struct wl_resource *resource, const char *text) +{ + // TODO: + ds_inf("Not Implemented. text_input_handle_prediction_hint"); +} + +static void +text_input_handle_set_mime_type(struct wl_client *client, + struct wl_resource *resource, const char *type) +{ + // TODO: + ds_inf("Not Implemented. text_input_handle_set_mime_type"); +} + +static void +text_input_handle_set_input_panel_position(struct wl_client *client, + struct wl_resource *resource, uint32_t x, uint32_t y) +{ + // TODO: + ds_inf("Not Implemented. text_input_handle_set_input_panel_position"); +} + +static void +text_input_handle_finalize_content(struct wl_client *client, + struct wl_resource *resource, const char *text, uint32_t cursor_position) +{ + // TODO: + ds_inf("Not Implemented. text_input_handle_finalize_content"); +} + +static void +text_input_handle_prediction_hint_data(struct wl_client *client, + struct wl_resource *resource, const char *key, const char *value) +{ + // TODO: + ds_inf("Not Implemented. text_input_handle_prediction_hint_data"); +} + +static void +text_input_handle_input_panel_enabled(struct wl_client *client, + struct wl_resource *resource, uint32_t enabled) +{ + // TODO: + ds_inf("Not Implemented. text_input_handle_input_panel_enabled"); +} + static const struct wl_text_input_interface text_input_impl = { .destroy = text_input_handle_destroy, .activate = text_input_handle_activate, @@ -367,21 +491,21 @@ static const struct wl_text_input_interface text_input_impl = { .commit_state = text_input_handle_commit_state, .invoke_action = text_input_handle_invoke_action, //for tizen only - .set_return_key_type = NULL, - .set_return_key_disabled = NULL, - .set_input_panel_data = NULL, - .bidi_direction = NULL, - .set_cursor_position = NULL, - .process_input_device_event = NULL, - .filter_key_event = NULL, - .get_hide_permission = NULL, - .set_capital_mode = NULL, - .prediction_hint = NULL, - .set_mime_type = NULL, - .set_input_panel_position = NULL, - .finalize_content = NULL, - .prediction_hint_data = NULL, - .input_panel_enabled = NULL, + .set_return_key_type = text_input_handle_set_return_key_type, + .set_return_key_disabled = text_input_handle_set_return_key_disabled, + .set_input_panel_data = text_input_handle_set_input_panel_data, + .bidi_direction = text_input_handle_bidi_direction, + .set_cursor_position = text_input_handle_set_cursor_position, + .process_input_device_event = text_input_handle_process_input_device_event, + .filter_key_event = text_input_handle_filter_key_event, + .get_hide_permission = text_input_handle_get_hide_permission, + .set_capital_mode = text_input_handle_set_capital_mode, + .prediction_hint = text_input_handle_prediction_hint, + .set_mime_type = text_input_handle_set_mime_type, + .set_input_panel_position = text_input_handle_set_input_panel_position, + .finalize_content = text_input_handle_finalize_content, + .prediction_hint_data = text_input_handle_prediction_hint_data, + .input_panel_enabled = text_input_handle_input_panel_enabled, }; static void -- 2.7.4 From 9a4e6e809615a83d8ad45695332629b49b34413f Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Wed, 7 Sep 2022 17:16:27 +0900 Subject: [PATCH 06/16] fix the memory leak Change-Id: I58f5eb7d5ec611e41d78e2110a1d20fe1ee6b0da --- src/input_method/input_method.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/input_method/input_method.c b/src/input_method/input_method.c index 0c16b28..d2e6cbb 100644 --- a/src/input_method/input_method.c +++ b/src/input_method/input_method.c @@ -228,7 +228,8 @@ ds_tizen_input_method_create_context(struct ds_tizen_input_method *input_method) binding = input_method->resource; if (!binding) { - ds_err("context. there is no wl_resource_create() failed."); + ds_err("context. there is no resource of input_method."); + free(context); return NULL; } context->resource = wl_resource_create(wl_resource_get_client(binding), -- 2.7.4 From 64e627968bb6ec889e1387f2ae4ccb819acabbea Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Tue, 13 Sep 2022 10:25:38 +0900 Subject: [PATCH 07/16] text_input: Add a missing parameter This is to silence a warning. Change-Id: I0a8291a194a7bea1f8c651230e732f092bc31540 --- src/text_input/text_input.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/text_input/text_input.c b/src/text_input/text_input.c index ad4bcf2..709cadb 100644 --- a/src/text_input/text_input.c +++ b/src/text_input/text_input.c @@ -407,8 +407,9 @@ text_input_handle_process_input_device_event(struct wl_client *client, static void text_input_handle_filter_key_event(struct wl_client *client, struct wl_resource *resource, uint32_t serial, uint32_t time, - const char *keyname, uint32_t modifiers, const char *dev_name, - uint32_t dev_class, uint32_t dev_subclass, uint32_t keycode) + const char *keyname, uint32_t state, uint32_t modifiers, + const char *dev_name, uint32_t dev_class, uint32_t dev_subclass, + uint32_t keycode) { // TODO: ds_inf("Not Implemented. text_input_handle_filter_key_event"); -- 2.7.4 From 13ae5fb81f8193d65a4eccfbf624a4fd2936dfd6 Mon Sep 17 00:00:00 2001 From: Junkyeong Kim Date: Wed, 7 Sep 2022 17:33:30 +0900 Subject: [PATCH 08/16] Init tizen-screenshooter Change-Id: I438cd7e690f93bc9f64894c968bbd8dedcc7c919 Signed-off-by: Junkyeong Kim --- include/libds-tizen/screenshooter.h | 97 +++++ packaging/libds-tizen.spec | 30 ++ src/meson.build | 1 + src/screenshooter/meson.build | 31 ++ src/screenshooter/screenmirror.c | 247 ++++++++++++ src/screenshooter/screenshooter.c | 215 +++++++++++ src/screenshooter/screenshooter.h | 62 +++ tests/meson.build | 20 + tests/tc_screenshooter.cpp | 747 ++++++++++++++++++++++++++++++++++++ 9 files changed, 1450 insertions(+) create mode 100644 include/libds-tizen/screenshooter.h create mode 100644 src/screenshooter/meson.build create mode 100644 src/screenshooter/screenmirror.c create mode 100644 src/screenshooter/screenshooter.c create mode 100644 src/screenshooter/screenshooter.h create mode 100644 tests/tc_screenshooter.cpp diff --git a/include/libds-tizen/screenshooter.h b/include/libds-tizen/screenshooter.h new file mode 100644 index 0000000..d16b899 --- /dev/null +++ b/include/libds-tizen/screenshooter.h @@ -0,0 +1,97 @@ +#ifndef LIBDS_TIZEN_SCREENSHOOTER_H +#define LIBDS_TIZEN_SCREENSHOOTER_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ds_tizen_screenshooter; +struct ds_tizen_screenmirror; +struct ds_tizen_screenshooter_client; + +enum ds_tizen_screenmirror_stretch +{ + DS_TIZEN_SCREENMIRROR_STRETCH_KEEP_RATIO, + DS_TIZEN_SCREENMIRROR_STRETCH_FULLY, +}; + +enum ds_tizen_screenmirror_content +{ + DS_TIZEN_SCREENMIRROR_CONTENT_NORMAL, + DS_TIZEN_SCREENMIRROR_CONTENT_VIDEO, +}; + +struct ds_tizen_screenshooter_shoot_event +{ + struct ds_output *output; + struct ds_buffer *buffer; + struct ds_tizen_screenshooter_client *client; + bool auto_rotation; +}; + +struct ds_tizen_screenshooter * +ds_tizen_screenshooter_create(struct wl_display *display); + +void +ds_tizen_screenshooter_add_destroy_listener(struct ds_tizen_screenshooter *shot, + struct wl_listener *listener); + +void +ds_tizen_screenshooter_add_get_screenmirror_listener(struct ds_tizen_screenshooter *shot, + struct wl_listener *listener); + +void +ds_tizen_screenshooter_add_shoot_listener(struct ds_tizen_screenshooter *shot, + struct wl_listener *listener); + +void +ds_tizen_screenshooter_send_shoot_done(struct ds_tizen_screenshooter *shot, + struct ds_tizen_screenshooter_client *client); + +void +ds_tizen_screenmirror_add_destroy_listener(struct ds_tizen_screenmirror *mirror, + struct wl_listener *listener); + +void +ds_tizen_screenmirror_add_set_stretch_listener(struct ds_tizen_screenmirror *mirror, + struct wl_listener *listener); + +void +ds_tizen_screenmirror_add_queue_listener(struct ds_tizen_screenmirror *mirror, + struct wl_listener *listener); + +void +ds_tizen_screenmirror_add_dequeue_listener(struct ds_tizen_screenmirror *mirror, + struct wl_listener *listener); + +void +ds_tizen_screenmirror_add_start_listener(struct ds_tizen_screenmirror *mirror, + struct wl_listener *listener); + +void +ds_tizen_screenmirror_add_stop_listener(struct ds_tizen_screenmirror *mirror, + struct wl_listener *listener); + +void +ds_tizen_screenmirror_add_auto_rotation_listener(struct ds_tizen_screenmirror *mirror, + struct wl_listener *listener); + +void +ds_tizen_screenmirror_send_content(struct ds_tizen_screenmirror *mirror, + enum ds_tizen_screenmirror_content content); + +void +ds_tizen_screenmirror_send_dequeued(struct ds_tizen_screenmirror *mirror, + struct ds_buffer *buffer); + +void +ds_tizen_screenmirror_send_stop(struct ds_tizen_screenmirror *mirror); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packaging/libds-tizen.spec b/packaging/libds-tizen.spec index e1d4c25..485abfc 100644 --- a/packaging/libds-tizen.spec +++ b/packaging/libds-tizen.spec @@ -327,6 +327,21 @@ Group: Development/Libraries %description policy-devel Development package for tizen policy +## libds-tizen-screenshooter +%package screenshooter +Summary: Library for tizen screenshooter +Group: Development/Libraries + +%description screenshooter +Library for tizen screenshooter + +%package screenshooter-devel +Summary: Development package for tizen screenshooter +Group: Development/Libraries + +%description screenshooter-devel +Development package for tizen screenshooter + %prep %setup -q cp %{SOURCE1001} . @@ -631,3 +646,18 @@ ninja -C builddir install %{_libdir}/pkgconfig/libds-tizen-policy.pc %{_libdir}/libds-tizen-policy.so %{_bindir}/libds-tizen-policy-tests + +%files screenshooter +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_libdir}/libds-tizen-screenshooter.so.* + +%files screenshooter-devel +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_includedir}/libds-tizen/screenshooter.h +%{_libdir}/pkgconfig/libds-tizen-screenshooter.pc +%{_libdir}/libds-tizen-screenshooter.so +%{_bindir}/libds-tizen-screenshooter-tests diff --git a/src/meson.build b/src/meson.build index 227b7a9..9cc81b5 100644 --- a/src/meson.build +++ b/src/meson.build @@ -46,3 +46,4 @@ subdir('input_method') subdir('text_input') subdir('hwc') subdir('policy') +subdir('screenshooter') diff --git a/src/screenshooter/meson.build b/src/screenshooter/meson.build new file mode 100644 index 0000000..4a5f619 --- /dev/null +++ b/src/screenshooter/meson.build @@ -0,0 +1,31 @@ +libds_tizen_screenshooter_files = [ + 'screenshooter.c', + 'screenmirror.c', +] + +libds_tizen_screenshooter_deps = [ + deps_libds_tizen, + dependency('tizen-extension-server', required: true), + dependency('wayland-tbm-server', required: true), +] + +lib_libds_tizen_screenshooter = shared_library('ds-tizen-screenshooter', libds_tizen_screenshooter_files, + dependencies: libds_tizen_screenshooter_deps, + include_directories: [ common_inc, include_directories('.'), include_directories('..') ], + version: meson.project_version(), + install: true +) + +deps_libds_tizen_screenshooter = declare_dependency( + link_with: lib_libds_tizen_screenshooter, + dependencies: libds_tizen_screenshooter_deps, + include_directories: [ common_inc, include_directories('.') ], +) + +pkgconfig = import('pkgconfig') +pkgconfig.generate(lib_libds_tizen_screenshooter, + version: meson.project_version(), + filebase: 'libds-tizen-screenshooter', + name: 'libds-tizen-screenshooter', + description: 'tizen screenshooter extension of libds-tizen for tizen platform', +) diff --git a/src/screenshooter/screenmirror.c b/src/screenshooter/screenmirror.c new file mode 100644 index 0000000..4d15d87 --- /dev/null +++ b/src/screenshooter/screenmirror.c @@ -0,0 +1,247 @@ +#include +#include "screenshooter.h" +#include "util.h" + +static const struct tizen_screenmirror_interface _screenmirror_interface; + +WL_EXPORT void +ds_tizen_screenmirror_add_destroy_listener(struct ds_tizen_screenmirror *mirror, + struct wl_listener *listener) +{ + wl_signal_add(&mirror->events.destroy, listener); +} + +WL_EXPORT void +ds_tizen_screenmirror_add_set_stretch_listener(struct ds_tizen_screenmirror *mirror, + struct wl_listener *listener) +{ + wl_signal_add(&mirror->events.set_stretch, listener); +} + +WL_EXPORT void +ds_tizen_screenmirror_add_queue_listener(struct ds_tizen_screenmirror *mirror, + struct wl_listener *listener) +{ + wl_signal_add(&mirror->events.queue, listener); +} + +WL_EXPORT void +ds_tizen_screenmirror_add_dequeue_listener(struct ds_tizen_screenmirror *mirror, + struct wl_listener *listener) +{ + wl_signal_add(&mirror->events.dequeue, listener); +} + +WL_EXPORT void +ds_tizen_screenmirror_add_start_listener(struct ds_tizen_screenmirror *mirror, + struct wl_listener *listener) +{ + wl_signal_add(&mirror->events.start, listener); +} + +WL_EXPORT void +ds_tizen_screenmirror_add_stop_listener(struct ds_tizen_screenmirror *mirror, + struct wl_listener *listener) +{ + wl_signal_add(&mirror->events.stop, listener); +} + +WL_EXPORT void +ds_tizen_screenmirror_add_auto_rotation_listener(struct ds_tizen_screenmirror *mirror, + struct wl_listener *listener) +{ + wl_signal_add(&mirror->events.set_auto_rotation, listener); +} + +WL_EXPORT void +ds_tizen_screenmirror_send_content(struct ds_tizen_screenmirror *mirror, + enum ds_tizen_screenmirror_content content) +{ + if (content == DS_TIZEN_SCREENMIRROR_CONTENT_NORMAL) + tizen_screenmirror_send_content(mirror->resource, TIZEN_SCREENMIRROR_CONTENT_NORMAL); + else if (content == DS_TIZEN_SCREENMIRROR_CONTENT_VIDEO) + tizen_screenmirror_send_content(mirror->resource, TIZEN_SCREENMIRROR_CONTENT_VIDEO); +} + +WL_EXPORT void +ds_tizen_screenmirror_send_dequeued(struct ds_tizen_screenmirror *mirror, + struct ds_buffer *buffer) +{ + struct wl_resource *wl_buffer; + + wl_buffer = ds_buffer_get_resource(buffer); + tizen_screenmirror_send_dequeued(mirror->resource, wl_buffer); +} + +WL_EXPORT void +ds_tizen_screenmirror_send_stop(struct ds_tizen_screenmirror *mirror) +{ + tizen_screenmirror_send_stop(mirror->resource); +} + +void +ds_tizen_screenmirror_destroy(struct ds_tizen_screenmirror *mirror) +{ + if (mirror == NULL) + return; + + if (mirror->client_destroy_listener.notify) + wl_list_remove(&mirror->client_destroy_listener.link); + mirror->client_destroy_listener.notify = NULL; + + if (mirror->resource) + wl_resource_set_destructor(mirror->resource, NULL); + + wl_signal_emit(&mirror->events.destroy, NULL); + //should be called buffer_dequeued from server(ds_tizen_screenmirror_send_dequeued) + + free(mirror); +} + +static void +screenmirror_handle_resource_destroy(struct wl_resource *resource) +{ + struct ds_tizen_screenmirror *mirror = wl_resource_get_user_data(resource); + ds_tizen_screenmirror_destroy(mirror); +} + +static void +screenmirror_handle_client_destroy(struct wl_listener *listener, void *data) +{ + struct ds_tizen_screenmirror *mirror = wl_container_of(listener, mirror, client_destroy_listener); + ds_tizen_screenmirror_destroy(mirror); +} + +struct ds_tizen_screenmirror * +ds_tizen_screenmirror_create(struct ds_tizen_screenshooter_client *client, + int version, uint32_t id) +{ + struct ds_tizen_screenmirror *mirror; + + mirror = calloc(1, sizeof *mirror); + if (!mirror) { + ds_err("screenmirror create fail : memory alloc failed"); + return NULL; + } + + mirror->resource = wl_resource_create(client->client, &tizen_screenmirror_interface, + version, id); + if (mirror->resource == NULL) { + ds_err("screenmirror wl_resource create fail : memory alloc failed"); + free(mirror); + return NULL; + } + + wl_signal_init(&mirror->events.destroy); + wl_signal_init(&mirror->events.set_stretch); + wl_signal_init(&mirror->events.queue); + wl_signal_init(&mirror->events.dequeue); + wl_signal_init(&mirror->events.start); + wl_signal_init(&mirror->events.stop); + wl_signal_init(&mirror->events.set_auto_rotation); + + wl_resource_set_implementation(mirror->resource, &_screenmirror_interface, + mirror, screenmirror_handle_resource_destroy); + + + ds_inf("create : tizen_screenmirror(%p)", mirror); + + mirror->client_destroy_listener.notify = screenmirror_handle_client_destroy; + wl_client_add_destroy_listener(client->client, &mirror->client_destroy_listener); + + return mirror; +} + +static void +_tizen_screenmirror_handle_destroy(struct wl_client *client, struct wl_resource *resource) +{ + ds_inf("_tizen_screenmirror_handle_destroy (res:%p)", resource); + wl_resource_destroy(resource); +} + +static void +_tizen_screenmirror_handle_set_stretch(struct wl_client *client, struct wl_resource *resource, uint32_t stretch) +{ + struct ds_tizen_screenmirror *mirror = wl_resource_get_user_data(resource); + enum ds_tizen_screenmirror_stretch ds_stretch; + + if (stretch > TIZEN_SCREENMIRROR_STRETCH_FULLY) { + ds_err("set stretch error : not supported stretch(%d)", stretch); + return; + } + if (stretch == TIZEN_SCREENMIRROR_STRETCH_KEEP_RATIO) + ds_stretch = DS_TIZEN_SCREENMIRROR_STRETCH_KEEP_RATIO; + else + ds_stretch = DS_TIZEN_SCREENMIRROR_STRETCH_FULLY; + + wl_signal_emit(&mirror->events.set_stretch, &ds_stretch); +} + +static void +_tizen_screenmirror_handle_queue(struct wl_client *client, struct wl_resource *resource, struct wl_resource *wl_buffer) +{ + struct ds_tizen_screenmirror *mirror; + struct ds_buffer *buffer; + + mirror = wl_resource_get_user_data(resource); + buffer = ds_buffer_from_resource(wl_buffer); + if (!buffer) { + ds_err("ds_buffer_from_resource fail"); + return; + } + + wl_signal_emit(&mirror->events.queue, &buffer); +} + +static void +_tizen_screenmirror_handle_dequeue(struct wl_client *client, struct wl_resource *resource, struct wl_resource *wl_buffer) +{ + struct ds_tizen_screenmirror *mirror; + struct ds_buffer *buffer; + + mirror = wl_resource_get_user_data(resource); + buffer = ds_buffer_from_resource(wl_buffer); + if (!buffer) { + ds_err("ds_buffer_from_resource fail"); + return; + } + + wl_signal_emit(&mirror->events.dequeue, &buffer); +} + +static void +_tizen_screenmirror_handle_start(struct wl_client *client, struct wl_resource *resource) +{ + struct ds_tizen_screenmirror *mirror; + + mirror = wl_resource_get_user_data(resource); + wl_signal_emit(&mirror->events.start, NULL); +} + +static void +_tizen_screenmirror_handle_stop(struct wl_client *client, struct wl_resource *resource) +{ + struct ds_tizen_screenmirror *mirror; + + mirror = wl_resource_get_user_data(resource); + wl_signal_emit(&mirror->events.stop, NULL); +} + +static void +_tizen_screenmirror_handle_set_auto_rotation(struct wl_client *client, struct wl_resource *resource, uint32_t set) +{ + struct ds_tizen_screenmirror *mirror; + + mirror = wl_resource_get_user_data(resource); + wl_signal_emit(&mirror->events.set_auto_rotation, &set); +} + +static const struct tizen_screenmirror_interface _screenmirror_interface = { + _tizen_screenmirror_handle_destroy, + _tizen_screenmirror_handle_set_stretch, + _tizen_screenmirror_handle_queue, + _tizen_screenmirror_handle_dequeue, + _tizen_screenmirror_handle_start, + _tizen_screenmirror_handle_stop, + _tizen_screenmirror_handle_set_auto_rotation +}; diff --git a/src/screenshooter/screenshooter.c b/src/screenshooter/screenshooter.c new file mode 100644 index 0000000..890bd2f --- /dev/null +++ b/src/screenshooter/screenshooter.c @@ -0,0 +1,215 @@ +#include +#include "screenshooter.h" +#include "util.h" + +#define TIZEN_SCREENSHOOTER_VERSION 3 + +static void screenshooter_handle_display_destroy(struct wl_listener *listener, + void *data); + +static void screenshooter_bind(struct wl_client *wl_client, void *data, + uint32_t version, uint32_t id); + +WL_EXPORT struct ds_tizen_screenshooter * +ds_tizen_screenshooter_create(struct wl_display *display) +{ + struct ds_tizen_screenshooter *shot; + + shot = calloc(1, sizeof *shot); + if (!shot) { + ds_err("screenshooter create fail : memory alloc failed"); + return NULL; + } + + shot->global = wl_global_create(display, &tizen_screenshooter_interface, + TIZEN_SCREENSHOOTER_VERSION, NULL, screenshooter_bind); + + wl_list_init(&shot->clients); + wl_signal_init(&shot->events.destroy); + wl_signal_init(&shot->events.shoot); + + shot->destroy.notify = screenshooter_handle_display_destroy; + wl_display_add_destroy_listener(display, &shot->destroy); + + ds_inf("create : tizen_screenshooter(%p)", shot); + + return shot; +} + +WL_EXPORT void +ds_tizen_screenshooter_add_destroy_listener(struct ds_tizen_screenshooter *shot, + struct wl_listener *listener) +{ + wl_signal_add(&shot->events.destroy, listener); +} + +WL_EXPORT void +ds_tizen_screenshooter_add_get_screenmirror_listener(struct ds_tizen_screenshooter *shot, + struct wl_listener *listener) +{ + wl_signal_add(&shot->events.get_screenmirror, listener); +} + +WL_EXPORT void +ds_tizen_screenshooter_add_shoot_listener(struct ds_tizen_screenshooter *shot, + struct wl_listener *listener) +{ + wl_signal_add(&shot->events.shoot, listener); +} + +WL_EXPORT void +ds_tizen_screenshooter_send_shoot_done(struct ds_tizen_screenshooter *shot, + struct ds_tizen_screenshooter_client *client) +{ + struct ds_tizen_screenshooter_client *temp; + + wl_list_for_each(temp, &shot->clients, link) { + if (temp == client) { + ds_dbg("screenshooter send shoot done"); + tizen_screenshooter_send_done(client->res); + } + } +} + +static void +screenshooter_handle_display_destroy(struct wl_listener *listener, void *data) +{ + struct ds_tizen_screenshooter *shot; + + shot = wl_container_of(listener, shot, destroy); + + ds_inf("global destroy : tizen_screenshooter(%p)", shot); + + wl_signal_emit(&shot->events.destroy, shot); + wl_list_remove(&shot->destroy.link); + wl_global_destroy(shot->global); + free(shot); +} + +static void +_tizen_screenshooter_handle_get_screenmirror(struct wl_client *client, + struct wl_resource *resource, uint32_t id, struct wl_resource *output) +{ + struct ds_tizen_screenshooter *shot; + struct ds_tizen_screenshooter_client *shot_client; + int version = wl_resource_get_version(resource); + + shot_client = wl_resource_get_user_data(resource); + shot = shot_client->shot; + + if (shot_client->mirror) { + ds_err("screenshooter get_screenmirror error : already created"); + return; + } + + shot_client->mirror = ds_tizen_screenmirror_create(shot_client, version, id); + if (shot_client->mirror == NULL) + wl_client_post_no_memory(client); + else + wl_signal_emit(&shot->events.get_screenmirror, shot_client->mirror); +} + +static void +_tizen_screenshooter_handle_set_oneshot_auto_rotation(struct wl_client *client, + struct wl_resource *resource, uint32_t set) +{ + struct ds_tizen_screenshooter *shot; + struct ds_tizen_screenshooter_client *shot_client; + + shot_client = wl_resource_get_user_data(resource); + shot = shot_client->shot; + if (set) + shot->auto_rotation = true; + else + shot->auto_rotation = false; +} + +static void +_tizen_screenshooter_handle_destroy(struct wl_client *client, + struct wl_resource *resource) +{ + ds_inf("_tizen_screenshooter_handle_destroy (res:%p)", resource); + wl_resource_destroy(resource); +} + +static void +_tizen_screenshooter_handle_shoot(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *wl_output, + struct wl_resource *wl_buffer) +{ + struct ds_tizen_screenshooter *shot; + struct ds_tizen_screenshooter_client *shot_client; + struct ds_output *output = NULL; + struct ds_buffer *buffer = NULL; + + shot_client = wl_resource_get_user_data(resource); + shot = shot_client->shot; + output = wl_resource_get_user_data(wl_output); + buffer = ds_buffer_from_resource(wl_buffer); + if (!buffer) { + ds_err("ds_buffer_from_resource fail"); + return; + } + + struct ds_tizen_screenshooter_shoot_event event = { + .output = output, + .buffer = buffer, + .client = shot_client, + .auto_rotation = shot->auto_rotation, + }; + + wl_signal_emit(&shot->events.shoot, &event); +} + +static const struct tizen_screenshooter_interface _tizen_screenshooter_interface = +{ + _tizen_screenshooter_handle_get_screenmirror, + _tizen_screenshooter_handle_set_oneshot_auto_rotation, + _tizen_screenshooter_handle_destroy, + _tizen_screenshooter_handle_shoot, +}; + +static void +_screenshooter_client_cb_destroy(struct wl_resource *resource) +{ + struct ds_tizen_screenshooter_client *shot_client; + + ds_inf("_screenshooter_client_cb_destroy (res:%p)", resource); + + shot_client = wl_resource_get_user_data(resource); + if (shot_client) { + wl_list_remove(&shot_client->link); + free(shot_client); + } +} + +static void +screenshooter_bind(struct wl_client *client, void *data, uint32_t version, + uint32_t id) +{ + struct ds_tizen_screenshooter *shot = data; + struct ds_tizen_screenshooter_client *shot_client; + + shot_client = calloc(1, sizeof *shot_client); + if (shot_client == NULL) { + wl_client_post_no_memory(client); + return; + } + + shot_client->shot = shot; + shot_client->client = client; + + shot_client->res = wl_resource_create(client, &tizen_screenshooter_interface, + MIN(version, TIZEN_SCREENSHOOTER_VERSION), id); + if (shot_client->res == NULL) { + ds_err("screenshooter bind error : wl_resource_create failed."); + wl_client_post_no_memory(client); + free(shot_client); + return; + } + + wl_resource_set_implementation(shot_client->res, &_tizen_screenshooter_interface, + shot_client, _screenshooter_client_cb_destroy); + + wl_list_insert(&shot->clients, &shot_client->link); +} diff --git a/src/screenshooter/screenshooter.h b/src/screenshooter/screenshooter.h new file mode 100644 index 0000000..bdc52bd --- /dev/null +++ b/src/screenshooter/screenshooter.h @@ -0,0 +1,62 @@ +#ifndef DS_TIZEN_SCREENSHOOTER_H +#define DS_TIZEN_SCREENSHOOTER_H + +#include +#include +#include +#include +#include +#include +#include +#include + +struct ds_tizen_screenshooter +{ + struct wl_global *global; + struct wl_list clients; + + struct wl_listener destroy; + + struct { + struct wl_signal destroy; + struct wl_signal get_screenmirror; + struct wl_signal shoot; + } events; + + bool auto_rotation; +}; + +struct ds_tizen_screenshooter_client +{ + struct ds_tizen_screenshooter *shot; + struct ds_tizen_screenmirror *mirror; + struct wl_resource *res; + struct wl_client *client; + struct wl_list link; // ds_tizen_screenshooter::clients +}; + +struct ds_tizen_screenmirror +{ + struct wl_resource *resource; + struct ds_tizen_screenshooter_client *client; + struct wl_listener client_destroy_listener; + + struct { + struct wl_signal destroy; + struct wl_signal set_stretch; + struct wl_signal queue; + struct wl_signal dequeue; + struct wl_signal start; + struct wl_signal stop; + struct wl_signal set_auto_rotation; + } events; +}; + +struct ds_tizen_screenmirror * +ds_tizen_screenmirror_create(struct ds_tizen_screenshooter_client *client, + int version, uint32_t id); + +void +ds_tizen_screenmirror_destroy(struct ds_tizen_screenmirror *mirror); + +#endif diff --git a/tests/meson.build b/tests/meson.build index 030c3b0..e620eb0 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -324,3 +324,23 @@ executable('libds-tizen-policy-tests', install_dir: libds_tizen_bindir, install : true ) + +## screenshooter-compositor tests +tc_screenshooter_files = [ + 'tc_main.cpp', + 'tc_screenshooter.cpp', +] + +executable('libds-tizen-screenshooter-tests', + [ + tc_mock_files, + tc_screenshooter_files + ], + dependencies: [ + deps_test_common, + deps_libds_tizen_screenshooter, + dependency('tizen-extension-client', required: true), + ], + install_dir: libds_tizen_bindir, + install : true +) diff --git a/tests/tc_screenshooter.cpp b/tests/tc_screenshooter.cpp new file mode 100644 index 0000000..929ecdf --- /dev/null +++ b/tests/tc_screenshooter.cpp @@ -0,0 +1,747 @@ +#include +#include +#include +#ifdef TIZEN_SCREENMIRROR_STOP +#undef TIZEN_SCREENMIRROR_STOP +#endif +#include +#include +#include +#include +#include "tc_main.h" +#include "mockclient.h" +#include "mockcompositor.h" + +#define TIZEN_SCREENSHOOTER_VERSION 3 +#define SHM_BUF_WIDTH 1920 +#define SHM_BUF_HEIGHT 1080 +#define SHM_BUF_STRIDE 7680 //width * 4 +#define SHM_BUF_FORMAT WL_SHM_FORMAT_XRGB8888 + +class MockScreenShooterCompositor : public MockCompositor +{ +public: + MockScreenShooterCompositor() + : MockCompositor(&MockScreenShooterCompositor::TestSetup, this) + { + ds_inf("%s : this(%p)", __func__, this); + + bDestroyed = false; + bMirror = false; + bDestroyMirror = false; + bShoot = false; + bStart = false; + bAutoRotation = false; + mBackend = nullptr; + mBuffer = nullptr; + mOutput = nullptr;; + mScreenShooter = nullptr; + mScreenMirror = nullptr; + new_output = {}; + + mDestroyListener = {}; + mNewScreenMirrorListener = {}; + mScreenShootListener = {}; + mScreenMirrorDestroyListener = {}; + mScreenMirrorSetStretchListener = {}; + mScreenMirrorQueueListener = {}; + mScreenMirrorDequeueListener = {}; + mScreenMirrorStartListener = {}; + mScreenMirrorStopListener = {}; + mScreenMirrorAutoRotationListener = {}; + } + + ~MockScreenShooterCompositor() + { + ds_inf("%s : this(%p)", __func__, this); + } + + static void TestSetup(void *data) + { + MockScreenShooterCompositor *mockComp = + static_cast(data); + Compositor *comp = mockComp->compositor; + + ds_inf("%s: mockComp(%p)", __func__, mockComp); + + mockComp->mBackend = ds_wl_backend_create(comp->display, NULL); + mockComp->new_output.notify = screenshooter_backend_handle_new_output; + ds_backend_add_new_output_listener(mockComp->mBackend, &mockComp->new_output); + ds_backend_start(mockComp->mBackend); + + mockComp->mScreenShooter = + ds_tizen_screenshooter_create(comp->display); + + // add destroy listener + mockComp->mDestroyListener.notify = + MockScreenShooterCompositor::DestroyCallback; + mockComp->mDestroyListener.parent = mockComp; + ds_tizen_screenshooter_add_destroy_listener(mockComp->mScreenShooter, + &mockComp->mDestroyListener); + + // add newscreenmirror listener + mockComp->mNewScreenMirrorListener.notify = + MockScreenShooterCompositor::NewScreenMirrorCallback; + mockComp->mNewScreenMirrorListener.parent = mockComp; + ds_tizen_screenshooter_add_get_screenmirror_listener(mockComp->mScreenShooter, + &mockComp->mNewScreenMirrorListener); + + // add shoot listener + mockComp->mScreenShootListener.notify = + MockScreenShooterCompositor::ScreenShootCallback; + mockComp->mScreenShootListener.parent = mockComp; + ds_tizen_screenshooter_add_shoot_listener(mockComp->mScreenShooter, + &mockComp->mScreenShootListener); + } + + static void screenshooter_backend_handle_new_output(struct wl_listener *listener, + void *data) + { + MockScreenShooterCompositor *mockComp; + + mockComp = wl_container_of(listener, mockComp, new_output); + mockComp->mOutput = static_cast(data); + + ds_inf("New ds_output(%p)", mockComp->mOutput); + + ds_output_create_global(mockComp->mOutput); + ds_inf("create output global"); + } + + static void DestroyCallback(struct wl_listener *listener, void *data) + { + ds_inf("%s", __func__); + + MockScreenShooterCompositor *mockComp = + reinterpret_cast(listener)->parent; + + mockComp->bDestroyed = true; + } + + static void NewScreenMirrorCallback(struct wl_listener *listener, + void *data) + { + ds_inf("%s", __func__); + + MockScreenShooterCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_tizen_screenmirror *mirror = + static_cast(data); + + ds_inf("%s: mockComp(%p), mirror(%p)", __func__, mockComp, mirror); + + mockComp->bMirror = true; + mockComp->mScreenMirror = mirror; + + // add destroy listener + mockComp->mScreenMirrorDestroyListener.notify = + MockScreenShooterCompositor::ScreenMirrorDestroyCallback; + mockComp->mScreenMirrorDestroyListener.parent = mockComp; + ds_tizen_screenmirror_add_destroy_listener(mockComp->mScreenMirror, + &mockComp->mScreenMirrorDestroyListener); + + // add set_stretch listener + mockComp->mScreenMirrorSetStretchListener.notify = + MockScreenShooterCompositor::ScreenMirrorSetStretchCallback; + mockComp->mScreenMirrorSetStretchListener.parent = mockComp; + ds_tizen_screenmirror_add_set_stretch_listener(mockComp->mScreenMirror, + &mockComp->mScreenMirrorSetStretchListener); + + // add queue listener + mockComp->mScreenMirrorQueueListener.notify = + MockScreenShooterCompositor::ScreenMirrorQueueCallback; + mockComp->mScreenMirrorQueueListener.parent = mockComp; + ds_tizen_screenmirror_add_queue_listener(mockComp->mScreenMirror, + &mockComp->mScreenMirrorQueueListener); + + // add dequeue listener + mockComp->mScreenMirrorDequeueListener.notify = + MockScreenShooterCompositor::ScreenMirrorDequeueCallback; + mockComp->mScreenMirrorDequeueListener.parent = mockComp; + ds_tizen_screenmirror_add_dequeue_listener(mockComp->mScreenMirror, + &mockComp->mScreenMirrorDequeueListener); + + // add start listener + mockComp->mScreenMirrorStartListener.notify = + MockScreenShooterCompositor::ScreenMirrorStartCallback; + mockComp->mScreenMirrorStartListener.parent = mockComp; + ds_tizen_screenmirror_add_start_listener(mockComp->mScreenMirror, + &mockComp->mScreenMirrorStartListener); + + // add stop listener + mockComp->mScreenMirrorStopListener.notify = + MockScreenShooterCompositor::ScreenMirrorStopCallback; + mockComp->mScreenMirrorStopListener.parent = mockComp; + ds_tizen_screenmirror_add_stop_listener(mockComp->mScreenMirror, + &mockComp->mScreenMirrorStopListener); + + // add auto rotation listener + mockComp->mScreenMirrorAutoRotationListener.notify = + MockScreenShooterCompositor::ScreenMirrorAutoRotationCallback; + mockComp->mScreenMirrorAutoRotationListener.parent = mockComp; + ds_tizen_screenmirror_add_auto_rotation_listener(mockComp->mScreenMirror, + &mockComp->mScreenMirrorAutoRotationListener); + } + + static void ScreenShootCallback(struct wl_listener *listener, + void *data) + { + ds_inf("%s", __func__); + + MockScreenShooterCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_tizen_screenshooter_shoot_event *event = + static_cast(data); + + + ds_inf("%s: mockComp(%p), output(%p), buffer(%p), client(%p), auto_rotate:%d", + __func__, mockComp, event->output, event->buffer, event->client, + event->auto_rotation ? 1 : 0); + + mockComp->bShoot = true; + ds_tizen_screenshooter_send_shoot_done(mockComp->mScreenShooter, event->client); + } + + static void ScreenMirrorDestroyCallback(struct wl_listener *listener, + void *data) + { + ds_inf("%s", __func__); + + MockScreenShooterCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_tizen_screenmirror *mirror = + static_cast(data); + + ds_inf("%s: mockComp(%p), info(%p)", __func__, mockComp, mirror); + + if (mockComp->mScreenMirror == mirror) { + ds_inf("%s: info is deleted.", __func__); + mockComp->bDestroyMirror = true; + } + } + + static void ScreenMirrorSetStretchCallback(struct wl_listener *listener, + void *data) + { + ds_inf("%s", __func__); + + MockScreenShooterCompositor *mockComp = + reinterpret_cast(listener)->parent; + enum ds_tizen_screenmirror_stretch *stretch = (enum ds_tizen_screenmirror_stretch *)data; + + ds_inf("%s: mockComp(%p), stretch(%d)", __func__, mockComp, *stretch); + } + + static void ScreenMirrorQueueCallback(struct wl_listener *listener, + void *data) + { + ds_inf("%s", __func__); + + MockScreenShooterCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_buffer *buffer = + static_cast(data); + + ds_inf("%s: mockComp(%p), queue(%p)", __func__, mockComp, buffer); + } + + static void ScreenMirrorDequeueCallback(struct wl_listener *listener, + void *data) + { + ds_inf("%s", __func__); + + MockScreenShooterCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_buffer *buffer = + static_cast(data); + + ds_inf("%s: mockComp(%p), dequeue(%p)", __func__, mockComp, buffer); + + ds_tizen_screenmirror_send_dequeued(mockComp->mScreenMirror, buffer); + } + + static void ScreenMirrorStartCallback(struct wl_listener *listener, + void *data) + { + ds_inf("%s", __func__); + + MockScreenShooterCompositor *mockComp = + reinterpret_cast(listener)->parent; + + ds_inf("%s: mockComp(%p), start", __func__, mockComp); + + mockComp->bStart = true; + } + + static void ScreenMirrorStopCallback(struct wl_listener *listener, + void *data) + { + ds_inf("%s", __func__); + + MockScreenShooterCompositor *mockComp = + reinterpret_cast(listener)->parent; + + ds_inf("%s: mockComp(%p), stop", __func__, mockComp); + + mockComp->bStart = false; + } + + static void ScreenMirrorAutoRotationCallback(struct wl_listener *listener, + void *data) + { + ds_inf("%s", __func__); + + MockScreenShooterCompositor *mockComp = + reinterpret_cast(listener)->parent; + uint32_t *set = (uint32_t *)data; + + ds_inf("%s: mockComp(%p), autorotation(%d)", __func__, mockComp, *set); + + if (*set) + mockComp->bAutoRotation = true; + else + mockComp->bAutoRotation = false; + } + +public: + bool bDestroyed; + + bool bMirror; + bool bDestroyMirror; + bool bShoot; + bool bStart; + bool bAutoRotation; + +private: + struct ds_backend *mBackend; + struct ds_buffer *mBuffer; + struct ds_output *mOutput; + struct ds_tizen_screenshooter *mScreenShooter; + struct ds_tizen_screenmirror *mScreenMirror; + struct wl_listener new_output; + + struct DestroyListener : ::wl_listener { + MockScreenShooterCompositor *parent; + }; + DestroyListener mDestroyListener; + + struct NewScreenMirrorListener : ::wl_listener { + MockScreenShooterCompositor *parent; + }; + NewScreenMirrorListener mNewScreenMirrorListener; + + struct ScreenShootListener : ::wl_listener { + MockScreenShooterCompositor *parent; + }; + ScreenShootListener mScreenShootListener; + + struct ScreenMirrorDestroyListener : ::wl_listener { + MockScreenShooterCompositor *parent; + }; + ScreenMirrorDestroyListener mScreenMirrorDestroyListener; + + struct ScreenMirrorSetStretchListener : ::wl_listener { + MockScreenShooterCompositor *parent; + }; + ScreenMirrorSetStretchListener mScreenMirrorSetStretchListener; + + struct ScreenMirrorQueueListener : ::wl_listener { + MockScreenShooterCompositor *parent; + }; + ScreenMirrorQueueListener mScreenMirrorQueueListener; + + struct ScreenMirrorDequeueListener : ::wl_listener { + MockScreenShooterCompositor *parent; + }; + ScreenMirrorDequeueListener mScreenMirrorDequeueListener; + + struct ScreenMirrorStartListener : ::wl_listener { + MockScreenShooterCompositor *parent; + }; + ScreenMirrorStartListener mScreenMirrorStartListener; + + struct ScreenMirrorStopListener : ::wl_listener { + MockScreenShooterCompositor *parent; + }; + ScreenMirrorStopListener mScreenMirrorStopListener; + + struct ScreenMirrorAutoRotationListener : ::wl_listener { + MockScreenShooterCompositor *parent; + }; + ScreenMirrorAutoRotationListener mScreenMirrorAutoRotationListener; +}; + +class MockScreenShooterClient : public MockClient +{ +public: + MockScreenShooterClient() + : bShootEvent(false), + bMirrorStartEvent(false), + bMirrorStopEvent(false), + output_res(nullptr), + shm_res(nullptr), + shm_pool(nullptr), + screenshooter_res(nullptr), + screenmirror_res(nullptr) + {} + MockScreenShooterClient(const struct wl_registry_listener *listener) + : MockClient(listener, this) + { + ds_inf("%s", __func__); + + bShootEvent = false; + bMirrorStartEvent = false; + bMirrorStopEvent = false; + output_res = nullptr; + shm_res = nullptr; + shm_pool = nullptr; + screenshooter_res = nullptr; + screenmirror_res = nullptr; + } + ~MockScreenShooterClient() + { + ds_inf("%s", __func__); + } + + void SetWlOutput(struct wl_output *global_res) + { + ds_inf("%s", __func__); + + output_res = global_res; + } + + struct wl_output *GetWlOutput() + { + ds_inf("%s", __func__); + + return output_res; + } + + void SetWlShm(struct wl_shm *global_res) + { + ds_inf("%s", __func__); + + shm_res = global_res; + } + + struct wl_shm *GetWlShm() + { + ds_inf("%s", __func__); + + return shm_res; + } + + void SetWlShmPool(struct wl_shm_pool *_shm_pool) + { + ds_inf("%s", __func__); + + shm_pool = _shm_pool; + } + + struct wl_shm_pool *GetWlShmPool() + { + ds_inf("%s", __func__); + + return shm_pool; + } + + void SetTizenScreenShooter(struct tizen_screenshooter *resource) + { + ds_inf("%s", __func__); + + screenshooter_res = resource; + } + + struct tizen_screenshooter *GetTizenScreenShooter() + { + ds_inf("%s", __func__); + + return screenshooter_res; + } + + + void SetTizenScreenMirror(struct tizen_screenmirror *resource) + { + ds_inf("%s", __func__); + + screenmirror_res = resource; + } + + struct tizen_screenmirror *GetTizenScreenMirror() + { + ds_inf("%s", __func__); + + return screenmirror_res; + } + +public: + bool bShootEvent; + bool bMirrorStartEvent; + bool bMirrorStopEvent; + +private: + struct wl_output *output_res; + struct wl_shm *shm_res; + struct wl_shm_pool *shm_pool; + struct tizen_screenshooter *screenshooter_res; + struct tizen_screenmirror *screenmirror_res; +}; + +static void +client_tizen_screenshooter_cb_format(void *data, + struct tizen_screenshooter *screenshooter_res, uint32_t format) +{ +} + +static void +client_tizen_screenshooter_cb_noti(void *data, + struct tizen_screenshooter *screenshooter_res, uint32_t noti) +{ + ds_inf("noti : %d"); +} + +static void +client_tizen_screenshooter_cb_done(void *data, + struct tizen_screenshooter *screenshooter_res) +{ + MockScreenShooterClient *client = static_cast(data); + + client->bShootEvent = true; +} + +static const struct +tizen_screenshooter_listener screenshooter_cb_listener = { + client_tizen_screenshooter_cb_format, + client_tizen_screenshooter_cb_noti, + client_tizen_screenshooter_cb_done, +}; + +static void +_client_tizen_screenshooter_destroy_anonymous_file(int fd) +{ + if (fd < 0) + return; + + close(fd); +} + +static int +_client_tizen_screenshooter_create_anonymous_file(off_t size) +{ + static const char tempname[] = "/shooter-XXXXXX"; + const char *path; + char *name = NULL; + int fd = -1; + int ret = -1; + int path_len = 0; + + path = getenv("XDG_RUNTIME_DIR"); + if (!path) { + errno = ENOENT; + return -1; + } + path_len = strlen(path); + if (path_len == 0) + return -1; + + name = (char *)malloc(path_len + (int)sizeof(tempname)); + if (name == NULL) + return -1; + + strncpy(name, path, path_len); + strncat(name, tempname, (int)sizeof(tempname)); + + fd = mkstemp(name); + if (fd >= 0) + unlink(name); + + free(name); + + if (fd < 0) + return -1; + + ret = ftruncate(fd, size); + if (ret < 0) { + close(fd); + return -1; + } + + return fd; +} + +static struct wl_shm_pool * +_client_tizen_screenshooter_create_shm_pool(struct wl_shm *shm, int size) +{ + struct wl_shm_pool *shm_pool = NULL; + void *data = NULL; + int fd = -1; + + fd = _client_tizen_screenshooter_create_anonymous_file(size); + if (fd < 0) + goto fail; + + data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (data == NULL) + goto fail; + + memset(data, 0xff, size); + munmap(data, size); + + shm_pool = wl_shm_create_pool(shm, fd, size); + if (shm_pool == NULL) + goto fail; + + _client_tizen_screenshooter_destroy_anonymous_file(fd); + + return shm_pool; + +fail: + if (fd > 0) + _client_tizen_screenshooter_destroy_anonymous_file(fd); + + return NULL; +} + +void +_client_tizen_screenshooter_destroy_shm_pool(struct wl_shm_pool *shm_pool) +{ + if (!shm_pool) + return; + + wl_shm_pool_destroy(shm_pool); +} + +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__); + + MockScreenShooterClient *client = static_cast(data); + struct tizen_screenshooter *screenshooter_res; + struct wl_shm *shm_res; + struct wl_shm_pool *shm_pool; + struct wl_output *output_res; + + if (!strcmp(interface, "wl_shm")) { + shm_res = (struct wl_shm *)wl_registry_bind(registry, + name, &wl_shm_interface, 1); + if (shm_res == nullptr) { + ds_err("wl_registry_bind() failed. wl_shm resource."); + return; + } + shm_pool = _client_tizen_screenshooter_create_shm_pool(shm_res, SHM_BUF_WIDTH * 4 * SHM_BUF_HEIGHT); + if (shm_pool == NULL) { + ds_err("wl_registry_bind() failed. wl_shm_pool create fail."); + wl_shm_destroy(shm_res); + return; + } + client->SetWlShm(shm_res); + client->SetWlShmPool(shm_pool); + } else if (!strcmp(interface, "wl_output")) { + output_res = (struct wl_output *)wl_registry_bind(registry, + name, &wl_output_interface, 1); + if (output_res == nullptr) { + ds_err("wl_registry_bind() failed. wl_output resource."); + return; + } + client->SetWlOutput(output_res); + } else if (!strcmp(interface, "tizen_screenshooter")) { + screenshooter_res = (struct tizen_screenshooter *)wl_registry_bind(registry, + name, &tizen_screenshooter_interface, TIZEN_SCREENSHOOTER_VERSION); + if (screenshooter_res == nullptr) { + ds_err("wl_registry_bind() failed. tizen_screenshooter resource."); + return; + } + client->SetTizenScreenShooter(screenshooter_res); + + tizen_screenshooter_add_listener(screenshooter_res, + &screenshooter_cb_listener, client); + } +} + +static void +client_registry_cb_global_remove(void *data, struct wl_registry *registry, + uint32_t name) +{ + ds_inf("%s", __func__); + + MockScreenShooterClient *client = static_cast(data); + struct wl_shm *shm_res = client->GetWlShm(); + struct wl_shm_pool *shm_pool = client->GetWlShmPool(); + struct tizen_screenshooter *screenshooter_res = client->GetTizenScreenShooter(); + struct tizen_screenmirror *screenmirror_res = client->GetTizenScreenMirror(); + + if (screenmirror_res) + tizen_screenmirror_destroy(screenmirror_res); + tizen_screenshooter_destroy(screenshooter_res); + _client_tizen_screenshooter_destroy_shm_pool(shm_pool); + wl_shm_destroy(shm_res); +} + +static const struct wl_registry_listener registry_listener = { + .global = client_registry_cb_global, + .global_remove = client_registry_cb_global_remove +}; + +class ScreenShooterTest : public ::testing::Test +{ +public: + void SetUp(void) override; + void TearDown(void) override; + + MockScreenShooterCompositor *comp; + MockScreenShooterClient *client; + struct wl_output *output_res; + struct wl_shm *shm_res; + struct wl_shm_pool *shm_pool; + struct wl_buffer *buffer_res1; + struct wl_buffer *buffer_res2; + struct wl_buffer *buffer_res3; + struct tizen_screenshooter *screenshooter_res; + struct tizen_screenmirror *screenmirror_res; +}; + +void +ScreenShooterTest::SetUp(void) +{ + //ds_log_init(DS_DBG, NULL); + + ds_inf("%s", __func__); + + comp = new MockScreenShooterCompositor(); + client = new MockScreenShooterClient(®istry_listener); + output_res = client->GetWlOutput(); + shm_res = client->GetWlShm(); + shm_pool = client->GetWlShmPool(); + screenshooter_res = client->GetTizenScreenShooter(); + + client->RoundTrip(); +} + +void +ScreenShooterTest::TearDown(void) +{ + ds_inf("%s", __func__); + + client->RoundTrip(); + + delete client; + delete comp; +} + +TEST_F(ScreenShooterTest, Create_P) +{ + EXPECT_TRUE(true); +} + +TEST_F(ScreenShooterTest, Req_TizenScreenShooterShot) +{ + buffer_res1 = wl_shm_pool_create_buffer(shm_pool, 0, + SHM_BUF_WIDTH, SHM_BUF_HEIGHT, SHM_BUF_STRIDE, SHM_BUF_FORMAT); + tizen_screenshooter_shoot(screenshooter_res, output_res, buffer_res1); + client->RoundTrip(); + EXPECT_TRUE(comp->bShoot); + comp->Process(); + EXPECT_TRUE(client->bShootEvent); +} -- 2.7.4 From c05a3844ab51bb2f9f08d95760d1a89942cd5ece Mon Sep 17 00:00:00 2001 From: Seunghun Date: Tue, 23 Aug 2022 14:51:43 +0900 Subject: [PATCH 09/16] Add ds_tizen_scaler for wl_scaler Change-Id: Ib6d1f7e43aee8f96f05ecaf2b81f855bce66648e --- include/libds-tizen/scaler.h | 18 +++ packaging/libds-tizen.spec | 30 +++++ src/meson.build | 1 + src/scaler/meson.build | 25 ++++ src/scaler/scaler.c | 291 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 365 insertions(+) create mode 100644 include/libds-tizen/scaler.h create mode 100644 src/scaler/meson.build create mode 100644 src/scaler/scaler.c diff --git a/include/libds-tizen/scaler.h b/include/libds-tizen/scaler.h new file mode 100644 index 0000000..4a52b4e --- /dev/null +++ b/include/libds-tizen/scaler.h @@ -0,0 +1,18 @@ +#ifndef LIBDS_TIZEN_SCALER_H +#define LIBDS_TIZEN_SCALER_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ds_tizen_scaler; + +struct ds_tizen_scaler *ds_tizen_scaler_create(struct wl_display *display); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packaging/libds-tizen.spec b/packaging/libds-tizen.spec index 485abfc..4ef8195 100644 --- a/packaging/libds-tizen.spec +++ b/packaging/libds-tizen.spec @@ -38,6 +38,7 @@ BuildRequires: pkgconfig(cynara-client) BuildRequires: pkgconfig(cynara-session) BuildRequires: pkgconfig(libsmack) BuildRequires: pkgconfig(gmock) +BuildRequires: pkgconfig(scaler-server) %description Wayland Compositor Library for Tizen @@ -342,6 +343,21 @@ Group: Development/Libraries %description screenshooter-devel Development package for tizen screenshooter +## libds-tizen-scaler +%package scaler +Summary: Library for tizen scaler +Group: Development/Libraries + +%description scaler +Library for tizen scaler + +%package scaler-devel +Summary: Development package for tizen scaler +Group: Development/Libraries + +%description scaler-devel +Development package for tizen scaler + %prep %setup -q cp %{SOURCE1001} . @@ -661,3 +677,17 @@ ninja -C builddir install %{_libdir}/pkgconfig/libds-tizen-screenshooter.pc %{_libdir}/libds-tizen-screenshooter.so %{_bindir}/libds-tizen-screenshooter-tests + +%files scaler +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_libdir}/libds-tizen-scaler.so.* + +%files scaler-devel +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_includedir}/libds-tizen/scaler.h +%{_libdir}/pkgconfig/libds-tizen-scaler.pc +%{_libdir}/libds-tizen-scaler.so diff --git a/src/meson.build b/src/meson.build index 9cc81b5..b039f9d 100644 --- a/src/meson.build +++ b/src/meson.build @@ -47,3 +47,4 @@ subdir('text_input') subdir('hwc') subdir('policy') subdir('screenshooter') +subdir('scaler') diff --git a/src/scaler/meson.build b/src/scaler/meson.build new file mode 100644 index 0000000..cfcc71b --- /dev/null +++ b/src/scaler/meson.build @@ -0,0 +1,25 @@ +libds_tizen_scaler_deps = [ + deps_libds_tizen, + dependency('scaler-server', required: true), +] + +lib_libds_tizen_scaler = shared_library('ds-tizen-scaler', 'scaler.c', + dependencies: libds_tizen_scaler_deps, + include_directories: [ common_inc, include_directories('.'), include_directories('..') ], + version: meson.project_version(), + install: true +) + +deps_libds_tizen_scaler = declare_dependency( + link_with: lib_libds_tizen_scaler, + dependencies: libds_tizen_scaler_deps, + include_directories: [ common_inc, include_directories('.') ], +) + +pkgconfig = import('pkgconfig') +pkgconfig.generate(lib_libds_tizen_scaler, + version: meson.project_version(), + filebase: 'libds-tizen-scaler', + name: 'libds-tizen-scaler', + description: 'tizen scaler extension of libds-tizen for tizen platform', +) diff --git a/src/scaler/scaler.c b/src/scaler/scaler.c new file mode 100644 index 0000000..9cd3b42 --- /dev/null +++ b/src/scaler/scaler.c @@ -0,0 +1,291 @@ +#include + +#include +#include + +#include +#include + +#define SCALER_VERSION 2 + +struct ds_tizen_scaler +{ + struct wl_global *global; + + struct wl_listener display_destroy; +}; + +struct viewport +{ + struct wl_resource *resource; + struct ds_surface_viewport *surface_viewport; + + struct wl_listener surface_destroy; + struct wl_listener surface_commit; +}; + +static void scaler_bind(struct wl_client *client, void *data, uint32_t version, + uint32_t id); +static void scaler_handle_display_destroy(struct wl_listener *listener, + void *data); +static void viewport_set_source(struct viewport *viewport, + wl_fixed_t x_fixed, wl_fixed_t y_fixed, + wl_fixed_t width_fixed, wl_fixed_t height_fixed); +static void viewport_set_destination(struct viewport *viewport, + int32_t width, int32_t height); + +struct ds_tizen_scaler * +ds_tizen_scaler_create(struct wl_display *display) +{ + struct ds_tizen_scaler *scaler; + + scaler = calloc(1, sizeof *scaler); + if (!scaler) + return NULL; + + scaler->global = wl_global_create(display, &wl_scaler_interface, + SCALER_VERSION, NULL, scaler_bind); + if (!scaler->global) { + free(scaler); + return NULL; + } + + scaler->display_destroy.notify = scaler_handle_display_destroy; + wl_display_add_destroy_listener(display, &scaler->display_destroy); + + return scaler; +} + +static void +viewport_destroy(struct viewport *viewport) +{ + ds_surface_viewport_release(viewport->surface_viewport); + + wl_resource_set_user_data(viewport->resource, NULL); + wl_list_remove(&viewport->surface_commit.link); + wl_list_remove(&viewport->surface_destroy.link); + free(viewport); +} + +static void +viewport_handle_destroy(struct wl_client *client, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void +viewport_handle_set(struct wl_client *client, struct wl_resource *resource, + wl_fixed_t src_x, wl_fixed_t src_y, + wl_fixed_t src_width, wl_fixed_t src_height, + int32_t dst_width, int32_t dst_height) +{ + struct viewport *viewport; + + viewport = wl_resource_get_user_data(resource); + if (!viewport) { + ds_err("wl_viewport@%d.set sent after wl_surface has been destroyed", + wl_resource_get_id(resource)); + return; + } + + viewport_set_source(viewport, src_x, src_y, src_width, src_height); + viewport_set_destination(viewport, dst_width, dst_height); +} + +static void +viewport_handle_set_source(struct wl_client *client, + struct wl_resource *resource, wl_fixed_t x, wl_fixed_t y, + wl_fixed_t width, wl_fixed_t height) +{ + struct viewport *viewport; + + viewport = wl_resource_get_user_data(resource); + if (!viewport) { + ds_err("wl_viewport@%d.set_source sent after wl_surface has been " + "destroyed", wl_resource_get_id(resource)); + return; + } + + viewport_set_source(viewport, x, y, width, height); +} + +static void +viewport_handle_set_destination(struct wl_client *client, + struct wl_resource *resource, int32_t width, int32_t height) +{ + struct viewport *viewport; + + viewport = wl_resource_get_user_data(resource); + if (!viewport) { + ds_err("wl_viewport@%d.set_destination sent after wl_surface has been " + "destroyed", wl_resource_get_id(resource)); + return; + } + + viewport_set_destination(viewport, width, height); +} + +static const struct wl_viewport_interface viewport_iface = { + .destroy = viewport_handle_destroy, + .set = viewport_handle_set, + .set_source = viewport_handle_set_source, + .set_destination = viewport_handle_set_destination, +}; + +static void +viewport_handle_surface_destroy(struct wl_listener *listener, void *data) +{ + struct viewport *viewport; + + viewport = wl_container_of(listener, viewport, surface_destroy); + viewport_destroy(viewport); +} + +static void +viewport_handle_resource_destroy(struct wl_resource *resource) +{ + struct viewport *viewport; + + viewport = wl_resource_get_user_data(resource); + if (viewport) + viewport_destroy(viewport); +} + +static void +viewport_handle_surface_commit(struct wl_listener *listener, void *data) +{ + struct viewport *viewport; + + viewport = wl_container_of(listener, viewport, surface_commit); + + // TODO +} + +static void +scaler_handle_destroy(struct wl_client *client, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void +scaler_handle_get_viewport(struct wl_client *client, + struct wl_resource *resource, uint32_t id, + struct wl_resource *surface_resource) +{ + struct viewport *viewport; + struct ds_surface *surface; + struct ds_surface_viewport *surface_viewport; + + surface = ds_surface_from_resource(surface_resource); + surface_viewport = ds_surface_take_viewport(surface); + if (!surface_viewport) { + wl_resource_post_error(resource, WL_SCALER_ERROR_VIEWPORT_EXISTS, + "a viewport for that surface already exists"); + return; + } + + viewport = calloc(1, sizeof *viewport); + if (!viewport) { + wl_resource_post_no_memory(resource); + return; + } + + viewport->resource = wl_resource_create(client, &wl_viewport_interface, + wl_resource_get_version(resource), id); + if (!viewport->resource) { + wl_resource_post_no_memory(resource); + free(viewport); + return; + } + wl_resource_set_implementation(viewport->resource, &viewport_iface, + viewport, viewport_handle_resource_destroy); + + viewport->surface_viewport = surface_viewport; + + viewport->surface_destroy.notify = viewport_handle_surface_destroy; + ds_surface_add_destroy_listener(surface, &viewport->surface_destroy); + + viewport->surface_commit.notify = viewport_handle_surface_commit; + ds_surface_add_commit_listener(surface, &viewport->surface_commit); +} + +static const struct wl_scaler_interface scaler_iface = { + .destroy = scaler_handle_destroy, + .get_viewport = scaler_handle_get_viewport, +}; + +static void +scaler_bind(struct wl_client *client, void *data, uint32_t version, + uint32_t id) +{ + struct wl_resource *resource; + uint32_t bind_version; + + bind_version = version < SCALER_VERSION ? version : SCALER_VERSION; + resource = wl_resource_create(client, &wl_scaler_interface, bind_version, + id); + if (!resource) { + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(resource, &scaler_iface, NULL, NULL); +} + +static void +scaler_handle_display_destroy(struct wl_listener *listener, void *data) +{ + struct ds_tizen_scaler *scaler; + + scaler = wl_container_of(listener, scaler, display_destroy); + wl_list_remove(&scaler->display_destroy.link); + wl_global_destroy(scaler->global); + free(scaler); +} + +static void +viewport_set_source(struct viewport *viewport, + wl_fixed_t x_fixed, wl_fixed_t y_fixed, + wl_fixed_t width_fixed, wl_fixed_t height_fixed) +{ + double x, y, width, height; + + x = wl_fixed_to_double(x_fixed); + y = wl_fixed_to_double(y_fixed); + width = wl_fixed_to_double(width_fixed); + height = wl_fixed_to_double(height_fixed); + + if (width == -1.0 && height == -1.0) { + ds_surface_viewport_unset_source(viewport->surface_viewport); + } + else if (x < 0 || y < 0 || width <= 0 || height <= 0) { + ds_inf("wl_viewport.set_source sent with invalid values (%f %f %fx%f)", + x, y, width, height); + if (width <= 0 || height <= 0) { + wl_resource_post_error(viewport->resource, + WL_VIEWPORT_ERROR_BAD_VALUE, + "wl_viewport.set_source sent with invalid values"); + } + } + else { + ds_surface_viewport_set_source(viewport->surface_viewport, + x, y, width, height); + } +} + +static void +viewport_set_destination(struct viewport *viewport, + int32_t width, int32_t height) +{ + if (width == -1 && height == -1) { + ds_surface_viewport_unset_destination(viewport->surface_viewport); + } + else if (width <= 0 || height <= 0) { + wl_resource_post_error(viewport->resource, WL_VIEWPORT_ERROR_BAD_VALUE, + "destination size must be positive (%dx%d)", + width, height); + } + else { + ds_surface_viewport_set_destination(viewport->surface_viewport, + width, height); + } +} -- 2.7.4 From 0e394cdf54f64544576fc51d5fe6dbe91f817dea Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 8 Sep 2022 13:10:10 +0900 Subject: [PATCH 10/16] test: Add tests for ds_tizen_scaler Change-Id: I1eb8d0b69f236e77d46c3ef0fd737a337adfc387 --- packaging/libds-tizen.spec | 2 + tests/meson.build | 19 ++++ tests/mockclient.cpp | 46 +++++++- tests/mockclient.h | 2 + tests/mockcompositor.cpp | 5 + tests/mockcompositor.h | 2 + tests/tc_scaler.cpp | 267 +++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 342 insertions(+), 1 deletion(-) create mode 100644 tests/tc_scaler.cpp diff --git a/packaging/libds-tizen.spec b/packaging/libds-tizen.spec index 4ef8195..777384b 100644 --- a/packaging/libds-tizen.spec +++ b/packaging/libds-tizen.spec @@ -39,6 +39,7 @@ BuildRequires: pkgconfig(cynara-session) BuildRequires: pkgconfig(libsmack) BuildRequires: pkgconfig(gmock) BuildRequires: pkgconfig(scaler-server) +BuildRequires: pkgconfig(scaler-client) %description Wayland Compositor Library for Tizen @@ -691,3 +692,4 @@ ninja -C builddir install %{_includedir}/libds-tizen/scaler.h %{_libdir}/pkgconfig/libds-tizen-scaler.pc %{_libdir}/libds-tizen-scaler.so +%{_bindir}/libds-tizen-scaler-tests diff --git a/tests/meson.build b/tests/meson.build index e620eb0..b933ced 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -344,3 +344,22 @@ executable('libds-tizen-screenshooter-tests', install_dir: libds_tizen_bindir, install : true ) + +tc_scaler_files = [ + 'tc_main.cpp', + 'tc_scaler.cpp', +] + +executable('libds-tizen-scaler-tests', + [ + tc_mock_files, + tc_scaler_files + ], + dependencies: [ + deps_test_common, + deps_libds_tizen_scaler, + dependency('scaler-client', required: true), + ], + install_dir: libds_tizen_bindir, + install : true +) diff --git a/tests/mockclient.cpp b/tests/mockclient.cpp index f9f9581..135c51c 100644 --- a/tests/mockclient.cpp +++ b/tests/mockclient.cpp @@ -28,6 +28,7 @@ #include "mockclient.h" #include +#include MockClient::MockClient() { @@ -67,4 +68,47 @@ MockClient::~MockClient() void MockClient::RoundTrip() { wl_display_roundtrip(display); -} \ No newline at end of file +} + +void MockClient::ExpectNoError() +{ + const struct wl_interface *interface; + uint32_t errcode; + + this->RoundTrip(); + + int err = wl_display_get_error(this->display); + + if (err != 0) { + errcode = wl_display_get_protocol_error(this->display, &interface, + NULL); + } + + ASSERT_EQ(err, 0) + << "Expected no error, but got error(" << err << ") interface(" + << interface->name << ") errcode(" << errcode << ")"; + +} + +void MockClient::ExpectProtocolError(const struct wl_interface *intf, + uint32_t code) +{ + this->RoundTrip(); + + int err = wl_display_get_error(this->display); + + ASSERT_NE(err, 0) << "Expected protocol error but nothing came"; + ASSERT_EQ(err, EPROTO) + << "Expected protocol error but got local error"; + + const struct wl_interface *interface; + uint32_t errcode = wl_display_get_protocol_error(this->display, + &interface, NULL); + + ASSERT_EQ(errcode, code) + << "Should get error code " << code << " but got " << errcode; + + ASSERT_STREQ(intf->name, interface->name) + << "Should get interface '" << intf->name << "' but got '" + << interface->name << "'"; +} diff --git a/tests/mockclient.h b/tests/mockclient.h index 178b9bc..d3f4bf6 100644 --- a/tests/mockclient.h +++ b/tests/mockclient.h @@ -39,6 +39,8 @@ public: MockClient(const struct wl_registry_listener *registry_listener, void *data); virtual ~MockClient(); void RoundTrip(); + void ExpectNoError(); + void ExpectProtocolError(const struct wl_interface *intf, uint32_t code); private: struct wl_display *display; diff --git a/tests/mockcompositor.cpp b/tests/mockcompositor.cpp index 62fc779..ef40f81 100644 --- a/tests/mockcompositor.cpp +++ b/tests/mockcompositor.cpp @@ -147,3 +147,8 @@ void MockCompositor::Process() std::lock_guard lock(m); compositor->DispatchEvents(); } + +struct wl_display *MockCompositor::GetWlDisplay() +{ + return this->compositor->display; +} diff --git a/tests/mockcompositor.h b/tests/mockcompositor.h index 2b03f46..a0a8f87 100644 --- a/tests/mockcompositor.h +++ b/tests/mockcompositor.h @@ -65,6 +65,8 @@ public: void Process(); + struct wl_display *GetWlDisplay(); + protected: Compositor *compositor; diff --git a/tests/tc_scaler.cpp b/tests/tc_scaler.cpp new file mode 100644 index 0000000..6a74df5 --- /dev/null +++ b/tests/tc_scaler.cpp @@ -0,0 +1,267 @@ +#include "tc_main.h" +#include "mockclient.h" +#include "mockcompositor.h" + +#include +#include +#include +#include + +TEST(ScalerSimpleTest, CreateScaler) +{ + struct wl_display *display = wl_display_create(); + + struct ds_tizen_scaler *scaler = ds_tizen_scaler_create(display); + ASSERT_NE(scaler, nullptr); + + wl_display_destroy(display); +} + +class ScalerCompositor : public MockCompositor, public ::testing::Test +{ +public: + ScalerCompositor() : + MockCompositor(&ScalerCompositor::SetUpComp, this) + { + /* We are only interested in test results. Let's silence libds log. */ + ds_log_init(DS_SILENT, nullptr); + } + + static void SetUpComp(void *data) + { + ScalerCompositor *comp = static_cast(data); + + struct ds_tizen_scaler *scaler = + ds_tizen_scaler_create(comp->GetWlDisplay()); + ASSERT_NE(scaler, nullptr); + } +}; + +static void handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version); +static void handle_global_remove(void *data, struct wl_registry *registry, + uint32_t name); + +static const struct wl_registry_listener registry_listener = { + .global = handle_global, + .global_remove = handle_global_remove, +}; + +class MockScalerClient : public MockClient +{ +public: + MockScalerClient() : MockClient(®istry_listener, this) + { + EXPECT_NE(this->compositor, nullptr); + EXPECT_NE(this->scaler, nullptr); + + surface = wl_compositor_create_surface(this->compositor); + EXPECT_NE(this->surface, nullptr); + } + + ~MockScalerClient() + { + wl_surface_destroy(this->surface); + wl_scaler_destroy(this->scaler); + wl_compositor_destroy(this->compositor); + } + + struct wl_compositor *compositor; + struct wl_scaler *scaler; + struct wl_surface *surface; +}; + +static void +handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) +{ + MockScalerClient *client = static_cast(data); + + if (strcmp(interface, "wl_compositor") == 0) { + client->compositor = static_cast( + wl_registry_bind(registry, name, &wl_compositor_interface, 4)); + } else if (strcmp(interface, "wl_scaler") == 0) { + client->scaler = static_cast( + wl_registry_bind(registry, name, &wl_scaler_interface, 2)); + } +} + +static void +handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) +{ +} + +TEST_F(ScalerCompositor, CreateViewport) +{ + MockScalerClient *client = new MockScalerClient(); + + struct wl_viewport *vp = wl_scaler_get_viewport(client->scaler, + client->surface); + + client->ExpectNoError(); + + wl_viewport_destroy(vp); + delete client; +} + +TEST_F(ScalerCompositor, CreateViewportTwice) +{ + MockScalerClient *client = new MockScalerClient(); + + struct wl_viewport *vp[2]; + vp[0] = wl_scaler_get_viewport(client->scaler, client->surface); + vp[1] = wl_scaler_get_viewport(client->scaler, client->surface); + + client->ExpectProtocolError(&wl_scaler_interface, + WL_SCALER_ERROR_VIEWPORT_EXISTS); + + wl_viewport_destroy(vp[0]); + wl_viewport_destroy(vp[1]); + delete client; +} + +TEST_F(ScalerCompositor, SetSource) +{ + MockScalerClient *client = new MockScalerClient(); + + struct wl_viewport *vp = wl_scaler_get_viewport(client->scaler, + client->surface); + + wl_viewport_set_source(vp, + wl_fixed_from_int(100), wl_fixed_from_int(100), + wl_fixed_from_int(100), wl_fixed_from_int(100)); + wl_surface_commit(client->surface); + + client->ExpectNoError(); + + wl_viewport_destroy(vp); + delete client; +} + +TEST_F(ScalerCompositor, UnsetSource) +{ + MockScalerClient *client = new MockScalerClient(); + + struct wl_viewport *vp = wl_scaler_get_viewport(client->scaler, + client->surface); + + wl_viewport_set_source(vp, + wl_fixed_from_int(-1.0), wl_fixed_from_int(-1.0), + wl_fixed_from_int(-1.0), wl_fixed_from_int(-1.0)); + wl_surface_commit(client->surface); + + client->ExpectNoError(); + + wl_viewport_destroy(vp); + delete client; +} + +TEST_F(ScalerCompositor, SetDestination) +{ + MockScalerClient *client = new MockScalerClient(); + + struct wl_viewport *vp = wl_scaler_get_viewport(client->scaler, + client->surface); + + wl_viewport_set_destination(vp, 100, 100); + wl_surface_commit(client->surface); + + client->ExpectNoError(); + + wl_viewport_destroy(vp); + delete client; +} + +TEST_F(ScalerCompositor, UnsetDestination) +{ + MockScalerClient *client = new MockScalerClient(); + + struct wl_viewport *vp = wl_scaler_get_viewport(client->scaler, + client->surface); + + wl_viewport_set_destination(vp, -1, -1); + wl_surface_commit(client->surface); + + client->ExpectNoError(); + + wl_viewport_destroy(vp); + delete client; +} + +struct Box { + int x, y, width, height; +}; + +class ScalerCompositorBadSourceTest : + public ScalerCompositor, + public testing::WithParamInterface +{ +}; + +INSTANTIATE_TEST_SUITE_P(ScalerBadSourceParamTest, + ScalerCompositorBadSourceTest, + testing::Values( + Box{0, 0, 0, 0}, + Box{0, 0, 0, 10}, + Box{0, 0, 20, 0}, + Box{0, 0, -20, 10}, + Box{0, 0, 20, -10}, + Box{0, 0, -20, -10})); + +TEST_P(ScalerCompositorBadSourceTest, SetBadSource) +{ + MockScalerClient *client = new MockScalerClient(); + + struct wl_viewport *vp = wl_scaler_get_viewport(client->scaler, + client->surface); + + Box src = GetParam(); + wl_viewport_set_source(vp, + wl_fixed_from_int(src.x), wl_fixed_from_int(src.y), + wl_fixed_from_int(src.width), wl_fixed_from_int(src.height)); + wl_surface_commit(client->surface); + + client->ExpectProtocolError(&wl_viewport_interface, + WL_VIEWPORT_ERROR_BAD_VALUE); + + wl_viewport_destroy(vp); + delete client; +} + +struct Size { + int width, height; +}; + +class ScalerCompositorBadDestinationTest : + public ScalerCompositor, + public testing::WithParamInterface +{ +}; + +INSTANTIATE_TEST_SUITE_P(ScalerBadDestinationParamTest, + ScalerCompositorBadDestinationTest, + testing::Values( + Size{0, 0}, + Size{0, 10}, + Size{20, 0}, + Size{-20, 10}, + Size{20, -10}, + Size{-20, -10})); + +TEST_P(ScalerCompositorBadDestinationTest, SetBadDestination) +{ + MockScalerClient *client = new MockScalerClient(); + + struct wl_viewport *vp = wl_scaler_get_viewport(client->scaler, + client->surface); + + Size dst = GetParam(); + wl_viewport_set_destination(vp, dst.width, dst.height); + wl_surface_commit(client->surface); + + client->ExpectProtocolError(&wl_viewport_interface, + WL_VIEWPORT_ERROR_BAD_VALUE); + + wl_viewport_destroy(vp); + delete client; +} -- 2.7.4 From e468e1e7159dd97e5000606d300853f61665f4c3 Mon Sep 17 00:00:00 2001 From: "duna.oh" Date: Fri, 16 Sep 2022 13:55:03 +0900 Subject: [PATCH 11/16] tinyds: add 'protocol_trace' feature 1. add rules in rule file ALLOW iface=wl_pointer and msg=motion ALLOW iface=wl_seat and type=event 2. set environment variables (or default path is given) $export DS_PROTOCOL_RULE_FILE=/tmp/rule $export DS_PROTOCOL_TRACE_FILE=/tmp/trace 3. will see protocol logs in trace file $tail -f /tmp/trace [1499148.714] Server->Client [PID:25430]wl_seat@7.capabilities(7), cmd: ds-simple-tbm [1499148.810] Server->Client [PID:25430]wl_seat@7.name("seat0"), cmd: ds-simple-tbm [1499155.391] Server [PID:25430] client destroying Change-Id: I9fff75555d002fa0c25a5f3d61ce31c8d7c0886b --- examples/meson.build | 1 + examples/protocol-trace.c | 1603 +++++++++++++++++++++++++++++++++++++++++++++ examples/protocol-trace.h | 10 + examples/tinyds-tdm.c | 9 + 4 files changed, 1623 insertions(+) create mode 100644 examples/protocol-trace.c create mode 100644 examples/protocol-trace.h diff --git a/examples/meson.build b/examples/meson.build index 6a81cbf..dbda372 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -20,6 +20,7 @@ tinyds_tdm_files = [ 'pixman-helper.c', 'pixman-tbm-helper.c', 'tinyds-tdm-renderer.c', + 'protocol-trace.c', ] executable('tinyds-tdm', diff --git a/examples/protocol-trace.c b/examples/protocol-trace.c new file mode 100644 index 0000000..d57e3c2 --- /dev/null +++ b/examples/protocol-trace.c @@ -0,0 +1,1603 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "protocol-trace.h" + +#define PATH_MAX 512 +#define MAX_RULE 64 +#define STRING_MAX 64 + +#define BUF_SNPRINTF(fmt, ARG...) do { \ + str_l = snprintf(str_buff, str_r, fmt, ##ARG); \ + str_buff += str_l; \ + str_r -= str_l; \ +} while (0) + +#ifndef REPLY + #define REPLY(fmt, ARG...) \ + do { \ + if (reply && len && *len > 0) { \ + int s = snprintf(reply, *len, fmt, ##ARG); \ + reply += s; \ + *len -= s; \ + } \ + } while (0) +#endif + +#define MIN(a,b) ((a)<(b)?(a):(b)) + +struct protocol_trace_tree_node +{ + struct protocol_trace_tree_node *left; + struct protocol_trace_tree_node *right; +}; + +struct protocol_trace_tree +{ + int size; + struct protocol_trace_tree_node *head; +}; + +//enums for protocol_trace_policy_type +enum protocol_trace_policy_type +{ + PROTOCOL_POLICY_TYPE_UNDEFINED, + PROTOCOL_POLICY_TYPE_ALLOW, + PROTOCOL_POLICY_TYPE_DENY +}; + +struct protocol_trace_rule +{ + enum protocol_trace_policy_type policy; + struct protocol_trace_tree *tree; +}; + +struct protocol_trace_rule_checker +{ + struct protocol_trace_rule rules[MAX_RULE]; + int count; +}; + +//enums for protocol_trace_protocol_log +enum protocol_trace_protocol_type { + PROTOCOL_TYPE_REQUEST, + PROTOCOL_TYPE_EVENT +}; + +struct protocol_trace_protocol_log +{ + enum protocol_trace_protocol_type type; + int client_pid; + int target_id; + char name[PATH_MAX + 1]; + char cmd[PATH_MAX + 1]; +}; + +//enums for protocol_trace_rule_node +enum protocol_trace_result_type +{ + PROTOCOL_TRACE_RESULT_UNKNOWN, + PROTOCOL_TRACE_RESULT_TRUE, + PROTOCOL_TRACE_RESULT_FALSE +}; + +enum protocol_trace_node_type +{ + PROTOCOL_TRACE_NODE_TYPE_NONE, + PROTOCOL_TRACE_NODE_TYPE_AND, + PROTOCOL_TRACE_NODE_TYPE_OR, + PROTOCOL_TRACE_NODE_TYPE_DATA, + PROTOCOL_TRACE_NODE_TYPE_ALL +}; + +enum protocol_trace_comparer +{ + PROTOCOL_TRACE_COMPARER_EQUAL, + PROTOCOL_TRACE_COMPARER_LESS, + PROTOCOL_TRACE_COMPARER_GREATER, + PROTOCOL_TRACE_COMPARER_LESS_EQ, + PROTOCOL_TRACE_COMPARER_GREATE_EQ, + PROTOCOL_TRACE_COMPARER_NOT_EQ +}; + +enum protocol_trace_data_type +{ + PROTOCOL_TRACE_DATA_TYPE_INTEGER, + PROTOCOL_TRACE_DATA_TYPE_STRING +}; + +struct protocol_trace_rule_node +{ + enum protocol_trace_node_type node_type; + enum protocol_trace_comparer comparer; + enum protocol_trace_data_type value_type; + enum protocol_trace_result_type result; + char variable_name[STRING_MAX]; + + union + { + char string[STRING_MAX]; + int integer; + }value; +}; + +//enums for protocol_trace_token_data +enum protocol_trace_token +{ + PROTOCOL_TRACE_TOKEN_UNKNOWN, + PROTOCOL_TRACE_TOKEN_L_BR, + PROTOCOL_TRACE_TOKEN_R_BR, + PROTOCOL_TRACE_TOKEN_NOT_EQ, + PROTOCOL_TRACE_TOKEN_EQUAL, + PROTOCOL_TRACE_TOKEN_LSS_THAN, + PROTOCOL_TRACE_TOKEN_LSS_EQ, + PROTOCOL_TRACE_TOKEN_GRT_THAN, + PROTOCOL_TRACE_TOKEN_GRT_EQ, + PROTOCOL_TRACE_TOKEN_AND, + PROTOCOL_TRACE_TOKEN_OR, + PROTOCOL_TRACE_TOKEN_SPACE, + PROTOCOL_TRACE_TOKEN_SYMBOL, + PROTOCOL_TRACE_TOKEN_NUMBER, + PROTOCOL_TRACE_TOKEN_EOS, +}; + +struct protocol_trace_token_data +{ + const char **string; + enum protocol_trace_token last_token; + const char *last_symbol; + int symbol_len; +}; + +struct protocol_trace_validate_args +{ + int type; + int target_id; + const char *name; + int pid; + const char *cmd; +}; + +struct argument_details { + char type; + int nullable; +}; + +struct protocol_trace_reply_buffer +{ + char **reply; + int *len; +}; + +enum protocol_trace_rule_set_result +{ + PROTOCOL_TRACE_RULE_SET_OK, + PROTOCOL_TRACE_RULE_SET_ERR_TOO_MANY_RULES, + PROTOCOL_TRACE_RULE_SET_ERR_PARSE, + PROTOCOL_TRACE_RULE_SET_ERR_NO_RULE +}; + +typedef int (*tree_traverse_cb) (struct protocol_trace_tree *tree, + struct protocol_trace_tree_node *node, + struct protocol_trace_tree_node *parent, + void *arg); +static struct protocol_trace_tree_node *parser_parse_token( + struct protocol_trace_tree *tree, + struct protocol_trace_token_data *token); +static bool rule_set(const int argc, const char **argv, char *reply, int *len); + +char trace_env_path[PATH_MAX + 1]; +static FILE *log_fp_ptrace = NULL; +static struct wl_protocol_logger *ds_wl_protocol_logger; +static struct protocol_trace_rule_checker *rc = NULL; +static struct wl_display *display; + +static struct +{ + const char *token_char; + const int token_length; + enum protocol_trace_token token_name; +} token_table[] = +{ + {"\0", 1, PROTOCOL_TRACE_TOKEN_EOS}, + {"\t", 1, PROTOCOL_TRACE_TOKEN_SPACE}, + {" ", 1, PROTOCOL_TRACE_TOKEN_SPACE}, + {"!=", 2, PROTOCOL_TRACE_TOKEN_NOT_EQ}, + {"&", 1, PROTOCOL_TRACE_TOKEN_AND}, + {"&&", 2, PROTOCOL_TRACE_TOKEN_AND}, + {"(", 1, PROTOCOL_TRACE_TOKEN_L_BR}, + {")", 1, PROTOCOL_TRACE_TOKEN_R_BR}, + {"<", 1, PROTOCOL_TRACE_TOKEN_LSS_THAN}, + {"<=", 2, PROTOCOL_TRACE_TOKEN_LSS_EQ}, + {"<>", 2, PROTOCOL_TRACE_TOKEN_NOT_EQ}, + {"=", 1, PROTOCOL_TRACE_TOKEN_EQUAL}, + {"==", 2, PROTOCOL_TRACE_TOKEN_EQUAL}, + {">", 1, PROTOCOL_TRACE_TOKEN_GRT_THAN}, + {">=", 2, PROTOCOL_TRACE_TOKEN_GRT_EQ}, + {"and", 3, PROTOCOL_TRACE_TOKEN_AND}, + {"or", 2, PROTOCOL_TRACE_TOKEN_OR}, + {"|", 1, PROTOCOL_TRACE_TOKEN_OR}, + {"||", 2, PROTOCOL_TRACE_TOKEN_OR}, +}; + +static struct protocol_trace_tree_node * +bintree_get_head(struct protocol_trace_tree *tree) +{ + return tree->head; +} + +static void +bintree_set_head(struct protocol_trace_tree *tree, + struct protocol_trace_tree_node *head) +{ + tree->head = head; +} + +static struct protocol_trace_tree_node * +bintree_get_left_child(struct protocol_trace_tree_node *node) +{ + return node->left; +} + +static void +bintree_set_left_child(struct protocol_trace_tree_node *node, + struct protocol_trace_tree_node *child) +{ + node->left = child; +} + +static struct protocol_trace_tree_node * +bintree_get_right_child(struct protocol_trace_tree_node *node) +{ + return node->right; +} + +static void +bintree_set_right_child(struct protocol_trace_tree_node *node, + struct protocol_trace_tree_node *child) +{ + node->right = child; +} + +static void * +bintree_get_node_data(struct protocol_trace_tree_node *node) +{ + return (void*)(node+1); +} + +static int +bintree_inorder_traverse_recursive(struct protocol_trace_tree *tree, + struct protocol_trace_tree_node *node, + struct protocol_trace_tree_node *parent, + tree_traverse_cb func, void *arg) +{ + if (node->left) { + if (bintree_inorder_traverse_recursive(tree, node->left, node, + func, arg) != 0) + return 1; + } + + if (func(tree, node, parent, arg)) + return 1; + + if (node->right) { + if (bintree_inorder_traverse_recursive(tree, node->right, node, + func, arg) != 0) + return 1; + } + + return 0; +} + +static void +bintree_inorder_traverse(struct protocol_trace_tree *tree, + tree_traverse_cb func, void *arg) +{ + if (tree->head) + bintree_inorder_traverse_recursive(tree, tree->head, tree->head, + func, arg); +} + +static int +bintree_postorder_traverse_recursive(struct protocol_trace_tree *tree, + struct protocol_trace_tree_node *node, + struct protocol_trace_tree_node *parent, + tree_traverse_cb func, void *arg) +{ + if (node->left) { + if (bintree_postorder_traverse_recursive(tree, node->left, node, + func, arg) != 0) + return 1; + } + if (node->right) { + if (bintree_postorder_traverse_recursive(tree, node->right, node, + func, arg) != 0) + return 1; + } + + return func(tree, node,parent, arg); +} + +static void +bintree_postorder_traverse(struct protocol_trace_tree *tree, + tree_traverse_cb func, void *arg) +{ + if (tree->head) + bintree_postorder_traverse_recursive(tree, tree->head, tree->head, + func, arg); +} + +static struct protocol_trace_tree * +bintree_create_tree(int size) +{ + struct protocol_trace_tree *tree; + + tree = calloc(1, sizeof(struct protocol_trace_tree) + size); + if (!tree) + return NULL; + + tree->size = size; + tree->head = NULL; + + return tree; +} +static struct protocol_trace_tree_node * +bintree_create_node(struct protocol_trace_tree *tree) +{ + struct protocol_trace_tree_node *node; + + node = calloc(1, sizeof(struct protocol_trace_tree_node) + tree->size); + if (!node) + return NULL; + + node->left = NULL; + node->right = NULL; + + return node; +} + +static void +bintree_remove_node(struct protocol_trace_tree_node *node) +{ + free(node); +} + +static void +bintree_remove_node_recursive(struct protocol_trace_tree_node *node) +{ + if (node->left) + bintree_remove_node_recursive(node->left); + if (node->right) + bintree_remove_node_recursive(node->right); + + bintree_remove_node(node); +} + +static void +bintree_destroy_tree(struct protocol_trace_tree *tree) +{ + if (tree->head) + bintree_remove_node_recursive(tree->head); + free(tree); +} + +static int +rulechecker_string_compare(enum protocol_trace_comparer comparer, + char *str2, const char *str1) +{ + int result; + + result = strcasecmp(str2, str1); + + switch (comparer) { + case PROTOCOL_TRACE_COMPARER_EQUAL: + return result == 0; + case PROTOCOL_TRACE_COMPARER_LESS: + return result < 0; + case PROTOCOL_TRACE_COMPARER_GREATER: + return result > 0; + case PROTOCOL_TRACE_COMPARER_LESS_EQ: + return result <= 0; + case PROTOCOL_TRACE_COMPARER_GREATE_EQ: + return result >= 0; + case PROTOCOL_TRACE_COMPARER_NOT_EQ: + return result != 0; + } + + return 0; +} + +static int +rulechecker_int_compare(enum protocol_trace_comparer comparer, + int int2, int int1) +{ + switch (comparer) { + case PROTOCOL_TRACE_COMPARER_EQUAL: + return int1 == int2; + case PROTOCOL_TRACE_COMPARER_LESS: + return int1 < int2; + case PROTOCOL_TRACE_COMPARER_GREATER: + return int1 > int2; + case PROTOCOL_TRACE_COMPARER_LESS_EQ: + return int1 <= int2; + case PROTOCOL_TRACE_COMPARER_GREATE_EQ: + return int1 >= int2; + case PROTOCOL_TRACE_COMPARER_NOT_EQ: + return int1 != int2; + } + + return 0; +} + +static int +rulechecker_validate_rule_func(struct protocol_trace_tree *tree, + struct protocol_trace_tree_node *node, + struct protocol_trace_tree_node *parent, + void *arg) +{ + struct protocol_trace_validate_args *args; + struct protocol_trace_tree_node *left, *right; + struct protocol_trace_rule_node *data, *left_data, *right_data; + + args = (struct protocol_trace_validate_args *)arg; + data = (struct protocol_trace_rule_node *)bintree_get_node_data(node); + data->result = PROTOCOL_TRACE_RESULT_UNKNOWN; + + if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_AND || + data->node_type == PROTOCOL_TRACE_NODE_TYPE_OR) { + left = bintree_get_left_child(node); + right = bintree_get_right_child(node); + if (!left || !right) { + ds_err("Node error"); + return -1; + } + + left_data = (struct protocol_trace_rule_node *)bintree_get_node_data(left); + right_data = (struct protocol_trace_rule_node *)bintree_get_node_data(right); + } + + if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_ALL) { + data->result = PROTOCOL_TRACE_RESULT_TRUE; + } else if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_DATA) { + char iface[64] = {0,}; + char *msg = NULL; + + if (args->name) { + msg = (char *) strchr(args->name, ':'); + } + if (msg) { + int size_iface = sizeof(iface) -1; + int min = MIN(size_iface, msg-args->name); + strncpy(iface, args->name, min); + iface[min] = '\0'; + msg++; + } + if (!strcasecmp(data->variable_name, "TYPE")) { + const char *type_string; + if (args->type == 0) + type_string = "REQUEST"; + else if (args->type == 1) + type_string = "EVENT"; + else { + ds_err("Invalid type %d", args->type); + return -1; + } + + if (rulechecker_string_compare(data->comparer, + data->value.string, type_string)) + data->result = PROTOCOL_TRACE_RESULT_TRUE; + else + data->result = PROTOCOL_TRACE_RESULT_FALSE; + } else if (!strcasecmp(data->variable_name, "IFACE")) { + if (msg && iface[0] && + rulechecker_string_compare(data->comparer, + data->value.string, (const char *)iface)) + data->result = PROTOCOL_TRACE_RESULT_TRUE; + else + data->result = PROTOCOL_TRACE_RESULT_FALSE; + } else if (!strcasecmp(data->variable_name, "MSG")) { + if (msg && + rulechecker_string_compare(data->comparer, + data->value.string, msg)) + data->result = PROTOCOL_TRACE_RESULT_TRUE; + else + data->result = PROTOCOL_TRACE_RESULT_FALSE; + } else if (!strcasecmp(data->variable_name, "PID")) { + if (rulechecker_int_compare(data->comparer, + data->value.integer, args->pid)) + data->result = PROTOCOL_TRACE_RESULT_TRUE; + else + data->result = PROTOCOL_TRACE_RESULT_FALSE; + } else if (!strcasecmp(data->variable_name, "CMD") || + !strcasecmp(data->variable_name, "COMMAND")) { + if (msg && + rulechecker_string_compare(data->comparer, + data->value.string, args->cmd)) + data->result = PROTOCOL_TRACE_RESULT_TRUE; + else + data->result = PROTOCOL_TRACE_RESULT_FALSE; + } + } else if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_AND) { + if (left_data->result == PROTOCOL_TRACE_RESULT_TRUE && + right_data->result == PROTOCOL_TRACE_RESULT_TRUE) + data->result = PROTOCOL_TRACE_RESULT_TRUE; + else + data->result = PROTOCOL_TRACE_RESULT_FALSE; + } else if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_OR) { + if (left_data->result == PROTOCOL_TRACE_RESULT_TRUE || + right_data->result == PROTOCOL_TRACE_RESULT_TRUE) + data->result = PROTOCOL_TRACE_RESULT_TRUE; + else + data->result = PROTOCOL_TRACE_RESULT_FALSE; + } else { + return -1; + } + + return 0; +} + +static int +rulechecker_validate_rules(struct protocol_trace_rule_checker *rc, + int type, int target_id, const char *name, int pid, const char *cmd) +{ + struct protocol_trace_validate_args args = {type, target_id, name, pid, cmd}; + struct protocol_trace_tree_node *node; + struct protocol_trace_rule_node *data; + enum protocol_trace_policy_type default_policy; + + default_policy = PROTOCOL_POLICY_TYPE_DENY; + + for (int i = rc->count - 1; i >= 0 ; i--) { + bintree_postorder_traverse(rc->rules[i].tree, rulechecker_validate_rule_func, &args); + node = (struct protocol_trace_tree_node *)bintree_get_head(rc->rules[i].tree); + data = (struct protocol_trace_rule_node *)bintree_get_node_data(node); + + if (data->result == PROTOCOL_TRACE_RESULT_TRUE) { + return rc->rules[i].policy == PROTOCOL_POLICY_TYPE_ALLOW; + } + } + + return default_policy == PROTOCOL_POLICY_TYPE_ALLOW; +} + +static char * +logger_cmd_get(char *path) +{ + char *p; + + if (!path) return NULL; + + p = strrchr(path, '/'); + + return (p) ? p+1 : path; +} + +static bool +logger_validate_rule(struct protocol_trace_protocol_log *log) +{ + const char *cmd = ""; + int ret; + + if (!rc) + return false; + + cmd = logger_cmd_get(log->cmd); + + ret = rulechecker_validate_rules(rc, log->type, log->target_id, log->name, + log->client_pid, cmd); + + return ret; +} + +static void +logger_get_proc_name(pid_t pid, char *name, int size) +{ + FILE *h; + char proc[PATH_MAX], pname[PATH_MAX]; + size_t len; + + if (!name) return; + + snprintf(proc, PATH_MAX, "/proc/%d/cmdline", pid); + + h = fopen(proc, "r"); + if (!h) return; + + len = fread(pname, sizeof(char), PATH_MAX, h); + if (len > 0) + pname[len - 1]='\0'; + else + strncpy(pname, "NO NAME", sizeof(pname)); + + fclose(h); + + strncpy(name, pname, size); +} + +static const char * +logger_get_next_argument(const char *signature, struct argument_details *details) +{ + details->nullable = 0; + + for (; *signature; ++signature) { + switch (*signature) { + case 'i': + case 'u': + case 'f': + case 's': + case 'o': + case 'n': + case 'a': + case 'h': + details->type = *signature; + return signature + 1; + case '?': + details->nullable = 1; + } + } + details->type = '\0'; + + return signature; +} + +static void +logger_handle_client_destroy(struct wl_listener *listener, void *data) +{ + struct wl_client *wc = (struct wl_client *)data; + struct timespec tp; + unsigned int time; + pid_t client_pid =-1; + + char strbuf[PATH_MAX], *str_buff = strbuf; + int str_r, str_l; + + str_buff[0] = '\0'; + str_r = sizeof(strbuf); + + wl_client_get_credentials(wc, &client_pid, NULL, NULL); + + clock_gettime(CLOCK_MONOTONIC, &tp); + time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); + + BUF_SNPRINTF("[%10.3f] Server [PID:%d] client destroying", time / 1000.0, + client_pid); + + if (log_fp_ptrace) + fprintf(log_fp_ptrace, "%s\n", strbuf); + else + ds_dbg("%s", strbuf); + + wl_list_remove(&listener->link); + free(listener); + listener = NULL; +} + +static void +logger_add_client_destroy_listener(struct wl_client *client) +{ + struct wl_listener *destroy_listener; + + destroy_listener = wl_client_get_destroy_listener(client, + logger_handle_client_destroy); + if (destroy_listener) + return; + + destroy_listener = calloc(1, sizeof *destroy_listener); + if (!destroy_listener) + return; + + destroy_listener->notify = logger_handle_client_destroy; + wl_client_add_destroy_listener(client, destroy_listener); +} + +void +logger_func(void *user_data, enum wl_protocol_logger_type direction, + const struct wl_protocol_logger_message *message) +{ + struct argument_details arg; + struct wl_client *wc; + const char *signature;; + pid_t client_pid = -1; + struct timespec tp; + unsigned int time; + + char strbuf[PATH_MAX], *str_buff; + int str_r, str_l; + + wc = wl_resource_get_client(message->resource); + if (wc) { + logger_add_client_destroy_listener(wc); + wl_client_get_credentials(wc, &client_pid, NULL, NULL); + } + + clock_gettime(CLOCK_MONOTONIC, &tp); + time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); + + struct protocol_trace_protocol_log elog = {PROTOCOL_TYPE_REQUEST,}; + if (direction == WL_PROTOCOL_LOGGER_EVENT) + elog.type = PROTOCOL_TYPE_EVENT; + else + elog.type = PROTOCOL_TYPE_REQUEST; + elog.client_pid = client_pid; + elog.target_id = wl_resource_get_id(message->resource); + snprintf(elog.name, PATH_MAX,"%s:%s", + wl_resource_get_class(message->resource), message->message->name); + + char name[PATH_MAX]; + logger_get_proc_name(client_pid, name, PATH_MAX); + snprintf(elog.cmd, PATH_MAX, "%s", name); + + if (!logger_validate_rule(&elog)) return; + + str_buff = strbuf; + str_buff[0] = '\0'; + str_r = sizeof(strbuf); + + BUF_SNPRINTF("[%10.3f] %s%d%s%s@%u.%s(", + time / 1000.0, + elog.type ? "Server->Client [PID:" : "Server<-Client [PID:", + client_pid, "]", + wl_resource_get_class(message->resource), + wl_resource_get_id(message->resource), + message->message->name); + + signature = message->message->signature; + + for (int i = 0; i < message->arguments_count; i++) { + signature = logger_get_next_argument(signature, &arg); + + if (i > 0) BUF_SNPRINTF(", "); + + switch (arg.type) { + case 'u': + BUF_SNPRINTF("%u", message->arguments[i].u); + break; + case 'i': + BUF_SNPRINTF("%i", message->arguments[i].i); + break; + case 'f': + BUF_SNPRINTF("%f", wl_fixed_to_double(message->arguments[i].f)); + break; + case 's': + BUF_SNPRINTF("\"%s\"", message->arguments[i].s); + break; + case 'o': + if (message->arguments[i].o) { + struct wl_resource *resource; + resource = (struct wl_resource *)message->arguments[i].o; + BUF_SNPRINTF("%s@%u", + wl_resource_get_class(resource), + wl_resource_get_id(resource)); + } else + BUF_SNPRINTF("nil"); + break; + case 'n': + BUF_SNPRINTF("new id %s@", (message->message->types[i]) ? + message->message->types[i]->name : "[unknown]"); + if (message->arguments[i].n != 0) + BUF_SNPRINTF("%u", message->arguments[i].n); + else + BUF_SNPRINTF("nil"); + break; + case 'a': + BUF_SNPRINTF("array"); + break; + case 'h': + BUF_SNPRINTF("fd %d", message->arguments[i].h); + break; + } + } + + BUF_SNPRINTF("), cmd: %s", elog.cmd ? elog.cmd : "cmd is NULL"); + + if (log_fp_ptrace) + fprintf(log_fp_ptrace, "%s\n", strbuf); + else + ds_dbg("%s", strbuf); +} + +static void +logger_set(void) +{ + ds_dbg("IN >> logger_set"); + + log_fp_ptrace = fopen(trace_env_path, "a"); + if (!log_fp_ptrace) { + ds_err("failed open file(%s)", trace_env_path); + return; + } + setvbuf(log_fp_ptrace, NULL, _IOLBF, 512); + ds_dbg("has log_fp_ptrace"); + + if (ds_wl_protocol_logger) { + ds_dbg("if has ds_wl_protocol_logger -> destroy"); + wl_protocol_logger_destroy(ds_wl_protocol_logger); + ds_wl_protocol_logger = NULL; + } + ds_wl_protocol_logger = + wl_display_add_protocol_logger(display, logger_func, NULL); + + ds_dbg("OUT << logger_set"); +} + +static void +logger_unset(void) +{ + ds_dbg("IN >> logger_unset"); + + if (ds_wl_protocol_logger) { + wl_protocol_logger_destroy(ds_wl_protocol_logger); + ds_wl_protocol_logger = NULL; + } + + ds_dbg("OUT << logger_unset"); +} + +static enum protocol_trace_token +parser_get_next_token(const char **string) +{ + static int token_cnt; + int i, compare_res, found = 0, first, last; + + first = 0; + last = token_cnt -1; + token_cnt = sizeof(token_table) / sizeof(token_table[0]); + + i = (first + last) / 2; + while (1) { + compare_res = strncmp(*string, token_table[i].token_char, + token_table[i].token_length); + while (compare_res == 0) { + found = 1; + i++; + if (i == token_cnt) + break; + compare_res = strncmp(*string, token_table[i].token_char, + token_table[i].token_length); + } + + if (found) { + i--; + *string += token_table[i].token_length; + return token_table[i].token_name; + } + + if (first >= last) + break; + + if (compare_res > 0) + first = i + 1; + else + last = i - 1; + + i = (first + last) / 2; + } + + if (isalpha(**string)) { + (*string)++; + while (isalpha(**string) || isdigit(**string) || + **string == '_' || **string == '-') { + (*string)++; + } + + return PROTOCOL_TRACE_TOKEN_SYMBOL; + } + + if (isdigit(**string)) { + (*string)++; + while (isdigit(**string)) + (*string)++; + + return PROTOCOL_TRACE_TOKEN_NUMBER; + } + + return PROTOCOL_TRACE_TOKEN_UNKNOWN; +} + +static void +parser_process_token(struct protocol_trace_token_data *token) +{ + do { + token->last_symbol = *(token->string); + token->last_token = parser_get_next_token(token->string); + token->symbol_len = *(token->string) - token->last_symbol; + } while (token->last_token == PROTOCOL_TRACE_TOKEN_SPACE); +} + +static struct protocol_trace_tree_node * +parser_parse_statement(struct protocol_trace_tree *tree, + struct protocol_trace_token_data *token) +{ + struct protocol_trace_tree_node *node = NULL; + struct protocol_trace_rule_node *data; + + if (token->last_token == PROTOCOL_TRACE_TOKEN_L_BR) { + parser_process_token(token); + + node = parser_parse_token(tree, token); + if (!node) + return NULL; + + if (token->last_token != PROTOCOL_TRACE_TOKEN_R_BR) + goto fail; + + parser_process_token(token); + + return node; + } + + if (token->last_token != PROTOCOL_TRACE_TOKEN_SYMBOL) + goto fail; + + node = bintree_create_node(tree); + if (!node) + goto fail; + + data = (struct protocol_trace_rule_node *) bintree_get_node_data(node); + + strncpy(data->variable_name, token->last_symbol, token->symbol_len); + data->variable_name[token->symbol_len] = '\0'; + + if (!strcasecmp(data->variable_name, "all")) { + ds_dbg("data = all"); + data->node_type = PROTOCOL_TRACE_NODE_TYPE_ALL; + parser_process_token(token); + + return node; + } + + data->node_type = PROTOCOL_TRACE_NODE_TYPE_DATA; + + parser_process_token(token); + + switch (token->last_token) { + case PROTOCOL_TRACE_TOKEN_NOT_EQ: + data->comparer = PROTOCOL_TRACE_COMPARER_NOT_EQ; + break; + case PROTOCOL_TRACE_TOKEN_EQUAL: + data->comparer = PROTOCOL_TRACE_COMPARER_EQUAL; + break; + case PROTOCOL_TRACE_TOKEN_LSS_THAN: + data->comparer = PROTOCOL_TRACE_COMPARER_LESS_EQ; + break; + case PROTOCOL_TRACE_TOKEN_GRT_THAN: + data->comparer = PROTOCOL_TRACE_COMPARER_GREATER; + break; + case PROTOCOL_TRACE_TOKEN_GRT_EQ: + data->comparer = PROTOCOL_TRACE_COMPARER_GREATE_EQ; + break; + default: + goto fail; + } + + parser_process_token(token); + + if (token->last_token == PROTOCOL_TRACE_TOKEN_NUMBER) { + data->value_type = PROTOCOL_TRACE_DATA_TYPE_INTEGER; + data->value.integer = atoi(token->last_symbol); + } else if (token->last_token == PROTOCOL_TRACE_TOKEN_SYMBOL) { + data->value_type = PROTOCOL_TRACE_DATA_TYPE_STRING; + strncpy(data->value.string, token->last_symbol, token->symbol_len); + data->value.string[token->symbol_len] = '\0'; + } else { + goto fail; + } + + parser_process_token(token); + + return node; + +fail: + if (node) + bintree_remove_node_recursive(node); + + return NULL; +} + +static struct protocol_trace_tree_node * +parser_parse_token(struct protocol_trace_tree *tree, + struct protocol_trace_token_data *token) +{ + struct protocol_trace_tree_node *node, *left = NULL, *right = NULL; + struct protocol_trace_rule_node *data; + + node = parser_parse_statement(tree,token); + if (!node) { + ds_err("PARSE statement error\n"); + goto fail; + } + + while (token->last_token == PROTOCOL_TRACE_TOKEN_AND) { + left = node; + node = NULL; + + parser_process_token(token); + + right = parser_parse_statement(tree, token); + if (!right) + goto fail; + + node = bintree_create_node(tree); + if (!node) + goto fail; + + data = (struct protocol_trace_rule_node *) bintree_get_node_data(node); + data->node_type = PROTOCOL_TRACE_NODE_TYPE_AND; + bintree_set_left_child(node, left); + bintree_set_right_child(node, right); + } + + if (token->last_token == PROTOCOL_TRACE_TOKEN_OR) { + left = node; + node = NULL; + + parser_process_token(token); + + right = parser_parse_token(tree, token); + if (!right) + goto fail; + + node = bintree_create_node(tree); + if (!node) + goto fail; + + data = (struct protocol_trace_rule_node *) bintree_get_node_data(node); + data->node_type = PROTOCOL_TRACE_NODE_TYPE_OR; + bintree_set_left_child(node, left); + bintree_set_right_child(node, right); + } + + return node; + +fail: + ds_dbg("[fail] recursive remove node"); + if (left) + bintree_remove_node_recursive(left); + + return NULL; +} + +static struct protocol_trace_tree * +parser_parse_rule_string(const char *string) +{ + struct protocol_trace_tree *tree; + struct protocol_trace_tree_node *node; + struct protocol_trace_token_data token; + + token.string = &string; + parser_process_token(&token); + + tree = bintree_create_tree(sizeof(struct protocol_trace_rule_node)); + if (!tree) + return NULL; + + node = parser_parse_token(tree, &token); + if (!node) { + bintree_destroy_tree(tree); + ds_dbg("finish destroy tree & return null"); + return NULL; + } + + bintree_set_head(tree, node); + + return tree; +} + +static enum protocol_trace_rule_set_result +rulechecker_rule_add(struct protocol_trace_rule_checker *rc, + enum protocol_trace_policy_type policy, const char *rule_string) +{ + if (rc->count == MAX_RULE) + return PROTOCOL_TRACE_RULE_SET_ERR_TOO_MANY_RULES; + + rc->rules[rc->count].tree = parser_parse_rule_string(rule_string); + if (!rc->rules[rc->count].tree) { + ds_dbg("parse error"); + return PROTOCOL_TRACE_RULE_SET_ERR_PARSE; + } + + rc->rules[rc->count].policy = policy; + rc->count++; + + return PROTOCOL_TRACE_RULE_SET_OK; +} + +static const char * +rulechecker_usage_print() +{ + return + "##########################################################\n" + "### Enlightenment Protocol Log filtering. ###\n" + "##########################################################\n" + "\n" + "-----------------------------------------------------------------\n" + "How to read enlightenment_info protocol messages :\n" + "[timestamp] Server --> Client [PID: [pid]] interface@id.message(arguments..) cmd: CMD\n" + " ex)\n" + "[1476930.145] Server --> Client [PID: 103] wl_touch@10.down(758, 6769315, wl_surface@23, 0, 408.000, 831.000) cmd: /usr/bin/launchpad-loader\n" + " ==> type = event && pid = 103 && cmd = launchpad-loader && iface = wl_touch && msg = up\n" + "[4234234.123] Server <-- Client [PID: 123] wl_seat@32.get_touch(new id wl_touch@22) cmd: /usr/bin/launchpad-loader\n" + " ==> type = request && pid = 123 && cmd = launchpad-loader && iface = wl_seat && msg = get_touch\n" + "-----------------------------------------------------------------\n" + "Usage : enlightenment_info -protocol_rule add [POLICY] [RULE]\n" + " enlightenment_info -protocol_rule remove [INDEX]\n" + " enlightenment_info -protocol_rule file [RULE_FILE]\n" + " enlightenment_info -protocol_rule print\n" + " enlightenment_info -protocol_rule help\n" + " [POLICY] : allow / deny \n" + " [RULE] : C Language-style boolean expression syntax. [VARIABLE] [COMPAROTOR] [VALUE]\n" + " [VARIABLE] : type / iface / msg / cmd(command) / pid\n" + " [COMPARATOR] : & / && / and / | / || / or / = / == / != / > / >= / < / <=\n" + " [VALUE] : string / number \n" + " ex)\n" + " enlightenment_info -protocol_rule add allow \"(type=request) && (iface == wl_pointer and (msg = down or msg = up))\"\n" + " enlightenment_info -protocol_rule add deny cmd!= launch-loader\n" + " enlightenment_info -protocol_rule remove all\n" + " enlightenment_info -protocol_rule remove 3\n" + "\n"; +} + +static int +rulechecker_print_func(struct protocol_trace_tree *tree, + struct protocol_trace_tree_node *node, + struct protocol_trace_tree_node *parent, void *arg) +{ + struct protocol_trace_reply_buffer *buffer = (struct protocol_trace_reply_buffer *)arg; + char *reply = *buffer->reply; + int *len = buffer->len; + const char *operators[] = {"==", "<", ">", "<=", ">=", "!=" }; + struct protocol_trace_rule_node *data; + + data = (struct protocol_trace_rule_node *)bintree_get_node_data(node); + + if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_ALL) + REPLY(" ALL"); + else if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_AND) + REPLY(" AND"); + else if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_OR) + REPLY(" OR"); + else { // data->node_type == PROTOCOL_TRACE_NODE_TYPE_DATA + if (node == bintree_get_left_child(parent)) + REPLY(" ("); + REPLY(" %s %s ", + data->variable_name, operators[data->comparer]); + + if (data->value_type == PROTOCOL_TRACE_DATA_TYPE_INTEGER) + REPLY(" %d", + data->value.integer); + else + REPLY(" %s", + data->value.string); + + if (node == bintree_get_right_child(parent)) + REPLY(" )"); + } + + *buffer->reply = reply; + + return 0; +} + +static void +rulechecker_print_rules(struct protocol_trace_rule_checker *rc, + char *reply, int *len) +{ + struct protocol_trace_reply_buffer buffer = {&reply, len}; + int i; + + REPLY("\n --------------------[ Protocol Filter Rules ]--------------------\n"); + REPLY(" No Policy Rule\n"); + REPLY(" -----------------------------------------------------------------\n"); + + for (i =0; i < rc->count; i++) { + REPLY(" %3d %10s \"", i, + rc->rules[i].policy == PROTOCOL_POLICY_TYPE_ALLOW ? + "ALLOW" : "DENY"); + bintree_inorder_traverse(rc->rules[i].tree, rulechecker_print_func, + (void*) & buffer); + REPLY("\"\n"); + } +} + +static enum protocol_trace_rule_set_result +rulechecker_rule_remove(struct protocol_trace_rule_checker *rc, int index) +{ + if (index < 0 || index >= rc->count) + return PROTOCOL_TRACE_RULE_SET_ERR_NO_RULE; + + bintree_destroy_tree(rc->rules[index].tree); + rc->count--; + if (index != rc->count) { + memmove(&rc->rules[index], &rc->rules[index + 1], + sizeof(struct protocol_trace_rule)*(rc->count - index)); + } + + return PROTOCOL_TRACE_RULE_SET_OK; +} + +static struct protocol_trace_rule_checker * +rulechecker_init() +{ + struct protocol_trace_rule_checker *rc; + + rc = calloc(1, sizeof *rc); + if (!rc) + return NULL; + + rc->count = 0; + + return rc; +} + +static void rulechecker_destroy(struct protocol_trace_rule_checker *rc) +{ + for (int i = rc->count - 1; i >= 0; i--) + rulechecker_rule_remove(rc, i); + + free(rc); +} + +static bool +rule_file_set(const char *filename, char *reply, int *len) +{ + int fd = -1, rule_len; + char fs[8096], *pfs; + + ds_dbg("IN >> rule_file_set"); + + fd = open(filename, O_RDONLY); + if (fd < 0) { + ds_err("failed: open '%s'", filename); + return false; + } + + rule_len = read(fd, fs, sizeof(fs)); + pfs = fs; + + while (pfs -fs < rule_len) { + int i, new_argc =3; + const char *new_argv[3] = {"add", }; + char policy[64] = {0,}; + char rule[1024] = {0,}; + + if (pfs[0] == ' ' || pfs[0] == '\n') { + pfs++; + continue; + } + for (i = 0; pfs[i] != ' '; i++) + policy[i] = pfs[i]; + + new_argv[1] = policy; + pfs += (strlen(new_argv[1]) + 1); + + memset(rule, 0, sizeof(rule)); + for (i = 0; pfs[i] != '\n'; i++) + rule[i] = pfs[i]; + + new_argv[2] = rule; + + pfs += (strlen(new_argv[2]) +1); + + if (!rule_set((const int)new_argc, (const char**)new_argv, + reply, len)) { + close(fd); + return false; + } + } + close(fd); + + ds_dbg("OUT << rule_file_set"); + + return true; +} + +static int +rule_check_remove_rule(const char *str) +{ + char *endptr; + int index; + + index = strtol(str, &endptr, 10); + + if (errno == ERANGE) { + ds_err("Rule remove fail : overflow"); + return -1; + } + + if (errno != 0) { + ds_err("Rule remove fail : other error"); + return -1; + } + + if (endptr == 0) { + ds_err("Rule remove fail : non-numeric"); + return -1; + } + + if (*endptr != '\0') { + ds_err("Rule remove fail : non-numeric at end"); + return -1; + } + + if (isspace(*str)) { + ds_err("Rule remove fail : space at beginning"); + return -1; + } + + return index; +} + +static void +rule_arguments_merge(char *target, int target_size, + int argc, const char **argv) +{ + int i, len; + + for (i = 0; i < argc; i++) { + len = snprintf(target, target_size, "%s", argv[i]); + target += len; + target_size -= len; + + if (i != argc - 1) { + *(target++) = ' '; + target_size--; + } + } +} + +static bool +rule_set(const int argc, const char **argv, char *reply, int *len) +{ + const char * command; + + ds_dbg("IN >> rule_set"); + ds_dbg("(parameter) argc = %d, argv[0] = %s", argc, argv[0]); + + if (argc == 0) { + rulechecker_print_rules(rc, reply, len); + return true; + } + + command = argv[0]; + + if (!strcasecmp(command, "add")) { + ds_dbg("ADD"); + enum protocol_trace_policy_type policy_type; + enum protocol_trace_rule_set_result result; + const char * policy = argv[1]; //allow, deny + char merge[8192] = {0,}, rule[8192] = {0,}; + int i, index=0, size_rule, apply = 0, size_merge; + + if (argc <3) { + ds_err("Error: Too few argumens."); + return false; + } + + if (!strcasecmp(policy, "ALLOW")) + policy_type = PROTOCOL_POLICY_TYPE_ALLOW; + else if (!strcasecmp(policy, "DENY")) + policy_type = PROTOCOL_POLICY_TYPE_DENY; + else { + ds_err("Error : Unknown : [%s].\n should be ALLOW/DENY.", policy); + return false; + } + + rule_arguments_merge(merge, sizeof(merge), argc -2, &(argv[2])); + + size_rule = sizeof(rule) -1; + size_merge = strlen(merge); + + for (i = 0; i < size_merge; i++) { + if (merge[i] == '\"' || merge[i] == '\'') { + rule[index++] = ' '; + if (index > size_rule) + return false; + continue; + } + if (merge[i] == '+') { + rule[index++] = ' '; + if (index > size_rule) + return false; + if (apply == 0) { + const char * plus = "|| type=reply || type=error"; + int size_plus = strlen(plus); + int len = MIN(size_rule - index, size_plus); + snprintf(rule, sizeof(rule), "%s", plus); + index += len; + if (index >size_rule) + return false; + apply =1; + } + continue; + } + rule[index++] = merge[i]; + if (index > size_rule) + return false; + } + ds_dbg("ADD :: rule = %s", rule); + + result = rulechecker_rule_add(rc, policy_type, rule); + + if (result == PROTOCOL_TRACE_RULE_SET_ERR_TOO_MANY_RULES) { + ds_err("Error: Too many rules were added."); + return false; + } else if (result == PROTOCOL_TRACE_RULE_SET_ERR_PARSE) { + ds_err("Error: parsing the rule [%s]", rule); + return false; + } + ds_dbg( "The rule was successfully added"); + + } else if (!strcasecmp(command, "remove")) { + const char * remove_idx; + int i; + + ds_dbg("REMOVE"); + + if (argc < 2) { + ds_err("Error: Too few arguments"); + return false; + } + + for (i = 0; i < argc - 1; i++) { + remove_idx = argv[i + 1]; + if (!strcasecmp(remove_idx, "all")) { + ds_dbg("REMOVE :: all"); + rulechecker_destroy(rc); + rc = rulechecker_init(); + if (!rc) { + ds_err("Error: rules not removed"); + return false; + } + } else { + int index = rule_check_remove_rule(remove_idx); + if (index == -1) { + ds_err("Rule remove fail : overflow"); + } else { + ds_dbg("REMOVE :: remove idx = %d", index); + + if (isdigit(*remove_idx) && + rulechecker_rule_remove(rc, index) == 0) + ds_dbg("Rule remove success : rule [%d]", index); + else + ds_err("Rule remove fail : No rule [%s]", remove_idx); + } + } + } + } else if (!strcasecmp(command, "file")) { + ds_dbg("FILE"); + if (argc <2) { + ds_err("Error: Too few argumens."); + return false; + } + + if (!rule_file_set(argv[1], reply, len)) + return false; + + rulechecker_print_rules(rc, reply, len); + } else if (!strcasecmp(command, "print")) { + rulechecker_print_rules(rc, reply, len); + } else if (!strcasecmp(command, "help")) { + ds_dbg( "%s", rulechecker_usage_print()); + } else { + ds_err("%s\nUnknown command : [%s] ", rulechecker_usage_print(), command); + } + + ds_dbg("OUT << rule_set"); + + return true; +} + +static bool +rule_init(char *rule_path) +{ + bool ret = false; + const char *argv[2]; + int argc = 2; + + char tmpReply[4096]; + int tmpLen = sizeof(tmpReply); + char *reply = tmpReply; + int *len = &tmpLen; + + if (!rule_path || strlen(rule_path) <= 0) { + rule_path = alloca(10); + snprintf(rule_path, 10, "%s", "/tmp/rule"); + ds_inf("rule path is default = %s", rule_path); + } + + argv[0] = "file"; + argv[1] = rule_path; + + ds_dbg("rule_path = %s", rule_path); + + ret = rule_set(argc, (const char**)&(argv[0]), reply, len); + ds_inf("%s", &tmpReply); + + return ret; +} + +static bool +logger_init(char *trace_path) +{ + ds_dbg("IN >> logger_init"); + if (!trace_path || strlen(trace_path) <= 0) { + snprintf(trace_env_path, sizeof(trace_env_path), "%s", "/tmp/trace"); + ds_inf("trace path is default = %s", trace_env_path); + } else { + snprintf(trace_env_path, sizeof(trace_env_path), "%s", trace_path); + } + + ds_dbg("saved trace path = %s", trace_env_path); + + logger_unset(); + ds_dbg("OUT << logger_init"); + + return true; +} + +int +protocol_trace_enable(bool state) +{ + if (log_fp_ptrace != NULL) { + fclose(log_fp_ptrace); + log_fp_ptrace = NULL; + } + + if (state) { + //TODO: can change trace file path by cmd + ds_inf("state: protocol_trace enabled"); + logger_set(); + return 1; + } else { + ds_inf("state: protocol_trace disabled"); + logger_unset(); + return 0; + } + + return -1; +} + +bool +protocol_trace_init(struct wl_display *d) +{ + bool ret = false; + char *env_path = NULL; + + display = d; + rc = rulechecker_init(); + + env_path = getenv("DS_PROTOCOL_RULE_FILE"); + ret = rule_init(env_path); + + if (env_path) { + char *tmp = strdup(env_path); + if (!tmp) return false; + free(tmp); + env_path = NULL; + } + if (!ret) + return ret; + + env_path = getenv("DS_PROTOCOL_TRACE_FILE"); + ret = logger_init(env_path); + + if (env_path) { + char *tmp = strdup(env_path); + if (!tmp) return false; + free(tmp); + env_path = NULL; + } + + return ret; +} + +void +protocol_trace_fini() +{ + rulechecker_destroy(rc); +} \ No newline at end of file diff --git a/examples/protocol-trace.h b/examples/protocol-trace.h new file mode 100644 index 0000000..973b30e --- /dev/null +++ b/examples/protocol-trace.h @@ -0,0 +1,10 @@ +#ifndef EXAMPLES_PROTOCOL_TRACE_H +#define EXAMPLES_PROTOCOL_TRACE_H + +#include + +bool protocol_trace_init(struct wl_display *display); +int protocol_trace_enable(bool state); +void protocol_trace_fini(); + +#endif diff --git a/examples/tinyds-tdm.c b/examples/tinyds-tdm.c index a797ca2..a915c21 100644 --- a/examples/tinyds-tdm.c +++ b/examples/tinyds-tdm.c @@ -42,6 +42,7 @@ #endif #include "pixman-helper.h" +#include "protocol-trace.h" #define TINYDS_UNUSED __attribute__((unused)) struct tinyds_keyboard; @@ -427,6 +428,9 @@ main(void) wl_display_run(display); + protocol_trace_enable(false); + protocol_trace_fini(); + wl_display_destroy_clients(display); wl_display_destroy(display); @@ -1010,6 +1014,11 @@ init_server(struct tinyds_server *server, struct wl_display *display) if (!add_new_input_method(server)) goto err; + if (!protocol_trace_init(display)) + goto err; + + protocol_trace_enable(true); + return true; err: -- 2.7.4 From 9ee25d4092b825884e6723088a38ab2a851b01bc Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Fri, 23 Sep 2022 14:52:48 +0900 Subject: [PATCH 12/16] test: adapt the change of policy request the argument of interactive_mode_done and interactive_resize_done is changed. Change-Id: I81d604d1ca7a2f69e5ccda7b7731ba5ed42fb6a0 --- tests/tc_policy.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/tc_policy.cpp b/tests/tc_policy.cpp index d38152e..c96c629 100644 --- a/tests/tc_policy.cpp +++ b/tests/tc_policy.cpp @@ -1606,6 +1606,7 @@ public: mConformantPart(0), mState(0), mX(-1), mY(-1), mW(0), mH(0), + mAngle(0), mSerial(0), mVisibilityType(0), mVisibilityOption(0), @@ -1681,6 +1682,7 @@ public: uint32_t mConformantPart; uint32_t mState; int32_t mX, mY, mW, mH; + int32_t mAngle; uint32_t mSerial; uint32_t mVisibilityType; uint32_t mVisibilityOption; @@ -1842,7 +1844,7 @@ client_tizen_policy_cb_conformant_region(void *data, static void client_tizen_policy_cb_interactive_mode_done(void *data, struct tizen_policy *policy_res, struct wl_surface *surface_resource, - int32_t x, int32_t y, uint32_t w, uint32_t h) + int32_t x, int32_t y, uint32_t w, uint32_t h, int32_t angle) { ds_inf("%s", __func__); @@ -1853,12 +1855,13 @@ client_tizen_policy_cb_interactive_mode_done(void *data, client->mY = y; client->mW = w; client->mH = h; + client->mAngle = angle; } static void client_tizen_policy_cb_interactive_resize_done(void *data, struct tizen_policy *policy_res, struct wl_surface *surface_resource, - int32_t x, int32_t y, uint32_t w, uint32_t h) + int32_t x, int32_t y, uint32_t w, uint32_t h, int32_t angle) { ds_inf("%s", __func__); @@ -1869,6 +1872,7 @@ client_tizen_policy_cb_interactive_resize_done(void *data, client->mY = y; client->mW = w; client->mH = h; + client->mAngle = angle; } static const struct -- 2.7.4 From b84fa0574cfe29d309b7a3d88336d02c1404285c Mon Sep 17 00:00:00 2001 From: "duna.oh" Date: Thu, 22 Sep 2022 10:59:03 +0900 Subject: [PATCH 13/16] dpms: add null checking of 'dpms->res' variable dpms->res could be null if no client binds to dpms interface Change-Id: I4bb631903190ed9a892857b24ea0eb4776b341c5 --- src/dpms/dpms.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dpms/dpms.c b/src/dpms/dpms.c index 833005f..cec0dc2 100644 --- a/src/dpms/dpms.c +++ b/src/dpms/dpms.c @@ -110,7 +110,8 @@ dpms_handle_display_destroy(struct wl_listener *listener, void *data) wl_signal_emit(&dpms->events.destroy, dpms); wl_list_remove(&dpms->destroy.link); - wl_resource_set_user_data(dpms->res, NULL); + if (dpms->res) + wl_resource_set_user_data(dpms->res, NULL); wl_global_destroy(dpms->global); free(dpms); } -- 2.7.4 From b1ecbab669ed1c57b91c9e3748846121020159ab Mon Sep 17 00:00:00 2001 From: "duna.oh" Date: Thu, 22 Sep 2022 11:06:42 +0900 Subject: [PATCH 14/16] tinyds: removes wl_listeners when it's destroied To fix segfault error, wl_listeners should be removed properly. Change-Id: Ida1a6c8c51eefa08932c22fb6296635532f3edb7 --- examples/tinyds-tdm.c | 80 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 63 insertions(+), 17 deletions(-) diff --git a/examples/tinyds-tdm.c b/examples/tinyds-tdm.c index a915c21..b64271e 100644 --- a/examples/tinyds-tdm.c +++ b/examples/tinyds-tdm.c @@ -288,11 +288,10 @@ struct tinyds_text_input { struct wl_list input_methods; - struct wl_listener destroy; struct wl_listener mgr_destroy; - struct wl_listener new_text_input; + struct wl_listener destroy; struct wl_listener text_input_activate; struct wl_listener text_input_deactivate; struct wl_listener text_input_reset; @@ -1946,22 +1945,10 @@ text_input_mgr_handle_destroy(struct wl_listener *listener, void *data) text_input = wl_container_of(listener, text_input, mgr_destroy); wl_list_remove(&text_input->mgr_destroy.link); - wl_list_remove(&text_input->destroy.link); - wl_list_remove(&text_input->new_text_input.link); - wl_list_remove(&text_input->text_input_activate.link); - wl_list_remove(&text_input->text_input_deactivate.link); - wl_list_remove(&text_input->text_input_reset.link); - wl_list_remove(&text_input->text_input_set_content_type.link); - wl_list_remove(&text_input->text_input_invoke_action.link); - wl_list_remove(&text_input->text_input_commit_state.link); - wl_list_remove(&text_input->text_input_set_preferred_language.link); - server = text_input->server; server->text_input = NULL; - - free(text_input); } static void @@ -1974,6 +1961,15 @@ text_input_handle_destroy(struct wl_listener *listener, void *data) text_input = wl_container_of(listener, text_input, destroy); wl_list_remove(&text_input->destroy.link); + wl_list_remove(&text_input->text_input_activate.link); + wl_list_remove(&text_input->text_input_deactivate.link); + wl_list_remove(&text_input->text_input_reset.link); + wl_list_remove(&text_input->text_input_set_content_type.link); + wl_list_remove(&text_input->text_input_invoke_action.link); + wl_list_remove(&text_input->text_input_commit_state.link); + wl_list_remove(&text_input->text_input_set_preferred_language.link); + + free(text_input); } static void @@ -2450,9 +2446,9 @@ add_new_text_input(struct tinyds_server *server) wl_list_init(&text_input->input_methods); - text_input->destroy.notify = text_input_mgr_handle_destroy; + text_input->mgr_destroy.notify = text_input_mgr_handle_destroy; ds_tizen_text_input_manager_add_destroy_listener(text_input->text_input_mgr, - &text_input->destroy); + &text_input->mgr_destroy); text_input->new_text_input.notify = text_input_mgr_handle_new_text_input; ds_tizen_text_input_manager_add_new_text_input_listener(text_input->text_input_mgr, @@ -2595,6 +2591,7 @@ visibility_handle_destroy(struct wl_listener *listener, void *data) ds_inf("Policy Visibility(%p) destroy", visibility); + wl_list_remove(&visibility->destroy.link); wl_list_remove(&visibility->link); free(visibility); } @@ -2608,6 +2605,8 @@ position_handle_destroy(struct wl_listener *listener, void *data) ds_inf("Policy Position(%p) destroy", position); + wl_list_remove(&position->destroy.link); + wl_list_remove(&position->set.link); wl_list_remove(&position->link); free(position); } @@ -2633,6 +2632,7 @@ subsurface_watcher_handle_destroy(struct wl_listener *listener, void *data) ds_inf("Policy Subsurface_Watcher(%p) destroy", subsurface_watcher); + wl_list_remove(&subsurface_watcher->destroy.link); wl_list_remove(&subsurface_watcher->link); free(subsurface_watcher); } @@ -2646,6 +2646,38 @@ policy_surface_handle_destroy(struct wl_listener *listener, void *data) ds_inf("Policy Info(%p) destroy", policy_surface); + wl_list_remove(&policy_surface->destroy.link); + wl_list_remove(&policy_surface->new_visibility.link); + wl_list_remove(&policy_surface->new_position.link); + wl_list_remove(&policy_surface->activate.link); + wl_list_remove(&policy_surface->raise.link); + wl_list_remove(&policy_surface->lower.link); + wl_list_remove(&policy_surface->set_focus_skip.link); + wl_list_remove(&policy_surface->unset_focus_skip.link); + wl_list_remove(&policy_surface->set_role.link); + wl_list_remove(&policy_surface->set_window_type.link); + wl_list_remove(&policy_surface->set_conformant.link); + wl_list_remove(&policy_surface->unset_conformant.link); + wl_list_remove(&policy_surface->get_conformant.link); + wl_list_remove(&policy_surface->set_notification_level.link); + wl_list_remove(&policy_surface->set_window_screen_mode.link); + wl_list_remove(&policy_surface->get_subsurface.link); + wl_list_remove(&policy_surface->iconify.link); + wl_list_remove(&policy_surface->uniconify.link); + wl_list_remove(&policy_surface->add_aux_hint.link); + wl_list_remove(&policy_surface->change_aux_hint.link); + wl_list_remove(&policy_surface->delete_aux_hint.link); + wl_list_remove(&policy_surface->get_supported_aux_hints.link); + wl_list_remove(&policy_surface->set_floating_mode.link); + wl_list_remove(&policy_surface->unset_floating_mode.link); + wl_list_remove(&policy_surface->set_stack_mode.link); + wl_list_remove(&policy_surface->new_subsurface_watcher.link); + wl_list_remove(&policy_surface->set_parent.link); + wl_list_remove(&policy_surface->ack_conformant_region.link); + wl_list_remove(&policy_surface->set_video.link); + wl_list_remove(&policy_surface->show.link); + wl_list_remove(&policy_surface->hide.link); + wl_list_remove(&policy_surface->set_parent_with_below.link); wl_list_remove(&policy_surface->link); free(policy_surface); } @@ -3074,6 +3106,20 @@ policy_handle_destroy(struct wl_listener *listener, void *data) ds_inf("Policy(%p) destroy", policy); + wl_list_remove(&policy->destroy.link); + wl_list_remove(&policy->new_surface.link); + wl_list_remove(&policy->activate_below_by_univeral_id.link); + wl_list_remove(&policy->lower_by_universal_id.link); + wl_list_remove(&policy->set_transient_for.link); + wl_list_remove(&policy->unset_transient_for.link); + wl_list_remove(&policy->place_subsurface_below_parent.link); + wl_list_remove(&policy->set_subsurface_stand_alone.link); + wl_list_remove(&policy->set_background_state.link); + wl_list_remove(&policy->unset_background_state.link); + wl_list_remove(&policy->add_activate_above_by_universal_id.link); + wl_list_remove(&policy->set_appid.link); + wl_list_remove(&policy->set_transient_for_below.link); + free(policy); } @@ -3422,7 +3468,7 @@ new_policy(struct tinyds_server *server) policy->set_background_state.notify = policy_handle_set_background_state; ds_tizen_policy_add_set_background_state_listener(policy->policy, - &policy->destroy); + &policy->set_background_state); policy->unset_background_state.notify = policy_handle_unset_background_state; ds_tizen_policy_add_unset_background_state_listener(policy->policy, -- 2.7.4 From f56b48d1f5e8076afc4b00020a97952db52a1c86 Mon Sep 17 00:00:00 2001 From: Junkyeong Kim Date: Thu, 6 Oct 2022 11:42:49 +0900 Subject: [PATCH 15/16] dpms: remove tizen dpms protocol header include from ds dpms header Change-Id: I92aa03eb77fef0830e170900304d9f44736b8e5a Signed-off-by: Junkyeong Kim --- include/libds-tizen/dpms.h | 24 +++++++-------- src/dpms/dpms.c | 74 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 79 insertions(+), 19 deletions(-) diff --git a/include/libds-tizen/dpms.h b/include/libds-tizen/dpms.h index c614e66..1aabd61 100644 --- a/include/libds-tizen/dpms.h +++ b/include/libds-tizen/dpms.h @@ -3,7 +3,7 @@ #include #include -#include +#include #ifdef __cplusplus extern "C" { @@ -13,19 +13,19 @@ struct ds_tizen_dpms; enum ds_tizen_dpms_mode { - DS_TIZEN_DPMS_MODE_ON = TIZEN_DPMS_MANAGER_MODE_ON, - DS_TIZEN_DPMS_MODE_STANDBY = TIZEN_DPMS_MANAGER_MODE_STANDBY, - DS_TIZEN_DPMS_MODE_SUSPEND = TIZEN_DPMS_MANAGER_MODE_SUSPEND, - DS_TIZEN_DPMS_MODE_OFF = TIZEN_DPMS_MANAGER_MODE_OFF, + DS_TIZEN_DPMS_MODE_ON, + DS_TIZEN_DPMS_MODE_STANDBY, + DS_TIZEN_DPMS_MODE_SUSPEND, + DS_TIZEN_DPMS_MODE_OFF, }; enum ds_tizen_dpms_error { - DS_TIZEN_DPMS_ERROR_NONE = TIZEN_DPMS_MANAGER_ERROR_NONE, - DS_TIZEN_DPMS_ERROR_INVALID_PERMISSION = TIZEN_DPMS_MANAGER_ERROR_INVALID_PERMISSION, - DS_TIZEN_DPMS_ERROR_INVALID_PARAMETER = TIZEN_DPMS_MANAGER_ERROR_INVALID_PARAMETER, - DS_TIZEN_DPMS_ERROR_NOT_SUPPORTED = TIZEN_DPMS_MANAGER_ERROR_NOT_SUPPORTED, - DS_TIZEN_DPMS_ERROR_ALREADY_DONE = TIZEN_DPMS_MANAGER_ERROR_ALREADY_DONE, + DS_TIZEN_DPMS_ERROR_NONE, + DS_TIZEN_DPMS_ERROR_INVALID_PERMISSION, + DS_TIZEN_DPMS_ERROR_INVALID_PARAMETER, + DS_TIZEN_DPMS_ERROR_NOT_SUPPORTED, + DS_TIZEN_DPMS_ERROR_ALREADY_DONE, }; struct ds_tizen_dpms_event @@ -51,11 +51,11 @@ ds_tizen_dpms_add_get_dpms_listener(struct ds_tizen_dpms *dpms, void ds_tizen_dpms_send_set_result(struct ds_tizen_dpms *dpms, - enum ds_tizen_dpms_mode mode, enum ds_tizen_dpms_error error); + enum ds_tizen_dpms_mode ds_mode, enum ds_tizen_dpms_error ds_error); void ds_tizen_dpms_send_get_result(struct ds_tizen_dpms *dpms, - enum ds_tizen_dpms_mode mode, enum ds_tizen_dpms_error error); + enum ds_tizen_dpms_mode ds_mode, enum ds_tizen_dpms_error ds_error); #ifdef __cplusplus } diff --git a/src/dpms/dpms.c b/src/dpms/dpms.c index cec0dc2..4497657 100644 --- a/src/dpms/dpms.c +++ b/src/dpms/dpms.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include "libds-tizen/dpms.h" #include "util.h" @@ -31,6 +30,47 @@ static void dpms_handle_display_destroy(struct wl_listener *listener, static void dpms_bind(struct wl_client *wl_client, void *data, uint32_t version, uint32_t id); +static enum ds_tizen_dpms_mode +_ds_tizen_dpms_get_ds_dpms_mode(uint32_t mode) +{ + if (mode == TIZEN_DPMS_MANAGER_MODE_ON) + return DS_TIZEN_DPMS_MODE_ON; + else if (mode == TIZEN_DPMS_MANAGER_MODE_STANDBY) + return DS_TIZEN_DPMS_MODE_STANDBY; + else if (mode == TIZEN_DPMS_MANAGER_MODE_SUSPEND) + return DS_TIZEN_DPMS_MODE_SUSPEND; + else //TIZEN_DPMS_MANAGER_MODE_OFF + return DS_TIZEN_DPMS_MODE_OFF; +} + +static uint32_t +_ds_tizen_dpms_get_tizen_dpms_mode(enum ds_tizen_dpms_mode ds_mode) +{ + if (ds_mode == DS_TIZEN_DPMS_MODE_ON) + return TIZEN_DPMS_MANAGER_MODE_ON; + else if (ds_mode == DS_TIZEN_DPMS_MODE_STANDBY) + return TIZEN_DPMS_MANAGER_MODE_STANDBY; + else if (ds_mode == DS_TIZEN_DPMS_MODE_SUSPEND) + return TIZEN_DPMS_MANAGER_MODE_SUSPEND; + else //DS_TIZEN_DPMS_MODE_OFF + return TIZEN_DPMS_MANAGER_MODE_OFF; +} + +static uint32_t +_ds_tizen_dpms_get_tizen_dpms_error(enum ds_tizen_dpms_error ds_error) +{ + if (ds_error == DS_TIZEN_DPMS_ERROR_NONE) + return TIZEN_DPMS_MANAGER_ERROR_NONE; + else if (ds_error == DS_TIZEN_DPMS_ERROR_INVALID_PERMISSION) + return TIZEN_DPMS_MANAGER_ERROR_INVALID_PERMISSION; + else if (ds_error == DS_TIZEN_DPMS_ERROR_INVALID_PARAMETER) + return TIZEN_DPMS_MANAGER_ERROR_INVALID_PARAMETER; + else if (ds_error == DS_TIZEN_DPMS_ERROR_NOT_SUPPORTED) + return TIZEN_DPMS_MANAGER_ERROR_NOT_SUPPORTED; + else //DS_TIZEN_DPMS_ERROR_ALREADY_DONE + return TIZEN_DPMS_MANAGER_ERROR_ALREADY_DONE; +} + WL_EXPORT struct ds_tizen_dpms * ds_tizen_dpms_create(struct wl_display *display) { @@ -85,16 +125,34 @@ ds_tizen_dpms_add_get_dpms_listener(struct ds_tizen_dpms *dpms, WL_EXPORT void ds_tizen_dpms_send_set_result(struct ds_tizen_dpms *dpms, - enum ds_tizen_dpms_mode mode, enum ds_tizen_dpms_error error) + enum ds_tizen_dpms_mode ds_mode, enum ds_tizen_dpms_error ds_error) { + uint32_t mode; + uint32_t error; + + if (ds_mode > DS_TIZEN_DPMS_MODE_OFF || ds_error > DS_TIZEN_DPMS_ERROR_ALREADY_DONE) { + ds_err("dpms send set result error invalid parameter"); + return; + } + mode = _ds_tizen_dpms_get_tizen_dpms_mode(ds_mode); + error = _ds_tizen_dpms_get_tizen_dpms_error(ds_error); ds_dbg("dpms send set result : mode(%d), error(%d)", mode, error); tizen_dpms_manager_send_set_state(dpms->res, mode, error); } WL_EXPORT void ds_tizen_dpms_send_get_result(struct ds_tizen_dpms *dpms, - enum ds_tizen_dpms_mode mode, enum ds_tizen_dpms_error error) + enum ds_tizen_dpms_mode ds_mode, enum ds_tizen_dpms_error ds_error) { + uint32_t mode; + uint32_t error; + + if (ds_mode > DS_TIZEN_DPMS_MODE_OFF || ds_error > DS_TIZEN_DPMS_ERROR_ALREADY_DONE) { + ds_err("dpms send get result error invalid parameter"); + return; + } + mode = _ds_tizen_dpms_get_tizen_dpms_mode(ds_mode); + error = _ds_tizen_dpms_get_tizen_dpms_error(ds_error); ds_dbg("dpms send get result : mode(%d), error(%d)", mode, error); tizen_dpms_manager_send_get_state(dpms->res, mode, error); } @@ -129,18 +187,20 @@ _tizen_dpms_manager_handle_set_dpms(struct wl_client *client, struct wl_resource *resource, struct wl_resource *output, uint32_t mode) { struct ds_tizen_dpms *dpms; + enum ds_tizen_dpms_mode ds_mode; dpms = wl_resource_get_user_data(resource); - if (mode > DS_TIZEN_DPMS_MODE_OFF) { + if (mode > TIZEN_DPMS_MANAGER_MODE_OFF) { ds_err("set dpms error : not supported mode(%d)", mode); - tizen_dpms_manager_send_set_state(resource, DS_TIZEN_DPMS_MODE_OFF, - DS_TIZEN_DPMS_ERROR_INVALID_PARAMETER); + tizen_dpms_manager_send_set_state(resource, TIZEN_DPMS_MANAGER_MODE_OFF, + TIZEN_DPMS_MANAGER_ERROR_INVALID_PARAMETER); return; } + ds_mode = _ds_tizen_dpms_get_ds_dpms_mode(mode); struct ds_tizen_dpms_event event = { - .mode = mode, + .mode = ds_mode, }; wl_signal_emit(&dpms->events.set_dpms, &event); -- 2.7.4 From 70148b06aa19f52f739dfc5fdc30d5a4c28552e3 Mon Sep 17 00:00:00 2001 From: Junkyeong Kim Date: Thu, 6 Oct 2022 11:52:17 +0900 Subject: [PATCH 16/16] dpms: use output resource Change-Id: Icdcfb2790b928d7f14561b0b5e4c4e3f9aeffd36 Signed-off-by: Junkyeong Kim --- include/libds-tizen/dpms.h | 2 +- src/dpms/dpms.c | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/include/libds-tizen/dpms.h b/include/libds-tizen/dpms.h index 1aabd61..ea873b4 100644 --- a/include/libds-tizen/dpms.h +++ b/include/libds-tizen/dpms.h @@ -30,7 +30,7 @@ enum ds_tizen_dpms_error struct ds_tizen_dpms_event { - //struct ds_output *output; + struct ds_output *output; enum ds_tizen_dpms_mode mode; }; diff --git a/src/dpms/dpms.c b/src/dpms/dpms.c index 4497657..e352317 100644 --- a/src/dpms/dpms.c +++ b/src/dpms/dpms.c @@ -184,9 +184,10 @@ _tizen_dpms_manager_handle_destroy(struct wl_client *client, static void _tizen_dpms_manager_handle_set_dpms(struct wl_client *client, - struct wl_resource *resource, struct wl_resource *output, uint32_t mode) + struct wl_resource *resource, struct wl_resource *wl_output, uint32_t mode) { struct ds_tizen_dpms *dpms; + struct ds_output *output; enum ds_tizen_dpms_mode ds_mode; dpms = wl_resource_get_user_data(resource); @@ -198,8 +199,10 @@ _tizen_dpms_manager_handle_set_dpms(struct wl_client *client, return; } + output = wl_resource_get_user_data(wl_output); ds_mode = _ds_tizen_dpms_get_ds_dpms_mode(mode); struct ds_tizen_dpms_event event = { + .output = output, .mode = ds_mode, }; @@ -208,13 +211,15 @@ _tizen_dpms_manager_handle_set_dpms(struct wl_client *client, static void _tizen_dpms_manager_handle_get_dpms(struct wl_client *client, - struct wl_resource *resource, struct wl_resource *output) + struct wl_resource *resource, struct wl_resource *wl_output) { struct ds_tizen_dpms *dpms; + struct ds_output *output; dpms = wl_resource_get_user_data(resource); + output = wl_resource_get_user_data(wl_output); - wl_signal_emit(&dpms->events.get_dpms, NULL); + wl_signal_emit(&dpms->events.get_dpms, output); } static const struct tizen_dpms_manager_interface dpms_impl = -- 2.7.4