From f656aa397f02d70dd51a4e450a021fb582b53732 Mon Sep 17 00:00:00 2001 From: Jan Arne Petersen Date: Wed, 17 Apr 2013 11:59:46 +0200 Subject: [PATCH] ecore_imf: Add support for wayland Add an input method module supporting the Wayland input method protocol. In v2: - Missing call to ecore_wl_shutdown() in im_module_shutdown() - Access the already stored 'wayland globals' with ecore_wl_globals_get() - Fixed compilation by adding -I(top_srcdir)/src/efl to CFLAGS - EFL formatting fixes Signed-off-by: Eduardo Lima (Etrunko) --- configure.ac | 18 + src/Makefile_Ecore_IMF.am | 26 + .../ecore_imf/wayland/text-client-protocol.h | 544 ++++++++++++ src/modules/ecore_imf/wayland/text-protocol.c | 94 +++ .../ecore_imf/wayland/wayland_imcontext.c | 778 ++++++++++++++++++ .../ecore_imf/wayland/wayland_imcontext.h | 70 ++ .../ecore_imf/wayland/wayland_module.c | 154 ++++ 7 files changed, 1684 insertions(+) create mode 100644 src/modules/ecore_imf/wayland/text-client-protocol.h create mode 100644 src/modules/ecore_imf/wayland/text-protocol.c create mode 100644 src/modules/ecore_imf/wayland/wayland_imcontext.c create mode 100644 src/modules/ecore_imf/wayland/wayland_imcontext.h create mode 100644 src/modules/ecore_imf/wayland/wayland_module.c diff --git a/configure.ac b/configure.ac index 4a6a4bec41..556f996afc 100644 --- a/configure.ac +++ b/configure.ac @@ -2771,6 +2771,7 @@ want_ecore_imf="yes" want_ecore_imf_xim="no" want_ecore_imf_scim="no" want_ecore_imf_ibus="no" +want_ecore_imf_wayland="no" if test "${have_wince}" = "yes"; then want_ecore_imf="no" @@ -2782,6 +2783,9 @@ else want_ecore_imf_xim="yes" want_ecore_imf_scim="yes" want_ecore_imf_ibus="yes" + if test "${want_wayland}" = "yes"; then + want_ecore_imf_wayland="yes" + fi fi fi @@ -2851,6 +2855,20 @@ fi AM_CONDITIONAL([BUILD_ECORE_IMF_XIM], [test "x${have_ecore_imf_xim}" = "xyes"]) EFL_ADD_FEATURE([ECORE_IMF], [xim]) +# wayland +if test "x${want_ecore_imf_wayland}" = "xyes" ; then + PKG_CHECK_MODULES([WAYLAND], + [wayland-client], + [ + have_ecore_imf_wayland="yes" + AC_DEFINE([BUILD_ECORE_IMF_WAYLAND], [1], [Ecore Imf Wayland Support]) + ], + [have_ecore_imf_wayland="no"]) +fi + +AM_CONDITIONAL([BUILD_ECORE_IMF_WAYLAND], [test "x${have_ecore_imf_wayland}" = "xyes"]) +EFL_ADD_FEATURE([ECORE_IMF], [wayland], [${want_ecore_imf_wayland}]) + ### Checks for header files ### Checks for types diff --git a/src/Makefile_Ecore_IMF.am b/src/Makefile_Ecore_IMF.am index cb6176986b..c4c78721c9 100644 --- a/src/Makefile_Ecore_IMF.am +++ b/src/Makefile_Ecore_IMF.am @@ -101,3 +101,29 @@ modules_ecore_imf_xim_module_la_DEPENDENCIES = \ modules_ecore_imf_xim_module_la_LDFLAGS = -module @EFL_LTMODULE_FLAGS@ modules_ecore_imf_xim_module_la_LIBTOOLFLAGS = --tag=disable-static endif + +# Wayland +if BUILD_ECORE_IMF_WAYLAND +ecoreimfwaylandpkgdir = $(libdir)/ecore_imf/modules/wayland/$(MODULE_ARCH) +ecoreimfwaylandpkg_LTLIBRARIES = modules/ecore_imf/wayland/module.la +modules_ecore_imf_wayland_module_la_SOURCES = \ +modules/ecore_imf/wayland/wayland_module.c \ +modules/ecore_imf/wayland/wayland_imcontext.c \ +modules/ecore_imf/wayland/wayland_imcontext.h \ +modules/ecore_imf/wayland/text-client-protocol.h \ +modules/ecore_imf/wayland/text-protocol.c +modules_ecore_imf_wayland_module_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ +@ECORE_IMF_CFLAGS@ \ +@ECORE_EVAS_CFLAGS@ \ +@ECORE_WAYLAND_CFLAGS@ +modules_ecore_imf_wayland_module_la_LIBADD = \ +@USE_ECORE_IMF_LIBS@ \ +@USE_ECORE_EVAS_LIBS@ \ +@USE_ECORE_WAYLAND_LIBS@ +modules_ecore_imf_wayland_module_la_DEPENDENCIES = \ +@USE_ECORE_IMF_INTERNAL_LIBS@ \ +@USE_ECORE_EVAS_INTERNAL_LIBS@ \ +@USE_ECORE_WAYLAND_INTERNAL_LIBS@ +modules_ecore_imf_wayland_module_la_LDFLAGS = -module @EFL_LTMODULE_FLAGS@ +modules_ecore_imf_wayland_module_la_LIBTOOLFLAGS = --tag=disable-static +endif diff --git a/src/modules/ecore_imf/wayland/text-client-protocol.h b/src/modules/ecore_imf/wayland/text-client-protocol.h new file mode 100644 index 0000000000..cfea94bbeb --- /dev/null +++ b/src/modules/ecore_imf/wayland/text-client-protocol.h @@ -0,0 +1,544 @@ +/* + * Copyright © 2012, 2013 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this + * software and its documentation for any purpose is hereby granted + * without fee, provided that the above copyright notice appear in + * all copies and that both that copyright notice and this permission + * notice appear in supporting documentation, and that the name of + * the copyright holders not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + * THIS SOFTWARE. + */ + +#ifndef TEXT_CLIENT_PROTOCOL_H +#define TEXT_CLIENT_PROTOCOL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "wayland-client.h" + +struct wl_client; +struct wl_resource; + +struct wl_text_input; +struct wl_text_input_manager; + +extern const struct wl_interface wl_text_input_interface; +extern const struct wl_interface wl_text_input_manager_interface; + +#ifndef WL_TEXT_INPUT_CONTENT_HINT_ENUM +#define WL_TEXT_INPUT_CONTENT_HINT_ENUM +/** + * wl_text_input_content_hint - content hint + * @WL_TEXT_INPUT_CONTENT_HINT_NONE: no special behaviour + * @WL_TEXT_INPUT_CONTENT_HINT_DEFAULT: auto completion, correction and + * capitalization + * @WL_TEXT_INPUT_CONTENT_HINT_PASSWORD: hidden and sensitive text + * @WL_TEXT_INPUT_CONTENT_HINT_AUTO_COMPLETION: suggest word completions + * @WL_TEXT_INPUT_CONTENT_HINT_AUTO_CORRECTION: suggest word corrections + * @WL_TEXT_INPUT_CONTENT_HINT_AUTO_CAPITALIZATION: switch to uppercase + * letters at the start of a sentence + * @WL_TEXT_INPUT_CONTENT_HINT_LOWERCASE: prefer lowercase letters + * @WL_TEXT_INPUT_CONTENT_HINT_UPPERCASE: prefer uppercase letters + * @WL_TEXT_INPUT_CONTENT_HINT_TITLECASE: prefer casing for titles and + * headings (can be language dependent) + * @WL_TEXT_INPUT_CONTENT_HINT_HIDDEN_TEXT: characters should be hidden + * @WL_TEXT_INPUT_CONTENT_HINT_SENSITIVE_DATA: typed text should not be + * stored + * @WL_TEXT_INPUT_CONTENT_HINT_LATIN: just latin characters should be + * entered + * @WL_TEXT_INPUT_CONTENT_HINT_MULTILINE: the text input is multiline + * + * Content hint is a bitmask to allow to modify the behavior of the text + * input. + */ +enum wl_text_input_content_hint { + WL_TEXT_INPUT_CONTENT_HINT_NONE = 0x0, + WL_TEXT_INPUT_CONTENT_HINT_DEFAULT = 0x7, + WL_TEXT_INPUT_CONTENT_HINT_PASSWORD = 0xc0, + WL_TEXT_INPUT_CONTENT_HINT_AUTO_COMPLETION = 0x1, + WL_TEXT_INPUT_CONTENT_HINT_AUTO_CORRECTION = 0x2, + WL_TEXT_INPUT_CONTENT_HINT_AUTO_CAPITALIZATION = 0x4, + WL_TEXT_INPUT_CONTENT_HINT_LOWERCASE = 0x8, + WL_TEXT_INPUT_CONTENT_HINT_UPPERCASE = 0x10, + WL_TEXT_INPUT_CONTENT_HINT_TITLECASE = 0x20, + WL_TEXT_INPUT_CONTENT_HINT_HIDDEN_TEXT = 0x40, + WL_TEXT_INPUT_CONTENT_HINT_SENSITIVE_DATA = 0x80, + WL_TEXT_INPUT_CONTENT_HINT_LATIN = 0x100, + WL_TEXT_INPUT_CONTENT_HINT_MULTILINE = 0x200, +}; +#endif /* WL_TEXT_INPUT_CONTENT_HINT_ENUM */ + +#ifndef WL_TEXT_INPUT_CONTENT_PURPOSE_ENUM +#define WL_TEXT_INPUT_CONTENT_PURPOSE_ENUM +/** + * wl_text_input_content_purpose - content purpose + * @WL_TEXT_INPUT_CONTENT_PURPOSE_NORMAL: default input, allowing all + * characters + * @WL_TEXT_INPUT_CONTENT_PURPOSE_ALPHA: allow only alphabetic characters + * @WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS: allow only digits + * @WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER: input a number (including + * decimal separator and sign) + * @WL_TEXT_INPUT_CONTENT_PURPOSE_PHONE: input a phone number + * @WL_TEXT_INPUT_CONTENT_PURPOSE_URL: input an URL + * @WL_TEXT_INPUT_CONTENT_PURPOSE_EMAIL: input an email address + * @WL_TEXT_INPUT_CONTENT_PURPOSE_NAME: input a name of a person + * @WL_TEXT_INPUT_CONTENT_PURPOSE_PASSWORD: input a password (combine + * with password or sensitive_data hint) + * @WL_TEXT_INPUT_CONTENT_PURPOSE_DATE: input a date + * @WL_TEXT_INPUT_CONTENT_PURPOSE_TIME: input a time + * @WL_TEXT_INPUT_CONTENT_PURPOSE_DATETIME: input a date and time + * @WL_TEXT_INPUT_CONTENT_PURPOSE_TERMINAL: input for a terminal + * + * The content purpose allows to specify the primary purpose of a text + * input. + * + * This allows an input method to show special purpose input panels with + * extra characters or to disallow some characters. + */ +enum wl_text_input_content_purpose { + WL_TEXT_INPUT_CONTENT_PURPOSE_NORMAL = 0, + WL_TEXT_INPUT_CONTENT_PURPOSE_ALPHA = 1, + WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS = 2, + WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER = 3, + WL_TEXT_INPUT_CONTENT_PURPOSE_PHONE = 4, + WL_TEXT_INPUT_CONTENT_PURPOSE_URL = 5, + WL_TEXT_INPUT_CONTENT_PURPOSE_EMAIL = 6, + WL_TEXT_INPUT_CONTENT_PURPOSE_NAME = 7, + WL_TEXT_INPUT_CONTENT_PURPOSE_PASSWORD = 8, + WL_TEXT_INPUT_CONTENT_PURPOSE_DATE = 9, + WL_TEXT_INPUT_CONTENT_PURPOSE_TIME = 10, + WL_TEXT_INPUT_CONTENT_PURPOSE_DATETIME = 11, + WL_TEXT_INPUT_CONTENT_PURPOSE_TERMINAL = 12, +}; +#endif /* WL_TEXT_INPUT_CONTENT_PURPOSE_ENUM */ + +#ifndef WL_TEXT_INPUT_PREEDIT_STYLE_ENUM +#define WL_TEXT_INPUT_PREEDIT_STYLE_ENUM +enum wl_text_input_preedit_style { + WL_TEXT_INPUT_PREEDIT_STYLE_DEFAULT = 0, + WL_TEXT_INPUT_PREEDIT_STYLE_NONE = 1, + WL_TEXT_INPUT_PREEDIT_STYLE_ACTIVE = 2, + WL_TEXT_INPUT_PREEDIT_STYLE_INACTIVE = 3, + WL_TEXT_INPUT_PREEDIT_STYLE_HIGHLIGHT = 4, + WL_TEXT_INPUT_PREEDIT_STYLE_UNDERLINE = 5, + WL_TEXT_INPUT_PREEDIT_STYLE_SELECTION = 6, + WL_TEXT_INPUT_PREEDIT_STYLE_INCORRECT = 7, +}; +#endif /* WL_TEXT_INPUT_PREEDIT_STYLE_ENUM */ + +#ifndef WL_TEXT_INPUT_TEXT_DIRECTION_ENUM +#define WL_TEXT_INPUT_TEXT_DIRECTION_ENUM +enum wl_text_input_text_direction { + WL_TEXT_INPUT_TEXT_DIRECTION_AUTO = 0, + WL_TEXT_INPUT_TEXT_DIRECTION_LTR = 1, + WL_TEXT_INPUT_TEXT_DIRECTION_RTL = 2, +}; +#endif /* WL_TEXT_INPUT_TEXT_DIRECTION_ENUM */ + +/** + * wl_text_input - text input + * @enter: enter event + * @leave: leave event + * @modifiers_map: modifiers map + * @input_panel_state: state of the input panel + * @preedit_string: pre-edit + * @preedit_styling: pre-edit styling + * @preedit_cursor: pre-edit cursor + * @commit_string: commit + * @cursor_position: set cursor to new position + * @delete_surrounding_text: delete surrounding text + * @keysym: keysym + * @language: language + * @text_direction: text direction + * + * An object used for text input. Adds support for text input and input + * methods to applications. A text-input object is created from a + * wl_text_input_manager and corresponds typically to a text entry in an + * application. Requests are used to activate/deactivate the text-input + * object and set state information like surrounding and selected text or + * the content type. The information about entered text is sent to the + * text-input object via the pre-edit and commit events. Using this + * interface removes the need for applications to directly process hardware + * key events and compose text out of them. + * + * Text is generally UTF-8 encoded, indices and lengths are in Unicode + * characters. + * + * Serials are used to synchronize the state between the text input and an + * input method. New serials are sent by the text input in the commit_state + * request and are used by the input method to indicate the known text + * input state in events like preedit_string, commit_string, and keysym. + * The text input can then ignore events from the input method which are + * based on an outdated state (for example after a reset). + */ +struct wl_text_input_listener { + /** + * enter - enter event + * @surface: (none) + * + * Notify the text-input object when it received focus. Typically + * in response to an activate request. + */ + void (*enter)(void *data, + struct wl_text_input *wl_text_input, + struct wl_surface *surface); + /** + * leave - leave event + * + * Notify the text-input object when it lost focus. Either in + * response to a deactivate request or when the assigned surface + * lost focus or was destroyed. + */ + void (*leave)(void *data, + struct wl_text_input *wl_text_input); + /** + * modifiers_map - modifiers map + * @map: (none) + * + * Transfer an array of 0-terminated modifiers names. The + * position in the array is the index of the modifier as used in + * the modifiers bitmask in the keysym event. + */ + void (*modifiers_map)(void *data, + struct wl_text_input *wl_text_input, + struct wl_array *map); + /** + * input_panel_state - state of the input panel + * @state: (none) + * + * Notify when the visibility state of the input panel changed. + */ + void (*input_panel_state)(void *data, + struct wl_text_input *wl_text_input, + uint32_t state); + /** + * preedit_string - pre-edit + * @serial: serial of the latest known text input state + * @text: (none) + * @commit: (none) + * + * Notify when a new composing text (pre-edit) should be set + * around the current cursor position. Any previously set composing + * text should be removed. + * + * The commit text can be used to replace the preedit text on reset + * (for example on unfocus). + * + * The text input should also handle all preedit_style and + * preedit_cursor events occuring directly before preedit_string. + */ + void (*preedit_string)(void *data, + struct wl_text_input *wl_text_input, + uint32_t serial, + const char *text, + const char *commit); + /** + * preedit_styling - pre-edit styling + * @index: (none) + * @length: (none) + * @style: (none) + * + * Sets styling information on composing text. The style is + * applied for length Unicode characters from index relative to the + * beginning of the composing text (as Unicode character offset). + * Multiple styles can be applied to a composing text by sending + * multiple preedit_styling events. + * + * This event is handled as part of a following preedit_string + * event. + */ + void (*preedit_styling)(void *data, + struct wl_text_input *wl_text_input, + uint32_t index, + uint32_t length, + uint32_t style); + /** + * preedit_cursor - pre-edit cursor + * @index: (none) + * + * Sets the cursor position inside the composing text (as Unicode + * character offset) relative to the start of the composing text. + * When index is a negative number no cursor is shown. + * + * This event is handled as part of a following preedit_string + * event. + */ + void (*preedit_cursor)(void *data, + struct wl_text_input *wl_text_input, + int32_t index); + /** + * commit_string - commit + * @serial: serial of the latest known text input state + * @text: (none) + * + * Notify when text should be inserted into the editor widget. + * The text to commit could be either just a single character after + * a key press or the result of some composing (pre-edit). It could + * be also an empty text when some text should be removed (see + * delete_surrounding_text) or when the input cursor should be + * moved (see cursor_position). + * + * Any previously set composing text should be removed. + */ + void (*commit_string)(void *data, + struct wl_text_input *wl_text_input, + uint32_t serial, + const char *text); + /** + * cursor_position - set cursor to new position + * @index: (none) + * @anchor: (none) + * + * Notify when the cursor or anchor position should be modified. + * + * This event should be handled as part of a following + * commit_string event. + */ + void (*cursor_position)(void *data, + struct wl_text_input *wl_text_input, + int32_t index, + int32_t anchor); + /** + * delete_surrounding_text - delete surrounding text + * @index: (none) + * @length: (none) + * + * Notify when the text around the current cursor position should + * be deleted. + * + * Index is relative to the current cursor (in Unicode characters). + * Length is the length of deleted text (in Unicode characters). + * + * This event should be handled as part of a following + * commit_string event. + */ + void (*delete_surrounding_text)(void *data, + struct wl_text_input *wl_text_input, + int32_t index, + uint32_t length); + /** + * keysym - keysym + * @serial: serial of the latest known text input state + * @time: (none) + * @sym: (none) + * @state: (none) + * @modifiers: (none) + * + * Notify when a key event was sent. Key events should not be + * used for normal text input operations, which should be done with + * commit_string, delete_surrounding_text, etc. The key event + * follows the wl_keyboard key event convention. Sym is a XKB + * keysym, state a wl_keyboard key_state. Modifiers are a mask for + * effective modifiers (where the modifier indices are set by the + * modifiers_map event) + */ + void (*keysym)(void *data, + struct wl_text_input *wl_text_input, + uint32_t serial, + uint32_t time, + uint32_t sym, + uint32_t state, + uint32_t modifiers); + /** + * language - language + * @serial: serial of the latest known text input state + * @language: (none) + * + * Sets the language of the input text. The "language" argument + * is a RFC-3066 format language tag. + */ + void (*language)(void *data, + struct wl_text_input *wl_text_input, + uint32_t serial, + const char *language); + /** + * text_direction - text direction + * @serial: serial of the latest known text input state + * @direction: (none) + * + * Sets the text direction of input text. + * + * It is mainly needed for showing input cursor on correct side of + * the editor when there is no input yet done and making sure + * neutral direction text is laid out properly. + */ + void (*text_direction)(void *data, + struct wl_text_input *wl_text_input, + uint32_t serial, + uint32_t direction); +}; + +static inline int +wl_text_input_add_listener(struct wl_text_input *wl_text_input, + const struct wl_text_input_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_text_input, + (void (**)(void)) listener, data); +} + +#define WL_TEXT_INPUT_ACTIVATE 0 +#define WL_TEXT_INPUT_DEACTIVATE 1 +#define WL_TEXT_INPUT_SHOW_INPUT_PANEL 2 +#define WL_TEXT_INPUT_HIDE_INPUT_PANEL 3 +#define WL_TEXT_INPUT_RESET 4 +#define WL_TEXT_INPUT_SET_SURROUNDING_TEXT 5 +#define WL_TEXT_INPUT_SET_CONTENT_TYPE 6 +#define WL_TEXT_INPUT_SET_CURSOR_RECTANGLE 7 +#define WL_TEXT_INPUT_SET_PREFERRED_LANGUAGE 8 +#define WL_TEXT_INPUT_COMMIT_STATE 9 +#define WL_TEXT_INPUT_INVOKE_ACTION 10 + +static inline void +wl_text_input_set_user_data(struct wl_text_input *wl_text_input, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_text_input, user_data); +} + +static inline void * +wl_text_input_get_user_data(struct wl_text_input *wl_text_input) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_text_input); +} + +static inline void +wl_text_input_destroy(struct wl_text_input *wl_text_input) +{ + wl_proxy_destroy((struct wl_proxy *) wl_text_input); +} + +static inline void +wl_text_input_activate(struct wl_text_input *wl_text_input, struct wl_seat *seat, struct wl_surface *surface) +{ + wl_proxy_marshal((struct wl_proxy *) wl_text_input, + WL_TEXT_INPUT_ACTIVATE, seat, surface); +} + +static inline void +wl_text_input_deactivate(struct wl_text_input *wl_text_input, struct wl_seat *seat) +{ + wl_proxy_marshal((struct wl_proxy *) wl_text_input, + WL_TEXT_INPUT_DEACTIVATE, seat); +} + +static inline void +wl_text_input_show_input_panel(struct wl_text_input *wl_text_input) +{ + wl_proxy_marshal((struct wl_proxy *) wl_text_input, + WL_TEXT_INPUT_SHOW_INPUT_PANEL); +} + +static inline void +wl_text_input_hide_input_panel(struct wl_text_input *wl_text_input) +{ + wl_proxy_marshal((struct wl_proxy *) wl_text_input, + WL_TEXT_INPUT_HIDE_INPUT_PANEL); +} + +static inline void +wl_text_input_reset(struct wl_text_input *wl_text_input) +{ + wl_proxy_marshal((struct wl_proxy *) wl_text_input, + WL_TEXT_INPUT_RESET); +} + +static inline void +wl_text_input_set_surrounding_text(struct wl_text_input *wl_text_input, const char *text, uint32_t cursor, uint32_t anchor) +{ + wl_proxy_marshal((struct wl_proxy *) wl_text_input, + WL_TEXT_INPUT_SET_SURROUNDING_TEXT, text, cursor, anchor); +} + +static inline void +wl_text_input_set_content_type(struct wl_text_input *wl_text_input, uint32_t hint, uint32_t purpose) +{ + wl_proxy_marshal((struct wl_proxy *) wl_text_input, + WL_TEXT_INPUT_SET_CONTENT_TYPE, hint, purpose); +} + +static inline void +wl_text_input_set_cursor_rectangle(struct wl_text_input *wl_text_input, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_proxy_marshal((struct wl_proxy *) wl_text_input, + WL_TEXT_INPUT_SET_CURSOR_RECTANGLE, x, y, width, height); +} + +static inline void +wl_text_input_set_preferred_language(struct wl_text_input *wl_text_input, const char *language) +{ + wl_proxy_marshal((struct wl_proxy *) wl_text_input, + WL_TEXT_INPUT_SET_PREFERRED_LANGUAGE, language); +} + +static inline void +wl_text_input_commit_state(struct wl_text_input *wl_text_input, uint32_t serial) +{ + wl_proxy_marshal((struct wl_proxy *) wl_text_input, + WL_TEXT_INPUT_COMMIT_STATE, serial); +} + +static inline void +wl_text_input_invoke_action(struct wl_text_input *wl_text_input, uint32_t button, uint32_t index) +{ + wl_proxy_marshal((struct wl_proxy *) wl_text_input, + WL_TEXT_INPUT_INVOKE_ACTION, button, index); +} + +#define WL_TEXT_INPUT_MANAGER_CREATE_TEXT_INPUT 0 + +static inline void +wl_text_input_manager_set_user_data(struct wl_text_input_manager *wl_text_input_manager, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_text_input_manager, user_data); +} + +static inline void * +wl_text_input_manager_get_user_data(struct wl_text_input_manager *wl_text_input_manager) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_text_input_manager); +} + +static inline void +wl_text_input_manager_destroy(struct wl_text_input_manager *wl_text_input_manager) +{ + wl_proxy_destroy((struct wl_proxy *) wl_text_input_manager); +} + +static inline struct wl_text_input * +wl_text_input_manager_create_text_input(struct wl_text_input_manager *wl_text_input_manager) +{ + struct wl_proxy *id; + + id = wl_proxy_create((struct wl_proxy *) wl_text_input_manager, + &wl_text_input_interface); + if (!id) + return NULL; + + wl_proxy_marshal((struct wl_proxy *) wl_text_input_manager, + WL_TEXT_INPUT_MANAGER_CREATE_TEXT_INPUT, id); + + return (struct wl_text_input *) id; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/modules/ecore_imf/wayland/text-protocol.c b/src/modules/ecore_imf/wayland/text-protocol.c new file mode 100644 index 0000000000..af549d5866 --- /dev/null +++ b/src/modules/ecore_imf/wayland/text-protocol.c @@ -0,0 +1,94 @@ +/* + * Copyright © 2012, 2013 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this + * software and its documentation for any purpose is hereby granted + * without fee, provided that the above copyright notice appear in + * all copies and that both that copyright notice and this permission + * notice appear in supporting documentation, and that the name of + * the copyright holders not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + * THIS SOFTWARE. + */ + +#include +#include +#include "wayland-util.h" + +extern const struct wl_interface wl_seat_interface; +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface wl_seat_interface; +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface wl_text_input_interface; + +static const struct wl_interface *types[] = { + NULL, + NULL, + NULL, + NULL, + NULL, + &wl_seat_interface, + &wl_surface_interface, + &wl_seat_interface, + &wl_surface_interface, + &wl_text_input_interface, +}; + +static const struct wl_message wl_text_input_requests[] = { + { "activate", "oo", types + 5 }, + { "deactivate", "o", types + 7 }, + { "show_input_panel", "", types + 0 }, + { "hide_input_panel", "", types + 0 }, + { "reset", "", types + 0 }, + { "set_surrounding_text", "suu", types + 0 }, + { "set_content_type", "uu", types + 0 }, + { "set_cursor_rectangle", "iiii", types + 0 }, + { "set_preferred_language", "s", types + 0 }, + { "commit_state", "u", types + 0 }, + { "invoke_action", "uu", types + 0 }, +}; + +static const struct wl_message wl_text_input_events[] = { + { "enter", "o", types + 8 }, + { "leave", "", types + 0 }, + { "modifiers_map", "a", types + 0 }, + { "input_panel_state", "u", types + 0 }, + { "preedit_string", "uss", types + 0 }, + { "preedit_styling", "uuu", types + 0 }, + { "preedit_cursor", "i", types + 0 }, + { "commit_string", "us", types + 0 }, + { "cursor_position", "ii", types + 0 }, + { "delete_surrounding_text", "iu", types + 0 }, + { "keysym", "uuuuu", types + 0 }, + { "language", "us", types + 0 }, + { "text_direction", "uu", types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_text_input_interface = { + "wl_text_input", 1, + 11, wl_text_input_requests, + 13, wl_text_input_events, +}; + +static const struct wl_message wl_text_input_manager_requests[] = { + { "create_text_input", "n", types + 9 }, +}; + +WL_EXPORT const struct wl_interface wl_text_input_manager_interface = { + "wl_text_input_manager", 1, + 1, wl_text_input_manager_requests, + 0, NULL, +}; + diff --git a/src/modules/ecore_imf/wayland/wayland_imcontext.c b/src/modules/ecore_imf/wayland/wayland_imcontext.c new file mode 100644 index 0000000000..f91b8a7893 --- /dev/null +++ b/src/modules/ecore_imf/wayland/wayland_imcontext.c @@ -0,0 +1,778 @@ +/* + * Copyright © 2012, 2013 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "wayland_imcontext.h" + +struct _WaylandIMContext +{ + Ecore_IMF_Context *ctx; + + struct wl_text_input_manager *text_input_manager; + struct wl_text_input *text_input; + + Ecore_Wl_Window *window; + Evas *canvas; + + char *preedit_text; + char *preedit_commit; + Eina_List *preedit_attrs; + int32_t preedit_cursor; + + struct + { + Eina_List *attrs; + int32_t cursor; + } pending_preedit; + + struct + { + int32_t cursor; + int32_t anchor; + uint32_t delete_index; + uint32_t delete_length; + } pending_commit; + + struct + { + int x; + int y; + int width; + int height; + } cursor_location; + + xkb_mod_mask_t control_mask; + xkb_mod_mask_t alt_mask; + xkb_mod_mask_t shift_mask; + + uint32_t serial; + uint32_t reset_serial; +}; + +static unsigned int +utf8_offset_to_characters(const char *str, int offset) +{ + int index = 0; + unsigned int i = 0; + for (; index < offset; i++) + eina_unicode_utf8_next_get(str, &index); + + return i; +} + +static void +update_state(WaylandIMContext *imcontext) +{ + char *surrounding; + int cursor_pos; + Ecore_Evas *ee; + int canvas_x = 0, canvas_y = 0; + + if (!imcontext->ctx) + return; + + /* cursor_pos is a byte index */ + if (ecore_imf_context_surrounding_get(imcontext->ctx, &surrounding, &cursor_pos)) + { + wl_text_input_set_surrounding_text(imcontext->text_input, + surrounding, + cursor_pos, + cursor_pos); + free(surrounding); + } + + if (imcontext->canvas) + { + ee = ecore_evas_ecore_evas_get(imcontext->canvas); + if (ee) + ecore_evas_geometry_get(ee, &canvas_x, &canvas_y, NULL, NULL); + } + + EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, "canvas (x: %d, y: %d)", canvas_x, canvas_y); + + wl_text_input_set_cursor_rectangle(imcontext->text_input, + imcontext->cursor_location.x + canvas_x, + imcontext->cursor_location.y + canvas_y, + imcontext->cursor_location.width, + imcontext->cursor_location.height); + + wl_text_input_commit_state(imcontext->text_input, ++imcontext->serial); +} + +static Eina_Bool +check_serial(WaylandIMContext *imcontext, uint32_t serial) +{ + Ecore_IMF_Preedit_Attr *attr; + + if ((imcontext->serial - serial) > (imcontext->serial - imcontext->reset_serial)) + { + EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, + "outdated serial: %u, current: %u, reset: %u", + serial, imcontext->serial, imcontext->reset_serial); + + /* Clear pending data */ + imcontext->pending_commit.delete_index = 0; + imcontext->pending_commit.delete_length = 0; + imcontext->pending_commit.cursor = 0; + imcontext->pending_commit.anchor = 0; + + imcontext->pending_preedit.cursor = 0; + EINA_LIST_FREE(imcontext->pending_preedit.attrs, attr) free(attr); + imcontext->pending_preedit.attrs = NULL; + + return EINA_FALSE; + } + + return EINA_TRUE; +} + +static void +clear_preedit(WaylandIMContext *imcontext) +{ + Ecore_IMF_Preedit_Attr *attr; + + imcontext->preedit_cursor = 0; + + free(imcontext->preedit_text); + imcontext->preedit_text = NULL; + + free(imcontext->preedit_commit); + imcontext->preedit_commit = NULL; + + EINA_LIST_FREE(imcontext->preedit_attrs, attr) + free(attr); + + imcontext->preedit_attrs = NULL; +} + +static void +text_input_commit_string(void *data, + struct wl_text_input *text_input EINA_UNUSED, + uint32_t serial, + const char *text) +{ + WaylandIMContext *imcontext = (WaylandIMContext *)data; + Eina_Bool old_preedit = EINA_FALSE; + char *surrounding; + int cursor_pos, cursor; + Ecore_IMF_Event_Delete_Surrounding ev; + + EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, + "commit event (text: `%s', current pre-edit: `%s')", + text, + imcontext->preedit_text ? imcontext->preedit_text : ""); + + old_preedit = imcontext->preedit_text && strlen(imcontext->preedit_text) > 0; + + if (!imcontext->ctx) + return; + + if (!check_serial(imcontext, serial)) + return; + + if (old_preedit) + { + ecore_imf_context_preedit_end_event_add(imcontext->ctx); + ecore_imf_context_event_callback_call(imcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL); + } + + clear_preedit(imcontext); + + if (imcontext->pending_commit.delete_length > 0) + { + /* cursor_pos is a byte index */ + if (ecore_imf_context_surrounding_get(imcontext->ctx, &surrounding, &cursor_pos)) + { + ev.ctx = imcontext->ctx; + /* offset and n_chars are in characters */ + ev.offset = utf8_offset_to_characters(surrounding, cursor_pos + imcontext->pending_commit.delete_index); + ev.n_chars = utf8_offset_to_characters(surrounding, + cursor_pos + imcontext->pending_commit.delete_index + imcontext->pending_commit.delete_length) - ev.offset; + + /* cursor in characters */ + cursor = utf8_offset_to_characters(surrounding, cursor_pos); + + ev.offset -= cursor; + + EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, + "delete on commit (text: `%s', offset `%d', length: `%d')", + surrounding, ev.offset, ev.n_chars); + + ecore_imf_context_delete_surrounding_event_add(imcontext->ctx, ev.offset, ev.n_chars); + ecore_imf_context_event_callback_call(imcontext->ctx, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, &ev); + } + } + + imcontext->pending_commit.delete_index = 0; + imcontext->pending_commit.delete_length = 0; + imcontext->pending_commit.cursor = 0; + imcontext->pending_commit.anchor = 0; + + ecore_imf_context_commit_event_add(imcontext->ctx, text); + ecore_imf_context_event_callback_call(imcontext->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)text); +} + +static void +commit_preedit(WaylandIMContext *imcontext) +{ + if (!imcontext->preedit_commit) + return; + + if (!imcontext->ctx) + return; + + ecore_imf_context_commit_event_add(imcontext->ctx, imcontext->preedit_commit); + ecore_imf_context_event_callback_call(imcontext->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)imcontext->preedit_commit); +} + +static void +text_input_preedit_string(void *data, + struct wl_text_input *text_input EINA_UNUSED, + uint32_t serial, + const char *text, + const char *commit) +{ + WaylandIMContext *imcontext = (WaylandIMContext *)data; + Eina_Bool old_preedit = EINA_FALSE; + + EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, + "preedit event (text: `%s', current pre-edit: `%s')", + text, + imcontext->preedit_text ? imcontext->preedit_text : ""); + + if (!check_serial(imcontext, serial)) + return; + + old_preedit = imcontext->preedit_text && strlen(imcontext->preedit_text) > 0; + + clear_preedit(imcontext); + + imcontext->preedit_text = strdup(text); + imcontext->preedit_commit = strdup(commit); + imcontext->preedit_cursor = utf8_offset_to_characters(text, imcontext->pending_preedit.cursor); + imcontext->preedit_attrs = imcontext->pending_preedit.attrs; + + imcontext->pending_preedit.attrs = NULL; + + if (!old_preedit) + { + ecore_imf_context_preedit_start_event_add(imcontext->ctx); + ecore_imf_context_event_callback_call(imcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL); + } + + ecore_imf_context_preedit_changed_event_add(imcontext->ctx); + ecore_imf_context_event_callback_call(imcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL); + + if (strlen(imcontext->preedit_text) == 0) + { + ecore_imf_context_preedit_end_event_add(imcontext->ctx); + ecore_imf_context_event_callback_call(imcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL); + } +} + +static void +text_input_delete_surrounding_text(void *data, + struct wl_text_input *text_input EINA_UNUSED, + int32_t index, + uint32_t length) +{ + WaylandIMContext *imcontext = (WaylandIMContext *)data; + + EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, + "delete surrounding text (index: %d, length: %u)", + index, + length); + + imcontext->pending_commit.delete_index = index; + imcontext->pending_commit.delete_length = length; +} + +static void +text_input_cursor_position(void *data, + struct wl_text_input *text_input EINA_UNUSED, + int32_t index, + int32_t anchor) +{ + WaylandIMContext *imcontext = (WaylandIMContext *)data; + + EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, + "cursor_position for next commit (index: %d, anchor: %d)", + index, + anchor); + + imcontext->pending_commit.cursor = index; + imcontext->pending_commit.anchor = anchor; +} + +static void +text_input_preedit_styling(void *data, + struct wl_text_input *text_input EINA_UNUSED, + uint32_t index, + uint32_t length, + uint32_t style) +{ + WaylandIMContext *imcontext = (WaylandIMContext *)data; + Ecore_IMF_Preedit_Attr *attr = calloc(1, sizeof(*attr)); + + switch (style) + { + case WL_TEXT_INPUT_PREEDIT_STYLE_DEFAULT: + case WL_TEXT_INPUT_PREEDIT_STYLE_UNDERLINE: + case WL_TEXT_INPUT_PREEDIT_STYLE_INCORRECT: + case WL_TEXT_INPUT_PREEDIT_STYLE_HIGHLIGHT: + case WL_TEXT_INPUT_PREEDIT_STYLE_ACTIVE: + case WL_TEXT_INPUT_PREEDIT_STYLE_INACTIVE: + attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB1; + break; + case WL_TEXT_INPUT_PREEDIT_STYLE_SELECTION: + attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB2; + break; + } + + attr->start_index = index; + attr->end_index = index + length; + + imcontext->pending_preedit.attrs = eina_list_append(imcontext->pending_preedit.attrs, attr); +} + +static void +text_input_preedit_cursor(void *data, + struct wl_text_input *text_input EINA_UNUSED, + int32_t index) +{ + WaylandIMContext *imcontext = (WaylandIMContext *)data; + + imcontext->pending_preedit.cursor = index; +} + +static xkb_mod_index_t +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 +modifiers_get_mask(struct wl_array *modifiers_map, + const char *name) +{ + xkb_mod_index_t index = modifiers_get_index(modifiers_map, name); + + if (index == XKB_MOD_INVALID) + return XKB_MOD_INVALID; + + return 1 << index; +} +static void +text_input_modifiers_map(void *data, + struct wl_text_input *text_input EINA_UNUSED, + struct wl_array *map) +{ + WaylandIMContext *imcontext = (WaylandIMContext *)data; + + imcontext->shift_mask = modifiers_get_mask(map, "Shift"); + imcontext->control_mask = modifiers_get_mask(map, "Control"); + imcontext->alt_mask = modifiers_get_mask(map, "Mod1"); +} + +static void +text_input_keysym(void *data, + struct wl_text_input *text_input EINA_UNUSED, + uint32_t serial EINA_UNUSED, + uint32_t time, + uint32_t sym, + uint32_t state, + uint32_t modifiers) +{ + WaylandIMContext *imcontext = (WaylandIMContext *)data; + char string[32], key[32], keyname[32]; + Ecore_Event_Key *e; + + memset(key, 0, sizeof(key)); + xkb_keysym_get_name(sym, key, sizeof(key)); + + memset(keyname, 0, sizeof(keyname)); + xkb_keysym_get_name(sym, keyname, sizeof(keyname)); + if (keyname[0] == '\0') + snprintf(keyname, sizeof(keyname), "Keysym-%u", sym); + + memset(string, 0, sizeof(string)); + xkb_keysym_to_utf8(sym, string, 32); + + EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, + "key event (key: %s)", + keyname); + + e = malloc(sizeof(Ecore_Event_Key) + strlen(key) + strlen(keyname) + strlen(string) + 3); + if (!e) + return; + + e->keyname = (char *)(e + 1); + e->key = e->keyname + strlen(keyname) + 1; + e->string = e->key + strlen(key) + 1; + e->compose = e->string; + + strcpy((char *)e->keyname, keyname); + strcpy((char *)e->key, key); + strcpy((char *)e->string, string); + + e->window = imcontext->window->id; + e->event_window = imcontext->window->id; + e->timestamp = time; + + e->modifiers = 0; + if (modifiers & imcontext->shift_mask) + e->modifiers |= ECORE_EVENT_MODIFIER_SHIFT; + + if (modifiers & imcontext->control_mask) + e->modifiers |= ECORE_EVENT_MODIFIER_CTRL; + + if (modifiers & imcontext->alt_mask) + e->modifiers |= ECORE_EVENT_MODIFIER_ALT; + + if (state) + ecore_event_add(ECORE_EVENT_KEY_DOWN, e, NULL, NULL); + else + ecore_event_add(ECORE_EVENT_KEY_UP, e, NULL, NULL); +} + +static void +text_input_enter(void *data, + struct wl_text_input *text_input EINA_UNUSED, + struct wl_surface *surface EINA_UNUSED) +{ + WaylandIMContext *imcontext = (WaylandIMContext *)data; + + update_state(imcontext); + + imcontext->reset_serial = imcontext->serial; +} + +static void +text_input_leave(void *data, + struct wl_text_input *text_input) +{ + WaylandIMContext *imcontext = (WaylandIMContext *)data; + + wl_text_input_hide_input_panel(text_input); + + /* clear preedit */ + commit_preedit(imcontext); + clear_preedit(imcontext); + + ecore_imf_context_preedit_changed_event_add(imcontext->ctx); + ecore_imf_context_event_callback_call(imcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL); + + ecore_imf_context_preedit_end_event_add(imcontext->ctx); + ecore_imf_context_event_callback_call(imcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL); +} + +static void +text_input_input_panel_state(void *data EINA_UNUSED, + struct wl_text_input *text_input EINA_UNUSED, + uint32_t state EINA_UNUSED) +{ +} + +static void +text_input_language(void *data EINA_UNUSED, + struct wl_text_input *text_input EINA_UNUSED, + uint32_t serial EINA_UNUSED, + const char *language EINA_UNUSED) +{ +} + +static void +text_input_text_direction(void *data EINA_UNUSED, + struct wl_text_input *text_input EINA_UNUSED, + uint32_t serial EINA_UNUSED, + uint32_t direction EINA_UNUSED) +{ +} + +static const struct wl_text_input_listener text_input_listener = +{ + text_input_enter, + text_input_leave, + text_input_modifiers_map, + text_input_input_panel_state, + text_input_preedit_string, + text_input_preedit_styling, + text_input_preedit_cursor, + text_input_commit_string, + text_input_cursor_position, + text_input_delete_surrounding_text, + text_input_keysym, + text_input_language, + text_input_text_direction +}; + +EAPI void +wayland_im_context_add(Ecore_IMF_Context *ctx) +{ + WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx); + + EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, "context_add"); + + imcontext->ctx = ctx; + + imcontext->text_input = wl_text_input_manager_create_text_input(imcontext->text_input_manager); + wl_text_input_add_listener(imcontext->text_input, &text_input_listener, imcontext); +} + +EAPI void +wayland_im_context_del(Ecore_IMF_Context *ctx) +{ + WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx); + + EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, "context_del"); + + wl_text_input_destroy(imcontext->text_input); + + clear_preedit(imcontext); +} + +EAPI void +wayland_im_context_reset(Ecore_IMF_Context *ctx) +{ + WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx); + + commit_preedit(imcontext); + clear_preedit(imcontext); + + wl_text_input_reset(imcontext->text_input); + + update_state(imcontext); + + imcontext->reset_serial = imcontext->serial; +} + +EAPI void +wayland_im_context_focus_in(Ecore_IMF_Context *ctx) +{ + WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx); + Ecore_Wl_Input *input; + + EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, "focus-in"); + + if (!imcontext->window) + return; + + input = imcontext->window->keyboard_device; + if (!input || !input->seat) + return; + + wl_text_input_show_input_panel(imcontext->text_input); + wl_text_input_activate(imcontext->text_input, + input->seat, + ecore_wl_window_surface_get(imcontext->window)); +} + +EAPI void +wayland_im_context_focus_out(Ecore_IMF_Context *ctx) +{ + WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx); + + EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, "focus-out"); + + if (!imcontext->window) + return; + + wl_text_input_deactivate(imcontext->text_input, + imcontext->window->display->input->seat); +} + +EAPI void +wayland_im_context_preedit_string_get(Ecore_IMF_Context *ctx, + char **str, + int *cursor_pos) +{ + WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx); + + EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, + "pre-edit string requested (preedit: `%s')", + imcontext->preedit_text ? imcontext->preedit_text : ""); + + if (str) + *str = strdup(imcontext->preedit_text ? imcontext->preedit_text : ""); + + if (cursor_pos) + *cursor_pos = imcontext->preedit_cursor; +} + +EAPI void +wayland_im_context_preedit_string_with_attributes_get(Ecore_IMF_Context *ctx, + char **str, + Eina_List **attrs, + int *cursor_pos) +{ + WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx); + + EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, + "pre-edit string with attributes requested (preedit: `%s')", + imcontext->preedit_text ? imcontext->preedit_text : ""); + + if (str) + *str = strdup(imcontext->preedit_text ? imcontext->preedit_text : ""); + + if (attrs) + { + Eina_List *l; + Ecore_IMF_Preedit_Attr *a, *attr; + + EINA_LIST_FOREACH(imcontext->preedit_attrs, l, a) + { + attr = malloc(sizeof(*attr)); + attr = memcpy(attr, a, sizeof(*attr)); + *attrs = eina_list_append(*attrs, attr); + } + } + + if (cursor_pos) + *cursor_pos = imcontext->preedit_cursor; +} + +EAPI void +wayland_im_context_cursor_position_set(Ecore_IMF_Context *ctx, + int cursor_pos) +{ + WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx); + + EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, + "set cursor position (cursor: %d)", + cursor_pos); + + update_state(imcontext); +} + +EAPI void +wayland_im_context_use_preedit_set(Ecore_IMF_Context *ctx EINA_UNUSED, + Eina_Bool use_preedit EINA_UNUSED) +{ +} + +EAPI void +wayland_im_context_client_window_set(Ecore_IMF_Context *ctx, + void *window) +{ + WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx); + + EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, "client window set (window: %p)", window); + + if (window != NULL) + imcontext->window = ecore_wl_window_find((Ecore_Window)window); +} + +EAPI void +wayland_im_context_client_canvas_set(Ecore_IMF_Context *ctx, + void *canvas) +{ + WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx); + + EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, "client canvas set (canvas: %p)", canvas); + + if (canvas != NULL) + imcontext->canvas = canvas; +} + +EAPI void +wayland_im_context_show(Ecore_IMF_Context *ctx) +{ + WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx); + + EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, "context_show"); + + wl_text_input_show_input_panel(imcontext->text_input); +} + +EAPI void +wayland_im_context_hide(Ecore_IMF_Context *ctx) +{ + WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx); + + EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, "context_hide"); + + wl_text_input_hide_input_panel(imcontext->text_input); +} + +EAPI Eina_Bool +wayland_im_context_filter_event(Ecore_IMF_Context *ctx EINA_UNUSED, + Ecore_IMF_Event_Type type EINA_UNUSED, + Ecore_IMF_Event *event EINA_UNUSED) +{ + return EINA_FALSE; +} + +EAPI void +wayland_im_context_cursor_location_set(Ecore_IMF_Context *ctx, int x, int y, int width, int height) +{ + WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx); + + EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, "cursor_location_set (x: %d, y: %d, w: %d, h: %d)", x, y, width, height); + + if ((imcontext->cursor_location.x != x) || + (imcontext->cursor_location.y != y) || + (imcontext->cursor_location.width != width) || + (imcontext->cursor_location.height != height)) + { + imcontext->cursor_location.x = x; + imcontext->cursor_location.y = y; + imcontext->cursor_location.width = width; + imcontext->cursor_location.height = height; + + update_state(imcontext); + } +} + + +WaylandIMContext *wayland_im_context_new (struct wl_text_input_manager *text_input_manager) +{ + WaylandIMContext *context = calloc(1, sizeof(WaylandIMContext)); + + EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, "new context created"); + context->text_input_manager = text_input_manager; + + return context; +} + +/* vim:ts=8 sw=3 sts=3 expandtab cino=>5n-3f0^-2{2(0W1st0 +*/ diff --git a/src/modules/ecore_imf/wayland/wayland_imcontext.h b/src/modules/ecore_imf/wayland/wayland_imcontext.h new file mode 100644 index 0000000000..fb6906c2e8 --- /dev/null +++ b/src/modules/ecore_imf/wayland/wayland_imcontext.h @@ -0,0 +1,70 @@ +/* + * Copyright © 2012, 2013 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WAYLAND_IM_CONTEXT_H_ +#define __WAYLAND_IM_CONTEXT_H_ + +#include +#include "text-client-protocol.h" + +typedef struct _WaylandIMContext WaylandIMContext; + +EAPI void wayland_im_context_add (Ecore_IMF_Context *ctx); +EAPI void wayland_im_context_del (Ecore_IMF_Context *ctx); +EAPI void wayland_im_context_reset (Ecore_IMF_Context *ctx); +EAPI void wayland_im_context_focus_in (Ecore_IMF_Context *ctx); +EAPI void wayland_im_context_focus_out (Ecore_IMF_Context *ctx); +EAPI void wayland_im_context_preedit_string_get (Ecore_IMF_Context *ctx, + char **str, + int *cursor_pos); +EAPI void wayland_im_context_preedit_string_with_attributes_get(Ecore_IMF_Context *ctx, + char **str, + Eina_List **attr, + int *cursor_pos); + +EAPI void wayland_im_context_cursor_position_set(Ecore_IMF_Context *ctx, + int cursor_pos); +EAPI void wayland_im_context_use_preedit_set (Ecore_IMF_Context *ctx, + Eina_Bool use_preedit); +EAPI void wayland_im_context_client_window_set (Ecore_IMF_Context *ctx, + void *window); +EAPI void wayland_im_context_client_canvas_set (Ecore_IMF_Context *ctx, + void *canvas); +EAPI void wayland_im_context_show (Ecore_IMF_Context *ctx); +EAPI void wayland_im_context_hide (Ecore_IMF_Context *ctx); +EAPI Eina_Bool wayland_im_context_filter_event (Ecore_IMF_Context *ctx, + Ecore_IMF_Event_Type type, + Ecore_IMF_Event *event); +EAPI void wayland_im_context_cursor_location_set(Ecore_IMF_Context *ctx, + int x, + int y, + int width, + int height); + +WaylandIMContext *wayland_im_context_new (struct wl_text_input_manager *text_input_manager); + +extern int _ecore_imf_wayland_log_dom; + +#endif + +/* vim:ts=8 sw=3 sts=3 expandtab cino=>5n-3f0^-2{2(0W1st0 + */ diff --git a/src/modules/ecore_imf/wayland/wayland_module.c b/src/modules/ecore_imf/wayland/wayland_module.c new file mode 100644 index 0000000000..6b4e337fa5 --- /dev/null +++ b/src/modules/ecore_imf/wayland/wayland_module.c @@ -0,0 +1,154 @@ +/* + * Copyright © 2012, 2013 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include "wayland_imcontext.h" +#include "text-client-protocol.h" + +int _ecore_imf_wayland_log_dom = -1; + +static const Ecore_IMF_Context_Info wayland_im_info = +{ + "wayland", + "Wayland", + "*", + NULL, + 0 +}; + +static Ecore_IMF_Context_Class wayland_imf_class = +{ + wayland_im_context_add, /* add */ + wayland_im_context_del, /* del */ + wayland_im_context_client_window_set, /* client_window_set */ + wayland_im_context_client_canvas_set, /* client_canvas_set */ + wayland_im_context_show, /* show */ + wayland_im_context_hide, /* hide */ + wayland_im_context_preedit_string_get, /* get_preedit_string */ + wayland_im_context_focus_in, /* focus_in */ + wayland_im_context_focus_out, /* focus_out */ + wayland_im_context_reset, /* reset */ + wayland_im_context_cursor_position_set, /* cursor_position_set */ + wayland_im_context_use_preedit_set, /* use_preedit_set */ + NULL, /* input_mode_set */ + wayland_im_context_filter_event, /* filter_event */ + wayland_im_context_preedit_string_with_attributes_get, /* preedit_string_with_attribute_get */ + NULL, /* prediction_allow_set */ + NULL, /* autocapital_type_set */ + NULL, /* control panel show */ + NULL, /* control panel hide */ + NULL, /* input_panel_layout_set */ + NULL, /* input_panel_layout_get, */ + NULL, /* input_panel_language_set, */ + NULL, /* input_panel_language_get, */ + wayland_im_context_cursor_location_set, /* cursor_location_set */ + NULL, /* input_panel_imdata_set */ + NULL, /* input_panel_imdata_get */ + NULL, /* input_panel_return_key_type_set */ + NULL, /* input_panel_return_key_disabled_set */ + NULL, /* input_panel_caps_lock_mode_set */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +static struct wl_text_input_manager *text_input_manager = NULL; + +static Ecore_IMF_Context * +im_module_exit(void) +{ + return NULL; +} + +static Ecore_IMF_Context * +im_module_create() +{ + Ecore_IMF_Context *ctx = NULL; + WaylandIMContext *ctxd = NULL; + + ctxd = wayland_im_context_new(text_input_manager); + if (!ctxd) + { + return NULL; + } + + ctx = ecore_imf_context_new(&wayland_imf_class); + if (!ctx) + { + free(ctxd); + return NULL; + } + + ecore_imf_context_data_set(ctx, ctxd); + + return ctx; +} + +static Eina_Bool +im_module_init(void) +{ + struct wl_registry *registry; + struct wl_list *globals; + Ecore_Wl_Global *global; + + ecore_wl_init(NULL); + + _ecore_imf_wayland_log_dom = eina_log_domain_register("ecore_imf_wayland", EINA_COLOR_YELLOW); + + ecore_wl_display_iterate(); + registry = ecore_wl_registry_get(); + globals = ecore_wl_globals_get(); + + wl_list_for_each(global, globals, link) + { + if (!strcmp(global->interface, "wl_text_input_manager")) + { + text_input_manager = wl_registry_bind(registry, global->id, &wl_text_input_manager_interface, 1); + EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, "bound wl_text_input_manager interface"); + } + } + + ecore_imf_module_register(&wayland_im_info, im_module_create, im_module_exit); + EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, "im module initalized"); + + return EINA_TRUE; +} + +static void +im_module_shutdown(void) +{ + ecore_wl_shutdown(); + EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, "im module shutdown"); +} + +EINA_MODULE_INIT(im_module_init); +EINA_MODULE_SHUTDOWN(im_module_shutdown); + +/* vim:ts=8 sw=3 sts=3 expandtab cino=>5n-3f0^-2{2(0W1st0 +*/