From 025afe5a1bdd21b7353b05c5c20e1b96b962f9e9 Mon Sep 17 00:00:00 2001 From: "duna.oh" Date: Fri, 19 Aug 2022 19:19:24 +0900 Subject: [PATCH] input_method: implement zwp_input_method_manager Change-Id: Ia98c1e325f014ad0f4c3f2445f236b2b4e93eba8 --- include/libds-tizen/input_method.h | 16 +++ packaging/libds-tizen.spec | 1 + src/input_method/input_method.c | 121 ++++++++++++++++++ tests/meson.build | 19 +++ tests/tc_input_method_manager.cpp | 255 +++++++++++++++++++++++++++++++++++++ 5 files changed, 412 insertions(+) create mode 100644 tests/tc_input_method_manager.cpp diff --git a/include/libds-tizen/input_method.h b/include/libds-tizen/input_method.h index c79c534..731b889 100644 --- a/include/libds-tizen/input_method.h +++ b/include/libds-tizen/input_method.h @@ -8,6 +8,11 @@ extern "C" { #endif +struct ds_tizen_input_method_manager_event_set_transient_for +{ + uint32_t pid_parent, pid_child; +}; + struct ds_tizen_input_method_context_event_commit_string { uint32_t serial; @@ -62,6 +67,17 @@ struct ds_tizen_input_method_context_event_text_direction uint32_t serial, direction; }; +//input_method_manager +struct ds_tizen_input_method_manager * +ds_tizen_input_method_manager_create(struct wl_display *display); + +void +ds_tizen_input_method_manager_add_destroy_listener( + struct ds_tizen_input_method_manager *im_mgr, struct wl_listener *listener); +void +ds_tizen_input_method_manager_add_set_transient_for_listener( + struct ds_tizen_input_method_manager *im_mgr, struct wl_listener *listener); + //input_method struct ds_tizen_input_method * ds_tizen_input_method_create(struct wl_display *display); diff --git a/packaging/libds-tizen.spec b/packaging/libds-tizen.spec index 65b6c33..4db5813 100644 --- a/packaging/libds-tizen.spec +++ b/packaging/libds-tizen.spec @@ -536,3 +536,4 @@ ninja -C builddir install %{_libdir}/pkgconfig/libds-tizen-input-method.pc %{_libdir}/libds-tizen-input-method.so %{_bindir}/libds-tizen-input-method-tests +%{_bindir}/libds-tizen-input-method-manager-tests diff --git a/src/input_method/input_method.c b/src/input_method/input_method.c index 0481e1a..2293272 100644 --- a/src/input_method/input_method.c +++ b/src/input_method/input_method.c @@ -46,7 +46,128 @@ struct ds_tizen_input_method { } events; }; +struct ds_tizen_input_method_manager { + struct wl_global *global; + struct wl_resource *resource; + + struct wl_listener destroy; + + struct { + struct wl_signal destroy; + struct wl_signal set_transient_for; + } events; +}; + static const struct zwp_input_method_context_v1_interface context_impl; +static const struct zwp_input_method_manager_v1_interface input_method_mgr_impl; + +WL_EXPORT void +ds_tizen_input_method_manager_add_destroy_listener( + struct ds_tizen_input_method_manager *im_mgr, struct wl_listener *listener) +{ + wl_signal_add(&im_mgr->events.destroy, listener); +} + +WL_EXPORT void +ds_tizen_input_method_manager_add_set_transient_for_listener( + struct ds_tizen_input_method_manager *im_mgr, struct wl_listener *listener) +{ + wl_signal_add(&im_mgr->events.set_transient_for, listener); +} + +static void +input_method_mgr_handle_display_destroy(struct wl_listener *listener, void *data) +{ + struct ds_tizen_input_method_manager *input_method_mgr; + + input_method_mgr = wl_container_of(listener, input_method_mgr, destroy); + + ds_inf("Global destroy: input_method_mgr(%p)", input_method_mgr); + + wl_signal_emit(&input_method_mgr->events.destroy, input_method_mgr); + wl_list_remove(&input_method_mgr->destroy.link); + + wl_global_destroy(input_method_mgr->global); + free(input_method_mgr); +} + +static void +input_method_mgr_handle_set_transient_for(struct wl_client *wl_client, + struct wl_resource *resource, uint32_t parent_pid, uint32_t child_pid) +{ + struct ds_tizen_input_method_manager_event_set_transient_for ds_event; + struct ds_tizen_input_method_manager *input_method_mgr; + + input_method_mgr = wl_resource_get_user_data(resource); + + ds_inf("input_method_mgr_handle_set_transient_for() parent:%u, child:%u", + parent_pid, child_pid); + + ds_event.pid_parent = parent_pid; + ds_event.pid_child = child_pid; + wl_signal_emit(&input_method_mgr->events.set_transient_for, &ds_event); +} + +static const struct zwp_input_method_manager_v1_interface input_method_mgr_impl = +{ + .set_transient_for = input_method_mgr_handle_set_transient_for, +}; + +static void +input_method_mgr_client_handle_destroy(struct wl_resource *resource) +{ + ds_inf("input_method_mgr_client_handle_destroy"); +} + +static void +input_method_mgr_bind(struct wl_client *wl_client, void *data, + uint32_t version, uint32_t id) +{ + struct ds_tizen_input_method_manager *input_method_mgr = data; + struct wl_resource *resource; + + ds_inf("input_method_mgr. client binds. (client:%p)", wl_client); + + resource = wl_resource_create(wl_client, + &zwp_input_method_manager_v1_interface, + version, id); + if (resource == NULL) { + ds_err("input_method_mgr. wl_resource_create() failed."); + wl_client_post_no_memory(wl_client); + return; + } + wl_resource_set_implementation(resource, &input_method_mgr_impl, + input_method_mgr, input_method_mgr_client_handle_destroy); +} + +WL_EXPORT struct ds_tizen_input_method_manager * +ds_tizen_input_method_manager_create(struct wl_display *display) +{ + struct ds_tizen_input_method_manager *input_method_mgr; + + input_method_mgr = calloc(1, sizeof *input_method_mgr); + if (input_method_mgr == NULL) { + ds_err("calloc() failed. ds_tizen_input_method_manager"); + return NULL; + } + + input_method_mgr->global = wl_global_create(display, + &zwp_input_method_manager_v1_interface, INPUT_METHOD_VERSION, input_method_mgr, input_method_mgr_bind); + if (!input_method_mgr->global) { + free(input_method_mgr); + return NULL; + } + + wl_signal_init(&input_method_mgr->events.destroy); + wl_signal_init(&input_method_mgr->events.set_transient_for); + + input_method_mgr->destroy.notify = input_method_mgr_handle_display_destroy; + wl_display_add_destroy_listener(display, &input_method_mgr->destroy); + + ds_inf("Global create: zwp_input_method_manager_v1. input_method_mgr(%p)", input_method_mgr); + + return input_method_mgr; +} WL_EXPORT void ds_tizen_input_method_add_destroy_listener( diff --git a/tests/meson.build b/tests/meson.build index 9ec62fa..e8e4421 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -246,3 +246,22 @@ executable('libds-tizen-input-method-tests', install_dir: libds_tizen_bindir, install : true ) + +## input method tests +tc_input_method_manager_files = [ + 'tc_main.cpp', + 'tc_input_method_manager.cpp', +] + +executable('libds-tizen-input-method-manager-tests', + [ + tc_mock_files, + tc_input_method_manager_files + ], + dependencies: [ + deps_test_common, + deps_libds_tizen_input_method, + ], + install_dir: libds_tizen_bindir, + install : true +) diff --git a/tests/tc_input_method_manager.cpp b/tests/tc_input_method_manager.cpp new file mode 100644 index 0000000..a338d8f --- /dev/null +++ b/tests/tc_input_method_manager.cpp @@ -0,0 +1,255 @@ +#include "tc_main.h" +#include "mockclient.h" +#include "mockcompositor.h" +#include +#include +#include + +#define INPUT_METHOD_VERSION 1 + +class MockInputMethodMgrCompositor : public MockCompositor +{ +public: + MockInputMethodMgrCompositor() + : MockCompositor(&MockInputMethodMgrCompositor::TestSetup, this) + { + ds_inf("%s : this(%p)", __func__, this); + + // initialize the flags to check + bDestroyed = false; + + bSetTransientFor = false; + mParentPid = 0; + mChildPid = 0; + } + + ~MockInputMethodMgrCompositor() + { + ds_inf("%s : this(%p)", __func__, this); + } + + static void TestSetup(void *data) + { + MockInputMethodMgrCompositor *mockComp = + static_cast(data); + Compositor *comp = mockComp->compositor; + + ds_inf("%s: mockComp(%p)", __func__, mockComp); + + mockComp->mInputMethodMgr = ds_tizen_input_method_manager_create(comp->display); + + // destroy listener + mockComp->mDestroyListener.notify = + MockInputMethodMgrCompositor::DestroyCallback; + mockComp->mDestroyListener.parent = mockComp; + ds_tizen_input_method_manager_add_destroy_listener(mockComp->mInputMethodMgr, + &mockComp->mDestroyListener); + + // set_transient_for listener + mockComp->mSetTransientForListener.notify = + MockInputMethodMgrCompositor::SetTransientForCallback; + mockComp->mSetTransientForListener.parent = mockComp; + ds_tizen_input_method_manager_add_set_transient_for_listener(mockComp->mInputMethodMgr, + &mockComp->mSetTransientForListener); + } + + static void DestroyCallback(struct wl_listener *listener, void *data) + { + ds_inf("%s", __func__); + + MockInputMethodMgrCompositor *mockComp = + reinterpret_cast(listener)->parent; + + mockComp->bDestroyed = true; + } + + static void SetTransientForCallback(struct wl_listener *listener, void *data) + { + struct ds_tizen_input_method_manager_event_set_transient_for *event = + (struct ds_tizen_input_method_manager_event_set_transient_for *)data; + + ds_inf("%s", __func__); + + MockInputMethodMgrCompositor *mockComp = + reinterpret_cast(listener)->parent; + + mockComp->bSetTransientFor = true; + mockComp->mParentPid = event->pid_parent; + mockComp->mChildPid = event->pid_child; + } + +public: + bool bDestroyed; + bool bSetTransientFor; + uint32_t mParentPid; + uint32_t mChildPid; + +private: + struct ds_tizen_input_method_manager *mInputMethodMgr; + struct DestroyListener: ::wl_listener { + MockInputMethodMgrCompositor *parent; + }; + DestroyListener mDestroyListener; + + struct SetTransientForListener: ::wl_listener { + MockInputMethodMgrCompositor *parent; + }; + SetTransientForListener mSetTransientForListener; +}; + +class MockInputMethodMgrClient : public MockClient +{ +public: + MockInputMethodMgrClient() + : bActivated(false), + compositor_res(nullptr), + zwp_input_method_manager(nullptr) + {} + + MockInputMethodMgrClient(const struct wl_registry_listener *listener) + : MockClient(listener, this) + { + ds_inf("%s", __func__); + } + + ~MockInputMethodMgrClient() + { + ds_inf("%s", __func__); + } + + void SetWlCompositor(struct wl_compositor *global_res) + { + ds_inf("%s", __func__); + + compositor_res = global_res; + } + + struct wl_compositor *GetWlCompositor() + { + ds_inf("%s", __func__); + + return compositor_res; + } + + void SetInputMethodMgr(struct zwp_input_method_manager_v1 *global_res) + { + ds_inf("%s", __func__); + zwp_input_method_manager = global_res; + } + + struct zwp_input_method_manager_v1 *GetInputMethodMgr() + { + ds_inf("%s", __func__); + + return zwp_input_method_manager; + } + +public: + bool bActivated; + +private: + struct wl_compositor *compositor_res; + struct zwp_input_method_manager_v1 *zwp_input_method_manager; +}; + +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__); + + MockInputMethodMgrClient *client = static_cast(data); + struct wl_compositor *compositor_res; + struct zwp_input_method_manager_v1 *zwp_input_method_manager; + + if (!strcmp(interface, "wl_compositor")) { + compositor_res = (struct wl_compositor *)wl_registry_bind(registry, + name, &wl_compositor_interface, 1); + if (compositor_res == nullptr) { + ds_err("wl_registry_bind() failed. wl_compositor resource."); + return; + } + client->SetWlCompositor(compositor_res); + } else if (!strcmp(interface, "zwp_input_method_manager_v1")) { + zwp_input_method_manager = (struct zwp_input_method_manager_v1 *)wl_registry_bind(registry, + name, &zwp_input_method_manager_v1_interface, INPUT_METHOD_VERSION); + if (zwp_input_method_manager == nullptr) { + ds_err("wl_registry_bind() failed. zwp_input_method_manager_v1 resource."); + return; + } + client->SetInputMethodMgr(zwp_input_method_manager); + } +} + +static void +client_registry_cb_global_remove(void *data, struct wl_registry *registry, + uint32_t name) +{ + ds_inf("%s", __func__); + + MockInputMethodMgrClient *client = static_cast(data); + struct wl_compositor *compositor_res = client->GetWlCompositor(); + struct zwp_input_method_manager_v1 *input_method_mgr_res = client->GetInputMethodMgr(); + + zwp_input_method_manager_v1_destroy(input_method_mgr_res); + wl_compositor_destroy(compositor_res); +} + +static const struct wl_registry_listener registry_listener = { + .global = client_registry_cb_global, + .global_remove = client_registry_cb_global_remove +}; + +class InputMethodMgrTest : public ::testing::Test +{ +public: + void SetUp(void) override; + void TearDown(void) override; + + MockInputMethodMgrCompositor *comp; + MockInputMethodMgrClient *client; + struct wl_compositor *compositor_res; + struct zwp_input_method_manager_v1 *input_method_mgr_res; +}; + +void +InputMethodMgrTest::SetUp(void) +{ + ds_log_init(DS_INF, NULL); + + ds_inf("%s", __func__); + + comp = new MockInputMethodMgrCompositor(); + client = new MockInputMethodMgrClient(®istry_listener); + compositor_res = client->GetWlCompositor(); + input_method_mgr_res = client->GetInputMethodMgr(); + + client->RoundTrip(); +} + +void +InputMethodMgrTest::TearDown(void) +{ + ds_inf("%s", __func__); + + client->RoundTrip(); + + delete client; + delete comp; +} + +TEST_F(InputMethodMgrTest, Create_P) +{ + EXPECT_TRUE(true); +} + +TEST_F(InputMethodMgrTest, Req_SetTransientFor) +{ + uint32_t parent_pid = 123; + uint32_t child_pid = 321; + + zwp_input_method_manager_v1_set_transient_for(input_method_mgr_res, parent_pid, child_pid); + client->RoundTrip(); + EXPECT_TRUE(comp->mParentPid == parent_pid); + EXPECT_TRUE(comp->mChildPid == child_pid); +} \ No newline at end of file -- 2.7.4