summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2017-12-06 12:43:14 +0100
committerCarlos Garnacho <carlosg@gnome.org>2018-01-18 15:35:29 +0100
commitaa6561a3b14e03902f725587cd71a6972a71af08 (patch)
treee455a268214e49064149051f986e562621e06f0f
parent9eb962328806005bc231df6c6d166bbd62803293 (diff)
downloadmutter-aa6561a3b14e03902f725587cd71a6972a71af08.tar.gz
clutter: Add ClutterInputMethod and ClutterInputFocus
ClutterInputFocus is an abstract object to be subclassed by UI actors and the wayland interface and represents the user of an input method. It represents the current focus of the input method, so all emitted signals and public API hooks are expected to be called when the input method is currently interfacing with the input focus. ClutterInputMethod is an abstract class (to be implemented in the upper layers) that represents the input method itself. Besides focus management itself, all public API calls that would be called by the subclasses are delivered through the current input focus.
-rw-r--r--clutter/clutter/Makefile.am6
-rw-r--r--clutter/clutter/clutter-enums.h35
-rw-r--r--clutter/clutter/clutter-input-focus-private.h40
-rw-r--r--clutter/clutter/clutter-input-focus.c243
-rw-r--r--clutter/clutter/clutter-input-focus.h83
-rw-r--r--clutter/clutter/clutter-input-method-private.h46
-rw-r--r--clutter/clutter/clutter-input-method.c442
-rw-r--r--clutter/clutter/clutter-input-method.h88
-rw-r--r--clutter/clutter/clutter-types.h1
-rw-r--r--clutter/clutter/clutter.h2
10 files changed, 986 insertions, 0 deletions
diff --git a/clutter/clutter/Makefile.am b/clutter/clutter/Makefile.am
index 8fbd99324..c4576c052 100644
--- a/clutter/clutter/Makefile.am
+++ b/clutter/clutter/Makefile.am
@@ -87,6 +87,8 @@ source_h = \
clutter-image.h \
clutter-input-device.h \
clutter-input-device-tool.h \
+ clutter-input-focus.h \
+ clutter-input-method.h \
clutter-interval.h \
clutter-keyframe-transition.h \
clutter-keysyms.h \
@@ -169,6 +171,8 @@ source_c = \
clutter-image.c \
clutter-input-device.c \
clutter-input-device-tool.c \
+ clutter-input-focus.c \
+ clutter-input-method.c \
clutter-virtual-input-device.c \
clutter-interval.c \
clutter-keyframe-transition.c \
@@ -229,6 +233,8 @@ source_h_priv = \
clutter-flatten-effect.h \
clutter-gesture-action-private.h \
clutter-id-pool.h \
+ clutter-input-focus-private.h \
+ clutter-input-method-private.h \
clutter-master-clock.h \
clutter-master-clock-default.h \
clutter-offscreen-effect-private.h \
diff --git a/clutter/clutter/clutter-enums.h b/clutter/clutter/clutter-enums.h
index a0450a5af..b9987d875 100644
--- a/clutter/clutter/clutter-enums.h
+++ b/clutter/clutter/clutter-enums.h
@@ -1574,6 +1574,41 @@ typedef enum {
CLUTTER_INPUT_DEVICE_MAPPING_RELATIVE,
} ClutterInputDeviceMapping;
+typedef enum {
+ CLUTTER_INPUT_CONTENT_HINT_COMPLETION = 1 << 0,
+ CLUTTER_INPUT_CONTENT_HINT_SPELLCHECK = 1 << 1,
+ CLUTTER_INPUT_CONTENT_HINT_AUTO_CAPITALIZATION = 1 << 2,
+ CLUTTER_INPUT_CONTENT_HINT_LOWERCASE = 1 << 3,
+ CLUTTER_INPUT_CONTENT_HINT_UPPERCASE = 1 << 4,
+ CLUTTER_INPUT_CONTENT_HINT_TITLECASE = 1 << 5,
+ CLUTTER_INPUT_CONTENT_HINT_HIDDEN_TEXT = 1 << 6,
+ CLUTTER_INPUT_CONTENT_HINT_SENSITIVE_DATA = 1 << 7,
+ CLUTTER_INPUT_CONTENT_HINT_LATIN = 1 << 8,
+ CLUTTER_INPUT_CONTENT_HINT_MULTILINE = 1 << 9,
+} ClutterInputContentHintFlags;
+
+typedef enum {
+ CLUTTER_INPUT_CONTENT_PURPOSE_NORMAL,
+ CLUTTER_INPUT_CONTENT_PURPOSE_ALPHA,
+ CLUTTER_INPUT_CONTENT_PURPOSE_DIGITS,
+ CLUTTER_INPUT_CONTENT_PURPOSE_NUMBER,
+ CLUTTER_INPUT_CONTENT_PURPOSE_PHONE,
+ CLUTTER_INPUT_CONTENT_PURPOSE_URL,
+ CLUTTER_INPUT_CONTENT_PURPOSE_EMAIL,
+ CLUTTER_INPUT_CONTENT_PURPOSE_NAME,
+ CLUTTER_INPUT_CONTENT_PURPOSE_PASSWORD,
+ CLUTTER_INPUT_CONTENT_PURPOSE_DATE,
+ CLUTTER_INPUT_CONTENT_PURPOSE_TIME,
+ CLUTTER_INPUT_CONTENT_PURPOSE_DATETIME,
+ CLUTTER_INPUT_CONTENT_PURPOSE_TERMINAL,
+} ClutterInputContentPurpose;
+
+typedef enum {
+ CLUTTER_INPUT_PANEL_STATE_OFF,
+ CLUTTER_INPUT_PANEL_STATE_ON,
+ CLUTTER_INPUT_PANEL_STATE_TOGGLE,
+} ClutterInputPanelState;
+
G_END_DECLS
#endif /* __CLUTTER_ENUMS_H__ */
diff --git a/clutter/clutter/clutter-input-focus-private.h b/clutter/clutter/clutter-input-focus-private.h
new file mode 100644
index 000000000..563e58978
--- /dev/null
+++ b/clutter/clutter/clutter-input-focus-private.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017,2018 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Carlos Garnacho <carlosg@gnome.org>
+ */
+
+#ifndef __CLUTTER_INPUT_FOCUS_PRIVATE_H__
+#define __CLUTTER_INPUT_FOCUS_PRIVATE_H__
+
+void clutter_input_focus_focus_in (ClutterInputFocus *focus,
+ ClutterInputMethod *method);
+void clutter_input_focus_focus_out (ClutterInputFocus *focus);
+
+void clutter_input_focus_commit (ClutterInputFocus *focus,
+ const gchar *text);
+void clutter_input_focus_delete_surrounding (ClutterInputFocus *focus,
+ guint offset,
+ guint len);
+void clutter_input_focus_request_surrounding (ClutterInputFocus *focus);
+
+void clutter_input_focus_set_preedit_text (ClutterInputFocus *focus,
+ const gchar *preedit,
+ guint cursor);
+
+#endif /* __CLUTTER_INPUT_FOCUS_PRIVATE_H__ */
diff --git a/clutter/clutter/clutter-input-focus.c b/clutter/clutter/clutter-input-focus.c
new file mode 100644
index 000000000..51381ace6
--- /dev/null
+++ b/clutter/clutter/clutter-input-focus.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2017,2018 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Carlos Garnacho <carlosg@gnome.org>
+ */
+
+#include "clutter-build-config.h"
+
+#include "clutter/clutter-input-focus.h"
+#include "clutter/clutter-input-focus-private.h"
+#include "clutter/clutter-input-method-private.h"
+
+typedef struct _ClutterInputFocusPrivate ClutterInputFocusPrivate;
+
+struct _ClutterInputFocusPrivate
+{
+ ClutterInputMethod *im;
+};
+
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ClutterInputFocus, clutter_input_focus, G_TYPE_OBJECT)
+
+static void
+clutter_input_focus_real_focus_in (ClutterInputFocus *focus,
+ ClutterInputMethod *im)
+{
+ ClutterInputFocusPrivate *priv;
+
+ priv = clutter_input_focus_get_instance_private (focus);
+ priv->im = im;
+}
+
+static void
+clutter_input_focus_real_focus_out (ClutterInputFocus *focus)
+{
+ ClutterInputFocusPrivate *priv;
+
+ priv = clutter_input_focus_get_instance_private (focus);
+ priv->im = NULL;
+}
+
+static void
+clutter_input_focus_class_init (ClutterInputFocusClass *klass)
+{
+ klass->focus_in = clutter_input_focus_real_focus_in;
+ klass->focus_out = clutter_input_focus_real_focus_out;
+}
+
+static void
+clutter_input_focus_init (ClutterInputFocus *focus)
+{
+}
+
+gboolean
+clutter_input_focus_is_focused (ClutterInputFocus *focus)
+{
+ ClutterInputFocusPrivate *priv;
+
+ priv = clutter_input_focus_get_instance_private (focus);
+
+ return !!priv->im;
+}
+
+void
+clutter_input_focus_reset (ClutterInputFocus *focus)
+{
+ ClutterInputFocusPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
+ g_return_if_fail (clutter_input_focus_is_focused (focus));
+
+ priv = clutter_input_focus_get_instance_private (focus);
+
+ clutter_input_method_reset (priv->im);
+}
+
+void
+clutter_input_focus_set_cursor_location (ClutterInputFocus *focus,
+ const ClutterRect *rect)
+{
+ ClutterInputFocusPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
+ g_return_if_fail (clutter_input_focus_is_focused (focus));
+
+ priv = clutter_input_focus_get_instance_private (focus);
+
+ clutter_input_method_set_cursor_location (priv->im, rect);
+}
+
+void
+clutter_input_focus_set_surrounding (ClutterInputFocus *focus,
+ const gchar *text,
+ guint cursor,
+ guint anchor)
+{
+ ClutterInputFocusPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
+ g_return_if_fail (clutter_input_focus_is_focused (focus));
+
+ priv = clutter_input_focus_get_instance_private (focus);
+
+ clutter_input_method_set_surrounding (priv->im, text, cursor, anchor);
+}
+
+void
+clutter_input_focus_set_content_hints (ClutterInputFocus *focus,
+ ClutterInputContentHintFlags hints)
+{
+ ClutterInputFocusPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
+ g_return_if_fail (clutter_input_focus_is_focused (focus));
+
+ priv = clutter_input_focus_get_instance_private (focus);
+
+ clutter_input_method_set_content_hints (priv->im, hints);
+}
+
+void
+clutter_input_focus_set_content_purpose (ClutterInputFocus *focus,
+ ClutterInputContentPurpose purpose)
+{
+ ClutterInputFocusPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
+ g_return_if_fail (clutter_input_focus_is_focused (focus));
+
+ priv = clutter_input_focus_get_instance_private (focus);
+
+ clutter_input_method_set_content_purpose (priv->im, purpose);
+}
+
+gboolean
+clutter_input_focus_filter_key_event (ClutterInputFocus *focus,
+ const ClutterKeyEvent *key)
+{
+ ClutterInputFocusPrivate *priv;
+
+ g_return_val_if_fail (CLUTTER_IS_INPUT_FOCUS (focus), FALSE);
+ g_return_val_if_fail (clutter_input_focus_is_focused (focus), FALSE);
+
+ priv = clutter_input_focus_get_instance_private (focus);
+
+ return clutter_input_method_filter_key_event (priv->im, key);
+}
+
+void
+clutter_input_focus_set_can_show_preedit (ClutterInputFocus *focus,
+ gboolean can_show_preedit)
+{
+ ClutterInputFocusPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
+ g_return_if_fail (clutter_input_focus_is_focused (focus));
+
+ priv = clutter_input_focus_get_instance_private (focus);
+
+ clutter_input_method_set_can_show_preedit (priv->im, can_show_preedit);
+}
+
+void
+clutter_input_focus_request_toggle_input_panel (ClutterInputFocus *focus)
+{
+ ClutterInputFocusPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
+ g_return_if_fail (clutter_input_focus_is_focused (focus));
+
+ priv = clutter_input_focus_get_instance_private (focus);
+
+ clutter_input_method_toggle_input_panel (priv->im);
+}
+
+void
+clutter_input_focus_focus_in (ClutterInputFocus *focus,
+ ClutterInputMethod *im)
+{
+ g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
+ g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im));
+
+ CLUTTER_INPUT_FOCUS_GET_CLASS (focus)->focus_in (focus, im);
+}
+
+void
+clutter_input_focus_focus_out (ClutterInputFocus *focus)
+{
+ g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
+
+ CLUTTER_INPUT_FOCUS_GET_CLASS (focus)->focus_out (focus);
+}
+
+void
+clutter_input_focus_commit (ClutterInputFocus *focus,
+ const gchar *text)
+{
+ g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
+
+ CLUTTER_INPUT_FOCUS_GET_CLASS (focus)->commit_text (focus, text);
+}
+
+void
+clutter_input_focus_delete_surrounding (ClutterInputFocus *focus,
+ guint offset,
+ guint len)
+{
+ g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
+
+ CLUTTER_INPUT_FOCUS_GET_CLASS (focus)->delete_surrounding (focus, offset, len);
+}
+
+void
+clutter_input_focus_request_surrounding (ClutterInputFocus *focus)
+{
+ g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
+
+ CLUTTER_INPUT_FOCUS_GET_CLASS (focus)->request_surrounding (focus);
+}
+
+void
+clutter_input_focus_set_preedit_text (ClutterInputFocus *focus,
+ const gchar *preedit,
+ guint cursor)
+{
+ g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
+
+ CLUTTER_INPUT_FOCUS_GET_CLASS (focus)->set_preedit_text (focus, preedit, cursor);
+}
diff --git a/clutter/clutter/clutter-input-focus.h b/clutter/clutter/clutter-input-focus.h
new file mode 100644
index 000000000..a31521fb0
--- /dev/null
+++ b/clutter/clutter/clutter-input-focus.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2017,2018 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Carlos Garnacho <carlosg@gnome.org>
+ */
+
+#ifndef __CLUTTER_INPUT_FOCUS_H__
+#define __CLUTTER_INPUT_FOCUS_H__
+
+#include <clutter/clutter.h>
+
+#define CLUTTER_TYPE_INPUT_FOCUS (clutter_input_focus_get_type ())
+
+CLUTTER_AVAILABLE_IN_MUTTER
+G_DECLARE_DERIVABLE_TYPE (ClutterInputFocus, clutter_input_focus,
+ CLUTTER, INPUT_FOCUS, GObject)
+
+struct _ClutterInputFocusClass
+{
+ GObjectClass parent_class;
+ GTypeInterface iface;
+
+ void (* focus_in) (ClutterInputFocus *focus,
+ ClutterInputMethod *input_method);
+ void (* focus_out) (ClutterInputFocus *focus);
+
+ void (* request_surrounding) (ClutterInputFocus *focus);
+ void (* delete_surrounding) (ClutterInputFocus *focus,
+ guint offset,
+ guint len);
+ void (* commit_text) (ClutterInputFocus *focus,
+ const gchar *text);
+
+ void (* set_preedit_text) (ClutterInputFocus *focus,
+ const gchar *preedit,
+ guint cursor);
+};
+
+CLUTTER_AVAILABLE_IN_MUTTER
+gboolean clutter_input_focus_is_focused (ClutterInputFocus *focus);
+
+CLUTTER_AVAILABLE_IN_MUTTER
+void clutter_input_focus_reset (ClutterInputFocus *focus);
+CLUTTER_AVAILABLE_IN_MUTTER
+void clutter_input_focus_set_cursor_location (ClutterInputFocus *focus,
+ const ClutterRect *rect);
+
+CLUTTER_AVAILABLE_IN_MUTTER
+void clutter_input_focus_set_surrounding (ClutterInputFocus *focus,
+ const gchar *text,
+ guint cursor,
+ guint anchor);
+CLUTTER_AVAILABLE_IN_MUTTER
+void clutter_input_focus_set_content_hints (ClutterInputFocus *focus,
+ ClutterInputContentHintFlags hint);
+CLUTTER_AVAILABLE_IN_MUTTER
+void clutter_input_focus_set_content_purpose (ClutterInputFocus *focus,
+ ClutterInputContentPurpose purpose);
+CLUTTER_AVAILABLE_IN_MUTTER
+gboolean clutter_input_focus_filter_key_event (ClutterInputFocus *focus,
+ const ClutterKeyEvent *key);
+CLUTTER_AVAILABLE_IN_MUTTER
+void clutter_input_focus_set_can_show_preedit (ClutterInputFocus *focus,
+ gboolean can_show_preedit);
+CLUTTER_AVAILABLE_IN_MUTTER
+void clutter_input_focus_request_toggle_input_panel (ClutterInputFocus *focus);
+
+#endif /* __CLUTTER_INPUT_FOCUS_H__ */
diff --git a/clutter/clutter/clutter-input-method-private.h b/clutter/clutter/clutter-input-method-private.h
new file mode 100644
index 000000000..e8ab2cabf
--- /dev/null
+++ b/clutter/clutter/clutter-input-method-private.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017,2018 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Carlos Garnacho <carlosg@gnome.org>
+ */
+
+#ifndef __CLUTTER_INPUT_METHOD_PRIVATE_H__
+#define __CLUTTER_INPUT_METHOD_PRIVATE_H__
+
+ClutterInputFocus * clutter_input_method_get_focus (ClutterInputMethod *method);
+
+void clutter_input_method_reset (ClutterInputMethod *method);
+
+void clutter_input_method_set_cursor_location (ClutterInputMethod *method,
+ const ClutterRect *rect);
+void clutter_input_method_set_surrounding (ClutterInputMethod *method,
+ const gchar *text,
+ guint cursor,
+ guint anchor);
+void clutter_input_method_set_content_hints (ClutterInputMethod *method,
+ ClutterInputContentHintFlags hints);
+void clutter_input_method_set_content_purpose (ClutterInputMethod *method,
+ ClutterInputContentPurpose purpose);
+void clutter_input_method_set_can_show_preedit (ClutterInputMethod *method,
+ gboolean can_show_preedit);
+gboolean clutter_input_method_filter_key_event (ClutterInputMethod *method,
+ const ClutterKeyEvent *key);
+
+void clutter_input_method_toggle_input_panel (ClutterInputMethod *method);
+
+#endif /* __CLUTTER_INPUT_METHOD_PRIVATE_H__ */
diff --git a/clutter/clutter/clutter-input-method.c b/clutter/clutter/clutter-input-method.c
new file mode 100644
index 000000000..5c1462015
--- /dev/null
+++ b/clutter/clutter/clutter-input-method.c
@@ -0,0 +1,442 @@
+/*
+ * Copyright (C) 2017,2018 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Carlos Garnacho <carlosg@gnome.org>
+ */
+
+#include "clutter-build-config.h"
+
+#include "clutter-private.h"
+#include "clutter/clutter-input-method.h"
+#include "clutter/clutter-input-method-private.h"
+#include "clutter/clutter-input-focus-private.h"
+
+typedef struct _ClutterInputMethodPrivate ClutterInputMethodPrivate;
+
+struct _ClutterInputMethodPrivate
+{
+ ClutterInputFocus *focus;
+ ClutterInputContentHintFlags content_hints;
+ ClutterInputContentPurpose content_purpose;
+ gboolean can_show_preedit;
+};
+
+enum {
+ COMMIT,
+ DELETE_SURROUNDING,
+ REQUEST_SURROUNDING,
+ INPUT_PANEL_STATE,
+ CURSOR_LOCATION_CHANGED,
+ N_SIGNALS,
+};
+
+enum {
+ PROP_0,
+ PROP_CONTENT_HINTS,
+ PROP_CONTENT_PURPOSE,
+ PROP_CAN_SHOW_PREEDIT,
+ N_PROPS
+};
+
+static guint signals[N_SIGNALS] = { 0 };
+static GParamSpec *pspecs[N_PROPS] = { 0 };
+
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ClutterInputMethod, clutter_input_method, G_TYPE_OBJECT)
+
+static void
+set_content_hints (ClutterInputMethod *im,
+ ClutterInputContentHintFlags content_hints)
+{
+ ClutterInputMethodPrivate *priv;
+
+ priv = clutter_input_method_get_instance_private (im);
+ priv->content_hints = content_hints;
+ CLUTTER_INPUT_METHOD_GET_CLASS (im)->update_content_hints (im, content_hints);
+}
+
+static void
+set_content_purpose (ClutterInputMethod *im,
+ ClutterInputContentPurpose content_purpose)
+{
+ ClutterInputMethodPrivate *priv;
+
+ priv = clutter_input_method_get_instance_private (im);
+ priv->content_purpose = content_purpose;
+ CLUTTER_INPUT_METHOD_GET_CLASS (im)->update_content_purpose (im,
+ content_purpose);
+}
+
+static void
+set_can_show_preedit (ClutterInputMethod *im,
+ gboolean can_show_preedit)
+{
+ ClutterInputMethodPrivate *priv;
+
+ priv = clutter_input_method_get_instance_private (im);
+ priv->can_show_preedit = can_show_preedit;
+}
+
+static void
+clutter_input_method_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id)
+ {
+ case PROP_CONTENT_HINTS:
+ set_content_hints (CLUTTER_INPUT_METHOD (object),
+ g_value_get_flags (value));
+ break;
+ case PROP_CONTENT_PURPOSE:
+ set_content_purpose (CLUTTER_INPUT_METHOD (object),
+ g_value_get_enum (value));
+ break;
+ case PROP_CAN_SHOW_PREEDIT:
+ set_can_show_preedit (CLUTTER_INPUT_METHOD (object),
+ g_value_get_boolean (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+clutter_input_method_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ClutterInputMethodPrivate *priv;
+ ClutterInputMethod *im;
+
+ im = CLUTTER_INPUT_METHOD (object);
+ priv = clutter_input_method_get_instance_private (im);
+
+ switch (prop_id)
+ {
+ case PROP_CONTENT_HINTS:
+ g_value_set_flags (value, priv->content_hints);
+ break;
+ case PROP_CONTENT_PURPOSE:
+ g_value_set_enum (value, priv->content_purpose);
+ break;
+ case PROP_CAN_SHOW_PREEDIT:
+ g_value_set_boolean (value, priv->can_show_preedit);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+clutter_input_method_class_init (ClutterInputMethodClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->set_property = clutter_input_method_set_property;
+ object_class->get_property = clutter_input_method_get_property;
+
+ signals[COMMIT] =
+ g_signal_new ("commit",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 1, G_TYPE_STRING);
+ signals[DELETE_SURROUNDING] =
+ g_signal_new ("delete-surrounding",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
+ signals[REQUEST_SURROUNDING] =
+ g_signal_new ("request-surrounding",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
+ signals[INPUT_PANEL_STATE] =
+ g_signal_new ("input-panel-state",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 1,
+ CLUTTER_TYPE_INPUT_PANEL_STATE);
+ signals[CURSOR_LOCATION_CHANGED] =
+ g_signal_new ("cursor-location-changed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 1, CLUTTER_TYPE_RECT);
+
+ pspecs[PROP_CONTENT_HINTS] =
+ g_param_spec_flags ("content-hints",
+ P_("Content hints"),
+ P_("Content hints"),
+ CLUTTER_TYPE_INPUT_CONTENT_HINT_FLAGS, 0,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+ pspecs[PROP_CONTENT_PURPOSE] =
+ g_param_spec_enum ("content-purpose",
+ P_("Content purpose"),
+ P_("Content purpose"),
+ CLUTTER_TYPE_INPUT_CONTENT_PURPOSE, 0,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+ pspecs[PROP_CAN_SHOW_PREEDIT] =
+ g_param_spec_boolean ("can-show-preedit",
+ P_("Can show preedit"),
+ P_("Can show preedit"),
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPS, pspecs);
+}
+
+static void
+clutter_input_method_init (ClutterInputMethod *im)
+{
+}
+
+void
+clutter_input_method_focus_in (ClutterInputMethod *im,
+ ClutterInputFocus *focus)
+{
+ ClutterInputMethodPrivate *priv;
+ ClutterInputMethodClass *klass;
+
+ g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im));
+ g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
+
+ priv = clutter_input_method_get_instance_private (im);
+
+ if (priv->focus == focus)
+ return;
+
+ if (priv->focus)
+ clutter_input_method_focus_out (im);
+
+ g_set_object (&priv->focus, focus);
+
+ if (focus)
+ {
+ klass = CLUTTER_INPUT_METHOD_GET_CLASS (im);
+ klass->focus_in (im, focus);
+
+ clutter_input_focus_focus_in (priv->focus, im);
+ }
+}
+
+void
+clutter_input_method_focus_out (ClutterInputMethod *im)
+{
+ ClutterInputMethodPrivate *priv;
+ ClutterInputMethodClass *klass;
+
+ g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im));
+
+ priv = clutter_input_method_get_instance_private (im);
+
+ if (!priv->focus)
+ return;
+
+ clutter_input_focus_focus_out (priv->focus);
+ g_clear_object (&priv->focus);
+
+ klass = CLUTTER_INPUT_METHOD_GET_CLASS (im);
+ klass->focus_out (im);
+
+ g_signal_emit (im, signals[INPUT_PANEL_STATE],
+ 0, CLUTTER_INPUT_PANEL_STATE_OFF);
+}
+
+ClutterInputFocus *
+clutter_input_method_get_focus (ClutterInputMethod *im)
+{
+ ClutterInputMethodPrivate *priv;
+
+ priv = clutter_input_method_get_instance_private (im);
+ return priv->focus;
+}
+
+void
+clutter_input_method_commit (ClutterInputMethod *im,
+ const gchar *text)
+{
+ ClutterInputMethodPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im));
+
+ priv = clutter_input_method_get_instance_private (im);
+ if (priv->focus)
+ clutter_input_focus_commit (priv->focus, text);
+}
+
+void
+clutter_input_method_delete_surrounding (ClutterInputMethod *im,
+ guint offset,
+ guint len)
+{
+ ClutterInputMethodPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im));
+
+ priv = clutter_input_method_get_instance_private (im);
+ if (priv->focus)
+ clutter_input_focus_delete_surrounding (priv->focus, offset, len);
+}
+
+void
+clutter_input_method_request_surrounding (ClutterInputMethod *im)
+{
+ ClutterInputMethodPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im));
+
+ priv = clutter_input_method_get_instance_private (im);
+ if (priv->focus)
+ clutter_input_focus_request_surrounding (priv->focus);
+}
+
+/**
+ * clutter_input_method_set_preedit_text:
+ * @method: a #ClutterInputMethod
+ * @preedit: (nullable): the preedit text, or %NULL
+ *
+ * Sets the preedit text on the current input focus.
+ **/
+void
+clutter_input_method_set_preedit_text (ClutterInputMethod *im,
+ const gchar *preedit,
+ guint cursor)
+{
+ ClutterInputMethodPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im));
+
+ priv = clutter_input_method_get_instance_private (im);
+ if (priv->focus)
+ clutter_input_focus_set_preedit_text (priv->focus, preedit, cursor);
+}
+
+void
+clutter_input_method_notify_key_event (ClutterInputMethod *im,
+ const ClutterEvent *event,
+ gboolean filtered)
+{
+ if (!filtered)
+ {
+ ClutterEvent *copy;
+
+ /* XXX: we rely on the IM implementation to notify back of
+ * key events in the exact same order they were given.
+ */
+ copy = clutter_event_copy (event);
+ clutter_event_set_flags (copy, clutter_event_get_flags (event) |
+ CLUTTER_EVENT_FLAG_INPUT_METHOD);
+ clutter_event_put (copy);
+ clutter_event_free (copy);
+ }
+}
+
+void
+clutter_input_method_toggle_input_panel (ClutterInputMethod *im)
+{
+ g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im));
+
+ g_signal_emit (im, signals[INPUT_PANEL_STATE], 0,
+ CLUTTER_INPUT_PANEL_STATE_TOGGLE);
+}
+
+void
+clutter_input_method_reset (ClutterInputMethod *im)
+{
+ g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im));
+
+ CLUTTER_INPUT_METHOD_GET_CLASS (im)->reset (im);
+}
+
+void
+clutter_input_method_set_cursor_location (ClutterInputMethod *im,
+ const ClutterRect *rect)
+{
+ g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im));
+
+ CLUTTER_INPUT_METHOD_GET_CLASS (im)->set_cursor_location (im, rect);
+
+ g_signal_emit (im, signals[CURSOR_LOCATION_CHANGED], 0, rect);
+}
+
+void
+clutter_input_method_set_surrounding (ClutterInputMethod *im,
+ const gchar *text,
+ guint cursor,
+ guint anchor)
+{
+ g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im));
+
+ CLUTTER_INPUT_METHOD_GET_CLASS (im)->set_surrounding (im, text,
+ cursor, anchor);
+}
+
+void
+clutter_input_method_set_content_hints (ClutterInputMethod *im,
+ ClutterInputContentHintFlags hints)
+{
+ g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im));
+
+ g_object_set (G_OBJECT (im), "content-hints", hints, NULL);
+}
+
+void
+clutter_input_method_set_content_purpose (ClutterInputMethod *im,
+ ClutterInputContentPurpose purpose)
+{
+ g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im));
+
+ g_object_set (G_OBJECT (im), "content-purpose", purpose, NULL);
+}
+
+void
+clutter_input_method_set_can_show_preedit (ClutterInputMethod *im,
+ gboolean can_show_preedit)
+{
+ g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im));
+
+ g_object_set (G_OBJECT (im), "can-show-preedit", can_show_preedit, NULL);
+}
+
+gboolean
+clutter_input_method_filter_key_event (ClutterInputMethod *im,
+ const ClutterKeyEvent *key)
+{
+ ClutterInputMethodClass *im_class = CLUTTER_INPUT_METHOD_GET_CLASS (im);
+
+ g_return_val_if_fail (CLUTTER_IS_INPUT_METHOD (im), FALSE);
+ g_return_val_if_fail (key != NULL, FALSE);
+
+ if (clutter_event_get_flags ((ClutterEvent *) key) & CLUTTER_EVENT_FLAG_INPUT_METHOD)
+ return FALSE;
+ if (!im_class->filter_key_event)
+ return FALSE;
+
+ return im_class->filter_key_event (im, (const ClutterEvent *) key);
+}
diff --git a/clutter/clutter/clutter-input-method.h b/clutter/clutter/clutter-input-method.h
new file mode 100644
index 000000000..d37522d14
--- /dev/null
+++ b/clutter/clutter/clutter-input-method.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2017,2018 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Carlos Garnacho <carlosg@gnome.org>
+ */
+
+#ifndef __CLUTTER_INPUT_METHOD_H__
+#define __CLUTTER_INPUT_METHOD_H__
+
+#include <clutter/clutter.h>
+
+#define CLUTTER_TYPE_INPUT_METHOD (clutter_input_method_get_type ())
+
+CLUTTER_AVAILABLE_IN_MUTTER
+G_DECLARE_DERIVABLE_TYPE (ClutterInputMethod, clutter_input_method,
+ CLUTTER, INPUT_METHOD, GObject)
+
+typedef struct _ClutterInputMethodClass ClutterInputMethodClass;
+
+struct _ClutterInputMethodClass
+{
+ GObjectClass parent_class;
+
+ void (* focus_in) (ClutterInputMethod *im,
+ ClutterInputFocus *actor);
+ void (* focus_out) (ClutterInputMethod *im);
+
+ void (* reset) (ClutterInputMethod *im);
+
+ void (* set_cursor_location) (ClutterInputMethod *im,
+ const ClutterRect *rect);
+ void (* set_surrounding) (ClutterInputMethod *im,
+ const gchar *text,
+ guint cursor,
+ guint anchor);
+ void (* update_content_hints) (ClutterInputMethod *im,
+ ClutterInputContentHintFlags hint);
+ void (* update_content_purpose) (ClutterInputMethod *im,
+ ClutterInputContentPurpose purpose);
+
+ gboolean (* filter_key_event) (ClutterInputMethod *im,
+ const ClutterEvent *key);
+};
+
+CLUTTER_AVAILABLE_IN_MUTTER
+void clutter_input_method_focus_in (ClutterInputMethod *im,
+ ClutterInputFocus *focus);
+CLUTTER_AVAILABLE_IN_MUTTER
+void clutter_input_method_focus_out (ClutterInputMethod *im);
+
+CLUTTER_AVAILABLE_IN_MUTTER
+void clutter_input_method_commit (ClutterInputMethod *im,
+ const gchar *text);
+CLUTTER_AVAILABLE_IN_MUTTER
+void clutter_input_method_delete_surrounding (ClutterInputMethod *im,
+ guint offset,
+ guint len);
+CLUTTER_AVAILABLE_IN_MUTTER
+void clutter_input_method_request_surrounding (ClutterInputMethod *im);
+
+CLUTTER_AVAILABLE_IN_MUTTER
+void clutter_input_method_set_preedit_text (ClutterInputMethod *im,
+ const gchar *preedit,
+ guint cursor);
+
+CLUTTER_AVAILABLE_IN_MUTTER
+void clutter_input_method_notify_key_event (ClutterInputMethod *im,
+ const ClutterEvent *event,
+ gboolean filtered);
+CLUTTER_AVAILABLE_IN_MUTTER
+void clutter_input_method_request_toggle_input_panel (ClutterInputMethod *im);
+
+#endif /* __CLUTTER_INPUT_METHOD_H__ */
diff --git a/clutter/clutter/clutter-types.h b/clutter/clutter/clutter-types.h
index 4d5b018dc..d7f3dfb9c 100644
--- a/clutter/clutter/clutter-types.h
+++ b/clutter/clutter/clutter-types.h
@@ -98,6 +98,7 @@ typedef struct _ClutterInputDevice ClutterInputDevice;
typedef struct _ClutterVirtualInputDevice ClutterVirtualInputDevice;
typedef struct _ClutterInputMethod ClutterInputMethod;
+typedef struct _ClutterInputFocus ClutterInputFocus;
typedef CoglMatrix ClutterMatrix;
diff --git a/clutter/clutter/clutter.h b/clutter/clutter/clutter.h
index cdf54ac01..721e30e7e 100644
--- a/clutter/clutter/clutter.h
+++ b/clutter/clutter/clutter.h
@@ -72,6 +72,8 @@
#include "clutter-image.h"
#include "clutter-input-device.h"
#include "clutter-input-device-tool.h"
+#include "clutter-input-method.h"
+#include "clutter-input-focus.h"
#include "clutter-interval.h"
#include "clutter-keyframe-transition.h"
#include "clutter-keysyms.h"