summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2017-12-06 12:49:34 +0100
committerCarlos Garnacho <carlosg@gnome.org>2017-12-22 16:59:50 +0100
commitd7cb3da324ae370eac8fd46e1bf9bc91485b3adb (patch)
tree6721f4f276586c0aa271158cb823990dd38a1db2
parentca654ac544aef993feab875c65f46c132cb8a824 (diff)
downloadmutter-d7cb3da324ae370eac8fd46e1bf9bc91485b3adb.tar.gz
clutter: Make ClutterText implement ClutterInputFocus
This only applies when the actor is editable. Implementing this interface will allow it to interact with the input method.
-rw-r--r--clutter/clutter/clutter-text.c131
1 files changed, 129 insertions, 2 deletions
diff --git a/clutter/clutter/clutter-text.c b/clutter/clutter/clutter-text.c
index b57b3c535..7df53ffef 100644
--- a/clutter/clutter/clutter-text.c
+++ b/clutter/clutter/clutter-text.c
@@ -63,6 +63,7 @@
#include "clutter-units.h"
#include "clutter-paint-volume-private.h"
#include "clutter-scriptable.h"
+#include "clutter-input-focus.h"
/* cursor width in pixels */
#define DEFAULT_CURSOR_SIZE 2
@@ -269,6 +270,7 @@ static const ClutterColor default_selected_text_color = { 0, 0, 0, 255 };
static ClutterAnimatableIface *parent_animatable_iface = NULL;
static ClutterScriptableIface *parent_scriptable_iface = NULL;
+static void clutter_input_focus_iface_init (ClutterInputFocusInterface *iface);
static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
@@ -276,11 +278,91 @@ G_DEFINE_TYPE_WITH_CODE (ClutterText,
clutter_text,
CLUTTER_TYPE_ACTOR,
G_ADD_PRIVATE (ClutterText)
+ G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_INPUT_FOCUS,
+ clutter_input_focus_iface_init)
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
clutter_scriptable_iface_init)
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
clutter_animatable_iface_init));
+static void
+clutter_text_input_focus_request_surrounding (ClutterInputFocus *focus)
+{
+ ClutterText *clutter_text = CLUTTER_TEXT (focus);
+ ClutterTextBuffer *buffer;
+ const gchar *text;
+ gint anchor_pos, cursor_pos;
+
+ buffer = clutter_text_get_buffer (clutter_text);
+ text = clutter_text_buffer_get_text (buffer);
+
+ cursor_pos = clutter_text_get_cursor_position (clutter_text);
+ if (cursor_pos < 0)
+ cursor_pos = clutter_text_buffer_get_length (buffer);
+
+ anchor_pos = clutter_text_get_selection_bound (clutter_text);
+ if (anchor_pos < 0)
+ anchor_pos = cursor_pos;
+
+ clutter_input_focus_set_surrounding (focus, text,
+ g_utf8_offset_to_pointer (text, cursor_pos) - text,
+ g_utf8_offset_to_pointer (text, anchor_pos) - text);
+}
+
+static void
+clutter_text_input_focus_delete_surrounding (ClutterInputFocus *focus,
+ guint offset,
+ guint len)
+{
+ ClutterText *clutter_text = CLUTTER_TEXT (focus);
+
+ if (clutter_text_get_editable (clutter_text))
+ clutter_text_delete_text (clutter_text, offset, len);
+}
+
+static void
+clutter_text_input_focus_commit_text (ClutterInputFocus *focus,
+ const gchar *text)
+{
+ ClutterText *clutter_text = CLUTTER_TEXT (focus);
+
+ if (clutter_text_get_editable (clutter_text))
+ {
+ clutter_text_delete_selection (clutter_text);
+ clutter_text_insert_text (clutter_text, text,
+ clutter_text_get_cursor_position (clutter_text));
+ }
+}
+
+static void
+clutter_text_input_focus_set_preedit_text (ClutterInputFocus *focus,
+ const gchar *preedit_text,
+ guint cursor_pos)
+{
+ ClutterText *clutter_text = CLUTTER_TEXT (focus);
+
+ if (clutter_text_get_editable (clutter_text))
+ {
+ PangoAttrList *list;
+
+ list = pango_attr_list_new ();
+ pango_attr_list_insert (list, pango_attr_underline_new (PANGO_UNDERLINE_SINGLE));
+ clutter_text_set_preedit_string (clutter_text,
+ preedit_text, list,
+ cursor_pos);
+ pango_attr_list_unref (list);
+ }
+}
+
+static void
+clutter_input_focus_iface_init (ClutterInputFocusInterface *iface)
+{
+ iface->request_surrounding = clutter_text_input_focus_request_surrounding;
+ iface->delete_surrounding = clutter_text_input_focus_delete_surrounding;
+ iface->commit_text = clutter_text_input_focus_commit_text;
+ iface->set_preedit_text = clutter_text_input_focus_set_preedit_text;
+}
+
static inline void
clutter_text_dirty_paint_volume (ClutterText *text)
{
@@ -1010,6 +1092,22 @@ clutter_text_position_to_coords (ClutterText *self,
}
static inline void
+update_cursor_location (ClutterText *self)
+{
+ ClutterTextPrivate *priv = self->priv;
+ ClutterRect rect;
+ float x, y;
+
+ if (!priv->editable)
+ return;
+
+ rect = priv->cursor_rect;
+ clutter_actor_get_transformed_position (CLUTTER_ACTOR (self), &x, &y);
+ clutter_rect_offset (&rect, x, y);
+ clutter_input_focus_set_cursor_location (CLUTTER_INPUT_FOCUS (self), &rect);
+}
+
+static inline void
clutter_text_ensure_cursor_position (ClutterText *self)
{
ClutterTextPrivate *priv = self->priv;
@@ -1057,6 +1155,8 @@ clutter_text_ensure_cursor_position (ClutterText *self)
g_signal_emit (self, text_signals[CURSOR_EVENT], 0, &cursor_pos);
g_signal_emit (self, text_signals[CURSOR_CHANGED], 0);
+
+ update_cursor_location (self);
}
}
@@ -2085,9 +2185,11 @@ clutter_text_key_press (ClutterActor *actor,
g_assert (pool != NULL);
/* we allow passing synthetic events that only contain
- * the Unicode value and not the key symbol
+ * the Unicode value and not the key symbol, unless they
+ * contain the input method flag.
*/
- if (event->keyval == 0 && (event->flags & CLUTTER_EVENT_FLAG_SYNTHETIC))
+ if (event->keyval == 0 && (event->flags & CLUTTER_EVENT_FLAG_SYNTHETIC) &&
+ !(event->flags & CLUTTER_EVENT_FLAG_INPUT_METHOD))
res = FALSE;
else
res = clutter_binding_pool_activate (pool, event->keyval,
@@ -2105,6 +2207,9 @@ clutter_text_key_press (ClutterActor *actor,
{
gunichar key_unichar;
+ if (clutter_input_focus_filter_key_event (CLUTTER_INPUT_FOCUS (actor), event))
+ return CLUTTER_EVENT_STOP;
+
/* Skip keys when control is pressed */
key_unichar = clutter_event_get_key_unicode ((ClutterEvent *) event);
@@ -2141,6 +2246,16 @@ clutter_text_key_press (ClutterActor *actor,
return CLUTTER_EVENT_PROPAGATE;
}
+static gboolean
+clutter_text_key_release (ClutterActor *actor,
+ ClutterKeyEvent *event)
+{
+ if (clutter_input_focus_filter_key_event (CLUTTER_INPUT_FOCUS (actor), event))
+ return CLUTTER_EVENT_STOP;
+
+ return CLUTTER_EVENT_PROPAGATE;
+}
+
static void
clutter_text_compute_layout_offsets (ClutterText *self,
PangoLayout *layout,
@@ -2664,6 +2779,9 @@ clutter_text_key_focus_in (ClutterActor *actor)
{
ClutterTextPrivate *priv = CLUTTER_TEXT (actor)->priv;
+ if (priv->editable)
+ clutter_input_focus_focus_in (CLUTTER_INPUT_FOCUS (actor));
+
priv->has_focus = TRUE;
clutter_text_queue_redraw (actor);
@@ -2676,6 +2794,9 @@ clutter_text_key_focus_out (ClutterActor *actor)
priv->has_focus = FALSE;
+ if (priv->editable)
+ clutter_input_focus_focus_out (CLUTTER_INPUT_FOCUS (actor));
+
clutter_text_queue_redraw (actor);
}
@@ -3369,6 +3490,7 @@ clutter_text_class_init (ClutterTextClass *klass)
actor_class->get_preferred_height = clutter_text_get_preferred_height;
actor_class->allocate = clutter_text_allocate;
actor_class->key_press_event = clutter_text_key_press;
+ actor_class->key_release_event = clutter_text_key_release;
actor_class->button_press_event = clutter_text_button_press;
actor_class->button_release_event = clutter_text_button_release;
actor_class->motion_event = clutter_text_motion;
@@ -4469,6 +4591,11 @@ clutter_text_set_editable (ClutterText *self,
{
priv->editable = editable;
+ if (!priv->editable)
+ clutter_input_focus_focus_out (CLUTTER_INPUT_FOCUS (self));
+ else if (priv->has_focus)
+ clutter_input_focus_focus_in (CLUTTER_INPUT_FOCUS (self));
+
clutter_text_queue_redraw (CLUTTER_ACTOR (self));
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EDITABLE]);