wayland: Add wayland client
authorJan Arne Petersen <jan.petersen@kdab.com>
Tue, 13 Aug 2013 08:30:52 +0000 (10:30 +0200)
committerDaiki Ueno <ueno@unixuser.org>
Tue, 13 Aug 2013 08:30:52 +0000 (10:30 +0200)
This patch adds a new client which supports the Wayland input method
protocol.  Note that the support is disabled by default until the
input method protocol becomes official in the Wayland upstream.
Supply --enable-wayland to configure to try it.  Also, you will need
to set the executable path of ibus-wayland under the "input-method"
section of weston.ini, like this:

 [input-method]
 path=.../libexec/ibus-wayland

BUG=Issue#1617

Review URL: https://codereview.appspot.com/11320043
Patch from Jan Arne Petersen <jan.petersen@kdab.com>.

client/Makefile.am
client/wayland/Makefile.am [new file with mode: 0644]
client/wayland/README [new file with mode: 0644]
client/wayland/input-method-client-protocol.h [new file with mode: 0644]
client/wayland/input-method-protocol.c [new file with mode: 0644]
client/wayland/main.c [new file with mode: 0644]
configure.ac

index 0074b99..546ca13 100644 (file)
@@ -32,10 +32,15 @@ if ENABLE_XIM
 X11 = x11
 endif
 
+if ENABLE_WAYLAND
+WAYLAND = wayland
+endif
+
 SUBDIRS = \
        $(GTK2) \
        $(GTK3) \
        $(X11) \
+       $(WAYLAND) \
        $(NULL)
 
 -include $(top_srcdir)/git.mk
diff --git a/client/wayland/Makefile.am b/client/wayland/Makefile.am
new file mode 100644 (file)
index 0000000..67b104d
--- /dev/null
@@ -0,0 +1,62 @@
+# vim:set noet ts=4:
+#
+# ibus - The Input Bus
+#
+# Copyright (c) 2007-2013 Peng Huang <shawn.p.huang@gmail.com>
+# Copyright (c) 2007-2013 Red Hat, Inc.
+#
+# This library is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of the
+# License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 USA.
+
+libibus = $(top_builddir)/src/libibus-@IBUS_API_VERSION@.la
+
+libexec_PROGRAMS = ibus-wayland
+
+protocol_sources = \
+       input-method-protocol.c \
+       input-method-client-protocol.h \
+       $(NULL)
+
+ibus_wayland_SOURCES = \
+       $(protocol_sources) \
+       main.c \
+       $(NULL)
+
+ibus_wayland_DEPENDENCIES = \
+       $(libibus) \
+       $(NULL)
+
+ibus_wayland_LDADD = \
+       $(libibus) \
+       $(GIO2_LIBS) \
+       $(WAYLAND_LIBS) \
+       $(NULL)
+
+ibus_wayland_CFLAGS = \
+       $(GIO2_CFLAGS) \
+       $(WAYLAND_CFLAGS) \
+       -I$(top_srcdir)/src \
+       -I$(top_builddir)/src \
+       $(NULL)
+
+$(libibus):
+       (cd $(top_builddir)/src; make)
+
+EXTRA_DIST = \
+       README \
+       $(protocol_sources) \
+       $(NULL)
+
+-include $(top_srcdir)/git.mk
diff --git a/client/wayland/README b/client/wayland/README
new file mode 100644 (file)
index 0000000..e5b42f6
--- /dev/null
@@ -0,0 +1,17 @@
+The following two files are generated with wayland-scanner:
+
+input-method-protocol.c
+input-method-client-protocol.h
+
+We include them in the distribution instead of generating them, since
+the Wayland protocol structure will unlikely change.  Do not modify
+those files manually.
+
+To generate them, use the wayland-scanner command as follows.  You can
+find input-method.xml in the Weston source code (maybe it will be
+moved to the Wayland source code later).
+
+$ wayland-scanner code < input-method.xml \
+  > input-method-protocol.c
+$ wayland-scanner client-header < input-method.xml \
+  > input-method-client-protocol.h
diff --git a/client/wayland/input-method-client-protocol.h b/client/wayland/input-method-client-protocol.h
new file mode 100644 (file)
index 0000000..05d03a3
--- /dev/null
@@ -0,0 +1,419 @@
+/* 
+ * 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_CLIENT_PROTOCOL_H
+#define INPUT_METHOD_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_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
+ * @surrounding_text: surrounding text event
+ * @reset: (none)
+ * @content_type: (none)
+ * @invoke_action: (none)
+ * @commit_state: (none)
+ * @preferred_language: (none)
+ *
+ * Corresponds to a text model on input method side. An input method
+ * context is created on text mode 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_listener {
+       /**
+        * surrounding_text - surrounding text event
+        * @text: (none)
+        * @cursor: (none)
+        * @anchor: (none)
+        *
+        * The plain surrounding text around the input position. Cursor
+        * is the position in bytes within the surrounding text relative to
+        * the beginning of the text. Anchor is the position in bytes of
+        * the selection anchor within the surrounding text relative to the
+        * beginning of the text. If there is no selected text anchor is
+        * the same as cursor.
+        */
+       void (*surrounding_text)(void *data,
+                                struct wl_input_method_context *wl_input_method_context,
+                                const char *text,
+                                uint32_t cursor,
+                                uint32_t anchor);
+       /**
+        * reset - (none)
+        */
+       void (*reset)(void *data,
+                     struct wl_input_method_context *wl_input_method_context);
+       /**
+        * content_type - (none)
+        * @hint: (none)
+        * @purpose: (none)
+        */
+       void (*content_type)(void *data,
+                            struct wl_input_method_context *wl_input_method_context,
+                            uint32_t hint,
+                            uint32_t purpose);
+       /**
+        * invoke_action - (none)
+        * @button: (none)
+        * @index: (none)
+        */
+       void (*invoke_action)(void *data,
+                             struct wl_input_method_context *wl_input_method_context,
+                             uint32_t button,
+                             uint32_t index);
+       /**
+        * commit_state - (none)
+        * @serial: serial of text input state
+        */
+       void (*commit_state)(void *data,
+                            struct wl_input_method_context *wl_input_method_context,
+                            uint32_t serial);
+       /**
+        * preferred_language - (none)
+        * @language: (none)
+        */
+       void (*preferred_language)(void *data,
+                                  struct wl_input_method_context *wl_input_method_context,
+                                  const char *language);
+};
+
+static inline int
+wl_input_method_context_add_listener(struct wl_input_method_context *wl_input_method_context,
+                                    const struct wl_input_method_context_listener *listener, void *data)
+{
+       return wl_proxy_add_listener((struct wl_proxy *) wl_input_method_context,
+                                    (void (**)(void)) listener, data);
+}
+
+#define WL_INPUT_METHOD_CONTEXT_DESTROY        0
+#define WL_INPUT_METHOD_CONTEXT_COMMIT_STRING  1
+#define WL_INPUT_METHOD_CONTEXT_PREEDIT_STRING 2
+#define WL_INPUT_METHOD_CONTEXT_PREEDIT_STYLING        3
+#define WL_INPUT_METHOD_CONTEXT_PREEDIT_CURSOR 4
+#define WL_INPUT_METHOD_CONTEXT_DELETE_SURROUNDING_TEXT        5
+#define WL_INPUT_METHOD_CONTEXT_CURSOR_POSITION        6
+#define WL_INPUT_METHOD_CONTEXT_MODIFIERS_MAP  7
+#define WL_INPUT_METHOD_CONTEXT_KEYSYM 8
+#define WL_INPUT_METHOD_CONTEXT_GRAB_KEYBOARD  9
+#define WL_INPUT_METHOD_CONTEXT_KEY    10
+#define WL_INPUT_METHOD_CONTEXT_MODIFIERS      11
+#define WL_INPUT_METHOD_CONTEXT_LANGUAGE       12
+#define WL_INPUT_METHOD_CONTEXT_TEXT_DIRECTION 13
+
+static inline void
+wl_input_method_context_set_user_data(struct wl_input_method_context *wl_input_method_context, void *user_data)
+{
+       wl_proxy_set_user_data((struct wl_proxy *) wl_input_method_context, user_data);
+}
+
+static inline void *
+wl_input_method_context_get_user_data(struct wl_input_method_context *wl_input_method_context)
+{
+       return wl_proxy_get_user_data((struct wl_proxy *) wl_input_method_context);
+}
+
+static inline void
+wl_input_method_context_destroy(struct wl_input_method_context *wl_input_method_context)
+{
+       wl_proxy_marshal((struct wl_proxy *) wl_input_method_context,
+                        WL_INPUT_METHOD_CONTEXT_DESTROY);
+
+       wl_proxy_destroy((struct wl_proxy *) wl_input_method_context);
+}
+
+static inline void
+wl_input_method_context_commit_string(struct wl_input_method_context *wl_input_method_context, uint32_t serial, const char *text)
+{
+       wl_proxy_marshal((struct wl_proxy *) wl_input_method_context,
+                        WL_INPUT_METHOD_CONTEXT_COMMIT_STRING, serial, text);
+}
+
+static inline void
+wl_input_method_context_preedit_string(struct wl_input_method_context *wl_input_method_context, uint32_t serial, const char *text, const char *commit)
+{
+       wl_proxy_marshal((struct wl_proxy *) wl_input_method_context,
+                        WL_INPUT_METHOD_CONTEXT_PREEDIT_STRING, serial, text, commit);
+}
+
+static inline void
+wl_input_method_context_preedit_styling(struct wl_input_method_context *wl_input_method_context, uint32_t index, uint32_t length, uint32_t style)
+{
+       wl_proxy_marshal((struct wl_proxy *) wl_input_method_context,
+                        WL_INPUT_METHOD_CONTEXT_PREEDIT_STYLING, index, length, style);
+}
+
+static inline void
+wl_input_method_context_preedit_cursor(struct wl_input_method_context *wl_input_method_context, int32_t index)
+{
+       wl_proxy_marshal((struct wl_proxy *) wl_input_method_context,
+                        WL_INPUT_METHOD_CONTEXT_PREEDIT_CURSOR, index);
+}
+
+static inline void
+wl_input_method_context_delete_surrounding_text(struct wl_input_method_context *wl_input_method_context, int32_t index, uint32_t length)
+{
+       wl_proxy_marshal((struct wl_proxy *) wl_input_method_context,
+                        WL_INPUT_METHOD_CONTEXT_DELETE_SURROUNDING_TEXT, index, length);
+}
+
+static inline void
+wl_input_method_context_cursor_position(struct wl_input_method_context *wl_input_method_context, int32_t index, int32_t anchor)
+{
+       wl_proxy_marshal((struct wl_proxy *) wl_input_method_context,
+                        WL_INPUT_METHOD_CONTEXT_CURSOR_POSITION, index, anchor);
+}
+
+static inline void
+wl_input_method_context_modifiers_map(struct wl_input_method_context *wl_input_method_context, struct wl_array *map)
+{
+       wl_proxy_marshal((struct wl_proxy *) wl_input_method_context,
+                        WL_INPUT_METHOD_CONTEXT_MODIFIERS_MAP, map);
+}
+
+static inline void
+wl_input_method_context_keysym(struct wl_input_method_context *wl_input_method_context, uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, uint32_t modifiers)
+{
+       wl_proxy_marshal((struct wl_proxy *) wl_input_method_context,
+                        WL_INPUT_METHOD_CONTEXT_KEYSYM, serial, time, sym, state, modifiers);
+}
+
+static inline struct wl_keyboard *
+wl_input_method_context_grab_keyboard(struct wl_input_method_context *wl_input_method_context)
+{
+       struct wl_proxy *keyboard;
+
+       keyboard = wl_proxy_create((struct wl_proxy *) wl_input_method_context,
+                            &wl_keyboard_interface);
+       if (!keyboard)
+               return NULL;
+
+       wl_proxy_marshal((struct wl_proxy *) wl_input_method_context,
+                        WL_INPUT_METHOD_CONTEXT_GRAB_KEYBOARD, keyboard);
+
+       return (struct wl_keyboard *) keyboard;
+}
+
+static inline void
+wl_input_method_context_key(struct wl_input_method_context *wl_input_method_context, uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
+{
+       wl_proxy_marshal((struct wl_proxy *) wl_input_method_context,
+                        WL_INPUT_METHOD_CONTEXT_KEY, serial, time, key, state);
+}
+
+static inline void
+wl_input_method_context_modifiers(struct wl_input_method_context *wl_input_method_context, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
+{
+       wl_proxy_marshal((struct wl_proxy *) wl_input_method_context,
+                        WL_INPUT_METHOD_CONTEXT_MODIFIERS, serial, mods_depressed, mods_latched, mods_locked, group);
+}
+
+static inline void
+wl_input_method_context_language(struct wl_input_method_context *wl_input_method_context, uint32_t serial, const char *language)
+{
+       wl_proxy_marshal((struct wl_proxy *) wl_input_method_context,
+                        WL_INPUT_METHOD_CONTEXT_LANGUAGE, serial, language);
+}
+
+static inline void
+wl_input_method_context_text_direction(struct wl_input_method_context *wl_input_method_context, uint32_t serial, uint32_t direction)
+{
+       wl_proxy_marshal((struct wl_proxy *) wl_input_method_context,
+                        WL_INPUT_METHOD_CONTEXT_TEXT_DIRECTION, serial, direction);
+}
+
+/**
+ * wl_input_method - input method
+ * @activate: activate event
+ * @deactivate: activate event
+ *
+ * An input method object is responsible to compose text in response to
+ * input from hardware or virtual keyboards. There is one input method
+ * object per seat. On activate there is a new input method context object
+ * created which allows the input method to communicate with the text
+ * model.
+ */
+struct wl_input_method_listener {
+       /**
+        * activate - activate event
+        * @id: (none)
+        *
+        * A text model was activated. Creates an input method context
+        * object which allows communication with the text model.
+        */
+       void (*activate)(void *data,
+                        struct wl_input_method *wl_input_method,
+                        struct wl_input_method_context *id);
+       /**
+        * deactivate - activate event
+        * @context: (none)
+        *
+        * The text model corresponding to the context argument was
+        * deactivated. The input method context should be destroyed after
+        * deactivation is handled.
+        */
+       void (*deactivate)(void *data,
+                          struct wl_input_method *wl_input_method,
+                          struct wl_input_method_context *context);
+};
+
+static inline int
+wl_input_method_add_listener(struct wl_input_method *wl_input_method,
+                            const struct wl_input_method_listener *listener, void *data)
+{
+       return wl_proxy_add_listener((struct wl_proxy *) wl_input_method,
+                                    (void (**)(void)) listener, data);
+}
+
+static inline void
+wl_input_method_set_user_data(struct wl_input_method *wl_input_method, void *user_data)
+{
+       wl_proxy_set_user_data((struct wl_proxy *) wl_input_method, user_data);
+}
+
+static inline void *
+wl_input_method_get_user_data(struct wl_input_method *wl_input_method)
+{
+       return wl_proxy_get_user_data((struct wl_proxy *) wl_input_method);
+}
+
+static inline void
+wl_input_method_destroy(struct wl_input_method *wl_input_method)
+{
+       wl_proxy_destroy((struct wl_proxy *) wl_input_method);
+}
+
+#define WL_INPUT_PANEL_GET_INPUT_PANEL_SURFACE 0
+
+static inline void
+wl_input_panel_set_user_data(struct wl_input_panel *wl_input_panel, void *user_data)
+{
+       wl_proxy_set_user_data((struct wl_proxy *) wl_input_panel, user_data);
+}
+
+static inline void *
+wl_input_panel_get_user_data(struct wl_input_panel *wl_input_panel)
+{
+       return wl_proxy_get_user_data((struct wl_proxy *) wl_input_panel);
+}
+
+static inline void
+wl_input_panel_destroy(struct wl_input_panel *wl_input_panel)
+{
+       wl_proxy_destroy((struct wl_proxy *) wl_input_panel);
+}
+
+static inline struct wl_input_panel_surface *
+wl_input_panel_get_input_panel_surface(struct wl_input_panel *wl_input_panel, struct wl_surface *surface)
+{
+       struct wl_proxy *id;
+
+       id = wl_proxy_create((struct wl_proxy *) wl_input_panel,
+                            &wl_input_panel_surface_interface);
+       if (!id)
+               return NULL;
+
+       wl_proxy_marshal((struct wl_proxy *) wl_input_panel,
+                        WL_INPUT_PANEL_GET_INPUT_PANEL_SURFACE, id, surface);
+
+       return (struct wl_input_panel_surface *) id;
+}
+
+#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 */
+
+#define WL_INPUT_PANEL_SURFACE_SET_TOPLEVEL    0
+#define WL_INPUT_PANEL_SURFACE_SET_OVERLAY_PANEL       1
+
+static inline void
+wl_input_panel_surface_set_user_data(struct wl_input_panel_surface *wl_input_panel_surface, void *user_data)
+{
+       wl_proxy_set_user_data((struct wl_proxy *) wl_input_panel_surface, user_data);
+}
+
+static inline void *
+wl_input_panel_surface_get_user_data(struct wl_input_panel_surface *wl_input_panel_surface)
+{
+       return wl_proxy_get_user_data((struct wl_proxy *) wl_input_panel_surface);
+}
+
+static inline void
+wl_input_panel_surface_destroy(struct wl_input_panel_surface *wl_input_panel_surface)
+{
+       wl_proxy_destroy((struct wl_proxy *) wl_input_panel_surface);
+}
+
+static inline void
+wl_input_panel_surface_set_toplevel(struct wl_input_panel_surface *wl_input_panel_surface, struct wl_output *output, uint32_t position)
+{
+       wl_proxy_marshal((struct wl_proxy *) wl_input_panel_surface,
+                        WL_INPUT_PANEL_SURFACE_SET_TOPLEVEL, output, position);
+}
+
+static inline void
+wl_input_panel_surface_set_overlay_panel(struct wl_input_panel_surface *wl_input_panel_surface)
+{
+       wl_proxy_marshal((struct wl_proxy *) wl_input_panel_surface,
+                        WL_INPUT_PANEL_SURFACE_SET_OVERLAY_PANEL);
+}
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/client/wayland/input-method-protocol.c b/client/wayland/input-method-protocol.c
new file mode 100644 (file)
index 0000000..7bd5a9a
--- /dev/null
@@ -0,0 +1,115 @@
+/* 
+ * 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_keyboard_interface;
+extern const struct wl_interface wl_input_method_context_interface;
+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_surface_interface;
+extern const struct wl_interface wl_output_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/client/wayland/main.c b/client/wayland/main.c
new file mode 100644 (file)
index 0000000..7a7490b
--- /dev/null
@@ -0,0 +1,755 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/* vim:set et sts=4: */
+/* ibus - The Input Bus
+ * Copyright (C) 2013 Intel Corporation
+ * Copyright (C) 2013 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <ibus.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wayland-client.h>
+#include <xkbcommon/xkbcommon.h>
+
+#include "input-method-client-protocol.h"
+
+struct _IBusWaylandIM
+{
+    struct wl_input_method *input_method;
+    struct wl_input_method_context *context;
+    struct wl_keyboard *keyboard;
+
+    IBusInputContext *ibuscontext;
+    IBusText *preedit_text;
+    guint preedit_cursor_pos;
+    IBusModifierType modifiers;
+
+    struct xkb_context *xkb_context;
+
+    struct xkb_keymap *keymap;
+    struct xkb_state *state;
+
+    xkb_mod_mask_t shift_mask;
+    xkb_mod_mask_t lock_mask;
+    xkb_mod_mask_t control_mask;
+    xkb_mod_mask_t mod1_mask;
+    xkb_mod_mask_t mod2_mask;
+    xkb_mod_mask_t mod3_mask;
+    xkb_mod_mask_t mod4_mask;
+    xkb_mod_mask_t mod5_mask;
+    xkb_mod_mask_t super_mask;
+    xkb_mod_mask_t hyper_mask;
+    xkb_mod_mask_t meta_mask;
+
+    uint32_t serial;
+
+    GCancellable *cancellable;
+};
+typedef struct _IBusWaylandIM IBusWaylandIM;
+
+struct _IBusWaylandKeyEvent
+{
+    struct wl_input_method_context *context;
+    uint32_t serial;
+    uint32_t time;
+    uint32_t key;
+    enum wl_keyboard_key_state state;
+};
+typedef struct _IBusWaylandKeyEvent IBusWaylandKeyEvent;
+
+struct _IBusWaylandSource
+{
+    GSource source;
+    GPollFD pfd;
+    uint32_t mask;
+    struct wl_display *display;
+};
+typedef struct _IBusWaylandSource IBusWaylandSource;
+
+struct wl_display *_display = NULL;
+struct wl_registry *_registry = NULL;
+static IBusBus *_bus = NULL;
+
+static gboolean _use_sync_mode = FALSE;
+
+static gboolean
+_get_boolean_env (const gchar *name,
+                  gboolean     defval)
+{
+    const gchar *value = g_getenv (name);
+
+    if (value == NULL)
+      return defval;
+
+    if (g_strcmp0 (value, "") == 0 ||
+        g_strcmp0 (value, "0") == 0 ||
+        g_strcmp0 (value, "false") == 0 ||
+        g_strcmp0 (value, "False") == 0 ||
+        g_strcmp0 (value, "FALSE") == 0)
+      return FALSE;
+
+    return TRUE;
+}
+
+static gboolean
+ibus_wayland_source_prepare (GSource *base,
+                             gint    *timeout)
+{
+    IBusWaylandSource *source = (IBusWaylandSource *) base;
+
+    *timeout = -1;
+
+    wl_display_flush (source->display);
+
+    return FALSE;
+}
+
+static gboolean
+ibus_wayland_source_check (GSource *base)
+{
+    IBusWaylandSource *source = (IBusWaylandSource *) base;
+
+    if (source->pfd.revents & (G_IO_ERR | G_IO_HUP))
+        g_error ("Lost connection to wayland compositor");
+
+    return source->pfd.revents;
+}
+
+static gboolean
+ibus_wayland_source_dispatch (GSource    *base,
+                              GSourceFunc callback,
+                              gpointer    data)
+{
+    IBusWaylandSource *source = (IBusWaylandSource *) base;
+
+    if (source->pfd.revents) {
+        wl_display_dispatch (source->display);
+        source->pfd.revents = 0;
+    }
+
+    return TRUE;
+}
+
+static void
+ibus_wayland_source_finalize (GSource *source)
+{
+}
+
+static GSourceFuncs ibus_wayland_source_funcs = {
+    ibus_wayland_source_prepare,
+    ibus_wayland_source_check,
+    ibus_wayland_source_dispatch,
+    ibus_wayland_source_finalize
+};
+
+GSource *
+ibus_wayland_source_new (struct wl_display *display)
+{
+    GSource *source;
+    IBusWaylandSource *wlsource;
+
+    source = g_source_new (&ibus_wayland_source_funcs,
+                           sizeof (IBusWaylandSource));
+    wlsource = (IBusWaylandSource *) source;
+
+    wlsource->display = display;
+    wlsource->pfd.fd = wl_display_get_fd (display);
+    wlsource->pfd.events = G_IO_IN | G_IO_ERR | G_IO_HUP;
+    g_source_add_poll (source, &wlsource->pfd);
+
+    return source;
+}
+
+static void
+_context_commit_text_cb (IBusInputContext *context,
+                         IBusText         *text,
+                         IBusWaylandIM    *wlim)
+{
+    wl_input_method_context_commit_string (wlim->context,
+                                           wlim->serial,
+                                           text->text);
+}
+
+static void
+_context_forward_key_event_cb (IBusInputContext *context,
+                               guint             keyval,
+                               guint             keycode,
+                               guint             modifiers,
+                               IBusWaylandIM    *wlim)
+{
+    uint32_t state;
+
+    if (modifiers & IBUS_RELEASE_MASK)
+        state = WL_KEYBOARD_KEY_STATE_RELEASED;
+    else
+        state = WL_KEYBOARD_KEY_STATE_PRESSED;
+
+    wl_input_method_context_keysym (wlim->context,
+                                    wlim->serial,
+                                    0,
+                                    keyval,
+                                    state,
+                                    modifiers);
+}
+
+static void
+_context_show_preedit_text_cb (IBusInputContext *context,
+                               IBusWaylandIM    *wlim)
+{
+    /* CURSOR is byte offset.  */
+    uint32_t cursor =
+        g_utf8_offset_to_pointer (wlim->preedit_text->text,
+                                  wlim->preedit_cursor_pos) -
+        wlim->preedit_text->text;
+
+    wl_input_method_context_preedit_cursor (wlim->context,
+                                            cursor);
+    wl_input_method_context_preedit_string (wlim->context,
+                                            wlim->serial,
+                                            wlim->preedit_text->text,
+                                            wlim->preedit_text->text);
+}
+
+static void
+_context_hide_preedit_text_cb (IBusInputContext *context,
+                               IBusWaylandIM    *wlim)
+{
+    wl_input_method_context_preedit_string (wlim->context,
+                                            wlim->serial,
+                                            "",
+                                            "");
+}
+
+static void
+_context_update_preedit_text_cb (IBusInputContext *context,
+                                 IBusText         *text,
+                                 gint              cursor_pos,
+                                 gboolean          visible,
+                                 IBusWaylandIM    *wlim)
+{
+    if (wlim->preedit_text)
+        g_object_unref (wlim->preedit_text);
+    wlim->preedit_text = g_object_ref_sink (text);
+    wlim->preedit_cursor_pos = cursor_pos;
+
+    if (visible)
+        _context_show_preedit_text_cb (context, wlim);
+    else
+        _context_hide_preedit_text_cb (context, wlim);
+}
+
+static void
+handle_surrounding_text (void                           *data,
+                         struct wl_input_method_context *context,
+                         const char                     *text,
+                         uint32_t                        cursor,
+                         uint32_t                        anchor)
+{
+#if ENABLE_SURROUNDING
+    IBusWaylandIM *wlim = data;
+
+    if (wlim->ibuscontext != NULL &&
+        ibus_input_context_needs_surrounding_text (wlim->ibuscontext)) {
+        /* CURSOR_POS and ANCHOR_POS are character offset.  */
+        guint cursor_pos = g_utf8_pointer_to_offset (text, text + cursor);
+        guint anchor_pos = g_utf8_pointer_to_offset (text, text + anchor);
+        IBusText *ibustext = ibus_text_new_from_string (text);
+
+        ibus_input_context_set_surrounding_text (wlim->ibuscontext,
+                                                 ibustext,
+                                                 cursor_pos,
+                                                 anchor_pos);
+    }
+#endif
+}
+
+static void
+handle_reset (void                           *data,
+              struct wl_input_method_context *context)
+{
+}
+
+static void
+handle_content_type (void                           *data,
+                     struct wl_input_method_context *context,
+                     uint32_t                        hint,
+                     uint32_t                        purpose)
+{
+}
+
+static void
+handle_invoke_action (void                           *data,
+                      struct wl_input_method_context *context,
+                      uint32_t                        button,
+                      uint32_t                        index)
+{
+}
+
+static void
+handle_commit_state (void                           *data,
+                     struct wl_input_method_context *context,
+                     uint32_t                        serial)
+{
+    IBusWaylandIM *wlim = data;
+
+    wlim->serial = serial;
+}
+
+static void
+handle_preferred_language (void                           *data,
+                           struct wl_input_method_context *context,
+                           const char                     *language)
+{
+}
+
+static const struct wl_input_method_context_listener context_listener = {
+    handle_surrounding_text,
+    handle_reset,
+    handle_content_type,
+    handle_invoke_action,
+    handle_commit_state,
+    handle_preferred_language
+};
+
+static void
+input_method_keyboard_keymap (void               *data,
+                              struct wl_keyboard *wl_keyboard,
+                              uint32_t            format,
+                              int32_t             fd,
+                              uint32_t            size)
+{
+    IBusWaylandIM *wlim = data;
+    GMappedFile *map;
+    GError *error;
+
+    if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
+        close(fd);
+        return;
+    }
+
+    error = NULL;
+    map = g_mapped_file_new_from_fd (fd, FALSE, &error);
+    if (map == NULL) {
+        close (fd);
+        return;
+    }
+
+    wlim->keymap =
+        xkb_map_new_from_string (wlim->xkb_context,
+                                 g_mapped_file_get_contents (map),
+                                 XKB_KEYMAP_FORMAT_TEXT_V1,
+                                 0);
+
+    g_mapped_file_unref (map);
+    close(fd);
+
+    if (!wlim->keymap) {
+        return;
+    }
+
+    wlim->state = xkb_state_new (wlim->keymap);
+    if (!wlim->state) {
+        xkb_map_unref (wlim->keymap);
+        return;
+    }
+
+    wlim->shift_mask =
+        1 << xkb_map_mod_get_index (wlim->keymap, "Shift");
+    wlim->lock_mask =
+        1 << xkb_map_mod_get_index (wlim->keymap, "Lock");
+    wlim->control_mask =
+        1 << xkb_map_mod_get_index (wlim->keymap, "Control");
+    wlim->mod1_mask =
+        1 << xkb_map_mod_get_index (wlim->keymap, "Mod1");
+    wlim->mod2_mask =
+        1 << xkb_map_mod_get_index (wlim->keymap, "Mod2");
+    wlim->mod3_mask =
+        1 << xkb_map_mod_get_index (wlim->keymap, "Mod3");
+    wlim->mod4_mask =
+        1 << xkb_map_mod_get_index (wlim->keymap, "Mod4");
+    wlim->mod5_mask =
+        1 << xkb_map_mod_get_index (wlim->keymap, "Mod5");
+    wlim->super_mask =
+        1 << xkb_map_mod_get_index (wlim->keymap, "Super");
+    wlim->hyper_mask =
+        1 << xkb_map_mod_get_index (wlim->keymap, "Hyper");
+    wlim->meta_mask =
+        1 << xkb_map_mod_get_index (wlim->keymap, "Meta");
+}
+
+static void
+_process_key_event_done (GObject      *object,
+                         GAsyncResult *res,
+                         gpointer      user_data)
+{
+    IBusInputContext *context = (IBusInputContext *)object;
+    IBusWaylandKeyEvent *event = (IBusWaylandKeyEvent *) user_data;
+
+    GError *error = NULL;
+    gboolean retval = ibus_input_context_process_key_event_async_finish (
+            context,
+            res,
+            &error);
+
+    if (error != NULL) {
+        g_warning ("Process Key Event failed: %s.", error->message);
+        g_error_free (error);
+    }
+
+    if (!retval) {
+        wl_input_method_context_key (event->context,
+                                     event->serial,
+                                     event->time,
+                                     event->key,
+                                     event->state);
+    }
+
+    g_free (event);
+}
+
+static void
+input_method_keyboard_key (void               *data,
+                           struct wl_keyboard *wl_keyboard,
+                           uint32_t            serial,
+                           uint32_t            time,
+                           uint32_t            key,
+                           uint32_t            state)
+{
+    IBusWaylandIM *wlim = data;
+    uint32_t code;
+    uint32_t num_syms;
+    const xkb_keysym_t *syms;
+    xkb_keysym_t sym;
+    guint32 modifiers;
+
+    if (!wlim->state)
+        return;
+
+    if (!wlim->ibuscontext) {
+        wl_input_method_context_key (wlim->context,
+                                     serial,
+                                     time,
+                                     key,
+                                     state);
+        return;
+    }
+        
+    code = key + 8;
+    num_syms = xkb_key_get_syms (wlim->state, code, &syms);
+
+    sym = XKB_KEY_NoSymbol;
+    if (num_syms == 1)
+        sym = syms[0];
+
+    modifiers = wlim->modifiers;
+    if (state == WL_KEYBOARD_KEY_STATE_RELEASED)
+        modifiers |= IBUS_RELEASE_MASK;
+
+    if (_use_sync_mode) {
+        gboolean retval =
+            ibus_input_context_process_key_event (wlim->ibuscontext,
+                                                  sym,
+                                                  code,
+                                                  modifiers);
+        if (!retval) {
+            wl_input_method_context_key (wlim->context,
+                                         serial,
+                                         time,
+                                         key,
+                                         state);
+        }
+    } else {
+        IBusWaylandKeyEvent *event = g_new (IBusWaylandKeyEvent, 1);
+        event->context = wlim->context;
+        event->serial = serial;
+        event->time = time;
+        event->key = key;
+        event->state = state;
+        ibus_input_context_process_key_event_async (wlim->ibuscontext,
+                                                    sym,
+                                                    code,
+                                                    modifiers,
+                                                    -1,
+                                                    NULL,
+                                                    _process_key_event_done,
+                                                    event);
+    }
+}
+
+static void
+input_method_keyboard_modifiers (void               *data,
+                                 struct wl_keyboard *wl_keyboard,
+                                 uint32_t            serial,
+                                 uint32_t            mods_depressed,
+                                 uint32_t            mods_latched,
+                                 uint32_t            mods_locked,
+                                 uint32_t            group)
+{
+    IBusWaylandIM *wlim = data;
+    struct wl_input_method_context *context = wlim->context;
+    xkb_mod_mask_t mask;
+
+    xkb_state_update_mask (wlim->state, mods_depressed,
+                           mods_latched, mods_locked, 0, 0, group);
+    mask = xkb_state_serialize_mods (wlim->state,
+                                     XKB_STATE_DEPRESSED |
+                                     XKB_STATE_LATCHED);
+
+    wlim->modifiers = 0;
+    if (mask & wlim->shift_mask)
+        wlim->modifiers |= IBUS_SHIFT_MASK;
+    if (mask & wlim->lock_mask)
+        wlim->modifiers |= IBUS_LOCK_MASK;
+    if (mask & wlim->control_mask)
+        wlim->modifiers |= IBUS_CONTROL_MASK;
+    if (mask & wlim->mod1_mask)
+        wlim->modifiers |= IBUS_MOD1_MASK;
+    if (mask & wlim->mod2_mask)
+        wlim->modifiers |= IBUS_MOD2_MASK;
+    if (mask & wlim->mod3_mask)
+        wlim->modifiers |= IBUS_MOD3_MASK;
+    if (mask & wlim->mod4_mask)
+        wlim->modifiers |= IBUS_MOD4_MASK;
+    if (mask & wlim->mod5_mask)
+        wlim->modifiers |= IBUS_MOD5_MASK;
+    if (mask & wlim->super_mask)
+        wlim->modifiers |= IBUS_SUPER_MASK;
+    if (mask & wlim->hyper_mask)
+        wlim->modifiers |= IBUS_HYPER_MASK;
+    if (mask & wlim->meta_mask)
+        wlim->modifiers |= IBUS_META_MASK;
+
+    wl_input_method_context_modifiers (context, serial,
+                                       mods_depressed, mods_depressed,
+                                       mods_latched, group);
+}
+
+static const struct wl_keyboard_listener keyboard_listener = {
+    input_method_keyboard_keymap,
+    NULL, /* enter */
+    NULL, /* leave */
+    input_method_keyboard_key,
+    input_method_keyboard_modifiers
+};
+
+static void
+_create_input_context_done (GObject      *object,
+                            GAsyncResult *res,
+                            gpointer      user_data)
+{
+    IBusWaylandIM *wlim = (IBusWaylandIM *) user_data;
+
+    GError *error = NULL;
+    IBusInputContext *context = ibus_bus_create_input_context_async_finish (
+            _bus, res, &error);
+
+    if (wlim->cancellable != NULL) {
+        g_object_unref (wlim->cancellable);
+        wlim->cancellable = NULL;
+    }
+
+    if (context == NULL) {
+        g_warning ("Create input context failed: %s.", error->message);
+        g_error_free (error);
+    }
+    else {
+        wlim->ibuscontext = context;
+
+        g_signal_connect (wlim->ibuscontext, "commit-text",
+                          G_CALLBACK (_context_commit_text_cb),
+                          wlim);
+        g_signal_connect (wlim->ibuscontext, "forward-key-event",
+                          G_CALLBACK (_context_forward_key_event_cb),
+                          wlim);
+
+        g_signal_connect (wlim->ibuscontext, "update-preedit-text",
+                          G_CALLBACK (_context_update_preedit_text_cb),
+                          wlim);
+        g_signal_connect (wlim->ibuscontext, "show-preedit-text",
+                          G_CALLBACK (_context_show_preedit_text_cb),
+                          wlim);
+        g_signal_connect (wlim->ibuscontext, "hide-preedit-text",
+                          G_CALLBACK (_context_hide_preedit_text_cb),
+                          wlim);
+    
+#ifdef ENABLE_SURROUNDING
+        ibus_input_context_set_capabilities (wlim->ibuscontext,
+                                             IBUS_CAP_FOCUS |
+                                             IBUS_CAP_PREEDIT_TEXT |
+                                             IBUS_CAP_SURROUNDING_TEXT);
+#else
+        ibus_input_context_set_capabilities (wlim->ibuscontext,
+                                             IBUS_CAP_FOCUS |
+                                             IBUS_CAP_PREEDIT_TEXT);
+#endif
+
+        ibus_input_context_focus_in (wlim->ibuscontext);
+    }
+}
+
+static void
+input_method_activate (void                           *data,
+                       struct wl_input_method         *input_method,
+                       struct wl_input_method_context *context)
+{
+    IBusWaylandIM *wlim = data;
+
+    if (wlim->context) {
+        wl_input_method_context_destroy (wlim->context);
+        wlim->context = NULL;
+    }
+
+    wlim->serial = 0;
+    wlim->context = context;
+
+    wl_input_method_context_add_listener (context, &context_listener, wlim);
+    wlim->keyboard = wl_input_method_context_grab_keyboard (context);
+    wl_keyboard_add_listener(wlim->keyboard,
+                             &keyboard_listener,
+                             wlim);
+
+    if (wlim->ibuscontext) {
+        g_object_unref (wlim->ibuscontext);
+        wlim->ibuscontext = NULL;
+    }
+
+    wlim->cancellable = g_cancellable_new ();
+    ibus_bus_create_input_context_async (_bus,
+                                         "wayland",
+                                         -1,
+                                         wlim->cancellable,
+                                         _create_input_context_done,
+                                         wlim);
+}
+
+static void
+input_method_deactivate (void                           *data,
+                         struct wl_input_method         *input_method,
+                         struct wl_input_method_context *context)
+{
+    IBusWaylandIM *wlim = data;
+
+    if (wlim->cancellable) {
+        /* Cancel any ongoing create input context request.  */
+        g_cancellable_cancel (wlim->cancellable);
+        g_object_unref (wlim->cancellable);
+        wlim->cancellable = NULL;
+    }
+
+    if (wlim->ibuscontext) {
+        ibus_input_context_focus_out (wlim->ibuscontext);
+        g_object_unref (wlim->ibuscontext);
+        wlim->ibuscontext = NULL;
+    }
+
+    if (wlim->preedit_text) {
+        g_object_unref (wlim->preedit_text);
+        wlim->preedit_text = NULL;
+    }
+
+    if (wlim->context) {
+        wl_input_method_context_destroy (wlim->context);
+        wlim->context = NULL;
+    }
+}
+
+static const struct wl_input_method_listener input_method_listener = {
+    input_method_activate,
+    input_method_deactivate
+};
+
+static void
+registry_handle_global (void               *data,
+                        struct wl_registry *registry,
+                        uint32_t            name,
+                        const char         *interface,
+                        uint32_t            version)
+{
+    IBusWaylandIM *wlim = data;
+
+    if (!g_strcmp0 (interface, "wl_input_method")) {
+        wlim->input_method =
+            wl_registry_bind (registry, name, &wl_input_method_interface, 1);
+        wl_input_method_add_listener (wlim->input_method,
+                                      &input_method_listener, wlim);
+    }
+}
+
+static void
+registry_handle_global_remove (void               *data,
+                               struct wl_registry *registry,
+                               uint32_t            name)
+{
+}
+
+static const struct wl_registry_listener registry_listener = {
+    registry_handle_global,
+    registry_handle_global_remove
+};
+
+gint
+main (gint    argc,
+      gchar **argv)
+{
+    IBusWaylandIM wlim;
+    GSource *source;
+
+    ibus_init ();
+
+    _bus = ibus_bus_new ();
+    if (!ibus_bus_is_connected (_bus)) {
+        g_printerr ("Cannot connect to ibus-daemon\n");
+        return EXIT_FAILURE;
+    }
+
+    _display = wl_display_connect (NULL);
+    if (_display == NULL) {
+        g_printerr ("Failed to connect to Wayland server: %s\n",
+                    g_strerror (errno));
+        return EXIT_FAILURE;
+    }
+
+    _registry = wl_display_get_registry (_display);
+    memset (&wlim, 0, sizeof (wlim));
+    wl_registry_add_listener (_registry, &registry_listener, &wlim);
+    wl_display_roundtrip (_display);
+    if (wlim.input_method == NULL) {
+        g_printerr ("No input_method global\n");
+        return EXIT_FAILURE;
+    }
+
+    wlim.xkb_context = xkb_context_new (0);
+    if (wlim.xkb_context == NULL) {
+        g_printerr ("Failed to create XKB context\n");
+        return EXIT_FAILURE;
+    }
+
+    _use_sync_mode = _get_boolean_env ("IBUS_ENABLE_SYNC_MODE", FALSE);
+
+    source = ibus_wayland_source_new (_display);
+    g_source_set_priority (source, G_PRIORITY_DEFAULT);
+    g_source_set_can_recurse (source, TRUE);
+    g_source_attach (source, NULL);
+
+    ibus_main ();
+
+    return EXIT_SUCCESS;
+}
index 3e9996d..36515e2 100644 (file)
@@ -197,6 +197,15 @@ AC_ARG_ENABLE(xim,
 )
 AM_CONDITIONAL([ENABLE_XIM], [test x"$enable_xim" = x"yes"])
 
+# --enable-wayland option.
+AC_ARG_ENABLE(wayland,
+    AS_HELP_STRING([--enable-wayland],
+                   [Build wayland support]),
+    [enable_wayland=$enableval],
+    [enable_wayland=no]
+)
+AM_CONDITIONAL([ENABLE_WAYLAND], [test x"$enable_wayland" = x"yes"])
+
 if test x"$enable_gtk2" = x"yes" -o x"$enable_xim" = x"yes" ; then
     # check for gtk2
     PKG_CHECK_MODULES(GTK2, [
@@ -242,6 +251,16 @@ else
     enable_xim="no (disabled, use --enable-xim to enable)"
 fi
 
+if test x"$enable_wayland" = x"yes"; then
+    # Check for wayland
+    PKG_CHECK_MODULES(WAYLAND, [
+        wayland-client >= 1.2.0
+        xkbcommon
+    ])
+else
+    enable_wayland="no (disabled, use --enable-wayland to enable)"
+fi
+
 # GObject introspection
 GOBJECT_INTROSPECTION_CHECK([0.6.8])
 
@@ -534,6 +553,7 @@ client/Makefile
 client/gtk2/Makefile
 client/gtk3/Makefile
 client/x11/Makefile
+client/wayland/Makefile
 src/Makefile
 src/ibusversion.h
 src/tests/Makefile
@@ -580,6 +600,7 @@ Build options:
   Build gtk2 immodule       $enable_gtk2
   Build gtk3 immodule       $enable_gtk3
   Build XIM agent server    $enable_xim
+  Build wayland support     $enable_wayland
   Build python library      $enable_python_library
   Build gconf modules       $enable_gconf
   Build memconf modules     $enable_memconf