ecore_imf: Add support for wayland
authorJan Arne Petersen <jpetersen@openismus.com>
Wed, 17 Apr 2013 09:59:46 +0000 (11:59 +0200)
committerEduardo Lima (Etrunko) <eduardo.lima@intel.com>
Mon, 24 Jun 2013 19:14:14 +0000 (16:14 -0300)
Add an input method module supporting the Wayland input method protocol.

In v2:
 - Missing call to ecore_wl_shutdown() in im_module_shutdown()
 - Access the already stored 'wayland globals' with ecore_wl_globals_get()
 - Fixed compilation by adding -I(top_srcdir)/src/efl to CFLAGS
 - EFL formatting fixes

Signed-off-by: Eduardo Lima (Etrunko) <eduardo.lima@intel.com>
configure.ac
src/Makefile_Ecore_IMF.am
src/modules/ecore_imf/wayland/text-client-protocol.h [new file with mode: 0644]
src/modules/ecore_imf/wayland/text-protocol.c [new file with mode: 0644]
src/modules/ecore_imf/wayland/wayland_imcontext.c [new file with mode: 0644]
src/modules/ecore_imf/wayland/wayland_imcontext.h [new file with mode: 0644]
src/modules/ecore_imf/wayland/wayland_module.c [new file with mode: 0644]

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