From d2c775cad597a1c2508a7e3d12bb4b0b44b9d27a Mon Sep 17 00:00:00 2001 From: "duna.oh" Date: Fri, 19 Aug 2022 19:08:17 +0900 Subject: [PATCH 01/16] 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 From 025afe5a1bdd21b7353b05c5c20e1b96b962f9e9 Mon Sep 17 00:00:00 2001 From: "duna.oh" Date: Fri, 19 Aug 2022 19:19:24 +0900 Subject: [PATCH 02/16] 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 From a27b3a06a1b1d7aac09d794d9bf10d13c1477440 Mon Sep 17 00:00:00 2001 From: "duna.oh" Date: Mon, 22 Aug 2022 10:16:15 +0900 Subject: [PATCH 03/16] text_input: implement wl_text_input and manager Change-Id: Ibfa33280ad057afaac5168e3be15d10cb341f017 --- include/libds-tizen/text_input.h | 131 ++++++ packaging/libds-tizen.spec | 32 ++ src/meson.build | 1 + src/text_input/meson.build | 29 ++ src/text_input/text_input.c | 532 +++++++++++++++++++++ tests/meson.build | 19 + tests/tc_text_input.cpp | 967 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 1711 insertions(+) create mode 100644 include/libds-tizen/text_input.h create mode 100644 src/text_input/meson.build create mode 100644 src/text_input/text_input.c create mode 100644 tests/tc_text_input.cpp diff --git a/include/libds-tizen/text_input.h b/include/libds-tizen/text_input.h new file mode 100644 index 0000000..ecd3e6f --- /dev/null +++ b/include/libds-tizen/text_input.h @@ -0,0 +1,131 @@ +#ifndef LIBDS_TIZEN_TEXT_INPUT_H +#define LIBDS_TIZEN_TEXT_INPUT_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ds_tizen_text_input; +struct ds_tizen_text_input_manager; + +struct ds_tizen_text_input_event_activate +{ + struct ds_tizen_text_input *text_input; + struct ds_seat *seat; + struct ds_surface *surface; +}; + +struct ds_tizen_text_input_event_deactivate +{ + struct ds_tizen_text_input *text_input; + struct ds_seat *seat; +}; + +struct ds_tizen_text_input_event_set_content_type +{ + struct ds_tizen_text_input *text_input; + uint32_t hint, purpose; +}; + +struct ds_tizen_text_input_event_set_preferred_language +{ + struct ds_tizen_text_input *text_input; + const char *language; +}; + +struct ds_tizen_text_input_event_commit_state +{ + struct ds_tizen_text_input *text_input; + uint32_t serial; +}; + +struct ds_tizen_text_input_event_invoke_action +{ + struct ds_tizen_text_input *text_input; + uint32_t button, index; +}; + +struct ds_tizen_text_input_manager * +ds_tizen_text_input_manager_create(struct wl_display *display); + +void +ds_tizen_text_input_manager_add_destroy_listener( + struct ds_tizen_text_input_manager *ti_mgr, struct wl_listener *listener); +void +ds_tizen_text_input_manager_add_new_text_input_listener( + struct ds_tizen_text_input_manager *ti_mgr, struct wl_listener *listener); + +void +ds_tizen_text_input_add_destroy_listener( + struct ds_tizen_text_input *ti, struct wl_listener *listener); +void +ds_tizen_text_input_add_activate_listener( + struct ds_tizen_text_input *ti, struct wl_listener *listener); +void +ds_tizen_text_input_add_deactivate_listener( + struct ds_tizen_text_input *ti, struct wl_listener *listener); +void +ds_tizen_text_input_add_reset_listener( + struct ds_tizen_text_input *ti, struct wl_listener *listener); +void +ds_tizen_text_input_add_set_content_type_listener( + struct ds_tizen_text_input *ti, struct wl_listener *listener); +void +ds_tizen_text_input_add_set_preferred_language_listener( + struct ds_tizen_text_input *ti, struct wl_listener *listener); +void +ds_tizen_text_input_add_commit_state_listener( + struct ds_tizen_text_input *ti, struct wl_listener *listener); +void +ds_tizen_text_input_add_invoke_action_listener( + struct ds_tizen_text_input *ti, struct wl_listener *listener); + +void +ds_tizen_text_input_send_enter(struct ds_tizen_text_input *ti, struct ds_surface *surface); +void +ds_tizen_text_input_send_leave(struct ds_tizen_text_input *ti); +void +ds_tizen_text_input_send_modifiers_map(struct ds_tizen_text_input *ti, + struct wl_array *map); +void +ds_tizen_text_input_send_input_panel_state(struct ds_tizen_text_input *ti, + uint32_t input_panel_state); +void +ds_tizen_text_input_send_preedit_string(struct ds_tizen_text_input *ti, + uint32_t serial, const char *text, const char *commit); +void +ds_tizen_text_input_send_preedit_styling(struct ds_tizen_text_input *ti, + uint32_t index, uint32_t length, uint32_t style); +void +ds_tizen_text_input_send_preedit_cursor(struct ds_tizen_text_input *ti, + uint32_t index); +void +ds_tizen_text_input_send_commit_string(struct ds_tizen_text_input *ti, + uint32_t serial, const char *text); +void +ds_tizen_text_input_send_cursor_position(struct ds_tizen_text_input *ti, + int32_t index, int32_t anchor); +void +ds_tizen_text_input_send_delete_surrounding_text(struct ds_tizen_text_input *ti, + int32_t index, uint32_t length); +void +ds_tizen_text_input_send_keysym(struct ds_tizen_text_input *ti, + uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, + uint32_t modifiers); +void +ds_tizen_text_input_send_language(struct ds_tizen_text_input *ti, + uint32_t serial, const char *language); +void +ds_tizen_text_input_send_text_direction(struct ds_tizen_text_input *ti, + uint32_t serial, uint32_t direction); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/packaging/libds-tizen.spec b/packaging/libds-tizen.spec index 4db5813..f392041 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(text-server) +BuildRequires: pkgconfig(text-client) BuildRequires: pkgconfig(input-method-server) BuildRequires: pkgconfig(input-method-client) BuildRequires: pkgconfig(pixman-1) @@ -263,6 +265,21 @@ Group: Development/Libraries %description embedded-compositor-devel Development package for tizen embedded compositor +## libds-tizen-text-input +%package text-input +Summary: Library for tizen text-input +Group: Development/Libraries + +%description text-input +Library for tizen text-input + +%package text-input-devel +Summary: Development package for tizen text-input +Group: Development/Libraries + +%description text-input-devel +Development package for tizen text-input + ## libds-tizen-input-method %package input-method Summary: Library for tizen input-method @@ -522,6 +539,21 @@ ninja -C builddir install %{_libdir}/libds-tizen-embedded-compositor.so %{_bindir}/libds-tizen-embedded-compositor-tests +%files text-input +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_libdir}/libds-tizen-text-input.so.* + +%files text-input-devel +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_includedir}/libds-tizen/text_input.h +%{_libdir}/pkgconfig/libds-tizen-text-input.pc +%{_libdir}/libds-tizen-text-input.so +%{_bindir}/libds-tizen-text-input-tests + %files input-method %manifest %{name}.manifest %defattr(-,root,root,-) diff --git a/src/meson.build b/src/meson.build index 37ef631..aef63ac 100644 --- a/src/meson.build +++ b/src/meson.build @@ -43,3 +43,4 @@ subdir('screen_rotation') subdir('global_resource') subdir('embedded_compositor') subdir('input_method') +subdir('text_input') \ No newline at end of file diff --git a/src/text_input/meson.build b/src/text_input/meson.build new file mode 100644 index 0000000..796758e --- /dev/null +++ b/src/text_input/meson.build @@ -0,0 +1,29 @@ +libds_tizen_text_input_files = [ + 'text_input.c', +] + +libds_tizen_text_input_deps = [ + deps_libds_tizen, + dependency('text-server', required: true), +] + +lib_libds_tizen_text_input = shared_library('ds-tizen-text-input', libds_tizen_text_input_files, + dependencies: libds_tizen_text_input_deps, + include_directories: [ common_inc, include_directories('.'), include_directories('..') ], + version: meson.project_version(), + install: true +) + +deps_libds_tizen_text_input = declare_dependency( + link_with: lib_libds_tizen_text_input, + dependencies: libds_tizen_text_input_deps, + include_directories: [ common_inc, include_directories('.') ], +) + +pkgconfig = import('pkgconfig') +pkgconfig.generate(lib_libds_tizen_text_input, + version: meson.project_version(), + filebase: 'libds-tizen-text-input', + name: 'libds-tizen-text-input', + description: 'tizen text-input extension of libds-tizen for tizen platform', +) diff --git a/src/text_input/text_input.c b/src/text_input/text_input.c new file mode 100644 index 0000000..7a9c4f2 --- /dev/null +++ b/src/text_input/text_input.c @@ -0,0 +1,532 @@ +#include +#include +#include +#include + +#include "util.h" +#include + +#define TEXT_INPUT_VERSION 1 + +struct ds_tizen_text_input { + struct wl_resource *resource; + + struct wl_list link; + + struct { + struct wl_signal destroy; + struct wl_signal activate; + struct wl_signal deactivate; + struct wl_signal reset; + struct wl_signal set_content_type; + struct wl_signal invoke_action; + struct wl_signal commit_state; + struct wl_signal set_preferred_language; + } events; +}; + +struct ds_tizen_text_input_manager { + struct wl_global *global; + struct wl_list text_inputs; + + struct wl_listener destroy; + + struct { + struct wl_signal new_text_input; + struct wl_signal destroy; + } events; +}; + +static const struct wl_text_input_interface text_input_impl; +static const struct wl_text_input_manager_interface text_input_mgr_impl; + +WL_EXPORT void +ds_tizen_text_input_manager_add_destroy_listener( + struct ds_tizen_text_input_manager *ti_mgr, struct wl_listener *listener) +{ + wl_signal_add(&ti_mgr->events.destroy, listener); +} + +WL_EXPORT void +ds_tizen_text_input_manager_add_new_text_input_listener( + struct ds_tizen_text_input_manager *ti_mgr, struct wl_listener *listener) +{ + wl_signal_add(&ti_mgr->events.new_text_input, listener); +} + +WL_EXPORT void +ds_tizen_text_input_add_destroy_listener( + struct ds_tizen_text_input *ti, struct wl_listener *listener) +{ + wl_signal_add(&ti->events.destroy, listener); +} + +WL_EXPORT void +ds_tizen_text_input_add_activate_listener( + struct ds_tizen_text_input *ti, struct wl_listener *listener) +{ + wl_signal_add(&ti->events.activate, listener); +} + +WL_EXPORT void +ds_tizen_text_input_add_deactivate_listener( + struct ds_tizen_text_input *ti, struct wl_listener *listener) +{ + wl_signal_add(&ti->events.deactivate, listener); +} + +WL_EXPORT void +ds_tizen_text_input_add_reset_listener( + struct ds_tizen_text_input *ti, struct wl_listener *listener) +{ + wl_signal_add(&ti->events.reset, listener); +} + +WL_EXPORT void +ds_tizen_text_input_add_set_content_type_listener( + struct ds_tizen_text_input *ti, struct wl_listener *listener) +{ + wl_signal_add(&ti->events.set_content_type, listener); +} + +WL_EXPORT void +ds_tizen_text_input_add_set_preferred_language_listener( + struct ds_tizen_text_input *ti, struct wl_listener *listener) +{ + wl_signal_add(&ti->events.set_preferred_language, listener); +} + +WL_EXPORT void +ds_tizen_text_input_add_commit_state_listener( + struct ds_tizen_text_input *ti, struct wl_listener *listener) +{ + wl_signal_add(&ti->events.commit_state, listener); +} + +WL_EXPORT void +ds_tizen_text_input_add_invoke_action_listener( + struct ds_tizen_text_input *ti, struct wl_listener *listener) +{ + wl_signal_add(&ti->events.invoke_action, listener); +} + +WL_EXPORT void +ds_tizen_text_input_send_enter(struct ds_tizen_text_input *ti, + struct ds_surface *surface) +{ + struct wl_resource *resource; + + ds_inf("ds_tizen_text_input_send_enter"); + resource = ds_surface_get_wl_resource(surface); + wl_text_input_send_enter(ti->resource, resource); +} + +WL_EXPORT void +ds_tizen_text_input_send_leave(struct ds_tizen_text_input *ti) +{ + ds_inf("ds_tizen_text_input_send_leave"); + wl_text_input_send_leave(ti->resource); +} + +WL_EXPORT void +ds_tizen_text_input_send_modifiers_map(struct ds_tizen_text_input *ti, + struct wl_array *map) +{ + ds_inf("ds_tizen_text_input_send_modifiers_map"); + wl_text_input_send_modifiers_map(ti->resource, map); +} + +WL_EXPORT void +ds_tizen_text_input_send_input_panel_state(struct ds_tizen_text_input *ti, + uint32_t state) +{ + ds_inf("ds_tizen_text_input_send_input_panel_state"); + wl_text_input_send_input_panel_state(ti->resource, state); +} + +WL_EXPORT void +ds_tizen_text_input_send_preedit_string(struct ds_tizen_text_input *ti, + uint32_t serial, const char *text, const char *commit) +{ + ds_inf("ds_tizen_text_input_send_preedit_string"); + wl_text_input_send_preedit_string(ti->resource, serial, text, commit); +} + +WL_EXPORT void +ds_tizen_text_input_send_preedit_styling(struct ds_tizen_text_input *ti, + uint32_t index, uint32_t length, uint32_t style) +{ + ds_inf("ds_tizen_text_input_send_preedit_styling"); + wl_text_input_send_preedit_styling(ti->resource, index, length, style); +} + +WL_EXPORT void +ds_tizen_text_input_send_preedit_cursor(struct ds_tizen_text_input *ti, + uint32_t index) +{ + ds_inf("ds_tizen_text_input_send_preedit_cursor"); + wl_text_input_send_preedit_cursor(ti->resource, index); +} + +WL_EXPORT void +ds_tizen_text_input_send_commit_string(struct ds_tizen_text_input *ti, + uint32_t serial, const char *text) +{ + ds_inf("ds_tizen_text_input_send_commit_string"); + wl_text_input_send_commit_string(ti->resource, serial, text); +} + +WL_EXPORT void +ds_tizen_text_input_send_cursor_position(struct ds_tizen_text_input *ti, + int32_t index, int32_t anchor) +{ + ds_inf("ds_tizen_text_input_send_cursor_position"); + wl_text_input_send_cursor_position(ti->resource, index, anchor); +} + +WL_EXPORT void +ds_tizen_text_input_send_delete_surrounding_text(struct ds_tizen_text_input *ti, + int32_t index, uint32_t length) +{ + ds_inf("ds_tizen_text_input_send_delete_surrounding_text"); + wl_text_input_send_delete_surrounding_text(ti->resource, index, length); +} + +WL_EXPORT void +ds_tizen_text_input_send_keysym(struct ds_tizen_text_input *ti, + uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, + uint32_t modifiers) +{ + ds_inf("ds_tizen_text_input_send_keysym"); + wl_text_input_send_keysym(ti->resource, serial, time, sym, state, modifiers); +} + +WL_EXPORT void +ds_tizen_text_input_send_language(struct ds_tizen_text_input *ti, + uint32_t serial, const char *language) +{ + ds_inf("ds_tizen_text_input_send_language"); + wl_text_input_send_language(ti->resource, serial, language); +} + +WL_EXPORT void +ds_tizen_text_input_send_text_direction(struct ds_tizen_text_input *ti, + uint32_t serial, uint32_t direction) +{ + ds_inf("ds_tizen_text_input_send_text_direction"); + wl_text_input_send_text_direction(ti->resource, serial, direction); +} + +static void +text_input_handle_destroy(struct wl_client *client, struct wl_resource *resource) +{ + ds_inf("text_input_handle_destroy"); + wl_resource_destroy(resource); +} + +static void +text_input_handle_activate(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *seat, struct wl_resource *surface) +{ + struct ds_tizen_text_input *text_input = wl_resource_get_user_data(resource); + struct ds_tizen_text_input_event_activate ds_event; + struct ds_surface *ds_surf; + struct ds_seat_client *seat_client; + + ds_inf("text_input_handle_activate"); + ds_surf = ds_surface_from_resource(surface); + + ds_event.text_input = text_input; + seat_client = ds_seat_client_from_resource(seat); + if (seat_client) + ds_event.seat = ds_seat_client_get_seat(seat_client); + ds_event.surface = ds_surf; + wl_signal_emit(&text_input->events.activate, &ds_event); + + ds_tizen_text_input_send_enter(text_input, ds_surf); +} + +static void +text_input_handle_deactivate(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *seat) +{ + struct ds_tizen_text_input *text_input = wl_resource_get_user_data(resource); + struct ds_tizen_text_input_event_deactivate ds_event; + struct ds_seat_client *seat_client; + + ds_inf("text_input_handle_deactivate"); + ds_event.text_input = text_input; + seat_client = ds_seat_client_from_resource(seat); + if (seat_client) + ds_event.seat = ds_seat_client_get_seat(seat_client); + wl_signal_emit(&text_input->events.deactivate, &ds_event); + + ds_tizen_text_input_send_leave(text_input); +} + +static void +text_input_handle_show_input_panel(struct wl_client *client, + struct wl_resource *resource) +{ + ds_inf("text_input_handle_show_input_panel"); +} + +static void +text_input_handle_hide_input_panel(struct wl_client *client, + struct wl_resource *resource) +{ + ds_inf("text_input_handle_hide_input_panel"); +} + +static void +text_input_handle_reset(struct wl_client *client, struct wl_resource *resource) +{ + struct ds_tizen_text_input *text_input = wl_resource_get_user_data(resource); + + ds_inf("text_input_handle_reset"); + wl_signal_emit(&text_input->events.reset, text_input); +} + +static void +text_input_handle_set_content_type(struct wl_client *client, + struct wl_resource *resource, uint32_t hint, uint32_t purpose) +{ + struct ds_tizen_text_input *text_input = wl_resource_get_user_data(resource); + struct ds_tizen_text_input_event_set_content_type ds_event; + + ds_inf("text_input_handle_set_content_type"); + ds_event.hint = hint; + ds_event.purpose = purpose; + ds_event.text_input = text_input; + + wl_signal_emit(&text_input->events.set_content_type, &ds_event); +} + +static void +text_input_handle_set_cursor_rectangle(struct wl_client *client, + struct wl_resource *resource, int32_t x, int32_t y, + int32_t width, int32_t height) +{ + ds_inf("text_input_handle_set_cursor_rectangle"); +} + +static void +text_input_handle_set_preferred_language(struct wl_client *client, + struct wl_resource *resource, const char *language) +{ + struct ds_tizen_text_input *text_input = wl_resource_get_user_data(resource); + struct ds_tizen_text_input_event_set_preferred_language ds_event; + + ds_inf("text_input_handle_set_preferred_language"); + ds_event.language = language; + ds_event.text_input = text_input; + + wl_signal_emit(&text_input->events.set_preferred_language, &ds_event); +} + +static void +text_input_handle_commit_state(struct wl_client *client, + struct wl_resource *resource, uint32_t serial) +{ + struct ds_tizen_text_input *text_input = wl_resource_get_user_data(resource); + struct ds_tizen_text_input_event_commit_state ds_event; + + ds_inf("text_input_handle_invoke_action"); + ds_event.serial = serial; + ds_event.text_input = text_input; + + wl_signal_emit(&text_input->events.commit_state, &ds_event); +} + +static void +text_input_handle_invoke_action(struct wl_client *client, + struct wl_resource *resource, uint32_t button, uint32_t index) +{ + struct ds_tizen_text_input *text_input = wl_resource_get_user_data(resource); + struct ds_tizen_text_input_event_invoke_action ds_event; + + ds_inf("text_input_handle_invoke_action"); + + ds_event.button = button; + ds_event.index = index; + ds_event.text_input = text_input; + + wl_signal_emit(&text_input->events.invoke_action, &ds_event); +} + +static const struct wl_text_input_interface text_input_impl = { + .destroy = text_input_handle_destroy, + .activate = text_input_handle_activate, + .deactivate = text_input_handle_deactivate, + .show_input_panel = text_input_handle_show_input_panel, + .hide_input_panel = text_input_handle_hide_input_panel, + .reset = text_input_handle_reset, + .set_content_type = text_input_handle_set_content_type, + .set_cursor_rectangle = text_input_handle_set_cursor_rectangle, + .set_preferred_language = text_input_handle_set_preferred_language, + .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, +}; + +static void +text_input_destroy(struct ds_tizen_text_input *text_input) +{ + wl_signal_emit(&text_input->events.destroy, text_input); + wl_list_remove(&text_input->link); + + free(text_input); +} + +static void +text_input_mgr_handle_display_destroy(struct wl_listener *listener, void *data) +{ + struct ds_tizen_text_input_manager *text_input_mgr; + struct ds_tizen_text_input *text_input, *tmp; + + text_input_mgr = wl_container_of(listener, text_input_mgr, destroy); + + ds_inf("Global destroy: text_input_mgr(%p)", text_input_mgr); + + wl_signal_emit(&text_input_mgr->events.destroy, text_input_mgr); + wl_list_remove(&text_input_mgr->destroy.link); + + wl_list_for_each_safe(text_input, tmp, &text_input_mgr->text_inputs, link) { + text_input_destroy(text_input); + } + + wl_global_destroy(text_input_mgr->global); + free(text_input_mgr); +} + +static void +text_input_client_handle_destroy(struct wl_resource *resource) +{ + struct ds_tizen_text_input *text_input; + + ds_inf("text_input_client_handle_destroy"); + + text_input = wl_resource_get_user_data(resource); + text_input_destroy(text_input); +} + +static void +text_input_manager_handle_create_text_input(struct wl_client *wl_client, + struct wl_resource *resource, uint32_t id) +{ + struct ds_tizen_text_input *text_input; + struct ds_tizen_text_input_manager *text_input_mgr; + + ds_inf("text_input_manager_handle_create_text_input"); + + text_input_mgr = wl_resource_get_user_data(resource); + + text_input = calloc(1, sizeof *text_input); + if (text_input == NULL) { + ds_err("calloc() failed. ds_tizen_text_input"); + return; + } + + text_input->resource = wl_resource_create(wl_client, + &wl_text_input_interface, + TEXT_INPUT_VERSION, id); + if (text_input->resource == NULL) { + ds_err("text_input. wl_resource_create() failed."); + wl_client_post_no_memory(wl_client); + return; + } + wl_resource_set_implementation(text_input->resource, &text_input_impl, + text_input, text_input_client_handle_destroy); + + wl_signal_init(&text_input->events.activate); + wl_signal_init(&text_input->events.deactivate); + wl_signal_init(&text_input->events.reset); + wl_signal_init(&text_input->events.set_content_type); + wl_signal_init(&text_input->events.invoke_action); + wl_signal_init(&text_input->events.commit_state); + wl_signal_init(&text_input->events.set_preferred_language); + wl_signal_init(&text_input->events.destroy); + + wl_list_insert(&text_input_mgr->text_inputs, &text_input->link); + wl_signal_emit(&text_input_mgr->events.new_text_input, text_input); +} + +static const struct wl_text_input_manager_interface text_input_mgr_impl = +{ + .create_text_input = text_input_manager_handle_create_text_input, +}; + +static void +text_input_mgr_client_handle_destroy(struct wl_resource *resource) +{ + ds_inf("text_input_mgr_client_handle_destroy"); +} + +static void +text_input_mgr_bind(struct wl_client *wl_client, void *data, + uint32_t version, uint32_t id) +{ + struct ds_tizen_text_input_manager *text_input_mgr = data; + struct wl_resource *resource; + + ds_inf("text_input_mgr. client binds. (client:%p)", wl_client); + + resource = wl_resource_create(wl_client, + &wl_text_input_manager_interface, + version, id); + if (resource == NULL) { + ds_err("text_input_mgr. wl_resource_create() failed."); + wl_client_post_no_memory(wl_client); + return; + } + wl_resource_set_implementation(resource, &text_input_mgr_impl, + text_input_mgr, text_input_mgr_client_handle_destroy); +} + +WL_EXPORT struct ds_tizen_text_input_manager * +ds_tizen_text_input_manager_create(struct wl_display *display) +{ + struct ds_tizen_text_input_manager *text_input_mgr; + + text_input_mgr = calloc(1, sizeof *text_input_mgr); + if (text_input_mgr == NULL) { + ds_err("calloc() failed. ds_tizen_text_input_manager"); + return NULL; + } + + text_input_mgr->global = wl_global_create(display, + &wl_text_input_manager_interface, TEXT_INPUT_VERSION, text_input_mgr, + text_input_mgr_bind); + if (!text_input_mgr->global) { + free(text_input_mgr); + return NULL; + } + + wl_list_init(&text_input_mgr->text_inputs); + + wl_signal_init(&text_input_mgr->events.new_text_input); + wl_signal_init(&text_input_mgr->events.destroy); + + + text_input_mgr->destroy.notify = text_input_mgr_handle_display_destroy; + wl_display_add_destroy_listener(display, &text_input_mgr->destroy); + + ds_inf("Global create: wl_text_input_manager. text_input_mgr(%p)", text_input_mgr); + + return text_input_mgr; +} diff --git a/tests/meson.build b/tests/meson.build index e8e4421..0405794 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -265,3 +265,22 @@ executable('libds-tizen-input-method-manager-tests', install_dir: libds_tizen_bindir, install : true ) + +## text input tests +tc_text_input_files = [ + 'tc_main.cpp', + 'tc_text_input.cpp', +] + +executable('libds-tizen-text-input-tests', + [ + tc_mock_files, + tc_text_input_files + ], + dependencies: [ + deps_test_common, + deps_libds_tizen_text_input, + ], + install_dir: libds_tizen_bindir, + install : true +) \ No newline at end of file diff --git a/tests/tc_text_input.cpp b/tests/tc_text_input.cpp new file mode 100644 index 0000000..f9ad47e --- /dev/null +++ b/tests/tc_text_input.cpp @@ -0,0 +1,967 @@ +#include "tc_main.h" +#include "mockclient.h" +#include "mockcompositor.h" +#include +#include +#include +#include + +#define TEXT_INPUT_MGR_VERSION 1 +#define SEAT_VERSION 7 + +class MockTextInputCompositor : public MockCompositor +{ +public: + MockTextInputCompositor() + : MockCompositor(&MockTextInputCompositor::TestSetup, this) + { + ds_inf("%s : this(%p)", __func__, this); + + // initialize the flags to check + bDestroyed = false; + bNewTextInput = false; + bActivated = false; + bReset = false;; + bContentType = false; + bInvokeAction = false; + bCommitState = false; + bPreferredLanguage = false; + } + + ~MockTextInputCompositor() + { + ds_inf("%s : this(%p)", __func__, this); + } + + static void TestSetup(void *data) + { + MockTextInputCompositor *mockComp = + static_cast(data); + Compositor *comp = mockComp->compositor; + + ds_inf("%s: mockComp(%p)", __func__, mockComp); + + ds_seat_create(comp->display, "seat0"); //for client to be bound to wl_seat_interface + + mockComp->mTextInputMgr = ds_tizen_text_input_manager_create(comp->display); + + // destroy listener + mockComp->mDestroyListener.notify = + MockTextInputCompositor::DestroyCallback; + mockComp->mDestroyListener.parent = mockComp; + ds_tizen_text_input_manager_add_destroy_listener(mockComp->mTextInputMgr, + &mockComp->mDestroyListener); + + mockComp->mNewTextInputListener.notify = + MockTextInputCompositor::NewTextInputCallback; + mockComp->mNewTextInputListener.parent = mockComp; + ds_tizen_text_input_manager_add_new_text_input_listener(mockComp->mTextInputMgr, + &mockComp->mNewTextInputListener); + } + + static void DestroyCallback(struct wl_listener *listener, void *data) + { + ds_inf("%s", __func__); + + MockTextInputCompositor *mockComp = + reinterpret_cast(listener)->parent; + + mockComp->bDestroyed = true; + } + + static void NewTextInputCallback(struct wl_listener *listener, void *data) + { + struct ds_tizen_text_input *text_input = (ds_tizen_text_input *)data; + ds_inf("%s", __func__); + + MockTextInputCompositor *mockComp = + reinterpret_cast(listener)->parent; + + mockComp->bNewTextInput = true; + mockComp->mTextInput = text_input; + + mockComp->mActivateListener.notify = + MockTextInputCompositor::ActivateCallback; + mockComp->mActivateListener.parent = mockComp; + ds_tizen_text_input_add_activate_listener(mockComp->mTextInput, + &mockComp->mActivateListener); + + mockComp->mDeactivateListener.notify = + MockTextInputCompositor::DeactivateCallback; + mockComp->mDeactivateListener.parent = mockComp; + ds_tizen_text_input_add_deactivate_listener(mockComp->mTextInput, + &mockComp->mDeactivateListener); + + mockComp->mResetListener.notify = + MockTextInputCompositor::ResetCallback; + mockComp->mResetListener.parent = mockComp; + ds_tizen_text_input_add_reset_listener(mockComp->mTextInput, + &mockComp->mResetListener); + + mockComp->mContentTypeListener.notify = + MockTextInputCompositor::ContentTypeCallback; + mockComp->mContentTypeListener.parent = mockComp; + ds_tizen_text_input_add_set_content_type_listener(mockComp->mTextInput, + &mockComp->mContentTypeListener); + + mockComp->mInvokeActionListener.notify = + MockTextInputCompositor::InvokeActionCallback; + mockComp->mInvokeActionListener.parent = mockComp; + ds_tizen_text_input_add_invoke_action_listener(mockComp->mTextInput, + &mockComp->mInvokeActionListener); + + mockComp->mCommitStateListener.notify = + MockTextInputCompositor::CommitStateCallback; + mockComp->mCommitStateListener.parent = mockComp; + ds_tizen_text_input_add_commit_state_listener(mockComp->mTextInput, + &mockComp->mCommitStateListener); + + mockComp->mPreferredLanguageListener.notify = + MockTextInputCompositor::PreferredLanguageCallback; + mockComp->mPreferredLanguageListener.parent = mockComp; + ds_tizen_text_input_add_set_preferred_language_listener(mockComp->mTextInput, + &mockComp->mPreferredLanguageListener); + } + + static void ActivateCallback(struct wl_listener *listener, void *data) + { + struct ds_tizen_text_input_event_activate *event = (struct ds_tizen_text_input_event_activate *)data; + + ds_inf("%s", __func__); + + MockTextInputCompositor *mockComp = + reinterpret_cast(listener)->parent; + + mockComp->bActivated = true; + mockComp->mSeat = event->seat; + mockComp->mSurface = event->surface; + } + + static void DeactivateCallback(struct wl_listener *listener, void *data) + { + struct ds_tizen_text_input_event_deactivate *event = (struct ds_tizen_text_input_event_deactivate *)data; + + ds_inf("%s", __func__); + + MockTextInputCompositor *mockComp = + reinterpret_cast(listener)->parent; + + mockComp->bActivated = false; + if (mockComp->mSeat == event->seat) + mockComp->mSeat = NULL; + mockComp->mSurface = NULL; + } + + + static void ResetCallback(struct wl_listener *listener, void *data) + { + ds_inf("%s", __func__); + + MockTextInputCompositor *mockComp = + reinterpret_cast(listener)->parent; + + mockComp->bReset = true; + } + + static void ContentTypeCallback(struct wl_listener *listener, void *data) + { + ds_inf("%s", __func__); + + MockTextInputCompositor *mockComp = + reinterpret_cast(listener)->parent; + + mockComp->bContentType = true; + } + + static void InvokeActionCallback(struct wl_listener *listener, void *data) + { + ds_inf("%s", __func__); + + MockTextInputCompositor *mockComp = + reinterpret_cast(listener)->parent; + + mockComp->bInvokeAction = true; + } + + static void CommitStateCallback(struct wl_listener *listener, void *data) + { + ds_inf("%s", __func__); + + MockTextInputCompositor *mockComp = + reinterpret_cast(listener)->parent; + + mockComp->bCommitState = true; + } + + static void PreferredLanguageCallback(struct wl_listener *listener, void *data) + { + ds_inf("%s", __func__); + + MockTextInputCompositor *mockComp = + reinterpret_cast(listener)->parent; + + mockComp->bPreferredLanguage = true; + } + + void SendEnter() + { + ds_inf("%s", __func__); + + ds_tizen_text_input_send_enter(mTextInput, mSurface); + } + void SendLeave() + { + ds_inf("%s", __func__); + + ds_tizen_text_input_send_leave(mTextInput); + } + void SendModifiersMap(struct wl_array *map) + { + ds_inf("%s", __func__); + + ds_tizen_text_input_send_modifiers_map(mTextInput, map); + } + void SendInputPanelState(uint32_t state) + { + ds_inf("%s", __func__); + + ds_tizen_text_input_send_input_panel_state(mTextInput, state); + } + void SendPreeditString(uint32_t serial, const char *text, const char *commit) + { + ds_inf("%s", __func__); + + ds_tizen_text_input_send_preedit_string(mTextInput, serial, text, commit); + } + void SendPreeditStyling(uint32_t index, uint32_t length, uint32_t style) + { + ds_inf("%s", __func__); + + ds_tizen_text_input_send_preedit_styling(mTextInput, index, length, style); + } + void SendPreeditCursor(uint32_t index) + { + ds_inf("%s", __func__); + + ds_tizen_text_input_send_preedit_cursor(mTextInput, index); + } + void SendCommitString(uint32_t serial, const char *text) + { + ds_inf("%s", __func__); + + ds_tizen_text_input_send_commit_string(mTextInput, serial, text); + } + void SendCursorPosition(int32_t index, int32_t anchor) + { + ds_inf("%s", __func__); + + ds_tizen_text_input_send_cursor_position(mTextInput, index, anchor); + } + void SendDeleteSurroundingText(int32_t index, uint32_t length) + { + ds_inf("%s", __func__); + + ds_tizen_text_input_send_delete_surrounding_text(mTextInput, index, length); + } + void SendKeysym(uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, + uint32_t modifiers) + { + ds_inf("%s", __func__); + + ds_tizen_text_input_send_keysym(mTextInput, serial, time, sym, state, modifiers); + } + void SendLanguage(uint32_t serial, const char *language) + { + ds_inf("%s", __func__); + + ds_tizen_text_input_send_language(mTextInput, serial, language); + } + void SendTextDirection(uint32_t serial, uint32_t direction) + { + ds_inf("%s", __func__); + + ds_tizen_text_input_send_text_direction(mTextInput, serial, direction); + } + +public: + bool bDestroyed; + bool bNewTextInput; + bool bActivated; + + bool bReset; + bool bContentType; + bool bInvokeAction; + bool bCommitState; + bool bPreferredLanguage; + + struct ds_seat *mSeat; + struct ds_surface *mSurface; + +private: + struct ds_tizen_text_input_manager *mTextInputMgr; + struct ds_tizen_text_input *mTextInput; + + struct DestroyListener: ::wl_listener { + MockTextInputCompositor *parent; + }; + DestroyListener mDestroyListener; + + struct NewTextInputListener: ::wl_listener { + MockTextInputCompositor *parent; + }; + NewTextInputListener mNewTextInputListener; + + struct ActivateListener: ::wl_listener { + MockTextInputCompositor *parent; + }; + ActivateListener mActivateListener; + + struct DeactivateListener: ::wl_listener { + MockTextInputCompositor *parent; + }; + DeactivateListener mDeactivateListener; + + struct ResetListener: ::wl_listener { + MockTextInputCompositor *parent; + }; + ResetListener mResetListener; + + struct ContentTypeListener: ::wl_listener { + MockTextInputCompositor *parent; + }; + ContentTypeListener mContentTypeListener; + + struct InvokeActionListener: ::wl_listener { + MockTextInputCompositor *parent; + }; + InvokeActionListener mInvokeActionListener; + + struct CommitStateListener: ::wl_listener { + MockTextInputCompositor *parent; + }; + CommitStateListener mCommitStateListener; + + struct PreferredLanguageListener: ::wl_listener { + MockTextInputCompositor *parent; + }; + PreferredLanguageListener mPreferredLanguageListener; +}; + +class MockTextInputClient : public MockClient +{ +public: + MockTextInputClient() + : bEnter(false), + bLeave(false), + bCallback(false), + compositor_res(nullptr), + wl_text_input_manager(nullptr), + wl_seat(nullptr) + {} + + MockTextInputClient(const struct wl_registry_listener *listener) + : MockClient(listener, this) + { + ds_inf("%s", __func__); + } + + ~MockTextInputClient() + { + 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 SetTextInputMgr(struct wl_text_input_manager *global_res) + { + ds_inf("%s", __func__); + wl_text_input_manager = global_res; + } + + struct wl_text_input_manager *GetTextInputMgr() + { + ds_inf("%s", __func__); + + return wl_text_input_manager; + } + + void SetSeat(struct wl_seat *global_res) + { + ds_inf("%s", __func__); + wl_seat = global_res; + } + + struct wl_seat *GetSeat() + { + ds_inf("%s", __func__); + + return wl_seat; + } + +public: + bool bEnter; + bool bLeave; + bool bCallback; + +private: + struct wl_compositor *compositor_res; + struct wl_text_input_manager *wl_text_input_manager; + struct wl_seat *wl_seat; +}; + +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__); + + MockTextInputClient *client = static_cast(data); + struct wl_compositor *compositor_res; + struct wl_text_input_manager *wl_text_input_manager; + struct wl_seat *wl_seat; + + 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, "wl_text_input_manager")) { + wl_text_input_manager = (struct wl_text_input_manager *)wl_registry_bind(registry, + name, &wl_text_input_manager_interface, TEXT_INPUT_MGR_VERSION); + if (wl_text_input_manager == nullptr) { + ds_err("wl_registry_bind() failed. wl_text_input_manager resource."); + return; + } + client->SetTextInputMgr(wl_text_input_manager); + } else if (!strcmp(interface, "wl_seat")) { + wl_seat = (struct wl_seat *)wl_registry_bind(registry, + name, &wl_seat_interface, SEAT_VERSION); + if (wl_seat == nullptr) { + ds_err("wl_registry_bind() failed. wl_seat resource."); + return; + } + client->SetSeat(wl_seat); + } +} + +static void +client_registry_cb_global_remove(void *data, struct wl_registry *registry, + uint32_t name) +{ + ds_inf("%s", __func__); + + MockTextInputClient *client = static_cast(data); + struct wl_compositor *compositor_res = client->GetWlCompositor(); + struct wl_text_input_manager *text_input_mgr_res = client->GetTextInputMgr(); + struct wl_seat *seat_res = client->GetSeat(); + + wl_seat_destroy(seat_res); + wl_text_input_manager_destroy(text_input_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 +}; + +static void +text_input_cb_enter(void *data, struct wl_text_input *text_input, + struct wl_surface *surface) +{ + ds_inf("%s", __func__); + MockTextInputClient *client = static_cast(data); + client->bEnter = true; +} +static void +text_input_cb_leave(void *data, struct wl_text_input *text_input) +{ + ds_inf("%s", __func__); + MockTextInputClient *client = static_cast(data); + client->bLeave = true; +} +static void +text_input_cb_modifiers_map(void *data, struct wl_text_input *text_input, + struct wl_array *map) +{ + ds_inf("%s", __func__); + MockTextInputClient *client = static_cast(data); + client->bCallback = true; +} +static void +text_input_cb_input_panel_state(void *data, struct wl_text_input *text_input, + uint32_t state) +{ + ds_inf("%s", __func__); + MockTextInputClient *client = static_cast(data); + client->bCallback = true; +} +static void +text_input_cb_preedit_string(void *data, struct wl_text_input *text_input, + uint32_t serial, const char *text, const char *commit) +{ + ds_inf("%s", __func__); + MockTextInputClient *client = static_cast(data); + client->bCallback = true; +} +static void +text_input_cb_preedit_styling(void *data, struct wl_text_input *text_input, + uint32_t index, uint32_t length, uint32_t style) +{ + ds_inf("%s", __func__); + MockTextInputClient *client = static_cast(data); + client->bCallback = true; +} +static void +text_input_cb_preedit_cursor(void *data, struct wl_text_input *text_input, + int32_t index) +{ + ds_inf("%s", __func__); + MockTextInputClient *client = static_cast(data); + client->bCallback = true; +} +static void +text_input_cb_commit_string(void *data, struct wl_text_input *text_input, + uint32_t serial, const char *text) +{ + ds_inf("%s", __func__); + MockTextInputClient *client = static_cast(data); + client->bCallback = true; +} +static void +text_input_cb_cursor_position(void *data, struct wl_text_input *text_input, + int32_t index, int32_t anchor) +{ + ds_inf("%s", __func__); + MockTextInputClient *client = static_cast(data); + client->bCallback = true; +} +static void +text_input_cb_delete_surrounding_text(void *data, + struct wl_text_input *text_input, int32_t index, uint32_t length) +{ + ds_inf("%s", __func__); + MockTextInputClient *client = static_cast(data); + client->bCallback = true; +} +static void +text_input_cb_keysym(void *data, struct wl_text_input *text_input, + uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, + uint32_t modifiers) +{ + ds_inf("%s", __func__); + MockTextInputClient *client = static_cast(data); + client->bCallback = true; +} +static void +text_input_cb_language(void *data, struct wl_text_input *text_input, + uint32_t serial, const char *language) +{ + ds_inf("%s", __func__); + MockTextInputClient *client = static_cast(data); + client->bCallback = true; +} +static void +text_input_cb_text_direction(void *data, struct wl_text_input *text_input, + uint32_t serial, uint32_t direction) +{ + ds_inf("%s", __func__); + MockTextInputClient *client = static_cast(data); + client->bCallback = true; +} +//for tizen only +static void +text_input_cb_selection_region(void *data, + struct wl_text_input *text_input, + uint32_t serial, + int32_t start, + int32_t end) +{} +static void +text_input_cb_private_command(void *data, + struct wl_text_input *text_input, + uint32_t serial, + const char *command) +{} +static void +text_input_cb_input_panel_geometry(void *data, + struct wl_text_input *text_input, + uint32_t x, + uint32_t y, + uint32_t w, + uint32_t h) +{} +static void +text_input_cb_input_panel_data(void *data, + struct wl_text_input *text_input, + uint32_t serial, + const char *input_panel_data, + uint32_t length) +{} +static void +text_input_cb_get_selection_text (void *data, + struct wl_text_input *text_input, + int32_t fd) +{} +static void +text_input_cb_get_surrounding_text (void *data, + struct wl_text_input *text_input, + uint32_t maxlen_before, + uint32_t maxlen_after, + int32_t fd) +{} +static void +text_input_cb_filter_key_event_done(void *data, + struct wl_text_input *text_input, + uint32_t serial, + uint32_t state) +{} +static void +text_input_cb_hide_permission(void *data, + struct wl_text_input *text_input, + uint32_t permission) +{} +static void +text_input_cb_recapture_string(void *data, + struct wl_text_input *text_input, + uint32_t serial, + int32_t index, + uint32_t length, + const char *preedit, + const char *preedit_commit, + const char *commit) +{} +static void +text_input_cb_input_panel_event(void *data, + struct wl_text_input *text_input, + uint32_t serial, + uint32_t event_type, + uint32_t value) +{} + +static void +text_input_cb_commit_content(void *data, + struct wl_text_input *text_input, + uint32_t serial, + const char *content, + const char *description, + const char *mime_types) +{} +static const struct wl_text_input_listener text_input_cb_listener = +{ + .enter = text_input_cb_enter, + .leave = text_input_cb_leave, + .modifiers_map = text_input_cb_modifiers_map, + .input_panel_state = text_input_cb_input_panel_state, + .preedit_string = text_input_cb_preedit_string, + .preedit_styling = text_input_cb_preedit_styling, + .preedit_cursor = text_input_cb_preedit_cursor, + .commit_string = text_input_cb_commit_string, + .cursor_position = text_input_cb_cursor_position, + .delete_surrounding_text = text_input_cb_delete_surrounding_text, + .keysym = text_input_cb_keysym, + .language = text_input_cb_language, + .text_direction = text_input_cb_text_direction, + //for tizen only + .selection_region = text_input_cb_selection_region, + .private_command = text_input_cb_private_command, + .input_panel_geometry = text_input_cb_input_panel_geometry, + .input_panel_data = text_input_cb_input_panel_data, + .get_selection_text = text_input_cb_get_selection_text, + .get_surrounding_text = text_input_cb_get_surrounding_text, + .filter_key_event_done = text_input_cb_filter_key_event_done, + .hide_permission = text_input_cb_hide_permission, + .recapture_string = text_input_cb_recapture_string, + .input_panel_event = text_input_cb_input_panel_event, + .commit_content = text_input_cb_commit_content, +}; + +class TextInputTest : public ::testing::Test +{ +public: + void SetUp(void) override; + void TearDown(void) override; + + MockTextInputCompositor *comp; + MockTextInputClient *client; + struct wl_compositor *compositor_res; + struct wl_text_input_manager *text_input_mgr_res; + struct wl_text_input *text_input_res; + struct wl_seat *seat_res; +}; + +void +TextInputTest::SetUp(void) +{ + ds_inf("%s", __func__); + + comp = new MockTextInputCompositor(); + client = new MockTextInputClient(®istry_listener); + compositor_res = client->GetWlCompositor(); + text_input_mgr_res = client->GetTextInputMgr(); + seat_res = client->GetSeat(); + + text_input_res = wl_text_input_manager_create_text_input(text_input_mgr_res); + + wl_text_input_add_listener(text_input_res, + &text_input_cb_listener, client); + + client->RoundTrip(); +} + +void +TextInputTest::TearDown(void) +{ + ds_inf("%s", __func__); + + client->RoundTrip(); + + delete client; + delete comp; +} + +TEST_F(TextInputTest, Create_P) +{ + EXPECT_TRUE(true); +} + +TEST_F(TextInputTest, Req_TextInputMgr_CreateTextInput) +{ + EXPECT_TRUE(comp->bNewTextInput); + EXPECT_TRUE(text_input_res != NULL); +} + +TEST_F(TextInputTest, Req_TextInput_Activate) +{ + struct wl_surface *surface_res; + + surface_res = wl_compositor_create_surface(compositor_res); + client->RoundTrip(); + EXPECT_TRUE(surface_res != NULL); + wl_text_input_activate(text_input_res, seat_res, surface_res); + client->RoundTrip(); + EXPECT_TRUE(comp->bActivated); + EXPECT_TRUE(comp->mSeat != NULL); + EXPECT_TRUE(comp->mSurface != NULL); + + EXPECT_TRUE(client->bEnter); +} + +TEST_F(TextInputTest, Req_TextInput_Deactivate) +{ + struct wl_surface *surface_res; + + surface_res = wl_compositor_create_surface(compositor_res); + client->RoundTrip(); + EXPECT_TRUE(surface_res != NULL); + wl_text_input_activate(text_input_res, seat_res, surface_res); + client->RoundTrip(); + EXPECT_TRUE(comp->bActivated); + EXPECT_TRUE(comp->mSeat != NULL); + EXPECT_TRUE(comp->mSurface != NULL); + + EXPECT_TRUE(client->bEnter); + + wl_text_input_deactivate(text_input_res, seat_res); + client->RoundTrip(); + EXPECT_TRUE(comp->bActivated == false); + EXPECT_TRUE(comp->mSeat == NULL); + EXPECT_TRUE(comp->mSurface == NULL); + + EXPECT_TRUE(client->bLeave); +} + +TEST_F(TextInputTest, Req_TextInput_Reset) +{ + wl_text_input_reset(text_input_res); + client->RoundTrip(); + EXPECT_TRUE(comp->bReset); +} + +TEST_F(TextInputTest, Req_TextInput_SetContentType) +{ + uint32_t hint = 0, purpose = 0; + wl_text_input_set_content_type(text_input_res, hint, purpose); + client->RoundTrip(); + EXPECT_TRUE(comp->bContentType); +} + +TEST_F(TextInputTest, Req_TextInput_SetPreferredLanguage) +{ + wl_text_input_set_preferred_language(text_input_res, "en"); + client->RoundTrip(); + EXPECT_TRUE(comp->bPreferredLanguage); +} + +TEST_F(TextInputTest, Req_TextInput_CommitState) +{ + uint32_t serial = 1; + + wl_text_input_commit_state(text_input_res, serial); + client->RoundTrip(); + EXPECT_TRUE(comp->bCommitState); +} + +TEST_F(TextInputTest, Req_TextInput_InvokeAction) +{ + uint32_t button = 0, index = 1; + wl_text_input_invoke_action(text_input_res, button, index); + client->RoundTrip(); + EXPECT_TRUE(comp->bInvokeAction); +} + +TEST_F(TextInputTest, Ev_TextInput_Enter) +{ + struct wl_surface *surface_res; + + surface_res = wl_compositor_create_surface(compositor_res); + client->RoundTrip(); + EXPECT_TRUE(surface_res != NULL); + wl_text_input_activate(text_input_res, seat_res, surface_res); + client->RoundTrip(); + + EXPECT_TRUE(comp->mSurface != NULL); + comp->SendEnter(); + comp->Process(); + + EXPECT_TRUE(client->bEnter); +} + +TEST_F(TextInputTest, Ev_TextInput_Leave) +{ + struct wl_surface *surface_res; + + surface_res = wl_compositor_create_surface(compositor_res); + client->RoundTrip(); + EXPECT_TRUE(surface_res != NULL); + wl_text_input_activate(text_input_res, seat_res, surface_res); + client->RoundTrip(); + + EXPECT_TRUE(comp->mSurface != NULL); + comp->SendLeave(); + comp->Process(); + + EXPECT_TRUE(client->bLeave); +} + +TEST_F(TextInputTest, Ev_TextInput_ModifiersMap) +{ + struct wl_array map_data; + int size; + void *data; + const char *modShift = "Shift", *modControl = "Control", *mod1 = "Mod1"; + + wl_array_init(&map_data); + + size = strlen(modShift) + 1; + data = wl_array_add(&map_data, size); + memcpy(data, modShift, size); + + size = strlen(modControl) + 1; + data = wl_array_add(&map_data, size); + memcpy(data, modControl, size); + + size = strlen(mod1) + 1; + data = wl_array_add(&map_data, size); + memcpy(data, mod1, size); + + comp->SendModifiersMap(&map_data); + comp->Process(); + + EXPECT_TRUE(client->bCallback); +} + +TEST_F(TextInputTest, Ev_TextInput_InputPanelState) +{ + comp->SendInputPanelState(WL_TEXT_INPUT_INPUT_PANEL_STATE_SHOW); + comp->Process(); + + EXPECT_TRUE(client->bCallback); +} + +TEST_F(TextInputTest, Ev_TextInput_PreeditString) +{ + comp->SendPreeditString(1, "", ""); + comp->Process(); + + EXPECT_TRUE(client->bCallback); +} + +TEST_F(TextInputTest, Ev_TextInput_PreeditStyling) +{ + comp->SendPreeditStyling(1, 1, 1); + comp->Process(); + + EXPECT_TRUE(client->bCallback); +} + +TEST_F(TextInputTest, Ev_TextInput_PreeditCursor) +{ + comp->SendPreeditCursor(0); + comp->Process(); + + EXPECT_TRUE(client->bCallback); +} + +TEST_F(TextInputTest, Ev_TextInput_CommitString) +{ + comp->SendCommitString(0, ""); + comp->Process(); + + EXPECT_TRUE(client->bCallback); +} + +TEST_F(TextInputTest, Ev_TextInput_CursorPosition) +{ + comp->SendCursorPosition(1, 1); + comp->Process(); + + EXPECT_TRUE(client->bCallback); +} + +TEST_F(TextInputTest, Ev_TextInput_DeleteSurroundingText) +{ + comp->SendDeleteSurroundingText(1, 1); + comp->Process(); + + EXPECT_TRUE(client->bCallback); +} + +TEST_F(TextInputTest, Ev_TextInput_Keysym) +{ + comp->SendKeysym(1, 10, 65, 1, 1); + comp->Process(); + + EXPECT_TRUE(client->bCallback); +} + +TEST_F(TextInputTest, Ev_TextInput_Language) +{ + comp->SendLanguage(1, "en_US"); + comp->Process(); + + EXPECT_TRUE(client->bCallback); +} + +TEST_F(TextInputTest, Ev_TextInput_TextDirection) +{ + comp->SendTextDirection(1, 1); + comp->Process(); + + EXPECT_TRUE(client->bCallback); +} \ No newline at end of file -- 2.7.4 From f854b9fd11277eac9ac471c9357698df2ca98c2d Mon Sep 17 00:00:00 2001 From: "duna.oh" Date: Mon, 22 Aug 2022 19:44:53 +0900 Subject: [PATCH 04/16] clients: add ime-keyboard(input_method), text-entry(text_input) ime-keyboard - deals with input_method - input key event usage) key [keys index] [down=1/up=0] ( keys = [q,w,e,r,t,,,,] ) ex) key 1 1 (input 'w' key) key 1 0 key 2 1 (input 'e' key) key 2 0 text-entry - deals with text_input - when mouse enters into the surface and mouse is pressed, text_input is activated. when mouse is released, text_input is deactivated. - usage) when text_input is activated, this gets key event from input_method. Change-Id: Idbea6f4d5756cfcb65f2810f4a3967669ff04045 --- clients/ime-keyboard.c | 957 +++++++++++++++++++++++++++++++++++++++ clients/meson.build | 32 ++ clients/text-entry.c | 1071 ++++++++++++++++++++++++++++++++++++++++++++ examples/meson.build | 2 + examples/tinyds-tdm.c | 743 +++++++++++++++++++++++++++++- packaging/libds-tizen.spec | 2 + 6 files changed, 2806 insertions(+), 1 deletion(-) create mode 100644 clients/ime-keyboard.c create mode 100644 clients/text-entry.c diff --git a/clients/ime-keyboard.c b/clients/ime-keyboard.c new file mode 100644 index 0000000..4d6346d --- /dev/null +++ b/clients/ime-keyboard.c @@ -0,0 +1,957 @@ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define MAX_STR 1024 +#define SIZE_EPOLL 16 + +enum keyboard_state { + KEYBOARD_STATE_DEFAULT, + KEYBOARD_STATE_UPPERCASE, + KEYBOARD_STATE_SYMBOLS +}; + +struct display +{ + struct wl_display *display; + struct wl_registry *registry; + struct wl_compositor *compositor; + struct wl_event_queue *queue; + + int run; + int fd_epoll; + int fd_display; + + int enable_log; + + struct zwp_input_method_manager_v1 *input_method_mgr; + struct zwp_input_method_v1 *input_method; + struct zwp_input_method_context_v1 *context; + + char *preedit_string; + uint32_t preedit_style; + struct { + xkb_mod_mask_t shift_mask; + } keysym; + uint32_t serial; + uint32_t content_hint; + int32_t content_purpose; + char *preferred_language; + char *surrounding_text; + uint32_t surrounding_cursor; + enum keyboard_state state; //struct keyboard *keyboard; + + //struct zwp_input_panel_surface_v1 *ips; +}; + +struct layout { + const struct key *keys; + uint32_t count; + + uint32_t columns; + uint32_t rows; + + const char *language; + uint32_t text_direction; +}; + +enum key_type { + keytype_default, + keytype_backspace, + keytype_enter, + keytype_space, + keytype_switch, + keytype_symbols, + keytype_tab, + keytype_arrow_up, + keytype_arrow_left, + keytype_arrow_right, + keytype_arrow_down, + keytype_style +}; + +struct key { + enum key_type key_type; + + char *label; + char *uppercase; + char *symbol; + + unsigned int width; +}; + +static const struct key normal_keys[] = { + { keytype_default, "q", "Q", "1", 1}, + { keytype_default, "w", "W", "2", 1}, + { keytype_default, "e", "E", "3", 1}, + { keytype_default, "r", "R", "4", 1}, + { keytype_default, "t", "T", "5", 1}, + { keytype_default, "y", "Y", "6", 1}, + { keytype_default, "u", "U", "7", 1}, + { keytype_default, "i", "I", "8", 1}, + { keytype_default, "o", "O", "9", 1}, + { keytype_default, "p", "P", "0", 1}, + { keytype_backspace, "<--", "<--", "<--", 2}, + + { keytype_tab, "->|", "->|", "->|", 1}, + { keytype_default, "a", "A", "-", 1}, + { keytype_default, "s", "S", "@", 1}, + { keytype_default, "d", "D", "*", 1}, + { keytype_default, "f", "F", "^", 1}, + { keytype_default, "g", "G", ":", 1}, + { keytype_default, "h", "H", ";", 1}, + { keytype_default, "j", "J", "(", 1}, + { keytype_default, "k", "K", ")", 1}, + { keytype_default, "l", "L", "~", 1}, + { keytype_enter, "Enter", "Enter", "Enter", 2}, + + { keytype_switch, "ABC", "abc", "ABC", 2}, + { keytype_default, "z", "Z", "/", 1}, + { keytype_default, "x", "X", "\'", 1}, + { keytype_default, "c", "C", "\"", 1}, + { keytype_default, "v", "V", "+", 1}, + { keytype_default, "b", "B", "=", 1}, + { keytype_default, "n", "N", "?", 1}, + { keytype_default, "m", "M", "!", 1}, + { keytype_default, ",", ",", "\\", 1}, + { keytype_default, ".", ".", "|", 1}, + { keytype_switch, "ABC", "abc", "ABC", 1}, + + { keytype_symbols, "?123", "?123", "abc", 1}, + { keytype_space, "", "", "", 5}, + { keytype_arrow_up, "/\\", "/\\", "/\\", 1}, + { keytype_arrow_left, "<", "<", "<", 1}, + { keytype_arrow_right, ">", ">", ">", 1}, + { keytype_arrow_down, "\\/", "\\/", "\\/", 1}, + { keytype_style, "", "", "", 2} +}; + +static const struct key numeric_keys[] = { + { keytype_default, "1", "1", "1", 1}, + { keytype_default, "2", "2", "2", 1}, + { keytype_default, "3", "3", "3", 1}, + { keytype_default, "4", "4", "4", 1}, + { keytype_default, "5", "5", "5", 1}, + { keytype_default, "6", "6", "6", 1}, + { keytype_default, "7", "7", "7", 1}, + { keytype_default, "8", "8", "8", 1}, + { keytype_default, "9", "9", "9", 1}, + { keytype_default, "0", "0", "0", 1}, + { keytype_backspace, "<--", "<--", "<--", 2}, + + { keytype_space, "", "", "", 4}, + { keytype_enter, "Enter", "Enter", "Enter", 2}, + { keytype_arrow_up, "/\\", "/\\", "/\\", 1}, + { keytype_arrow_left, "<", "<", "<", 1}, + { keytype_arrow_right, ">", ">", ">", 1}, + { keytype_arrow_down, "\\/", "\\/", "\\/", 1}, + { keytype_style, "", "", "", 2} +}; + +static const struct layout normal_layout = { + normal_keys, + sizeof(normal_keys) / sizeof(*normal_keys), + 12, + 4, + "en", + WL_TEXT_INPUT_TEXT_DIRECTION_LTR +}; + +static const struct layout numeric_layout = { + numeric_keys, + sizeof(numeric_keys) / sizeof(*numeric_keys), + 12, + 2, + "en", + WL_TEXT_INPUT_TEXT_DIRECTION_LTR +}; + +struct display data_wl; +static void +request_key(uint32_t time, const struct key *key, enum wl_pointer_button_state state); + +static void +usage(void) +{ + printf(" This is virtual keyboard. (refer to weston/clients/keyboard.c)\n"); + printf("\n"); +} + +static const struct layout * +get_current_layout(void) +{ + switch (data_wl.content_purpose) { + case WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS: + case WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER: + return &numeric_layout; + default: + return &normal_layout; + } +} + +static void +stdin_read(void) +{ + int c; + char buf[MAX_STR] = {0, }, *tmp, *buf_ptr; + int count = 0; + static uint32_t time = 12345; + const struct layout *layout; + uint32_t key_type = 0, key_idx = 0; + + while ((c = getchar()) != EOF) { + if (c == '\n') break; + if (count >= MAX_STR) break; + + buf[count] = c; + count++; + } + + count = 0; + tmp = strtok_r(buf, " ", &buf_ptr); + if (!tmp) return; + + if (!strncmp(buf, "q", MAX_STR) || !strncmp(buf, "quit", MAX_STR)) { + data_wl.run = 0; + } else if (!strncmp(buf, "help", MAX_STR)) { + usage(); + } else if (!strncmp(buf, "log", MAX_STR)) { + if (data_wl.enable_log) + printf("Disable detailed logs\n"); + else + printf("Enable detailed logs\n"); + + data_wl.enable_log = !data_wl.enable_log; + } else if (!strncmp(tmp, "key", MAX_STR)) { + while (tmp) { + tmp = strtok_r(NULL, " ", &buf_ptr); + if (tmp) { + switch (count) { + case 0: + key_idx = atoi(tmp); + break; + case 1: + key_type = atoi(tmp); + break; + default: + break; + } + } + count++; + } + if (data_wl.enable_log) + printf("request key() key_idx:%u, key_type:%u\n", key_idx, key_type); + + layout = get_current_layout(); + request_key(time++, &layout->keys[key_idx], key_type); + + } else { + printf("Invalid arguments\n"); + usage(); + } +} + +static const char * +prev_utf8_char(const char *s, const char *p) +{ + for (--p; p >= s; --p) { + if ((*p & 0xc0) != 0x80) + return p; + } + return NULL; +} + +static void +delete_before_cursor(void) +{ + const char *start, *end; + + if (!data_wl.surrounding_text) { + printf("delete_before_cursor: No surrounding text available\n"); + return; + } + + start = prev_utf8_char(data_wl.surrounding_text, + data_wl.surrounding_text + data_wl.surrounding_cursor); + if (!start) { + printf("delete_before_cursor: No previous character to delete\n"); + return; + } + + end = data_wl.surrounding_text + data_wl.surrounding_cursor; + + zwp_input_method_context_v1_delete_surrounding_text(data_wl.context, + (start - data_wl.surrounding_text) - data_wl.surrounding_cursor, + end - start); + zwp_input_method_context_v1_commit_string(data_wl.context, + data_wl.serial, + ""); + + /* Update surrounding text */ + data_wl.surrounding_cursor = start - data_wl.surrounding_text; + data_wl.surrounding_text[data_wl.surrounding_cursor] = '\0'; + if (*end) + memmove(data_wl.surrounding_text + data_wl.surrounding_cursor, end, strlen(end)); +} + +static char * +append(char *s1, const char *s2) +{ + int len1, len2; + char *s = NULL; + + len1 = strlen(s1); + len2 = strlen(s2); + s = realloc(s1, len1 + len2 + 1); + if (s == NULL) { + printf("alloc fail"); + return NULL; + } + memcpy(s + len1, s2, len2); + s[len1 + len2] = '\0'; + + return s; +} + +static void +request_preedit(int32_t cursor) +{ + printf("request_preedit() preedit_string:%s\n", data_wl.preedit_string); + uint32_t index = strlen(data_wl.preedit_string); + + if (!data_wl.context) return; + + if (data_wl.preedit_style) + zwp_input_method_context_v1_preedit_styling(data_wl.context, + 0, + strlen(data_wl.preedit_string), + data_wl.preedit_style); + if (cursor > 0) + index = cursor; + zwp_input_method_context_v1_preedit_cursor(data_wl.context, + index); + zwp_input_method_context_v1_preedit_string(data_wl.context, + data_wl.serial, + data_wl.preedit_string, + data_wl.preedit_string); +} + +static char * +insert_text(const char *text, uint32_t offset, const char *insert) +{ + int tlen = strlen(text), ilen = strlen(insert); + char *new_text = NULL; + + new_text = malloc(tlen + ilen + 1); + if (new_text == NULL) { + printf("alloc fail"); + return NULL; + } + + memcpy(new_text, text, offset); + memcpy(new_text + offset, insert, ilen); + memcpy(new_text + offset + ilen, text + offset, tlen - offset); + new_text[tlen + ilen] = '\0'; + + return new_text; +} + +static void +request_commit_string(void) +{ + char *surrounding_text; + + printf("request_commit_string()\n"); + + if (!data_wl.preedit_string || + strlen(data_wl.preedit_string) == 0) + return; + printf("request_commit_string() preedit_string:%s\n", data_wl.preedit_string); + + if (!data_wl.context) return; + + zwp_input_method_context_v1_cursor_position(data_wl.context, + 0, 0); + zwp_input_method_context_v1_commit_string(data_wl.context, + data_wl.serial, + data_wl.preedit_string); + + if (data_wl.surrounding_text) { + surrounding_text = insert_text(data_wl.surrounding_text, + data_wl.surrounding_cursor, + data_wl.preedit_string); + free(data_wl.surrounding_text); + data_wl.surrounding_text = surrounding_text; + data_wl.surrounding_cursor += strlen(data_wl.preedit_string); + } else { + data_wl.surrounding_text = strdup(data_wl.preedit_string); + data_wl.surrounding_cursor = strlen(data_wl.preedit_string); + } + + free(data_wl.preedit_string); + data_wl.preedit_string = strdup(""); +} + +static void +request_key(uint32_t time, const struct key *key, enum wl_pointer_button_state state) +{ + const char *label = NULL; + static uint32_t serial = 9999; + + switch(data_wl.state) { + case KEYBOARD_STATE_DEFAULT : + label = key->label; + break; + case KEYBOARD_STATE_UPPERCASE : + label = key->uppercase; + break; + case KEYBOARD_STATE_SYMBOLS : + label = key->symbol; + break; + default : + label = key->label; + break; + } + + xkb_mod_mask_t mod_mask = data_wl.state == KEYBOARD_STATE_DEFAULT ? 0 : data_wl.keysym.shift_mask; + uint32_t key_state = (state == WL_POINTER_BUTTON_STATE_PRESSED) ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED; + + printf("request_key() data_wl.state:%d, key->key_type:%d, pressed:%u, label:%s\n", data_wl.state, key->key_type, key_state, label); + switch (key->key_type) { + case keytype_default: + if (state != WL_POINTER_BUTTON_STATE_PRESSED) + break; + + printf("request_key() keytype_default. append label(%s) to preedit_string(%s)\n", label, data_wl.preedit_string); + data_wl.preedit_string = + append(data_wl.preedit_string, + label); + request_preedit(-1); + break; + case keytype_backspace: + if (state != WL_POINTER_BUTTON_STATE_PRESSED) + break; + + if (strlen(data_wl.preedit_string) == 0) { + delete_before_cursor(); + } else { + data_wl.preedit_string[strlen(data_wl.preedit_string) - 1] = '\0'; + request_preedit(-1); + } + break; + case keytype_enter: + request_commit_string(); + + if (!data_wl.context) break; + zwp_input_method_context_v1_keysym(data_wl.context, + serial++, + time, + XKB_KEY_Return, key_state, mod_mask); + break; + case keytype_space: + if (state != WL_POINTER_BUTTON_STATE_PRESSED) + break; + data_wl.preedit_string = + append(data_wl.preedit_string, " "); + request_commit_string(); + break; + case keytype_switch: + if (state != WL_POINTER_BUTTON_STATE_PRESSED) + break; + switch(data_wl.state) { + case KEYBOARD_STATE_DEFAULT: + data_wl.state = KEYBOARD_STATE_UPPERCASE; + break; + case KEYBOARD_STATE_UPPERCASE: + data_wl.state = KEYBOARD_STATE_DEFAULT; + break; + case KEYBOARD_STATE_SYMBOLS: + data_wl.state = KEYBOARD_STATE_UPPERCASE; + break; + } + break; + case keytype_symbols: + if (state != WL_POINTER_BUTTON_STATE_PRESSED) + break; + switch(data_wl.state) { + case KEYBOARD_STATE_DEFAULT: + data_wl.state = KEYBOARD_STATE_SYMBOLS; + break; + case KEYBOARD_STATE_UPPERCASE: + data_wl.state = KEYBOARD_STATE_SYMBOLS; + break; + case KEYBOARD_STATE_SYMBOLS: + data_wl.state = KEYBOARD_STATE_DEFAULT; + break; + } + break; + case keytype_tab: + request_commit_string(); + if (!data_wl.context) break; + zwp_input_method_context_v1_keysym(data_wl.context, + serial++, + time, + XKB_KEY_Tab, key_state, mod_mask); + break; + case keytype_arrow_up: + request_commit_string(); + if (!data_wl.context) break; + zwp_input_method_context_v1_keysym(data_wl.context, + serial++, + time, + XKB_KEY_Up, key_state, mod_mask); + break; + case keytype_arrow_left: + request_commit_string(); + if (!data_wl.context) break; + zwp_input_method_context_v1_keysym(data_wl.context, + serial++, + time, + XKB_KEY_Left, key_state, mod_mask); + break; + case keytype_arrow_right: + request_commit_string(); + if (!data_wl.context) break; + zwp_input_method_context_v1_keysym(data_wl.context, + serial++, + time, + XKB_KEY_Right, key_state, mod_mask); + break; + case keytype_arrow_down: + request_commit_string(); + if (!data_wl.context) break; + zwp_input_method_context_v1_keysym(data_wl.context, + serial++, + time, + XKB_KEY_Down, key_state, mod_mask); + break; + case keytype_style: + if (state != WL_POINTER_BUTTON_STATE_PRESSED) + break; + data_wl.preedit_style = (data_wl.preedit_style + 1) % 8; /* TODO */ + request_preedit(-1); + break; + } +} + +static void +im_context_cb_surrounding_text (void *data, struct zwp_input_method_context_v1 *im_ctx, const char *text, uint32_t cursor, uint32_t anchor) +{ + printf("im_context_cb_surrounding_text\n"); + free(data_wl.surrounding_text); + data_wl.surrounding_text = strdup(text); + + data_wl.surrounding_cursor = cursor; +} + +static void +im_context_cb_reset (void *data, struct zwp_input_method_context_v1 *im_ctx) +{ + printf("im_context_cb_reset\n"); + + if (strlen(data_wl.preedit_string)) { + free(data_wl.preedit_string); + data_wl.preedit_string = strdup(""); + } +} + +static void +im_context_cb_content_type (void *data, struct zwp_input_method_context_v1 *im_ctx, uint32_t hint, uint32_t purpose) +{ + printf("im_context_cb_content_type\n"); + + data_wl.content_hint = hint; + data_wl.content_purpose = purpose; +} + +static void +im_context_cb_invoke_action (void *data, struct zwp_input_method_context_v1 *im_ctx, uint32_t button, uint32_t index) +{ + printf("im_context_cb_invoke_action\n"); + + if (button != BTN_LEFT) + return; + + request_preedit(index); +} + +static void +im_context_cb_commit_state (void *data, struct zwp_input_method_context_v1 *context, uint32_t serial) +{ + printf("im_context_cb_commit_state\n"); + + const struct layout *layout; + + data_wl.serial = serial; + + layout = get_current_layout(); + + if (data_wl.surrounding_text) + printf("Surrounding text updated: %s\n", data_wl.surrounding_text); + + if (!context) return; + zwp_input_method_context_v1_language(context, + data_wl.serial, + layout->language); + zwp_input_method_context_v1_text_direction(context, + data_wl.serial, + layout->text_direction); +} + +static void +im_context_cb_preferred_language (void *data, struct zwp_input_method_context_v1 *context, const char *language) +{ + printf("im_context_cb_preferred_language\n"); + + if (data_wl.preferred_language) + free(data_wl.preferred_language); + + data_wl.preferred_language = NULL; + + if (language) + data_wl.preferred_language = strdup(language); +} + +static const struct zwp_input_method_context_v1_listener input_method_context_cb_listener = { + .surrounding_text = im_context_cb_surrounding_text, + .reset = im_context_cb_reset, + .content_type = im_context_cb_content_type, + .invoke_action = im_context_cb_invoke_action, + .commit_state = im_context_cb_commit_state, + .preferred_language = im_context_cb_preferred_language, + //for tizen only + .return_key_type = NULL, + .return_key_disabled = NULL, + .input_panel_data = NULL, + .bidi_direction = NULL, + .cursor_position = NULL, + .process_input_device_event = NULL, + .filter_key_event = NULL, + .capital_mode = NULL, + .prediction_hint = NULL, + .mime_type = NULL, + .finalized_content = NULL, + .prediction_hint_data = NULL, + .input_panel_enabled = NULL, +}; + +static void +keysym_modifiers_add(struct wl_array *modifiers_map, + const char *name) +{ + size_t len = strlen(name) + 1; + char *p; + + p = wl_array_add(modifiers_map, len); + + if (p == NULL) + return; + + strncpy(p, name, len); +} + +static xkb_mod_index_t +keysym_modifiers_get_index(struct wl_array *modifiers_map, + const char *name) +{ + xkb_mod_index_t index = 0; + char *p = modifiers_map->data; + + while ((const char *)p < (const char *)(modifiers_map->data + modifiers_map->size)) { + if (strcmp(p, name) == 0) + return index; + + index++; + p += strlen(p) + 1; + } + + return XKB_MOD_INVALID; +} + +xkb_mod_mask_t +keysym_modifiers_get_mask(struct wl_array *modifiers_map, + const char *name) +{ + xkb_mod_index_t index = keysym_modifiers_get_index(modifiers_map, name); + + if (index == XKB_MOD_INVALID) + return XKB_MOD_INVALID; + + return 1 << index; +} + +static void +im_cb_activate (void *data, struct zwp_input_method_v1 *input_method, struct zwp_input_method_context_v1 *context) +{ + printf("im_cb_activate\n"); + + struct wl_array modifiers_map; + const struct layout *layout; + + if (data_wl.context) + zwp_input_method_context_v1_destroy(data_wl.context); + + if (data_wl.preedit_string) + free(data_wl.preedit_string); + + data_wl.preedit_style = 0; + data_wl.preedit_string = strdup(""); + data_wl.content_hint = 0; + data_wl.content_purpose = 0; + free(data_wl.preferred_language); + data_wl.preferred_language = NULL; + free(data_wl.surrounding_text); + data_wl.surrounding_text = NULL; + + data_wl.serial = 0; + + data_wl.context = context; + zwp_input_method_context_v1_add_listener(context, + &input_method_context_cb_listener, + NULL); + + wl_array_init(&modifiers_map); + keysym_modifiers_add(&modifiers_map, "Shift"); + keysym_modifiers_add(&modifiers_map, "Control"); + keysym_modifiers_add(&modifiers_map, "Mod1"); + zwp_input_method_context_v1_modifiers_map(context, &modifiers_map); + data_wl.keysym.shift_mask = keysym_modifiers_get_mask(&modifiers_map, "Shift"); + wl_array_release(&modifiers_map); + + layout = get_current_layout(); + + zwp_input_method_context_v1_language(context, + data_wl.serial, + layout->language); + zwp_input_method_context_v1_text_direction(context, + data_wl.serial, + layout->text_direction); +} +static void +im_cb_deactivate (void *data, struct zwp_input_method_v1 *input_method, struct zwp_input_method_context_v1 *im_ctx) +{ + printf("im_cb_deactivate\n"); + + if (!data_wl.context) + return; + + zwp_input_method_context_v1_destroy(data_wl.context); + data_wl.context = NULL; +} + +static void +im_cb_destroy (void *data, struct zwp_input_method_v1 *input_method, struct zwp_input_method_context_v1 *im_ctx) +{ + printf("im_cb_destroy\n"); + zwp_input_method_v1_destroy(data_wl.input_method); + data_wl.input_method = NULL; +} + +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 = NULL, + .hide_input_panel = NULL, + .open_connection = NULL, + .close_connection = NULL, + .set_text_input_id = NULL, +}; + +static void +registry_handle_global(void * data, struct wl_registry * registry, uint32_t id, + const char * interface, uint32_t version) +{ + if (strcmp(interface, "wl_compositor") == 0) { + data_wl.compositor = wl_registry_bind(registry, id, + &wl_compositor_interface, version); + if (!data_wl.compositor) { + printf("Failed to bind compositor.\n"); + return; + } + if (data_wl.enable_log) + printf("Success to bind compositor.\n"); + } else if (!strcmp(interface, "zwp_input_method_manager_v1")) { + data_wl.input_method_mgr = wl_registry_bind(registry, id, + &zwp_input_method_manager_v1_interface, version); + } else if (!strcmp(interface, "zwp_input_method_v1")) { + data_wl.input_method = wl_registry_bind(registry, id, + &zwp_input_method_v1_interface, version); + zwp_input_method_v1_add_listener(data_wl.input_method, + &input_method_cb_listener, + NULL); + + //TODO: delte this code. this job should be done in cb_activate + data_wl.preedit_string = strdup(""); + data_wl.content_hint = 0; + data_wl.content_purpose = 0; + free(data_wl.preferred_language); + data_wl.preferred_language = NULL; + free(data_wl.surrounding_text); + data_wl.surrounding_text = NULL; + data_wl.serial = 0; + } +} + +static void +registry_handle_global_remove(void * data, struct wl_registry * registry, uint32_t id) +{ + if (data_wl.enable_log) + printf("registry is removed. id: %d !\n", id); +} + +static const struct wl_registry_listener _registry_listener = { + registry_handle_global, + registry_handle_global_remove +}; + +static int +wayland_init(void) +{ + memset(&data_wl, 0, sizeof(struct display)); + + data_wl.display = wl_display_connect(NULL); + if (!data_wl.display) { + printf("Failed to connect wayland display\n"); + return 0; + } + + data_wl.queue = wl_display_create_queue(data_wl.display); + if (!data_wl.queue) { + printf("Failed to create queue\n"); + return 0; + } + + data_wl.registry = wl_display_get_registry(data_wl.display); + if (!data_wl.registry) { + printf("Failed to get registry\n"); + return 0; + } + + wl_proxy_set_queue((struct wl_proxy*)data_wl.registry, data_wl.queue); + wl_registry_add_listener(data_wl.registry, &_registry_listener, NULL); + + if (wl_display_dispatch_queue(data_wl.display, data_wl.queue) == -1) { + printf("Failed to dispatch display\n"); + return 0; + } + if (wl_display_roundtrip_queue(data_wl.display, data_wl.queue) == -1) { + printf("Failed to roundtrip display\n"); + return 0; + } + + return 1; +} + +static void +wayland_deinit(void) +{ + if (data_wl.enable_log) + printf("Shutdown wayland system\n"); + + if (data_wl.queue) wl_event_queue_destroy(data_wl.queue); + if (data_wl.display) { + if (data_wl.input_method) + zwp_input_method_v1_destroy(data_wl.input_method); + zwp_input_method_manager_v1_destroy(data_wl.input_method_mgr); + wl_registry_destroy(data_wl.registry); + wl_display_flush(data_wl.display); + wl_display_disconnect(data_wl.display); + } +} + +static int +epoll_init(void) +{ + struct epoll_event ep[2]; + + data_wl.fd_epoll = epoll_create(SIZE_EPOLL); + if (data_wl.fd_epoll <= 0) { + printf("Failed to epoll create: %d\n", SIZE_EPOLL); + return 0; + } + + data_wl.fd_display = wl_display_get_fd(data_wl.display); + + memset(ep, 0, sizeof(struct epoll_event)*2); + + ep[0].events = EPOLLIN | EPOLLERR | EPOLLHUP; + ep[0].data.fd = data_wl.fd_display; + epoll_ctl(data_wl.fd_epoll, EPOLL_CTL_ADD, data_wl.fd_display, &ep[0]); + ep[1].events = EPOLLIN | EPOLLERR | EPOLLHUP; + ep[1].data.fd = STDIN_FILENO; + epoll_ctl(data_wl.fd_epoll, EPOLL_CTL_ADD, 0, &ep[1]); + + return 1; +} + +static void +mainloop(void) +{ + struct epoll_event ep[SIZE_EPOLL]; + int res, count, i; + + res = epoll_init(); + if (!res) { + printf("Failed to init epoll\n"); + return; + } + + data_wl.run = 1; + while (data_wl.run) { + res = wl_display_dispatch_queue_pending(data_wl.display, data_wl.queue); + if (res < 0) { + printf("Failed to dispatch pending. result: %d\n", res); + data_wl.run = 0; + break; + } + res = wl_display_flush(data_wl.display); + if (res < 0) { + printf("Failed to flush display. result: %d\n", res); + data_wl.run = 0; + break; + } + + count = epoll_wait(data_wl.fd_epoll, ep, SIZE_EPOLL, -1); + for (i = 0; i < count; i++) { + if (ep[i].events & EPOLLIN) { + if (ep[i].data.fd == data_wl.fd_display) { + wl_display_dispatch_queue(data_wl.display, data_wl.queue); + } else { + stdin_read(); + } + } + if (ep[i].events & EPOLLERR) { + data_wl.run = 0; + } + if (ep[i].events & EPOLLHUP) { + data_wl.run = 0; + } + } + } +} + +int +main(int argc, char **argv) +{ + int res; + + res = wayland_init(); + if (!res) return 0; + + mainloop(); + + wayland_deinit(); + + return 0; +} diff --git a/clients/meson.build b/clients/meson.build index c97e3ad..672792a 100644 --- a/clients/meson.build +++ b/clients/meson.build @@ -14,6 +14,13 @@ simple_tbm_deps = [ tizen_extension_client, ] +text_entry_files = ['text-entry.c'] +text_entry_deps = [ + dependency('wayland-client', required: true), + wayland_tbm_client, + libtbm, +] + protocols = { 'xdg-shell': wl_protocol_dir / 'stable/xdg-shell/xdg-shell.xml', } @@ -28,6 +35,7 @@ foreach name, path : protocols command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'], ) simple_tbm_files += code + text_entry_files += code client_header = custom_target( name.underscorify() + '_client_h', @@ -37,6 +45,7 @@ foreach name, path : protocols build_by_default: false, ) simple_tbm_files += client_header + text_entry_files += client_header endforeach executable('ds-simple-tbm', @@ -56,6 +65,15 @@ executable('ds-simple-dpms', install: true, ) +executable('text-entry', + text_entry_files, + dependencies: [text_entry_deps, + deps_libds_tizen_text_input, + ], + install_dir: libds_tizen_bindir, + install: true, +) + input_generator_files = ['input-generator.c'] input_generator_deps = [ dependency('wayland-client', required: true), @@ -68,3 +86,17 @@ executable('input-generator', install_dir: libds_tizen_bindir, install: true, ) + +ime_keyboard_files = ['ime-keyboard.c'] +ime_keyboard_deps = [ + dependency('wayland-client', required: true), +] + +executable('ime-keyboard', + ime_keyboard_files, + dependencies: [ime_keyboard_deps, + deps_libds_tizen_input_method, + ], + install_dir: libds_tizen_bindir, + install: true, +) diff --git a/clients/text-entry.c b/clients/text-entry.c new file mode 100644 index 0000000..a806f0e --- /dev/null +++ b/clients/text-entry.c @@ -0,0 +1,1071 @@ +/* + * Copyright © 2011 Benjamin Franzke + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "xdg-shell-client-protocol.h" +#include +#include + +static uint64_t buffer_info_key; +#define BUFFER_INFO_KEY (unsigned long)(&buffer_info_key) + +struct display { + struct wl_display *display; + struct wl_registry *registry; + struct wl_compositor *compositor; + struct xdg_wm_base *wm_base; + struct wl_shm *shm; + struct wl_seat *seat; + struct wayland_tbm_client *wl_tbm; + bool has_xrgb; + + struct wl_text_input_manager *text_input_mgr; + int notified; + bool blocked; + struct wl_surface *entered_surface; + + struct text_entry *entry; +}; + +struct window { + struct display *display; + int width, height; + struct wl_surface *surface; + struct xdg_surface *xdg_surface; + struct xdg_toplevel *xdg_toplevel; + struct wl_callback *callback; + tbm_surface_queue_h surface_queue; + bool wait_for_configure; +}; + +struct buffer_info { + struct window *window; + struct wl_buffer *wl_buffer; +}; + +struct text_entry { + char *text; + int active; + bool panel_visible; + uint32_t cursor; + uint32_t anchor; + struct { + char *text; + int32_t cursor; + char *commit; + } preedit; + struct { + int32_t cursor; + } preedit_info; + struct { + int32_t cursor; + int32_t anchor; + uint32_t delete_index; + uint32_t delete_length; + bool invalid_delete; + } pending_commit; + struct wl_text_input *text_input; + struct { + xkb_mod_mask_t shift_mask; + } keysym; + uint32_t serial; + uint32_t reset_serial; + uint32_t content_purpose; + bool click_to_show; + char *preferred_language; + bool button_pressed; +}; + +struct rectangle { + int32_t x; + int32_t y; + int32_t width; + int32_t height; +}; + +static int running = 1; + +static void +redraw(void *data, struct wl_callback *callback, uint32_t time); +static void +text_entry_activate(struct display *d); +static void +text_entry_deactivate(struct display *d); + +static void +handle_xdg_surface_configure(void *data, struct xdg_surface *surface, + uint32_t serial) +{ + struct window *window = data; + + xdg_surface_ack_configure(surface, serial); + + if (window->wait_for_configure) { + redraw(window, NULL, 0); + window->wait_for_configure = false; + } +} + +static const struct xdg_surface_listener xdg_surface_listener = { + handle_xdg_surface_configure, +}; + +static void +handle_xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel, + int32_t width, int32_t height, + struct wl_array *state) +{ +} + +static void +handle_xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel) +{ + running = 0; +} + +static const struct xdg_toplevel_listener xdg_toplevel_listener = { + handle_xdg_toplevel_configure, + handle_xdg_toplevel_close, +}; + +static struct window * +create_window(struct display *display, int width, int height) +{ + struct window *window; + + window = calloc(1, sizeof *window); + if (!window) + return NULL; + + window->callback = NULL; + window->display = display; + window->width = width; + window->height = height; + window->surface = wl_compositor_create_surface(display->compositor); + + if (display->wm_base) { + window->xdg_surface = + xdg_wm_base_get_xdg_surface(display->wm_base, + window->surface); + assert(window->xdg_surface); + xdg_surface_add_listener(window->xdg_surface, + &xdg_surface_listener, window); + + window->xdg_toplevel = + xdg_surface_get_toplevel(window->xdg_surface); + assert(window->xdg_toplevel); + xdg_toplevel_add_listener(window->xdg_toplevel, + &xdg_toplevel_listener, window); + + xdg_toplevel_set_title(window->xdg_toplevel, "simple-tbm"); + wl_surface_commit(window->surface); + window->wait_for_configure = true; + } else { + assert(0); + } + + window->surface_queue = + wayland_tbm_client_create_surface_queue(display->wl_tbm, + window->surface, + 3, + width, + height, + TBM_FORMAT_XRGB8888); + assert(window->surface_queue); + + return window; +} + +static void +destroy_window(struct window *window) +{ + tbm_surface_queue_destroy(window->surface_queue); + + if (window->callback) + wl_callback_destroy(window->callback); + + if (window->xdg_toplevel) + xdg_toplevel_destroy(window->xdg_toplevel); + if (window->xdg_surface) + xdg_surface_destroy(window->xdg_surface); + wl_surface_destroy(window->surface); + free(window); +} + +static void +paint_pixels(void *image, int padding, int width, int height, uint32_t time) +{ + const int halfh = padding + (height - padding * 2) / 2; + const int halfw = padding + (width - padding * 2) / 2; + int ir, or; + uint32_t *pixel = image; + int y; + + /* squared radii thresholds */ + or = (halfw < halfh ? halfw : halfh) - 8; + ir = or - 32; + or *= or; + ir *= ir; + + pixel += padding * width; + for (y = padding; y < height - padding; y++) { + int x; + int y2 = (y - halfh) * (y - halfh); + + pixel += padding; + for (x = padding; x < width - padding; x++) { + uint32_t v; + + /* squared distance from center */ + int r2 = (x - halfw) * (x - halfw) + y2; + + if (r2 < ir) + v = (r2 / 32 + time / 64) * 0x0080401; + else if (r2 < or) + v = (y + time / 32) * 0x0080401; + else + v = (x + time / 16) * 0x0080401; + v &= 0x00ffffff; + + /* cross if compositor uses X from XRGB as alpha */ + if (abs(x - y) > 6 && abs(x + y - height) > 6) + v |= 0xff000000; + + *pixel++ = v; + } + + pixel += padding; + } +} + +static void +buffer_info_free_cb(void *data) +{ + struct buffer_info *buffer_info = data; + + if (!buffer_info) + return; + + wayland_tbm_client_destroy_buffer(buffer_info->window->display->wl_tbm, + buffer_info->wl_buffer); + free(buffer_info); +} + +static void +buffer_handle_release(void *data, struct wl_buffer *wl_buffer) +{ + tbm_surface_h surface = data; + struct buffer_info *buffer_info; + + tbm_surface_internal_get_user_data(surface, BUFFER_INFO_KEY, + (void **)&buffer_info); + if (buffer_info) + tbm_surface_queue_release(buffer_info->window->surface_queue, surface); +} + +static const struct wl_buffer_listener buffer_listener = { + .release = buffer_handle_release, +}; + +static const struct wl_callback_listener frame_listener; + +static void +redraw(void *data, struct wl_callback *callback, uint32_t time) +{ + struct window *window = data; + struct buffer_info *buffer_info = NULL; + tbm_surface_h surface = NULL; + tbm_surface_info_s surface_info; + + if (!tbm_surface_queue_can_dequeue(window->surface_queue, 0)) + return; + + tbm_surface_queue_dequeue(window->surface_queue, &surface); + assert(surface); + + tbm_surface_internal_get_user_data(surface, BUFFER_INFO_KEY, + (void **)&buffer_info); + if (!buffer_info) { + buffer_info = calloc(1, sizeof *buffer_info); + assert(buffer_info); + + tbm_surface_internal_add_user_data(surface, BUFFER_INFO_KEY, buffer_info_free_cb); + tbm_surface_internal_set_user_data(surface, BUFFER_INFO_KEY, buffer_info); + + buffer_info->wl_buffer = + wayland_tbm_client_create_buffer(window->display->wl_tbm, surface); + assert(buffer_info->wl_buffer); + + wl_buffer_add_listener(buffer_info->wl_buffer, &buffer_listener, + surface); + + buffer_info->window = window; + } + + tbm_surface_map(surface, TBM_SURF_OPTION_WRITE, &surface_info); + + paint_pixels(surface_info.planes[0].ptr, 20, + (surface_info.planes[0].stride/4), surface_info.height, time); + + tbm_surface_unmap(surface); + + wl_surface_attach(window->surface, buffer_info->wl_buffer, 0, 0); + wl_surface_damage(window->surface, + 20, 20, window->width - 40, window->height - 40); + + if (callback) + wl_callback_destroy(callback); + + window->callback = wl_surface_frame(window->surface); + wl_callback_add_listener(window->callback, &frame_listener, window); + wl_surface_commit(window->surface); +} + +static const struct wl_callback_listener frame_listener = { + redraw +}; + +static void +shm_format(void *data, struct wl_shm *wl_shm, uint32_t format) +{ + struct display *d = data; + + if (format == WL_SHM_FORMAT_XRGB8888) + d->has_xrgb = true; +} + +struct wl_shm_listener shm_listener = { + shm_format +}; + +static void +xdg_wm_base_ping(void *data, struct xdg_wm_base *shell, uint32_t serial) +{ + xdg_wm_base_pong(shell, serial); +} + +static const struct xdg_wm_base_listener xdg_wm_base_listener = { + xdg_wm_base_ping, +}; + +static void pointer_handle_button(void *data, struct wl_pointer *pointer, + uint32_t serial, uint32_t time, uint32_t button, uint32_t state) +{ + struct display *d = data; + + if (state == WL_POINTER_BUTTON_STATE_PRESSED) { + fprintf(stderr, "pointer_handle_button: PRESSED\n"); + + text_entry_activate(d); + } + else { + fprintf(stderr, "pointer_handle_button: RELEASED\n"); + + text_entry_deactivate(d); + } +} + +static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, + uint32_t serial, struct wl_surface *surface, + wl_fixed_t surface_x, wl_fixed_t surface_y) +{ + struct display *d = data; + + fprintf(stderr, "pointer_handle_enter surface_x:%d, surface_y:%d\n", + wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y)); + d->entered_surface = surface; +} + +static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer, + uint32_t serial, struct wl_surface *surface) +{ + fprintf(stderr, "pointer_handle_leave\n"); +} + +static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, + uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) +{ + fprintf(stderr, "pointer_handle_motion surface_x:%d, surface_y:%d\n", + wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y)); +} + +static void pointer_handle_frame(void *data, struct wl_pointer *wl_pointer) +{ + fprintf(stderr, "pointer_handle_frame\n"); +} + +static struct wl_pointer_listener pointer_listener = { + .enter = pointer_handle_enter, + .leave = pointer_handle_leave, + .motion = pointer_handle_motion, + .button = pointer_handle_button, + .axis = NULL, + .frame = pointer_handle_frame, + .axis_source = NULL, + .axis_stop = NULL, + .axis_discrete = NULL, +}; + +static void touch_handle_down(void *data, struct wl_touch *wl_touch, + uint32_t serial, uint32_t time, struct wl_surface *surface, + int32_t id, wl_fixed_t x, wl_fixed_t y) +{ + fprintf(stderr, "touch_handle_down id:%d, x:%d, y:%d\n", + id, wl_fixed_to_int(x), wl_fixed_to_int(y)); +} + +static void touch_handle_up(void *data, struct wl_touch *wl_touch, + uint32_t serial, uint32_t time, int32_t id) +{ + fprintf(stderr, "touch_handle_up id:%d\n", id); +} + +static void touch_handle_motion(void *data, struct wl_touch *wl_touch, + uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y) +{ + fprintf(stderr, "touch_handle_motion id:%d, x:%d, y:%d\n", + id, wl_fixed_to_int(x), wl_fixed_to_int(y)); +} + +static void touch_handle_frame(void *data, struct wl_touch *wl_touch) +{ + fprintf(stderr, "touch_handle_frame\n"); +} + +static struct wl_touch_listener touch_listener = { + .down = touch_handle_down, + .up = touch_handle_up, + .motion = touch_handle_motion, + .frame = touch_handle_frame, + .cancel = NULL, + .shape = NULL, + .orientation = NULL, +}; + +static void keyboard_handle_keymap(void *data, struct wl_keyboard *wl_keyboard, + uint32_t format, int32_t fd, uint32_t size) +{ + fprintf(stderr, "keyboard_handle_keymap\n"); +} +static void keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, struct wl_surface *surface, struct wl_array *keys) +{ + fprintf(stderr, "keyboard_handle_enter\n"); +} +static void keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, struct wl_surface *surface) +{ + fprintf(stderr, "keyboard_handle_leave\n"); +} +static void keyboard_handle_modifiers(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, + uint32_t mods_locked, uint32_t group) +{ + fprintf(stderr, "keyboard_handle_modifiers\n"); +} +static void keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard, + int32_t rate, int32_t delay) +{ + fprintf(stderr, "keyboard_handle_repeat_info\n"); +} + +static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, uint32_t time, uint32_t key, uint32_t state) +{ + if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { + fprintf(stderr, "keyboard_handle_key: key:%d, PRESSED\n", key); + } else { + fprintf(stderr, "keyboard_handle_key: key:%d, RELEASED\n", key); + } +} + +static struct wl_keyboard_listener keyboard_listener = { + .keymap = keyboard_handle_keymap, + .enter = keyboard_handle_enter, + .leave = keyboard_handle_leave, + .key = keyboard_handle_key, + .modifiers = keyboard_handle_modifiers, + .repeat_info = keyboard_handle_repeat_info, +}; + +static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, + enum wl_seat_capability caps) +{ + struct display *d = data; + if ((caps & WL_SEAT_CAPABILITY_KEYBOARD)) { + struct wl_keyboard *keyboard = wl_seat_get_keyboard(wl_seat); + wl_keyboard_add_listener(keyboard, &keyboard_listener, NULL); + fprintf(stderr, "seat_handle_capabilities: keyboard\n"); + } + if ((caps & WL_SEAT_CAPABILITY_POINTER)) { + struct wl_pointer *pointer = wl_seat_get_pointer(wl_seat); + wl_pointer_add_listener(pointer, &pointer_listener, d); + fprintf(stderr, "seat_handle_capabilities: pointer\n"); + } + if ((caps & WL_SEAT_CAPABILITY_TOUCH)) { + struct wl_touch *touch = wl_seat_get_touch(wl_seat); + wl_touch_add_listener(touch, &touch_listener, d); + fprintf(stderr, "seat_handle_capabilities: touch\n"); + } +} + +static void seat_handle_name(void *data, struct wl_seat *wl_seat, + const char *name) +{ + fprintf(stderr, "seat_handle_name name:%s\n", name); +} + +const struct wl_seat_listener seat_listener = { + .capabilities = seat_handle_capabilities, + .name = seat_handle_name, +}; + +static void +text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle) +{ + if (entry->preedit.text && entry->preedit.cursor < 0) { + rectangle->x = 0; + rectangle->y = 0; + rectangle->width = 0; + rectangle->height = 0; + return; + } + + rectangle->x = 10; + rectangle->y = 20; + rectangle->width = 50; + rectangle->height = 50; +} + +static void +text_entry_update(struct text_entry *entry) +{ + struct rectangle cursor_rectangle; + + fprintf(stderr, "text_entry_update()\n"); + + wl_text_input_set_content_type(entry->text_input, + WL_TEXT_INPUT_CONTENT_HINT_NONE, + entry->content_purpose); + + if (entry->preferred_language) + wl_text_input_set_preferred_language(entry->text_input, + entry->preferred_language); + + text_entry_get_cursor_rectangle(entry, &cursor_rectangle); + wl_text_input_set_cursor_rectangle(entry->text_input, + cursor_rectangle.x, + cursor_rectangle.y, + cursor_rectangle.width, + cursor_rectangle.height); + + wl_text_input_commit_state(entry->text_input, ++entry->serial); +} + +static void +text_entry_reset_preedit(struct text_entry *entry) +{ + fprintf(stderr, "text_entry_reset_preedit()\n"); + entry->preedit.cursor = 0; + + free(entry->preedit.text); + entry->preedit.text = NULL; + + free(entry->preedit.commit); + entry->preedit.commit = NULL; +} + +static void +text_entry_insert_at_cursor(struct text_entry *entry, const char *text, + int32_t cursor, int32_t anchor) +{ + fprintf(stderr, "text_entry_insert_at_cursor()\n"); + char *new_text = malloc(strlen(entry->text) + strlen(text) + 1); + if (new_text == NULL) { + fprintf(stderr, "alloc fail"); + return; + } + + strncpy(new_text, entry->text, entry->cursor); + strcpy(new_text + entry->cursor, text); + strcpy(new_text + entry->cursor + strlen(text), + entry->text + entry->cursor); + + free(entry->text); + entry->text = new_text; + if (anchor >= 0) + entry->anchor = entry->cursor + strlen(text) + anchor; + else + entry->anchor = entry->cursor + 1 + anchor; + + if (cursor >= 0) + entry->cursor += strlen(text) + cursor; + else + entry->cursor += 1 + cursor; + + text_entry_update(entry); +} + +static void +text_entry_commit_and_reset(struct text_entry *entry) +{ + char *commit = NULL; + + fprintf(stderr, "text_entry_commit_and_reset()\n"); + + if (entry->preedit.commit) + commit = strdup(entry->preedit.commit); + + text_entry_reset_preedit(entry); + if (commit) { + text_entry_insert_at_cursor(entry, commit, 0, 0); + free(commit); + } + + wl_text_input_reset(entry->text_input); + text_entry_update(entry); + entry->reset_serial = entry->serial; +} + +static void +text_input_enter(void *data, struct wl_text_input *text_input, + struct wl_surface *surface) +{ + fprintf(stderr, "text_input_enter()\n"); + + struct display *d = data; + struct text_entry *entry = d->entry; + + entry->active++; + + text_entry_update(entry); + entry->reset_serial = entry->serial; +} +static void +text_input_leave(void *data, struct wl_text_input *text_input) +{ + fprintf(stderr, "text_input_leave()\n"); + + struct display *d = data; + struct text_entry *entry = d->entry; + + text_entry_commit_and_reset(entry); + d->entry->active--; + + if (!entry->active) { + wl_text_input_hide_input_panel(text_input); + entry->panel_visible = false; + } +} + +static void +text_input_modifiers_map(void *data, struct wl_text_input *text_input, + struct wl_array *map) +{ + fprintf(stderr, "text_input_modifiers_map()\n"); +} + +static void +text_input_input_panel_state(void *data, struct wl_text_input *text_input, + uint32_t state) +{ + fprintf(stderr, "text_input_input_panel_state() state:%u\n", state); +} + +static void +text_input_preedit_string(void *data, struct wl_text_input *text_input, + uint32_t serial, const char *text, const char *commit) +{ + fprintf(stderr, "text_input_preedit_string() serial(%u), text(%s), commit(%s)\n", serial, text, commit); +} + +static void +text_input_preedit_styling(void *data, struct wl_text_input *text_input, + uint32_t index, uint32_t length, uint32_t style) +{ + fprintf(stderr, "text_input_preedit_styling() index(%u), length(%u), style(%u)\n", index, length, style); +} + +static void +text_input_preedit_cursor(void *data, struct wl_text_input *text_input, + int32_t index) +{ + fprintf(stderr, "text_input_preedit_cursor() index(%u)\n", index); +} + +static void +text_input_commit_string(void *data, struct wl_text_input *text_input, + uint32_t serial, const char *text) +{ + fprintf(stderr, "text_input_commit_string() serial(%u), text(%s)\n", serial, text); +} + +static void +text_input_cursor_position(void *data, struct wl_text_input *text_input, + int32_t index, int32_t anchor) +{ + fprintf(stderr, "text_input_cursor_position() index(%d), anchor(%d)\n", index, anchor); +} + +static void +text_input_delete_surrounding_text(void *data, + struct wl_text_input *text_input, int32_t index, uint32_t length) +{ + fprintf(stderr, "text_input_delete_surrounding_text() index(%d), length(%u)\n", index, length); +} + +static void +text_input_keysym(void *data, struct wl_text_input *text_input, + uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, + uint32_t modifiers) +{ + fprintf(stderr, "text_input_keysym() serial(%u), time(%u), sym(%u), state(%u), modifiers(%u)\n", + serial, time, sym, state, modifiers); +} + +static void +text_input_language(void *data, struct wl_text_input *text_input, + uint32_t serial, const char *language) +{ + fprintf(stderr, "text_input_language() serial(%u), language(%s)\n", serial, language); +} + +static void +text_input_text_direction(void *data, struct wl_text_input *text_input, + uint32_t serial, uint32_t direction) +{ + fprintf(stderr, "text_input_text_direction() serial(%d), direction(%d)\n", serial, direction); +} + +static const struct wl_text_input_listener text_input_listener = { + .enter = text_input_enter, + .leave = text_input_leave, + .modifiers_map = text_input_modifiers_map, + .input_panel_state = text_input_input_panel_state, + .preedit_string = text_input_preedit_string, + .preedit_styling = text_input_preedit_styling, + .preedit_cursor = text_input_preedit_cursor, + .commit_string = text_input_commit_string, + .cursor_position = text_input_cursor_position, + .delete_surrounding_text = text_input_delete_surrounding_text, + .keysym = text_input_keysym, + .language = text_input_language, + .text_direction = text_input_text_direction, + // TIZEN_ONLY(20150918): Support to set the selection region + .selection_region = NULL, + .private_command = NULL, + .input_panel_geometry = NULL, + .input_panel_data = NULL, + .get_selection_text = NULL, + .get_surrounding_text = NULL, + .filter_key_event_done = NULL, + .hide_permission = NULL, + .recapture_string = NULL, + .input_panel_event = NULL, + .commit_content = NULL, + // +}; + +static void +text_entry_activate(struct display *d) +{ + struct wl_surface *surface = d->entered_surface; + struct text_entry *entry = d->entry; + + fprintf(stderr, "text_entry_activate\n"); + if (entry->click_to_show && entry->active) { + entry->panel_visible = !entry->panel_visible; + + if (entry->panel_visible) + wl_text_input_show_input_panel(entry->text_input); + else + wl_text_input_hide_input_panel(entry->text_input); + + return; + } + + if (!entry->click_to_show) + wl_text_input_show_input_panel(entry->text_input); + + wl_text_input_activate(entry->text_input, + d->seat, + surface); +} + +static void +text_entry_deactivate(struct display *d) +{ + struct text_entry *entry = d->entry; + + fprintf(stderr, "text_entry_deactivate\n"); + wl_text_input_deactivate(entry->text_input, + d->seat); +} + +static void +text_entry_destroy(struct display *d) +{ + struct text_entry *entry; + + entry = d->entry; + d->entry = NULL; + + wl_text_input_destroy(entry->text_input); + free(entry->text); + free(entry->preferred_language); + free(entry); +} + +static struct text_entry* +text_entry_create(struct display *d, const char *text) +{ + struct text_entry *entry; + + entry = calloc(1, sizeof *entry); + if (!entry) + return NULL; + + entry->text = strdup(text); + entry->active = 0; + entry->panel_visible = false; + entry->cursor = strlen(text); + entry->anchor = entry->cursor; + entry->click_to_show = true; + entry->text_input = + wl_text_input_manager_create_text_input(d->text_input_mgr); + wl_text_input_add_listener(entry->text_input, + &text_input_listener, d); + + d->entry = entry; + fprintf(stderr, "text_entry_create() entry(%p) created.\n", entry); + + return entry; +} + +static void +registry_handle_global(void *data, struct wl_registry *registry, + uint32_t id, const char *interface, uint32_t version) +{ + struct display *d = data; + + if (strcmp(interface, "wl_compositor") == 0) { + d->compositor = + wl_registry_bind(registry, + id, &wl_compositor_interface, 1); + } else if (strcmp(interface, "xdg_wm_base") == 0) { + d->wm_base = wl_registry_bind(registry, + id, &xdg_wm_base_interface, 1); + xdg_wm_base_add_listener(d->wm_base, &xdg_wm_base_listener, d); + } else if (strcmp(interface, "wl_shm") == 0) { + d->shm = wl_registry_bind(registry, + id, &wl_shm_interface, 1); + wl_shm_add_listener(d->shm, &shm_listener, d); + } else if (strcmp(interface, "wl_seat") == 0) { + d->seat = wl_registry_bind(registry, + id, &wl_seat_interface, 7); + wl_seat_add_listener(d->seat, &seat_listener, d); + fprintf(stderr, "wl_seat bound!\n"); + } else if (strcmp(interface, "wl_text_input_manager") == 0) { + d->text_input_mgr = wl_registry_bind(registry, + id, &wl_text_input_manager_interface, version); + fprintf(stderr, "wl_text_input_manager bound!\n"); + + text_entry_create(d, "Entry"); + } +} + +static void +registry_handle_global_remove(void *data, struct wl_registry *registry, + uint32_t name) +{ +} + +static const struct wl_registry_listener registry_listener = { + registry_handle_global, + registry_handle_global_remove +}; + +static struct display * +create_display(void) +{ + struct display *display; + + display = calloc(1, sizeof *display); + if (display == NULL) { + fprintf(stderr, "out of memory\n"); + exit(1); + } + display->display = wl_display_connect(NULL); + assert(display->display); + + display->has_xrgb = false; + display->registry = wl_display_get_registry(display->display); + wl_registry_add_listener(display->registry, + ®istry_listener, display); + wl_display_roundtrip(display->display); + if (display->shm == NULL) { + fprintf(stderr, "No wl_shm global\n"); + exit(1); + } + + wl_display_roundtrip(display->display); + + /* + * Why do we need two roundtrips here? + * + * wl_display_get_registry() sends a request to the server, to which + * the server replies by emitting the wl_registry.global events. + * The first wl_display_roundtrip() sends wl_display.sync. The server + * first processes the wl_display.get_registry which includes sending + * the global events, and then processes the sync. Therefore when the + * sync (roundtrip) returns, we are guaranteed to have received and + * processed all the global events. + * + * While we are inside the first wl_display_roundtrip(), incoming + * events are dispatched, which causes registry_handle_global() to + * be called for each global. One of these globals is wl_shm. + * registry_handle_global() sends wl_registry.bind request for the + * wl_shm global. However, wl_registry.bind request is sent after + * the first wl_display.sync, so the reply to the sync comes before + * the initial events of the wl_shm object. + * + * The initial events that get sent as a reply to binding to wl_shm + * include wl_shm.format. These tell us which pixel formats are + * supported, and we need them before we can create buffers. They + * don't change at runtime, so we receive them as part of init. + * + * When the reply to the first sync comes, the server may or may not + * have sent the initial wl_shm events. Therefore we need the second + * wl_display_roundtrip() call here. + * + * The server processes the wl_registry.bind for wl_shm first, and + * the second wl_display.sync next. During our second call to + * wl_display_roundtrip() the initial wl_shm events are received and + * processed. Finally, when the reply to the second wl_display.sync + * arrives, it guarantees we have processed all wl_shm initial events. + * + * This sequence contains two examples on how wl_display_roundtrip() + * can be used to guarantee, that all reply events to a request + * have been received and processed. This is a general Wayland + * technique. + */ + + if (!display->has_xrgb) { + fprintf(stderr, "WL_SHM_FORMAT_XRGB32 not available\n"); + exit(1); + } + + display->wl_tbm = wayland_tbm_client_init(display->display); + if (!display->wl_tbm) { + fprintf(stderr, "failed wayland_tbm_client_init()\n"); + exit(1); + } + + display->notified = -1; + + return display; +} + +static void +destroy_display(struct display *display) +{ + text_entry_destroy(display); + + if (display->text_input_mgr) + wl_text_input_manager_destroy(display->text_input_mgr); + + if (display->seat) + wl_seat_destroy(display->seat); + + if (display->shm) + wl_shm_destroy(display->shm); + + if (display->wm_base) + xdg_wm_base_destroy(display->wm_base); + + if (display->compositor) + wl_compositor_destroy(display->compositor); + + wayland_tbm_client_deinit(display->wl_tbm); + wl_registry_destroy(display->registry); + wl_display_flush(display->display); + wl_display_disconnect(display->display); + free(display); +} + +static void +signal_int(int signum) +{ + running = 0; +} + +int +main(int argc, char **argv) +{ + struct sigaction sigint; + struct display *display; + struct window *window; + int ret = 0; + + display = create_display(); + window = create_window(display, 250, 250); + if (!window) + return 1; + + sigint.sa_handler = signal_int; + sigemptyset(&sigint.sa_mask); + sigint.sa_flags = SA_RESETHAND; + sigaction(SIGINT, &sigint, NULL); + + /* Initialise damage to full surface, so the padding gets painted */ + wl_surface_damage(window->surface, 0, 0, + window->width, window->height); + + if (!window->wait_for_configure) + redraw(window, NULL, 0); + + while (running && ret != -1) + ret = wl_display_dispatch(display->display); + + fprintf(stderr, "simple-shm exiting\n"); + + destroy_window(window); + destroy_display(display); + + return 0; +} diff --git a/examples/meson.build b/examples/meson.build index 899529e..2d5c09c 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -31,6 +31,8 @@ executable('tinyds-tdm', deps_libds_tizen_dpms, deps_libds_tizen_input_devicemgr, deps_libds_tizen_launch, + deps_libds_tizen_input_method, + deps_libds_tizen_text_input, dependency('pixman-1', required: true), dependency('threads', required: true), ], diff --git a/examples/tinyds-tdm.c b/examples/tinyds-tdm.c index a7428f1..56d9412 100644 --- a/examples/tinyds-tdm.c +++ b/examples/tinyds-tdm.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #define USE_TDM_BUFFER_QUEUE @@ -118,6 +120,9 @@ struct tinyds_server struct wl_list keyboards; struct wl_list pointers; + + struct tinyds_text_input *text_input; + struct tinyds_input_method *input_method; }; struct tinyds_view @@ -177,6 +182,69 @@ struct tinyds_touch struct wl_listener motion; }; +struct tinyds_text_input { + struct ds_tizen_text_input *input; + struct ds_tizen_text_input_manager *text_input_mgr; + + struct tinyds_server *server; + struct ds_surface *surface; + + struct wl_list input_methods; + + struct wl_listener destroy; + struct wl_listener mgr_destroy; + + struct wl_listener new_text_input; + + struct wl_listener text_input_activate; + struct wl_listener text_input_deactivate; + struct wl_listener text_input_reset; + struct wl_listener text_input_set_content_type; + struct wl_listener text_input_invoke_action; + struct wl_listener text_input_commit_state; + struct wl_listener text_input_set_preferred_language; +}; + +struct tinyds_input_method { + struct ds_tizen_input_method *input_method; + struct ds_tizen_input_method_manager *input_method_mgr; + + struct tinyds_server *server; + struct tinyds_text_input *input; + struct tinyds_input_method_context *context; + + struct wl_list link; + + struct wl_listener destroy; + struct wl_listener mgr_destroy; + + struct wl_listener new_im_context; +}; + +struct tinyds_input_method_context { + struct ds_tizen_input_method_context *context; + + struct tinyds_server *server; + struct tinyds_text_input *input; + struct tinyds_input_method *input_method; + + struct wl_listener destroy; + + struct wl_listener im_context_commit_string; + struct wl_listener im_context_preedit_string; + struct wl_listener im_context_preedit_styling; + struct wl_listener im_context_preedit_cursor; + struct wl_listener im_context_delete_surrounding_text; + struct wl_listener im_context_cursor_position; + struct wl_listener im_context_modifiers_map; + struct wl_listener im_context_keysym; + struct wl_listener im_context_grab_keyboard; + struct wl_listener im_context_key; + struct wl_listener im_context_modifiers; + struct wl_listener im_context_language; + struct wl_listener im_context_text_direction; +}; + struct tinyds_server tinyds; static bool init_server(struct tinyds_server *server, struct wl_display *display); @@ -215,6 +283,22 @@ static struct tinyds_view * server_view_at(struct tinyds_server *server, double lx, double ly, double *sx, double *sy); +static bool add_new_text_input(struct tinyds_server *server); +static bool add_new_input_method(struct tinyds_server *server); + +static void text_input_mgr_handle_destroy(struct wl_listener *listener, + void *data TINYDS_UNUSED); +static void text_input_mgr_handle_new_text_input(struct wl_listener *listener, + void *data TINYDS_UNUSED); + +static void input_method_mgr_handle_destroy(struct wl_listener *listener, + void *data TINYDS_UNUSED); + +static void input_method_handle_destroy(struct wl_listener *listener, + void *data TINYDS_UNUSED); +static void input_method_handle_new_im_context(struct wl_listener *listener, + void *data TINYDS_UNUSED); + int main(void) { @@ -820,6 +904,12 @@ init_server(struct tinyds_server *server, struct wl_display *display) ds_tizen_launch_effect_add_new_splash_listener(server->effect, &server->new_splash); + if (!add_new_text_input(server)) + goto err; + + if (!add_new_input_method(server)) + goto err; + return true; err: @@ -1717,7 +1807,6 @@ server_add_pointer(struct tinyds_server *server, struct ds_input_device *dev) ds_inf("Pointer(%p) added", pointer); } - static void output_schedule_commit_handle_idle_timer(void *data) { @@ -1737,3 +1826,655 @@ output_schedule_commit(struct tinyds_output *output) output->idle_commit = wl_event_loop_add_idle(ev, output_schedule_commit_handle_idle_timer, output); } + +static bool +add_new_text_input(struct tinyds_server *server) +{ + struct tinyds_text_input *text_input; + + text_input = calloc(1, sizeof *text_input); + if (!text_input) + return false; + + text_input->text_input_mgr = ds_tizen_text_input_manager_create(server->display); + if (!text_input->text_input_mgr) { + free(text_input); + ds_err("Could not create ds_tizen_text_input_manager"); + return false; + } + + wl_list_init(&text_input->input_methods); + + text_input->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->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, + &text_input->new_text_input); + + text_input->server = server; + server->text_input = text_input; + + ds_inf("Text_Input (%p) added", text_input); + + return true; +} + +static bool +add_new_input_method(struct tinyds_server *server) +{ + struct tinyds_input_method *input_method; + + input_method = calloc(1, sizeof *input_method); + if (!input_method) + return false; + + input_method->input_method = ds_tizen_input_method_create(server->display); + if (!input_method->input_method) { + free(input_method); + ds_err("Could not create ds_tizen_input_method"); + return false; + } + input_method->destroy.notify = input_method_handle_destroy; + ds_tizen_input_method_add_destroy_listener(input_method->input_method, + &input_method->destroy); + + input_method->input_method_mgr = ds_tizen_input_method_manager_create(server->display); + if (!input_method->input_method_mgr) { + free(input_method); + ds_err("Could not create ds_tizen_input_method_manager"); + return false; + } + + input_method->mgr_destroy.notify = input_method_mgr_handle_destroy; + ds_tizen_input_method_manager_add_destroy_listener(input_method->input_method_mgr, + &input_method->mgr_destroy); + + input_method->new_im_context.notify = input_method_handle_new_im_context; + ds_tizen_input_method_add_new_input_method_context_listener(input_method->input_method, + &input_method->new_im_context); + + input_method->server = server; + server->input_method = input_method; + + ds_inf("Input_Method (%p) added", input_method); + + return true; +} + +static void +text_input_mgr_handle_destroy(struct wl_listener *listener, void *data) +{ + struct tinyds_text_input *text_input; + struct tinyds_server *server; + + ds_inf("text_input_mgr_handle_destroy"); + 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 +text_input_handle_destroy(struct wl_listener *listener, void *data) +{ + struct tinyds_text_input *text_input; + + ds_inf("text_input_handle_destroy"); + + text_input = wl_container_of(listener, text_input, destroy); + + wl_list_remove(&text_input->destroy.link); +} + +static void +text_input_handle_activate(struct wl_listener *listener, void *data) +{ + struct tinyds_text_input *text_input; + struct tinyds_input_method *input_method; + struct tinyds_input_method_context *context; + struct ds_tizen_text_input_event_activate *event = data; + + text_input = wl_container_of(listener, text_input, text_input_activate); + + input_method = text_input->server->input_method; + + ds_inf("text_input_handle_activate. text_input(%p) seat(%p) surface(%p) text_input(%p)", + text_input, event->seat, event->surface, event->text_input); + + if (input_method->input == text_input) + return; + if (input_method->input) + ;//deactivate_input_method(server->input_method); + input_method->input = text_input; + wl_list_insert(&text_input->input_methods, &input_method->link); + + text_input->surface = event->surface; + + context = calloc(1, sizeof *context); + if (context == NULL) + { + ds_err("calloc is failed. tinyds_input_method_context"); + return; + } + input_method->context = context; + context->server = text_input->server; + context->context = ds_tizen_input_method_create_context(input_method->input_method); + context->input = text_input; + context->input_method = input_method; + + // ds_tizen_input_method_send_set_text_input_id(); +} + +static void +text_input_handle_deactivate(struct wl_listener *listener, void *data) +{ + struct tinyds_text_input *text_input; + struct tinyds_input_method *input_method, *tmp; + struct ds_tizen_text_input_event_deactivate *event = data; + + text_input = wl_container_of(listener, text_input, text_input_deactivate); + ds_inf("text_input_handle_deactivate. text_input(%p) seat(%p) text_input(%p)", + text_input, event->seat, event->text_input); + + wl_list_for_each_safe(input_method, tmp, &text_input->input_methods, link) { + if (!input_method->input_method || !input_method->context->context) continue; + ds_tizen_input_method_send_deactivate(input_method->input_method, input_method->context->context); + input_method->input = NULL; + input_method->context = NULL; + wl_list_remove(&input_method->link); + } + + text_input->surface = NULL; + // ds_tizen_input_method_send_close_connection(); +} + +static void +text_input_handle_reset(struct wl_listener *listener, void *data) +{ + struct tinyds_text_input *text_input; + struct tinyds_input_method *input_method; + + text_input = wl_container_of(listener, text_input, text_input_reset); + + ds_inf("text_input_handle_reset. text_input(%p)", text_input); + + wl_list_for_each(input_method, &text_input->input_methods, link) { + if (!input_method->context || !input_method->context->context) continue; + ds_tizen_input_method_context_send_reset(input_method->context->context); + } +} + +static void +text_input_handle_set_content_type(struct wl_listener *listener, void *data) +{ + struct tinyds_text_input *text_input; + struct ds_tizen_text_input_event_set_content_type *event = data; + struct tinyds_input_method *input_method; + + text_input = wl_container_of(listener, text_input, text_input_set_content_type); + + ds_inf("text_input_handle_content_type. text_input(%p) hint(%u) purpose(%u)", + text_input, event->hint, event->purpose); + + wl_list_for_each(input_method, &text_input->input_methods, link) { + if (!input_method->context || !input_method->context->context) continue; + ds_tizen_input_method_context_send_content_type(input_method->context->context, + event->hint, event->purpose); + } +} + +static void +text_input_handle_invoke_action(struct wl_listener *listener, void *data) +{ + struct tinyds_text_input *text_input; + struct ds_tizen_text_input_event_invoke_action *event = data; + struct tinyds_input_method *input_method; + + text_input = wl_container_of(listener, text_input, text_input_invoke_action); + + ds_inf("text_input_handle_invoke_action. text_input(%p) button(%u) index(%u)", + text_input, event->button, event->index); + + wl_list_for_each(input_method, &text_input->input_methods, link) { + if (!input_method->context || !input_method->context->context) continue; + ds_tizen_input_method_context_send_invoke_action(input_method->context->context, + event->button, event->index); + } +} + +static void +text_input_handle_commit_state(struct wl_listener *listener, void *data) +{ + struct tinyds_text_input *text_input; + struct ds_tizen_text_input_event_commit_state *event = data; + struct tinyds_input_method *input_method; + + text_input = wl_container_of(listener, text_input, text_input_commit_state); + + ds_inf("text_input_handle_commit_state. text_input(%p) serial(%u)", + text_input, event->serial); + + wl_list_for_each(input_method, &text_input->input_methods, link) { + if (!input_method->context || !input_method->context->context) continue; + ds_tizen_input_method_context_send_commit_state(input_method->context->context, + event->serial); + } +} + +static void +text_input_handle_set_preferred_language(struct wl_listener *listener, void *data) +{ + struct tinyds_text_input *text_input; + struct ds_tizen_text_input_event_set_preferred_language *event = data; + struct tinyds_input_method *input_method; + + text_input = wl_container_of(listener, text_input, text_input_set_preferred_language); + + ds_inf("text_input_handle_set_preferred_language. text_input(%p) language(%s)", + text_input, event->language); + + wl_list_for_each(input_method, &text_input->input_methods, link) { + if (!input_method->context || !input_method->context->context) continue; + ds_tizen_input_method_context_send_preferred_language(input_method->context->context, + event->language); + } +} + +static void +text_input_mgr_handle_new_text_input(struct wl_listener *listener, void *data) +{ + struct tinyds_text_input *text_input; + struct ds_tizen_text_input *input = data; + + text_input = wl_container_of(listener, text_input, new_text_input); + + ds_inf("text_input_mgr_handle_new_text_input"); + + text_input->input = input; + + text_input->destroy.notify = text_input_handle_destroy; + ds_tizen_text_input_add_destroy_listener(text_input->input, + &text_input->destroy); + + text_input->text_input_activate.notify = text_input_handle_activate; + ds_tizen_text_input_add_activate_listener(text_input->input, + &text_input->text_input_activate); + + text_input->text_input_deactivate.notify = text_input_handle_deactivate; + ds_tizen_text_input_add_deactivate_listener(text_input->input, + &text_input->text_input_deactivate); + + text_input->text_input_reset.notify = text_input_handle_reset; + ds_tizen_text_input_add_reset_listener(text_input->input, + &text_input->text_input_reset); + + text_input->text_input_set_content_type.notify = text_input_handle_set_content_type; + ds_tizen_text_input_add_set_content_type_listener(text_input->input, + &text_input->text_input_set_content_type); + + text_input->text_input_invoke_action.notify = text_input_handle_invoke_action; + ds_tizen_text_input_add_invoke_action_listener(text_input->input, + &text_input->text_input_invoke_action); + + text_input->text_input_commit_state.notify = text_input_handle_commit_state; + ds_tizen_text_input_add_commit_state_listener(text_input->input, + &text_input->text_input_commit_state); + + text_input->text_input_set_preferred_language.notify = text_input_handle_set_preferred_language; + ds_tizen_text_input_add_set_preferred_language_listener(text_input->input, + &text_input->text_input_set_preferred_language); +} + +static void +input_method_mgr_handle_destroy(struct wl_listener *listener, void *data) +{ + struct tinyds_input_method *input_method; + + ds_inf("input_method_mgr_handle_destroy"); + + input_method = wl_container_of(listener, input_method, mgr_destroy); + + wl_list_remove(&input_method->mgr_destroy.link); +} + +static void +input_method_handle_destroy(struct wl_listener *listener, void *data) +{ + struct tinyds_input_method *input_method; + struct tinyds_server *server; + + ds_inf("input_method_handle_destroy"); + + input_method = wl_container_of(listener, input_method, destroy); + + wl_list_remove(&input_method->destroy.link); + wl_list_remove(&input_method->new_im_context.link); + + server = input_method->server; + server->input_method = NULL; + + free(input_method); +} + +static void +context_handle_destroy(struct wl_listener *listener, void *data) +{ + struct tinyds_input_method_context *context; + struct tinyds_server *server; + + ds_inf("context_handle_destroy"); + + context = wl_container_of(listener, context, destroy); + + wl_list_remove(&context->destroy.link); + + wl_list_remove(&context->im_context_commit_string.link); + wl_list_remove(&context->im_context_preedit_string.link); + wl_list_remove(&context->im_context_preedit_styling.link); + wl_list_remove(&context->im_context_preedit_cursor.link); + wl_list_remove(&context->im_context_delete_surrounding_text.link); + wl_list_remove(&context->im_context_cursor_position.link); + wl_list_remove(&context->im_context_modifiers_map.link); + wl_list_remove(&context->im_context_keysym.link); + wl_list_remove(&context->im_context_grab_keyboard.link); + wl_list_remove(&context->im_context_key.link); + wl_list_remove(&context->im_context_modifiers.link); + wl_list_remove(&context->im_context_language.link); + wl_list_remove(&context->im_context_text_direction.link); + + server = context->server; + server->input_method->context = NULL; + + free(context); +} + +static void +context_handle_commit_string(struct wl_listener *listener, void *data) +{ + struct tinyds_text_input *text_input; + struct tinyds_input_method_context *context; + struct ds_tizen_input_method_context_event_commit_string *event = data; + + context = wl_container_of(listener, context, im_context_commit_string); + text_input = context->server->text_input; + + ds_inf("context_handle_commit_string. text_input(%p) serial(%u) text(%s)", + text_input, event->serial, event->text); + + ds_tizen_text_input_send_commit_string(text_input->input, event->serial, event->text); +} + +static void +context_handle_preedit_string(struct wl_listener *listener, void *data) +{ + struct tinyds_input_method_context *context; + struct tinyds_text_input *text_input; + struct ds_tizen_input_method_context_event_preedit_string *event = data; + + context = wl_container_of(listener, context, im_context_preedit_string); + text_input = context->server->text_input; + + ds_inf("context_handle_preedit_string. text_input(%p) serial(%u) text(%s) commit(%s)", + text_input, event->serial, event->text, event->commit); + + ds_tizen_text_input_send_preedit_string(text_input->input, event->serial, event->text, event->commit); +} + +static void +context_handle_preedit_styling(struct wl_listener *listener, void *data) +{ + struct tinyds_input_method_context *context; + struct tinyds_text_input *text_input; + struct ds_tizen_input_method_context_event_preedit_styling *event = data; + + context = wl_container_of(listener, context, im_context_preedit_styling); + text_input = context->server->text_input; + + ds_inf("context_handle_preedit_styling. text_input(%p) index(%u) length(%u) style(%u)", + text_input, event->index, event->length, event->style); + + ds_tizen_text_input_send_preedit_styling(text_input->input, event->index, event->length, event->style); +} + +static void +context_handle_preedit_cursor(struct wl_listener *listener, void *data) +{ + struct tinyds_input_method_context *context; + struct tinyds_text_input *text_input; + struct ds_tizen_input_method_context_event_preedit_cursor *event = data; + + context = wl_container_of(listener, context, im_context_preedit_cursor); + text_input = context->server->text_input; + + ds_inf("context_handle_preedit_cursor. text_input(%p) index(%u)", + text_input, event->index); + + ds_tizen_text_input_send_preedit_cursor(text_input->input, event->index); +} + +static void +context_handle_delete_surrounding_text(struct wl_listener *listener, void *data) +{ + struct tinyds_input_method_context *context; + struct tinyds_text_input *text_input; + struct ds_tizen_input_method_context_event_delete_surrounding_text *event = data; + + context = wl_container_of(listener, context, im_context_delete_surrounding_text); + text_input = context->server->text_input; + + ds_inf("context_handle_delete_surrounding_text. text_input(%p) index(%d) length(%u)", + text_input, event->index, event->length); + + ds_tizen_text_input_send_delete_surrounding_text(text_input->input, event->index, event->length); +} + +static void +context_handle_cursor_position(struct wl_listener *listener, void *data) +{ + struct tinyds_input_method_context *context; + struct tinyds_text_input *text_input; + struct ds_tizen_input_method_context_event_cursor_position *event = data; + + context = wl_container_of(listener, context, im_context_cursor_position); + text_input = context->server->text_input; + + ds_inf("context_handle_cursor_position. text_input(%p) index(%d) length(%d)", + text_input, event->index, event->anchor); + + ds_tizen_text_input_send_cursor_position(text_input->input, event->index, event->anchor); +} + +static void +context_handle_modifiers_map(struct wl_listener *listener, void *data) +{ + struct tinyds_input_method_context *context; + struct tinyds_text_input *text_input; + struct ds_tizen_input_method_context_event_modifiers_map *event = data; + + context = wl_container_of(listener, context, im_context_modifiers_map); + text_input = context->server->text_input; + + ds_inf("context_handle_modifiers_map. text_input(%p) map(%p)", + text_input, event->map); + + ds_tizen_text_input_send_modifiers_map(text_input->input, event->map); +} + +static void +context_handle_keysym(struct wl_listener *listener, void *data) +{ + struct tinyds_input_method_context *context; + struct tinyds_text_input *text_input; + struct ds_tizen_input_method_context_event_keysym *event = data; + + context = wl_container_of(listener, context, im_context_keysym); + text_input = context->server->text_input; + + ds_inf("context_handle_keysym. text_input(%p) serial(%u) time(%u) sysm(%u) state(%u) modifiers(%u)", + text_input, event->serial, event->time, event->sym, event->state, event->modifiers); + + ds_tizen_text_input_send_keysym(text_input->input, event->serial, event->time, event->sym, event->state, event->modifiers); +} + +static void +context_handle_grab_keyboard(struct wl_listener *listener, void *data) +{ + struct tinyds_input_method_context *context; + struct tinyds_text_input *text_input; + + context = wl_container_of(listener, context, im_context_grab_keyboard); + text_input = context->server->text_input; + + ds_inf("context_handle_grab_keyboard. text_input(%p)", + text_input); + + //TODO +} + +static void +context_handle_key(struct wl_listener *listener, void *data) +{ + struct tinyds_input_method_context *context; + struct tinyds_text_input *text_input; + + context = wl_container_of(listener, context, im_context_key); + text_input = context->server->text_input; + + ds_inf("context_handle_key. text_input(%p)", + text_input); + + //TODO +} + +static void +context_handle_modifiers(struct wl_listener *listener, void *data) +{ + struct tinyds_input_method_context *context; + struct tinyds_text_input *text_input; + + context = wl_container_of(listener, context, im_context_modifiers); + text_input = context->server->text_input; + + ds_inf("context_handle_modifiers. text_input(%p)", + text_input); + + //TODO +} + +static void +context_handle_language(struct wl_listener *listener, void *data) +{ + struct tinyds_input_method_context *context; + struct tinyds_text_input *text_input; + struct ds_tizen_input_method_context_event_language *event = data; + + context = wl_container_of(listener, context, im_context_language); + text_input = context->server->text_input; + + ds_inf("context_handle_language. text_input(%p) serial(%u), language(%s)", + text_input, event->serial, event->language); + + ds_tizen_text_input_send_language(text_input->input, event->serial, event->language); +} + +static void +context_handle_text_direction(struct wl_listener *listener, void *data) +{ + struct tinyds_input_method_context *context; + struct tinyds_text_input *text_input; + struct ds_tizen_input_method_context_event_text_direction *event = data; + + context = wl_container_of(listener, context, im_context_text_direction); + text_input = context->server->text_input; + + ds_inf("context_handle_text_direction. text_input(%p) serial(%u), direction(%u)", + text_input, event->serial, event->direction); + + ds_tizen_text_input_send_text_direction(text_input->input, event->serial, event->direction); +} + +static void +input_method_handle_new_im_context(struct wl_listener *listener, void *data) +{ + struct ds_tizen_input_method_context *context = data; + struct tinyds_input_method *input_method; + struct tinyds_input_method_context *ctx; + + ds_inf("input_method_handle_new_im_context"); + + input_method = wl_container_of(listener, input_method, new_im_context); + ctx = input_method->context; + + ctx->destroy.notify = context_handle_destroy; + ds_tizen_input_method_context_add_destroy_listener(context, + &ctx->destroy); + + ctx->im_context_commit_string.notify = context_handle_commit_string; + ds_tizen_input_method_context_add_commit_string_listener(context, + &ctx->im_context_commit_string); + + ctx->im_context_preedit_string.notify = context_handle_preedit_string; + ds_tizen_input_method_context_add_preedit_string_listener(context, + &ctx->im_context_preedit_string); + + ctx->im_context_preedit_styling.notify = context_handle_preedit_styling; + ds_tizen_input_method_context_add_preedit_styling_listener(context, + &ctx->im_context_preedit_styling); + + ctx->im_context_preedit_cursor.notify = context_handle_preedit_cursor; + ds_tizen_input_method_context_add_preedit_cursor_listener(context, + &ctx->im_context_preedit_cursor); + + ctx->im_context_delete_surrounding_text.notify = context_handle_delete_surrounding_text; + ds_tizen_input_method_context_add_delete_surrounding_text_listener(context, + &ctx->im_context_delete_surrounding_text); + + ctx->im_context_cursor_position.notify = context_handle_cursor_position; + ds_tizen_input_method_context_add_cursor_position_listener(context, + &ctx->im_context_cursor_position); + + ctx->im_context_modifiers_map.notify = context_handle_modifiers_map; + ds_tizen_input_method_context_add_modifiers_map_listener(context, + &ctx->im_context_modifiers_map); + + ctx->im_context_keysym.notify = context_handle_keysym; + ds_tizen_input_method_context_add_keysym_listener(context, + &ctx->im_context_keysym); + + ctx->im_context_grab_keyboard.notify = context_handle_grab_keyboard; + ds_tizen_input_method_context_add_grab_keyboard_listener(context, + &ctx->im_context_grab_keyboard); + + ctx->im_context_key.notify = context_handle_key; + ds_tizen_input_method_context_add_key_listener(context, + &ctx->im_context_key); + + ctx->im_context_modifiers.notify = context_handle_modifiers; + ds_tizen_input_method_context_add_modifiers_listener(context, + &ctx->im_context_modifiers); + + ctx->im_context_language.notify = context_handle_language; + ds_tizen_input_method_context_add_language_listener(context, + &ctx->im_context_language); + + ctx->im_context_text_direction.notify = context_handle_text_direction; + ds_tizen_input_method_context_add_text_direction_listener(context, + &ctx->im_context_text_direction); +} diff --git a/packaging/libds-tizen.spec b/packaging/libds-tizen.spec index f392041..fc126c7 100644 --- a/packaging/libds-tizen.spec +++ b/packaging/libds-tizen.spec @@ -553,6 +553,7 @@ ninja -C builddir install %{_libdir}/pkgconfig/libds-tizen-text-input.pc %{_libdir}/libds-tizen-text-input.so %{_bindir}/libds-tizen-text-input-tests +%{_bindir}/text-entry %files input-method %manifest %{name}.manifest @@ -569,3 +570,4 @@ ninja -C builddir install %{_libdir}/libds-tizen-input-method.so %{_bindir}/libds-tizen-input-method-tests %{_bindir}/libds-tizen-input-method-manager-tests +%{_bindir}/ime-keyboard -- 2.7.4 From 6b623314a75861b6695c577dc2462ad98e711b43 Mon Sep 17 00:00:00 2001 From: "duna.oh" Date: Tue, 23 Aug 2022 18:19:37 +0900 Subject: [PATCH 05/16] input_method: add object pointer member in event struct Change-Id: I5002a7b4e42c5c6a7bb5b47dcf92500a0b22dcdf --- include/libds-tizen/input_method.h | 15 +++++++++++++++ src/input_method/input_method.c | 13 ++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/include/libds-tizen/input_method.h b/include/libds-tizen/input_method.h index 731b889..2209026 100644 --- a/include/libds-tizen/input_method.h +++ b/include/libds-tizen/input_method.h @@ -8,62 +8,77 @@ extern "C" { #endif +struct ds_tizen_input_method_manager; +struct ds_tizen_input_method_context; +struct ds_tizen_input_method; + struct ds_tizen_input_method_manager_event_set_transient_for { + struct ds_tizen_input_method_manager *im_mgr; uint32_t pid_parent, pid_child; }; struct ds_tizen_input_method_context_event_commit_string { + struct ds_tizen_input_method_context *im_context; uint32_t serial; const char *text; }; struct ds_tizen_input_method_context_event_preedit_string { + struct ds_tizen_input_method_context *im_context; uint32_t serial; const char *text, *commit; }; struct ds_tizen_input_method_context_event_preedit_styling { + struct ds_tizen_input_method_context *im_context; uint32_t index, length, style; }; struct ds_tizen_input_method_context_event_preedit_cursor { + struct ds_tizen_input_method_context *im_context; int32_t index; }; struct ds_tizen_input_method_context_event_delete_surrounding_text { + struct ds_tizen_input_method_context *im_context; int32_t index; uint32_t length; }; struct ds_tizen_input_method_context_event_cursor_position { + struct ds_tizen_input_method_context *im_context; int32_t index, anchor; }; struct ds_tizen_input_method_context_event_modifiers_map { + struct ds_tizen_input_method_context *im_context; struct wl_array *map; }; struct ds_tizen_input_method_context_event_keysym { + struct ds_tizen_input_method_context *im_context; uint32_t serial, time, sym, state, modifiers; }; struct ds_tizen_input_method_context_event_language { + struct ds_tizen_input_method_context *im_context; uint32_t serial; const char *language; }; struct ds_tizen_input_method_context_event_text_direction { + struct ds_tizen_input_method_context *im_context; uint32_t serial, direction; }; diff --git a/src/input_method/input_method.c b/src/input_method/input_method.c index 2293272..eb6232b 100644 --- a/src/input_method/input_method.c +++ b/src/input_method/input_method.c @@ -103,6 +103,7 @@ input_method_mgr_handle_set_transient_for(struct wl_client *wl_client, ds_inf("input_method_mgr_handle_set_transient_for() parent:%u, child:%u", parent_pid, child_pid); + ds_event.im_mgr = input_method_mgr; ds_event.pid_parent = parent_pid; ds_event.pid_child = child_pid; wl_signal_emit(&input_method_mgr->events.set_transient_for, &ds_event); @@ -218,7 +219,7 @@ 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; @@ -443,6 +444,7 @@ context_handle_commit_string(struct wl_client *client, struct ds_tizen_input_method_context_event_commit_string ds_event; ds_inf("context_handle_commit_string"); + ds_event.im_context = context; ds_event.serial = serial; ds_event.text = text; @@ -460,6 +462,7 @@ context_handle_preedit_string(struct wl_client *client, ds_inf("context_handle_preedit_string() serial:%u, text:%s, commit:%s", serial, text, commit); + ds_event.im_context = context; ds_event.serial = serial; ds_event.text = text; ds_event.commit = commit; @@ -478,6 +481,7 @@ context_handle_preedit_styling(struct wl_client *client, ds_inf("context_handle_preedit_styling() index:%u, length:%u, style:%u", index, length, style); + ds_event.im_context = context; ds_event.index = index; ds_event.length = length; ds_event.style = style; @@ -494,6 +498,7 @@ context_handle_preedit_cursor(struct wl_client *client, ds_inf("context_handle_preedit_cursor() cursor:%d", index); + ds_event.im_context = context; ds_event.index = index; wl_signal_emit(&context->events.preedit_styling, &ds_event); } @@ -507,6 +512,7 @@ context_handle_delete_surrounding_text(struct wl_client *client, ds_inf("context_handle_delete_surrounding_text() index:%d, length:%u", index, length); + ds_event.im_context = context; ds_event.index = index; ds_event.length = length; wl_signal_emit(&context->events.delete_surrounding_text, &ds_event); @@ -521,6 +527,7 @@ context_handle_cursor_position(struct wl_client *client, ds_inf("context_handle_cursor_position() index:%d anchor:%d", index, anchor); + ds_event.im_context = context; ds_event.index = index; ds_event.anchor = anchor; wl_signal_emit(&context->events.cursor_position, &ds_event); @@ -535,6 +542,7 @@ context_handle_modifiers_map(struct wl_client *client, ds_inf("context_handle_modifiers_map() map(%p)", map); + ds_event.im_context = context; ds_event.map = map; wl_signal_emit(&context->events.modifiers_map, &ds_event); } @@ -550,6 +558,7 @@ context_handle_keysym(struct wl_client *client, struct wl_resource *resource, ds_inf("context_handle_keysym() serial(%u), time(%u), sym(%u), state(%u), modifiers(%u)", serial, time, sym, state, modifiers); + ds_event.im_context = context; ds_event.serial = serial; ds_event.time = time; ds_event.sym = sym; @@ -592,6 +601,7 @@ context_handle_language(struct wl_client *client, ds_inf("context_handle_language() serial(%u) language(%s)", serial, language); + ds_event.im_context = context; ds_event.serial = serial; ds_event.language = language; wl_signal_emit(&context->events.language, &ds_event); @@ -606,6 +616,7 @@ context_handle_text_direction(struct wl_client *client, ds_inf("context_handle_text_direction() serial(%u) direction(%u)", serial, direction); + ds_event.im_context = context; ds_event.serial = serial; ds_event.direction = direction; wl_signal_emit(&context->events.text_direction, &ds_event); -- 2.7.4 From c6b878a8afb44527c778f518c2da7349dfa33078 Mon Sep 17 00:00:00 2001 From: "duna.oh" Date: Wed, 24 Aug 2022 10:12:38 +0900 Subject: [PATCH 06/16] clients: 'text-entry' fix formatting Change-Id: I5f175968d063363be2cb6343d92ea3e27ce6b60f --- clients/text-entry.c | 300 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 242 insertions(+), 58 deletions(-) diff --git a/clients/text-entry.c b/clients/text-entry.c index a806f0e..ce21d02 100644 --- a/clients/text-entry.c +++ b/clients/text-entry.c @@ -51,7 +51,7 @@ struct display { struct xdg_wm_base *wm_base; struct wl_shm *shm; struct wl_seat *seat; - struct wayland_tbm_client *wl_tbm; + struct wayland_tbm_client *wl_tbm; bool has_xrgb; struct wl_text_input_manager *text_input_mgr; @@ -69,13 +69,13 @@ struct window { struct xdg_surface *xdg_surface; struct xdg_toplevel *xdg_toplevel; struct wl_callback *callback; - tbm_surface_queue_h surface_queue; + tbm_surface_queue_h surface_queue; bool wait_for_configure; }; struct buffer_info { - struct window *window; - struct wl_buffer *wl_buffer; + struct window *window; + struct wl_buffer *wl_buffer; }; struct text_entry { @@ -580,19 +580,19 @@ text_entry_update(struct text_entry *entry) fprintf(stderr, "text_entry_update()\n"); wl_text_input_set_content_type(entry->text_input, - WL_TEXT_INPUT_CONTENT_HINT_NONE, - entry->content_purpose); + WL_TEXT_INPUT_CONTENT_HINT_NONE, + entry->content_purpose); if (entry->preferred_language) wl_text_input_set_preferred_language(entry->text_input, - entry->preferred_language); + entry->preferred_language); text_entry_get_cursor_rectangle(entry, &cursor_rectangle); wl_text_input_set_cursor_rectangle(entry->text_input, - cursor_rectangle.x, - cursor_rectangle.y, - cursor_rectangle.width, - cursor_rectangle.height); + cursor_rectangle.x, + cursor_rectangle.y, + cursor_rectangle.width, + cursor_rectangle.height); wl_text_input_commit_state(entry->text_input, ++entry->serial); } @@ -600,7 +600,7 @@ text_entry_update(struct text_entry *entry) static void text_entry_reset_preedit(struct text_entry *entry) { - fprintf(stderr, "text_entry_reset_preedit()\n"); + fprintf(stderr, "text_entry_reset_preedit()\n"); entry->preedit.cursor = 0; free(entry->preedit.text); @@ -664,9 +664,9 @@ text_entry_commit_and_reset(struct text_entry *entry) static void text_input_enter(void *data, struct wl_text_input *text_input, - struct wl_surface *surface) + struct wl_surface *surface) { - fprintf(stderr, "text_input_enter()\n"); + fprintf(stderr, "text_input_enter()\n"); struct display *d = data; struct text_entry *entry = d->entry; @@ -676,15 +676,16 @@ text_input_enter(void *data, struct wl_text_input *text_input, text_entry_update(entry); entry->reset_serial = entry->serial; } + static void text_input_leave(void *data, struct wl_text_input *text_input) { - fprintf(stderr, "text_input_leave()\n"); + fprintf(stderr, "text_input_leave()\n"); struct display *d = data; struct text_entry *entry = d->entry; - text_entry_commit_and_reset(entry); + text_entry_commit_and_reset(entry); d->entry->active--; if (!entry->active) { @@ -695,81 +696,264 @@ text_input_leave(void *data, struct wl_text_input *text_input) static void text_input_modifiers_map(void *data, struct wl_text_input *text_input, - struct wl_array *map) + struct wl_array *map) { - fprintf(stderr, "text_input_modifiers_map()\n"); + fprintf(stderr, "text_input_modifiers_map()\n"); } static void text_input_input_panel_state(void *data, struct wl_text_input *text_input, - uint32_t state) + uint32_t state) +{ + fprintf(stderr, "text_input_input_panel_state() state:%u\n", state); +} + +static void +clear_pending_preedit(struct text_entry *entry) +{ + fprintf(stderr, "clear_pending_preedit()\n"); + + memset(&entry->pending_commit, 0, sizeof entry->pending_commit); + + entry->preedit_info.cursor = 0; + + memset(&entry->preedit_info, 0, sizeof entry->preedit_info); +} + +static void +text_entry_delete_text(struct text_entry *entry, + uint32_t index, uint32_t length) +{ + uint32_t l; + + fprintf(stderr, "text_entry_delete_text()\n"); + + assert(index <= strlen(entry->text)); + assert(index + length <= strlen(entry->text)); + assert(index + length >= length); + + l = strlen(entry->text + index + length); + memmove(entry->text + index, + entry->text + index + length, + l + 1); + + if (entry->cursor > (index + length)) + entry->cursor -= length; + else if (entry->cursor > index) + entry->cursor = index; + + entry->anchor = entry->cursor; + + text_entry_update(entry); +} + +static void +text_entry_delete_selected_text(struct text_entry *entry) +{ + uint32_t start_index = entry->anchor < entry->cursor ? entry->anchor : entry->cursor; + uint32_t end_index = entry->anchor < entry->cursor ? entry->cursor : entry->anchor; + + fprintf(stderr, "text_entry_delete_selected_text()\n"); + + if (entry->anchor == entry->cursor) + return; + + text_entry_delete_text(entry, start_index, end_index - start_index); + + entry->anchor = entry->cursor; +} + +static void +text_entry_set_preedit(struct text_entry *entry, + const char *preedit_text, + int preedit_cursor) { - fprintf(stderr, "text_input_input_panel_state() state:%u\n", state); + fprintf(stderr, "text_entry_set_preedit()\n"); + + text_entry_reset_preedit(entry); + + if (!preedit_text) + return; + + entry->preedit.text = strdup(preedit_text); + entry->preedit.cursor = preedit_cursor; } static void text_input_preedit_string(void *data, struct wl_text_input *text_input, - uint32_t serial, const char *text, const char *commit) + uint32_t serial, const char *text, const char *commit) { - fprintf(stderr, "text_input_preedit_string() serial(%u), text(%s), commit(%s)\n", serial, text, commit); + struct display *d = data; + struct text_entry *entry = d->entry; + + fprintf(stderr, "text_input_preedit_string() serial(%u), text(%s), commit(%s)\n", serial, text, commit); + + if ((entry->serial - serial) > (entry->serial - entry->reset_serial)) { + fprintf(stderr, "Ignore preedit_string. Serial: %u, Current: %u, Reset: %u\n", + serial, entry->serial, entry->reset_serial); + clear_pending_preedit(entry); + return; + } + + if (entry->pending_commit.invalid_delete) { + fprintf(stderr, "Ignore preedit_string. Invalid previous delete_surrounding event.\n"); + clear_pending_preedit(entry); + return; + } + + if (entry->pending_commit.delete_length) { + text_entry_delete_text(entry, + entry->pending_commit.delete_index, + entry->pending_commit.delete_length); + } else { + text_entry_delete_selected_text(entry); + } + + text_entry_set_preedit(entry, text, entry->preedit_info.cursor); + entry->preedit.commit = strdup(commit); + + clear_pending_preedit(entry); + + text_entry_update(entry); } static void text_input_preedit_styling(void *data, struct wl_text_input *text_input, - uint32_t index, uint32_t length, uint32_t style) + uint32_t index, uint32_t length, uint32_t style) { - fprintf(stderr, "text_input_preedit_styling() index(%u), length(%u), style(%u)\n", index, length, style); + fprintf(stderr, "text_input_preedit_styling() index(%u), length(%u), style(%u)\n", index, length, style); + + switch (style) { + case WL_TEXT_INPUT_PREEDIT_STYLE_DEFAULT: + fprintf(stderr, "text_input_preedit_styling() style:DEFAULT"); + break; + case WL_TEXT_INPUT_PREEDIT_STYLE_UNDERLINE: + fprintf(stderr, "text_input_preedit_styling() style:UNDERLINE"); + break; + case WL_TEXT_INPUT_PREEDIT_STYLE_INCORRECT: + fprintf(stderr, "text_input_preedit_styling() style:INCORRECT"); + break; + case WL_TEXT_INPUT_PREEDIT_STYLE_SELECTION: + fprintf(stderr, "text_input_preedit_styling() style:SELECTION"); + break; + case WL_TEXT_INPUT_PREEDIT_STYLE_HIGHLIGHT: + fprintf(stderr, "text_input_preedit_styling() style:HIGHLIGHT"); + break; + case WL_TEXT_INPUT_PREEDIT_STYLE_ACTIVE: + fprintf(stderr, "text_input_preedit_styling() style:ACTIVE"); + break; + case WL_TEXT_INPUT_PREEDIT_STYLE_INACTIVE: + fprintf(stderr, "text_input_preedit_styling() style:INACTIVE"); + break; + default: + fprintf(stderr, "text_input_preedit_styling() no style enum found"); + break; + } } static void text_input_preedit_cursor(void *data, struct wl_text_input *text_input, - int32_t index) + int32_t index) { - fprintf(stderr, "text_input_preedit_cursor() index(%u)\n", index); + struct display *d = data; + struct text_entry *entry = d->entry; + + fprintf(stderr, "text_input_preedit_cursor() index(%u)\n", index); + + entry->preedit_info.cursor = index; } static void text_input_commit_string(void *data, struct wl_text_input *text_input, - uint32_t serial, const char *text) + uint32_t serial, const char *text) { - fprintf(stderr, "text_input_commit_string() serial(%u), text(%s)\n", serial, text); + struct display *d = data; + struct text_entry *entry = d->entry; + + fprintf(stderr, "text_input_commit_string() serial(%u), text(%s)\n", serial, text); + + if ((entry->serial - serial) > (entry->serial - entry->reset_serial)) { + fprintf(stderr, "Ignore commit. Serial: %u, Current: %u, Reset: %u\n", + serial, entry->serial, entry->reset_serial); + return; + } + + if (entry->pending_commit.invalid_delete) { + fprintf(stderr, "Ignore commit. Invalid previous delete_surrounding event.\n"); + memset(&entry->pending_commit, 0, sizeof entry->pending_commit); + return; + } + + text_entry_reset_preedit(entry); + + if (entry->pending_commit.delete_length) { + text_entry_delete_text(entry, + entry->pending_commit.delete_index, + entry->pending_commit.delete_length); + } else { + text_entry_delete_selected_text(entry); + } + + text_entry_insert_at_cursor(entry, text, + entry->pending_commit.cursor, + entry->pending_commit.anchor); + + memset(&entry->pending_commit, 0, sizeof entry->pending_commit); } static void text_input_cursor_position(void *data, struct wl_text_input *text_input, - int32_t index, int32_t anchor) + int32_t index, int32_t anchor) { - fprintf(stderr, "text_input_cursor_position() index(%d), anchor(%d)\n", index, anchor); + fprintf(stderr, "text_input_cursor_position() index(%d), anchor(%d)\n", index, anchor); } static void text_input_delete_surrounding_text(void *data, - struct wl_text_input *text_input, int32_t index, uint32_t length) + struct wl_text_input *text_input, int32_t index, uint32_t length) { - fprintf(stderr, "text_input_delete_surrounding_text() index(%d), length(%u)\n", index, length); + struct text_entry *entry = data; + uint32_t text_length; + + fprintf(stderr, "text_input_delete_surrounding_text() index(%d), length(%u)\n", index, length); + + entry->pending_commit.delete_index = entry->cursor + index; + entry->pending_commit.delete_length = length; + entry->pending_commit.invalid_delete = false; + + text_length = strlen(entry->text); + + if (entry->pending_commit.delete_index > text_length || + length > text_length || + entry->pending_commit.delete_index + length > text_length) { + fprintf(stderr, "delete_surrounding_text: Invalid index: %d," \ + "length %u'; cursor: %u text length: %u\n", index, length, entry->cursor, text_length); + entry->pending_commit.invalid_delete = true; + return; + } } static void text_input_keysym(void *data, struct wl_text_input *text_input, - uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, - uint32_t modifiers) + uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, + uint32_t modifiers) { - fprintf(stderr, "text_input_keysym() serial(%u), time(%u), sym(%u), state(%u), modifiers(%u)\n", - serial, time, sym, state, modifiers); + fprintf(stderr, "text_input_keysym() serial(%u), time(%u), sym(%u), state(%u), modifiers(%u)\n", + serial, time, sym, state, modifiers); } static void text_input_language(void *data, struct wl_text_input *text_input, - uint32_t serial, const char *language) + uint32_t serial, const char *language) { - fprintf(stderr, "text_input_language() serial(%u), language(%s)\n", serial, language); + fprintf(stderr, "text_input_language() serial(%u), language(%s)\n", serial, language); } static void text_input_text_direction(void *data, struct wl_text_input *text_input, - uint32_t serial, uint32_t direction) + uint32_t serial, uint32_t direction) { - fprintf(stderr, "text_input_text_direction() serial(%d), direction(%d)\n", serial, direction); + fprintf(stderr, "text_input_text_direction() serial(%d), direction(%d)\n", serial, direction); } static const struct wl_text_input_listener text_input_listener = { @@ -786,7 +970,7 @@ static const struct wl_text_input_listener text_input_listener = { .keysym = text_input_keysym, .language = text_input_language, .text_direction = text_input_text_direction, - // TIZEN_ONLY(20150918): Support to set the selection region + // TIZEN_ONLY .selection_region = NULL, .private_command = NULL, .input_panel_geometry = NULL, @@ -807,7 +991,7 @@ text_entry_activate(struct display *d) struct wl_surface *surface = d->entered_surface; struct text_entry *entry = d->entry; - fprintf(stderr, "text_entry_activate\n"); + fprintf(stderr, "text_entry_activate\n"); if (entry->click_to_show && entry->active) { entry->panel_visible = !entry->panel_visible; @@ -823,8 +1007,8 @@ text_entry_activate(struct display *d) wl_text_input_show_input_panel(entry->text_input); wl_text_input_activate(entry->text_input, - d->seat, - surface); + d->seat, + surface); } static void @@ -832,9 +1016,9 @@ text_entry_deactivate(struct display *d) { struct text_entry *entry = d->entry; - fprintf(stderr, "text_entry_deactivate\n"); + fprintf(stderr, "text_entry_deactivate\n"); wl_text_input_deactivate(entry->text_input, - d->seat); + d->seat); } static void @@ -858,7 +1042,7 @@ text_entry_create(struct display *d, const char *text) entry = calloc(1, sizeof *entry); if (!entry) - return NULL; + return NULL; entry->text = strdup(text); entry->active = 0; @@ -869,10 +1053,10 @@ text_entry_create(struct display *d, const char *text) entry->text_input = wl_text_input_manager_create_text_input(d->text_input_mgr); wl_text_input_add_listener(entry->text_input, - &text_input_listener, d); + &text_input_listener, d); - d->entry = entry; - fprintf(stderr, "text_entry_create() entry(%p) created.\n", entry); + d->entry = entry; + fprintf(stderr, "text_entry_create() entry(%p) created.\n", entry); return entry; } @@ -990,11 +1174,11 @@ create_display(void) exit(1); } - display->wl_tbm = wayland_tbm_client_init(display->display); - if (!display->wl_tbm) { - fprintf(stderr, "failed wayland_tbm_client_init()\n"); - exit(1); - } + display->wl_tbm = wayland_tbm_client_init(display->display); + if (!display->wl_tbm) { + fprintf(stderr, "failed wayland_tbm_client_init()\n"); + exit(1); + } display->notified = -1; @@ -1007,10 +1191,10 @@ destroy_display(struct display *display) text_entry_destroy(display); if (display->text_input_mgr) - wl_text_input_manager_destroy(display->text_input_mgr); + wl_text_input_manager_destroy(display->text_input_mgr); if (display->seat) - wl_seat_destroy(display->seat); + wl_seat_destroy(display->seat); if (display->shm) wl_shm_destroy(display->shm); @@ -1021,7 +1205,7 @@ destroy_display(struct display *display) if (display->compositor) wl_compositor_destroy(display->compositor); - wayland_tbm_client_deinit(display->wl_tbm); + wayland_tbm_client_deinit(display->wl_tbm); wl_registry_destroy(display->registry); wl_display_flush(display->display); wl_display_disconnect(display->display); -- 2.7.4 From 928ee8905b7248112a372b3de94d0d6058b2d8c9 Mon Sep 17 00:00:00 2001 From: "duna.oh" Date: Wed, 24 Aug 2022 11:32:57 +0900 Subject: [PATCH 07/16] ime: refactoring. delete new_input_method_context event/listener Change-Id: Iaf93b435f8178b8b8bf2a13d477d9a2364d20503 --- examples/tinyds-tdm.c | 277 ++++++++++++++++++------------------- include/libds-tizen/input_method.h | 3 - src/input_method/input_method.c | 38 ++--- src/text_input/text_input.c | 8 +- tests/tc_input_method.cpp | 31 +---- 5 files changed, 148 insertions(+), 209 deletions(-) diff --git a/examples/tinyds-tdm.c b/examples/tinyds-tdm.c index 56d9412..8ffaec5 100644 --- a/examples/tinyds-tdm.c +++ b/examples/tinyds-tdm.c @@ -217,8 +217,6 @@ struct tinyds_input_method { struct wl_listener destroy; struct wl_listener mgr_destroy; - - struct wl_listener new_im_context; }; struct tinyds_input_method_context { @@ -285,6 +283,9 @@ server_view_at(struct tinyds_server *server, double lx, double ly, static bool add_new_text_input(struct tinyds_server *server); static bool add_new_input_method(struct tinyds_server *server); +static bool add_new_input_method_context( + struct tinyds_input_method *input_method, + struct tinyds_text_input *text_input); static void text_input_mgr_handle_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED); @@ -296,8 +297,6 @@ static void input_method_mgr_handle_destroy(struct wl_listener *listener, static void input_method_handle_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED); -static void input_method_handle_new_im_context(struct wl_listener *listener, - void *data TINYDS_UNUSED); int main(void) @@ -1827,82 +1826,6 @@ output_schedule_commit(struct tinyds_output *output) wl_event_loop_add_idle(ev, output_schedule_commit_handle_idle_timer, output); } -static bool -add_new_text_input(struct tinyds_server *server) -{ - struct tinyds_text_input *text_input; - - text_input = calloc(1, sizeof *text_input); - if (!text_input) - return false; - - text_input->text_input_mgr = ds_tizen_text_input_manager_create(server->display); - if (!text_input->text_input_mgr) { - free(text_input); - ds_err("Could not create ds_tizen_text_input_manager"); - return false; - } - - wl_list_init(&text_input->input_methods); - - text_input->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->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, - &text_input->new_text_input); - - text_input->server = server; - server->text_input = text_input; - - ds_inf("Text_Input (%p) added", text_input); - - return true; -} - -static bool -add_new_input_method(struct tinyds_server *server) -{ - struct tinyds_input_method *input_method; - - input_method = calloc(1, sizeof *input_method); - if (!input_method) - return false; - - input_method->input_method = ds_tizen_input_method_create(server->display); - if (!input_method->input_method) { - free(input_method); - ds_err("Could not create ds_tizen_input_method"); - return false; - } - input_method->destroy.notify = input_method_handle_destroy; - ds_tizen_input_method_add_destroy_listener(input_method->input_method, - &input_method->destroy); - - input_method->input_method_mgr = ds_tizen_input_method_manager_create(server->display); - if (!input_method->input_method_mgr) { - free(input_method); - ds_err("Could not create ds_tizen_input_method_manager"); - return false; - } - - input_method->mgr_destroy.notify = input_method_mgr_handle_destroy; - ds_tizen_input_method_manager_add_destroy_listener(input_method->input_method_mgr, - &input_method->mgr_destroy); - - input_method->new_im_context.notify = input_method_handle_new_im_context; - ds_tizen_input_method_add_new_input_method_context_listener(input_method->input_method, - &input_method->new_im_context); - - input_method->server = server; - server->input_method = input_method; - - ds_inf("Input_Method (%p) added", input_method); - - return true; -} - static void text_input_mgr_handle_destroy(struct wl_listener *listener, void *data) { @@ -1935,7 +1858,7 @@ static void text_input_handle_destroy(struct wl_listener *listener, void *data) { struct tinyds_text_input *text_input; - + ds_inf("text_input_handle_destroy"); text_input = wl_container_of(listener, text_input, destroy); @@ -1948,7 +1871,6 @@ text_input_handle_activate(struct wl_listener *listener, void *data) { struct tinyds_text_input *text_input; struct tinyds_input_method *input_method; - struct tinyds_input_method_context *context; struct ds_tizen_text_input_event_activate *event = data; text_input = wl_container_of(listener, text_input, text_input_activate); @@ -1967,17 +1889,8 @@ text_input_handle_activate(struct wl_listener *listener, void *data) text_input->surface = event->surface; - context = calloc(1, sizeof *context); - if (context == NULL) - { - ds_err("calloc is failed. tinyds_input_method_context"); + if (!add_new_input_method_context(input_method, text_input)) return; - } - input_method->context = context; - context->server = text_input->server; - context->context = ds_tizen_input_method_create_context(input_method->input_method); - context->input = text_input; - context->input_method = input_method; // ds_tizen_input_method_send_set_text_input_id(); } @@ -2165,7 +2078,6 @@ input_method_handle_destroy(struct wl_listener *listener, void *data) input_method = wl_container_of(listener, input_method, destroy); wl_list_remove(&input_method->destroy.link); - wl_list_remove(&input_method->new_im_context.link); server = input_method->server; server->input_method = NULL; @@ -2410,71 +2322,152 @@ context_handle_text_direction(struct wl_listener *listener, void *data) ds_tizen_text_input_send_text_direction(text_input->input, event->serial, event->direction); } -static void -input_method_handle_new_im_context(struct wl_listener *listener, void *data) +static bool +add_new_text_input(struct tinyds_server *server) +{ + struct tinyds_text_input *text_input; + + text_input = calloc(1, sizeof *text_input); + if (!text_input) + return false; + + text_input->text_input_mgr = ds_tizen_text_input_manager_create(server->display); + if (!text_input->text_input_mgr) { + free(text_input); + ds_err("Could not create ds_tizen_text_input_manager"); + return false; + } + + wl_list_init(&text_input->input_methods); + + text_input->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->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, + &text_input->new_text_input); + + text_input->server = server; + server->text_input = text_input; + + ds_inf("Text_Input (%p) added", text_input); + + return true; +} + +static bool +add_new_input_method(struct tinyds_server *server) { - struct ds_tizen_input_method_context *context = data; struct tinyds_input_method *input_method; - struct tinyds_input_method_context *ctx; - ds_inf("input_method_handle_new_im_context"); + input_method = calloc(1, sizeof *input_method); + if (!input_method) + return false; + + input_method->input_method = ds_tizen_input_method_create(server->display); + if (!input_method->input_method) { + free(input_method); + ds_err("Could not create ds_tizen_input_method"); + return false; + } + input_method->destroy.notify = input_method_handle_destroy; + ds_tizen_input_method_add_destroy_listener(input_method->input_method, + &input_method->destroy); + + input_method->input_method_mgr = ds_tizen_input_method_manager_create(server->display); + if (!input_method->input_method_mgr) { + free(input_method); + ds_err("Could not create ds_tizen_input_method_manager"); + return false; + } - input_method = wl_container_of(listener, input_method, new_im_context); - ctx = input_method->context; + input_method->mgr_destroy.notify = input_method_mgr_handle_destroy; + ds_tizen_input_method_manager_add_destroy_listener(input_method->input_method_mgr, + &input_method->mgr_destroy); - ctx->destroy.notify = context_handle_destroy; - ds_tizen_input_method_context_add_destroy_listener(context, - &ctx->destroy); + input_method->server = server; + server->input_method = input_method; - ctx->im_context_commit_string.notify = context_handle_commit_string; - ds_tizen_input_method_context_add_commit_string_listener(context, - &ctx->im_context_commit_string); + ds_inf("Input_Method (%p) added", input_method); - ctx->im_context_preedit_string.notify = context_handle_preedit_string; - ds_tizen_input_method_context_add_preedit_string_listener(context, - &ctx->im_context_preedit_string); + return true; +} - ctx->im_context_preedit_styling.notify = context_handle_preedit_styling; - ds_tizen_input_method_context_add_preedit_styling_listener(context, - &ctx->im_context_preedit_styling); +static bool +add_new_input_method_context(struct tinyds_input_method *input_method, + struct tinyds_text_input *text_input) +{ + struct tinyds_input_method_context *context; - ctx->im_context_preedit_cursor.notify = context_handle_preedit_cursor; - ds_tizen_input_method_context_add_preedit_cursor_listener(context, - &ctx->im_context_preedit_cursor); + context = calloc(1, sizeof *context); + if (context == NULL) + { + ds_err("calloc is failed. tinyds_input_method_context"); + return false; + } + input_method->context = context; + context->input_method = input_method; + context->server = input_method->server; + context->input = text_input; + + context->context = ds_tizen_input_method_create_context(input_method->input_method); + + context->destroy.notify = context_handle_destroy; + ds_tizen_input_method_context_add_destroy_listener(context->context, + &context->destroy); + + context->im_context_commit_string.notify = context_handle_commit_string; + ds_tizen_input_method_context_add_commit_string_listener(context->context, + &context->im_context_commit_string); - ctx->im_context_delete_surrounding_text.notify = context_handle_delete_surrounding_text; - ds_tizen_input_method_context_add_delete_surrounding_text_listener(context, - &ctx->im_context_delete_surrounding_text); + context->im_context_preedit_string.notify = context_handle_preedit_string; + ds_tizen_input_method_context_add_preedit_string_listener(context->context, + &context->im_context_preedit_string); - ctx->im_context_cursor_position.notify = context_handle_cursor_position; - ds_tizen_input_method_context_add_cursor_position_listener(context, - &ctx->im_context_cursor_position); + context->im_context_preedit_styling.notify = context_handle_preedit_styling; + ds_tizen_input_method_context_add_preedit_styling_listener(context->context, + &context->im_context_preedit_styling); - ctx->im_context_modifiers_map.notify = context_handle_modifiers_map; - ds_tizen_input_method_context_add_modifiers_map_listener(context, - &ctx->im_context_modifiers_map); + context->im_context_preedit_cursor.notify = context_handle_preedit_cursor; + ds_tizen_input_method_context_add_preedit_cursor_listener(context->context, + &context->im_context_preedit_cursor); - ctx->im_context_keysym.notify = context_handle_keysym; - ds_tizen_input_method_context_add_keysym_listener(context, - &ctx->im_context_keysym); + context->im_context_delete_surrounding_text.notify = context_handle_delete_surrounding_text; + ds_tizen_input_method_context_add_delete_surrounding_text_listener(context->context, + &context->im_context_delete_surrounding_text); - ctx->im_context_grab_keyboard.notify = context_handle_grab_keyboard; - ds_tizen_input_method_context_add_grab_keyboard_listener(context, - &ctx->im_context_grab_keyboard); + context->im_context_cursor_position.notify = context_handle_cursor_position; + ds_tizen_input_method_context_add_cursor_position_listener(context->context, + &context->im_context_cursor_position); - ctx->im_context_key.notify = context_handle_key; - ds_tizen_input_method_context_add_key_listener(context, - &ctx->im_context_key); + context->im_context_modifiers_map.notify = context_handle_modifiers_map; + ds_tizen_input_method_context_add_modifiers_map_listener(context->context, + &context->im_context_modifiers_map); - ctx->im_context_modifiers.notify = context_handle_modifiers; - ds_tizen_input_method_context_add_modifiers_listener(context, - &ctx->im_context_modifiers); + context->im_context_keysym.notify = context_handle_keysym; + ds_tizen_input_method_context_add_keysym_listener(context->context, + &context->im_context_keysym); - ctx->im_context_language.notify = context_handle_language; - ds_tizen_input_method_context_add_language_listener(context, - &ctx->im_context_language); + context->im_context_grab_keyboard.notify = context_handle_grab_keyboard; + ds_tizen_input_method_context_add_grab_keyboard_listener(context->context, + &context->im_context_grab_keyboard); - ctx->im_context_text_direction.notify = context_handle_text_direction; - ds_tizen_input_method_context_add_text_direction_listener(context, - &ctx->im_context_text_direction); + context->im_context_key.notify = context_handle_key; + ds_tizen_input_method_context_add_key_listener(context->context, + &context->im_context_key); + + context->im_context_modifiers.notify = context_handle_modifiers; + ds_tizen_input_method_context_add_modifiers_listener(context->context, + &context->im_context_modifiers); + + context->im_context_language.notify = context_handle_language; + ds_tizen_input_method_context_add_language_listener(context->context, + &context->im_context_language); + + context->im_context_text_direction.notify = context_handle_text_direction; + ds_tizen_input_method_context_add_text_direction_listener(context->context, + &context->im_context_text_direction); + + return true; } diff --git a/include/libds-tizen/input_method.h b/include/libds-tizen/input_method.h index 2209026..c6a40c2 100644 --- a/include/libds-tizen/input_method.h +++ b/include/libds-tizen/input_method.h @@ -103,9 +103,6 @@ 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, diff --git a/src/input_method/input_method.c b/src/input_method/input_method.c index eb6232b..8eed2f2 100644 --- a/src/input_method/input_method.c +++ b/src/input_method/input_method.c @@ -42,7 +42,6 @@ struct ds_tizen_input_method { struct { struct wl_signal destroy; - struct wl_signal new_input_method_context; } events; }; @@ -115,30 +114,23 @@ static const struct zwp_input_method_manager_v1_interface input_method_mgr_impl }; 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, + input_method_mgr->resource = wl_resource_create(wl_client, &zwp_input_method_manager_v1_interface, version, id); - if (resource == NULL) { + if (input_method_mgr->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_resource_set_implementation(input_method_mgr->resource, &input_method_mgr_impl, + input_method_mgr, NULL); } WL_EXPORT struct ds_tizen_input_method_manager * @@ -178,13 +170,6 @@ ds_tizen_input_method_add_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) { @@ -243,6 +228,10 @@ ds_tizen_input_method_create_context(struct ds_tizen_input_method *input_method) if (!binding) 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) { + ds_err("context. wl_resource_create() failed."); + return NULL; + } wl_resource_set_implementation(context->resource, &context_impl, context, input_method_context_client_handle_destroy); @@ -261,8 +250,6 @@ ds_tizen_input_method_create_context(struct ds_tizen_input_method *input_method) 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; @@ -675,12 +662,6 @@ input_method_handle_display_destroy(struct wl_listener *listener, void *data) } 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) { @@ -697,7 +678,7 @@ input_method_bind(struct wl_client *wl_client, void *data, return; } wl_resource_set_implementation(input_method->resource, NULL, - input_method, input_method_client_handle_destroy); + input_method, NULL); } WL_EXPORT struct ds_tizen_input_method * @@ -719,7 +700,6 @@ ds_tizen_input_method_create(struct wl_display *display) } 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); diff --git a/src/text_input/text_input.c b/src/text_input/text_input.c index 7a9c4f2..05adda7 100644 --- a/src/text_input/text_input.c +++ b/src/text_input/text_input.c @@ -472,12 +472,6 @@ static const struct wl_text_input_manager_interface text_input_mgr_impl = }; static void -text_input_mgr_client_handle_destroy(struct wl_resource *resource) -{ - ds_inf("text_input_mgr_client_handle_destroy"); -} - -static void text_input_mgr_bind(struct wl_client *wl_client, void *data, uint32_t version, uint32_t id) { @@ -495,7 +489,7 @@ text_input_mgr_bind(struct wl_client *wl_client, void *data, return; } wl_resource_set_implementation(resource, &text_input_mgr_impl, - text_input_mgr, text_input_mgr_client_handle_destroy); + text_input_mgr, NULL); } WL_EXPORT struct ds_tizen_text_input_manager * diff --git a/tests/tc_input_method.cpp b/tests/tc_input_method.cpp index 1bbc1be..a9b1ecf 100644 --- a/tests/tc_input_method.cpp +++ b/tests/tc_input_method.cpp @@ -41,13 +41,6 @@ public: 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) @@ -60,26 +53,13 @@ public: 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); + mInputMethodContext = ds_tizen_input_method_create_context(mInputMethod); + if (mInputMethodContext) + bNewInputMethodContext = true; } void SendActivate() @@ -109,11 +89,6 @@ private: MockInputMethodCompositor *parent; }; DestroyListener mDestroyListener; - - struct NewInputMethodContextListener: ::wl_listener { - MockInputMethodCompositor *parent; - }; - NewInputMethodContextListener mNewInputMethodContextListener; }; class MockInputMethodClient : public MockClient -- 2.7.4 From 2c3579b368eabb2b245e902affdbf0def9d06083 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 24 Aug 2022 13:31:47 +0900 Subject: [PATCH 08/16] Update .gitignore This adds vim swapfiles. Change-Id: Ifce2e25131882a52806f7df06dc6d7c437f4093f --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index c6127b3..7ca031c 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,7 @@ modules.order Module.symvers Mkfile.old dkms.conf + +# Vim swapfiles +.*.sw? +.sw? -- 2.7.4 From fdde359c1102cb86740e77f44e20edd4d60e5c56 Mon Sep 17 00:00:00 2001 From: Changyeon Lee Date: Wed, 24 Aug 2022 15:40:50 +0900 Subject: [PATCH 09/16] implement ds_tizen_hwc This is the server implementation for tizen_hwc protocol. Change-Id: I4ba3b103efaf6ce2c8863d63f26b40e120ffc327 --- include/libds-tizen/hwc.h | 49 ++++++ packaging/libds-tizen.spec | 32 ++++ src/hwc/hwc.c | 297 +++++++++++++++++++++++++++++++++ src/hwc/meson.build | 29 ++++ src/meson.build | 3 +- tests/meson.build | 22 ++- tests/tc_hwc.cpp | 398 +++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 828 insertions(+), 2 deletions(-) create mode 100644 include/libds-tizen/hwc.h create mode 100644 src/hwc/hwc.c create mode 100644 src/hwc/meson.build create mode 100644 tests/tc_hwc.cpp diff --git a/include/libds-tizen/hwc.h b/include/libds-tizen/hwc.h new file mode 100644 index 0000000..11ffe9c --- /dev/null +++ b/include/libds-tizen/hwc.h @@ -0,0 +1,49 @@ +#ifndef LIBDS_TIZEN_HWC_H +#define LIBDS_TIZEN_HWC_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ds_tizen_hwc; + +struct ds_tizen_hwc_commit_feedback; + +struct ds_tizen_hwc * +ds_tizen_hwc_create(struct wl_display *display); + +void +ds_tizen_hwc_add_destroy_listener(struct ds_tizen_hwc *hwc, + struct wl_listener *listener); + +void +ds_tizen_hwc_add_new_commit_feedback_listener( + struct ds_tizen_hwc *hwc, + struct wl_listener *listener); + +void +ds_tizen_hwc_commit_feedback_add_destroy_listener( + struct ds_tizen_hwc_commit_feedback *commit_feedback, + struct wl_listener *listener); + +struct ds_surface * +ds_tizen_hwc_commit_feedback_get_surface( + struct ds_tizen_hwc_commit_feedback *commit_feedback); + +void +ds_tizen_hwc_commit_feedback_send_committed( + struct ds_tizen_hwc_commit_feedback *commit_feedback); + +void +ds_tizen_hwc_commit_feedback_send_discarded( + struct ds_tizen_hwc_commit_feedback *commit_feedback); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packaging/libds-tizen.spec b/packaging/libds-tizen.spec index fc126c7..53d3d2f 100644 --- a/packaging/libds-tizen.spec +++ b/packaging/libds-tizen.spec @@ -32,6 +32,8 @@ BuildRequires: pkgconfig(tizen-dpms-server) BuildRequires: pkgconfig(tizen-dpms-client) BuildRequires: pkgconfig(tizen-surface-server) BuildRequires: pkgconfig(tizen-surface-client) +BuildRequires : pkgconfig(tizen-hwc-server) +BuildRequires : pkgconfig(tizen-hwc-client) BuildRequires: pkgconfig(cynara-client) BuildRequires: pkgconfig(cynara-session) BuildRequires: pkgconfig(libsmack) @@ -295,6 +297,21 @@ Group: Development/Libraries %description input-method-devel Development package for tizen input-method +## libds-tizen-hwc +%package hwc +Summary: Library for tizen hwc +Group: Development/Libraries + +%description hwc +Library for tizen hwc + +%package hwc-devel +Summary: Development package for tizen hwc +Group: Development/Libraries + +%description hwc-devel +Development package for tizen hwc + %prep %setup -q cp %{SOURCE1001} . @@ -571,3 +588,18 @@ ninja -C builddir install %{_bindir}/libds-tizen-input-method-tests %{_bindir}/libds-tizen-input-method-manager-tests %{_bindir}/ime-keyboard + +%files hwc +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_libdir}/libds-tizen-hwc.so* + +%files hwc-devel +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_includedir}/libds-tizen/hwc.h +%{_libdir}/pkgconfig/libds-tizen-hwc.pc +%{_libdir}/libds-tizen-hwc.so* +%{_bindir}/libds-tizen-hwc-tests diff --git a/src/hwc/hwc.c b/src/hwc/hwc.c new file mode 100644 index 0000000..7346911 --- /dev/null +++ b/src/hwc/hwc.c @@ -0,0 +1,297 @@ +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "libds-tizen/hwc.h" + +#define TIZEN_HWC_VERSION 1 + +struct ds_tizen_hwc +{ + struct wl_global *global; + + struct wl_list clients; + + struct wl_listener destroy; + + struct { + struct wl_signal destroy; + struct wl_signal new_commit_feedback; + } events; +}; + +struct ds_tizen_hwc_client +{ + struct ds_tizen_hwc *hwc; + + struct wl_resource *resource; + struct wl_client *wl_client; + + struct { + struct wl_signal destroy; + } events; + + struct wl_list link; +}; + +struct ds_tizen_hwc_commit_feedback +{ + struct wl_resource *resource; + + struct ds_surface *surface; + uint32_t serial; + + struct { + struct wl_listener surface_destroy; + } listener; + + struct { + struct wl_signal destroy; + } events; +}; + +static void +hwc_commit_feedback_handle_surface_destroy(struct wl_listener *listener, void *data) +{ + struct ds_tizen_hwc_commit_feedback *commit_feedback; + + commit_feedback = wl_container_of(listener, commit_feedback, + listener.surface_destroy); + + if (commit_feedback->listener.surface_destroy.notify) { + wl_list_remove(&commit_feedback->listener.surface_destroy.link); + commit_feedback->listener.surface_destroy.notify = NULL; + } + + commit_feedback->surface = NULL; +} + +static void +_hwc_commit_feedback_cb_resource_destroy(struct wl_resource *commit_feedback_resource) +{ + struct ds_tizen_hwc_commit_feedback *commit_feedback; + + commit_feedback = wl_resource_get_user_data(commit_feedback_resource); + + ds_inf("hwc_commit_feedback:%p destroy", commit_feedback); + + if (commit_feedback->listener.surface_destroy.notify) { + wl_list_remove(&commit_feedback->listener.surface_destroy.link); + commit_feedback->listener.surface_destroy.notify = NULL; + } + + wl_signal_emit(&commit_feedback->events.destroy, commit_feedback); + + free(commit_feedback); +} + +static void +hwc_handle_create_commit_feedback(struct wl_client *client, + struct wl_resource *hwc_client_resource, + struct wl_resource *surface_resource, + uint32_t id, + uint32_t serial) +{ + struct ds_tizen_hwc_client *hwc_client; + struct ds_tizen_hwc_commit_feedback *commit_feedback; + struct ds_surface *surface; + + hwc_client = wl_resource_get_user_data(hwc_client_resource); + + surface = ds_surface_from_resource(surface_resource); + + commit_feedback = calloc(1, sizeof *commit_feedback); + if (!commit_feedback) { + wl_client_post_no_memory(client); + return; + } + + commit_feedback->resource = wl_resource_create(client, &tizen_hwc_commit_feedback_interface, + wl_resource_get_version(hwc_client_resource), id); + if (!commit_feedback->resource) { + wl_client_post_no_memory(client); + free(commit_feedback); + return; + } + + commit_feedback->listener.surface_destroy.notify = hwc_commit_feedback_handle_surface_destroy; + ds_surface_add_destroy_listener(surface, &commit_feedback->listener.surface_destroy); + commit_feedback->surface = surface; + + commit_feedback->serial = serial; + + wl_resource_set_implementation(commit_feedback->resource, NULL, + commit_feedback, _hwc_commit_feedback_cb_resource_destroy); + + ds_inf("hwc_commit_feedback:%p create", commit_feedback); + + wl_signal_init(&commit_feedback->events.destroy); + + wl_signal_emit(&hwc_client->hwc->events.new_commit_feedback, commit_feedback); +} + +static void +hwc_handle_destroy(struct wl_client *wl_client, + struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static const struct tizen_hwc_interface hwc_impl = +{ + .destroy = hwc_handle_destroy, + .create_commit_feedback = hwc_handle_create_commit_feedback, +}; + +static void +_tizen_hwc_client_handle_resource_destroy(struct wl_resource *resource) +{ + struct ds_tizen_hwc_client *client; + + client = wl_resource_get_user_data(resource); + + ds_inf("_tizen_hwc_client_handle_destroy (client:%p)", client); + + wl_list_remove(&client->link); + free(client); +} + +static void +hwc_bind(struct wl_client *wl_client, void *data, uint32_t version, + uint32_t id) +{ + struct ds_tizen_hwc *hwc = data; + struct ds_tizen_hwc_client *hwc_client; + + hwc_client = calloc(1, sizeof *hwc_client); + if (hwc_client == NULL) { + ds_err("calloc() failed. tizen_hwc"); + wl_client_post_no_memory(wl_client); + return; + } + + ds_inf("tizen_hwc_client binds. (hwc_client:%p)", hwc_client); + + hwc_client->hwc = hwc; + hwc_client->wl_client = wl_client; + + hwc_client->resource = wl_resource_create(wl_client, &tizen_hwc_interface, + MIN(version, TIZEN_HWC_VERSION), id); + if (hwc_client->resource == NULL) { + ds_err("tizen_hwc : wl_resource_create() failed."); + free(hwc_client); + wl_client_post_no_memory(wl_client); + return; + } + + wl_resource_set_implementation(hwc_client->resource, &hwc_impl, hwc_client, + _tizen_hwc_client_handle_resource_destroy); + + wl_signal_init(&hwc_client->events.destroy); + + wl_list_insert(&hwc->clients, &hwc_client->link); +} + +static void +hwc_handle_display_destroy(struct wl_listener *listener, void *data) +{ + struct ds_tizen_hwc *hwc; + + hwc = wl_container_of(listener, hwc, destroy); + + ds_inf("Global destroy: hwc(%p)", hwc); + + wl_signal_emit(&hwc->events.destroy, hwc); + wl_list_remove(&hwc->destroy.link); + wl_global_destroy(hwc->global); + free(hwc); +} + +WL_EXPORT struct ds_tizen_hwc * +ds_tizen_hwc_create(struct wl_display *display) +{ + struct ds_tizen_hwc *hwc; + + hwc = calloc(1, sizeof *hwc); + if (!hwc) { + ds_err("calloc() failed."); + return NULL; + } + + hwc->global = wl_global_create(display, &tizen_hwc_interface, + TIZEN_HWC_VERSION, hwc, hwc_bind); + if (!hwc->global) { + ds_err("wl_global_create() failed. tizen_hwc_interface"); + free(hwc); + return NULL; + } + + wl_list_init(&hwc->clients); + + hwc->destroy.notify = hwc_handle_display_destroy; + wl_display_add_destroy_listener(display, &hwc->destroy); + + wl_signal_init(&hwc->events.destroy); + wl_signal_init(&hwc->events.new_commit_feedback); + + ds_inf("Global created: tizen_hwc(%p)", hwc); + + return hwc; +} + +WL_EXPORT void +ds_tizen_hwc_add_destroy_listener( + struct ds_tizen_hwc *hwc, + struct wl_listener *listener) +{ + wl_signal_add(&hwc->events.destroy, listener); +} + +WL_EXPORT void +ds_tizen_hwc_add_new_commit_feedback_listener( + struct ds_tizen_hwc *hwc, + struct wl_listener *listener) +{ + wl_signal_add(&hwc->events.new_commit_feedback, listener); +} + +WL_EXPORT void +ds_tizen_hwc_commit_feedback_add_destroy_listener( + struct ds_tizen_hwc_commit_feedback *commit_feedback, + struct wl_listener *listener) +{ + wl_signal_add(&commit_feedback->events.destroy, listener); +} + +WL_EXPORT struct ds_surface * +ds_tizen_hwc_commit_feedback_get_surface( + struct ds_tizen_hwc_commit_feedback *commit_feedback) +{ + return commit_feedback->surface; +} + +WL_EXPORT void +ds_tizen_hwc_commit_feedback_send_committed( + struct ds_tizen_hwc_commit_feedback *commit_feedback) +{ + ds_inf("hwc_commit_feedback:%p send committed", commit_feedback); + + tizen_hwc_commit_feedback_send_committed(commit_feedback->resource, + commit_feedback->serial); + wl_resource_destroy(commit_feedback->resource); +} + +WL_EXPORT void +ds_tizen_hwc_commit_feedback_send_discarded( + struct ds_tizen_hwc_commit_feedback *commit_feedback) +{ + ds_inf("hwc_commit_feedback:%p send discard", commit_feedback); + + tizen_hwc_commit_feedback_send_discarded(commit_feedback->resource, + commit_feedback->serial); + wl_resource_destroy(commit_feedback->resource); +} diff --git a/src/hwc/meson.build b/src/hwc/meson.build new file mode 100644 index 0000000..7f9caa0 --- /dev/null +++ b/src/hwc/meson.build @@ -0,0 +1,29 @@ +libds_tizen_hwc_files = [ + 'hwc.c', +] + +libds_tizen_hwc_deps = [ + deps_libds_tizen, + dependency('tizen-hwc-server', required: true), +] + +lib_libds_tizen_hwc = shared_library('ds-tizen-hwc', libds_tizen_hwc_files, + dependencies: libds_tizen_hwc_deps, + include_directories: [ common_inc, include_directories('.'), include_directories('..') ], + version: meson.project_version(), + install: true +) + +deps_libds_tizen_hwc = declare_dependency( + link_with: lib_libds_tizen_hwc, + dependencies: libds_tizen_hwc_deps, + include_directories: [ common_inc, include_directories('.') ], +) + +pkgconfig = import('pkgconfig') +pkgconfig.generate(lib_libds_tizen_hwc, + version: meson.project_version(), + filebase: 'libds-tizen-hwc', + name: 'libds-tizen-hwc', + description: 'tizen hwc extension of libds-tizen for tizen platform', +) diff --git a/src/meson.build b/src/meson.build index aef63ac..8d254fa 100644 --- a/src/meson.build +++ b/src/meson.build @@ -43,4 +43,5 @@ subdir('screen_rotation') subdir('global_resource') subdir('embedded_compositor') subdir('input_method') -subdir('text_input') \ No newline at end of file +subdir('text_input') +subdir('hwc') diff --git a/tests/meson.build b/tests/meson.build index 0405794..1b78a64 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -283,4 +283,24 @@ executable('libds-tizen-text-input-tests', ], install_dir: libds_tizen_bindir, install : true -) \ No newline at end of file +) + +## hwc tests +tc_hwc_files = [ + 'tc_main.cpp', + 'tc_hwc.cpp', +] + +executable('libds-tizen-hwc-tests', + [ + tc_mock_files, + tc_hwc_files + ], + dependencies: [ + deps_test_common, + deps_libds_tizen_hwc, + dependency('tizen-hwc-client', required: true), + ], + install_dir: libds_tizen_bindir, + install : true +) diff --git a/tests/tc_hwc.cpp b/tests/tc_hwc.cpp new file mode 100644 index 0000000..77c93b1 --- /dev/null +++ b/tests/tc_hwc.cpp @@ -0,0 +1,398 @@ +#include "tc_main.h" +#include "mockclient.h" +#include "mockcompositor.h" +#include +#include + +#define TIZEN_HWC_VERSION 1 + +class MockHwcCompositor : public MockCompositor +{ +public: + MockHwcCompositor() + : MockCompositor(&MockHwcCompositor::TestSetup, this) + { + ds_inf("%s : this(%p)", __func__, this); + + bHwcDestroyed = false; + bSurfaceDestroyed = false; + } + + ~MockHwcCompositor() + { + ds_inf("%s : this(%p)", __func__, this); + } + + static void TestSetup(void *data) + { + MockHwcCompositor *mockComp = + static_cast(data); + Compositor *comp = mockComp->compositor; + + ds_inf("%s: mockComp(%p)", __func__, mockComp); + + // new surface listener + mockComp->mNewSurfaceListener.notify = + MockHwcCompositor::NewSurfaceCallback; + mockComp->mNewSurfaceListener.parent = mockComp; + ds_compositor_add_new_surface_listener(comp->compositor, + &mockComp->mNewSurfaceListener); + + mockComp->mHwc = + ds_tizen_hwc_create(comp->display); + + // destroy listener + mockComp->mHwcDestroyListener.notify = + MockHwcCompositor::HwcDestroyCallback; + mockComp->mHwcDestroyListener.parent = mockComp; + ds_tizen_hwc_add_destroy_listener(mockComp->mHwc, + &mockComp->mHwcDestroyListener); + + // add_ignore_output_transform listener + mockComp->mHwcNewCommitFeedbackListener.notify = + MockHwcCompositor::HwcNewCommitFeedbackCallback; + mockComp->mHwcNewCommitFeedbackListener.parent = mockComp; + ds_tizen_hwc_add_new_commit_feedback_listener( + mockComp->mHwc, + &mockComp->mHwcNewCommitFeedbackListener); + } + + static void NewSurfaceCallback(struct wl_listener *listener, void *data) + { + MockHwcCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_surface *surface = static_cast(data); + + ds_inf("%s: mockComp(%p), surface(%p)", __func__, mockComp, surface); + + mockComp->mSurface = surface; + + // del surface listener + mockComp->mDelSurfaceListener.notify = + MockHwcCompositor::DelSurfaceCallback; + mockComp->mDelSurfaceListener.parent = mockComp; + ds_surface_add_destroy_listener(surface, + &mockComp->mDelSurfaceListener); + } + + static void DelSurfaceCallback(struct wl_listener *listener, void *data) + { + MockHwcCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_surface *surface = static_cast(data); + + ds_inf("%s: mockComp(%p), surface(%p)", __func__, mockComp, surface); + + if (ds_surface_get_wl_resource(mockComp->mSurface) == + ds_surface_get_wl_resource(surface)) { + ds_inf("%s: surface is deleted.", __func__); + mockComp->bSurfaceDestroyed = true; + } + } + + static void HwcDestroyCallback(struct wl_listener *listener, void *data) + { + ds_inf("%s", __func__); + + MockHwcCompositor *mockComp = + reinterpret_cast(listener)->parent; + + mockComp->bHwcDestroyed = true; + } + + static void HwcNewCommitFeedbackCallback(struct wl_listener *listener, + void *data) + { + ds_inf("%s", __func__); + + MockHwcCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_tizen_hwc_commit_feedback *commitFeedback = + static_cast(data); + + ds_inf("%s: mockComp(%p), commitFeedback(%p)", __func__, mockComp, commitFeedback); + + mockComp->mCommitFeedback = commitFeedback; + mockComp->mSurface = + ds_tizen_hwc_commit_feedback_get_surface(mockComp->mCommitFeedback); + + mockComp->mHwcCommitFeedbackDestroyListener.notify = + MockHwcCompositor::HwcCommitFeedbackDestroyCallback; + mockComp->mHwcCommitFeedbackDestroyListener.parent = mockComp; + ds_tizen_hwc_commit_feedback_add_destroy_listener(mockComp->mCommitFeedback, + &mockComp->mHwcCommitFeedbackDestroyListener); + } + + static void HwcCommitFeedbackDestroyCallback(struct wl_listener *listener, + void *data) + { + ds_inf("%s", __func__); + + MockHwcCompositor *mockComp = + reinterpret_cast(listener)->parent; + struct ds_tizen_hwc_commit_feedback *commitFeedback = + static_cast(data); + + ds_inf("%s: mockComp(%p), info(%p)", __func__, mockComp, commitFeedback); + + if (mockComp->mCommitFeedback == commitFeedback) { + ds_inf("%s: commitFeedback is deleted.", __func__); + } + } + + void SendHwcCommitFeedbackCommitted(void) + { + ds_inf("%s", __func__); + + ds_tizen_hwc_commit_feedback_send_committed(mCommitFeedback); + } + + void SendHwcCommitFeedbackDiscarded(void) + { + ds_inf("%s", __func__); + + ds_tizen_hwc_commit_feedback_send_discarded(mCommitFeedback); + } + +public: + bool bHwcDestroyed; + bool bSurfaceDestroyed; + +private: + struct ds_tizen_hwc *mHwc; + + struct HwcDestroyListener : ::wl_listener { + MockHwcCompositor *parent; + }; + HwcDestroyListener mHwcDestroyListener; + + struct ds_surface *mSurface; + + struct NewSurfaceListener : ::wl_listener { + MockHwcCompositor *parent; + }; + NewSurfaceListener mNewSurfaceListener; + + struct DelSurfaceListener : ::wl_listener { + MockHwcCompositor *parent; + }; + DelSurfaceListener mDelSurfaceListener; + + struct ds_tizen_hwc_commit_feedback *mCommitFeedback; + + struct HwcNewCommitFeedbackListener : ::wl_listener { + MockHwcCompositor *parent; + }; + HwcNewCommitFeedbackListener mHwcNewCommitFeedbackListener; + + struct HwcCommitFeedbackDestroyListener : ::wl_listener { + MockHwcCompositor *parent; + }; + HwcCommitFeedbackDestroyListener mHwcCommitFeedbackDestroyListener; +}; + +class MockHwcClient : public MockClient +{ +public: + MockHwcClient() + : bCommittedEvent(false), + bDiscardedEvent(false), + compositorRes(nullptr), + tizenHwcRes(nullptr) + {} + MockHwcClient(const struct wl_registry_listener *listener) + : MockClient(listener, this) + { + ds_inf("%s", __func__); + } + ~MockHwcClient() + { + ds_inf("%s", __func__); + } + + void SetWlCompositor(struct wl_compositor *globalRes) + { + ds_inf("%s", __func__); + + compositorRes = globalRes; + } + + struct wl_compositor *GetWlCompositor() + { + ds_inf("%s", __func__); + + return compositorRes; + } + + void SetTizenHwc(struct tizen_hwc *resource) + { + ds_inf("%s", __func__); + + tizenHwcRes = resource; + } + + struct tizen_hwc *GetTizenHwc() + { + ds_inf("%s", __func__); + + return tizenHwcRes; + } + +public: + bool bCommittedEvent; + bool bDiscardedEvent; +private: + struct wl_compositor *compositorRes; + struct tizen_hwc *tizenHwcRes; +}; + +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__); + + MockHwcClient *client = static_cast(data); + struct wl_compositor *compositor_res; + struct tizen_hwc *tizen_hwc_res; + + if (!strcmp(interface, "wl_compositor")) { + compositor_res = (struct wl_compositor *)wl_registry_bind(registry, + name, &wl_compositor_interface, 1); + if (compositor_res == nullptr) { + ds_err("wl_registry_bind() failed. wl_compositor resource."); + return; + } + client->SetWlCompositor(compositor_res); + } else if (!strcmp(interface, "tizen_hwc")) { + tizen_hwc_res = (struct tizen_hwc *)wl_registry_bind(registry, + name, &tizen_hwc_interface, TIZEN_HWC_VERSION); + if (tizen_hwc_res == nullptr) { + ds_err("wl_registry_bind() failed. tizen_hwc resource."); + return; + } + client->SetTizenHwc(tizen_hwc_res); + } +} + +static void +client_registry_cb_global_remove(void *data, struct wl_registry *registry, + uint32_t name) +{ + ds_inf("%s", __func__); + + MockHwcClient *client = static_cast(data); + struct wl_compositor *compositor_res = client->GetWlCompositor(); + struct tizen_hwc *tizen_hwc_res = client->GetTizenHwc(); + + tizen_hwc_destroy(tizen_hwc_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 HwcTest : public ::testing::Test +{ +public: + void SetUp(void) override; + void TearDown(void) override; + + MockHwcCompositor *comp; + MockHwcClient *client; + struct wl_compositor *compositorRes; + struct tizen_hwc *tizenHwcRes; + struct wl_surface *surfaceRes; + struct tizen_hwc_commit_feedback *tizenHwcCommitFeedbackRes; +}; + +static void +tizen_hwc_commit_feedback_cb_committed(void *data, + struct tizen_hwc_commit_feedback *hwc_commit_feedback, + uint32_t serial) +{ + ds_inf("%s", __func__); + + MockHwcClient *client = static_cast(data); + + client->bCommittedEvent = true; + + tizen_hwc_commit_feedback_destroy(hwc_commit_feedback); +} + +static void +tizen_hwc_commit_feedback_cb_discarded(void *data, + struct tizen_hwc_commit_feedback *hwc_commit_feedback, + uint32_t serial) +{ + ds_inf("%s", __func__); + + MockHwcClient *client = static_cast(data); + + client->bDiscardedEvent = true; + + tizen_hwc_commit_feedback_destroy(hwc_commit_feedback); +} + +static const struct tizen_hwc_commit_feedback_listener tizen_hwc_commit_feedback_cb_listener = { + .committed = tizen_hwc_commit_feedback_cb_committed, + .discarded = tizen_hwc_commit_feedback_cb_discarded, +}; + +void +HwcTest::SetUp(void) +{ + ds_inf("%s", __func__); + + comp = new MockHwcCompositor(); + client = new MockHwcClient(®istry_listener); + compositorRes = client->GetWlCompositor(); + tizenHwcRes = client->GetTizenHwc(); + surfaceRes = wl_compositor_create_surface(compositorRes); + + tizenHwcCommitFeedbackRes = + tizen_hwc_create_commit_feedback(tizenHwcRes, surfaceRes, 1); + + tizen_hwc_commit_feedback_add_listener(tizenHwcCommitFeedbackRes, + &tizen_hwc_commit_feedback_cb_listener, client); + + client->RoundTrip(); +} + +void +HwcTest::TearDown(void) +{ + ds_inf("%s", __func__); + + wl_surface_destroy(surfaceRes); + client->RoundTrip(); + EXPECT_TRUE(comp->bSurfaceDestroyed); + + delete client; + delete comp; +} + +TEST_F(HwcTest, Create_P) +{ + EXPECT_TRUE(true); +} + +TEST_F(HwcTest, Ev_TizenHwcCommitFeedbackCommitted) +{ + comp->SendHwcCommitFeedbackCommitted(); + comp->Process(); + + client->RoundTrip(); + EXPECT_TRUE(client->bCommittedEvent); +} + +TEST_F(HwcTest, Ev_TizenHwcCommitFeedbackDiscared) +{ + comp->SendHwcCommitFeedbackDiscarded(); + comp->Process(); + + client->RoundTrip(); + EXPECT_TRUE(client->bDiscardedEvent); +} -- 2.7.4 From 4d948ed0eeb40a20867fe962ff4593f1560ccc23 Mon Sep 17 00:00:00 2001 From: "duna.oh" Date: Fri, 2 Sep 2022 15:28:39 +0900 Subject: [PATCH 10/16] tinyds: use 'rand_r' instead of function 'rand' For thread safety, rand_r is preferred to use. Change-Id: I56fef4a94ee5110b090add7c1449797956c93db3 --- examples/tinyds-tdm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/tinyds-tdm.c b/examples/tinyds-tdm.c index 8ffaec5..26ff72c 100644 --- a/examples/tinyds-tdm.c +++ b/examples/tinyds-tdm.c @@ -430,6 +430,8 @@ view_handle_surface_commit(struct wl_listener *listener, static void server_new_xdg_surface(struct wl_listener *listener, void *data) { + static unsigned int seedx = 1; + static unsigned int seedy = 43210; struct tinyds_server *server; struct tinyds_view *view; struct ds_xdg_surface *xdg_surface; @@ -462,8 +464,8 @@ server_new_xdg_surface(struct wl_listener *listener, void *data) ds_xdg_surface_get_surface(xdg_surface), &view->surface_commit); - view->x = rand() % 1000; - view->y = rand() % 500; + view->x = rand_r(&seedx) % 1000; + view->y = rand_r(&seedy) % 500; view->hwc_window = ds_tdm_output_hwc_window_create(server->output->hwc); assert(view->hwc_window); -- 2.7.4 From 3311099f1ec13a331437383ccb7d5bedfdf8b8c6 Mon Sep 17 00:00:00 2001 From: "duna.oh" Date: Sun, 4 Sep 2022 10:51:48 +0900 Subject: [PATCH 11/16] text-entry: use memcpy instead of strcpy For better security, do not use vulnerable function 'strcpy' Change-Id: Ib0ac0a253b19df4ce14d0faac233591ecd1d16c4 --- clients/text-entry.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/clients/text-entry.c b/clients/text-entry.c index ce21d02..0561e56 100644 --- a/clients/text-entry.c +++ b/clients/text-entry.c @@ -615,16 +615,22 @@ text_entry_insert_at_cursor(struct text_entry *entry, const char *text, int32_t cursor, int32_t anchor) { fprintf(stderr, "text_entry_insert_at_cursor()\n"); - char *new_text = malloc(strlen(entry->text) + strlen(text) + 1); + char *new_text; + int len_entry_text, len_text; + + len_entry_text = strlen(entry->text); + len_text = strlen(text); + new_text = malloc(len_entry_text + len_text + 1); if (new_text == NULL) { fprintf(stderr, "alloc fail"); return; } - strncpy(new_text, entry->text, entry->cursor); - strcpy(new_text + entry->cursor, text); - strcpy(new_text + entry->cursor + strlen(text), - entry->text + entry->cursor); + memcpy(new_text, entry->text, entry->cursor); + memcpy(new_text + entry->cursor, text, len_text); + memcpy(new_text + entry->cursor + len_text, + entry->text + entry->cursor, len_entry_text - entry->cursor); + new_text[len_entry_text + len_text] = '\0'; free(entry->text); entry->text = new_text; -- 2.7.4 From bcd2f95e229f6aa76765cdd9f914dd71a5936c24 Mon Sep 17 00:00:00 2001 From: "duna.oh" Date: Mon, 5 Sep 2022 13:19:11 +0900 Subject: [PATCH 12/16] ime: free allocated variables before return statement To fix resource leak. Change-Id: Icf1bdfdecebf14903c89c4f21fa92bbebc19513c --- src/input_method/input_method.c | 5 ++++- src/text_input/text_input.c | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/input_method/input_method.c b/src/input_method/input_method.c index 8eed2f2..138193f 100644 --- a/src/input_method/input_method.c +++ b/src/input_method/input_method.c @@ -221,8 +221,10 @@ ds_tizen_input_method_create_context(struct ds_tizen_input_method *input_method) ds_inf("ds_tizen_input_method_create_context"); context = calloc(1, sizeof *context); - if (context == NULL) + if (context == NULL) { + ds_err("calloc() failed. ds_tizen_input_method_context"); return NULL; + } binding = input_method->resource; if (!binding) return NULL; @@ -230,6 +232,7 @@ ds_tizen_input_method_create_context(struct ds_tizen_input_method *input_method) &zwp_input_method_context_v1_interface, INPUT_METHOD_VERSION, 0); if (context->resource == NULL) { ds_err("context. wl_resource_create() failed."); + free(context); return NULL; } wl_resource_set_implementation(context->resource, &context_impl, diff --git a/src/text_input/text_input.c b/src/text_input/text_input.c index 05adda7..d25b1a4 100644 --- a/src/text_input/text_input.c +++ b/src/text_input/text_input.c @@ -448,6 +448,7 @@ text_input_manager_handle_create_text_input(struct wl_client *wl_client, if (text_input->resource == NULL) { ds_err("text_input. wl_resource_create() failed."); wl_client_post_no_memory(wl_client); + free(text_input); return; } wl_resource_set_implementation(text_input->resource, &text_input_impl, -- 2.7.4 From 92fd0ced30e330e6a237312d31f33c0a5310dd6e Mon Sep 17 00:00:00 2001 From: "duna.oh" Date: Tue, 6 Sep 2022 16:07:03 +0900 Subject: [PATCH 13/16] clients: merge ime-keyboard code to input-generator Change-Id: I0e39cef61183833eaf7c06917a42285a2faa24f6 --- clients/ime-keyboard.c | 957 --------------------------------------------- clients/input-generator.c | 740 ++++++++++++++++++++++++++++++++++- clients/meson.build | 14 +- packaging/libds-tizen.spec | 1 - 4 files changed, 739 insertions(+), 973 deletions(-) delete mode 100644 clients/ime-keyboard.c diff --git a/clients/ime-keyboard.c b/clients/ime-keyboard.c deleted file mode 100644 index 4d6346d..0000000 --- a/clients/ime-keyboard.c +++ /dev/null @@ -1,957 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#define MAX_STR 1024 -#define SIZE_EPOLL 16 - -enum keyboard_state { - KEYBOARD_STATE_DEFAULT, - KEYBOARD_STATE_UPPERCASE, - KEYBOARD_STATE_SYMBOLS -}; - -struct display -{ - struct wl_display *display; - struct wl_registry *registry; - struct wl_compositor *compositor; - struct wl_event_queue *queue; - - int run; - int fd_epoll; - int fd_display; - - int enable_log; - - struct zwp_input_method_manager_v1 *input_method_mgr; - struct zwp_input_method_v1 *input_method; - struct zwp_input_method_context_v1 *context; - - char *preedit_string; - uint32_t preedit_style; - struct { - xkb_mod_mask_t shift_mask; - } keysym; - uint32_t serial; - uint32_t content_hint; - int32_t content_purpose; - char *preferred_language; - char *surrounding_text; - uint32_t surrounding_cursor; - enum keyboard_state state; //struct keyboard *keyboard; - - //struct zwp_input_panel_surface_v1 *ips; -}; - -struct layout { - const struct key *keys; - uint32_t count; - - uint32_t columns; - uint32_t rows; - - const char *language; - uint32_t text_direction; -}; - -enum key_type { - keytype_default, - keytype_backspace, - keytype_enter, - keytype_space, - keytype_switch, - keytype_symbols, - keytype_tab, - keytype_arrow_up, - keytype_arrow_left, - keytype_arrow_right, - keytype_arrow_down, - keytype_style -}; - -struct key { - enum key_type key_type; - - char *label; - char *uppercase; - char *symbol; - - unsigned int width; -}; - -static const struct key normal_keys[] = { - { keytype_default, "q", "Q", "1", 1}, - { keytype_default, "w", "W", "2", 1}, - { keytype_default, "e", "E", "3", 1}, - { keytype_default, "r", "R", "4", 1}, - { keytype_default, "t", "T", "5", 1}, - { keytype_default, "y", "Y", "6", 1}, - { keytype_default, "u", "U", "7", 1}, - { keytype_default, "i", "I", "8", 1}, - { keytype_default, "o", "O", "9", 1}, - { keytype_default, "p", "P", "0", 1}, - { keytype_backspace, "<--", "<--", "<--", 2}, - - { keytype_tab, "->|", "->|", "->|", 1}, - { keytype_default, "a", "A", "-", 1}, - { keytype_default, "s", "S", "@", 1}, - { keytype_default, "d", "D", "*", 1}, - { keytype_default, "f", "F", "^", 1}, - { keytype_default, "g", "G", ":", 1}, - { keytype_default, "h", "H", ";", 1}, - { keytype_default, "j", "J", "(", 1}, - { keytype_default, "k", "K", ")", 1}, - { keytype_default, "l", "L", "~", 1}, - { keytype_enter, "Enter", "Enter", "Enter", 2}, - - { keytype_switch, "ABC", "abc", "ABC", 2}, - { keytype_default, "z", "Z", "/", 1}, - { keytype_default, "x", "X", "\'", 1}, - { keytype_default, "c", "C", "\"", 1}, - { keytype_default, "v", "V", "+", 1}, - { keytype_default, "b", "B", "=", 1}, - { keytype_default, "n", "N", "?", 1}, - { keytype_default, "m", "M", "!", 1}, - { keytype_default, ",", ",", "\\", 1}, - { keytype_default, ".", ".", "|", 1}, - { keytype_switch, "ABC", "abc", "ABC", 1}, - - { keytype_symbols, "?123", "?123", "abc", 1}, - { keytype_space, "", "", "", 5}, - { keytype_arrow_up, "/\\", "/\\", "/\\", 1}, - { keytype_arrow_left, "<", "<", "<", 1}, - { keytype_arrow_right, ">", ">", ">", 1}, - { keytype_arrow_down, "\\/", "\\/", "\\/", 1}, - { keytype_style, "", "", "", 2} -}; - -static const struct key numeric_keys[] = { - { keytype_default, "1", "1", "1", 1}, - { keytype_default, "2", "2", "2", 1}, - { keytype_default, "3", "3", "3", 1}, - { keytype_default, "4", "4", "4", 1}, - { keytype_default, "5", "5", "5", 1}, - { keytype_default, "6", "6", "6", 1}, - { keytype_default, "7", "7", "7", 1}, - { keytype_default, "8", "8", "8", 1}, - { keytype_default, "9", "9", "9", 1}, - { keytype_default, "0", "0", "0", 1}, - { keytype_backspace, "<--", "<--", "<--", 2}, - - { keytype_space, "", "", "", 4}, - { keytype_enter, "Enter", "Enter", "Enter", 2}, - { keytype_arrow_up, "/\\", "/\\", "/\\", 1}, - { keytype_arrow_left, "<", "<", "<", 1}, - { keytype_arrow_right, ">", ">", ">", 1}, - { keytype_arrow_down, "\\/", "\\/", "\\/", 1}, - { keytype_style, "", "", "", 2} -}; - -static const struct layout normal_layout = { - normal_keys, - sizeof(normal_keys) / sizeof(*normal_keys), - 12, - 4, - "en", - WL_TEXT_INPUT_TEXT_DIRECTION_LTR -}; - -static const struct layout numeric_layout = { - numeric_keys, - sizeof(numeric_keys) / sizeof(*numeric_keys), - 12, - 2, - "en", - WL_TEXT_INPUT_TEXT_DIRECTION_LTR -}; - -struct display data_wl; -static void -request_key(uint32_t time, const struct key *key, enum wl_pointer_button_state state); - -static void -usage(void) -{ - printf(" This is virtual keyboard. (refer to weston/clients/keyboard.c)\n"); - printf("\n"); -} - -static const struct layout * -get_current_layout(void) -{ - switch (data_wl.content_purpose) { - case WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS: - case WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER: - return &numeric_layout; - default: - return &normal_layout; - } -} - -static void -stdin_read(void) -{ - int c; - char buf[MAX_STR] = {0, }, *tmp, *buf_ptr; - int count = 0; - static uint32_t time = 12345; - const struct layout *layout; - uint32_t key_type = 0, key_idx = 0; - - while ((c = getchar()) != EOF) { - if (c == '\n') break; - if (count >= MAX_STR) break; - - buf[count] = c; - count++; - } - - count = 0; - tmp = strtok_r(buf, " ", &buf_ptr); - if (!tmp) return; - - if (!strncmp(buf, "q", MAX_STR) || !strncmp(buf, "quit", MAX_STR)) { - data_wl.run = 0; - } else if (!strncmp(buf, "help", MAX_STR)) { - usage(); - } else if (!strncmp(buf, "log", MAX_STR)) { - if (data_wl.enable_log) - printf("Disable detailed logs\n"); - else - printf("Enable detailed logs\n"); - - data_wl.enable_log = !data_wl.enable_log; - } else if (!strncmp(tmp, "key", MAX_STR)) { - while (tmp) { - tmp = strtok_r(NULL, " ", &buf_ptr); - if (tmp) { - switch (count) { - case 0: - key_idx = atoi(tmp); - break; - case 1: - key_type = atoi(tmp); - break; - default: - break; - } - } - count++; - } - if (data_wl.enable_log) - printf("request key() key_idx:%u, key_type:%u\n", key_idx, key_type); - - layout = get_current_layout(); - request_key(time++, &layout->keys[key_idx], key_type); - - } else { - printf("Invalid arguments\n"); - usage(); - } -} - -static const char * -prev_utf8_char(const char *s, const char *p) -{ - for (--p; p >= s; --p) { - if ((*p & 0xc0) != 0x80) - return p; - } - return NULL; -} - -static void -delete_before_cursor(void) -{ - const char *start, *end; - - if (!data_wl.surrounding_text) { - printf("delete_before_cursor: No surrounding text available\n"); - return; - } - - start = prev_utf8_char(data_wl.surrounding_text, - data_wl.surrounding_text + data_wl.surrounding_cursor); - if (!start) { - printf("delete_before_cursor: No previous character to delete\n"); - return; - } - - end = data_wl.surrounding_text + data_wl.surrounding_cursor; - - zwp_input_method_context_v1_delete_surrounding_text(data_wl.context, - (start - data_wl.surrounding_text) - data_wl.surrounding_cursor, - end - start); - zwp_input_method_context_v1_commit_string(data_wl.context, - data_wl.serial, - ""); - - /* Update surrounding text */ - data_wl.surrounding_cursor = start - data_wl.surrounding_text; - data_wl.surrounding_text[data_wl.surrounding_cursor] = '\0'; - if (*end) - memmove(data_wl.surrounding_text + data_wl.surrounding_cursor, end, strlen(end)); -} - -static char * -append(char *s1, const char *s2) -{ - int len1, len2; - char *s = NULL; - - len1 = strlen(s1); - len2 = strlen(s2); - s = realloc(s1, len1 + len2 + 1); - if (s == NULL) { - printf("alloc fail"); - return NULL; - } - memcpy(s + len1, s2, len2); - s[len1 + len2] = '\0'; - - return s; -} - -static void -request_preedit(int32_t cursor) -{ - printf("request_preedit() preedit_string:%s\n", data_wl.preedit_string); - uint32_t index = strlen(data_wl.preedit_string); - - if (!data_wl.context) return; - - if (data_wl.preedit_style) - zwp_input_method_context_v1_preedit_styling(data_wl.context, - 0, - strlen(data_wl.preedit_string), - data_wl.preedit_style); - if (cursor > 0) - index = cursor; - zwp_input_method_context_v1_preedit_cursor(data_wl.context, - index); - zwp_input_method_context_v1_preedit_string(data_wl.context, - data_wl.serial, - data_wl.preedit_string, - data_wl.preedit_string); -} - -static char * -insert_text(const char *text, uint32_t offset, const char *insert) -{ - int tlen = strlen(text), ilen = strlen(insert); - char *new_text = NULL; - - new_text = malloc(tlen + ilen + 1); - if (new_text == NULL) { - printf("alloc fail"); - return NULL; - } - - memcpy(new_text, text, offset); - memcpy(new_text + offset, insert, ilen); - memcpy(new_text + offset + ilen, text + offset, tlen - offset); - new_text[tlen + ilen] = '\0'; - - return new_text; -} - -static void -request_commit_string(void) -{ - char *surrounding_text; - - printf("request_commit_string()\n"); - - if (!data_wl.preedit_string || - strlen(data_wl.preedit_string) == 0) - return; - printf("request_commit_string() preedit_string:%s\n", data_wl.preedit_string); - - if (!data_wl.context) return; - - zwp_input_method_context_v1_cursor_position(data_wl.context, - 0, 0); - zwp_input_method_context_v1_commit_string(data_wl.context, - data_wl.serial, - data_wl.preedit_string); - - if (data_wl.surrounding_text) { - surrounding_text = insert_text(data_wl.surrounding_text, - data_wl.surrounding_cursor, - data_wl.preedit_string); - free(data_wl.surrounding_text); - data_wl.surrounding_text = surrounding_text; - data_wl.surrounding_cursor += strlen(data_wl.preedit_string); - } else { - data_wl.surrounding_text = strdup(data_wl.preedit_string); - data_wl.surrounding_cursor = strlen(data_wl.preedit_string); - } - - free(data_wl.preedit_string); - data_wl.preedit_string = strdup(""); -} - -static void -request_key(uint32_t time, const struct key *key, enum wl_pointer_button_state state) -{ - const char *label = NULL; - static uint32_t serial = 9999; - - switch(data_wl.state) { - case KEYBOARD_STATE_DEFAULT : - label = key->label; - break; - case KEYBOARD_STATE_UPPERCASE : - label = key->uppercase; - break; - case KEYBOARD_STATE_SYMBOLS : - label = key->symbol; - break; - default : - label = key->label; - break; - } - - xkb_mod_mask_t mod_mask = data_wl.state == KEYBOARD_STATE_DEFAULT ? 0 : data_wl.keysym.shift_mask; - uint32_t key_state = (state == WL_POINTER_BUTTON_STATE_PRESSED) ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED; - - printf("request_key() data_wl.state:%d, key->key_type:%d, pressed:%u, label:%s\n", data_wl.state, key->key_type, key_state, label); - switch (key->key_type) { - case keytype_default: - if (state != WL_POINTER_BUTTON_STATE_PRESSED) - break; - - printf("request_key() keytype_default. append label(%s) to preedit_string(%s)\n", label, data_wl.preedit_string); - data_wl.preedit_string = - append(data_wl.preedit_string, - label); - request_preedit(-1); - break; - case keytype_backspace: - if (state != WL_POINTER_BUTTON_STATE_PRESSED) - break; - - if (strlen(data_wl.preedit_string) == 0) { - delete_before_cursor(); - } else { - data_wl.preedit_string[strlen(data_wl.preedit_string) - 1] = '\0'; - request_preedit(-1); - } - break; - case keytype_enter: - request_commit_string(); - - if (!data_wl.context) break; - zwp_input_method_context_v1_keysym(data_wl.context, - serial++, - time, - XKB_KEY_Return, key_state, mod_mask); - break; - case keytype_space: - if (state != WL_POINTER_BUTTON_STATE_PRESSED) - break; - data_wl.preedit_string = - append(data_wl.preedit_string, " "); - request_commit_string(); - break; - case keytype_switch: - if (state != WL_POINTER_BUTTON_STATE_PRESSED) - break; - switch(data_wl.state) { - case KEYBOARD_STATE_DEFAULT: - data_wl.state = KEYBOARD_STATE_UPPERCASE; - break; - case KEYBOARD_STATE_UPPERCASE: - data_wl.state = KEYBOARD_STATE_DEFAULT; - break; - case KEYBOARD_STATE_SYMBOLS: - data_wl.state = KEYBOARD_STATE_UPPERCASE; - break; - } - break; - case keytype_symbols: - if (state != WL_POINTER_BUTTON_STATE_PRESSED) - break; - switch(data_wl.state) { - case KEYBOARD_STATE_DEFAULT: - data_wl.state = KEYBOARD_STATE_SYMBOLS; - break; - case KEYBOARD_STATE_UPPERCASE: - data_wl.state = KEYBOARD_STATE_SYMBOLS; - break; - case KEYBOARD_STATE_SYMBOLS: - data_wl.state = KEYBOARD_STATE_DEFAULT; - break; - } - break; - case keytype_tab: - request_commit_string(); - if (!data_wl.context) break; - zwp_input_method_context_v1_keysym(data_wl.context, - serial++, - time, - XKB_KEY_Tab, key_state, mod_mask); - break; - case keytype_arrow_up: - request_commit_string(); - if (!data_wl.context) break; - zwp_input_method_context_v1_keysym(data_wl.context, - serial++, - time, - XKB_KEY_Up, key_state, mod_mask); - break; - case keytype_arrow_left: - request_commit_string(); - if (!data_wl.context) break; - zwp_input_method_context_v1_keysym(data_wl.context, - serial++, - time, - XKB_KEY_Left, key_state, mod_mask); - break; - case keytype_arrow_right: - request_commit_string(); - if (!data_wl.context) break; - zwp_input_method_context_v1_keysym(data_wl.context, - serial++, - time, - XKB_KEY_Right, key_state, mod_mask); - break; - case keytype_arrow_down: - request_commit_string(); - if (!data_wl.context) break; - zwp_input_method_context_v1_keysym(data_wl.context, - serial++, - time, - XKB_KEY_Down, key_state, mod_mask); - break; - case keytype_style: - if (state != WL_POINTER_BUTTON_STATE_PRESSED) - break; - data_wl.preedit_style = (data_wl.preedit_style + 1) % 8; /* TODO */ - request_preedit(-1); - break; - } -} - -static void -im_context_cb_surrounding_text (void *data, struct zwp_input_method_context_v1 *im_ctx, const char *text, uint32_t cursor, uint32_t anchor) -{ - printf("im_context_cb_surrounding_text\n"); - free(data_wl.surrounding_text); - data_wl.surrounding_text = strdup(text); - - data_wl.surrounding_cursor = cursor; -} - -static void -im_context_cb_reset (void *data, struct zwp_input_method_context_v1 *im_ctx) -{ - printf("im_context_cb_reset\n"); - - if (strlen(data_wl.preedit_string)) { - free(data_wl.preedit_string); - data_wl.preedit_string = strdup(""); - } -} - -static void -im_context_cb_content_type (void *data, struct zwp_input_method_context_v1 *im_ctx, uint32_t hint, uint32_t purpose) -{ - printf("im_context_cb_content_type\n"); - - data_wl.content_hint = hint; - data_wl.content_purpose = purpose; -} - -static void -im_context_cb_invoke_action (void *data, struct zwp_input_method_context_v1 *im_ctx, uint32_t button, uint32_t index) -{ - printf("im_context_cb_invoke_action\n"); - - if (button != BTN_LEFT) - return; - - request_preedit(index); -} - -static void -im_context_cb_commit_state (void *data, struct zwp_input_method_context_v1 *context, uint32_t serial) -{ - printf("im_context_cb_commit_state\n"); - - const struct layout *layout; - - data_wl.serial = serial; - - layout = get_current_layout(); - - if (data_wl.surrounding_text) - printf("Surrounding text updated: %s\n", data_wl.surrounding_text); - - if (!context) return; - zwp_input_method_context_v1_language(context, - data_wl.serial, - layout->language); - zwp_input_method_context_v1_text_direction(context, - data_wl.serial, - layout->text_direction); -} - -static void -im_context_cb_preferred_language (void *data, struct zwp_input_method_context_v1 *context, const char *language) -{ - printf("im_context_cb_preferred_language\n"); - - if (data_wl.preferred_language) - free(data_wl.preferred_language); - - data_wl.preferred_language = NULL; - - if (language) - data_wl.preferred_language = strdup(language); -} - -static const struct zwp_input_method_context_v1_listener input_method_context_cb_listener = { - .surrounding_text = im_context_cb_surrounding_text, - .reset = im_context_cb_reset, - .content_type = im_context_cb_content_type, - .invoke_action = im_context_cb_invoke_action, - .commit_state = im_context_cb_commit_state, - .preferred_language = im_context_cb_preferred_language, - //for tizen only - .return_key_type = NULL, - .return_key_disabled = NULL, - .input_panel_data = NULL, - .bidi_direction = NULL, - .cursor_position = NULL, - .process_input_device_event = NULL, - .filter_key_event = NULL, - .capital_mode = NULL, - .prediction_hint = NULL, - .mime_type = NULL, - .finalized_content = NULL, - .prediction_hint_data = NULL, - .input_panel_enabled = NULL, -}; - -static void -keysym_modifiers_add(struct wl_array *modifiers_map, - const char *name) -{ - size_t len = strlen(name) + 1; - char *p; - - p = wl_array_add(modifiers_map, len); - - if (p == NULL) - return; - - strncpy(p, name, len); -} - -static xkb_mod_index_t -keysym_modifiers_get_index(struct wl_array *modifiers_map, - const char *name) -{ - xkb_mod_index_t index = 0; - char *p = modifiers_map->data; - - while ((const char *)p < (const char *)(modifiers_map->data + modifiers_map->size)) { - if (strcmp(p, name) == 0) - return index; - - index++; - p += strlen(p) + 1; - } - - return XKB_MOD_INVALID; -} - -xkb_mod_mask_t -keysym_modifiers_get_mask(struct wl_array *modifiers_map, - const char *name) -{ - xkb_mod_index_t index = keysym_modifiers_get_index(modifiers_map, name); - - if (index == XKB_MOD_INVALID) - return XKB_MOD_INVALID; - - return 1 << index; -} - -static void -im_cb_activate (void *data, struct zwp_input_method_v1 *input_method, struct zwp_input_method_context_v1 *context) -{ - printf("im_cb_activate\n"); - - struct wl_array modifiers_map; - const struct layout *layout; - - if (data_wl.context) - zwp_input_method_context_v1_destroy(data_wl.context); - - if (data_wl.preedit_string) - free(data_wl.preedit_string); - - data_wl.preedit_style = 0; - data_wl.preedit_string = strdup(""); - data_wl.content_hint = 0; - data_wl.content_purpose = 0; - free(data_wl.preferred_language); - data_wl.preferred_language = NULL; - free(data_wl.surrounding_text); - data_wl.surrounding_text = NULL; - - data_wl.serial = 0; - - data_wl.context = context; - zwp_input_method_context_v1_add_listener(context, - &input_method_context_cb_listener, - NULL); - - wl_array_init(&modifiers_map); - keysym_modifiers_add(&modifiers_map, "Shift"); - keysym_modifiers_add(&modifiers_map, "Control"); - keysym_modifiers_add(&modifiers_map, "Mod1"); - zwp_input_method_context_v1_modifiers_map(context, &modifiers_map); - data_wl.keysym.shift_mask = keysym_modifiers_get_mask(&modifiers_map, "Shift"); - wl_array_release(&modifiers_map); - - layout = get_current_layout(); - - zwp_input_method_context_v1_language(context, - data_wl.serial, - layout->language); - zwp_input_method_context_v1_text_direction(context, - data_wl.serial, - layout->text_direction); -} -static void -im_cb_deactivate (void *data, struct zwp_input_method_v1 *input_method, struct zwp_input_method_context_v1 *im_ctx) -{ - printf("im_cb_deactivate\n"); - - if (!data_wl.context) - return; - - zwp_input_method_context_v1_destroy(data_wl.context); - data_wl.context = NULL; -} - -static void -im_cb_destroy (void *data, struct zwp_input_method_v1 *input_method, struct zwp_input_method_context_v1 *im_ctx) -{ - printf("im_cb_destroy\n"); - zwp_input_method_v1_destroy(data_wl.input_method); - data_wl.input_method = NULL; -} - -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 = NULL, - .hide_input_panel = NULL, - .open_connection = NULL, - .close_connection = NULL, - .set_text_input_id = NULL, -}; - -static void -registry_handle_global(void * data, struct wl_registry * registry, uint32_t id, - const char * interface, uint32_t version) -{ - if (strcmp(interface, "wl_compositor") == 0) { - data_wl.compositor = wl_registry_bind(registry, id, - &wl_compositor_interface, version); - if (!data_wl.compositor) { - printf("Failed to bind compositor.\n"); - return; - } - if (data_wl.enable_log) - printf("Success to bind compositor.\n"); - } else if (!strcmp(interface, "zwp_input_method_manager_v1")) { - data_wl.input_method_mgr = wl_registry_bind(registry, id, - &zwp_input_method_manager_v1_interface, version); - } else if (!strcmp(interface, "zwp_input_method_v1")) { - data_wl.input_method = wl_registry_bind(registry, id, - &zwp_input_method_v1_interface, version); - zwp_input_method_v1_add_listener(data_wl.input_method, - &input_method_cb_listener, - NULL); - - //TODO: delte this code. this job should be done in cb_activate - data_wl.preedit_string = strdup(""); - data_wl.content_hint = 0; - data_wl.content_purpose = 0; - free(data_wl.preferred_language); - data_wl.preferred_language = NULL; - free(data_wl.surrounding_text); - data_wl.surrounding_text = NULL; - data_wl.serial = 0; - } -} - -static void -registry_handle_global_remove(void * data, struct wl_registry * registry, uint32_t id) -{ - if (data_wl.enable_log) - printf("registry is removed. id: %d !\n", id); -} - -static const struct wl_registry_listener _registry_listener = { - registry_handle_global, - registry_handle_global_remove -}; - -static int -wayland_init(void) -{ - memset(&data_wl, 0, sizeof(struct display)); - - data_wl.display = wl_display_connect(NULL); - if (!data_wl.display) { - printf("Failed to connect wayland display\n"); - return 0; - } - - data_wl.queue = wl_display_create_queue(data_wl.display); - if (!data_wl.queue) { - printf("Failed to create queue\n"); - return 0; - } - - data_wl.registry = wl_display_get_registry(data_wl.display); - if (!data_wl.registry) { - printf("Failed to get registry\n"); - return 0; - } - - wl_proxy_set_queue((struct wl_proxy*)data_wl.registry, data_wl.queue); - wl_registry_add_listener(data_wl.registry, &_registry_listener, NULL); - - if (wl_display_dispatch_queue(data_wl.display, data_wl.queue) == -1) { - printf("Failed to dispatch display\n"); - return 0; - } - if (wl_display_roundtrip_queue(data_wl.display, data_wl.queue) == -1) { - printf("Failed to roundtrip display\n"); - return 0; - } - - return 1; -} - -static void -wayland_deinit(void) -{ - if (data_wl.enable_log) - printf("Shutdown wayland system\n"); - - if (data_wl.queue) wl_event_queue_destroy(data_wl.queue); - if (data_wl.display) { - if (data_wl.input_method) - zwp_input_method_v1_destroy(data_wl.input_method); - zwp_input_method_manager_v1_destroy(data_wl.input_method_mgr); - wl_registry_destroy(data_wl.registry); - wl_display_flush(data_wl.display); - wl_display_disconnect(data_wl.display); - } -} - -static int -epoll_init(void) -{ - struct epoll_event ep[2]; - - data_wl.fd_epoll = epoll_create(SIZE_EPOLL); - if (data_wl.fd_epoll <= 0) { - printf("Failed to epoll create: %d\n", SIZE_EPOLL); - return 0; - } - - data_wl.fd_display = wl_display_get_fd(data_wl.display); - - memset(ep, 0, sizeof(struct epoll_event)*2); - - ep[0].events = EPOLLIN | EPOLLERR | EPOLLHUP; - ep[0].data.fd = data_wl.fd_display; - epoll_ctl(data_wl.fd_epoll, EPOLL_CTL_ADD, data_wl.fd_display, &ep[0]); - ep[1].events = EPOLLIN | EPOLLERR | EPOLLHUP; - ep[1].data.fd = STDIN_FILENO; - epoll_ctl(data_wl.fd_epoll, EPOLL_CTL_ADD, 0, &ep[1]); - - return 1; -} - -static void -mainloop(void) -{ - struct epoll_event ep[SIZE_EPOLL]; - int res, count, i; - - res = epoll_init(); - if (!res) { - printf("Failed to init epoll\n"); - return; - } - - data_wl.run = 1; - while (data_wl.run) { - res = wl_display_dispatch_queue_pending(data_wl.display, data_wl.queue); - if (res < 0) { - printf("Failed to dispatch pending. result: %d\n", res); - data_wl.run = 0; - break; - } - res = wl_display_flush(data_wl.display); - if (res < 0) { - printf("Failed to flush display. result: %d\n", res); - data_wl.run = 0; - break; - } - - count = epoll_wait(data_wl.fd_epoll, ep, SIZE_EPOLL, -1); - for (i = 0; i < count; i++) { - if (ep[i].events & EPOLLIN) { - if (ep[i].data.fd == data_wl.fd_display) { - wl_display_dispatch_queue(data_wl.display, data_wl.queue); - } else { - stdin_read(); - } - } - if (ep[i].events & EPOLLERR) { - data_wl.run = 0; - } - if (ep[i].events & EPOLLHUP) { - data_wl.run = 0; - } - } - } -} - -int -main(int argc, char **argv) -{ - int res; - - res = wayland_init(); - if (!res) return 0; - - mainloop(); - - wayland_deinit(); - - return 0; -} diff --git a/clients/input-generator.c b/clients/input-generator.c index 73b7ab4..cfa1800 100644 --- a/clients/input-generator.c +++ b/clients/input-generator.c @@ -5,11 +5,22 @@ #include #include +#include +//#include + +#include +#include #include #define MAX_STR 1024 #define SIZE_EPOLL 16 +enum keyboard_state { + KEYBOARD_STATE_DEFAULT, + KEYBOARD_STATE_UPPERCASE, + KEYBOARD_STATE_SYMBOLS +}; + enum enum_key_type { KEY_UP = 0, @@ -43,11 +54,158 @@ struct display int init; int enable_log; + + struct zwp_input_method_manager_v1 *input_method_mgr; + struct zwp_input_method_v1 *input_method; + struct zwp_input_method_context_v1 *context; + + char *preedit_string; + uint32_t preedit_style; + struct { + xkb_mod_mask_t shift_mask; + } keysym; + uint32_t serial; + uint32_t content_hint; + int32_t content_purpose; + char *preferred_language; + char *surrounding_text; + uint32_t surrounding_cursor; + enum keyboard_state state; //struct keyboard *keyboard; + + //struct zwp_input_panel_surface_v1 *ips; +}; + +struct layout { + const struct key *keys; + uint32_t count; + + uint32_t columns; + uint32_t rows; + + const char *language; + uint32_t text_direction; +}; + +enum key_type { + keytype_default, + keytype_backspace, + keytype_enter, + keytype_space, + keytype_switch, + keytype_symbols, + keytype_tab, + keytype_arrow_up, + keytype_arrow_left, + keytype_arrow_right, + keytype_arrow_down, + keytype_style +}; + +struct key { + enum key_type key_type; + + char *label; + char *uppercase; + char *symbol; + + unsigned int width; +}; + +static const struct key normal_keys[] = { + { keytype_default, "q", "Q", "1", 1}, + { keytype_default, "w", "W", "2", 1}, + { keytype_default, "e", "E", "3", 1}, + { keytype_default, "r", "R", "4", 1}, + { keytype_default, "t", "T", "5", 1}, + { keytype_default, "y", "Y", "6", 1}, + { keytype_default, "u", "U", "7", 1}, + { keytype_default, "i", "I", "8", 1}, + { keytype_default, "o", "O", "9", 1}, + { keytype_default, "p", "P", "0", 1}, + { keytype_backspace, "<--", "<--", "<--", 2}, + + { keytype_tab, "->|", "->|", "->|", 1}, + { keytype_default, "a", "A", "-", 1}, + { keytype_default, "s", "S", "@", 1}, + { keytype_default, "d", "D", "*", 1}, + { keytype_default, "f", "F", "^", 1}, + { keytype_default, "g", "G", ":", 1}, + { keytype_default, "h", "H", ";", 1}, + { keytype_default, "j", "J", "(", 1}, + { keytype_default, "k", "K", ")", 1}, + { keytype_default, "l", "L", "~", 1}, + { keytype_enter, "Enter", "Enter", "Enter", 2}, + + { keytype_switch, "ABC", "abc", "ABC", 2}, + { keytype_default, "z", "Z", "/", 1}, + { keytype_default, "x", "X", "\'", 1}, + { keytype_default, "c", "C", "\"", 1}, + { keytype_default, "v", "V", "+", 1}, + { keytype_default, "b", "B", "=", 1}, + { keytype_default, "n", "N", "?", 1}, + { keytype_default, "m", "M", "!", 1}, + { keytype_default, ",", ",", "\\", 1}, + { keytype_default, ".", ".", "|", 1}, + { keytype_switch, "ABC", "abc", "ABC", 1}, + + { keytype_symbols, "?123", "?123", "abc", 1}, + { keytype_space, "", "", "", 5}, + { keytype_arrow_up, "/\\", "/\\", "/\\", 1}, + { keytype_arrow_left, "<", "<", "<", 1}, + { keytype_arrow_right, ">", ">", ">", 1}, + { keytype_arrow_down, "\\/", "\\/", "\\/", 1}, + { keytype_style, "", "", "", 2} +}; + +static const struct key numeric_keys[] = { + { keytype_default, "1", "1", "1", 1}, + { keytype_default, "2", "2", "2", 1}, + { keytype_default, "3", "3", "3", 1}, + { keytype_default, "4", "4", "4", 1}, + { keytype_default, "5", "5", "5", 1}, + { keytype_default, "6", "6", "6", 1}, + { keytype_default, "7", "7", "7", 1}, + { keytype_default, "8", "8", "8", 1}, + { keytype_default, "9", "9", "9", 1}, + { keytype_default, "0", "0", "0", 1}, + { keytype_backspace, "<--", "<--", "<--", 2}, + + { keytype_space, "", "", "", 4}, + { keytype_enter, "Enter", "Enter", "Enter", 2}, + { keytype_arrow_up, "/\\", "/\\", "/\\", 1}, + { keytype_arrow_left, "<", "<", "<", 1}, + { keytype_arrow_right, ">", ">", ">", 1}, + { keytype_arrow_down, "\\/", "\\/", "\\/", 1}, + { keytype_style, "", "", "", 2} +}; + +static const struct layout normal_layout = { + normal_keys, + sizeof(normal_keys) / sizeof(*normal_keys), + 12, + 4, + "en", + WL_TEXT_INPUT_TEXT_DIRECTION_LTR +}; + +static const struct layout numeric_layout = { + numeric_keys, + sizeof(numeric_keys) / sizeof(*numeric_keys), + 12, + 2, + "en", + WL_TEXT_INPUT_TEXT_DIRECTION_LTR }; struct display data_wl; static void +request_key(uint32_t time, const struct key *key, enum wl_keyboard_key_state state); + +static const struct layout * +get_current_layout(void); + +static void usage(void) { printf(" Supported commands: init (Initialize input generator)\n"); @@ -104,6 +262,13 @@ usage(void) printf(" : mouse 1 1 10 10\n"); printf(" : mouse 1 1 -10 -10\n"); printf(" : mouse 1 2 0 0\n"); + printf("ime {key_idx} {type}\n"); + printf(" : key_index\n"); + printf(" : - keys = [q,w,e,r,t,,,]\n"); + printf(" : type:\n"); + printf(" : - default: down & up\n"); + printf(" : - down: 1\n"); + printf(" : - up: 0\n"); printf("\n"); } @@ -305,6 +470,8 @@ stdin_read(void) char buf[MAX_STR] = {0, }, *tmp, *buf_ptr, key_name[MAX_STR] = {0, }; int count = 0; int key_type = KEY_ALL, idx = 0, type = POINTER_ALL, x = 0, y = 0; + static uint32_t time = 12345; + const struct layout *layout; while ((c = getchar()) != EOF) { if (c == '\n') break; @@ -405,6 +572,33 @@ stdin_read(void) count++; } mouse_generate(idx, type, x, y); + } else if (!strncmp(tmp, "ime", MAX_STR)) { + while (tmp) { + tmp = strtok_r(NULL, " ", &buf_ptr); + if (tmp) { + switch (count) { + case 0: + idx = atoi(tmp); + break; + case 1: + key_type = atoi(tmp); + break; + default: + break; + } + } + count++; + } + if (data_wl.enable_log) + printf("request key() key_idx:%u, key_type:%u\n", idx, key_type); + + layout = get_current_layout(); + if (key_type == KEY_ALL) { + request_key(time++, &layout->keys[idx], WL_KEYBOARD_KEY_STATE_PRESSED); + request_key(time++, &layout->keys[idx], WL_KEYBOARD_KEY_STATE_RELEASED); + } + else + request_key(time++, &layout->keys[idx], key_type); } else if (!strncmp(buf, "q", MAX_STR) || !strncmp(buf, "quit", MAX_STR)) { data_wl.run = 0; } else if (!strncmp(buf, "help", MAX_STR)) { @@ -440,6 +634,526 @@ static const struct tizen_input_device_manager_listener _input_device_manager_li .block_expired = NULL, }; +static const struct layout * +get_current_layout(void) +{ + switch (data_wl.content_purpose) { + case WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS: + case WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER: + return &numeric_layout; + default: + return &normal_layout; + } +} + +static const char * +prev_utf8_char(const char *s, const char *p) +{ + for (--p; p >= s; --p) { + if ((*p & 0xc0) != 0x80) + return p; + } + return NULL; +} + +static void +delete_before_cursor(void) +{ + const char *start, *end; + + if (!data_wl.surrounding_text) { + printf("delete_before_cursor: No surrounding text available\n"); + return; + } + + start = prev_utf8_char(data_wl.surrounding_text, + data_wl.surrounding_text + data_wl.surrounding_cursor); + if (!start) { + printf("delete_before_cursor: No previous character to delete\n"); + return; + } + + end = data_wl.surrounding_text + data_wl.surrounding_cursor; + + zwp_input_method_context_v1_delete_surrounding_text(data_wl.context, + (start - data_wl.surrounding_text) - data_wl.surrounding_cursor, + end - start); + zwp_input_method_context_v1_commit_string(data_wl.context, + data_wl.serial, + ""); + + /* Update surrounding text */ + data_wl.surrounding_cursor = start - data_wl.surrounding_text; + data_wl.surrounding_text[data_wl.surrounding_cursor] = '\0'; + if (*end) + memmove(data_wl.surrounding_text + data_wl.surrounding_cursor, end, strlen(end)); +} + +static char * +append(char *s1, const char *s2) +{ + int len1, len2; + char *s = NULL; + + len1 = strlen(s1); + len2 = strlen(s2); + s = realloc(s1, len1 + len2 + 1); + if (s == NULL) { + printf("alloc fail"); + return NULL; + } + memcpy(s + len1, s2, len2); + s[len1 + len2] = '\0'; + + return s; +} + +static void +request_preedit(int32_t cursor) +{ + printf("request_preedit() preedit_string:%s\n", data_wl.preedit_string); + uint32_t index = strlen(data_wl.preedit_string); + + if (!data_wl.context) return; + + if (data_wl.preedit_style) + zwp_input_method_context_v1_preedit_styling(data_wl.context, + 0, + strlen(data_wl.preedit_string), + data_wl.preedit_style); + if (cursor > 0) + index = cursor; + zwp_input_method_context_v1_preedit_cursor(data_wl.context, + index); + zwp_input_method_context_v1_preedit_string(data_wl.context, + data_wl.serial, + data_wl.preedit_string, + data_wl.preedit_string); +} + +static char * +insert_text(const char *text, uint32_t offset, const char *insert) +{ + int tlen = strlen(text), ilen = strlen(insert); + char *new_text = NULL; + + new_text = malloc(tlen + ilen + 1); + if (new_text == NULL) { + printf("alloc fail"); + return NULL; + } + + memcpy(new_text, text, offset); + memcpy(new_text + offset, insert, ilen); + memcpy(new_text + offset + ilen, text + offset, tlen - offset); + new_text[tlen + ilen] = '\0'; + + return new_text; +} + +static void +request_commit_string(void) +{ + char *surrounding_text; + + printf("request_commit_string()\n"); + + if (!data_wl.preedit_string || + strlen(data_wl.preedit_string) == 0) + return; + printf("request_commit_string() preedit_string:%s\n", data_wl.preedit_string); + + if (!data_wl.context) return; + + zwp_input_method_context_v1_cursor_position(data_wl.context, + 0, 0); + zwp_input_method_context_v1_commit_string(data_wl.context, + data_wl.serial, + data_wl.preedit_string); + + if (data_wl.surrounding_text) { + surrounding_text = insert_text(data_wl.surrounding_text, + data_wl.surrounding_cursor, + data_wl.preedit_string); + free(data_wl.surrounding_text); + data_wl.surrounding_text = surrounding_text; + data_wl.surrounding_cursor += strlen(data_wl.preedit_string); + } else { + data_wl.surrounding_text = strdup(data_wl.preedit_string); + data_wl.surrounding_cursor = strlen(data_wl.preedit_string); + } + + free(data_wl.preedit_string); + data_wl.preedit_string = strdup(""); +} + +static void +request_key(uint32_t time, const struct key *key, enum wl_keyboard_key_state state) +{ + const char *label = NULL; + static uint32_t serial = 9999; + + switch(data_wl.state) { + case KEYBOARD_STATE_DEFAULT : + label = key->label; + break; + case KEYBOARD_STATE_UPPERCASE : + label = key->uppercase; + break; + case KEYBOARD_STATE_SYMBOLS : + label = key->symbol; + break; + default : + label = key->label; + break; + } + + xkb_mod_mask_t mod_mask = data_wl.state == KEYBOARD_STATE_DEFAULT ? 0 : data_wl.keysym.shift_mask; + uint32_t key_state = (state == WL_KEYBOARD_KEY_STATE_PRESSED) ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED; + + printf("request_key() data_wl.state:%d, key->key_type:%d, pressed:%u, label:%s\n", data_wl.state, key->key_type, key_state, label); + switch (key->key_type) { + case keytype_default: + if (state != WL_KEYBOARD_KEY_STATE_PRESSED) + break; + + printf("request_key() keytype_default. append label(%s) to preedit_string(%s)\n", label, data_wl.preedit_string); + data_wl.preedit_string = + append(data_wl.preedit_string, + label); + request_preedit(-1); + break; + case keytype_backspace: + if (state != WL_KEYBOARD_KEY_STATE_PRESSED) + break; + + if (strlen(data_wl.preedit_string) == 0) { + delete_before_cursor(); + } else { + data_wl.preedit_string[strlen(data_wl.preedit_string) - 1] = '\0'; + request_preedit(-1); + } + break; + case keytype_enter: + request_commit_string(); + + if (!data_wl.context) break; + zwp_input_method_context_v1_keysym(data_wl.context, + serial++, + time, + XKB_KEY_Return, key_state, mod_mask); + break; + case keytype_space: + if (state != WL_KEYBOARD_KEY_STATE_PRESSED) + break; + data_wl.preedit_string = + append(data_wl.preedit_string, " "); + request_commit_string(); + break; + case keytype_switch: + if (state != WL_KEYBOARD_KEY_STATE_PRESSED) + break; + switch(data_wl.state) { + case KEYBOARD_STATE_DEFAULT: + data_wl.state = KEYBOARD_STATE_UPPERCASE; + break; + case KEYBOARD_STATE_UPPERCASE: + data_wl.state = KEYBOARD_STATE_DEFAULT; + break; + case KEYBOARD_STATE_SYMBOLS: + data_wl.state = KEYBOARD_STATE_UPPERCASE; + break; + } + break; + case keytype_symbols: + if (state != WL_KEYBOARD_KEY_STATE_PRESSED) + break; + switch(data_wl.state) { + case KEYBOARD_STATE_DEFAULT: + data_wl.state = KEYBOARD_STATE_SYMBOLS; + break; + case KEYBOARD_STATE_UPPERCASE: + data_wl.state = KEYBOARD_STATE_SYMBOLS; + break; + case KEYBOARD_STATE_SYMBOLS: + data_wl.state = KEYBOARD_STATE_DEFAULT; + break; + } + break; + case keytype_tab: + request_commit_string(); + if (!data_wl.context) break; + zwp_input_method_context_v1_keysym(data_wl.context, + serial++, + time, + XKB_KEY_Tab, key_state, mod_mask); + break; + case keytype_arrow_up: + request_commit_string(); + if (!data_wl.context) break; + zwp_input_method_context_v1_keysym(data_wl.context, + serial++, + time, + XKB_KEY_Up, key_state, mod_mask); + break; + case keytype_arrow_left: + request_commit_string(); + if (!data_wl.context) break; + zwp_input_method_context_v1_keysym(data_wl.context, + serial++, + time, + XKB_KEY_Left, key_state, mod_mask); + break; + case keytype_arrow_right: + request_commit_string(); + if (!data_wl.context) break; + zwp_input_method_context_v1_keysym(data_wl.context, + serial++, + time, + XKB_KEY_Right, key_state, mod_mask); + break; + case keytype_arrow_down: + request_commit_string(); + if (!data_wl.context) break; + zwp_input_method_context_v1_keysym(data_wl.context, + serial++, + time, + XKB_KEY_Down, key_state, mod_mask); + break; + case keytype_style: + if (state != WL_KEYBOARD_KEY_STATE_PRESSED) + break; + data_wl.preedit_style = (data_wl.preedit_style + 1) % 8; /* TODO */ + request_preedit(-1); + break; + } +} + +static void +im_context_cb_surrounding_text (void *data, struct zwp_input_method_context_v1 *im_ctx, const char *text, uint32_t cursor, uint32_t anchor) +{ + printf("im_context_cb_surrounding_text\n"); + free(data_wl.surrounding_text); + data_wl.surrounding_text = strdup(text); + + data_wl.surrounding_cursor = cursor; +} + +static void +im_context_cb_reset (void *data, struct zwp_input_method_context_v1 *im_ctx) +{ + printf("im_context_cb_reset\n"); + + if (strlen(data_wl.preedit_string)) { + free(data_wl.preedit_string); + data_wl.preedit_string = strdup(""); + } +} + +static void +im_context_cb_content_type (void *data, struct zwp_input_method_context_v1 *im_ctx, uint32_t hint, uint32_t purpose) +{ + printf("im_context_cb_content_type\n"); + + data_wl.content_hint = hint; + data_wl.content_purpose = purpose; +} + +static void +im_context_cb_invoke_action (void *data, struct zwp_input_method_context_v1 *im_ctx, uint32_t button, uint32_t index) +{ + printf("im_context_cb_invoke_action\n"); + + //if (button != BTN_LEFT) + // return; + + request_preedit(index); +} + +static void +im_context_cb_commit_state (void *data, struct zwp_input_method_context_v1 *context, uint32_t serial) +{ + printf("im_context_cb_commit_state\n"); + + const struct layout *layout; + + data_wl.serial = serial; + + layout = get_current_layout(); + + if (data_wl.surrounding_text) + printf("Surrounding text updated: %s\n", data_wl.surrounding_text); + + if (!context) return; + zwp_input_method_context_v1_language(context, + data_wl.serial, + layout->language); + zwp_input_method_context_v1_text_direction(context, + data_wl.serial, + layout->text_direction); +} + +static void +im_context_cb_preferred_language (void *data, struct zwp_input_method_context_v1 *context, const char *language) +{ + printf("im_context_cb_preferred_language\n"); + + if (data_wl.preferred_language) + free(data_wl.preferred_language); + + data_wl.preferred_language = NULL; + + if (language) + data_wl.preferred_language = strdup(language); +} + +static const struct zwp_input_method_context_v1_listener input_method_context_cb_listener = { + .surrounding_text = im_context_cb_surrounding_text, + .reset = im_context_cb_reset, + .content_type = im_context_cb_content_type, + .invoke_action = im_context_cb_invoke_action, + .commit_state = im_context_cb_commit_state, + .preferred_language = im_context_cb_preferred_language, + //for tizen only + .return_key_type = NULL, + .return_key_disabled = NULL, + .input_panel_data = NULL, + .bidi_direction = NULL, + .cursor_position = NULL, + .process_input_device_event = NULL, + .filter_key_event = NULL, + .capital_mode = NULL, + .prediction_hint = NULL, + .mime_type = NULL, + .finalized_content = NULL, + .prediction_hint_data = NULL, + .input_panel_enabled = NULL, +}; + +static void +keysym_modifiers_add(struct wl_array *modifiers_map, + const char *name) +{ + size_t len = strlen(name) + 1; + char *p; + + p = wl_array_add(modifiers_map, len); + + if (p == NULL) + return; + + strncpy(p, name, len); +} + +static xkb_mod_index_t +keysym_modifiers_get_index(struct wl_array *modifiers_map, + const char *name) +{ + xkb_mod_index_t index = 0; + char *p = modifiers_map->data; + + while ((const char *)p < (const char *)(modifiers_map->data + modifiers_map->size)) { + if (strcmp(p, name) == 0) + return index; + + index++; + p += strlen(p) + 1; + } + + return XKB_MOD_INVALID; +} + +static xkb_mod_mask_t +keysym_modifiers_get_mask(struct wl_array *modifiers_map, + const char *name) +{ + xkb_mod_index_t index = keysym_modifiers_get_index(modifiers_map, name); + + if (index == XKB_MOD_INVALID) + return XKB_MOD_INVALID; + + return 1 << index; +} + +static void +im_cb_activate (void *data, struct zwp_input_method_v1 *input_method, struct zwp_input_method_context_v1 *context) +{ + printf("im_cb_activate\n"); + + struct wl_array modifiers_map; + const struct layout *layout; + + if (data_wl.context) + zwp_input_method_context_v1_destroy(data_wl.context); + + if (data_wl.preedit_string) + free(data_wl.preedit_string); + + data_wl.preedit_style = 0; + data_wl.preedit_string = strdup(""); + data_wl.content_hint = 0; + data_wl.content_purpose = 0; + free(data_wl.preferred_language); + data_wl.preferred_language = NULL; + free(data_wl.surrounding_text); + data_wl.surrounding_text = NULL; + + data_wl.serial = 0; + + data_wl.context = context; + zwp_input_method_context_v1_add_listener(context, + &input_method_context_cb_listener, + NULL); + + wl_array_init(&modifiers_map); + keysym_modifiers_add(&modifiers_map, "Shift"); + keysym_modifiers_add(&modifiers_map, "Control"); + keysym_modifiers_add(&modifiers_map, "Mod1"); + zwp_input_method_context_v1_modifiers_map(context, &modifiers_map); + data_wl.keysym.shift_mask = keysym_modifiers_get_mask(&modifiers_map, "Shift"); + wl_array_release(&modifiers_map); + + layout = get_current_layout(); + + zwp_input_method_context_v1_language(context, + data_wl.serial, + layout->language); + zwp_input_method_context_v1_text_direction(context, + data_wl.serial, + layout->text_direction); +} +static void +im_cb_deactivate (void *data, struct zwp_input_method_v1 *input_method, struct zwp_input_method_context_v1 *im_ctx) +{ + printf("im_cb_deactivate\n"); + + if (!data_wl.context) + return; + + zwp_input_method_context_v1_destroy(data_wl.context); + data_wl.context = NULL; +} + +static void +im_cb_destroy (void *data, struct zwp_input_method_v1 *input_method, struct zwp_input_method_context_v1 *im_ctx) +{ + printf("im_cb_destroy\n"); + zwp_input_method_v1_destroy(data_wl.input_method); + data_wl.input_method = NULL; +} + +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 = NULL, + .hide_input_panel = NULL, + .open_connection = NULL, + .close_connection = NULL, + .set_text_input_id = NULL, +}; + static void registry_handle_global(void * data, struct wl_registry * registry, uint32_t id, const char * interface, uint32_t version) @@ -448,11 +1162,11 @@ registry_handle_global(void * data, struct wl_registry * registry, uint32_t id, data_wl.compositor = wl_registry_bind(registry, id, &wl_compositor_interface, version); if (!data_wl.compositor) { - printf("Failed to bind compositor."); + printf("Failed to bind compositor.\n"); return; } if (data_wl.enable_log) - printf("Success to bind compositor."); + printf("Success to bind compositor.\n"); } else if (strcmp(interface, "tizen_input_device_manager") == 0) { data_wl.devicemgr = wl_registry_bind(registry, id, &tizen_input_device_manager_interface, version); @@ -464,6 +1178,25 @@ registry_handle_global(void * data, struct wl_registry * registry, uint32_t id, printf("Success to bind tizen input device manager."); tizen_input_device_manager_add_listener(data_wl.devicemgr, &_input_device_manager_listener, data_wl.display); + } else if (!strcmp(interface, "zwp_input_method_manager_v1")) { + data_wl.input_method_mgr = wl_registry_bind(registry, id, + &zwp_input_method_manager_v1_interface, version); + } else if (!strcmp(interface, "zwp_input_method_v1")) { + data_wl.input_method = wl_registry_bind(registry, id, + &zwp_input_method_v1_interface, version); + zwp_input_method_v1_add_listener(data_wl.input_method, + &input_method_cb_listener, + NULL); + + //TODO: delte this code. this job should be done in cb_activate + data_wl.preedit_string = strdup(""); + data_wl.content_hint = 0; + data_wl.content_purpose = 0; + free(data_wl.preferred_language); + data_wl.preferred_language = NULL; + free(data_wl.surrounding_text); + data_wl.surrounding_text = NULL; + data_wl.serial = 0; } } @@ -529,6 +1262,9 @@ wayland_deinit(void) if (data_wl.queue) wl_event_queue_destroy(data_wl.queue); if (data_wl.devicemgr) tizen_input_device_manager_destroy(data_wl.devicemgr); if (data_wl.display) { + if (data_wl.input_method) + zwp_input_method_v1_destroy(data_wl.input_method); + zwp_input_method_manager_v1_destroy(data_wl.input_method_mgr); wl_registry_destroy(data_wl.registry); wl_display_flush(data_wl.display); wl_display_disconnect(data_wl.display); diff --git a/clients/meson.build b/clients/meson.build index 672792a..c825bce 100644 --- a/clients/meson.build +++ b/clients/meson.build @@ -82,19 +82,7 @@ input_generator_deps = [ executable('input-generator', input_generator_files, - dependencies: input_generator_deps, - install_dir: libds_tizen_bindir, - install: true, -) - -ime_keyboard_files = ['ime-keyboard.c'] -ime_keyboard_deps = [ - dependency('wayland-client', required: true), -] - -executable('ime-keyboard', - ime_keyboard_files, - dependencies: [ime_keyboard_deps, + dependencies: [input_generator_deps, deps_libds_tizen_input_method, ], install_dir: libds_tizen_bindir, diff --git a/packaging/libds-tizen.spec b/packaging/libds-tizen.spec index 53d3d2f..37f9559 100644 --- a/packaging/libds-tizen.spec +++ b/packaging/libds-tizen.spec @@ -587,7 +587,6 @@ ninja -C builddir install %{_libdir}/libds-tizen-input-method.so %{_bindir}/libds-tizen-input-method-tests %{_bindir}/libds-tizen-input-method-manager-tests -%{_bindir}/ime-keyboard %files hwc %manifest %{name}.manifest -- 2.7.4 From 084e0f7cae704d1ed467609f037f3958bf762705 Mon Sep 17 00:00:00 2001 From: "duna.oh" Date: Wed, 7 Sep 2022 14:41:25 +0900 Subject: [PATCH 14/16] clients: refactor to prevent access to global variable Change-Id: Ia2283b124fb4b19473d8ca173a017c434153271a --- clients/input-generator.c | 619 ++++++++++++++++++++++++---------------------- 1 file changed, 321 insertions(+), 298 deletions(-) diff --git a/clients/input-generator.c b/clients/input-generator.c index cfa1800..c8aee23 100644 --- a/clients/input-generator.c +++ b/clients/input-generator.c @@ -200,10 +200,10 @@ static const struct layout numeric_layout = { struct display data_wl; static void -request_key(uint32_t time, const struct key *key, enum wl_keyboard_key_state state); +request_key(struct display *d, uint32_t time, const struct key *key, enum wl_keyboard_key_state state); static const struct layout * -get_current_layout(void); +get_current_layout(struct display *d); static void usage(void) @@ -273,77 +273,77 @@ usage(void) } static void -init_input_generator(enum tizen_input_device_manager_clas clas) +init_input_generator(struct display *d, enum tizen_input_device_manager_clas clas) { - if (data_wl.init) { + if (d->init) { printf("Already init input generator\n"); return; } - tizen_input_device_manager_init_generator(data_wl.devicemgr, clas); + tizen_input_device_manager_init_generator(d->devicemgr, clas); - while (data_wl.request_notified == -1) - wl_display_dispatch_queue(data_wl.display, data_wl.queue); + while (d->request_notified == -1) + wl_display_dispatch_queue(d->display, d->queue); - if (data_wl.request_notified == TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) { - data_wl.init = 1; + if (d->request_notified == TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) { + d->init = 1; printf("Success to init input generator\n"); } else { - printf("Failed to init input generator: %d\n", data_wl.request_notified); + printf("Failed to init input generator: %d\n", d->request_notified); } - data_wl.clas = clas; - data_wl.request_notified = -1; + d->clas = clas; + d->request_notified = -1; } static void -deinit_input_generator(void) +deinit_input_generator(struct display *d) { - if (!data_wl.init) { + if (!d->init) { printf("input generator is not initialized\n"); return; } - tizen_input_device_manager_deinit_generator(data_wl.devicemgr, data_wl.clas); + tizen_input_device_manager_deinit_generator(d->devicemgr, d->clas); - while (data_wl.request_notified == -1) - wl_display_dispatch_queue(data_wl.display, data_wl.queue); + while (d->request_notified == -1) + wl_display_dispatch_queue(d->display, d->queue); - if (data_wl.request_notified == TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) { - data_wl.init = 0; + if (d->request_notified == TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) { + d->init = 0; printf("Success to deinit input generator\n"); } else { - printf("Failed to deinit input generator: %d\n", data_wl.request_notified); + printf("Failed to deinit input generator: %d\n", d->request_notified); } - data_wl.request_notified = -1; + d->request_notified = -1; } static void -input_generator_key(char *name, int type) +input_generator_key(struct display *d, char *name, int type) { - tizen_input_device_manager_generate_key(data_wl.devicemgr, name, !!type); + tizen_input_device_manager_generate_key(d->devicemgr, name, !!type); - while (data_wl.request_notified == -1) - wl_display_dispatch_queue(data_wl.display, data_wl.queue); + while (d->request_notified == -1) + wl_display_dispatch_queue(d->display, d->queue); - if (data_wl.request_notified == TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) { - if (data_wl.enable_log) { + if (d->request_notified == TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) { + if (d->enable_log) { printf("Success to generate key: %s key %s\n", name, type?"down":"up"); } } else { - printf("Failed to generate %s key %s: %d\n", name, type?"down":"up", data_wl.request_notified); + printf("Failed to generate %s key %s: %d\n", name, type?"down":"up", d->request_notified); } - data_wl.request_notified = -1; + d->request_notified = -1; } static void -key_generate(char *name, int type) +key_generate(struct display *d, char *name, int type) { printf("name: %s, type: %d\n", name, type); - if (!data_wl.init) { + if (!d->init) { printf("Input generator is not initialized\n"); return; } @@ -354,10 +354,10 @@ key_generate(char *name, int type) } if (type == KEY_ALL) { - input_generator_key(name, 1); - input_generator_key(name, 0); + input_generator_key(d, name, 1); + input_generator_key(d, name, 0); } else { - input_generator_key(name, !!type); + input_generator_key(d, name, !!type); } } @@ -377,94 +377,94 @@ type_string_get(int type) } static void -input_generator_touch(int idx, int type, int x, int y) +input_generator_touch(struct display *d, int idx, int type, int x, int y) { - tizen_input_device_manager_generate_touch(data_wl.devicemgr, type, x, y, idx); + tizen_input_device_manager_generate_touch(d->devicemgr, type, x, y, idx); - while (data_wl.request_notified == -1) - wl_display_dispatch_queue(data_wl.display, data_wl.queue); + while (d->request_notified == -1) + wl_display_dispatch_queue(d->display, d->queue); - if (data_wl.request_notified == TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) { - if (data_wl.enable_log) { + if (d->request_notified == TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) { + if (d->enable_log) { printf("Success to generate touch: %d finger %s on (%d, %d)\n", idx, type_string_get(type), x, y); } } else { - printf("Failed to generate touch(%d finger %s on (%d, %d)): %d\n", idx, type_string_get(type), x, y, data_wl.request_notified); + printf("Failed to generate touch(%d finger %s on (%d, %d)): %d\n", idx, type_string_get(type), x, y, d->request_notified); } - data_wl.request_notified = -1; + d->request_notified = -1; } static void -touch_generate(int idx, int type, int x, int y) +touch_generate(struct display *d, int idx, int type, int x, int y) { - if (!data_wl.init) { + if (!d->init) { printf("Input generator is not initialized\n"); return; } if (type == POINTER_ALL) { - input_generator_touch(0, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_BEGIN, 300, 300); - input_generator_touch(1, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_BEGIN, 400, 400); - input_generator_touch(2, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_BEGIN, 500, 500); + input_generator_touch(d, 0, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_BEGIN, 300, 300); + input_generator_touch(d, 1, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_BEGIN, 400, 400); + input_generator_touch(d, 2, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_BEGIN, 500, 500); - input_generator_touch(0, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 310, 310); - input_generator_touch(1, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 410, 410); - input_generator_touch(2, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 510, 510); + input_generator_touch(d, 0, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 310, 310); + input_generator_touch(d, 1, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 410, 410); + input_generator_touch(d, 2, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 510, 510); - input_generator_touch(0, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 320, 320); - input_generator_touch(1, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 420, 420); - input_generator_touch(2, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 520, 520); + input_generator_touch(d, 0, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 320, 320); + input_generator_touch(d, 1, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 420, 420); + input_generator_touch(d, 2, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 520, 520); - input_generator_touch(0, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_END, 320, 320); - input_generator_touch(1, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_END, 420, 420); - input_generator_touch(2, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_END, 520, 520); + input_generator_touch(d, 0, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_END, 320, 320); + input_generator_touch(d, 1, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_END, 420, 420); + input_generator_touch(d, 2, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_END, 520, 520); } else { - input_generator_touch(idx, type, x, y); + input_generator_touch(d, idx, type, x, y); } } static void -input_generator_mouse(int type, int x, int y, int button) +input_generator_mouse(struct display *d, int type, int x, int y, int button) { - tizen_input_device_manager_generate_pointer(data_wl.devicemgr, type, x, y, button); + tizen_input_device_manager_generate_pointer(d->devicemgr, type, x, y, button); - while (data_wl.request_notified == -1) - wl_display_dispatch_queue(data_wl.display, data_wl.queue); + while (d->request_notified == -1) + wl_display_dispatch_queue(d->display, d->queue); - if (data_wl.request_notified == TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) { - if (data_wl.enable_log) { + if (d->request_notified == TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) { + if (d->enable_log) { printf("Success to generate mouse: %s on (%d, %d)\n", type_string_get(type), x, y); } } else { - printf("Failed to generate mouse(%s on (%d, %d)): %d\n", type_string_get(type), x, y, data_wl.request_notified); + printf("Failed to generate mouse(%s on (%d, %d)): %d\n", type_string_get(type), x, y, d->request_notified); } - data_wl.request_notified = -1; + d->request_notified = -1; } static void -mouse_generate(int btn, int type, int x, int y) +mouse_generate(struct display *d, int btn, int type, int x, int y) { - if (!data_wl.init) { + if (!d->init) { printf("Input generator is not initialized\n"); return; } if (type == POINTER_ALL) { - input_generator_mouse(TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_BEGIN, -1, -1, 1); - input_generator_mouse(TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 10, 10, 1); - input_generator_mouse(TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 10, 10, 1); - input_generator_mouse(TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 10, 10, 1); - input_generator_mouse(TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_END, -1, -1, 1); + input_generator_mouse(d, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_BEGIN, -1, -1, 1); + input_generator_mouse(d, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 10, 10, 1); + input_generator_mouse(d, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 10, 10, 1); + input_generator_mouse(d, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 10, 10, 1); + input_generator_mouse(d, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_END, -1, -1, 1); } else { - input_generator_mouse(type, x, y, btn); + input_generator_mouse(d, type, x, y, btn); } } static void -stdin_read(void) +stdin_read(struct display *d) { int c; char buf[MAX_STR] = {0, }, *tmp, *buf_ptr, key_name[MAX_STR] = {0, }; @@ -492,11 +492,11 @@ stdin_read(void) switch (count) { case 0: if (!strncmp("keyboard", tmp, MAX_STR-1)) - init_input_generator(TIZEN_INPUT_DEVICE_MANAGER_CLAS_KEYBOARD); + init_input_generator(d, TIZEN_INPUT_DEVICE_MANAGER_CLAS_KEYBOARD); else if (!strncmp("touch", tmp, MAX_STR-1)) - init_input_generator(TIZEN_INPUT_DEVICE_MANAGER_CLAS_TOUCHSCREEN); + init_input_generator(d, TIZEN_INPUT_DEVICE_MANAGER_CLAS_TOUCHSCREEN); else if (!strncmp("mouse", tmp, MAX_STR-1)) - init_input_generator(TIZEN_INPUT_DEVICE_MANAGER_CLAS_MOUSE); + init_input_generator(d, TIZEN_INPUT_DEVICE_MANAGER_CLAS_MOUSE); break; default: break; @@ -505,7 +505,7 @@ stdin_read(void) count++; } } else if (!strncmp(tmp, "deinit", sizeof("deinit"))) { - deinit_input_generator(); + deinit_input_generator(d); } else if (!strncmp(tmp, "key", sizeof("key"))) { while (tmp) { tmp = strtok_r(NULL, " ", &buf_ptr); @@ -523,7 +523,7 @@ stdin_read(void) } count++; } - key_generate(key_name, key_type); + key_generate(d, key_name, key_type); } else if (!strncmp(tmp, "touch", sizeof("touch"))) { while (tmp) { tmp = strtok_r(NULL, " ", &buf_ptr); @@ -547,7 +547,7 @@ stdin_read(void) } count++; } - touch_generate(idx, type, x, y); + touch_generate(d, idx, type, x, y); } else if (!strncmp(tmp, "mouse", sizeof("mouse"))) { while (tmp) { tmp = strtok_r(NULL, " ", &buf_ptr); @@ -571,7 +571,7 @@ stdin_read(void) } count++; } - mouse_generate(idx, type, x, y); + mouse_generate(d, idx, type, x, y); } else if (!strncmp(tmp, "ime", MAX_STR)) { while (tmp) { tmp = strtok_r(NULL, " ", &buf_ptr); @@ -589,27 +589,27 @@ stdin_read(void) } count++; } - if (data_wl.enable_log) + if (d->enable_log) printf("request key() key_idx:%u, key_type:%u\n", idx, key_type); - layout = get_current_layout(); + layout = get_current_layout(d); if (key_type == KEY_ALL) { - request_key(time++, &layout->keys[idx], WL_KEYBOARD_KEY_STATE_PRESSED); - request_key(time++, &layout->keys[idx], WL_KEYBOARD_KEY_STATE_RELEASED); + request_key(d, time++, &layout->keys[idx], WL_KEYBOARD_KEY_STATE_PRESSED); + request_key(d, time++, &layout->keys[idx], WL_KEYBOARD_KEY_STATE_RELEASED); } else - request_key(time++, &layout->keys[idx], key_type); + request_key(d, time++, &layout->keys[idx], key_type); } else if (!strncmp(buf, "q", MAX_STR) || !strncmp(buf, "quit", MAX_STR)) { - data_wl.run = 0; + d->run = 0; } else if (!strncmp(buf, "help", MAX_STR)) { usage(); } else if (!strncmp(buf, "log", MAX_STR)) { - if (data_wl.enable_log) + if (d->enable_log) printf("Disable detailed logs\n"); else printf("Enable detailed logs\n"); - data_wl.enable_log = !data_wl.enable_log; + d->enable_log = !d->enable_log; } else { printf("Invalid arguments\n"); usage(); @@ -621,9 +621,11 @@ input_device_manager_handle_error(void *data, struct tizen_input_device_manager *tizen_input_device_manager, uint32_t errorcode) { - if (data_wl.enable_log) + struct display *d = (struct display *)data; + + if (d->enable_log) printf("errorcode: %d\n", errorcode); - data_wl.request_notified = errorcode; + d->request_notified = errorcode; } static const struct tizen_input_device_manager_listener _input_device_manager_listener = @@ -635,9 +637,9 @@ static const struct tizen_input_device_manager_listener _input_device_manager_li }; static const struct layout * -get_current_layout(void) +get_current_layout(struct display *d) { - switch (data_wl.content_purpose) { + switch (d->content_purpose) { case WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS: case WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER: return &numeric_layout; @@ -657,36 +659,36 @@ prev_utf8_char(const char *s, const char *p) } static void -delete_before_cursor(void) +delete_before_cursor(struct display *d) { const char *start, *end; - if (!data_wl.surrounding_text) { + if (!d->surrounding_text) { printf("delete_before_cursor: No surrounding text available\n"); return; } - start = prev_utf8_char(data_wl.surrounding_text, - data_wl.surrounding_text + data_wl.surrounding_cursor); + start = prev_utf8_char(d->surrounding_text, + d->surrounding_text + d->surrounding_cursor); if (!start) { printf("delete_before_cursor: No previous character to delete\n"); return; } - end = data_wl.surrounding_text + data_wl.surrounding_cursor; + end = d->surrounding_text + d->surrounding_cursor; - zwp_input_method_context_v1_delete_surrounding_text(data_wl.context, - (start - data_wl.surrounding_text) - data_wl.surrounding_cursor, + zwp_input_method_context_v1_delete_surrounding_text(d->context, + (start - d->surrounding_text) - d->surrounding_cursor, end - start); - zwp_input_method_context_v1_commit_string(data_wl.context, - data_wl.serial, + zwp_input_method_context_v1_commit_string(d->context, + d->serial, ""); /* Update surrounding text */ - data_wl.surrounding_cursor = start - data_wl.surrounding_text; - data_wl.surrounding_text[data_wl.surrounding_cursor] = '\0'; + d->surrounding_cursor = start - d->surrounding_text; + d->surrounding_text[d->surrounding_cursor] = '\0'; if (*end) - memmove(data_wl.surrounding_text + data_wl.surrounding_cursor, end, strlen(end)); + memmove(d->surrounding_text + d->surrounding_cursor, end, strlen(end)); } static char * @@ -709,26 +711,26 @@ append(char *s1, const char *s2) } static void -request_preedit(int32_t cursor) +request_preedit(struct display *d, int32_t cursor) { - printf("request_preedit() preedit_string:%s\n", data_wl.preedit_string); - uint32_t index = strlen(data_wl.preedit_string); + printf("request_preedit() preedit_string:%s\n", d->preedit_string); + uint32_t index = strlen(d->preedit_string); - if (!data_wl.context) return; + if (!d->context) return; - if (data_wl.preedit_style) - zwp_input_method_context_v1_preedit_styling(data_wl.context, + if (d->preedit_style) + zwp_input_method_context_v1_preedit_styling(d->context, 0, - strlen(data_wl.preedit_string), - data_wl.preedit_style); + strlen(d->preedit_string), + d->preedit_style); if (cursor > 0) index = cursor; - zwp_input_method_context_v1_preedit_cursor(data_wl.context, + zwp_input_method_context_v1_preedit_cursor(d->context, index); - zwp_input_method_context_v1_preedit_string(data_wl.context, - data_wl.serial, - data_wl.preedit_string, - data_wl.preedit_string); + zwp_input_method_context_v1_preedit_string(d->context, + d->serial, + d->preedit_string, + d->preedit_string); } static char * @@ -752,48 +754,48 @@ insert_text(const char *text, uint32_t offset, const char *insert) } static void -request_commit_string(void) +request_commit_string(struct display *d) { char *surrounding_text; printf("request_commit_string()\n"); - if (!data_wl.preedit_string || - strlen(data_wl.preedit_string) == 0) + if (!d->preedit_string || + strlen(d->preedit_string) == 0) return; - printf("request_commit_string() preedit_string:%s\n", data_wl.preedit_string); + printf("request_commit_string() preedit_string:%s\n", d->preedit_string); - if (!data_wl.context) return; + if (!d->context) return; - zwp_input_method_context_v1_cursor_position(data_wl.context, + zwp_input_method_context_v1_cursor_position(d->context, 0, 0); - zwp_input_method_context_v1_commit_string(data_wl.context, - data_wl.serial, - data_wl.preedit_string); - - if (data_wl.surrounding_text) { - surrounding_text = insert_text(data_wl.surrounding_text, - data_wl.surrounding_cursor, - data_wl.preedit_string); - free(data_wl.surrounding_text); - data_wl.surrounding_text = surrounding_text; - data_wl.surrounding_cursor += strlen(data_wl.preedit_string); + zwp_input_method_context_v1_commit_string(d->context, + d->serial, + d->preedit_string); + + if (d->surrounding_text) { + surrounding_text = insert_text(d->surrounding_text, + d->surrounding_cursor, + d->preedit_string); + free(d->surrounding_text); + d->surrounding_text = surrounding_text; + d->surrounding_cursor += strlen(d->preedit_string); } else { - data_wl.surrounding_text = strdup(data_wl.preedit_string); - data_wl.surrounding_cursor = strlen(data_wl.preedit_string); + d->surrounding_text = strdup(d->preedit_string); + d->surrounding_cursor = strlen(d->preedit_string); } - free(data_wl.preedit_string); - data_wl.preedit_string = strdup(""); + free(d->preedit_string); + d->preedit_string = strdup(""); } static void -request_key(uint32_t time, const struct key *key, enum wl_keyboard_key_state state) +request_key(struct display *d, uint32_t time, const struct key *key, enum wl_keyboard_key_state state) { const char *label = NULL; static uint32_t serial = 9999; - switch(data_wl.state) { + switch(d->state) { case KEYBOARD_STATE_DEFAULT : label = key->label; break; @@ -808,37 +810,37 @@ request_key(uint32_t time, const struct key *key, enum wl_keyboard_key_state sta break; } - xkb_mod_mask_t mod_mask = data_wl.state == KEYBOARD_STATE_DEFAULT ? 0 : data_wl.keysym.shift_mask; + xkb_mod_mask_t mod_mask = d->state == KEYBOARD_STATE_DEFAULT ? 0 : d->keysym.shift_mask; uint32_t key_state = (state == WL_KEYBOARD_KEY_STATE_PRESSED) ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED; - printf("request_key() data_wl.state:%d, key->key_type:%d, pressed:%u, label:%s\n", data_wl.state, key->key_type, key_state, label); + printf("request_key() d->state:%d, key->key_type:%d, pressed:%u, label:%s\n", d->state, key->key_type, key_state, label); switch (key->key_type) { case keytype_default: if (state != WL_KEYBOARD_KEY_STATE_PRESSED) break; - printf("request_key() keytype_default. append label(%s) to preedit_string(%s)\n", label, data_wl.preedit_string); - data_wl.preedit_string = - append(data_wl.preedit_string, + printf("request_key() keytype_default. append label(%s) to preedit_string(%s)\n", label, d->preedit_string); + d->preedit_string = + append(d->preedit_string, label); - request_preedit(-1); + request_preedit(d, -1); break; case keytype_backspace: if (state != WL_KEYBOARD_KEY_STATE_PRESSED) break; - if (strlen(data_wl.preedit_string) == 0) { - delete_before_cursor(); + if (strlen(d->preedit_string) == 0) { + delete_before_cursor(d); } else { - data_wl.preedit_string[strlen(data_wl.preedit_string) - 1] = '\0'; - request_preedit(-1); + d->preedit_string[strlen(d->preedit_string) - 1] = '\0'; + request_preedit(d, -1); } break; case keytype_enter: - request_commit_string(); + request_commit_string(d); - if (!data_wl.context) break; - zwp_input_method_context_v1_keysym(data_wl.context, + if (!d->context) break; + zwp_input_method_context_v1_keysym(d->context, serial++, time, XKB_KEY_Return, key_state, mod_mask); @@ -846,76 +848,76 @@ request_key(uint32_t time, const struct key *key, enum wl_keyboard_key_state sta case keytype_space: if (state != WL_KEYBOARD_KEY_STATE_PRESSED) break; - data_wl.preedit_string = - append(data_wl.preedit_string, " "); - request_commit_string(); + d->preedit_string = + append(d->preedit_string, " "); + request_commit_string(d); break; case keytype_switch: if (state != WL_KEYBOARD_KEY_STATE_PRESSED) break; - switch(data_wl.state) { + switch(d->state) { case KEYBOARD_STATE_DEFAULT: - data_wl.state = KEYBOARD_STATE_UPPERCASE; + d->state = KEYBOARD_STATE_UPPERCASE; break; case KEYBOARD_STATE_UPPERCASE: - data_wl.state = KEYBOARD_STATE_DEFAULT; + d->state = KEYBOARD_STATE_DEFAULT; break; case KEYBOARD_STATE_SYMBOLS: - data_wl.state = KEYBOARD_STATE_UPPERCASE; + d->state = KEYBOARD_STATE_UPPERCASE; break; } break; case keytype_symbols: if (state != WL_KEYBOARD_KEY_STATE_PRESSED) break; - switch(data_wl.state) { + switch(d->state) { case KEYBOARD_STATE_DEFAULT: - data_wl.state = KEYBOARD_STATE_SYMBOLS; + d->state = KEYBOARD_STATE_SYMBOLS; break; case KEYBOARD_STATE_UPPERCASE: - data_wl.state = KEYBOARD_STATE_SYMBOLS; + d->state = KEYBOARD_STATE_SYMBOLS; break; case KEYBOARD_STATE_SYMBOLS: - data_wl.state = KEYBOARD_STATE_DEFAULT; + d->state = KEYBOARD_STATE_DEFAULT; break; } break; case keytype_tab: - request_commit_string(); - if (!data_wl.context) break; - zwp_input_method_context_v1_keysym(data_wl.context, + request_commit_string(d); + if (!d->context) break; + zwp_input_method_context_v1_keysym(d->context, serial++, time, XKB_KEY_Tab, key_state, mod_mask); break; case keytype_arrow_up: - request_commit_string(); - if (!data_wl.context) break; - zwp_input_method_context_v1_keysym(data_wl.context, + request_commit_string(d); + if (!d->context) break; + zwp_input_method_context_v1_keysym(d->context, serial++, time, XKB_KEY_Up, key_state, mod_mask); break; case keytype_arrow_left: - request_commit_string(); - if (!data_wl.context) break; - zwp_input_method_context_v1_keysym(data_wl.context, + request_commit_string(d); + if (!d->context) break; + zwp_input_method_context_v1_keysym(d->context, serial++, time, XKB_KEY_Left, key_state, mod_mask); break; case keytype_arrow_right: - request_commit_string(); - if (!data_wl.context) break; - zwp_input_method_context_v1_keysym(data_wl.context, + request_commit_string(d); + if (!d->context) break; + zwp_input_method_context_v1_keysym(d->context, serial++, time, XKB_KEY_Right, key_state, mod_mask); break; case keytype_arrow_down: - request_commit_string(); - if (!data_wl.context) break; - zwp_input_method_context_v1_keysym(data_wl.context, + request_commit_string(d); + if (!d->context) break; + zwp_input_method_context_v1_keysym(d->context, serial++, time, XKB_KEY_Down, key_state, mod_mask); @@ -923,8 +925,8 @@ request_key(uint32_t time, const struct key *key, enum wl_keyboard_key_state sta case keytype_style: if (state != WL_KEYBOARD_KEY_STATE_PRESSED) break; - data_wl.preedit_style = (data_wl.preedit_style + 1) % 8; /* TODO */ - request_preedit(-1); + d->preedit_style = (d->preedit_style + 1) % 8; /* TODO */ + request_preedit(d, -1); break; } } @@ -932,79 +934,89 @@ request_key(uint32_t time, const struct key *key, enum wl_keyboard_key_state sta static void im_context_cb_surrounding_text (void *data, struct zwp_input_method_context_v1 *im_ctx, const char *text, uint32_t cursor, uint32_t anchor) { + struct display *d = (struct display *)data; + printf("im_context_cb_surrounding_text\n"); - free(data_wl.surrounding_text); - data_wl.surrounding_text = strdup(text); + free(d->surrounding_text); - data_wl.surrounding_cursor = cursor; + d->surrounding_text = strdup(text); + d->surrounding_cursor = cursor; } static void im_context_cb_reset (void *data, struct zwp_input_method_context_v1 *im_ctx) { + struct display *d = (struct display *)data; + printf("im_context_cb_reset\n"); - if (strlen(data_wl.preedit_string)) { - free(data_wl.preedit_string); - data_wl.preedit_string = strdup(""); + if (strlen(d->preedit_string)) { + free(d->preedit_string); + d->preedit_string = strdup(""); } } static void im_context_cb_content_type (void *data, struct zwp_input_method_context_v1 *im_ctx, uint32_t hint, uint32_t purpose) { + struct display *d = (struct display *)data; + printf("im_context_cb_content_type\n"); - data_wl.content_hint = hint; - data_wl.content_purpose = purpose; + d->content_hint = hint; + d->content_purpose = purpose; } static void im_context_cb_invoke_action (void *data, struct zwp_input_method_context_v1 *im_ctx, uint32_t button, uint32_t index) { + struct display *d = (struct display *)data; + printf("im_context_cb_invoke_action\n"); //if (button != BTN_LEFT) // return; - request_preedit(index); + request_preedit(d, index); } static void im_context_cb_commit_state (void *data, struct zwp_input_method_context_v1 *context, uint32_t serial) { - printf("im_context_cb_commit_state\n"); - + struct display *d = (struct display *)data; const struct layout *layout; - data_wl.serial = serial; + printf("im_context_cb_commit_state\n"); + d->serial = serial; - layout = get_current_layout(); + layout = get_current_layout(d); - if (data_wl.surrounding_text) - printf("Surrounding text updated: %s\n", data_wl.surrounding_text); + if (d->surrounding_text) + printf("Surrounding text updated: %s\n", d->surrounding_text); if (!context) return; zwp_input_method_context_v1_language(context, - data_wl.serial, + d->serial, layout->language); zwp_input_method_context_v1_text_direction(context, - data_wl.serial, + d->serial, layout->text_direction); } static void im_context_cb_preferred_language (void *data, struct zwp_input_method_context_v1 *context, const char *language) { + struct display *d = (struct display *)data; + printf("im_context_cb_preferred_language\n"); - if (data_wl.preferred_language) - free(data_wl.preferred_language); + if (d->preferred_language) + free(d->preferred_language); - data_wl.preferred_language = NULL; + d->preferred_language = NULL; if (language) - data_wl.preferred_language = strdup(language); + d->preferred_language = strdup(language); } static const struct zwp_input_method_context_v1_listener input_method_context_cb_listener = { @@ -1078,68 +1090,74 @@ keysym_modifiers_get_mask(struct wl_array *modifiers_map, static void im_cb_activate (void *data, struct zwp_input_method_v1 *input_method, struct zwp_input_method_context_v1 *context) { + struct display *d = (struct display *)data; + printf("im_cb_activate\n"); struct wl_array modifiers_map; const struct layout *layout; - if (data_wl.context) - zwp_input_method_context_v1_destroy(data_wl.context); + if (d->context) + zwp_input_method_context_v1_destroy(d->context); - if (data_wl.preedit_string) - free(data_wl.preedit_string); + if (d->preedit_string) + free(d->preedit_string); - data_wl.preedit_style = 0; - data_wl.preedit_string = strdup(""); - data_wl.content_hint = 0; - data_wl.content_purpose = 0; - free(data_wl.preferred_language); - data_wl.preferred_language = NULL; - free(data_wl.surrounding_text); - data_wl.surrounding_text = NULL; + d->preedit_style = 0; + d->preedit_string = strdup(""); + d->content_hint = 0; + d->content_purpose = 0; + free(d->preferred_language); + d->preferred_language = NULL; + free(d->surrounding_text); + d->surrounding_text = NULL; - data_wl.serial = 0; + d->serial = 0; - data_wl.context = context; + d->context = context; zwp_input_method_context_v1_add_listener(context, &input_method_context_cb_listener, - NULL); + d); wl_array_init(&modifiers_map); keysym_modifiers_add(&modifiers_map, "Shift"); keysym_modifiers_add(&modifiers_map, "Control"); keysym_modifiers_add(&modifiers_map, "Mod1"); zwp_input_method_context_v1_modifiers_map(context, &modifiers_map); - data_wl.keysym.shift_mask = keysym_modifiers_get_mask(&modifiers_map, "Shift"); + d->keysym.shift_mask = keysym_modifiers_get_mask(&modifiers_map, "Shift"); wl_array_release(&modifiers_map); - layout = get_current_layout(); + layout = get_current_layout(d); zwp_input_method_context_v1_language(context, - data_wl.serial, + d->serial, layout->language); zwp_input_method_context_v1_text_direction(context, - data_wl.serial, + d->serial, layout->text_direction); } static void im_cb_deactivate (void *data, struct zwp_input_method_v1 *input_method, struct zwp_input_method_context_v1 *im_ctx) { + struct display *d = (struct display *)data; + printf("im_cb_deactivate\n"); - if (!data_wl.context) + if (!d->context) return; - zwp_input_method_context_v1_destroy(data_wl.context); - data_wl.context = NULL; + zwp_input_method_context_v1_destroy(d->context); + d->context = NULL; } static void im_cb_destroy (void *data, struct zwp_input_method_v1 *input_method, struct zwp_input_method_context_v1 *im_ctx) { + struct display *d = (struct display *)data; + printf("im_cb_destroy\n"); - zwp_input_method_v1_destroy(data_wl.input_method); - data_wl.input_method = NULL; + zwp_input_method_v1_destroy(d->input_method); + d->input_method = NULL; } static const struct zwp_input_method_v1_listener input_method_cb_listener = { @@ -1158,52 +1176,56 @@ static void registry_handle_global(void * data, struct wl_registry * registry, uint32_t id, const char * interface, uint32_t version) { + struct display *d = (struct display *)data; + if (strcmp(interface, "wl_compositor") == 0) { - data_wl.compositor = wl_registry_bind(registry, id, + d->compositor = wl_registry_bind(registry, id, &wl_compositor_interface, version); - if (!data_wl.compositor) { + if (!d->compositor) { printf("Failed to bind compositor.\n"); return; } - if (data_wl.enable_log) + if (d->enable_log) printf("Success to bind compositor.\n"); } else if (strcmp(interface, "tizen_input_device_manager") == 0) { - data_wl.devicemgr = wl_registry_bind(registry, id, + d->devicemgr = wl_registry_bind(registry, id, &tizen_input_device_manager_interface, version); - if (!data_wl.devicemgr) { + if (!d->devicemgr) { printf("Failed to bind input device manager"); return; } - if (data_wl.enable_log) + if (d->enable_log) printf("Success to bind tizen input device manager."); - tizen_input_device_manager_add_listener(data_wl.devicemgr, - &_input_device_manager_listener, data_wl.display); + tizen_input_device_manager_add_listener(d->devicemgr, + &_input_device_manager_listener, d); } else if (!strcmp(interface, "zwp_input_method_manager_v1")) { - data_wl.input_method_mgr = wl_registry_bind(registry, id, + d->input_method_mgr = wl_registry_bind(registry, id, &zwp_input_method_manager_v1_interface, version); } else if (!strcmp(interface, "zwp_input_method_v1")) { - data_wl.input_method = wl_registry_bind(registry, id, + d->input_method = wl_registry_bind(registry, id, &zwp_input_method_v1_interface, version); - zwp_input_method_v1_add_listener(data_wl.input_method, + zwp_input_method_v1_add_listener(d->input_method, &input_method_cb_listener, - NULL); + d); //TODO: delte this code. this job should be done in cb_activate - data_wl.preedit_string = strdup(""); - data_wl.content_hint = 0; - data_wl.content_purpose = 0; - free(data_wl.preferred_language); - data_wl.preferred_language = NULL; - free(data_wl.surrounding_text); - data_wl.surrounding_text = NULL; - data_wl.serial = 0; + d->preedit_string = strdup(""); + d->content_hint = 0; + d->content_purpose = 0; + free(d->preferred_language); + d->preferred_language = NULL; + free(d->surrounding_text); + d->surrounding_text = NULL; + d->serial = 0; } } static void registry_handle_global_remove(void * data, struct wl_registry * registry, uint32_t id) { - if (data_wl.enable_log) + struct display *d = (struct display *)data; + + if (d->enable_log) printf("registry is removed. id: %d !\n", id); } @@ -1213,37 +1235,37 @@ static const struct wl_registry_listener _registry_listener = { }; static int -wayland_init(void) +wayland_init(struct display *d) { - memset(&data_wl, 0, sizeof(struct display)); - data_wl.request_notified = -1; + memset(d, 0, sizeof(struct display)); + d->request_notified = -1; - data_wl.display = wl_display_connect(NULL); - if (!data_wl.display) { + d->display = wl_display_connect(NULL); + if (!d->display) { printf("Failed to connect wayland display\n"); return 0; } - data_wl.queue = wl_display_create_queue(data_wl.display); - if (!data_wl.queue) { + d->queue = wl_display_create_queue(d->display); + if (!d->queue) { printf("Failed to create queue\n"); return 0; } - data_wl.registry = wl_display_get_registry(data_wl.display); - if (!data_wl.registry) { + d->registry = wl_display_get_registry(d->display); + if (!d->registry) { printf("Failed to get registry\n"); return 0; } - wl_proxy_set_queue((struct wl_proxy*)data_wl.registry, data_wl.queue); - wl_registry_add_listener(data_wl.registry, &_registry_listener, NULL); + wl_proxy_set_queue((struct wl_proxy*)d->registry, d->queue); + wl_registry_add_listener(d->registry, &_registry_listener, d); - if (wl_display_dispatch_queue(data_wl.display, data_wl.queue) == -1) { + if (wl_display_dispatch_queue(d->display, d->queue) == -1) { printf("Failed to dispatch display\n"); return 0; } - if (wl_display_roundtrip_queue(data_wl.display, data_wl.queue) == -1) { + if (wl_display_roundtrip_queue(d->display, d->queue) == -1) { printf("Failed to roundtrip display\n"); return 0; } @@ -1252,91 +1274,91 @@ wayland_init(void) } static void -wayland_deinit(void) +wayland_deinit(struct display *d) { - if (data_wl.enable_log) + if (d->enable_log) printf("Shutdown wayland system\n"); - if (data_wl.init) deinit_input_generator(); - - if (data_wl.queue) wl_event_queue_destroy(data_wl.queue); - if (data_wl.devicemgr) tizen_input_device_manager_destroy(data_wl.devicemgr); - if (data_wl.display) { - if (data_wl.input_method) - zwp_input_method_v1_destroy(data_wl.input_method); - zwp_input_method_manager_v1_destroy(data_wl.input_method_mgr); - wl_registry_destroy(data_wl.registry); - wl_display_flush(data_wl.display); - wl_display_disconnect(data_wl.display); + if (d->init) deinit_input_generator(d); + + if (d->queue) wl_event_queue_destroy(d->queue); + if (d->devicemgr) tizen_input_device_manager_destroy(d->devicemgr); + if (d->display) { + if (d->input_method) + zwp_input_method_v1_destroy(d->input_method); + zwp_input_method_manager_v1_destroy(d->input_method_mgr); + wl_registry_destroy(d->registry); + wl_display_flush(d->display); + wl_display_disconnect(d->display); } } static int -epoll_init(void) +epoll_init(struct display *d) { struct epoll_event ep[2]; - data_wl.fd_epoll = epoll_create(SIZE_EPOLL); - if (data_wl.fd_epoll <= 0) { + d->fd_epoll = epoll_create(SIZE_EPOLL); + if (d->fd_epoll <= 0) { printf("Failed to epoll create: %d\n", SIZE_EPOLL); return 0; } - data_wl.fd_display = wl_display_get_fd(data_wl.display); + d->fd_display = wl_display_get_fd(d->display); memset(ep, 0, sizeof(struct epoll_event)*2); ep[0].events = EPOLLIN | EPOLLERR | EPOLLHUP; - ep[0].data.fd = data_wl.fd_display; - epoll_ctl(data_wl.fd_epoll, EPOLL_CTL_ADD, data_wl.fd_display, &ep[0]); + ep[0].data.fd = d->fd_display; + epoll_ctl(d->fd_epoll, EPOLL_CTL_ADD, d->fd_display, &ep[0]); ep[1].events = EPOLLIN | EPOLLERR | EPOLLHUP; ep[1].data.fd = STDIN_FILENO; - epoll_ctl(data_wl.fd_epoll, EPOLL_CTL_ADD, 0, &ep[1]); + epoll_ctl(d->fd_epoll, EPOLL_CTL_ADD, 0, &ep[1]); return 1; } static void -mainloop(void) +mainloop(struct display *d) { struct epoll_event ep[SIZE_EPOLL]; int res, count, i; - res = epoll_init(); + res = epoll_init(d); if (!res) { printf("Failed to init epoll\n"); return; } - data_wl.run = 1; - while (data_wl.run) { - res = wl_display_dispatch_queue_pending(data_wl.display, data_wl.queue); + d->run = 1; + while (d->run) { + res = wl_display_dispatch_queue_pending(d->display, d->queue); if (res < 0) { printf("Failed to dispatch pending. result: %d\n", res); - data_wl.run = 0; + d->run = 0; break; } - res = wl_display_flush(data_wl.display); + res = wl_display_flush(d->display); if (res < 0) { printf("Failed to flush display. result: %d\n", res); - data_wl.run = 0; + d->run = 0; break; } - count = epoll_wait(data_wl.fd_epoll, ep, SIZE_EPOLL, -1); + count = epoll_wait(d->fd_epoll, ep, SIZE_EPOLL, -1); for (i = 0; i < count; i++) { if (ep[i].events & EPOLLIN) { - if (ep[i].data.fd == data_wl.fd_display) { - wl_display_dispatch_queue(data_wl.display, data_wl.queue); + if (ep[i].data.fd == d->fd_display) { + wl_display_dispatch_queue(d->display, d->queue); } else { - stdin_read(); + stdin_read(d); } } if (ep[i].events & EPOLLERR) { - data_wl.run = 0; + d->run = 0; } if (ep[i].events & EPOLLHUP) { - data_wl.run = 0; + d->run = 0; } } } @@ -1346,13 +1368,14 @@ int main(int argc, char **argv) { int res; + struct display *d = &data_wl; - res = wayland_init(); + res = wayland_init(d); if (!res) return 0; - mainloop(); + mainloop(d); - wayland_deinit(); + wayland_deinit(d); return 0; } -- 2.7.4 From 220451ac52d2e72389bb9990e5b42c817abfc8c9 Mon Sep 17 00:00:00 2001 From: "duna.oh" Date: Wed, 7 Sep 2022 14:56:00 +0900 Subject: [PATCH 15/16] tests: no need to include 'input-method-server-protocol.h' Change-Id: I0b65f6b0b4a089c13ec174076e44dcfdc8ca18dc --- tests/tc_input_method.cpp | 1 - tests/tc_input_method_manager.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/tests/tc_input_method.cpp b/tests/tc_input_method.cpp index a9b1ecf..bb234b8 100644 --- a/tests/tc_input_method.cpp +++ b/tests/tc_input_method.cpp @@ -2,7 +2,6 @@ #include "mockclient.h" #include "mockcompositor.h" #include -#include #include #define INPUT_METHOD_VERSION 1 diff --git a/tests/tc_input_method_manager.cpp b/tests/tc_input_method_manager.cpp index a338d8f..30721dd 100644 --- a/tests/tc_input_method_manager.cpp +++ b/tests/tc_input_method_manager.cpp @@ -2,7 +2,6 @@ #include "mockclient.h" #include "mockcompositor.h" #include -#include #include #define INPUT_METHOD_VERSION 1 -- 2.7.4 From 1bd5d3b200f9c1dc7d7f02c863a0cd21bf206fac Mon Sep 17 00:00:00 2001 From: "duna.oh" Date: Wed, 7 Sep 2022 15:44:23 +0900 Subject: [PATCH 16/16] clients: merge text-entry code to simple-tbm Change-Id: I9c74e6155cb570d74cdb24c6b05e0515cc8362bf --- clients/meson.build | 22 +- clients/simple-tbm.c | 605 ++++++++++++++++++++- clients/text-entry.c | 1261 -------------------------------------------- packaging/libds-tizen.spec | 1 - 4 files changed, 596 insertions(+), 1293 deletions(-) delete mode 100644 clients/text-entry.c diff --git a/clients/meson.build b/clients/meson.build index c825bce..aa89a3c 100644 --- a/clients/meson.build +++ b/clients/meson.build @@ -14,13 +14,6 @@ simple_tbm_deps = [ tizen_extension_client, ] -text_entry_files = ['text-entry.c'] -text_entry_deps = [ - dependency('wayland-client', required: true), - wayland_tbm_client, - libtbm, -] - protocols = { 'xdg-shell': wl_protocol_dir / 'stable/xdg-shell/xdg-shell.xml', } @@ -35,7 +28,6 @@ foreach name, path : protocols command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'], ) simple_tbm_files += code - text_entry_files += code client_header = custom_target( name.underscorify() + '_client_h', @@ -45,12 +37,13 @@ foreach name, path : protocols build_by_default: false, ) simple_tbm_files += client_header - text_entry_files += client_header endforeach executable('ds-simple-tbm', simple_tbm_files, - dependencies: simple_tbm_deps, + dependencies: [simple_tbm_deps, + deps_libds_tizen_text_input, + ], install_dir: libds_tizen_bindir, install: true, ) @@ -65,15 +58,6 @@ executable('ds-simple-dpms', install: true, ) -executable('text-entry', - text_entry_files, - dependencies: [text_entry_deps, - deps_libds_tizen_text_input, - ], - install_dir: libds_tizen_bindir, - install: true, -) - input_generator_files = ['input-generator.c'] input_generator_deps = [ dependency('wayland-client', required: true), diff --git a/clients/simple-tbm.c b/clients/simple-tbm.c index f68fedb..46d48dd 100644 --- a/clients/simple-tbm.c +++ b/clients/simple-tbm.c @@ -39,9 +39,12 @@ #include #include "xdg-shell-client-protocol.h" #include +#include +#include static uint64_t buffer_info_key; #define BUFFER_INFO_KEY (unsigned long)(&buffer_info_key) +struct text_entry; struct display { struct wl_display *display; @@ -57,6 +60,9 @@ struct display { int notified; bool blocked; struct wl_surface *entered_surface; + + struct wl_text_input_manager *text_input_mgr; + struct text_entry *entry; }; struct window { @@ -75,10 +81,54 @@ struct buffer_info { struct wl_buffer *wl_buffer; }; +struct text_entry { + char *text; + int active; + bool panel_visible; + uint32_t cursor; + uint32_t anchor; + struct { + char *text; + int32_t cursor; + char *commit; + } preedit; + struct { + int32_t cursor; + } preedit_info; + struct { + int32_t cursor; + int32_t anchor; + uint32_t delete_index; + uint32_t delete_length; + bool invalid_delete; + } pending_commit; + struct wl_text_input *text_input; + struct { + xkb_mod_mask_t shift_mask; + } keysym; + uint32_t serial; + uint32_t reset_serial; + uint32_t content_purpose; + bool click_to_show; + char *preferred_language; + bool button_pressed; +}; + +struct rectangle { + int32_t x; + int32_t y; + int32_t width; + int32_t height; +}; + static int running = 1; static void redraw(void *data, struct wl_callback *callback, uint32_t time); +static void +text_entry_activate(struct display *d); +static void +text_entry_deactivate(struct display *d); static void handle_xdg_surface_configure(void *data, struct xdg_surface *surface, @@ -343,20 +393,27 @@ static void pointer_handle_button(void *data, struct wl_pointer *pointer, static int warp_x = 0, warp_y = 0; if (state == WL_POINTER_BUTTON_STATE_PRESSED) { - fprintf(stderr, "pointer_handle_button: PRESSED\n"); - - warp_x += 10; - warp_y += 10; - tizen_input_device_manager_pointer_warp(d->devicemgr, - d->entered_surface, - wl_fixed_from_int(warp_x), - wl_fixed_from_int(warp_y)); - fprintf(stderr, "requesting pointer_warp: surface:%p sx: %d sy: %d\n", - d->entered_surface, - warp_x, warp_y); + fprintf(stderr, "pointer_handle_button: button(%d) PRESSED\n", button); + if (button == 1) { //left button + text_entry_activate(d); + } + else if (button == 3) {//right button + warp_x += 10; + warp_y += 10; + tizen_input_device_manager_pointer_warp(d->devicemgr, + d->entered_surface, + wl_fixed_from_int(warp_x), + wl_fixed_from_int(warp_y)); + fprintf(stderr, "requesting pointer_warp: surface:%p sx: %d sy: %d\n", + d->entered_surface, + warp_x, warp_y); + } } else { - fprintf(stderr, "pointer_handle_button: RELEASED\n"); + fprintf(stderr, "pointer_handle_button: button(%d) RELEASED\n", button); + if (button == 1) { + text_entry_deactivate(d); + } } } @@ -571,6 +628,519 @@ static const struct tizen_input_device_manager_listener _input_device_manager_li .block_expired = input_device_manager_handle_block_expired, }; + +static void +text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle) +{ + if (entry->preedit.text && entry->preedit.cursor < 0) { + rectangle->x = 0; + rectangle->y = 0; + rectangle->width = 0; + rectangle->height = 0; + return; + } + + rectangle->x = 10; + rectangle->y = 20; + rectangle->width = 50; + rectangle->height = 50; +} + +static void +text_entry_update(struct text_entry *entry) +{ + struct rectangle cursor_rectangle; + + fprintf(stderr, "text_entry_update()\n"); + + wl_text_input_set_content_type(entry->text_input, + WL_TEXT_INPUT_CONTENT_HINT_NONE, + entry->content_purpose); + + if (entry->preferred_language) + wl_text_input_set_preferred_language(entry->text_input, + entry->preferred_language); + + text_entry_get_cursor_rectangle(entry, &cursor_rectangle); + wl_text_input_set_cursor_rectangle(entry->text_input, + cursor_rectangle.x, + cursor_rectangle.y, + cursor_rectangle.width, + cursor_rectangle.height); + + wl_text_input_commit_state(entry->text_input, ++entry->serial); +} + +static void +text_entry_reset_preedit(struct text_entry *entry) +{ + fprintf(stderr, "text_entry_reset_preedit()\n"); + entry->preedit.cursor = 0; + + free(entry->preedit.text); + entry->preedit.text = NULL; + + free(entry->preedit.commit); + entry->preedit.commit = NULL; +} + +static void +text_entry_insert_at_cursor(struct text_entry *entry, const char *text, + int32_t cursor, int32_t anchor) +{ + fprintf(stderr, "text_entry_insert_at_cursor()\n"); + char *new_text; + int len_entry_text, len_text; + + len_entry_text = strlen(entry->text); + len_text = strlen(text); + new_text = malloc(len_entry_text + len_text + 1); + if (new_text == NULL) { + fprintf(stderr, "alloc fail"); + return; + } + + memcpy(new_text, entry->text, entry->cursor); + memcpy(new_text + entry->cursor, text, len_text); + memcpy(new_text + entry->cursor + len_text, + entry->text + entry->cursor, len_entry_text - entry->cursor); + new_text[len_entry_text + len_text] = '\0'; + + free(entry->text); + entry->text = new_text; + if (anchor >= 0) + entry->anchor = entry->cursor + strlen(text) + anchor; + else + entry->anchor = entry->cursor + 1 + anchor; + + if (cursor >= 0) + entry->cursor += strlen(text) + cursor; + else + entry->cursor += 1 + cursor; + + text_entry_update(entry); +} + +static void +text_entry_commit_and_reset(struct text_entry *entry) +{ + char *commit = NULL; + + fprintf(stderr, "text_entry_commit_and_reset()\n"); + + if (entry->preedit.commit) + commit = strdup(entry->preedit.commit); + + text_entry_reset_preedit(entry); + if (commit) { + text_entry_insert_at_cursor(entry, commit, 0, 0); + free(commit); + } + + wl_text_input_reset(entry->text_input); + text_entry_update(entry); + entry->reset_serial = entry->serial; +} + +static void +text_input_enter(void *data, struct wl_text_input *text_input, + struct wl_surface *surface) +{ + fprintf(stderr, "text_input_enter()\n"); + + struct display *d = data; + struct text_entry *entry = d->entry; + + entry->active++; + + text_entry_update(entry); + entry->reset_serial = entry->serial; +} + +static void +text_input_leave(void *data, struct wl_text_input *text_input) +{ + fprintf(stderr, "text_input_leave()\n"); + + struct display *d = data; + struct text_entry *entry = d->entry; + + text_entry_commit_and_reset(entry); + d->entry->active--; + + if (!entry->active) { + wl_text_input_hide_input_panel(text_input); + entry->panel_visible = false; + } +} + +static void +text_input_modifiers_map(void *data, struct wl_text_input *text_input, + struct wl_array *map) +{ + fprintf(stderr, "text_input_modifiers_map()\n"); +} + +static void +text_input_input_panel_state(void *data, struct wl_text_input *text_input, + uint32_t state) +{ + fprintf(stderr, "text_input_input_panel_state() state:%u\n", state); +} + +static void +clear_pending_preedit(struct text_entry *entry) +{ + fprintf(stderr, "clear_pending_preedit()\n"); + + memset(&entry->pending_commit, 0, sizeof entry->pending_commit); + + entry->preedit_info.cursor = 0; + + memset(&entry->preedit_info, 0, sizeof entry->preedit_info); +} + +static void +text_entry_delete_text(struct text_entry *entry, + uint32_t index, uint32_t length) +{ + uint32_t l; + + fprintf(stderr, "text_entry_delete_text()\n"); + + assert(index <= strlen(entry->text)); + assert(index + length <= strlen(entry->text)); + assert(index + length >= length); + + l = strlen(entry->text + index + length); + memmove(entry->text + index, + entry->text + index + length, + l + 1); + + if (entry->cursor > (index + length)) + entry->cursor -= length; + else if (entry->cursor > index) + entry->cursor = index; + + entry->anchor = entry->cursor; + + text_entry_update(entry); +} + +static void +text_entry_delete_selected_text(struct text_entry *entry) +{ + uint32_t start_index = entry->anchor < entry->cursor ? entry->anchor : entry->cursor; + uint32_t end_index = entry->anchor < entry->cursor ? entry->cursor : entry->anchor; + + fprintf(stderr, "text_entry_delete_selected_text()\n"); + + if (entry->anchor == entry->cursor) + return; + + text_entry_delete_text(entry, start_index, end_index - start_index); + + entry->anchor = entry->cursor; +} + +static void +text_entry_set_preedit(struct text_entry *entry, + const char *preedit_text, + int preedit_cursor) +{ + fprintf(stderr, "text_entry_set_preedit()\n"); + + text_entry_reset_preedit(entry); + + if (!preedit_text) + return; + + entry->preedit.text = strdup(preedit_text); + entry->preedit.cursor = preedit_cursor; +} + +static void +text_input_preedit_string(void *data, struct wl_text_input *text_input, + uint32_t serial, const char *text, const char *commit) +{ + struct display *d = data; + struct text_entry *entry = d->entry; + + fprintf(stderr, "text_input_preedit_string() serial(%u), text(%s), commit(%s)\n", serial, text, commit); + + if ((entry->serial - serial) > (entry->serial - entry->reset_serial)) { + fprintf(stderr, "Ignore preedit_string. Serial: %u, Current: %u, Reset: %u\n", + serial, entry->serial, entry->reset_serial); + clear_pending_preedit(entry); + return; + } + + if (entry->pending_commit.invalid_delete) { + fprintf(stderr, "Ignore preedit_string. Invalid previous delete_surrounding event.\n"); + clear_pending_preedit(entry); + return; + } + + if (entry->pending_commit.delete_length) { + text_entry_delete_text(entry, + entry->pending_commit.delete_index, + entry->pending_commit.delete_length); + } else { + text_entry_delete_selected_text(entry); + } + + text_entry_set_preedit(entry, text, entry->preedit_info.cursor); + entry->preedit.commit = strdup(commit); + + clear_pending_preedit(entry); + + text_entry_update(entry); +} + +static void +text_input_preedit_styling(void *data, struct wl_text_input *text_input, + uint32_t index, uint32_t length, uint32_t style) +{ + fprintf(stderr, "text_input_preedit_styling() index(%u), length(%u), style(%u)\n", index, length, style); + + switch (style) { + case WL_TEXT_INPUT_PREEDIT_STYLE_DEFAULT: + fprintf(stderr, "text_input_preedit_styling() style:DEFAULT"); + break; + case WL_TEXT_INPUT_PREEDIT_STYLE_UNDERLINE: + fprintf(stderr, "text_input_preedit_styling() style:UNDERLINE"); + break; + case WL_TEXT_INPUT_PREEDIT_STYLE_INCORRECT: + fprintf(stderr, "text_input_preedit_styling() style:INCORRECT"); + break; + case WL_TEXT_INPUT_PREEDIT_STYLE_SELECTION: + fprintf(stderr, "text_input_preedit_styling() style:SELECTION"); + break; + case WL_TEXT_INPUT_PREEDIT_STYLE_HIGHLIGHT: + fprintf(stderr, "text_input_preedit_styling() style:HIGHLIGHT"); + break; + case WL_TEXT_INPUT_PREEDIT_STYLE_ACTIVE: + fprintf(stderr, "text_input_preedit_styling() style:ACTIVE"); + break; + case WL_TEXT_INPUT_PREEDIT_STYLE_INACTIVE: + fprintf(stderr, "text_input_preedit_styling() style:INACTIVE"); + break; + default: + fprintf(stderr, "text_input_preedit_styling() no style enum found"); + break; + } +} + +static void +text_input_preedit_cursor(void *data, struct wl_text_input *text_input, + int32_t index) +{ + struct display *d = data; + struct text_entry *entry = d->entry; + + fprintf(stderr, "text_input_preedit_cursor() index(%u)\n", index); + + entry->preedit_info.cursor = index; +} + +static void +text_input_commit_string(void *data, struct wl_text_input *text_input, + uint32_t serial, const char *text) +{ + struct display *d = data; + struct text_entry *entry = d->entry; + + fprintf(stderr, "text_input_commit_string() serial(%u), text(%s)\n", serial, text); + + if ((entry->serial - serial) > (entry->serial - entry->reset_serial)) { + fprintf(stderr, "Ignore commit. Serial: %u, Current: %u, Reset: %u\n", + serial, entry->serial, entry->reset_serial); + return; + } + + if (entry->pending_commit.invalid_delete) { + fprintf(stderr, "Ignore commit. Invalid previous delete_surrounding event.\n"); + memset(&entry->pending_commit, 0, sizeof entry->pending_commit); + return; + } + + text_entry_reset_preedit(entry); + + if (entry->pending_commit.delete_length) { + text_entry_delete_text(entry, + entry->pending_commit.delete_index, + entry->pending_commit.delete_length); + } else { + text_entry_delete_selected_text(entry); + } + + text_entry_insert_at_cursor(entry, text, + entry->pending_commit.cursor, + entry->pending_commit.anchor); + + memset(&entry->pending_commit, 0, sizeof entry->pending_commit); +} + +static void +text_input_cursor_position(void *data, struct wl_text_input *text_input, + int32_t index, int32_t anchor) +{ + fprintf(stderr, "text_input_cursor_position() index(%d), anchor(%d)\n", index, anchor); +} + +static void +text_input_delete_surrounding_text(void *data, + struct wl_text_input *text_input, int32_t index, uint32_t length) +{ + struct text_entry *entry = data; + uint32_t text_length; + + fprintf(stderr, "text_input_delete_surrounding_text() index(%d), length(%u)\n", index, length); + + entry->pending_commit.delete_index = entry->cursor + index; + entry->pending_commit.delete_length = length; + entry->pending_commit.invalid_delete = false; + + text_length = strlen(entry->text); + + if (entry->pending_commit.delete_index > text_length || + length > text_length || + entry->pending_commit.delete_index + length > text_length) { + fprintf(stderr, "delete_surrounding_text: Invalid index: %d," \ + "length %u'; cursor: %u text length: %u\n", index, length, entry->cursor, text_length); + entry->pending_commit.invalid_delete = true; + return; + } +} + +static void +text_input_keysym(void *data, struct wl_text_input *text_input, + uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, + uint32_t modifiers) +{ + fprintf(stderr, "text_input_keysym() serial(%u), time(%u), sym(%u), state(%u), modifiers(%u)\n", + serial, time, sym, state, modifiers); +} + +static void +text_input_language(void *data, struct wl_text_input *text_input, + uint32_t serial, const char *language) +{ + fprintf(stderr, "text_input_language() serial(%u), language(%s)\n", serial, language); +} + +static void +text_input_text_direction(void *data, struct wl_text_input *text_input, + uint32_t serial, uint32_t direction) +{ + fprintf(stderr, "text_input_text_direction() serial(%d), direction(%d)\n", serial, direction); +} + +static const struct wl_text_input_listener text_input_listener = { + .enter = text_input_enter, + .leave = text_input_leave, + .modifiers_map = text_input_modifiers_map, + .input_panel_state = text_input_input_panel_state, + .preedit_string = text_input_preedit_string, + .preedit_styling = text_input_preedit_styling, + .preedit_cursor = text_input_preedit_cursor, + .commit_string = text_input_commit_string, + .cursor_position = text_input_cursor_position, + .delete_surrounding_text = text_input_delete_surrounding_text, + .keysym = text_input_keysym, + .language = text_input_language, + .text_direction = text_input_text_direction, + // TIZEN_ONLY + .selection_region = NULL, + .private_command = NULL, + .input_panel_geometry = NULL, + .input_panel_data = NULL, + .get_selection_text = NULL, + .get_surrounding_text = NULL, + .filter_key_event_done = NULL, + .hide_permission = NULL, + .recapture_string = NULL, + .input_panel_event = NULL, + .commit_content = NULL, + // +}; + +static void +text_entry_activate(struct display *d) +{ + struct wl_surface *surface = d->entered_surface; + struct text_entry *entry = d->entry; + + fprintf(stderr, "text_entry_activate\n"); + if (entry->click_to_show && entry->active) { + entry->panel_visible = !entry->panel_visible; + + if (entry->panel_visible) + wl_text_input_show_input_panel(entry->text_input); + else + wl_text_input_hide_input_panel(entry->text_input); + + return; + } + + if (!entry->click_to_show) + wl_text_input_show_input_panel(entry->text_input); + + wl_text_input_activate(entry->text_input, + d->seat, + surface); +} + +static void +text_entry_deactivate(struct display *d) +{ + struct text_entry *entry = d->entry; + + fprintf(stderr, "text_entry_deactivate\n"); + wl_text_input_deactivate(entry->text_input, + d->seat); +} + +static void +text_entry_destroy(struct display *d) +{ + struct text_entry *entry; + + entry = d->entry; + d->entry = NULL; + + wl_text_input_destroy(entry->text_input); + free(entry->text); + free(entry->preferred_language); + free(entry); +} + +static struct text_entry* +text_entry_create(struct display *d, const char *text) +{ + struct text_entry *entry; + + entry = calloc(1, sizeof *entry); + if (!entry) + return NULL; + + entry->text = strdup(text); + entry->active = 0; + entry->panel_visible = false; + entry->cursor = strlen(text); + entry->anchor = entry->cursor; + entry->click_to_show = true; + entry->text_input = + wl_text_input_manager_create_text_input(d->text_input_mgr); + wl_text_input_add_listener(entry->text_input, + &text_input_listener, d); + + d->entry = entry; + fprintf(stderr, "text_entry_create() entry(%p) created.\n", entry); + + return entry; +} + static void registry_handle_global(void *data, struct wl_registry *registry, uint32_t id, const char *interface, uint32_t version) @@ -600,6 +1170,12 @@ registry_handle_global(void *data, struct wl_registry *registry, tizen_input_device_manager_add_listener(d->devicemgr, &_input_device_manager_listener, d); fprintf(stderr, "tizen input device manager bound!\n"); + } else if (strcmp(interface, "wl_text_input_manager") == 0) { + d->text_input_mgr = wl_registry_bind(registry, + id, &wl_text_input_manager_interface, version); + fprintf(stderr, "wl_text_input_manager bound!\n"); + + text_entry_create(d, "Entry"); } } @@ -698,6 +1274,11 @@ create_display(void) static void destroy_display(struct display *display) { + text_entry_destroy(display); + + if (display->text_input_mgr) + wl_text_input_manager_destroy(display->text_input_mgr); + if (display->seat) wl_seat_destroy(display->seat); diff --git a/clients/text-entry.c b/clients/text-entry.c deleted file mode 100644 index 0561e56..0000000 --- a/clients/text-entry.c +++ /dev/null @@ -1,1261 +0,0 @@ -/* - * Copyright © 2011 Benjamin Franzke - * Copyright © 2010 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include "xdg-shell-client-protocol.h" -#include -#include - -static uint64_t buffer_info_key; -#define BUFFER_INFO_KEY (unsigned long)(&buffer_info_key) - -struct display { - struct wl_display *display; - struct wl_registry *registry; - struct wl_compositor *compositor; - struct xdg_wm_base *wm_base; - struct wl_shm *shm; - struct wl_seat *seat; - struct wayland_tbm_client *wl_tbm; - bool has_xrgb; - - struct wl_text_input_manager *text_input_mgr; - int notified; - bool blocked; - struct wl_surface *entered_surface; - - struct text_entry *entry; -}; - -struct window { - struct display *display; - int width, height; - struct wl_surface *surface; - struct xdg_surface *xdg_surface; - struct xdg_toplevel *xdg_toplevel; - struct wl_callback *callback; - tbm_surface_queue_h surface_queue; - bool wait_for_configure; -}; - -struct buffer_info { - struct window *window; - struct wl_buffer *wl_buffer; -}; - -struct text_entry { - char *text; - int active; - bool panel_visible; - uint32_t cursor; - uint32_t anchor; - struct { - char *text; - int32_t cursor; - char *commit; - } preedit; - struct { - int32_t cursor; - } preedit_info; - struct { - int32_t cursor; - int32_t anchor; - uint32_t delete_index; - uint32_t delete_length; - bool invalid_delete; - } pending_commit; - struct wl_text_input *text_input; - struct { - xkb_mod_mask_t shift_mask; - } keysym; - uint32_t serial; - uint32_t reset_serial; - uint32_t content_purpose; - bool click_to_show; - char *preferred_language; - bool button_pressed; -}; - -struct rectangle { - int32_t x; - int32_t y; - int32_t width; - int32_t height; -}; - -static int running = 1; - -static void -redraw(void *data, struct wl_callback *callback, uint32_t time); -static void -text_entry_activate(struct display *d); -static void -text_entry_deactivate(struct display *d); - -static void -handle_xdg_surface_configure(void *data, struct xdg_surface *surface, - uint32_t serial) -{ - struct window *window = data; - - xdg_surface_ack_configure(surface, serial); - - if (window->wait_for_configure) { - redraw(window, NULL, 0); - window->wait_for_configure = false; - } -} - -static const struct xdg_surface_listener xdg_surface_listener = { - handle_xdg_surface_configure, -}; - -static void -handle_xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel, - int32_t width, int32_t height, - struct wl_array *state) -{ -} - -static void -handle_xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel) -{ - running = 0; -} - -static const struct xdg_toplevel_listener xdg_toplevel_listener = { - handle_xdg_toplevel_configure, - handle_xdg_toplevel_close, -}; - -static struct window * -create_window(struct display *display, int width, int height) -{ - struct window *window; - - window = calloc(1, sizeof *window); - if (!window) - return NULL; - - window->callback = NULL; - window->display = display; - window->width = width; - window->height = height; - window->surface = wl_compositor_create_surface(display->compositor); - - if (display->wm_base) { - window->xdg_surface = - xdg_wm_base_get_xdg_surface(display->wm_base, - window->surface); - assert(window->xdg_surface); - xdg_surface_add_listener(window->xdg_surface, - &xdg_surface_listener, window); - - window->xdg_toplevel = - xdg_surface_get_toplevel(window->xdg_surface); - assert(window->xdg_toplevel); - xdg_toplevel_add_listener(window->xdg_toplevel, - &xdg_toplevel_listener, window); - - xdg_toplevel_set_title(window->xdg_toplevel, "simple-tbm"); - wl_surface_commit(window->surface); - window->wait_for_configure = true; - } else { - assert(0); - } - - window->surface_queue = - wayland_tbm_client_create_surface_queue(display->wl_tbm, - window->surface, - 3, - width, - height, - TBM_FORMAT_XRGB8888); - assert(window->surface_queue); - - return window; -} - -static void -destroy_window(struct window *window) -{ - tbm_surface_queue_destroy(window->surface_queue); - - if (window->callback) - wl_callback_destroy(window->callback); - - if (window->xdg_toplevel) - xdg_toplevel_destroy(window->xdg_toplevel); - if (window->xdg_surface) - xdg_surface_destroy(window->xdg_surface); - wl_surface_destroy(window->surface); - free(window); -} - -static void -paint_pixels(void *image, int padding, int width, int height, uint32_t time) -{ - const int halfh = padding + (height - padding * 2) / 2; - const int halfw = padding + (width - padding * 2) / 2; - int ir, or; - uint32_t *pixel = image; - int y; - - /* squared radii thresholds */ - or = (halfw < halfh ? halfw : halfh) - 8; - ir = or - 32; - or *= or; - ir *= ir; - - pixel += padding * width; - for (y = padding; y < height - padding; y++) { - int x; - int y2 = (y - halfh) * (y - halfh); - - pixel += padding; - for (x = padding; x < width - padding; x++) { - uint32_t v; - - /* squared distance from center */ - int r2 = (x - halfw) * (x - halfw) + y2; - - if (r2 < ir) - v = (r2 / 32 + time / 64) * 0x0080401; - else if (r2 < or) - v = (y + time / 32) * 0x0080401; - else - v = (x + time / 16) * 0x0080401; - v &= 0x00ffffff; - - /* cross if compositor uses X from XRGB as alpha */ - if (abs(x - y) > 6 && abs(x + y - height) > 6) - v |= 0xff000000; - - *pixel++ = v; - } - - pixel += padding; - } -} - -static void -buffer_info_free_cb(void *data) -{ - struct buffer_info *buffer_info = data; - - if (!buffer_info) - return; - - wayland_tbm_client_destroy_buffer(buffer_info->window->display->wl_tbm, - buffer_info->wl_buffer); - free(buffer_info); -} - -static void -buffer_handle_release(void *data, struct wl_buffer *wl_buffer) -{ - tbm_surface_h surface = data; - struct buffer_info *buffer_info; - - tbm_surface_internal_get_user_data(surface, BUFFER_INFO_KEY, - (void **)&buffer_info); - if (buffer_info) - tbm_surface_queue_release(buffer_info->window->surface_queue, surface); -} - -static const struct wl_buffer_listener buffer_listener = { - .release = buffer_handle_release, -}; - -static const struct wl_callback_listener frame_listener; - -static void -redraw(void *data, struct wl_callback *callback, uint32_t time) -{ - struct window *window = data; - struct buffer_info *buffer_info = NULL; - tbm_surface_h surface = NULL; - tbm_surface_info_s surface_info; - - if (!tbm_surface_queue_can_dequeue(window->surface_queue, 0)) - return; - - tbm_surface_queue_dequeue(window->surface_queue, &surface); - assert(surface); - - tbm_surface_internal_get_user_data(surface, BUFFER_INFO_KEY, - (void **)&buffer_info); - if (!buffer_info) { - buffer_info = calloc(1, sizeof *buffer_info); - assert(buffer_info); - - tbm_surface_internal_add_user_data(surface, BUFFER_INFO_KEY, buffer_info_free_cb); - tbm_surface_internal_set_user_data(surface, BUFFER_INFO_KEY, buffer_info); - - buffer_info->wl_buffer = - wayland_tbm_client_create_buffer(window->display->wl_tbm, surface); - assert(buffer_info->wl_buffer); - - wl_buffer_add_listener(buffer_info->wl_buffer, &buffer_listener, - surface); - - buffer_info->window = window; - } - - tbm_surface_map(surface, TBM_SURF_OPTION_WRITE, &surface_info); - - paint_pixels(surface_info.planes[0].ptr, 20, - (surface_info.planes[0].stride/4), surface_info.height, time); - - tbm_surface_unmap(surface); - - wl_surface_attach(window->surface, buffer_info->wl_buffer, 0, 0); - wl_surface_damage(window->surface, - 20, 20, window->width - 40, window->height - 40); - - if (callback) - wl_callback_destroy(callback); - - window->callback = wl_surface_frame(window->surface); - wl_callback_add_listener(window->callback, &frame_listener, window); - wl_surface_commit(window->surface); -} - -static const struct wl_callback_listener frame_listener = { - redraw -}; - -static void -shm_format(void *data, struct wl_shm *wl_shm, uint32_t format) -{ - struct display *d = data; - - if (format == WL_SHM_FORMAT_XRGB8888) - d->has_xrgb = true; -} - -struct wl_shm_listener shm_listener = { - shm_format -}; - -static void -xdg_wm_base_ping(void *data, struct xdg_wm_base *shell, uint32_t serial) -{ - xdg_wm_base_pong(shell, serial); -} - -static const struct xdg_wm_base_listener xdg_wm_base_listener = { - xdg_wm_base_ping, -}; - -static void pointer_handle_button(void *data, struct wl_pointer *pointer, - uint32_t serial, uint32_t time, uint32_t button, uint32_t state) -{ - struct display *d = data; - - if (state == WL_POINTER_BUTTON_STATE_PRESSED) { - fprintf(stderr, "pointer_handle_button: PRESSED\n"); - - text_entry_activate(d); - } - else { - fprintf(stderr, "pointer_handle_button: RELEASED\n"); - - text_entry_deactivate(d); - } -} - -static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, - uint32_t serial, struct wl_surface *surface, - wl_fixed_t surface_x, wl_fixed_t surface_y) -{ - struct display *d = data; - - fprintf(stderr, "pointer_handle_enter surface_x:%d, surface_y:%d\n", - wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y)); - d->entered_surface = surface; -} - -static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer, - uint32_t serial, struct wl_surface *surface) -{ - fprintf(stderr, "pointer_handle_leave\n"); -} - -static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, - uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) -{ - fprintf(stderr, "pointer_handle_motion surface_x:%d, surface_y:%d\n", - wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y)); -} - -static void pointer_handle_frame(void *data, struct wl_pointer *wl_pointer) -{ - fprintf(stderr, "pointer_handle_frame\n"); -} - -static struct wl_pointer_listener pointer_listener = { - .enter = pointer_handle_enter, - .leave = pointer_handle_leave, - .motion = pointer_handle_motion, - .button = pointer_handle_button, - .axis = NULL, - .frame = pointer_handle_frame, - .axis_source = NULL, - .axis_stop = NULL, - .axis_discrete = NULL, -}; - -static void touch_handle_down(void *data, struct wl_touch *wl_touch, - uint32_t serial, uint32_t time, struct wl_surface *surface, - int32_t id, wl_fixed_t x, wl_fixed_t y) -{ - fprintf(stderr, "touch_handle_down id:%d, x:%d, y:%d\n", - id, wl_fixed_to_int(x), wl_fixed_to_int(y)); -} - -static void touch_handle_up(void *data, struct wl_touch *wl_touch, - uint32_t serial, uint32_t time, int32_t id) -{ - fprintf(stderr, "touch_handle_up id:%d\n", id); -} - -static void touch_handle_motion(void *data, struct wl_touch *wl_touch, - uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y) -{ - fprintf(stderr, "touch_handle_motion id:%d, x:%d, y:%d\n", - id, wl_fixed_to_int(x), wl_fixed_to_int(y)); -} - -static void touch_handle_frame(void *data, struct wl_touch *wl_touch) -{ - fprintf(stderr, "touch_handle_frame\n"); -} - -static struct wl_touch_listener touch_listener = { - .down = touch_handle_down, - .up = touch_handle_up, - .motion = touch_handle_motion, - .frame = touch_handle_frame, - .cancel = NULL, - .shape = NULL, - .orientation = NULL, -}; - -static void keyboard_handle_keymap(void *data, struct wl_keyboard *wl_keyboard, - uint32_t format, int32_t fd, uint32_t size) -{ - fprintf(stderr, "keyboard_handle_keymap\n"); -} -static void keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard, - uint32_t serial, struct wl_surface *surface, struct wl_array *keys) -{ - fprintf(stderr, "keyboard_handle_enter\n"); -} -static void keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard, - uint32_t serial, struct wl_surface *surface) -{ - fprintf(stderr, "keyboard_handle_leave\n"); -} -static void keyboard_handle_modifiers(void *data, struct wl_keyboard *wl_keyboard, - uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, - uint32_t mods_locked, uint32_t group) -{ - fprintf(stderr, "keyboard_handle_modifiers\n"); -} -static void keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard, - int32_t rate, int32_t delay) -{ - fprintf(stderr, "keyboard_handle_repeat_info\n"); -} - -static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard, - uint32_t serial, uint32_t time, uint32_t key, uint32_t state) -{ - if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { - fprintf(stderr, "keyboard_handle_key: key:%d, PRESSED\n", key); - } else { - fprintf(stderr, "keyboard_handle_key: key:%d, RELEASED\n", key); - } -} - -static struct wl_keyboard_listener keyboard_listener = { - .keymap = keyboard_handle_keymap, - .enter = keyboard_handle_enter, - .leave = keyboard_handle_leave, - .key = keyboard_handle_key, - .modifiers = keyboard_handle_modifiers, - .repeat_info = keyboard_handle_repeat_info, -}; - -static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, - enum wl_seat_capability caps) -{ - struct display *d = data; - if ((caps & WL_SEAT_CAPABILITY_KEYBOARD)) { - struct wl_keyboard *keyboard = wl_seat_get_keyboard(wl_seat); - wl_keyboard_add_listener(keyboard, &keyboard_listener, NULL); - fprintf(stderr, "seat_handle_capabilities: keyboard\n"); - } - if ((caps & WL_SEAT_CAPABILITY_POINTER)) { - struct wl_pointer *pointer = wl_seat_get_pointer(wl_seat); - wl_pointer_add_listener(pointer, &pointer_listener, d); - fprintf(stderr, "seat_handle_capabilities: pointer\n"); - } - if ((caps & WL_SEAT_CAPABILITY_TOUCH)) { - struct wl_touch *touch = wl_seat_get_touch(wl_seat); - wl_touch_add_listener(touch, &touch_listener, d); - fprintf(stderr, "seat_handle_capabilities: touch\n"); - } -} - -static void seat_handle_name(void *data, struct wl_seat *wl_seat, - const char *name) -{ - fprintf(stderr, "seat_handle_name name:%s\n", name); -} - -const struct wl_seat_listener seat_listener = { - .capabilities = seat_handle_capabilities, - .name = seat_handle_name, -}; - -static void -text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle) -{ - if (entry->preedit.text && entry->preedit.cursor < 0) { - rectangle->x = 0; - rectangle->y = 0; - rectangle->width = 0; - rectangle->height = 0; - return; - } - - rectangle->x = 10; - rectangle->y = 20; - rectangle->width = 50; - rectangle->height = 50; -} - -static void -text_entry_update(struct text_entry *entry) -{ - struct rectangle cursor_rectangle; - - fprintf(stderr, "text_entry_update()\n"); - - wl_text_input_set_content_type(entry->text_input, - WL_TEXT_INPUT_CONTENT_HINT_NONE, - entry->content_purpose); - - if (entry->preferred_language) - wl_text_input_set_preferred_language(entry->text_input, - entry->preferred_language); - - text_entry_get_cursor_rectangle(entry, &cursor_rectangle); - wl_text_input_set_cursor_rectangle(entry->text_input, - cursor_rectangle.x, - cursor_rectangle.y, - cursor_rectangle.width, - cursor_rectangle.height); - - wl_text_input_commit_state(entry->text_input, ++entry->serial); -} - -static void -text_entry_reset_preedit(struct text_entry *entry) -{ - fprintf(stderr, "text_entry_reset_preedit()\n"); - entry->preedit.cursor = 0; - - free(entry->preedit.text); - entry->preedit.text = NULL; - - free(entry->preedit.commit); - entry->preedit.commit = NULL; -} - -static void -text_entry_insert_at_cursor(struct text_entry *entry, const char *text, - int32_t cursor, int32_t anchor) -{ - fprintf(stderr, "text_entry_insert_at_cursor()\n"); - char *new_text; - int len_entry_text, len_text; - - len_entry_text = strlen(entry->text); - len_text = strlen(text); - new_text = malloc(len_entry_text + len_text + 1); - if (new_text == NULL) { - fprintf(stderr, "alloc fail"); - return; - } - - memcpy(new_text, entry->text, entry->cursor); - memcpy(new_text + entry->cursor, text, len_text); - memcpy(new_text + entry->cursor + len_text, - entry->text + entry->cursor, len_entry_text - entry->cursor); - new_text[len_entry_text + len_text] = '\0'; - - free(entry->text); - entry->text = new_text; - if (anchor >= 0) - entry->anchor = entry->cursor + strlen(text) + anchor; - else - entry->anchor = entry->cursor + 1 + anchor; - - if (cursor >= 0) - entry->cursor += strlen(text) + cursor; - else - entry->cursor += 1 + cursor; - - text_entry_update(entry); -} - -static void -text_entry_commit_and_reset(struct text_entry *entry) -{ - char *commit = NULL; - - fprintf(stderr, "text_entry_commit_and_reset()\n"); - - if (entry->preedit.commit) - commit = strdup(entry->preedit.commit); - - text_entry_reset_preedit(entry); - if (commit) { - text_entry_insert_at_cursor(entry, commit, 0, 0); - free(commit); - } - - wl_text_input_reset(entry->text_input); - text_entry_update(entry); - entry->reset_serial = entry->serial; -} - -static void -text_input_enter(void *data, struct wl_text_input *text_input, - struct wl_surface *surface) -{ - fprintf(stderr, "text_input_enter()\n"); - - struct display *d = data; - struct text_entry *entry = d->entry; - - entry->active++; - - text_entry_update(entry); - entry->reset_serial = entry->serial; -} - -static void -text_input_leave(void *data, struct wl_text_input *text_input) -{ - fprintf(stderr, "text_input_leave()\n"); - - struct display *d = data; - struct text_entry *entry = d->entry; - - text_entry_commit_and_reset(entry); - d->entry->active--; - - if (!entry->active) { - wl_text_input_hide_input_panel(text_input); - entry->panel_visible = false; - } -} - -static void -text_input_modifiers_map(void *data, struct wl_text_input *text_input, - struct wl_array *map) -{ - fprintf(stderr, "text_input_modifiers_map()\n"); -} - -static void -text_input_input_panel_state(void *data, struct wl_text_input *text_input, - uint32_t state) -{ - fprintf(stderr, "text_input_input_panel_state() state:%u\n", state); -} - -static void -clear_pending_preedit(struct text_entry *entry) -{ - fprintf(stderr, "clear_pending_preedit()\n"); - - memset(&entry->pending_commit, 0, sizeof entry->pending_commit); - - entry->preedit_info.cursor = 0; - - memset(&entry->preedit_info, 0, sizeof entry->preedit_info); -} - -static void -text_entry_delete_text(struct text_entry *entry, - uint32_t index, uint32_t length) -{ - uint32_t l; - - fprintf(stderr, "text_entry_delete_text()\n"); - - assert(index <= strlen(entry->text)); - assert(index + length <= strlen(entry->text)); - assert(index + length >= length); - - l = strlen(entry->text + index + length); - memmove(entry->text + index, - entry->text + index + length, - l + 1); - - if (entry->cursor > (index + length)) - entry->cursor -= length; - else if (entry->cursor > index) - entry->cursor = index; - - entry->anchor = entry->cursor; - - text_entry_update(entry); -} - -static void -text_entry_delete_selected_text(struct text_entry *entry) -{ - uint32_t start_index = entry->anchor < entry->cursor ? entry->anchor : entry->cursor; - uint32_t end_index = entry->anchor < entry->cursor ? entry->cursor : entry->anchor; - - fprintf(stderr, "text_entry_delete_selected_text()\n"); - - if (entry->anchor == entry->cursor) - return; - - text_entry_delete_text(entry, start_index, end_index - start_index); - - entry->anchor = entry->cursor; -} - -static void -text_entry_set_preedit(struct text_entry *entry, - const char *preedit_text, - int preedit_cursor) -{ - fprintf(stderr, "text_entry_set_preedit()\n"); - - text_entry_reset_preedit(entry); - - if (!preedit_text) - return; - - entry->preedit.text = strdup(preedit_text); - entry->preedit.cursor = preedit_cursor; -} - -static void -text_input_preedit_string(void *data, struct wl_text_input *text_input, - uint32_t serial, const char *text, const char *commit) -{ - struct display *d = data; - struct text_entry *entry = d->entry; - - fprintf(stderr, "text_input_preedit_string() serial(%u), text(%s), commit(%s)\n", serial, text, commit); - - if ((entry->serial - serial) > (entry->serial - entry->reset_serial)) { - fprintf(stderr, "Ignore preedit_string. Serial: %u, Current: %u, Reset: %u\n", - serial, entry->serial, entry->reset_serial); - clear_pending_preedit(entry); - return; - } - - if (entry->pending_commit.invalid_delete) { - fprintf(stderr, "Ignore preedit_string. Invalid previous delete_surrounding event.\n"); - clear_pending_preedit(entry); - return; - } - - if (entry->pending_commit.delete_length) { - text_entry_delete_text(entry, - entry->pending_commit.delete_index, - entry->pending_commit.delete_length); - } else { - text_entry_delete_selected_text(entry); - } - - text_entry_set_preedit(entry, text, entry->preedit_info.cursor); - entry->preedit.commit = strdup(commit); - - clear_pending_preedit(entry); - - text_entry_update(entry); -} - -static void -text_input_preedit_styling(void *data, struct wl_text_input *text_input, - uint32_t index, uint32_t length, uint32_t style) -{ - fprintf(stderr, "text_input_preedit_styling() index(%u), length(%u), style(%u)\n", index, length, style); - - switch (style) { - case WL_TEXT_INPUT_PREEDIT_STYLE_DEFAULT: - fprintf(stderr, "text_input_preedit_styling() style:DEFAULT"); - break; - case WL_TEXT_INPUT_PREEDIT_STYLE_UNDERLINE: - fprintf(stderr, "text_input_preedit_styling() style:UNDERLINE"); - break; - case WL_TEXT_INPUT_PREEDIT_STYLE_INCORRECT: - fprintf(stderr, "text_input_preedit_styling() style:INCORRECT"); - break; - case WL_TEXT_INPUT_PREEDIT_STYLE_SELECTION: - fprintf(stderr, "text_input_preedit_styling() style:SELECTION"); - break; - case WL_TEXT_INPUT_PREEDIT_STYLE_HIGHLIGHT: - fprintf(stderr, "text_input_preedit_styling() style:HIGHLIGHT"); - break; - case WL_TEXT_INPUT_PREEDIT_STYLE_ACTIVE: - fprintf(stderr, "text_input_preedit_styling() style:ACTIVE"); - break; - case WL_TEXT_INPUT_PREEDIT_STYLE_INACTIVE: - fprintf(stderr, "text_input_preedit_styling() style:INACTIVE"); - break; - default: - fprintf(stderr, "text_input_preedit_styling() no style enum found"); - break; - } -} - -static void -text_input_preedit_cursor(void *data, struct wl_text_input *text_input, - int32_t index) -{ - struct display *d = data; - struct text_entry *entry = d->entry; - - fprintf(stderr, "text_input_preedit_cursor() index(%u)\n", index); - - entry->preedit_info.cursor = index; -} - -static void -text_input_commit_string(void *data, struct wl_text_input *text_input, - uint32_t serial, const char *text) -{ - struct display *d = data; - struct text_entry *entry = d->entry; - - fprintf(stderr, "text_input_commit_string() serial(%u), text(%s)\n", serial, text); - - if ((entry->serial - serial) > (entry->serial - entry->reset_serial)) { - fprintf(stderr, "Ignore commit. Serial: %u, Current: %u, Reset: %u\n", - serial, entry->serial, entry->reset_serial); - return; - } - - if (entry->pending_commit.invalid_delete) { - fprintf(stderr, "Ignore commit. Invalid previous delete_surrounding event.\n"); - memset(&entry->pending_commit, 0, sizeof entry->pending_commit); - return; - } - - text_entry_reset_preedit(entry); - - if (entry->pending_commit.delete_length) { - text_entry_delete_text(entry, - entry->pending_commit.delete_index, - entry->pending_commit.delete_length); - } else { - text_entry_delete_selected_text(entry); - } - - text_entry_insert_at_cursor(entry, text, - entry->pending_commit.cursor, - entry->pending_commit.anchor); - - memset(&entry->pending_commit, 0, sizeof entry->pending_commit); -} - -static void -text_input_cursor_position(void *data, struct wl_text_input *text_input, - int32_t index, int32_t anchor) -{ - fprintf(stderr, "text_input_cursor_position() index(%d), anchor(%d)\n", index, anchor); -} - -static void -text_input_delete_surrounding_text(void *data, - struct wl_text_input *text_input, int32_t index, uint32_t length) -{ - struct text_entry *entry = data; - uint32_t text_length; - - fprintf(stderr, "text_input_delete_surrounding_text() index(%d), length(%u)\n", index, length); - - entry->pending_commit.delete_index = entry->cursor + index; - entry->pending_commit.delete_length = length; - entry->pending_commit.invalid_delete = false; - - text_length = strlen(entry->text); - - if (entry->pending_commit.delete_index > text_length || - length > text_length || - entry->pending_commit.delete_index + length > text_length) { - fprintf(stderr, "delete_surrounding_text: Invalid index: %d," \ - "length %u'; cursor: %u text length: %u\n", index, length, entry->cursor, text_length); - entry->pending_commit.invalid_delete = true; - return; - } -} - -static void -text_input_keysym(void *data, struct wl_text_input *text_input, - uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, - uint32_t modifiers) -{ - fprintf(stderr, "text_input_keysym() serial(%u), time(%u), sym(%u), state(%u), modifiers(%u)\n", - serial, time, sym, state, modifiers); -} - -static void -text_input_language(void *data, struct wl_text_input *text_input, - uint32_t serial, const char *language) -{ - fprintf(stderr, "text_input_language() serial(%u), language(%s)\n", serial, language); -} - -static void -text_input_text_direction(void *data, struct wl_text_input *text_input, - uint32_t serial, uint32_t direction) -{ - fprintf(stderr, "text_input_text_direction() serial(%d), direction(%d)\n", serial, direction); -} - -static const struct wl_text_input_listener text_input_listener = { - .enter = text_input_enter, - .leave = text_input_leave, - .modifiers_map = text_input_modifiers_map, - .input_panel_state = text_input_input_panel_state, - .preedit_string = text_input_preedit_string, - .preedit_styling = text_input_preedit_styling, - .preedit_cursor = text_input_preedit_cursor, - .commit_string = text_input_commit_string, - .cursor_position = text_input_cursor_position, - .delete_surrounding_text = text_input_delete_surrounding_text, - .keysym = text_input_keysym, - .language = text_input_language, - .text_direction = text_input_text_direction, - // TIZEN_ONLY - .selection_region = NULL, - .private_command = NULL, - .input_panel_geometry = NULL, - .input_panel_data = NULL, - .get_selection_text = NULL, - .get_surrounding_text = NULL, - .filter_key_event_done = NULL, - .hide_permission = NULL, - .recapture_string = NULL, - .input_panel_event = NULL, - .commit_content = NULL, - // -}; - -static void -text_entry_activate(struct display *d) -{ - struct wl_surface *surface = d->entered_surface; - struct text_entry *entry = d->entry; - - fprintf(stderr, "text_entry_activate\n"); - if (entry->click_to_show && entry->active) { - entry->panel_visible = !entry->panel_visible; - - if (entry->panel_visible) - wl_text_input_show_input_panel(entry->text_input); - else - wl_text_input_hide_input_panel(entry->text_input); - - return; - } - - if (!entry->click_to_show) - wl_text_input_show_input_panel(entry->text_input); - - wl_text_input_activate(entry->text_input, - d->seat, - surface); -} - -static void -text_entry_deactivate(struct display *d) -{ - struct text_entry *entry = d->entry; - - fprintf(stderr, "text_entry_deactivate\n"); - wl_text_input_deactivate(entry->text_input, - d->seat); -} - -static void -text_entry_destroy(struct display *d) -{ - struct text_entry *entry; - - entry = d->entry; - d->entry = NULL; - - wl_text_input_destroy(entry->text_input); - free(entry->text); - free(entry->preferred_language); - free(entry); -} - -static struct text_entry* -text_entry_create(struct display *d, const char *text) -{ - struct text_entry *entry; - - entry = calloc(1, sizeof *entry); - if (!entry) - return NULL; - - entry->text = strdup(text); - entry->active = 0; - entry->panel_visible = false; - entry->cursor = strlen(text); - entry->anchor = entry->cursor; - entry->click_to_show = true; - entry->text_input = - wl_text_input_manager_create_text_input(d->text_input_mgr); - wl_text_input_add_listener(entry->text_input, - &text_input_listener, d); - - d->entry = entry; - fprintf(stderr, "text_entry_create() entry(%p) created.\n", entry); - - return entry; -} - -static void -registry_handle_global(void *data, struct wl_registry *registry, - uint32_t id, const char *interface, uint32_t version) -{ - struct display *d = data; - - if (strcmp(interface, "wl_compositor") == 0) { - d->compositor = - wl_registry_bind(registry, - id, &wl_compositor_interface, 1); - } else if (strcmp(interface, "xdg_wm_base") == 0) { - d->wm_base = wl_registry_bind(registry, - id, &xdg_wm_base_interface, 1); - xdg_wm_base_add_listener(d->wm_base, &xdg_wm_base_listener, d); - } else if (strcmp(interface, "wl_shm") == 0) { - d->shm = wl_registry_bind(registry, - id, &wl_shm_interface, 1); - wl_shm_add_listener(d->shm, &shm_listener, d); - } else if (strcmp(interface, "wl_seat") == 0) { - d->seat = wl_registry_bind(registry, - id, &wl_seat_interface, 7); - wl_seat_add_listener(d->seat, &seat_listener, d); - fprintf(stderr, "wl_seat bound!\n"); - } else if (strcmp(interface, "wl_text_input_manager") == 0) { - d->text_input_mgr = wl_registry_bind(registry, - id, &wl_text_input_manager_interface, version); - fprintf(stderr, "wl_text_input_manager bound!\n"); - - text_entry_create(d, "Entry"); - } -} - -static void -registry_handle_global_remove(void *data, struct wl_registry *registry, - uint32_t name) -{ -} - -static const struct wl_registry_listener registry_listener = { - registry_handle_global, - registry_handle_global_remove -}; - -static struct display * -create_display(void) -{ - struct display *display; - - display = calloc(1, sizeof *display); - if (display == NULL) { - fprintf(stderr, "out of memory\n"); - exit(1); - } - display->display = wl_display_connect(NULL); - assert(display->display); - - display->has_xrgb = false; - display->registry = wl_display_get_registry(display->display); - wl_registry_add_listener(display->registry, - ®istry_listener, display); - wl_display_roundtrip(display->display); - if (display->shm == NULL) { - fprintf(stderr, "No wl_shm global\n"); - exit(1); - } - - wl_display_roundtrip(display->display); - - /* - * Why do we need two roundtrips here? - * - * wl_display_get_registry() sends a request to the server, to which - * the server replies by emitting the wl_registry.global events. - * The first wl_display_roundtrip() sends wl_display.sync. The server - * first processes the wl_display.get_registry which includes sending - * the global events, and then processes the sync. Therefore when the - * sync (roundtrip) returns, we are guaranteed to have received and - * processed all the global events. - * - * While we are inside the first wl_display_roundtrip(), incoming - * events are dispatched, which causes registry_handle_global() to - * be called for each global. One of these globals is wl_shm. - * registry_handle_global() sends wl_registry.bind request for the - * wl_shm global. However, wl_registry.bind request is sent after - * the first wl_display.sync, so the reply to the sync comes before - * the initial events of the wl_shm object. - * - * The initial events that get sent as a reply to binding to wl_shm - * include wl_shm.format. These tell us which pixel formats are - * supported, and we need them before we can create buffers. They - * don't change at runtime, so we receive them as part of init. - * - * When the reply to the first sync comes, the server may or may not - * have sent the initial wl_shm events. Therefore we need the second - * wl_display_roundtrip() call here. - * - * The server processes the wl_registry.bind for wl_shm first, and - * the second wl_display.sync next. During our second call to - * wl_display_roundtrip() the initial wl_shm events are received and - * processed. Finally, when the reply to the second wl_display.sync - * arrives, it guarantees we have processed all wl_shm initial events. - * - * This sequence contains two examples on how wl_display_roundtrip() - * can be used to guarantee, that all reply events to a request - * have been received and processed. This is a general Wayland - * technique. - */ - - if (!display->has_xrgb) { - fprintf(stderr, "WL_SHM_FORMAT_XRGB32 not available\n"); - exit(1); - } - - display->wl_tbm = wayland_tbm_client_init(display->display); - if (!display->wl_tbm) { - fprintf(stderr, "failed wayland_tbm_client_init()\n"); - exit(1); - } - - display->notified = -1; - - return display; -} - -static void -destroy_display(struct display *display) -{ - text_entry_destroy(display); - - if (display->text_input_mgr) - wl_text_input_manager_destroy(display->text_input_mgr); - - if (display->seat) - wl_seat_destroy(display->seat); - - if (display->shm) - wl_shm_destroy(display->shm); - - if (display->wm_base) - xdg_wm_base_destroy(display->wm_base); - - if (display->compositor) - wl_compositor_destroy(display->compositor); - - wayland_tbm_client_deinit(display->wl_tbm); - wl_registry_destroy(display->registry); - wl_display_flush(display->display); - wl_display_disconnect(display->display); - free(display); -} - -static void -signal_int(int signum) -{ - running = 0; -} - -int -main(int argc, char **argv) -{ - struct sigaction sigint; - struct display *display; - struct window *window; - int ret = 0; - - display = create_display(); - window = create_window(display, 250, 250); - if (!window) - return 1; - - sigint.sa_handler = signal_int; - sigemptyset(&sigint.sa_mask); - sigint.sa_flags = SA_RESETHAND; - sigaction(SIGINT, &sigint, NULL); - - /* Initialise damage to full surface, so the padding gets painted */ - wl_surface_damage(window->surface, 0, 0, - window->width, window->height); - - if (!window->wait_for_configure) - redraw(window, NULL, 0); - - while (running && ret != -1) - ret = wl_display_dispatch(display->display); - - fprintf(stderr, "simple-shm exiting\n"); - - destroy_window(window); - destroy_display(display); - - return 0; -} diff --git a/packaging/libds-tizen.spec b/packaging/libds-tizen.spec index 37f9559..82a0fec 100644 --- a/packaging/libds-tizen.spec +++ b/packaging/libds-tizen.spec @@ -570,7 +570,6 @@ ninja -C builddir install %{_libdir}/pkgconfig/libds-tizen-text-input.pc %{_libdir}/libds-tizen-text-input.so %{_bindir}/libds-tizen-text-input-tests -%{_bindir}/text-entry %files input-method %manifest %{name}.manifest -- 2.7.4