From d2c775cad597a1c2508a7e3d12bb4b0b44b9d27a Mon Sep 17 00:00:00 2001 From: "duna.oh" Date: Fri, 19 Aug 2022 19:08:17 +0900 Subject: [PATCH] input_method: implement zwp_input_method and context Change-Id: Icc35ccd4f9e6285c37f9143630cca852b8edfd90 --- include/libds-tizen/input_method.h | 152 ++++++++++ packaging/libds-tizen.spec | 32 ++ src/input_method/input_method.c | 598 +++++++++++++++++++++++++++++++++++++ src/input_method/meson.build | 29 ++ src/meson.build | 1 + tests/meson.build | 21 +- tests/tc_input_method.cpp | 346 +++++++++++++++++++++ 7 files changed, 1178 insertions(+), 1 deletion(-) create mode 100644 include/libds-tizen/input_method.h create mode 100644 src/input_method/input_method.c create mode 100644 src/input_method/meson.build create mode 100644 tests/tc_input_method.cpp diff --git a/include/libds-tizen/input_method.h b/include/libds-tizen/input_method.h new file mode 100644 index 0000000..c79c534 --- /dev/null +++ b/include/libds-tizen/input_method.h @@ -0,0 +1,152 @@ +#ifndef LIBDS_TIZEN_INPUT_METHOD_H +#define LIBDS_TIZEN_INPUT_METHOD_H + +#include +#include +#include +#ifdef __cplusplus +extern "C" { +#endif + +struct ds_tizen_input_method_context_event_commit_string +{ + uint32_t serial; + const char *text; +}; + +struct ds_tizen_input_method_context_event_preedit_string +{ + uint32_t serial; + const char *text, *commit; +}; + +struct ds_tizen_input_method_context_event_preedit_styling +{ + uint32_t index, length, style; +}; + +struct ds_tizen_input_method_context_event_preedit_cursor +{ + int32_t index; +}; + +struct ds_tizen_input_method_context_event_delete_surrounding_text +{ + int32_t index; + uint32_t length; +}; + +struct ds_tizen_input_method_context_event_cursor_position +{ + int32_t index, anchor; +}; + +struct ds_tizen_input_method_context_event_modifiers_map +{ + struct wl_array *map; +}; + +struct ds_tizen_input_method_context_event_keysym +{ + uint32_t serial, time, sym, state, modifiers; +}; + +struct ds_tizen_input_method_context_event_language +{ + uint32_t serial; + const char *language; +}; + +struct ds_tizen_input_method_context_event_text_direction +{ + uint32_t serial, direction; +}; + +//input_method +struct ds_tizen_input_method * +ds_tizen_input_method_create(struct wl_display *display); + +struct ds_tizen_input_method_context * +ds_tizen_input_method_create_context(struct ds_tizen_input_method *input_method); + +void +ds_tizen_input_method_add_destroy_listener( + struct ds_tizen_input_method *im, struct wl_listener *listener); +void +ds_tizen_input_method_add_new_input_method_context_listener( + struct ds_tizen_input_method *im, struct wl_listener *listener); + +// events +void ds_tizen_input_method_send_activate(struct ds_tizen_input_method *im, + struct ds_tizen_input_method_context *context); +void ds_tizen_input_method_send_deactivate(struct ds_tizen_input_method *im, + struct ds_tizen_input_method_context *context); + +//input_method_context +void +ds_tizen_input_method_context_add_destroy_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener); +void +ds_tizen_input_method_context_add_commit_string_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener); +void +ds_tizen_input_method_context_add_preedit_string_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener); +void +ds_tizen_input_method_context_add_preedit_styling_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener); +void +ds_tizen_input_method_context_add_preedit_cursor_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener); +void +ds_tizen_input_method_context_add_delete_surrounding_text_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener); +void +ds_tizen_input_method_context_add_cursor_position_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener); +void +ds_tizen_input_method_context_add_modifiers_map_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener); +void +ds_tizen_input_method_context_add_keysym_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener); +void +ds_tizen_input_method_context_add_grab_keyboard_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener); +void +ds_tizen_input_method_context_add_key_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener); +void +ds_tizen_input_method_context_add_modifiers_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener); +void +ds_tizen_input_method_context_add_language_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener); +void +ds_tizen_input_method_context_add_text_direction_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener); + +// events +void +ds_tizen_input_method_context_send_surrounding_text(struct ds_tizen_input_method_context *context, + const char *text, uint32_t cursor, uint32_t anchor); +void +ds_tizen_input_method_context_send_reset(struct ds_tizen_input_method_context *context); +void +ds_tizen_input_method_context_send_content_type( + struct ds_tizen_input_method_context *context, uint32_t hint, uint32_t purpose); +void +ds_tizen_input_method_context_send_invoke_action( + struct ds_tizen_input_method_context *context, uint32_t button, uint32_t index); +void +ds_tizen_input_method_context_send_commit_state( + struct ds_tizen_input_method_context *context, uint32_t serial); +void +ds_tizen_input_method_context_send_preferred_language( + struct ds_tizen_input_method_context *context, const char *launguage); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/packaging/libds-tizen.spec b/packaging/libds-tizen.spec index 09fbf34..65b6c33 100644 --- a/packaging/libds-tizen.spec +++ b/packaging/libds-tizen.spec @@ -16,6 +16,8 @@ BuildRequires: pkgconfig(tizen-extension-server) BuildRequires: pkgconfig(tizen-extension-client) BuildRequires: pkgconfig(tizen-launch-server) BuildRequires: pkgconfig(tizen-launch-client) +BuildRequires: pkgconfig(input-method-server) +BuildRequires: pkgconfig(input-method-client) BuildRequires: pkgconfig(pixman-1) BuildRequires: pkgconfig(libdrm) BuildRequires: pkgconfig(xkbcommon) @@ -261,6 +263,21 @@ Group: Development/Libraries %description embedded-compositor-devel Development package for tizen embedded compositor +## libds-tizen-input-method +%package input-method +Summary: Library for tizen input-method +Group: Development/Libraries + +%description input-method +Library for tizen input-method + +%package input-method-devel +Summary: Development package for tizen input-method +Group: Development/Libraries + +%description input-method-devel +Development package for tizen input-method + %prep %setup -q cp %{SOURCE1001} . @@ -504,3 +521,18 @@ ninja -C builddir install %{_libdir}/pkgconfig/libds-tizen-embedded-compositor.pc %{_libdir}/libds-tizen-embedded-compositor.so %{_bindir}/libds-tizen-embedded-compositor-tests + +%files input-method +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_libdir}/libds-tizen-input-method.so.* + +%files input-method-devel +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_includedir}/libds-tizen/input_method.h +%{_libdir}/pkgconfig/libds-tizen-input-method.pc +%{_libdir}/libds-tizen-input-method.so +%{_bindir}/libds-tizen-input-method-tests diff --git a/src/input_method/input_method.c b/src/input_method/input_method.c new file mode 100644 index 0000000..0481e1a --- /dev/null +++ b/src/input_method/input_method.c @@ -0,0 +1,598 @@ +#include +#include +#include +#include + +#include "util.h" +#include +#include + +#define INPUT_METHOD_VERSION 1 + +struct ds_tizen_input_method; + +struct ds_tizen_input_method_context { + struct wl_resource *resource; + struct ds_tizen_input_method *input_method; + + struct { + struct wl_signal destroy; + struct wl_signal commit_string; + struct wl_signal preedit_string; + struct wl_signal preedit_styling; + struct wl_signal preedit_cursor; + struct wl_signal delete_surrounding_text; + struct wl_signal cursor_position; + struct wl_signal modifiers_map; + struct wl_signal keysym; + struct wl_signal grab_keyboard; + struct wl_signal key; + struct wl_signal modifiers; + struct wl_signal language; + struct wl_signal text_direction; + } events; +}; + +struct ds_tizen_input_method { + struct wl_global *global; + struct wl_resource *resource; + struct ds_tizen_input_method_context *context; + + struct wl_listener destroy; + + struct { + struct wl_signal destroy; + struct wl_signal new_input_method_context; + } events; +}; + +static const struct zwp_input_method_context_v1_interface context_impl; + +WL_EXPORT void +ds_tizen_input_method_add_destroy_listener( + struct ds_tizen_input_method *im, struct wl_listener *listener) +{ + wl_signal_add(&im->events.destroy, listener); +} + +WL_EXPORT void +ds_tizen_input_method_add_new_input_method_context_listener( + struct ds_tizen_input_method *im, struct wl_listener *listener) +{ + wl_signal_add(&im->events.new_input_method_context, listener); +} + +WL_EXPORT void +ds_tizen_input_method_send_activate(struct ds_tizen_input_method *im, + struct ds_tizen_input_method_context *context) +{ + if (!im || !context) return; + + ds_inf("ds_tizen_input_method_send_activate"); + zwp_input_method_v1_send_activate(im->resource, context->resource); +} + +WL_EXPORT void +ds_tizen_input_method_send_deactivate(struct ds_tizen_input_method *im, + struct ds_tizen_input_method_context *context) +{ + if (!im || !context) return; + + ds_inf("ds_tizen_input_method_send_deactivate"); + zwp_input_method_v1_send_deactivate(im->resource, context->resource); +} + +static void +context_destroy(struct ds_tizen_input_method_context *context) +{ + ds_inf("input_method_context(%p) destroy", context); + + wl_signal_emit(&context->events.destroy, context); + + free(context); +} + +static void +input_method_context_client_handle_destroy(struct wl_resource *resource) +{ + struct ds_tizen_input_method_context *context = wl_resource_get_user_data(resource); + struct ds_tizen_input_method *input_method; + + ds_inf("input_method_context_client_handle_destroy"); + + input_method = context->input_method; + input_method->context = NULL; + + context_destroy(context); +} + +WL_EXPORT struct ds_tizen_input_method_context * +ds_tizen_input_method_create_context(struct ds_tizen_input_method *input_method) +{ + struct ds_tizen_input_method_context *context; + struct wl_resource *binding; + + ds_inf("ds_tizen_input_method_create_context"); + context = calloc(1, sizeof *context); + if (context == NULL) + return NULL; + + binding = input_method->resource; + if (!binding) return NULL; + context->resource = wl_resource_create(wl_resource_get_client(binding), + &zwp_input_method_context_v1_interface, INPUT_METHOD_VERSION, 0); + wl_resource_set_implementation(context->resource, &context_impl, + context, input_method_context_client_handle_destroy); + + wl_signal_init(&context->events.destroy); + wl_signal_init(&context->events.commit_string); + wl_signal_init(&context->events.preedit_string); + wl_signal_init(&context->events.preedit_styling); + wl_signal_init(&context->events.preedit_cursor); + wl_signal_init(&context->events.delete_surrounding_text); + wl_signal_init(&context->events.cursor_position); + wl_signal_init(&context->events.modifiers_map); + wl_signal_init(&context->events.keysym); + wl_signal_init(&context->events.grab_keyboard); + wl_signal_init(&context->events.key); + wl_signal_init(&context->events.modifiers); + wl_signal_init(&context->events.language); + wl_signal_init(&context->events.text_direction); + + wl_signal_emit(&input_method->events.new_input_method_context, context); + + ds_tizen_input_method_send_activate(input_method, context); + + input_method->context = context; + context->input_method = input_method; + + return context; +} + +WL_EXPORT void +ds_tizen_input_method_context_add_destroy_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener) +{ + wl_signal_add(&context->events.destroy, listener); +} + +WL_EXPORT void +ds_tizen_input_method_context_add_commit_string_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener) +{ + wl_signal_add(&context->events.commit_string, listener); +} + +WL_EXPORT void +ds_tizen_input_method_context_add_preedit_string_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener) +{ + wl_signal_add(&context->events.preedit_string, listener); +} + +WL_EXPORT void +ds_tizen_input_method_context_add_preedit_styling_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener) +{ + wl_signal_add(&context->events.preedit_styling, listener); +} + +WL_EXPORT void +ds_tizen_input_method_context_add_preedit_cursor_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener) +{ + wl_signal_add(&context->events.preedit_cursor, listener); +} + +WL_EXPORT void +ds_tizen_input_method_context_add_delete_surrounding_text_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener) +{ + wl_signal_add(&context->events.delete_surrounding_text, listener); +} + +WL_EXPORT void +ds_tizen_input_method_context_add_cursor_position_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener) +{ + wl_signal_add(&context->events.cursor_position, listener); +} + +WL_EXPORT void +ds_tizen_input_method_context_add_modifiers_map_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener) +{ + wl_signal_add(&context->events.modifiers_map, listener); +} + +WL_EXPORT void +ds_tizen_input_method_context_add_keysym_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener) +{ + wl_signal_add(&context->events.keysym, listener); +} + +WL_EXPORT void +ds_tizen_input_method_context_add_grab_keyboard_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener) +{ + wl_signal_add(&context->events.grab_keyboard, listener); +} + +WL_EXPORT void +ds_tizen_input_method_context_add_key_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener) +{ + wl_signal_add(&context->events.key, listener); +} + +WL_EXPORT void +ds_tizen_input_method_context_add_modifiers_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener) +{ + wl_signal_add(&context->events.modifiers, listener); +} + +WL_EXPORT void +ds_tizen_input_method_context_add_language_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener) +{ + wl_signal_add(&context->events.language, listener); +} + +WL_EXPORT void +ds_tizen_input_method_context_add_text_direction_listener( + struct ds_tizen_input_method_context *context, struct wl_listener *listener) +{ + wl_signal_add(&context->events.text_direction, listener); +} + +WL_EXPORT void +ds_tizen_input_method_context_send_surrounding_text(struct ds_tizen_input_method_context *context, + const char *text, uint32_t cursor, uint32_t anchor) +{ + if (!context || !context->resource) return; + + ds_inf("ds_tizen_input_method_context_send_surrounding_text"); + zwp_input_method_context_v1_send_surrounding_text(context->resource, text, cursor, anchor); +} + +WL_EXPORT void +ds_tizen_input_method_context_send_reset( + struct ds_tizen_input_method_context *context) +{ + if (!context || !context->resource) return; + + ds_inf("ds_tizen_input_method_context_send_reset"); + zwp_input_method_context_v1_send_reset(context->resource); +} + +WL_EXPORT void +ds_tizen_input_method_context_send_content_type( + struct ds_tizen_input_method_context *context, uint32_t hint, uint32_t purpose) +{ + if (!context || !context->resource) return; + + ds_inf("ds_tizen_input_method_context_send_content_type"); + zwp_input_method_context_v1_send_content_type(context->resource, hint, purpose); +} + +WL_EXPORT void +ds_tizen_input_method_context_send_invoke_action( + struct ds_tizen_input_method_context *context, uint32_t button, uint32_t index) +{ + if (!context || !context->resource) return; + + ds_inf("ds_tizen_input_method_context_send_invoke_action"); + zwp_input_method_context_v1_send_invoke_action(context->resource, button, index); +} + +WL_EXPORT void +ds_tizen_input_method_context_send_commit_state( + struct ds_tizen_input_method_context *context, uint32_t serial) +{ + if (!context || !context->resource) return; + + ds_inf("ds_tizen_input_method_context_send_commit_state"); + zwp_input_method_context_v1_send_commit_state(context->resource, serial); +} + +WL_EXPORT void +ds_tizen_input_method_context_send_preferred_language( + struct ds_tizen_input_method_context *context, const char *language) +{ + if (!context || !context->resource) return; + + ds_inf("ds_tizen_input_method_context_send_preferred_language"); + zwp_input_method_context_v1_send_preferred_language(context->resource, language); +} + +static void +context_handle_destroy(struct wl_client *client, struct wl_resource *resource) +{ + ds_inf("context_handle_destroy"); + wl_resource_destroy(resource); +} + +static void +context_handle_commit_string(struct wl_client *client, + struct wl_resource *resource, uint32_t serial, const char *text) +{ + struct ds_tizen_input_method_context *context = wl_resource_get_user_data(resource); + struct ds_tizen_input_method_context_event_commit_string ds_event; + + ds_inf("context_handle_commit_string"); + ds_event.serial = serial; + ds_event.text = text; + + wl_signal_emit(&context->events.commit_string, &ds_event); +} + +static void +context_handle_preedit_string(struct wl_client *client, + struct wl_resource *resource, uint32_t serial, const char *text, + const char *commit) +{ + struct ds_tizen_input_method_context *context = wl_resource_get_user_data(resource); + struct ds_tizen_input_method_context_event_preedit_string ds_event; + + ds_inf("context_handle_preedit_string() serial:%u, text:%s, commit:%s", + serial, text, commit); + + ds_event.serial = serial; + ds_event.text = text; + ds_event.commit = commit; + + wl_signal_emit(&context->events.preedit_string, &ds_event); +} + +static void +context_handle_preedit_styling(struct wl_client *client, + struct wl_resource *resource, uint32_t index, uint32_t length, + uint32_t style) +{ + struct ds_tizen_input_method_context *context = wl_resource_get_user_data(resource); + struct ds_tizen_input_method_context_event_preedit_styling ds_event; + + ds_inf("context_handle_preedit_styling() index:%u, length:%u, style:%u", + index, length, style); + + ds_event.index = index; + ds_event.length = length; + ds_event.style = style; + + wl_signal_emit(&context->events.preedit_styling, &ds_event); +} + +static void +context_handle_preedit_cursor(struct wl_client *client, + struct wl_resource *resource, int32_t index) +{ + struct ds_tizen_input_method_context *context = wl_resource_get_user_data(resource); + struct ds_tizen_input_method_context_event_preedit_cursor ds_event; + + ds_inf("context_handle_preedit_cursor() cursor:%d", index); + + ds_event.index = index; + wl_signal_emit(&context->events.preedit_styling, &ds_event); +} + +static void +context_handle_delete_surrounding_text(struct wl_client *client, + struct wl_resource *resource, int32_t index, uint32_t length) +{ + struct ds_tizen_input_method_context *context = wl_resource_get_user_data(resource); + struct ds_tizen_input_method_context_event_delete_surrounding_text ds_event; + + ds_inf("context_handle_delete_surrounding_text() index:%d, length:%u", index, length); + + ds_event.index = index; + ds_event.length = length; + wl_signal_emit(&context->events.delete_surrounding_text, &ds_event); +} + +static void +context_handle_cursor_position(struct wl_client *client, + struct wl_resource *resource, int32_t index, int32_t anchor) +{ + struct ds_tizen_input_method_context *context = wl_resource_get_user_data(resource); + struct ds_tizen_input_method_context_event_cursor_position ds_event; + + ds_inf("context_handle_cursor_position() index:%d anchor:%d", index, anchor); + + ds_event.index = index; + ds_event.anchor = anchor; + wl_signal_emit(&context->events.cursor_position, &ds_event); +} + +static void +context_handle_modifiers_map(struct wl_client *client, + struct wl_resource *resource, struct wl_array *map) +{ + struct ds_tizen_input_method_context *context = wl_resource_get_user_data(resource); + struct ds_tizen_input_method_context_event_modifiers_map ds_event; + + ds_inf("context_handle_modifiers_map() map(%p)", map); + + ds_event.map = map; + wl_signal_emit(&context->events.modifiers_map, &ds_event); +} + +static void +context_handle_keysym(struct wl_client *client, struct wl_resource *resource, + uint32_t serial, uint32_t time, uint32_t sym, + uint32_t state, uint32_t modifiers) +{ + struct ds_tizen_input_method_context *context = wl_resource_get_user_data(resource); + struct ds_tizen_input_method_context_event_keysym ds_event; + + ds_inf("context_handle_keysym() serial(%u), time(%u), sym(%u), state(%u), modifiers(%u)", + serial, time, sym, state, modifiers); + + ds_event.serial = serial; + ds_event.time = time; + ds_event.sym = sym; + ds_event.state = state; + ds_event.modifiers = modifiers; + wl_signal_emit(&context->events.keysym, &ds_event); +} + +static void +context_handle_grab_keyboard(struct wl_client *client, + struct wl_resource *resource, uint32_t id) +{ + ds_inf("context_handle_grab_keyboard() nothing done"); + //TODO +} + +static void +context_handle_key(struct wl_client *client, struct wl_resource *resource, + uint32_t serial, uint32_t time, uint32_t key, uint32_t state_w) +{ + ds_inf("context_handle_key() nothing done"); + //TODO +} + +static void +context_handle_modifiers(struct wl_client *client, + struct wl_resource *resource, uint32_t serial, uint32_t mods_depressed, + uint32_t mods_latched, uint32_t mods_locked, uint32_t group) +{ + ds_inf("context_handle_modifiers() nothing done"); + //TODO +} + +static void +context_handle_language(struct wl_client *client, + struct wl_resource *resource, uint32_t serial, const char *language) +{ + struct ds_tizen_input_method_context *context = wl_resource_get_user_data(resource); + struct ds_tizen_input_method_context_event_language ds_event; + + ds_inf("context_handle_language() serial(%u) language(%s)", serial, language); + + ds_event.serial = serial; + ds_event.language = language; + wl_signal_emit(&context->events.language, &ds_event); +} + +static void +context_handle_text_direction(struct wl_client *client, + struct wl_resource *resource, uint32_t serial, uint32_t direction) +{ + struct ds_tizen_input_method_context *context = wl_resource_get_user_data(resource); + struct ds_tizen_input_method_context_event_text_direction ds_event; + + ds_inf("context_handle_text_direction() serial(%u) direction(%u)", serial, direction); + + ds_event.serial = serial; + ds_event.direction = direction; + wl_signal_emit(&context->events.text_direction, &ds_event); +} + +static const struct zwp_input_method_context_v1_interface context_impl = { + .destroy = context_handle_destroy, + .commit_string = context_handle_commit_string, + .preedit_string = context_handle_preedit_string, + .preedit_styling = context_handle_preedit_styling, + .preedit_cursor = context_handle_preedit_cursor, + .delete_surrounding_text = context_handle_delete_surrounding_text, + .cursor_position = context_handle_cursor_position, + .modifiers_map = context_handle_modifiers_map, + .keysym = context_handle_keysym, + .grab_keyboard = context_handle_grab_keyboard, + .key = context_handle_key, + .modifiers = context_handle_modifiers, + .language = context_handle_language, + .text_direction = context_handle_text_direction, + //for tizen_only + .selection_region = NULL, + .private_command = NULL, + .update_input_panel_data = NULL, + .hide_input_panel = NULL, + .get_selection_text = NULL, + .get_surrounding_text = NULL, + .filter_key_event_done = NULL, + .update_ise_geometry = NULL, + .recapture_string = NULL, + .input_panel_event = NULL, + .commit_content = NULL, + .update_candidate_state = NULL, + .reshow_input_panel = NULL, + .set_floating_panel = NULL, + .set_floating_drag_enabled = NULL, +}; + +static void +input_method_handle_display_destroy(struct wl_listener *listener, void *data) +{ + struct ds_tizen_input_method *input_method; + + input_method = wl_container_of(listener, input_method, destroy); + + ds_inf("Global destroy: input_method(%p)", input_method); + + if (input_method->context) + context_destroy(input_method->context); + + wl_signal_emit(&input_method->events.destroy, input_method); + wl_list_remove(&input_method->destroy.link); + + wl_global_destroy(input_method->global); + free(input_method); +} + +static void +input_method_client_handle_destroy(struct wl_resource *resource) +{ + ds_inf("input_method_client_handle_destroy"); +} + +static void +input_method_bind(struct wl_client *wl_client, void *data, + uint32_t version, uint32_t id) +{ + struct ds_tizen_input_method *input_method = data; + + ds_inf("input_method. client binds. (client:%p)", wl_client); + + input_method->resource = wl_resource_create(wl_client, + &zwp_input_method_v1_interface, + version, id); + if (input_method->resource == NULL) { + ds_err("input_method. wl_resource_create() failed."); + wl_client_post_no_memory(wl_client); + return; + } + wl_resource_set_implementation(input_method->resource, NULL, + input_method, input_method_client_handle_destroy); +} + +WL_EXPORT struct ds_tizen_input_method * +ds_tizen_input_method_create(struct wl_display *display) +{ + struct ds_tizen_input_method *input_method; + + input_method = calloc(1, sizeof *input_method); + if (input_method == NULL) { + ds_err("calloc() failed. ds_tizen_input_method"); + return NULL; + } + + input_method->global = wl_global_create(display, + &zwp_input_method_v1_interface, INPUT_METHOD_VERSION, input_method, input_method_bind); + if (!input_method->global) { + free(input_method); + return NULL; + } + + wl_signal_init(&input_method->events.destroy); + wl_signal_init(&input_method->events.new_input_method_context); + + input_method->destroy.notify = input_method_handle_display_destroy; + wl_display_add_destroy_listener(display, &input_method->destroy); + + ds_inf("Global create: zwp_input_method_v1. input_method(%p)", input_method); + + return input_method; +} diff --git a/src/input_method/meson.build b/src/input_method/meson.build new file mode 100644 index 0000000..eb20352 --- /dev/null +++ b/src/input_method/meson.build @@ -0,0 +1,29 @@ +libds_tizen_input_method_files = [ + 'input_method.c', +] + +libds_tizen_input_method_deps = [ + deps_libds_tizen, + dependency('input-method-server', required: true), +] + +lib_libds_tizen_input_method = shared_library('ds-tizen-input-method', libds_tizen_input_method_files, + dependencies: libds_tizen_input_method_deps, + include_directories: [ common_inc, include_directories('.'), include_directories('..') ], + version: meson.project_version(), + install: true +) + +deps_libds_tizen_input_method = declare_dependency( + link_with: lib_libds_tizen_input_method, + dependencies: libds_tizen_input_method_deps, + include_directories: [ common_inc, include_directories('.') ], +) + +pkgconfig = import('pkgconfig') +pkgconfig.generate(lib_libds_tizen_input_method, + version: meson.project_version(), + filebase: 'libds-tizen-input-method', + name: 'libds-tizen-input-method', + description: 'tizen input-method extension of libds-tizen for tizen platform', +) diff --git a/src/meson.build b/src/meson.build index a1ba1ab..37ef631 100644 --- a/src/meson.build +++ b/src/meson.build @@ -42,3 +42,4 @@ subdir('renderer') subdir('screen_rotation') subdir('global_resource') subdir('embedded_compositor') +subdir('input_method') diff --git a/tests/meson.build b/tests/meson.build index 34b9245..9ec62fa 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -226,4 +226,23 @@ executable('libds-tizen-embedded-compositor-tests', ], install_dir: libds_tizen_bindir, install : true -) \ No newline at end of file +) + +## input method tests +tc_input_method_files = [ + 'tc_main.cpp', + 'tc_input_method.cpp', +] + +executable('libds-tizen-input-method-tests', + [ + tc_mock_files, + tc_input_method_files + ], + dependencies: [ + deps_test_common, + deps_libds_tizen_input_method, + ], + install_dir: libds_tizen_bindir, + install : true +) diff --git a/tests/tc_input_method.cpp b/tests/tc_input_method.cpp new file mode 100644 index 0000000..1bbc1be --- /dev/null +++ b/tests/tc_input_method.cpp @@ -0,0 +1,346 @@ +#include "tc_main.h" +#include "mockclient.h" +#include "mockcompositor.h" +#include +#include +#include + +#define INPUT_METHOD_VERSION 1 + +class MockInputMethodCompositor : public MockCompositor +{ +public: + MockInputMethodCompositor() + : MockCompositor(&MockInputMethodCompositor::TestSetup, this) + { + ds_inf("%s : this(%p)", __func__, this); + + // initialize the flags to check + bDestroyed = false; + bNewInputMethodContext = false; + } + + ~MockInputMethodCompositor() + { + ds_inf("%s : this(%p)", __func__, this); + } + + static void TestSetup(void *data) + { + MockInputMethodCompositor *mockComp = + static_cast(data); + Compositor *comp = mockComp->compositor; + + ds_inf("%s: mockComp(%p)", __func__, mockComp); + + mockComp->mInputMethod = ds_tizen_input_method_create(comp->display); + + // destroy listener + mockComp->mDestroyListener.notify = + MockInputMethodCompositor::DestroyCallback; + mockComp->mDestroyListener.parent = mockComp; + ds_tizen_input_method_add_destroy_listener(mockComp->mInputMethod, + &mockComp->mDestroyListener); + + // new input method context listener + mockComp->mNewInputMethodContextListener.notify = + MockInputMethodCompositor::NewInputMethodContextCallback; + mockComp->mNewInputMethodContextListener.parent = mockComp; + ds_tizen_input_method_add_new_input_method_context_listener(mockComp->mInputMethod, + &mockComp->mNewInputMethodContextListener); + } + + static void DestroyCallback(struct wl_listener *listener, void *data) + { + ds_inf("%s", __func__); + + MockInputMethodCompositor *mockComp = + reinterpret_cast(listener)->parent; + + mockComp->bDestroyed = true; + } + + static void NewInputMethodContextCallback(struct wl_listener *listener, void *data) + { + ds_inf("%s", __func__); + + MockInputMethodCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_tizen_input_method_context *context = + static_cast(data); + + ds_inf("%s: mockComp(%p), input_method_context(%p)", __func__, mockComp, context); + + mockComp->mInputMethodContext = context; + mockComp->bNewInputMethodContext = true; + } + + void CreateInputMethodContext() + { + ds_inf("%s", __func__); + + ds_tizen_input_method_create_context(mInputMethod); + } + + void SendActivate() + { + ds_inf("%s", __func__); + + ds_tizen_input_method_send_activate(mInputMethod, mInputMethodContext); + } + + void SendDeactivate() + { + ds_inf("%s", __func__); + + ds_tizen_input_method_send_deactivate(mInputMethod, mInputMethodContext); + } + +public: + bool bDestroyed; + bool bNewInputMethodContext; + +private: + struct ds_tizen_input_method_manager *mInputMethodMgr; + struct ds_tizen_input_method *mInputMethod; + struct ds_tizen_input_method_context *mInputMethodContext; + + struct DestroyListener: ::wl_listener { + MockInputMethodCompositor *parent; + }; + DestroyListener mDestroyListener; + + struct NewInputMethodContextListener: ::wl_listener { + MockInputMethodCompositor *parent; + }; + NewInputMethodContextListener mNewInputMethodContextListener; +}; + +class MockInputMethodClient : public MockClient +{ +public: + MockInputMethodClient() + : bActivate(false), + bDeactivate(false), + compositor_res(nullptr), + zwp_input_method(nullptr) + {} + + MockInputMethodClient(const struct wl_registry_listener *listener) + : MockClient(listener, this) + { + ds_inf("%s", __func__); + } + + ~MockInputMethodClient() + { + 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 SetInputMethod(struct zwp_input_method_v1 *global_res) + { + ds_inf("%s", __func__); + zwp_input_method = global_res; + } + + struct zwp_input_method_v1 *GetInputMethod() + { + ds_inf("%s", __func__); + + return zwp_input_method; + } + +public: + bool bActivate; + bool bDeactivate; + +private: + struct wl_compositor *compositor_res; + struct zwp_input_method_v1 *zwp_input_method; +}; + +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__); + + MockInputMethodClient *client = static_cast(data); + struct wl_compositor *compositor_res; + struct zwp_input_method_v1 *zwp_input_method; + + 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_v1")) { + zwp_input_method = (struct zwp_input_method_v1 *)wl_registry_bind(registry, + name, &zwp_input_method_v1_interface, INPUT_METHOD_VERSION); + if (zwp_input_method == nullptr) { + ds_err("wl_registry_bind() failed. zwp_input_method_v1 resource."); + return; + } + client->SetInputMethod(zwp_input_method); + } +} + +static void +client_registry_cb_global_remove(void *data, struct wl_registry *registry, + uint32_t name) +{ + ds_inf("%s", __func__); + + MockInputMethodClient *client = static_cast(data); + struct wl_compositor *compositor_res = client->GetWlCompositor(); + struct zwp_input_method_v1 *input_method_res = client->GetInputMethod(); + + zwp_input_method_v1_destroy(input_method_res); + wl_compositor_destroy(compositor_res); +} + +static const struct wl_registry_listener registry_listener = { + .global = client_registry_cb_global, + .global_remove = client_registry_cb_global_remove +}; + +static void +im_cb_activate (void *data, struct zwp_input_method_v1 *input_method, struct zwp_input_method_context_v1 *im_ctx) +{ + ds_inf("%s", __func__); + + MockInputMethodClient *client = static_cast(data); + client->bActivate = true; +} +static void +im_cb_deactivate (void *data, struct zwp_input_method_v1 *input_method, struct zwp_input_method_context_v1 *im_ctx) +{ + ds_inf("%s", __func__); + + MockInputMethodClient *client = static_cast(data); + client->bDeactivate = true; +} +static void +im_cb_destroy (void *data, struct zwp_input_method_v1 *input_method, struct zwp_input_method_context_v1 *im_ctx) +{} +static void +im_cb_show_input_panel (void *data, struct zwp_input_method_v1 *input_method, struct zwp_input_method_context_v1 *im_ctx, uint32_t angle) +{} +static void +im_cb_hide_input_panel (void *data, struct zwp_input_method_v1 *input_method, struct zwp_input_method_context_v1 *im_ctx) +{} +static void +im_cb_open_connection (void *data, struct zwp_input_method_v1 *input_method, struct zwp_input_method_context_v1 *im_ctx) +{} +static void +im_cb_close_connection (void *data, struct zwp_input_method_v1 *input_method, struct zwp_input_method_context_v1 *im_ctx) +{} +static void +im_cb_set_text_input_id (void *data, struct zwp_input_method_v1 *input_method, struct zwp_input_method_context_v1 *im_ctx, uint32_t text_input_id) +{} +static const struct zwp_input_method_v1_listener input_method_cb_listener = { + .activate = im_cb_activate, + .deactivate = im_cb_deactivate, + //for tizen only + .destroy = im_cb_destroy, + .show_input_panel = im_cb_show_input_panel, + .hide_input_panel = im_cb_hide_input_panel, + .open_connection = im_cb_open_connection, + .close_connection = im_cb_close_connection, + .set_text_input_id = im_cb_set_text_input_id, +}; + +class InputMethodTest : public ::testing::Test +{ +public: + void SetUp(void) override; + void TearDown(void) override; + + MockInputMethodCompositor *comp; + MockInputMethodClient *client; + struct wl_compositor *compositor_res; + struct zwp_input_method_v1 *input_method_res; +}; + +void +InputMethodTest::SetUp(void) +{ + ds_log_init(DS_INF, NULL); + + ds_inf("%s", __func__); + + comp = new MockInputMethodCompositor(); + client = new MockInputMethodClient(®istry_listener); + compositor_res = client->GetWlCompositor(); + input_method_res = client->GetInputMethod(); + + zwp_input_method_v1_add_listener(input_method_res, + &input_method_cb_listener, client); + + client->RoundTrip(); +} + +void +InputMethodTest::TearDown(void) +{ + ds_inf("%s", __func__); + + client->RoundTrip(); + + delete client; + delete comp; +} + +TEST_F(InputMethodTest, Create_P) +{ + EXPECT_TRUE(true); +} + +TEST_F(InputMethodTest, CreateInputMethodContext) +{ + comp->CreateInputMethodContext(); + comp->Process(); + + EXPECT_TRUE(comp->bNewInputMethodContext); +} + +TEST_F(InputMethodTest, Ev_Activate) +{ + comp->CreateInputMethodContext(); + comp->Process(); + + comp->SendActivate(); + comp->Process(); + + client->RoundTrip(); + EXPECT_TRUE(client->bActivate); +} + +TEST_F(InputMethodTest, Ev_Deactivate) +{ + comp->CreateInputMethodContext(); + comp->Process(); + + comp->SendDeactivate(); + comp->Process(); + + client->RoundTrip(); + EXPECT_TRUE(client->bDeactivate); +} -- 2.7.4