[mutter/wip/carlosg/text-input: 17/24] clutter: Make ClutterText implement ClutterInputFocus



commit d7cb3da324ae370eac8fd46e1bf9bc91485b3adb
Author: Carlos Garnacho <carlosg gnome org>
Date:   Wed Dec 6 12:49:34 2017 +0100

    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.

 clutter/clutter/clutter-text.c |  131 +++++++++++++++++++++++++++++++++++++++-
 1 files changed, 129 insertions(+), 2 deletions(-)
---
diff --git a/clutter/clutter/clutter-text.c b/clutter/clutter/clutter-text.c
index b57b3c5..7df53ff 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]);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]