input_method: implement zwp_input_method_manager 46/280246/1
authorduna.oh <duna.oh@samsung.com>
Fri, 19 Aug 2022 10:19:24 +0000 (19:19 +0900)
committerTizen Window System <tizen.windowsystem@gmail.com>
Fri, 26 Aug 2022 00:33:05 +0000 (09:33 +0900)
Change-Id: Ia98c1e325f014ad0f4c3f2445f236b2b4e93eba8

include/libds-tizen/input_method.h
packaging/libds-tizen.spec
src/input_method/input_method.c
tests/meson.build
tests/tc_input_method_manager.cpp [new file with mode: 0644]

index c79c534..731b889 100644 (file)
@@ -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);
index 65b6c33..4db5813 100644 (file)
@@ -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
index 0481e1a..2293272 100644 (file)
@@ -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(
index 9ec62fa..e8e4421 100644 (file)
@@ -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 (file)
index 0000000..a338d8f
--- /dev/null
@@ -0,0 +1,255 @@
+#include "tc_main.h"
+#include "mockclient.h"
+#include "mockcompositor.h"
+#include <libds-tizen/input_method.h>
+#include <input-method-server-protocol.h>
+#include <input-method-client-protocol.h>
+
+#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<MockInputMethodMgrCompositor *>(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<DestroyListener *>(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<SetTransientForListener *>(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<MockInputMethodMgrClient *>(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<MockInputMethodMgrClient *>(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(&registry_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