From 26d352f219f1c4ffbaa21857903d6e9290a7763a Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 20 Aug 2015 14:55:14 -0400 Subject: [PATCH] Add module "wl_text_input" for supporting *wl_text_input* and *wl_input_method* protocol in wayland. Summary: this patch allow to use virtual keyboard such as weston-keyboard. it was tested in wayland verion 1.6. Test Plan: - Configure with --enable-wl-text-input - edit configuration file, e.cfg to enable module wl_text_input. 1. run enlightenment as a wayland display server. 2. run weston-keyboard. 3. run weston-editor. Reviewers: raster, Sergeant_Whitespace, devilhorns, zmike Reviewed By: zmike Subscribers: ManMower, Sergeant_Whitespace, cedric, jihoon Differential Revision: https://phab.enlightenment.org/D2275 --- configure.ac | 11 + src/bin/e_comp_wl.h | 6 + src/bin/e_comp_wl_input.c | 4 + src/bin/e_comp_wl_input.h | 9 + src/modules/Makefile.mk | 2 + src/modules/Makefile_wl_desktop_shell.mk | 5 + src/modules/Makefile_wl_text_input.mk | 27 + .../e_input_method_protocol.c | 114 +++ .../e_input_method_protocol.h | 418 ++++++++ .../wl_desktop_shell/e_mod_input_panel.c | 336 +++++++ src/modules/wl_desktop_shell/e_mod_main.c | 11 + src/modules/wl_desktop_shell/e_mod_main.h | 7 + src/modules/wl_text_input/e_mod_main.c | 933 ++++++++++++++++++ .../wl_text_input/input-method-protocol.c | 114 +++ .../wl_text_input/input-method-protocol.h | 418 ++++++++ src/modules/wl_text_input/text-protocol.c | 92 ++ src/modules/wl_text_input/text-protocol.h | 448 +++++++++ 17 files changed, 2955 insertions(+) create mode 100644 src/modules/Makefile_wl_text_input.mk create mode 100644 src/modules/wl_desktop_shell/e_input_method_protocol.c create mode 100644 src/modules/wl_desktop_shell/e_input_method_protocol.h create mode 100644 src/modules/wl_desktop_shell/e_mod_input_panel.c create mode 100644 src/modules/wl_desktop_shell/e_mod_main.h create mode 100644 src/modules/wl_text_input/e_mod_main.c create mode 100644 src/modules/wl_text_input/input-method-protocol.c create mode 100644 src/modules/wl_text_input/input-method-protocol.h create mode 100644 src/modules/wl_text_input/text-protocol.c create mode 100644 src/modules/wl_text_input/text-protocol.h diff --git a/configure.ac b/configure.ac index 6423c3bdf..db255d6f3 100644 --- a/configure.ac +++ b/configure.ac @@ -845,6 +845,16 @@ define([CHECK_MODULE_XWAYLAND], ]) AM_CONDITIONAL([HAVE_XWAYLAND], [test "x${HAVE_XWAYLAND}" != "xno"]) +define([CHECK_MODULE_WL_TEXT_INPUT], +[ + if test "x${have_wayland}" = "xyes"; then + AC_E_CHECK_PKG(WL_TEXT_INPUT, [ ecore >= $efl_version eina >= $efl_version ], [WL_TEXT_INPUT=true], [WL_TEXT_INPUT=false]) + else + WL_TEXT_INPUT=false + fi +]) +AM_CONDITIONAL([HAVE_WL_TEXT_INPUT], [test "x${WL_TEXT_INPUT}" = "xtrue"]) + AC_E_OPTIONAL_MODULE([ibar], true) AC_E_OPTIONAL_MODULE([clock], true) AC_E_OPTIONAL_MODULE([pager], true) @@ -899,6 +909,7 @@ AC_E_OPTIONAL_MODULE([wl_x11], $have_wayland, [CHECK_MODULE_WL_X11]) AC_E_OPTIONAL_MODULE([wl_wl], $have_wayland, [CHECK_MODULE_WL_WL]) #AC_E_OPTIONAL_MODULE([wl_fb], $have_wayland, [CHECK_MODULE_WL_FB]) AC_E_OPTIONAL_MODULE([wl_drm], $have_wayland, [CHECK_MODULE_WL_DRM]) +AC_E_OPTIONAL_MODULE([wl_text_input], $have_wayland, [CHECK_MODULE_WL_TEXT_INPUT]) AC_E_OPTIONAL_MODULE([policy_mobile], true) AC_E_OPTIONAL_MODULE([geolocation], true) AC_E_OPTIONAL_MODULE([xwayland], $have_wayland, [CHECK_MODULE_XWAYLAND]) diff --git a/src/bin/e_comp_wl.h b/src/bin/e_comp_wl.h index 821bd3865..932e386bc 100644 --- a/src/bin/e_comp_wl.h +++ b/src/bin/e_comp_wl.h @@ -178,6 +178,12 @@ struct _E_Comp_Wl_Data Eina_List *resources; uint32_t version; char *name; + + struct + { + struct wl_global *global; + struct wl_resource *resource; + } im; } seat; struct diff --git a/src/bin/e_comp_wl_input.c b/src/bin/e_comp_wl_input.c index 82e09ae51..e457aff30 100644 --- a/src/bin/e_comp_wl_input.c +++ b/src/bin/e_comp_wl_input.c @@ -3,6 +3,8 @@ #include "e.h" #include +EAPI int E_EVENT_TEXT_INPUT_PANEL_VISIBILITY_CHANGE = -1; + static void _e_comp_wl_input_update_seat_caps(void) { @@ -426,6 +428,8 @@ e_comp_wl_input_init(void) wl_array_init(&e_comp_wl->kbd.keys); + E_EVENT_TEXT_INPUT_PANEL_VISIBILITY_CHANGE = ecore_event_type_new(); + return EINA_TRUE; } diff --git a/src/bin/e_comp_wl_input.h b/src/bin/e_comp_wl_input.h index 8db117e02..15eef2fac 100644 --- a/src/bin/e_comp_wl_input.h +++ b/src/bin/e_comp_wl_input.h @@ -3,6 +3,15 @@ # ifndef E_COMP_WL_INPUT_H # define E_COMP_WL_INPUT_H +EAPI extern int E_EVENT_TEXT_INPUT_PANEL_VISIBILITY_CHANGE; + +typedef struct _E_Event_Text_Input_Panel_Visibility_Change E_Event_Text_Input_Panel_Visibility_Change; + +struct _E_Event_Text_Input_Panel_Visibility_Change +{ + Eina_Bool visible; +}; + EINTERN Eina_Bool e_comp_wl_input_init(void); EINTERN void e_comp_wl_input_shutdown(void); EINTERN Eina_Bool e_comp_wl_input_pointer_check(struct wl_resource *res); diff --git a/src/modules/Makefile.mk b/src/modules/Makefile.mk index 96f0c9436..ed334b236 100644 --- a/src/modules/Makefile.mk +++ b/src/modules/Makefile.mk @@ -121,6 +121,8 @@ include src/modules/Makefile_wl_x11.mk include src/modules/Makefile_xwayland.mk +include src/modules/Makefile_wl_text_input.mk + include src/modules/Makefile_policy_mobile.mk include src/modules/Makefile_geolocation.mk diff --git a/src/modules/Makefile_wl_desktop_shell.mk b/src/modules/Makefile_wl_desktop_shell.mk index 58aa2d487..8e1ffe383 100644 --- a/src/modules/Makefile_wl_desktop_shell.mk +++ b/src/modules/Makefile_wl_desktop_shell.mk @@ -1,6 +1,8 @@ EXTRA_DIST += src/modules/wl_desktop_shell/module.desktop.in \ src/modules/wl_desktop_shell/e-module-wl_desktop_shell.edj \ src/modules/wl_desktop_shell/module.desktop.in \ +src/modules/wl_desktop_shell/e_input_method_protocol.h \ +src/modules/wl_desktop_shell/e_input_method_protocol.c \ src/modules/wl_desktop_shell/e_desktop_shell_protocol.h \ src/modules/wl_desktop_shell/e_desktop_shell_protocol.c if USE_MODULE_WL_DESKTOP_SHELL @@ -18,6 +20,9 @@ src_modules_wl_desktop_shell_module_la_LDFLAGS = $(MOD_LDFLAGS) src_modules_wl_desktop_shell_module_la_SOURCES = \ src/modules/wl_desktop_shell/e_mod_main.c \ + src/modules/wl_desktop_shell/e_mod_input_panel.c \ + src/modules/wl_desktop_shell/e_input_method_protocol.c \ + src/modules/wl_desktop_shell/e_input_method_protocol.h \ src/modules/wl_desktop_shell/e_desktop_shell_protocol.c \ src/modules/wl_desktop_shell/e_desktop_shell_protocol.h diff --git a/src/modules/Makefile_wl_text_input.mk b/src/modules/Makefile_wl_text_input.mk new file mode 100644 index 000000000..4c749234b --- /dev/null +++ b/src/modules/Makefile_wl_text_input.mk @@ -0,0 +1,27 @@ +EXTRA_DIST += \ +src/modules/wl_text_input/text-protocol.h \ +src/modules/wl_text_input/text-protocol.c \ +src/modules/wl_text_input/input-method-protocol.h \ +src/modules/wl_text_input/input-method-protocol.c + +if USE_MODULE_WL_TEXT_INPUT +wl_text_inputdir = $(MDIR)/wl_text_input + +wl_text_inputpkgdir = $(MDIR)/wl_text_input/$(MODULE_ARCH) +wl_text_inputpkg_LTLIBRARIES = src/modules/wl_text_input/module.la + +src_modules_wl_text_input_module_la_DEPENDENCIES = $(MDEPENDENCIES) +src_modules_wl_text_input_module_la_CPPFLAGS = $(MOD_CPPFLAGS) @WAYLAND_CFLAGS@ +src_modules_wl_text_input_module_la_LIBADD = $(LIBS) @WAYLAND_LIBS@ +src_modules_wl_text_input_module_la_LDFLAGS = $(MOD_LDFLAGS) +src_modules_wl_text_input_module_la_SOURCES = \ + src/modules/wl_text_input/e_mod_main.c \ + src/modules/wl_text_input/text-protocol.c \ + src/modules/wl_text_input/text-protocol.h \ + src/modules/wl_text_input/input-method-protocol.c \ + src/modules/wl_text_input/input-method-protocol.h + +PHONIES += wl_text_input install-wl_text_input +wl_text_input: $(wl_text_inputpkg_LTLIBRARIES) $(wl_text_input_DATA) +install-wl_text_input: install-wl_text_inputDATA install-wl_text_inputpkgLTLIBRARIES +endif diff --git a/src/modules/wl_desktop_shell/e_input_method_protocol.c b/src/modules/wl_desktop_shell/e_input_method_protocol.c new file mode 100644 index 000000000..feae24429 --- /dev/null +++ b/src/modules/wl_desktop_shell/e_input_method_protocol.c @@ -0,0 +1,114 @@ +/* + * 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_input_method_context_interface; +extern const struct wl_interface wl_input_panel_surface_interface; +extern const struct wl_interface wl_keyboard_interface; +extern const struct wl_interface wl_output_interface; +extern const struct wl_interface wl_surface_interface; + +static const struct wl_interface *types[] = { + NULL, + NULL, + NULL, + NULL, + NULL, + &wl_keyboard_interface, + &wl_input_method_context_interface, + &wl_input_method_context_interface, + &wl_input_panel_surface_interface, + &wl_surface_interface, + &wl_output_interface, + NULL, +}; + +static const struct wl_message wl_input_method_context_requests[] = { + { "destroy", "", types + 0 }, + { "commit_string", "us", types + 0 }, + { "preedit_string", "uss", types + 0 }, + { "preedit_styling", "uuu", types + 0 }, + { "preedit_cursor", "i", types + 0 }, + { "delete_surrounding_text", "iu", types + 0 }, + { "cursor_position", "ii", types + 0 }, + { "modifiers_map", "a", types + 0 }, + { "keysym", "uuuuu", types + 0 }, + { "grab_keyboard", "n", types + 5 }, + { "key", "uuuu", types + 0 }, + { "modifiers", "uuuuu", types + 0 }, + { "language", "us", types + 0 }, + { "text_direction", "uu", types + 0 }, +}; + +static const struct wl_message wl_input_method_context_events[] = { + { "surrounding_text", "suu", types + 0 }, + { "reset", "", types + 0 }, + { "content_type", "uu", types + 0 }, + { "invoke_action", "uu", types + 0 }, + { "commit_state", "u", types + 0 }, + { "preferred_language", "s", types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_input_method_context_interface = { + "wl_input_method_context", 1, + 14, wl_input_method_context_requests, + 6, wl_input_method_context_events, +}; + +static const struct wl_message wl_input_method_events[] = { + { "activate", "n", types + 6 }, + { "deactivate", "o", types + 7 }, +}; + +WL_EXPORT const struct wl_interface wl_input_method_interface = { + "wl_input_method", 1, + 0, NULL, + 2, wl_input_method_events, +}; + +static const struct wl_message wl_input_panel_requests[] = { + { "get_input_panel_surface", "no", types + 8 }, +}; + +WL_EXPORT const struct wl_interface wl_input_panel_interface = { + "wl_input_panel", 1, + 1, wl_input_panel_requests, + 0, NULL, +}; + +static const struct wl_message wl_input_panel_surface_requests[] = { + { "set_toplevel", "ou", types + 10 }, + { "set_overlay_panel", "", types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_input_panel_surface_interface = { + "wl_input_panel_surface", 1, + 2, wl_input_panel_surface_requests, + 0, NULL, +}; + diff --git a/src/modules/wl_desktop_shell/e_input_method_protocol.h b/src/modules/wl_desktop_shell/e_input_method_protocol.h new file mode 100644 index 000000000..e4b89887e --- /dev/null +++ b/src/modules/wl_desktop_shell/e_input_method_protocol.h @@ -0,0 +1,418 @@ +/* + * 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 INPUT_METHOD_SERVER_PROTOCOL_H +#define INPUT_METHOD_SERVER_PROTOCOL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "wayland-server.h" + +struct wl_client; +struct wl_resource; + +struct wl_input_method_context; +struct wl_input_method; +struct wl_input_panel; +struct wl_input_panel_surface; + +extern const struct wl_interface wl_input_method_context_interface; +extern const struct wl_interface wl_input_method_interface; +extern const struct wl_interface wl_input_panel_interface; +extern const struct wl_interface wl_input_panel_surface_interface; + +/** + * wl_input_method_context - input method context + * @destroy: (none) + * @commit_string: commit string + * @preedit_string: pre-edit string + * @preedit_styling: pre-edit styling + * @preedit_cursor: pre-edit cursor + * @delete_surrounding_text: delete text + * @cursor_position: set cursor to a new position + * @modifiers_map: (none) + * @keysym: keysym + * @grab_keyboard: grab hardware keyboard + * @key: forward key event + * @modifiers: forward modifiers event + * @language: (none) + * @text_direction: (none) + * + * Corresponds to a text model on input method side. An input method + * context is created on text model activation on the input method side. It + * allows to receive information about the text model from the application + * via events. Input method contexts do not keep state after deactivation + * and should be destroyed after deactivation is handled. + * + * Text is generally UTF-8 encoded, indices and lengths are in bytes. + * + * 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_input_method_context_interface { + /** + * destroy - (none) + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * commit_string - commit string + * @serial: serial of the latest known text input state + * @text: (none) + * + * Send the commit string text for insertion to the application. + * + * 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 will be removed. + */ + void (*commit_string)(struct wl_client *client, + struct wl_resource *resource, + uint32_t serial, + const char *text); + /** + * preedit_string - pre-edit string + * @serial: serial of the latest known text input state + * @text: (none) + * @commit: (none) + * + * Send the pre-edit string text to the application text input. + * + * The commit text can be used to replace the preedit text on reset + * (for example on unfocus). + * + * Also previously sent preedit_style and preedit_cursor requests + * are processed bt the text_input also. + */ + void (*preedit_string)(struct wl_client *client, + struct wl_resource *resource, + 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 in bytes from index relative to the beginning + * of the composing text (as byte offset). Multiple styles can be + * applied to a composing text. + * + * This request should be sent before sending preedit_string + * request. + */ + void (*preedit_styling)(struct wl_client *client, + struct wl_resource *resource, + 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 byte + * offset) relative to the start of the composing text. + * + * When index is negative no cursor should be displayed. + * + * This request should be sent before sending preedit_string + * request. + */ + void (*preedit_cursor)(struct wl_client *client, + struct wl_resource *resource, + int32_t index); + /** + * delete_surrounding_text - delete text + * @index: (none) + * @length: (none) + * + * + * + * This request will be handled on text_input side as part of a + * directly following commit_string request. + */ + void (*delete_surrounding_text)(struct wl_client *client, + struct wl_resource *resource, + int32_t index, + uint32_t length); + /** + * cursor_position - set cursor to a new position + * @index: (none) + * @anchor: (none) + * + * Sets the cursor and anchor to a new position. Index is the new + * cursor position in bytes (when >= 0 relative to the end of + * inserted text else relative to beginning of inserted text). + * Anchor is the new anchor position in bytes (when >= 0 relative + * to the end of inserted text, else relative to beginning of + * inserted text). When there should be no selected text anchor + * should be the same as index. + * + * This request will be handled on text_input side as part of a + * directly following commit_string request. + */ + void (*cursor_position)(struct wl_client *client, + struct wl_resource *resource, + int32_t index, + int32_t anchor); + /** + * modifiers_map - (none) + * @map: (none) + */ + void (*modifiers_map)(struct wl_client *client, + struct wl_resource *resource, + struct wl_array *map); + /** + * 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_surrounfing_text, etc. The key event + * follows the wl_keyboard key event convention. Sym is a XKB + * keysym, state a wl_keyboard key_state. + */ + void (*keysym)(struct wl_client *client, + struct wl_resource *resource, + uint32_t serial, + uint32_t time, + uint32_t sym, + uint32_t state, + uint32_t modifiers); + /** + * grab_keyboard - grab hardware keyboard + * @keyboard: (none) + * + * Allows an input method to receive hardware keyboard input and + * process key events to generate text events (with pre-edit) over + * the wire. This allows input methods which compose multiple key + * events for inputting text like it is done for CJK languages. + */ + void (*grab_keyboard)(struct wl_client *client, + struct wl_resource *resource, + uint32_t keyboard); + /** + * key - forward key event + * @serial: serial from wl_keyboard::key + * @time: time from wl_keyboard::key + * @key: key from wl_keyboard::key + * @state: state from wl_keyboard::key + * + * Should be used when filtering key events with grab_keyboard. + * + * When the wl_keyboard::key event is not processed by the input + * method itself and should be sent to the client instead, forward + * it with this request. The arguments should be the ones from the + * wl_keyboard::key event. + * + * For generating custom key events use the keysym request instead. + */ + void (*key)(struct wl_client *client, + struct wl_resource *resource, + uint32_t serial, + uint32_t time, + uint32_t key, + uint32_t state); + /** + * modifiers - forward modifiers event + * @serial: serial from wl_keyboard::modifiers + * @mods_depressed: mods_depressed from wl_keyboard::modifiers + * @mods_latched: mods_latched from wl_keyboard::modifiers + * @mods_locked: mods_locked from wl_keyboard::modifiers + * @group: group from wl_keyboard::modifiers + * + * Should be used when filtering key events with grab_keyboard. + * + * When the wl_keyboard::modifiers event should be also send to the + * client, forward it with this request. The arguments should be + * the ones from the wl_keyboard::modifiers event. + */ + void (*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); + /** + * language - (none) + * @serial: serial of the latest known text input state + * @language: (none) + */ + void (*language)(struct wl_client *client, + struct wl_resource *resource, + uint32_t serial, + const char *language); + /** + * text_direction - (none) + * @serial: serial of the latest known text input state + * @direction: (none) + */ + void (*text_direction)(struct wl_client *client, + struct wl_resource *resource, + uint32_t serial, + uint32_t direction); +}; + +#define WL_INPUT_METHOD_CONTEXT_SURROUNDING_TEXT 0 +#define WL_INPUT_METHOD_CONTEXT_RESET 1 +#define WL_INPUT_METHOD_CONTEXT_CONTENT_TYPE 2 +#define WL_INPUT_METHOD_CONTEXT_INVOKE_ACTION 3 +#define WL_INPUT_METHOD_CONTEXT_COMMIT_STATE 4 +#define WL_INPUT_METHOD_CONTEXT_PREFERRED_LANGUAGE 5 + +#define WL_INPUT_METHOD_CONTEXT_SURROUNDING_TEXT_SINCE_VERSION 1 +#define WL_INPUT_METHOD_CONTEXT_RESET_SINCE_VERSION 1 +#define WL_INPUT_METHOD_CONTEXT_CONTENT_TYPE_SINCE_VERSION 1 +#define WL_INPUT_METHOD_CONTEXT_INVOKE_ACTION_SINCE_VERSION 1 +#define WL_INPUT_METHOD_CONTEXT_COMMIT_STATE_SINCE_VERSION 1 +#define WL_INPUT_METHOD_CONTEXT_PREFERRED_LANGUAGE_SINCE_VERSION 1 + +static inline void +wl_input_method_context_send_surrounding_text(struct wl_resource *resource_, const char *text, uint32_t cursor, uint32_t anchor) +{ + wl_resource_post_event(resource_, WL_INPUT_METHOD_CONTEXT_SURROUNDING_TEXT, text, cursor, anchor); +} + +static inline void +wl_input_method_context_send_reset(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, WL_INPUT_METHOD_CONTEXT_RESET); +} + +static inline void +wl_input_method_context_send_content_type(struct wl_resource *resource_, uint32_t hint, uint32_t purpose) +{ + wl_resource_post_event(resource_, WL_INPUT_METHOD_CONTEXT_CONTENT_TYPE, hint, purpose); +} + +static inline void +wl_input_method_context_send_invoke_action(struct wl_resource *resource_, uint32_t button, uint32_t index) +{ + wl_resource_post_event(resource_, WL_INPUT_METHOD_CONTEXT_INVOKE_ACTION, button, index); +} + +static inline void +wl_input_method_context_send_commit_state(struct wl_resource *resource_, uint32_t serial) +{ + wl_resource_post_event(resource_, WL_INPUT_METHOD_CONTEXT_COMMIT_STATE, serial); +} + +static inline void +wl_input_method_context_send_preferred_language(struct wl_resource *resource_, const char *language) +{ + wl_resource_post_event(resource_, WL_INPUT_METHOD_CONTEXT_PREFERRED_LANGUAGE, language); +} + +#define WL_INPUT_METHOD_ACTIVATE 0 +#define WL_INPUT_METHOD_DEACTIVATE 1 + +#define WL_INPUT_METHOD_ACTIVATE_SINCE_VERSION 1 +#define WL_INPUT_METHOD_DEACTIVATE_SINCE_VERSION 1 + +static inline void +wl_input_method_send_activate(struct wl_resource *resource_, struct wl_resource *id) +{ + wl_resource_post_event(resource_, WL_INPUT_METHOD_ACTIVATE, id); +} + +static inline void +wl_input_method_send_deactivate(struct wl_resource *resource_, struct wl_resource *context) +{ + wl_resource_post_event(resource_, WL_INPUT_METHOD_DEACTIVATE, context); +} + +/** + * wl_input_panel - interface for implementing keyboards + * @get_input_panel_surface: (none) + * + * Only one client can bind this interface at a time. + */ +struct wl_input_panel_interface { + /** + * get_input_panel_surface - (none) + * @id: (none) + * @surface: (none) + */ + void (*get_input_panel_surface)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *surface); +}; + + +#ifndef WL_INPUT_PANEL_SURFACE_POSITION_ENUM +#define WL_INPUT_PANEL_SURFACE_POSITION_ENUM +enum wl_input_panel_surface_position { + WL_INPUT_PANEL_SURFACE_POSITION_CENTER_BOTTOM = 0, +}; +#endif /* WL_INPUT_PANEL_SURFACE_POSITION_ENUM */ + +struct wl_input_panel_surface_interface { + /** + * set_toplevel - set the surface type as a keyboard + * @output: (none) + * @position: (none) + * + * A keyboard surface is only shown, when a text model is active + */ + void (*set_toplevel)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *output, + uint32_t position); + /** + * set_overlay_panel - set the surface type as an overlay panel + * + * An overlay panel is shown near the input cursor above the + * application window when a text model is active. + */ + void (*set_overlay_panel)(struct wl_client *client, + struct wl_resource *resource); +}; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/modules/wl_desktop_shell/e_mod_input_panel.c b/src/modules/wl_desktop_shell/e_mod_input_panel.c new file mode 100644 index 000000000..a8350adfb --- /dev/null +++ b/src/modules/wl_desktop_shell/e_mod_input_panel.c @@ -0,0 +1,336 @@ +#define E_COMP_WL +#include "e.h" +#include "e_mod_main.h" +#include "e_input_method_protocol.h" + +typedef struct _E_Input_Panel E_Input_Panel; +typedef struct _E_Input_Panel_Surface E_Input_Panel_Surface; + +struct _E_Input_Panel +{ + struct wl_resource *resource; + Eina_List *surfaces; +}; + +struct _E_Input_Panel_Surface +{ + E_Client *ec; + + Eina_Bool panel; + Eina_Bool showing; +}; + +static E_Input_Panel input_panel; +static Eina_List *handlers = NULL; +static struct wl_global *input_panel_global = NULL; + +static void +_e_input_panel_surface_cb_toplevel_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *output_resource EINA_UNUSED, uint32_t position EINA_UNUSED) +{ + E_Input_Panel_Surface *ips; + + ips = wl_resource_get_user_data(resource); + ips->panel = EINA_FALSE; +} + +static void +_e_input_panel_surface_cb_overlay_panel_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource) +{ + E_Input_Panel_Surface *ips; + + ips = wl_resource_get_user_data(resource); + ips->panel = EINA_TRUE; +} + +static const struct wl_input_panel_surface_interface _e_input_panel_surface_implementation = { + _e_input_panel_surface_cb_toplevel_set, + _e_input_panel_surface_cb_overlay_panel_set +}; + +static void +_e_input_panel_surface_resource_destroy(struct wl_resource *resource) +{ + E_Input_Panel_Surface *ips; + E_Client *ec; + + ips = wl_resource_get_user_data(resource); + ec = ips->ec; + if (!e_object_is_del(E_OBJECT(ec))) + { + if (ec->comp_data->mapped) + { + if ((ec->comp_data->shell.surface) && + (ec->comp_data->shell.unmap)) + ec->comp_data->shell.unmap(ec->comp_data->shell.surface); + } + if (ec->parent) + { + ec->parent->transients = + eina_list_remove(ec->parent->transients, ec); + } + ec->comp_data->shell.surface = NULL; + } + + input_panel.surfaces = eina_list_remove(input_panel.surfaces, ips); + + free(ips); +} + +static void +_e_input_panel_position_set(E_Client *ec, int w, int h) +{ + int nx, ny; + int zx, zy, zw, zh; + + e_zone_useful_geometry_get(ec->zone, &zx, &zy, &zw, &zh); + + nx = zx + (zw - w) / 2; + ny = zy + zh - h; + + e_client_util_move_without_frame(ec, nx, ny); +} + +static void +_e_input_panel_surface_visible_update(E_Input_Panel_Surface *ips) +{ + E_Client *ec; + + ec = ips->ec; + if ((ips->showing) && + (e_pixmap_usable_get(ec->pixmap))) + { + if (!ips->panel) + _e_input_panel_position_set(ec, ec->client.w, ec->client.h); + + ec->visible = EINA_TRUE; + evas_object_geometry_set(ec->frame, ec->x, ec->y, ec->w, ec->h); + evas_object_show(ec->frame); + e_comp_object_damage(ec->frame, ec->x, ec->y, ec->w, ec->h); + } + else + { + ec->visible = EINA_FALSE; + evas_object_hide(ec->frame); + } +} + +static void +_e_input_panel_surface_configure(struct wl_resource *resource, Evas_Coord x EINA_UNUSED, Evas_Coord y EINA_UNUSED, Evas_Coord w, Evas_Coord h) +{ + E_Input_Panel_Surface *ips; + + ips = wl_resource_get_user_data(resource); + + e_client_util_resize_without_frame(ips->ec, w, h); + + if (ips->showing) + _e_input_panel_surface_visible_update(ips); +} + +static void +_e_input_panel_surface_map(struct wl_resource *resource) +{ + E_Input_Panel_Surface *ips; + E_Client *ec; + + ips = wl_resource_get_user_data(resource); + ec = ips->ec; + + if (e_object_is_del(E_OBJECT(ec))) + return; + + // NOTE: we need to set mapped, so that avoid showing evas_object and continue buffer's commit process. + if ((!ec->comp_data->mapped) && (e_pixmap_usable_get(ec->pixmap))) + ec->comp_data->mapped = EINA_TRUE; +} + +static void +_e_input_panel_surface_unmap(struct wl_resource *resource) +{ + E_Input_Panel_Surface *ips; + E_Client *ec; + + ips = wl_resource_get_user_data(resource); + ec = ips->ec; + + if (e_object_is_del(E_OBJECT(ec))) + return; + + if (ec->comp_data->mapped) + { + ec->visible = EINA_FALSE; + evas_object_hide(ec->frame); + ec->comp_data->mapped = EINA_FALSE; + } +} + +static void +_e_input_panel_cb_surface_get(struct wl_client *client, struct wl_resource *resource EINA_UNUSED, uint32_t id, struct wl_resource *surface_resource) +{ + E_Client *ec; + E_Input_Panel_Surface *ips; + E_Comp_Client_Data *cd; + + ec = wl_resource_get_user_data(surface_resource); + if (!ec) + { + wl_resource_post_error(surface_resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Client Set On Surface"); + return; + } + + cd = ec->comp_data; + if (!cd) + { + wl_resource_post_error(surface_resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Comp Data For Client"); + return; + } + + /* check for existing shell surface */ + if (ec->comp_data->shell.surface) + { + wl_resource_post_error(surface_resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "Client already has shell surface"); + return; + } + + ips = E_NEW(E_Input_Panel_Surface, 1); + if (!ips) + { + wl_client_post_no_memory(client); + return NULL; + } + + cd->shell.surface = wl_resource_create(client, + &wl_input_panel_surface_interface, + 1, id); + if (!cd->shell.surface) + { + wl_client_post_no_memory(client); + free(ips); + return NULL; + } + + ips->ec = ec; + + EC_CHANGED(ec); + if (!ec->new_client) + { + ec->new_client = EINA_TRUE; + e_comp->new_clients++; + } + if (ec->ignored) + e_client_unignore(ec); + + /* set input panel client properties */ + ec->borderless = EINA_TRUE; + ec->argb = EINA_TRUE; + ec->lock_border = EINA_TRUE; + ec->lock_focus_in = ec->lock_focus_out = EINA_TRUE; + ec->netwm.state.skip_taskbar = EINA_TRUE; + ec->netwm.state.skip_pager = EINA_TRUE; + ec->no_shape_cut = EINA_TRUE; + ec->border_size = 0; + ec->netwm.type = E_WINDOW_TYPE_UTILITY; + ec->comp_data->set_win_type = EINA_TRUE; + + + cd->surface = surface_resource; + cd->shell.configure_send = NULL; + cd->shell.configure = _e_input_panel_surface_configure; + cd->shell.ping = NULL; + cd->shell.map = _e_input_panel_surface_map; + cd->shell.unmap = _e_input_panel_surface_unmap; + + + wl_resource_set_implementation(cd->shell.surface, + &_e_input_panel_surface_implementation, + ips, _e_input_panel_surface_resource_destroy); + + input_panel.surfaces = eina_list_append(input_panel.surfaces, ips); +} + +static const struct wl_input_panel_interface _e_input_panel_implementation = { + _e_input_panel_cb_surface_get +}; + +static void +_e_input_panel_unbind(struct wl_resource *resource EINA_UNUSED) +{ + input_panel.resource = NULL; + + E_FREE_FUNC(input_panel.surfaces, eina_list_free); +} + +static void +_e_input_panel_bind(struct wl_client *client, void *data EINA_UNUSED, uint32_t version EINA_UNUSED, uint32_t id) +{ + struct wl_resource *resource; + + resource = wl_resource_create(client, &wl_input_panel_interface, 1, id); + if (!resource) + { + wl_client_post_no_memory(client); + return; + } + + if (input_panel.resource) + { + wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, + "interface object already bound"); + return; + } + + input_panel.resource = resource; + + wl_resource_set_implementation(resource, + &_e_input_panel_implementation, + NULL, _e_input_panel_unbind); +} + +static Eina_Bool +_e_input_panel_cb_visible_change(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + E_Event_Text_Input_Panel_Visibility_Change *ev = event; + E_Input_Panel_Surface *ips; + Eina_List *l; + + EINA_LIST_FOREACH(input_panel.surfaces, l, ips) + { + if (!ips->ec) continue; + ips->showing = ev->visible; + _e_input_panel_surface_visible_update(ips); + } + + return ECORE_CALLBACK_RENEW; +} + +EINTERN Eina_Bool +e_input_panel_init(void) +{ + E_LIST_HANDLER_APPEND(handlers, E_EVENT_TEXT_INPUT_PANEL_VISIBILITY_CHANGE, + _e_input_panel_cb_visible_change, NULL); + // TODO: add signal handler - update input panel + + input_panel_global = wl_global_create(e_comp->wl_comp_data->wl.disp, + &wl_input_panel_interface, 1, + NULL, _e_input_panel_bind); + if (!input_panel_global) + { + ERR("failed to create wl_global for input panel"); + return EINA_FALSE; + } + + return EINA_TRUE; +} + +EINTERN void +e_input_panel_shutdown(void) +{ + E_FREE_FUNC(input_panel_global, wl_global_destroy); + E_FREE_LIST(handlers, ecore_event_handler_del); +} diff --git a/src/modules/wl_desktop_shell/e_mod_main.c b/src/modules/wl_desktop_shell/e_mod_main.c index e6415b8fd..4ce8f61cb 100644 --- a/src/modules/wl_desktop_shell/e_mod_main.c +++ b/src/modules/wl_desktop_shell/e_mod_main.c @@ -1,5 +1,6 @@ #define E_COMP_WL #include "e.h" +#include "e_mod_main.h" #include "e_desktop_shell_protocol.h" #define XDG_SERVER_VERSION 5 @@ -1379,11 +1380,21 @@ e_modapi_init(E_Module *m) return NULL; } +#ifdef HAVE_WL_TEXT_INPUT + if (!e_input_panel_init()) + { + ERR("Could not init input panel"); + return NULL; + } +#endif + return m; } E_API int e_modapi_shutdown(E_Module *m EINA_UNUSED) { + e_input_panel_shutdown(); + return 1; } diff --git a/src/modules/wl_desktop_shell/e_mod_main.h b/src/modules/wl_desktop_shell/e_mod_main.h new file mode 100644 index 000000000..6a8a75c06 --- /dev/null +++ b/src/modules/wl_desktop_shell/e_mod_main.h @@ -0,0 +1,7 @@ +#ifndef _E_MOD_MAIN_H +#define _E_MOD_MAIN_H + +Eina_Bool e_input_panel_init(void); +void e_input_panel_shutdown(void); + +#endif diff --git a/src/modules/wl_text_input/e_mod_main.c b/src/modules/wl_text_input/e_mod_main.c new file mode 100644 index 000000000..d0c5191bf --- /dev/null +++ b/src/modules/wl_text_input/e_mod_main.c @@ -0,0 +1,933 @@ +#define E_COMP_WL +#include "e.h" +#include "text-protocol.h" +#include "input-method-protocol.h" + +typedef struct _E_Text_Input E_Text_Input; +typedef struct _E_Input_Method E_Input_Method; +typedef struct _E_Input_Method_Context E_Input_Method_Context; + +struct _E_Text_Input +{ + struct wl_resource *resource; + + E_Client *ec; + Eina_List *input_methods; + Eina_Rectangle *cursor_rect; + Eina_Bool input_panel_visible; +}; + +struct _E_Input_Method +{ + struct wl_resource *resource; + + E_Text_Input *model; + E_Input_Method_Context *context; + Eina_List *handlers; +}; + +struct _E_Input_Method_Context +{ + struct wl_resource *resource; + + E_Text_Input *model; + E_Input_Method *input_method; + + struct + { + struct wl_resource *resource; + Eina_List *handlers; + Eina_Bool grabbed; + } kbd; +}; + +static struct wl_global *text_input_manager_global; + +static void +_e_text_input_event_visible_change_send(Eina_Bool visible) +{ + E_Event_Text_Input_Panel_Visibility_Change *ev; + + ev = E_NEW(E_Event_Text_Input_Panel_Visibility_Change, 1); + ev->visible = visible; + ecore_event_add(E_EVENT_TEXT_INPUT_PANEL_VISIBILITY_CHANGE, ev, NULL, NULL); +} + +static void +_e_text_input_method_context_key_send(E_Input_Method_Context *context, unsigned int keycode, unsigned int timestamp, enum wl_keyboard_key_state state) +{ + uint32_t serial, nk; + + nk = keycode - 8; + + serial = wl_display_next_serial(e_comp->wl_comp_data->wl.disp); + wl_keyboard_send_key(context->kbd.resource, serial, timestamp, nk, state); +} + +static Eina_Bool +_e_text_input_method_context_ecore_cb_key_down(void *data, int ev_type EINA_UNUSED, Ecore_Event_Key *ev) +{ + E_Input_Method_Context *context = data; + + _e_text_input_method_context_key_send(context, ev->keycode, ev->timestamp, + WL_KEYBOARD_KEY_STATE_PRESSED); + + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool +_e_text_input_method_context_ecore_cb_key_up(void *data, int ev_type EINA_UNUSED, Ecore_Event_Key *ev) +{ + E_Input_Method_Context *context = data; + + _e_text_input_method_context_key_send(context, ev->keycode, ev->timestamp, + WL_KEYBOARD_KEY_STATE_RELEASED); + + return ECORE_CALLBACK_RENEW; +} + +static void +_e_text_input_method_context_grab_set(E_Input_Method_Context *context, Eina_Bool set) +{ + if (set == context->kbd.grabbed) + return; + + context->kbd.grabbed = set; + + if (set) + { + E_LIST_HANDLER_APPEND(context->kbd.handlers, ECORE_EVENT_KEY_DOWN, + _e_text_input_method_context_ecore_cb_key_down, + context); + E_LIST_HANDLER_APPEND(context->kbd.handlers, ECORE_EVENT_KEY_UP, + _e_text_input_method_context_ecore_cb_key_up, + context); + + e_comp_grab_input(0, 1); + } + else + { + E_FREE_LIST(context->kbd.handlers, ecore_event_handler_del); + e_comp_ungrab_input(0, 1); + } +} + +static void +_e_text_input_deactivate(E_Text_Input *text_input, E_Input_Method *input_method) +{ + if (input_method->model == text_input) + { + if ((input_method->context) && (input_method->resource)) + { + if (input_method->context) + _e_text_input_method_context_grab_set(input_method->context, + EINA_FALSE); + + wl_input_method_send_deactivate(input_method->resource, + input_method->context->resource); + } + + input_method->model = NULL; + input_method->context = NULL; + + text_input->input_methods = eina_list_remove(text_input->input_methods, input_method); + + wl_text_input_send_leave(text_input->resource); + } +} + +static void +_e_text_input_method_context_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void +_e_text_input_method_context_cb_string_commit(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial, const char *text) +{ + E_Input_Method_Context *context = wl_resource_get_user_data(resource); + + if (!context) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Input Method Context For Resource"); + return; + } + + if (context->model) + wl_text_input_send_commit_string(context->model->resource, + serial, text); +} + +static void +_e_text_input_method_context_cb_preedit_string(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial, const char *text, const char *commit) +{ + E_Input_Method_Context *context = wl_resource_get_user_data(resource); + + if (!context) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Input Method Context For Resource"); + return; + } + + if (context->model) + wl_text_input_send_preedit_string(context->model->resource, + serial, text, commit); +} + +static void +_e_text_input_method_context_cb_preedit_styling(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t index, uint32_t length, uint32_t style) +{ + E_Input_Method_Context *context = wl_resource_get_user_data(resource); + + if (!context) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Input Method Context For Resource"); + return; + } + + if (context->model) + wl_text_input_send_preedit_styling(context->model->resource, + index, length, style); +} + +static void +_e_text_input_method_context_cb_preedit_cursor(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, int32_t cursor) +{ + E_Input_Method_Context *context = wl_resource_get_user_data(resource); + + if (!context) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Input Method Context For Resource"); + return; + } + + if (context->model) + wl_text_input_send_preedit_cursor(context->model->resource, + cursor); +} + +static void +_e_text_input_method_context_cb_surrounding_text_delete(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, int32_t index, uint32_t length) +{ + E_Input_Method_Context *context = wl_resource_get_user_data(resource); + + if (!context) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Input Method Context For Resource"); + return; + } + + if (context->model) + wl_text_input_send_delete_surrounding_text(context->model->resource, + index, length); +} + +static void +_e_text_input_method_context_cb_cursor_position(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, int32_t index, int32_t anchor) +{ + E_Input_Method_Context *context = wl_resource_get_user_data(resource); + + if (!context) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Input Method Context For Resource"); + return; + } + + if (context->model) + wl_text_input_send_cursor_position(context->model->resource, + index, anchor); +} + +static void +_e_text_input_method_context_cb_modifiers_map(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_array *map) +{ + E_Input_Method_Context *context = wl_resource_get_user_data(resource); + + if (!context) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Input Method Context For Resource"); + return; + } + + if (context->model) + wl_text_input_send_modifiers_map(context->model->resource, map); +} + +static void +_e_text_input_method_context_cb_keysym(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, uint32_t modifiers) +{ + E_Input_Method_Context *context = wl_resource_get_user_data(resource); + + if (!context) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Input Method Context For Resource"); + return; + } + + if (context->model) + wl_text_input_send_keysym(context->model->resource, + serial, time, sym, state, modifiers); +} + +static void +_e_text_input_method_context_keyboard_unbind(struct wl_resource *resource) +{ + E_Input_Method_Context *context; + + context = wl_resource_get_user_data(resource); + + _e_text_input_method_context_grab_set(context, EINA_FALSE); + + context->kbd.resource = NULL; +} + +static void +_e_text_input_method_context_cb_keyboard_grab(struct wl_client *client, struct wl_resource *resource, uint32_t id) +{ + E_Input_Method_Context *context; + struct wl_resource *new_resource; + + DBG("Input Method Context - grab keyboard %d", wl_resource_get_id(resource)); + + context = wl_resource_get_user_data(resource); + if (!context) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Input Method Context For Resource"); + return; + } + + new_resource = wl_resource_create(client, &wl_keyboard_interface, 1, id); + if (!new_resource) + { + wl_resource_post_no_memory(resource); + return; + } + + wl_resource_set_implementation(new_resource, NULL, context, + _e_text_input_method_context_keyboard_unbind); + + wl_keyboard_send_keymap(new_resource, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, + e_comp_wl->xkb.fd, + e_comp_wl->xkb.size); + + context->kbd.resource = new_resource; + + _e_text_input_method_context_grab_set(context, EINA_TRUE); +} + +static void +_e_text_input_method_context_cb_key(struct wl_client *client EINA_UNUSED, struct wl_resource *resource EINA_UNUSED, uint32_t serial EINA_UNUSED, uint32_t time EINA_UNUSED, uint32_t key EINA_UNUSED, uint32_t state_w EINA_UNUSED) +{ + DBG("Input Method Context - key %d", wl_resource_get_id(resource)); +} + +static void +_e_text_input_method_context_cb_modifiers(struct wl_client *client EINA_UNUSED, struct wl_resource *resource EINA_UNUSED, uint32_t serial EINA_UNUSED, uint32_t mods_depressed EINA_UNUSED, uint32_t mods_latched EINA_UNUSED, uint32_t mods_locked EINA_UNUSED, uint32_t group EINA_UNUSED) +{ + DBG("Input Method Context - modifiers %d", wl_resource_get_id(resource)); +} + +static void +_e_text_input_method_context_cb_language(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial, const char *language) +{ + E_Input_Method_Context *context = wl_resource_get_user_data(resource); + + if (!context) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Input Method Context For Resource"); + return; + } + + if (context->model) + wl_text_input_send_language(context->model->resource, + serial, language); +} + +static void +_e_text_input_method_context_cb_text_direction(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial, uint32_t direction) +{ + E_Input_Method_Context *context = wl_resource_get_user_data(resource); + + if (!context) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Input Method Context For Resource"); + return; + } + + if (context->model) + wl_text_input_send_text_direction(context->model->resource, + serial, direction); +} + +static const struct wl_input_method_context_interface _e_text_input_method_context_implementation = { + _e_text_input_method_context_cb_destroy, + _e_text_input_method_context_cb_string_commit, + _e_text_input_method_context_cb_preedit_string, + _e_text_input_method_context_cb_preedit_styling, + _e_text_input_method_context_cb_preedit_cursor, + _e_text_input_method_context_cb_surrounding_text_delete, + _e_text_input_method_context_cb_cursor_position, + _e_text_input_method_context_cb_modifiers_map, + _e_text_input_method_context_cb_keysym, + _e_text_input_method_context_cb_keyboard_grab, + _e_text_input_method_context_cb_key, + _e_text_input_method_context_cb_modifiers, + _e_text_input_method_context_cb_language, + _e_text_input_method_context_cb_text_direction +}; + +static void +_e_text_input_method_context_cb_resource_destroy(struct wl_resource *resource) +{ + E_Input_Method_Context *context = wl_resource_get_user_data(resource); + + if (!context) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Input Method Context For Resource"); + return; + } + + if (context->kbd.resource) + wl_resource_destroy(context->kbd.resource); + + free(context); +} + +static Eina_Bool +_e_text_input_cb_event_client_focus_in(void *data, int type EINA_UNUSED, void *event) +{ + E_Input_Method *input_method = data; + E_Event_Client *ev = event; + + if (!input_method->model) + return ECORE_CALLBACK_RENEW; + + if ((!ev->ec) || + (input_method->model->ec != ev->ec)) + { + _e_text_input_deactivate(input_method->model, input_method); + _e_text_input_event_visible_change_send(EINA_FALSE); + } + + return ECORE_CALLBACK_RENEW; +} + +static void +_e_text_input_cb_activate(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat, struct wl_resource *surface) +{ + E_Text_Input *text_input; + E_Input_Method *input_method; + E_Text_Input *old; + E_Input_Method_Context *context; + + text_input = wl_resource_get_user_data(resource); + if (!text_input) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Text Input For Resource"); + return; + } + + input_method = + wl_resource_get_user_data(e_comp->wl_comp_data->seat.im.resource); + if (!input_method) + { + wl_resource_post_error(seat, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Input Method For Seat"); + return; + } + + old = input_method->model; + if (old == text_input) + return; + + if (old) + _e_text_input_deactivate(old, input_method); + + input_method->model = text_input; + text_input->input_methods = + eina_list_append(text_input->input_methods, input_method); + + text_input->ec = wl_resource_get_user_data(surface); + + if (input_method->resource) + { + context = E_NEW(E_Input_Method_Context, 1); + if (!context) + { + wl_client_post_no_memory(client); + ERR("Could not allocate space for Input_Method_Context"); + return; + } + + context->resource = + wl_resource_create(wl_resource_get_client(input_method->resource), + &wl_input_method_context_interface, 1, 0); + wl_resource_set_implementation(context->resource, + &_e_text_input_method_context_implementation, + context, _e_text_input_method_context_cb_resource_destroy); + + context->model = text_input; + context->input_method = input_method; + input_method->context = context; + + wl_input_method_send_activate(input_method->resource, context->resource); + } + + if (text_input->input_panel_visible) + _e_text_input_event_visible_change_send(EINA_TRUE); + + wl_text_input_send_enter(text_input->resource, surface); +} + +static void +_e_text_input_cb_deactivate(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *seat) +{ + E_Text_Input *text_input; + E_Input_Method *input_method; + + text_input = wl_resource_get_user_data(resource); + if (!text_input) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Text Input For Resource"); + return; + } + + input_method = + wl_resource_get_user_data(e_comp->wl_comp_data->seat.im.resource); + if (!input_method) + { + wl_resource_post_error(seat, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Input Method For Seat"); + return; + } + + _e_text_input_deactivate(text_input, input_method); + _e_text_input_event_visible_change_send(EINA_FALSE); + +} + +static void +_e_text_input_cb_input_panel_show(struct wl_client *client EINA_UNUSED, struct wl_resource *resource) +{ + E_Text_Input *text_input = wl_resource_get_user_data(resource); + E_Input_Method *input_method; + Eina_List *l; + + if (!text_input) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Text Input For Resource"); + return; + } + + text_input->input_panel_visible = 1; + + EINA_LIST_FOREACH(text_input->input_methods, l, input_method) + { + if (input_method->model == text_input) + _e_text_input_event_visible_change_send(EINA_TRUE); + } +} + +static void +_e_text_input_cb_input_panel_hide(struct wl_client *client EINA_UNUSED, struct wl_resource *resource) +{ + E_Text_Input *text_input = wl_resource_get_user_data(resource); + E_Input_Method *input_method; + Eina_List *l; + + if (!text_input) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Text Input For Resource"); + return; + } + + text_input->input_panel_visible = 0; + + EINA_LIST_FOREACH(text_input->input_methods, l, input_method) + { + if (input_method->model == text_input) + _e_text_input_event_visible_change_send(EINA_FALSE); + } +} + +static void +_e_text_input_cb_reset(struct wl_client *client EINA_UNUSED, struct wl_resource *resource) +{ + E_Text_Input *text_input = wl_resource_get_user_data(resource); + E_Input_Method *input_method; + Eina_List *l; + + if (!text_input) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Text Input For Resource"); + return; + } + + EINA_LIST_FOREACH(text_input->input_methods, l, input_method) + { + if (!input_method->context) continue; + wl_input_method_context_send_reset(input_method->context->resource); + } +} + +static void +_e_text_input_cb_surrounding_text_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, const char *text, uint32_t cursor, uint32_t anchor) +{ + E_Text_Input *text_input = wl_resource_get_user_data(resource); + E_Input_Method *input_method; + Eina_List *l; + + if (!text_input) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Text Input For Resource"); + return; + } + + EINA_LIST_FOREACH(text_input->input_methods, l, input_method) + { + if (!input_method->context) continue; + wl_input_method_context_send_surrounding_text(input_method->context->resource, + text, cursor, anchor); + } +} + +static void +_e_text_input_cb_content_type_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t hint, uint32_t purpose) +{ + E_Text_Input *text_input = wl_resource_get_user_data(resource); + E_Input_Method *input_method; + Eina_List *l; + + if (!text_input) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Text Input For Resource"); + return; + } + + EINA_LIST_FOREACH(text_input->input_methods, l, input_method) + { + if (!input_method->context) continue; + wl_input_method_context_send_content_type(input_method->context->resource, + hint, purpose); + } +} + +static void +_e_text_input_cb_cursor_rectangle_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) +{ + E_Text_Input *text_input = wl_resource_get_user_data(resource); + + if (!text_input) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Text Input For Resource"); + return; + } + + text_input->cursor_rect = eina_rectangle_new(x, y, width, height); + + // TODO: issue event update input_panel +} + +static void +_e_text_input_cb_preferred_language_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, const char *language) +{ + E_Text_Input *text_input = wl_resource_get_user_data(resource); + E_Input_Method *input_method; + Eina_List *l; + + if (!text_input) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Text Input For Resource"); + return; + } + + EINA_LIST_FOREACH(text_input->input_methods, l, input_method) + { + if (!input_method->context) continue; + wl_input_method_context_send_preferred_language(input_method->context->resource, + language); + } +} + +static void +_e_text_input_cb_state_commit(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial) +{ + E_Text_Input *text_input = wl_resource_get_user_data(resource); + E_Input_Method *input_method; + Eina_List *l; + + if (!text_input) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Text Input For Resource"); + return; + } + + EINA_LIST_FOREACH(text_input->input_methods, l, input_method) + { + if (!input_method->context) continue; + wl_input_method_context_send_commit_state(input_method->context->resource, serial); + } +} + +static void +_e_text_input_cb_action_invoke(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t button, uint32_t index) +{ + E_Text_Input *text_input = wl_resource_get_user_data(resource); + E_Input_Method *input_method; + Eina_List *l; + + if (!text_input) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Text Input For Resource"); + return; + } + + EINA_LIST_FOREACH(text_input->input_methods, l, input_method) + { + if (!input_method->context) continue; + wl_input_method_context_send_invoke_action(input_method->context->resource, + button, index); + } +} + +static const struct wl_text_input_interface _e_text_input_implementation = { + _e_text_input_cb_activate, + _e_text_input_cb_deactivate, + _e_text_input_cb_input_panel_show, + _e_text_input_cb_input_panel_hide, + _e_text_input_cb_reset, + _e_text_input_cb_surrounding_text_set, + _e_text_input_cb_content_type_set, + _e_text_input_cb_cursor_rectangle_set, + _e_text_input_cb_preferred_language_set, + _e_text_input_cb_state_commit, + _e_text_input_cb_action_invoke +}; + +static void +_e_text_input_cb_destroy(struct wl_resource *resource) +{ + E_Text_Input *text_input = wl_resource_get_user_data(resource); + E_Input_Method *input_method; + + if (!text_input) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Text Input For Resource"); + return; + } + + EINA_LIST_FREE(text_input->input_methods, input_method) + _e_text_input_deactivate(text_input, input_method); + + eina_rectangle_free(text_input->cursor_rect); + free(text_input); +} + +static void +_e_text_input_manager_cb_text_input_create(struct wl_client *client, struct wl_resource *resource EINA_UNUSED, uint32_t id) +{ + E_Text_Input *text_input; + + text_input = E_NEW(E_Text_Input, 1); + if (!text_input) + { + wl_client_post_no_memory(client); + ERR("Could not allocate space for Text_Input"); + return; + } + + text_input->resource = wl_resource_create(client, + &wl_text_input_interface, + 1, id); + if (!text_input->resource) + { + wl_client_post_no_memory(client); + ERR("could not create wl_resource for text input"); + return; + } + + wl_resource_set_implementation(text_input->resource, + &_e_text_input_implementation, + text_input, _e_text_input_cb_destroy); +} + +static const struct wl_text_input_manager_interface _e_text_input_manager_implementation = { + _e_text_input_manager_cb_text_input_create +}; + +static void +_e_text_cb_bind_text_input_manager(struct wl_client *client, void *data EINA_UNUSED, uint32_t version EINA_UNUSED, uint32_t id) +{ + struct wl_resource *resource; + + resource = wl_resource_create(client, &wl_text_input_manager_interface, 1, id); + if (!resource) + { + wl_client_post_no_memory(client); + ERR("could not create resource for text input manager"); + return; + } + + wl_resource_set_implementation(resource, &_e_text_input_manager_implementation, NULL, NULL); +} + +static void +_e_text_input_method_cb_unbind(struct wl_resource *resource) +{ + E_Input_Method *input_method = wl_resource_get_user_data(resource); + + e_comp->wl_comp_data->seat.im.resource = NULL; + + input_method = wl_resource_get_user_data(resource); + if (!input_method) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Input Method For Resource"); + return; + } + + if (input_method->model) + _e_text_input_deactivate(input_method->model, input_method); + + E_FREE_FUNC(input_method->handlers, ecore_event_handler_del); + + input_method->resource = NULL; + input_method->context = NULL; + + free(input_method); +} + +static void +_e_text_cb_bind_input_method(struct wl_client *client, void *data EINA_UNUSED, uint32_t version EINA_UNUSED, uint32_t id) +{ + E_Input_Method *input_method; + struct wl_resource *resource; + + resource = wl_resource_create(client, &wl_input_method_interface, 1, id); + if (!resource) + { + wl_client_post_no_memory(client); + ERR("could not create wl_resource for input method"); + return; + } + + if (e_comp->wl_comp_data->seat.im.resource) + { + wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, + "interface object already bound"); + wl_resource_destroy(resource); + return; + } + + /* FIXME: we need to make sure the client attempting to bind + this interface really provides vkbd. */ + + input_method = E_NEW(E_Input_Method, 1); + if (!input_method) + { + wl_client_post_no_memory(client); + wl_resource_destroy(resource); + ERR("Could not allocate space for Input_Method"); + return; + } + + wl_resource_set_implementation(resource, NULL, input_method, + _e_text_input_method_cb_unbind); + + input_method->model = NULL; + input_method->context = NULL; + input_method->resource = resource; + + e_comp->wl_comp_data->seat.im.resource = resource; + + E_LIST_HANDLER_APPEND(input_method->handlers, E_EVENT_CLIENT_FOCUS_IN, + _e_text_input_cb_event_client_focus_in, input_method); +} + +EAPI E_Module_Api e_modapi = { E_MODULE_API_VERSION, "Wl_Text_Input" }; + +EAPI void * +e_modapi_init(E_Module *m) +{ + // FIXME: create only one input method object per seat. + e_comp->wl_comp_data->seat.im.global = + wl_global_create(e_comp->wl_comp_data->wl.disp, &wl_input_method_interface, 1, + NULL, _e_text_cb_bind_input_method); + if (!e_comp->wl_comp_data->seat.im.global) + { + ERR("failed to create wl_global for input method"); + return NULL; + } + + text_input_manager_global = + wl_global_create(e_comp->wl_comp_data->wl.disp, &wl_text_input_manager_interface, 1, + NULL, _e_text_cb_bind_text_input_manager); + if (!text_input_manager_global) + { + ERR("failed to create wl_global for text input manager"); + wl_global_destroy(e_comp->wl_comp_data->seat.im.global); + return NULL; + } + + return m; +} + +EAPI int +e_modapi_shutdown(E_Module *m EINA_UNUSED) +{ + E_FREE_FUNC(e_comp->wl_comp_data->seat.im.global, wl_global_destroy); + E_FREE_FUNC(text_input_manager_global, wl_global_destroy); + + return 1; +} diff --git a/src/modules/wl_text_input/input-method-protocol.c b/src/modules/wl_text_input/input-method-protocol.c new file mode 100644 index 000000000..feae24429 --- /dev/null +++ b/src/modules/wl_text_input/input-method-protocol.c @@ -0,0 +1,114 @@ +/* + * 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_input_method_context_interface; +extern const struct wl_interface wl_input_panel_surface_interface; +extern const struct wl_interface wl_keyboard_interface; +extern const struct wl_interface wl_output_interface; +extern const struct wl_interface wl_surface_interface; + +static const struct wl_interface *types[] = { + NULL, + NULL, + NULL, + NULL, + NULL, + &wl_keyboard_interface, + &wl_input_method_context_interface, + &wl_input_method_context_interface, + &wl_input_panel_surface_interface, + &wl_surface_interface, + &wl_output_interface, + NULL, +}; + +static const struct wl_message wl_input_method_context_requests[] = { + { "destroy", "", types + 0 }, + { "commit_string", "us", types + 0 }, + { "preedit_string", "uss", types + 0 }, + { "preedit_styling", "uuu", types + 0 }, + { "preedit_cursor", "i", types + 0 }, + { "delete_surrounding_text", "iu", types + 0 }, + { "cursor_position", "ii", types + 0 }, + { "modifiers_map", "a", types + 0 }, + { "keysym", "uuuuu", types + 0 }, + { "grab_keyboard", "n", types + 5 }, + { "key", "uuuu", types + 0 }, + { "modifiers", "uuuuu", types + 0 }, + { "language", "us", types + 0 }, + { "text_direction", "uu", types + 0 }, +}; + +static const struct wl_message wl_input_method_context_events[] = { + { "surrounding_text", "suu", types + 0 }, + { "reset", "", types + 0 }, + { "content_type", "uu", types + 0 }, + { "invoke_action", "uu", types + 0 }, + { "commit_state", "u", types + 0 }, + { "preferred_language", "s", types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_input_method_context_interface = { + "wl_input_method_context", 1, + 14, wl_input_method_context_requests, + 6, wl_input_method_context_events, +}; + +static const struct wl_message wl_input_method_events[] = { + { "activate", "n", types + 6 }, + { "deactivate", "o", types + 7 }, +}; + +WL_EXPORT const struct wl_interface wl_input_method_interface = { + "wl_input_method", 1, + 0, NULL, + 2, wl_input_method_events, +}; + +static const struct wl_message wl_input_panel_requests[] = { + { "get_input_panel_surface", "no", types + 8 }, +}; + +WL_EXPORT const struct wl_interface wl_input_panel_interface = { + "wl_input_panel", 1, + 1, wl_input_panel_requests, + 0, NULL, +}; + +static const struct wl_message wl_input_panel_surface_requests[] = { + { "set_toplevel", "ou", types + 10 }, + { "set_overlay_panel", "", types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_input_panel_surface_interface = { + "wl_input_panel_surface", 1, + 2, wl_input_panel_surface_requests, + 0, NULL, +}; + diff --git a/src/modules/wl_text_input/input-method-protocol.h b/src/modules/wl_text_input/input-method-protocol.h new file mode 100644 index 000000000..e4b89887e --- /dev/null +++ b/src/modules/wl_text_input/input-method-protocol.h @@ -0,0 +1,418 @@ +/* + * 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 INPUT_METHOD_SERVER_PROTOCOL_H +#define INPUT_METHOD_SERVER_PROTOCOL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "wayland-server.h" + +struct wl_client; +struct wl_resource; + +struct wl_input_method_context; +struct wl_input_method; +struct wl_input_panel; +struct wl_input_panel_surface; + +extern const struct wl_interface wl_input_method_context_interface; +extern const struct wl_interface wl_input_method_interface; +extern const struct wl_interface wl_input_panel_interface; +extern const struct wl_interface wl_input_panel_surface_interface; + +/** + * wl_input_method_context - input method context + * @destroy: (none) + * @commit_string: commit string + * @preedit_string: pre-edit string + * @preedit_styling: pre-edit styling + * @preedit_cursor: pre-edit cursor + * @delete_surrounding_text: delete text + * @cursor_position: set cursor to a new position + * @modifiers_map: (none) + * @keysym: keysym + * @grab_keyboard: grab hardware keyboard + * @key: forward key event + * @modifiers: forward modifiers event + * @language: (none) + * @text_direction: (none) + * + * Corresponds to a text model on input method side. An input method + * context is created on text model activation on the input method side. It + * allows to receive information about the text model from the application + * via events. Input method contexts do not keep state after deactivation + * and should be destroyed after deactivation is handled. + * + * Text is generally UTF-8 encoded, indices and lengths are in bytes. + * + * 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_input_method_context_interface { + /** + * destroy - (none) + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * commit_string - commit string + * @serial: serial of the latest known text input state + * @text: (none) + * + * Send the commit string text for insertion to the application. + * + * 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 will be removed. + */ + void (*commit_string)(struct wl_client *client, + struct wl_resource *resource, + uint32_t serial, + const char *text); + /** + * preedit_string - pre-edit string + * @serial: serial of the latest known text input state + * @text: (none) + * @commit: (none) + * + * Send the pre-edit string text to the application text input. + * + * The commit text can be used to replace the preedit text on reset + * (for example on unfocus). + * + * Also previously sent preedit_style and preedit_cursor requests + * are processed bt the text_input also. + */ + void (*preedit_string)(struct wl_client *client, + struct wl_resource *resource, + 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 in bytes from index relative to the beginning + * of the composing text (as byte offset). Multiple styles can be + * applied to a composing text. + * + * This request should be sent before sending preedit_string + * request. + */ + void (*preedit_styling)(struct wl_client *client, + struct wl_resource *resource, + 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 byte + * offset) relative to the start of the composing text. + * + * When index is negative no cursor should be displayed. + * + * This request should be sent before sending preedit_string + * request. + */ + void (*preedit_cursor)(struct wl_client *client, + struct wl_resource *resource, + int32_t index); + /** + * delete_surrounding_text - delete text + * @index: (none) + * @length: (none) + * + * + * + * This request will be handled on text_input side as part of a + * directly following commit_string request. + */ + void (*delete_surrounding_text)(struct wl_client *client, + struct wl_resource *resource, + int32_t index, + uint32_t length); + /** + * cursor_position - set cursor to a new position + * @index: (none) + * @anchor: (none) + * + * Sets the cursor and anchor to a new position. Index is the new + * cursor position in bytes (when >= 0 relative to the end of + * inserted text else relative to beginning of inserted text). + * Anchor is the new anchor position in bytes (when >= 0 relative + * to the end of inserted text, else relative to beginning of + * inserted text). When there should be no selected text anchor + * should be the same as index. + * + * This request will be handled on text_input side as part of a + * directly following commit_string request. + */ + void (*cursor_position)(struct wl_client *client, + struct wl_resource *resource, + int32_t index, + int32_t anchor); + /** + * modifiers_map - (none) + * @map: (none) + */ + void (*modifiers_map)(struct wl_client *client, + struct wl_resource *resource, + struct wl_array *map); + /** + * 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_surrounfing_text, etc. The key event + * follows the wl_keyboard key event convention. Sym is a XKB + * keysym, state a wl_keyboard key_state. + */ + void (*keysym)(struct wl_client *client, + struct wl_resource *resource, + uint32_t serial, + uint32_t time, + uint32_t sym, + uint32_t state, + uint32_t modifiers); + /** + * grab_keyboard - grab hardware keyboard + * @keyboard: (none) + * + * Allows an input method to receive hardware keyboard input and + * process key events to generate text events (with pre-edit) over + * the wire. This allows input methods which compose multiple key + * events for inputting text like it is done for CJK languages. + */ + void (*grab_keyboard)(struct wl_client *client, + struct wl_resource *resource, + uint32_t keyboard); + /** + * key - forward key event + * @serial: serial from wl_keyboard::key + * @time: time from wl_keyboard::key + * @key: key from wl_keyboard::key + * @state: state from wl_keyboard::key + * + * Should be used when filtering key events with grab_keyboard. + * + * When the wl_keyboard::key event is not processed by the input + * method itself and should be sent to the client instead, forward + * it with this request. The arguments should be the ones from the + * wl_keyboard::key event. + * + * For generating custom key events use the keysym request instead. + */ + void (*key)(struct wl_client *client, + struct wl_resource *resource, + uint32_t serial, + uint32_t time, + uint32_t key, + uint32_t state); + /** + * modifiers - forward modifiers event + * @serial: serial from wl_keyboard::modifiers + * @mods_depressed: mods_depressed from wl_keyboard::modifiers + * @mods_latched: mods_latched from wl_keyboard::modifiers + * @mods_locked: mods_locked from wl_keyboard::modifiers + * @group: group from wl_keyboard::modifiers + * + * Should be used when filtering key events with grab_keyboard. + * + * When the wl_keyboard::modifiers event should be also send to the + * client, forward it with this request. The arguments should be + * the ones from the wl_keyboard::modifiers event. + */ + void (*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); + /** + * language - (none) + * @serial: serial of the latest known text input state + * @language: (none) + */ + void (*language)(struct wl_client *client, + struct wl_resource *resource, + uint32_t serial, + const char *language); + /** + * text_direction - (none) + * @serial: serial of the latest known text input state + * @direction: (none) + */ + void (*text_direction)(struct wl_client *client, + struct wl_resource *resource, + uint32_t serial, + uint32_t direction); +}; + +#define WL_INPUT_METHOD_CONTEXT_SURROUNDING_TEXT 0 +#define WL_INPUT_METHOD_CONTEXT_RESET 1 +#define WL_INPUT_METHOD_CONTEXT_CONTENT_TYPE 2 +#define WL_INPUT_METHOD_CONTEXT_INVOKE_ACTION 3 +#define WL_INPUT_METHOD_CONTEXT_COMMIT_STATE 4 +#define WL_INPUT_METHOD_CONTEXT_PREFERRED_LANGUAGE 5 + +#define WL_INPUT_METHOD_CONTEXT_SURROUNDING_TEXT_SINCE_VERSION 1 +#define WL_INPUT_METHOD_CONTEXT_RESET_SINCE_VERSION 1 +#define WL_INPUT_METHOD_CONTEXT_CONTENT_TYPE_SINCE_VERSION 1 +#define WL_INPUT_METHOD_CONTEXT_INVOKE_ACTION_SINCE_VERSION 1 +#define WL_INPUT_METHOD_CONTEXT_COMMIT_STATE_SINCE_VERSION 1 +#define WL_INPUT_METHOD_CONTEXT_PREFERRED_LANGUAGE_SINCE_VERSION 1 + +static inline void +wl_input_method_context_send_surrounding_text(struct wl_resource *resource_, const char *text, uint32_t cursor, uint32_t anchor) +{ + wl_resource_post_event(resource_, WL_INPUT_METHOD_CONTEXT_SURROUNDING_TEXT, text, cursor, anchor); +} + +static inline void +wl_input_method_context_send_reset(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, WL_INPUT_METHOD_CONTEXT_RESET); +} + +static inline void +wl_input_method_context_send_content_type(struct wl_resource *resource_, uint32_t hint, uint32_t purpose) +{ + wl_resource_post_event(resource_, WL_INPUT_METHOD_CONTEXT_CONTENT_TYPE, hint, purpose); +} + +static inline void +wl_input_method_context_send_invoke_action(struct wl_resource *resource_, uint32_t button, uint32_t index) +{ + wl_resource_post_event(resource_, WL_INPUT_METHOD_CONTEXT_INVOKE_ACTION, button, index); +} + +static inline void +wl_input_method_context_send_commit_state(struct wl_resource *resource_, uint32_t serial) +{ + wl_resource_post_event(resource_, WL_INPUT_METHOD_CONTEXT_COMMIT_STATE, serial); +} + +static inline void +wl_input_method_context_send_preferred_language(struct wl_resource *resource_, const char *language) +{ + wl_resource_post_event(resource_, WL_INPUT_METHOD_CONTEXT_PREFERRED_LANGUAGE, language); +} + +#define WL_INPUT_METHOD_ACTIVATE 0 +#define WL_INPUT_METHOD_DEACTIVATE 1 + +#define WL_INPUT_METHOD_ACTIVATE_SINCE_VERSION 1 +#define WL_INPUT_METHOD_DEACTIVATE_SINCE_VERSION 1 + +static inline void +wl_input_method_send_activate(struct wl_resource *resource_, struct wl_resource *id) +{ + wl_resource_post_event(resource_, WL_INPUT_METHOD_ACTIVATE, id); +} + +static inline void +wl_input_method_send_deactivate(struct wl_resource *resource_, struct wl_resource *context) +{ + wl_resource_post_event(resource_, WL_INPUT_METHOD_DEACTIVATE, context); +} + +/** + * wl_input_panel - interface for implementing keyboards + * @get_input_panel_surface: (none) + * + * Only one client can bind this interface at a time. + */ +struct wl_input_panel_interface { + /** + * get_input_panel_surface - (none) + * @id: (none) + * @surface: (none) + */ + void (*get_input_panel_surface)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *surface); +}; + + +#ifndef WL_INPUT_PANEL_SURFACE_POSITION_ENUM +#define WL_INPUT_PANEL_SURFACE_POSITION_ENUM +enum wl_input_panel_surface_position { + WL_INPUT_PANEL_SURFACE_POSITION_CENTER_BOTTOM = 0, +}; +#endif /* WL_INPUT_PANEL_SURFACE_POSITION_ENUM */ + +struct wl_input_panel_surface_interface { + /** + * set_toplevel - set the surface type as a keyboard + * @output: (none) + * @position: (none) + * + * A keyboard surface is only shown, when a text model is active + */ + void (*set_toplevel)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *output, + uint32_t position); + /** + * set_overlay_panel - set the surface type as an overlay panel + * + * An overlay panel is shown near the input cursor above the + * application window when a text model is active. + */ + void (*set_overlay_panel)(struct wl_client *client, + struct wl_resource *resource); +}; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/modules/wl_text_input/text-protocol.c b/src/modules/wl_text_input/text-protocol.c new file mode 100644 index 000000000..c5b3f07e8 --- /dev/null +++ b/src/modules/wl_text_input/text-protocol.c @@ -0,0 +1,92 @@ +/* + * 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_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/wl_text_input/text-protocol.h b/src/modules/wl_text_input/text-protocol.h new file mode 100644 index 000000000..21ab8e15e --- /dev/null +++ b/src/modules/wl_text_input/text-protocol.h @@ -0,0 +1,448 @@ +/* + * 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_SERVER_PROTOCOL_H +#define TEXT_SERVER_PROTOCOL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "wayland-util.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 + * @activate: request activation + * @deactivate: request deactivation + * @show_input_panel: show input panels + * @hide_input_panel: hide input panels + * @reset: reset + * @set_surrounding_text: sets the surrounding text + * @set_content_type: set content purpose and hint + * @set_cursor_rectangle: (none) + * @set_preferred_language: sets preferred language + * @commit_state: (none) + * @invoke_action: (none) + * + * 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 bytes. + * + * 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_interface { + /** + * activate - request activation + * @seat: (none) + * @surface: (none) + * + * Requests the text-input object to be activated (typically when + * the text entry gets focus). The seat argument is a wl_seat which + * maintains the focus for this activation. The surface argument is + * a wl_surface assigned to the text-input object and tracked for + * focus lost. The enter event is emitted on successful activation. + */ + void (*activate)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat, + struct wl_resource *surface); + /** + * deactivate - request deactivation + * @seat: (none) + * + * Requests the text-input object to be deactivated (typically + * when the text entry lost focus). The seat argument is a wl_seat + * which was used for activation. + */ + void (*deactivate)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat); + /** + * show_input_panel - show input panels + * + * Requests input panels (virtual keyboard) to show. + */ + void (*show_input_panel)(struct wl_client *client, + struct wl_resource *resource); + /** + * hide_input_panel - hide input panels + * + * Requests input panels (virtual keyboard) to hide. + */ + void (*hide_input_panel)(struct wl_client *client, + struct wl_resource *resource); + /** + * reset - reset + * + * Should be called by an editor widget when the input state + * should be reset, for example after the text was changed outside + * of the normal input method flow. + */ + void (*reset)(struct wl_client *client, + struct wl_resource *resource); + /** + * set_surrounding_text - sets the surrounding text + * @text: (none) + * @cursor: (none) + * @anchor: (none) + * + * Sets the plain surrounding text around the input position. + * Text is UTF-8 encoded. Cursor is the byte offset within the + * surrounding text. Anchor is the byte offset of the selection + * anchor within the surrounding text. If there is no selected text + * anchor is the same as cursor. + */ + void (*set_surrounding_text)(struct wl_client *client, + struct wl_resource *resource, + const char *text, + uint32_t cursor, + uint32_t anchor); + /** + * set_content_type - set content purpose and hint + * @hint: (none) + * @purpose: (none) + * + * Sets the content purpose and content hint. While the purpose + * is the basic purpose of an input field, the hint flags allow to + * modify some of the behavior. + * + * When no content type is explicitly set, a normal content purpose + * with default hints (auto completion, auto correction, auto + * capitalization) should be assumed. + */ + void (*set_content_type)(struct wl_client *client, + struct wl_resource *resource, + uint32_t hint, + uint32_t purpose); + /** + * set_cursor_rectangle - (none) + * @x: (none) + * @y: (none) + * @width: (none) + * @height: (none) + */ + void (*set_cursor_rectangle)(struct wl_client *client, + struct wl_resource *resource, + int32_t x, + int32_t y, + int32_t width, + int32_t height); + /** + * set_preferred_language - sets preferred language + * @language: (none) + * + * Sets a specific language. This allows for example a virtual + * keyboard to show a language specific layout. The "language" + * argument is a RFC-3066 format language tag. + * + * It could be used for example in a word processor to indicate + * language of currently edited document or in an instant message + * application which tracks languages of contacts. + */ + void (*set_preferred_language)(struct wl_client *client, + struct wl_resource *resource, + const char *language); + /** + * commit_state - (none) + * @serial: used to identify the known state + */ + void (*commit_state)(struct wl_client *client, + struct wl_resource *resource, + uint32_t serial); + /** + * invoke_action - (none) + * @button: (none) + * @index: (none) + */ + void (*invoke_action)(struct wl_client *client, + struct wl_resource *resource, + uint32_t button, + uint32_t index); +}; + +#define WL_TEXT_INPUT_ENTER 0 +#define WL_TEXT_INPUT_LEAVE 1 +#define WL_TEXT_INPUT_MODIFIERS_MAP 2 +#define WL_TEXT_INPUT_INPUT_PANEL_STATE 3 +#define WL_TEXT_INPUT_PREEDIT_STRING 4 +#define WL_TEXT_INPUT_PREEDIT_STYLING 5 +#define WL_TEXT_INPUT_PREEDIT_CURSOR 6 +#define WL_TEXT_INPUT_COMMIT_STRING 7 +#define WL_TEXT_INPUT_CURSOR_POSITION 8 +#define WL_TEXT_INPUT_DELETE_SURROUNDING_TEXT 9 +#define WL_TEXT_INPUT_KEYSYM 10 +#define WL_TEXT_INPUT_LANGUAGE 11 +#define WL_TEXT_INPUT_TEXT_DIRECTION 12 + +#define WL_TEXT_INPUT_ENTER_SINCE_VERSION 1 +#define WL_TEXT_INPUT_LEAVE_SINCE_VERSION 1 +#define WL_TEXT_INPUT_MODIFIERS_MAP_SINCE_VERSION 1 +#define WL_TEXT_INPUT_INPUT_PANEL_STATE_SINCE_VERSION 1 +#define WL_TEXT_INPUT_PREEDIT_STRING_SINCE_VERSION 1 +#define WL_TEXT_INPUT_PREEDIT_STYLING_SINCE_VERSION 1 +#define WL_TEXT_INPUT_PREEDIT_CURSOR_SINCE_VERSION 1 +#define WL_TEXT_INPUT_COMMIT_STRING_SINCE_VERSION 1 +#define WL_TEXT_INPUT_CURSOR_POSITION_SINCE_VERSION 1 +#define WL_TEXT_INPUT_DELETE_SURROUNDING_TEXT_SINCE_VERSION 1 +#define WL_TEXT_INPUT_KEYSYM_SINCE_VERSION 1 +#define WL_TEXT_INPUT_LANGUAGE_SINCE_VERSION 1 +#define WL_TEXT_INPUT_TEXT_DIRECTION_SINCE_VERSION 1 + +static inline void +wl_text_input_send_enter(struct wl_resource *resource_, struct wl_resource *surface) +{ + wl_resource_post_event(resource_, WL_TEXT_INPUT_ENTER, surface); +} + +static inline void +wl_text_input_send_leave(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, WL_TEXT_INPUT_LEAVE); +} + +static inline void +wl_text_input_send_modifiers_map(struct wl_resource *resource_, struct wl_array *map) +{ + wl_resource_post_event(resource_, WL_TEXT_INPUT_MODIFIERS_MAP, map); +} + +static inline void +wl_text_input_send_input_panel_state(struct wl_resource *resource_, uint32_t state) +{ + wl_resource_post_event(resource_, WL_TEXT_INPUT_INPUT_PANEL_STATE, state); +} + +static inline void +wl_text_input_send_preedit_string(struct wl_resource *resource_, uint32_t serial, const char *text, const char *commit) +{ + wl_resource_post_event(resource_, WL_TEXT_INPUT_PREEDIT_STRING, serial, text, commit); +} + +static inline void +wl_text_input_send_preedit_styling(struct wl_resource *resource_, uint32_t index, uint32_t length, uint32_t style) +{ + wl_resource_post_event(resource_, WL_TEXT_INPUT_PREEDIT_STYLING, index, length, style); +} + +static inline void +wl_text_input_send_preedit_cursor(struct wl_resource *resource_, int32_t index) +{ + wl_resource_post_event(resource_, WL_TEXT_INPUT_PREEDIT_CURSOR, index); +} + +static inline void +wl_text_input_send_commit_string(struct wl_resource *resource_, uint32_t serial, const char *text) +{ + wl_resource_post_event(resource_, WL_TEXT_INPUT_COMMIT_STRING, serial, text); +} + +static inline void +wl_text_input_send_cursor_position(struct wl_resource *resource_, int32_t index, int32_t anchor) +{ + wl_resource_post_event(resource_, WL_TEXT_INPUT_CURSOR_POSITION, index, anchor); +} + +static inline void +wl_text_input_send_delete_surrounding_text(struct wl_resource *resource_, int32_t index, uint32_t length) +{ + wl_resource_post_event(resource_, WL_TEXT_INPUT_DELETE_SURROUNDING_TEXT, index, length); +} + +static inline void +wl_text_input_send_keysym(struct wl_resource *resource_, uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, uint32_t modifiers) +{ + wl_resource_post_event(resource_, WL_TEXT_INPUT_KEYSYM, serial, time, sym, state, modifiers); +} + +static inline void +wl_text_input_send_language(struct wl_resource *resource_, uint32_t serial, const char *language) +{ + wl_resource_post_event(resource_, WL_TEXT_INPUT_LANGUAGE, serial, language); +} + +static inline void +wl_text_input_send_text_direction(struct wl_resource *resource_, uint32_t serial, uint32_t direction) +{ + wl_resource_post_event(resource_, WL_TEXT_INPUT_TEXT_DIRECTION, serial, direction); +} + +/** + * wl_text_input_manager - text input manager + * @create_text_input: create text input + * + * A factory for text-input objects. This object is a global singleton. + */ +struct wl_text_input_manager_interface { + /** + * create_text_input - create text input + * @id: (none) + * + * Creates a new text-input object. + */ + void (*create_text_input)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id); +}; + + +#ifdef __cplusplus +} +#endif + +#endif