[gtk+/gestures: 163/202] entry: Use gestures to handle pointer/touch events



commit e580c29f07f42fb171264a97389a18a2a7cdb3cd
Author: Carlos Garnacho <carlosg gnome org>
Date:   Thu May 15 15:03:18 2014 +0200

    entry: Use gestures to handle pointer/touch events
    
    Similarly to GtkTextView, a GtkGestureMultiPress gesture handles
    button/touch presses to initiate one selection mode or other, and
    a GtkGestureDrag is used to handle text selection and DnD checks.
    
    The code from button press/release, motion, and grab_notify handlers
    has been shuffled into the actions triggered by those gestures.

 gtk/gtkentry.c |  671 +++++++++++++++++++++++++++++---------------------------
 1 files changed, 343 insertions(+), 328 deletions(-)
---
diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c
index 4f97458..27368cc 100644
--- a/gtk/gtkentry.c
+++ b/gtk/gtkentry.c
@@ -143,8 +143,6 @@ struct _GtkEntryPrivate
   GtkIMContext          *im_context;
   GtkWidget             *popup_menu;
 
-  GdkDevice             *device;
-
   GdkWindow             *text_area;
 
   PangoLayout           *cached_layout;
@@ -167,6 +165,9 @@ struct _GtkEntryPrivate
   GtkWidget     *magnifier_popover;
   GtkWidget     *magnifier;
 
+  GtkGesture    *drag_gesture;
+  GtkGesture    *multipress_gesture;
+
   gfloat        xalign;
 
   gint          ascent;                     /* font ascent in pango units  */
@@ -185,7 +186,6 @@ struct _GtkEntryPrivate
 
   gunichar      invisible_char;
 
-  guint         button;
   guint         blink_time;                  /* time in msec the cursor has blinked since last user event */
   guint         blink_timeout;
   guint         recompute_idle;
@@ -385,16 +385,12 @@ static void   gtk_entry_draw_progress        (GtkWidget        *widget,
                                               cairo_t          *cr);
 static gint   gtk_entry_draw                 (GtkWidget        *widget,
                                               cairo_t          *cr);
-static gint   gtk_entry_button_press         (GtkWidget        *widget,
-                                             GdkEventButton   *event);
-static gint   gtk_entry_button_release       (GtkWidget        *widget,
-                                             GdkEventButton   *event);
+static gboolean gtk_entry_event              (GtkWidget        *widget,
+                                              GdkEvent         *event);
 static gint   gtk_entry_enter_notify         (GtkWidget        *widget,
                                               GdkEventCrossing *event);
 static gint   gtk_entry_leave_notify         (GtkWidget        *widget,
                                               GdkEventCrossing *event);
-static gint   gtk_entry_motion_notify        (GtkWidget        *widget,
-                                             GdkEventMotion   *event);
 static gint   gtk_entry_key_press            (GtkWidget        *widget,
                                              GdkEventKey      *event);
 static gint   gtk_entry_key_release          (GtkWidget        *widget,
@@ -524,6 +520,21 @@ static gboolean gtk_entry_delete_surrounding_cb   (GtkIMContext *context,
                                                   gint          n_chars,
                                                   GtkEntry     *entry);
 
+/* Event controller callbacks */
+static void   gtk_entry_multipress_gesture_pressed (GtkGestureMultiPress *gesture,
+                                                    gint                  n_press,
+                                                    gdouble               x,
+                                                    gdouble               y,
+                                                    GtkEntry             *entry);
+static void   gtk_entry_drag_gesture_update        (GtkGestureDrag *gesture,
+                                                    gdouble         offset_x,
+                                                    gdouble         offset_y,
+                                                    GtkEntry       *entry);
+static void   gtk_entry_drag_gesture_end           (GtkGestureDrag *gesture,
+                                                    gdouble         offset_x,
+                                                    gdouble         offset_y,
+                                                    GtkEntry       *entry);
+
 /* Internal routines
  */
 static void         gtk_entry_enter_text               (GtkEntry       *entry,
@@ -566,11 +577,9 @@ static void         gtk_entry_paste                    (GtkEntry       *entry,
                                                        GdkAtom         selection);
 static void         gtk_entry_update_primary_selection (GtkEntry       *entry);
 static void         gtk_entry_do_popup                 (GtkEntry       *entry,
-                                                       GdkEventButton *event);
+                                                       const GdkEvent *event);
 static gboolean     gtk_entry_mnemonic_activate        (GtkWidget      *widget,
                                                        gboolean        group_cycling);
-static void         gtk_entry_grab_notify              (GtkWidget      *widget,
-                                                        gboolean        was_grabbed);
 static void         gtk_entry_check_cursor_blink       (GtkEntry       *entry);
 static void         gtk_entry_pend_cursor_blink        (GtkEntry       *entry);
 static void         gtk_entry_reset_blink_time         (GtkEntry       *entry);
@@ -696,9 +705,7 @@ gtk_entry_class_init (GtkEntryClass *class)
   widget_class->draw = gtk_entry_draw;
   widget_class->enter_notify_event = gtk_entry_enter_notify;
   widget_class->leave_notify_event = gtk_entry_leave_notify;
-  widget_class->button_press_event = gtk_entry_button_press;
-  widget_class->button_release_event = gtk_entry_button_release;
-  widget_class->motion_notify_event = gtk_entry_motion_notify;
+  widget_class->event = gtk_entry_event;
   widget_class->key_press_event = gtk_entry_key_press;
   widget_class->key_release_event = gtk_entry_key_release;
   widget_class->focus_in_event = gtk_entry_focus_in;
@@ -712,7 +719,6 @@ gtk_entry_class_init (GtkEntryClass *class)
   widget_class->state_flags_changed = gtk_entry_state_flags_changed;
   widget_class->screen_changed = gtk_entry_screen_changed;
   widget_class->mnemonic_activate = gtk_entry_mnemonic_activate;
-  widget_class->grab_notify = gtk_entry_grab_notify;
 
   widget_class->drag_drop = gtk_entry_drag_drop;
   widget_class->drag_motion = gtk_entry_drag_motion;
@@ -2687,6 +2693,22 @@ gtk_entry_init (GtkEntry *entry)
   gtk_style_context_add_class (context, GTK_STYLE_CLASS_ENTRY);
 
   gtk_entry_update_cached_style_values (entry);
+
+  priv->drag_gesture = gtk_gesture_drag_new (GTK_WIDGET (entry));
+  g_signal_connect (priv->drag_gesture, "drag-update",
+                    G_CALLBACK (gtk_entry_drag_gesture_update), entry);
+  g_signal_connect (priv->drag_gesture, "drag-end",
+                    G_CALLBACK (gtk_entry_drag_gesture_end), entry);
+  gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (priv->drag_gesture), FALSE);
+  gtk_gesture_single_set_exclusive (GTK_GESTURE_SINGLE (priv->drag_gesture), TRUE);
+  gtk_gesture_attach (priv->drag_gesture, GTK_PHASE_TARGET);
+
+  priv->multipress_gesture = gtk_gesture_multi_press_new (GTK_WIDGET (entry));
+  g_signal_connect (priv->multipress_gesture, "pressed",
+                    G_CALLBACK (gtk_entry_multipress_gesture_pressed), entry);
+  gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (priv->multipress_gesture), FALSE);
+  gtk_gesture_single_set_exclusive (GTK_GESTURE_SINGLE (priv->multipress_gesture), TRUE);
+  gtk_gesture_attach (priv->multipress_gesture, GTK_PHASE_TARGET);
 }
 
 static void
@@ -4178,289 +4200,292 @@ gtk_entry_update_handles (GtkEntry          *entry,
                            cursor, 0, height);
 }
 
-static gint
-gtk_entry_button_press (GtkWidget      *widget,
-                       GdkEventButton *event)
+static gboolean
+gtk_entry_event (GtkWidget *widget,
+                 GdkEvent  *event)
 {
-  GtkEntry *entry = GTK_ENTRY (widget);
-  GtkEditable *editable = GTK_EDITABLE (widget);
-  GtkEntryPrivate *priv = entry->priv;
+  GtkEntryPrivate *priv = GTK_ENTRY (widget)->priv;
   EntryIconInfo *icon_info = NULL;
-  gint tmp_pos;
-  gint sel_start, sel_end;
   gint i;
 
-  gtk_entry_selection_bubble_popup_unset (entry);
-
-  for (i = 0; i < MAX_ICONS; i++)
+  if (event->type == GDK_MOTION_NOTIFY &&
+      priv->mouse_cursor_obscured &&
+      event->any.window == priv->text_area)
     {
-      icon_info = priv->icons[i];
+      GdkCursor *cursor;
 
-      if (!icon_info || icon_info->insensitive)
-        continue;
+      cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), GDK_XTERM);
+      gdk_window_set_cursor (priv->text_area, cursor);
+      g_object_unref (cursor);
+      priv->mouse_cursor_obscured = FALSE;
+      return GDK_EVENT_PROPAGATE;
+    }
 
-      if (event->window == icon_info->window)
+  for (i = 0; i < MAX_ICONS; i++)
+    {
+      if (priv->icons[i] &&
+          priv->icons[i]->window == event->any.window)
         {
-          if (should_prelight (entry, i))
-            {
-              icon_info->prelight = FALSE;
-              gtk_widget_queue_draw (widget);
-            }
+          icon_info = priv->icons[i];
+          break;
+        }
+    }
 
-          priv->start_x = event->x;
-          priv->start_y = event->y;
-          icon_info->pressed = TRUE;
+  if (!icon_info)
+    return GDK_EVENT_PROPAGATE;
 
-          if (!icon_info->nonactivatable)
-            g_signal_emit (entry, signals[ICON_PRESS], 0, i, event);
+  if (icon_info->insensitive)
+    return GDK_EVENT_STOP;
 
-          return TRUE;
+  switch (event->type)
+    {
+    case GDK_BUTTON_PRESS:
+    case GDK_2BUTTON_PRESS:
+    case GDK_3BUTTON_PRESS:
+      if (should_prelight (GTK_ENTRY (widget), i))
+        {
+          icon_info->prelight = FALSE;
+          gtk_widget_queue_draw (widget);
         }
-    }
 
-  if (event->window != priv->text_area ||
-      (priv->button && event->button != priv->button))
-    return FALSE;
+      priv->start_x = event->button.x;
+      priv->start_y = event->button.y;
+      icon_info->pressed = TRUE;
 
-  gtk_entry_reset_blink_time (entry);
+      if (!icon_info->nonactivatable)
+        g_signal_emit (widget, signals[ICON_PRESS], 0, i, event);
 
-  priv->button = event->button;
-  priv->device = gdk_event_get_device ((GdkEvent *) event);
+      break;
+    case GDK_MOTION_NOTIFY:
+      if (icon_info->pressed &&
+          icon_info->target_list != NULL &&
+              gtk_drag_check_threshold (widget,
+                                        priv->start_x,
+                                        priv->start_y,
+                                        event->motion.x,
+                                        event->motion.y))
+        {
+          icon_info->in_drag = TRUE;
+          icon_info->pressed = FALSE;
+          gtk_drag_begin_with_coordinates (widget,
+                                           icon_info->target_list,
+                                           icon_info->actions,
+                                           1,
+                                           event,
+                                           priv->start_x,
+                                           priv->start_y);
+        }
 
-  if (!gtk_widget_has_focus (widget))
-    {
-      priv->in_click = TRUE;
-      gtk_widget_grab_focus (widget);
-      priv->in_click = FALSE;
-    }
+      break;
+    case GDK_BUTTON_RELEASE:
+      icon_info->pressed = FALSE;
 
-  tmp_pos = gtk_entry_find_position (entry, event->x + priv->scroll_offset);
+      if (should_prelight (GTK_ENTRY (widget), i) &&
+          event->button.x >= 0 && event->button.y >= 0 &&
+          event->button.x < gdk_window_get_width (icon_info->window) &&
+          event->button.y < gdk_window_get_height (icon_info->window))
+        {
+          icon_info->prelight = TRUE;
+          gtk_widget_queue_draw (widget);
+        }
 
-  if (gdk_event_triggers_context_menu ((GdkEvent *) event))
-    {
-      gtk_entry_do_popup (entry, event);
-      priv->button = 0; /* Don't wait for release, since the menu will gtk_grab_add */
-      priv->device = NULL;
+      if (!icon_info->nonactivatable)
+        g_signal_emit (widget, signals[ICON_RELEASE], 0, i, event);
 
-      return TRUE;
+      break;
+    default:
+      return GDK_EVENT_PROPAGATE;
     }
-  else if (event->button == GDK_BUTTON_PRIMARY)
-    {
-      gboolean have_selection = gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end);
-      gboolean is_touchscreen;
-      GdkDevice *source;
 
-      source = gdk_event_get_source_device ((GdkEvent *) event);
-      is_touchscreen = test_touchscreen ||
-        gdk_device_get_source (source) == GDK_SOURCE_TOUCHSCREEN;
+  return GDK_EVENT_STOP;
+}
 
-      if (is_touchscreen)
-        gtk_entry_ensure_text_handles (entry);
+static void
+gesture_get_current_point (GtkGestureSingle *gesture,
+                           GtkEntry         *entry,
+                           gint             *x,
+                           gint             *y)
+{
+  GtkAllocation primary, secondary;
+  gint frame_x, frame_y, tx, ty;
+  GdkEventSequence *sequence;
+  gdouble px, py;
 
-      priv->select_words = FALSE;
-      priv->select_lines = FALSE;
+  sequence = gtk_gesture_single_get_current_sequence (gesture);
+  gtk_gesture_get_point (GTK_GESTURE (gesture), sequence, &px, &py);
+  get_text_area_size (entry, &tx, &ty, NULL, NULL);
+  get_icon_allocations (entry, &primary, &secondary);
+  get_frame_size (entry, FALSE, &frame_x, &frame_y, NULL, NULL);
 
-      if (event->state &
-          gtk_widget_get_modifier_mask (widget,
-                                        GDK_MODIFIER_INTENT_EXTEND_SELECTION))
-       {
-         gtk_entry_reset_im_context (entry);
+  if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL)
+    tx += secondary.width;
+  else
+    tx += primary.width;
 
-         if (!have_selection) /* select from the current position to the clicked position */
-           sel_start = sel_end = priv->current_pos;
+  tx += frame_x;
+  ty += frame_y;
 
-         if (tmp_pos > sel_start && tmp_pos < sel_end)
-           {
-             /* Truncate current selection, but keep it as big as possible */
-             if (tmp_pos - sel_start > sel_end - tmp_pos)
-               gtk_entry_set_positions (entry, sel_start, tmp_pos);
-             else
-               gtk_entry_set_positions (entry, tmp_pos, sel_end);
-           }
-         else
-           {
-             gboolean extend_to_left;
-             gint start, end;
+  if (x)
+    *x = px - tx;
+  if (y)
+    *y = py - ty;
+}
 
-             /* Figure out what click selects and extend current selection */
-             switch (event->type)
-               {
-               case GDK_BUTTON_PRESS:
-                 gtk_entry_set_positions (entry, tmp_pos, tmp_pos);
-                 break;
-                 
-               case GDK_2BUTTON_PRESS:
-                 priv->select_words = TRUE;
-                 gtk_entry_select_word (entry);
-                 break;
-                 
-               case GDK_3BUTTON_PRESS:
-                 priv->select_lines = TRUE;
-                 gtk_entry_select_line (entry);
-                 break;
-
-               default:
-                 break;
-               }
+static void
+gtk_entry_multipress_gesture_pressed (GtkGestureMultiPress *gesture,
+                                      gint                  n_press,
+                                      gdouble               widget_x,
+                                      gdouble               widget_y,
+                                      GtkEntry             *entry)
+{
+  GtkEditable *editable = GTK_EDITABLE (entry);
+  GtkWidget *widget = GTK_WIDGET (entry);
+  GtkEntryPrivate *priv = entry->priv;
+  GdkEventSequence *current;
+  const GdkEvent *event;
+  gint x, y, sel_start, sel_end;
+  guint button;
+  gint tmp_pos;
 
-             start = MIN (priv->current_pos, priv->selection_bound);
-             start = MIN (sel_start, start);
-             
-             end = MAX (priv->current_pos, priv->selection_bound);
-             end = MAX (sel_end, end);
+  gtk_entry_selection_bubble_popup_unset (entry);
 
-             if (tmp_pos == sel_start || tmp_pos == sel_end)
-               extend_to_left = (tmp_pos == start);
-             else
-               extend_to_left = (end == sel_end);
-             
-             if (extend_to_left)
-               gtk_entry_set_positions (entry, start, end);
-             else
-               gtk_entry_set_positions (entry, end, start);
-           }
-       }
-      else /* no shift key */
-       switch (event->type)
-       {
-       case GDK_BUTTON_PRESS:
-         if (in_selection (entry, event->x + priv->scroll_offset))
-           {
-             /* Click inside the selection - we'll either start a drag, or
-              * clear the selection
-              */
-             priv->in_drag = TRUE;
-             priv->drag_start_x = event->x + priv->scroll_offset;
-             priv->drag_start_y = event->y;
-           }
-         else
-            {
-              gtk_editable_set_position (editable, tmp_pos);
-              if (is_touchscreen)
-                gtk_entry_update_handles (entry, GTK_TEXT_HANDLE_MODE_NONE);
-            }
-         break;
- 
-       case GDK_2BUTTON_PRESS:
-         /* We ALWAYS receive a GDK_BUTTON_PRESS immediately before 
-          * receiving a GDK_2BUTTON_PRESS so we need to reset
-           * priv->in_drag which may have been set above
-           */
-         priv->in_drag = FALSE;
-         priv->select_words = TRUE;
-         gtk_entry_select_word (entry);
+  button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
+  current = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
+  event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), current);
 
-          if (is_touchscreen)
-            gtk_entry_update_handles (entry, GTK_TEXT_HANDLE_MODE_SELECTION);
-         break;
-       
-       case GDK_3BUTTON_PRESS:
-         /* We ALWAYS receive a GDK_BUTTON_PRESS immediately before
-          * receiving a GDK_3BUTTON_PRESS so we need to reset
-          * priv->in_drag which may have been set above
-          */
-         priv->in_drag = FALSE;
-         priv->select_lines = TRUE;
-         gtk_entry_select_line (entry);
-          if (is_touchscreen)
-            gtk_entry_update_handles (entry, GTK_TEXT_HANDLE_MODE_SELECTION);
-         break;
+  gtk_gesture_set_sequence_state (GTK_GESTURE (gesture), current,
+                                  GTK_EVENT_SEQUENCE_CLAIMED);
+  gesture_get_current_point (GTK_GESTURE_SINGLE (gesture), entry, &x, &y);
+  gtk_entry_reset_blink_time (entry);
 
-       default:
-         break;
-       }
+  if (!gtk_widget_has_focus (widget))
+    {
+      priv->in_click = TRUE;
+      gtk_widget_grab_focus (widget);
+      priv->in_click = FALSE;
+    }
 
-      return TRUE;
+  tmp_pos = gtk_entry_find_position (entry, x + priv->scroll_offset);
+
+  if (gdk_event_triggers_context_menu ((GdkEvent *) event))
+    {
+      gtk_entry_do_popup (entry, event);
     }
-  else if (event->type == GDK_BUTTON_PRESS &&
-           event->button == GDK_BUTTON_MIDDLE &&
+  else if (n_press == 1 && button == GDK_BUTTON_MIDDLE &&
            get_middle_click_paste (entry))
     {
       if (priv->editable)
         {
           priv->insert_pos = tmp_pos;
           gtk_entry_paste (entry, GDK_SELECTION_PRIMARY);
-          return TRUE;
         }
       else
         {
           gtk_widget_error_bell (widget);
         }
     }
+  else if (button == GDK_BUTTON_PRIMARY)
+    {
+      gboolean have_selection = gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end);
+      GtkTextHandleMode mode = GTK_TEXT_HANDLE_MODE_NONE;
+      gboolean is_touchscreen, extend_selection;
+      GdkDevice *source;
 
-  return FALSE;
-}
+      source = gdk_event_get_source_device (event);
+      is_touchscreen = test_touchscreen ||
+        gdk_device_get_source (source) == GDK_SOURCE_TOUCHSCREEN;
 
-static gint
-gtk_entry_button_release (GtkWidget      *widget,
-                         GdkEventButton *event)
-{
-  GtkEntry *entry = GTK_ENTRY (widget);
-  GtkEntryPrivate *priv = entry->priv;
-  EntryIconInfo *icon_info = NULL;
-  gboolean is_touchscreen;
-  GdkDevice *source;
-  gint i;
+      if (is_touchscreen)
+        gtk_entry_ensure_text_handles (entry);
 
-  for (i = 0; i < MAX_ICONS; i++)
-    {
-      icon_info = priv->icons[i];
+      priv->in_drag = FALSE;
+      priv->select_words = FALSE;
+      priv->select_lines = FALSE;
 
-      if (!icon_info || icon_info->insensitive)
-        continue;
+      extend_selection =
+        (event->button.state &
+         gtk_widget_get_modifier_mask (widget,
+                                       GDK_MODIFIER_INTENT_EXTEND_SELECTION));
 
-      if (event->window == icon_info->window)
+      switch (n_press)
         {
-          icon_info->pressed = FALSE;
-
-          if (should_prelight (entry, i) &&
-              event->x >= 0 && event->y >= 0 &&
-              event->x < gdk_window_get_width (icon_info->window) &&
-              event->y < gdk_window_get_height (icon_info->window))
+        case 1:
+          if (in_selection (entry, x + priv->scroll_offset))
             {
-              icon_info->prelight = TRUE;
-              gtk_widget_queue_draw (widget);
+              /* Click inside the selection - we'll either start a drag, or
+               * clear the selection
+               */
+              priv->in_drag = TRUE;
+              priv->drag_start_x = x + priv->scroll_offset;
+              priv->drag_start_y = y;
             }
+          else if (!extend_selection)
+            {
+              gtk_editable_set_position (editable, tmp_pos);
+            }
+          else
+            {
+              gtk_entry_reset_im_context (entry);
+
+              if (!have_selection) /* select from the current position to the clicked position */
+                sel_start = sel_end = priv->current_pos;
 
-          if (!icon_info->nonactivatable)
-            g_signal_emit (entry, signals[ICON_RELEASE], 0, i, event);
+              if (tmp_pos > sel_start && tmp_pos < sel_end)
+                {
+                  /* Truncate current selection, but keep it as big as possible */
+                  if (tmp_pos - sel_start > sel_end - tmp_pos)
+                            gtk_entry_set_positions (entry, sel_start, tmp_pos);
+                  else
+                            gtk_entry_set_positions (entry, tmp_pos, sel_end);
+                }
+            }
 
-          return TRUE;
+          break;
+        case 2:
+          priv->select_words = TRUE;
+          gtk_entry_select_word (entry);
+          mode = GTK_TEXT_HANDLE_MODE_SELECTION;
+          break;
+        case 3:
+          priv->select_lines = TRUE;
+          gtk_entry_select_line (entry);
+          mode = GTK_TEXT_HANDLE_MODE_SELECTION;
+          break;
+        default:
+          break;
         }
-    }
 
-  if (event->window != priv->text_area || priv->button != event->button)
-    return FALSE;
+      if (extend_selection)
+        {
+          gboolean extend_to_left;
+          gint start, end;
 
-  source = gdk_event_get_source_device ((GdkEvent *) event);
-  is_touchscreen = (test_touchscreen ||
-                    gdk_device_get_source (source) == GDK_SOURCE_TOUCHSCREEN);
+          start = MIN (priv->current_pos, priv->selection_bound);
+          start = MIN (sel_start, start);
 
-  if (priv->in_drag)
-    {
-      gint tmp_pos = gtk_entry_find_position (entry, priv->drag_start_x);
+          end = MAX (priv->current_pos, priv->selection_bound);
+          end = MAX (sel_end, end);
 
-      gtk_editable_set_position (GTK_EDITABLE (entry), tmp_pos);
+          if (tmp_pos == sel_start || tmp_pos == sel_end)
+            extend_to_left = (tmp_pos == start);
+          else
+            extend_to_left = (end == sel_end);
 
-      if (is_touchscreen)
-        gtk_entry_update_handles (entry, GTK_TEXT_HANDLE_MODE_CURSOR);
+          if (extend_to_left)
+            gtk_entry_set_positions (entry, start, end);
+          else
+            gtk_entry_set_positions (entry, end, start);
+        }
 
-      priv->in_drag = 0;
-    }
-  else if (is_touchscreen)
-    {
-      gtk_entry_update_handles (entry, GTK_TEXT_HANDLE_MODE_CURSOR);
-      gtk_entry_selection_bubble_popup_set (entry);
-      if (priv->magnifier_popover)
-        gtk_widget_hide (priv->magnifier_popover);
-    }
+      gtk_gesture_set_state (priv->drag_gesture,
+                             GTK_EVENT_SEQUENCE_CLAIMED);
 
-  priv->button = 0;
-  priv->device = NULL;
+      if (is_touchscreen)
+        gtk_entry_update_handles (entry, mode);
+    }
 
-  gtk_entry_update_primary_selection (entry);
-             
-  return TRUE;
+  if (n_press >= 3)
+    gtk_event_controller_reset (GTK_EVENT_CONTROLLER (gesture));
 }
 
 static gchar *
@@ -4508,47 +4533,21 @@ gtk_entry_show_magnifier (GtkEntry *entry,
   gtk_widget_show (priv->magnifier_popover);
 }
 
-static gint
-gtk_entry_motion_notify (GtkWidget      *widget,
-                        GdkEventMotion *event)
+static void
+gtk_entry_drag_gesture_update (GtkGestureDrag *gesture,
+                               gdouble         offset_x,
+                               gdouble         offset_y,
+                               GtkEntry       *entry)
 {
-  GtkEntry *entry = GTK_ENTRY (widget);
+  GtkWidget *widget = GTK_WIDGET (entry);
   GtkEntryPrivate *priv = entry->priv;
-  EntryIconInfo *icon_info = NULL;
-  gint tmp_pos;
-  gint i;
-
-  for (i = 0; i < MAX_ICONS; i++)
-    {
-      icon_info = priv->icons[i];
-
-      if (!icon_info || icon_info->insensitive)
-        continue;
-
-      if (event->window == icon_info->window)
-        {
-          if (icon_info->pressed &&
-              icon_info->target_list != NULL &&
-              gtk_drag_check_threshold (widget,
-                                        priv->start_x,
-                                        priv->start_y,
-                                        event->x,
-                                        event->y))
-            {
-              icon_info->in_drag = TRUE;
-              icon_info->pressed = FALSE;
-              gtk_drag_begin_with_coordinates (widget,
-                                               icon_info->target_list,
-                                               icon_info->actions,
-                                               1,
-                                               (GdkEvent*)event,
-                                               priv->start_x,
-                                               priv->start_y);
-            }
+  GdkEventSequence *sequence;
+  const GdkEvent *event;
+  gint x, y;
 
-          return TRUE;
-        }
-    }
+  gesture_get_current_point (GTK_GESTURE_SINGLE (gesture), entry, &x, &y);
+  sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
+  event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
 
   if (priv->mouse_cursor_obscured)
     {
@@ -4560,20 +4559,15 @@ gtk_entry_motion_notify (GtkWidget      *widget,
       priv->mouse_cursor_obscured = FALSE;
     }
 
-  if (event->window != priv->text_area || priv->button != GDK_BUTTON_PRIMARY)
-    return FALSE;
-
   if (priv->select_lines)
-    return TRUE;
-
-  gdk_event_request_motions (event);
+    return;
 
   if (priv->in_drag)
     {
       if (gtk_entry_get_display_mode (entry) == DISPLAY_NORMAL &&
           gtk_drag_check_threshold (widget,
                                     priv->drag_start_x, priv->drag_start_y,
-                                    event->x + priv->scroll_offset, event->y))
+                                    x + priv->scroll_offset, y))
         {
           gint *ranges;
           gint n_ranges;
@@ -4582,6 +4576,7 @@ gtk_entry_motion_notify (GtkWidget      *widget,
           guint actions = priv->editable ? GDK_ACTION_COPY | GDK_ACTION_MOVE : GDK_ACTION_COPY;
           gchar *text = NULL;
           cairo_surface_t *surface;
+          guint button;
 
           gtk_target_list_add_text_targets (target_list, 0);
 
@@ -4593,8 +4588,9 @@ gtk_entry_motion_notify (GtkWidget      *widget,
                                            -(priv->drag_start_x - ranges[0]),
                                            -(priv->drag_start_y));
 
+          button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
           context = gtk_drag_begin_with_coordinates (widget, target_list, actions,
-                                                     priv->button, (GdkEvent *)event,
+                                                     button, (GdkEvent*) event,
                                                      priv->drag_start_x + ranges[0],
                                                      priv->drag_start_y);
           g_free (ranges);
@@ -4603,14 +4599,12 @@ gtk_entry_motion_notify (GtkWidget      *widget,
             gtk_drag_set_icon_surface (context, surface);
           else
             gtk_drag_set_icon_default (context);
-          
+
           if (surface)
             cairo_surface_destroy (surface);
           g_free (text);
 
           priv->in_drag = FALSE;
-          priv->button = 0;
-          priv->device = NULL;
 
           gtk_target_list_unref (target_list);
         }
@@ -4620,17 +4614,18 @@ gtk_entry_motion_notify (GtkWidget      *widget,
       GdkInputSource input_source;
       GdkDevice *source;
       guint length;
+      gint tmp_pos;
 
       length = gtk_entry_buffer_get_length (get_buffer (entry));
 
-      if (event->y < 0)
+      if (y < 0)
        tmp_pos = 0;
-      else if (event->y >= gdk_window_get_height (priv->text_area))
+      else if (y >= gdk_window_get_height (priv->text_area))
        tmp_pos = length;
       else
-       tmp_pos = gtk_entry_find_position (entry, event->x + priv->scroll_offset);
+       tmp_pos = gtk_entry_find_position (entry, x + priv->scroll_offset);
 
-      source = gdk_event_get_source_device ((GdkEvent *) event);
+      source = gdk_event_get_source_device (event);
       input_source = gdk_device_get_source (source);
 
       if (priv->select_words)
@@ -4638,32 +4633,32 @@ gtk_entry_motion_notify (GtkWidget      *widget,
          gint min, max;
          gint old_min, old_max;
          gint pos, bound;
-         
+
          min = gtk_entry_move_backward_word (entry, tmp_pos, TRUE);
          max = gtk_entry_move_forward_word (entry, tmp_pos, TRUE);
 
          pos = priv->current_pos;
          bound = priv->selection_bound;
 
-         old_min = MIN(priv->current_pos, priv->selection_bound);
-         old_max = MAX(priv->current_pos, priv->selection_bound);
-         
+         old_min = MIN (priv->current_pos, priv->selection_bound);
+         old_max = MAX (priv->current_pos, priv->selection_bound);
+
          if (min < old_min)
            {
              pos = min;
              bound = old_max;
            }
-         else if (old_max < max) 
+         else if (old_max < max)
            {
              pos = max;
              bound = old_min;
            }
-         else if (pos == old_min) 
+         else if (pos == old_min)
            {
              if (priv->current_pos != min)
                pos = max;
            }
-         else 
+         else
            {
              if (priv->current_pos != max)
                pos = min;
@@ -4677,22 +4672,59 @@ gtk_entry_motion_notify (GtkWidget      *widget,
       /* Update touch handles' position */
       if (test_touchscreen || input_source == GDK_SOURCE_TOUCHSCREEN)
         {
-          gint x, y;
-
           gtk_entry_ensure_text_handles (entry);
           gtk_entry_update_handles (entry,
                                     (priv->current_pos == priv->selection_bound) ?
                                     GTK_TEXT_HANDLE_MODE_CURSOR :
                                     GTK_TEXT_HANDLE_MODE_SELECTION);
-
-          gtk_entry_get_text_area_size (entry, &x, &y, NULL, NULL);
-          x += event->x;
-          y += event->y;
           gtk_entry_show_magnifier (entry, x, y);
         }
     }
+}
 
-  return TRUE;
+static void
+gtk_entry_drag_gesture_end (GtkGestureDrag *gesture,
+                            gdouble         offset_x,
+                            gdouble         offset_y,
+                            GtkEntry       *entry)
+{
+  GtkEntryPrivate *priv = entry->priv;
+  gboolean in_drag, is_touchscreen;
+  GdkEventSequence *sequence;
+  const GdkEvent *event;
+  GdkDevice *source;
+
+  sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
+  in_drag = priv->in_drag;
+  priv->in_drag = FALSE;
+
+  if (priv->magnifier_popover)
+    gtk_widget_hide (priv->magnifier_popover);
+
+  /* Check whether the drag was cancelled rather than finished */
+  if (!gtk_gesture_handles_sequence (GTK_GESTURE (gesture), sequence))
+    return;
+
+  event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
+  source = gdk_event_get_source_device (event);
+  is_touchscreen = (test_touchscreen ||
+                    gdk_device_get_source (source) == GDK_SOURCE_TOUCHSCREEN);
+
+  if (in_drag)
+    {
+      gint tmp_pos = gtk_entry_find_position (entry, priv->drag_start_x);
+
+      gtk_editable_set_position (GTK_EDITABLE (entry), tmp_pos);
+
+      if (is_touchscreen)
+        gtk_entry_update_handles (entry, GTK_TEXT_HANDLE_MODE_CURSOR);
+    }
+  else if (is_touchscreen)
+    {
+      gtk_entry_selection_bubble_popup_set (entry);
+    }
+
+  gtk_entry_update_primary_selection (entry);
 }
 
 static void
@@ -7147,8 +7179,11 @@ paste_received (GtkClipboard *clipboard,
   GtkEntry *entry = GTK_ENTRY (data);
   GtkEditable *editable = GTK_EDITABLE (entry);
   GtkEntryPrivate *priv = entry->priv;
+  guint button;
 
-  if (priv->button == GDK_BUTTON_MIDDLE)
+  button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (priv->multipress_gesture));
+
+  if (button == GDK_BUTTON_MIDDLE)
     {
       gint pos, start, end;
       pos = priv->insert_pos;
@@ -9315,26 +9350,6 @@ gtk_entry_mnemonic_activate (GtkWidget *widget,
 }
 
 static void
-gtk_entry_grab_notify (GtkWidget *widget,
-                       gboolean   was_grabbed)
-{
-  GtkEntryPrivate *priv;
-
-  priv = GTK_ENTRY (widget)->priv;
-
-  if (priv->device &&
-      gtk_widget_device_is_shadowed (widget, priv->device))
-    {
-      /* Unset button so we don't expect
-       * a button release anymore
-       */
-      priv->button = 0;
-      priv->device = NULL;
-      priv->in_drag = FALSE;
-    }
-}
-
-static void
 append_action_signal (GtkEntry     *entry,
                      GtkWidget    *menu,
                      const gchar  *label,
@@ -9415,7 +9430,7 @@ popup_position_func (GtkMenu   *menu,
 typedef struct
 {
   GtkEntry *entry;
-  gint button;
+  guint button;
   guint time;
   GdkDevice *device;
 } PopupInfo;
@@ -9497,7 +9512,7 @@ popup_targets_received (GtkClipboard     *clipboard,
 
 static void
 gtk_entry_do_popup (GtkEntry       *entry,
-                    GdkEventButton *event)
+                    const GdkEvent *event)
 {
   PopupInfo *info = g_slice_new (PopupInfo);
 
@@ -9509,9 +9524,9 @@ gtk_entry_do_popup (GtkEntry       *entry,
   
   if (event)
     {
-      info->button = event->button;
-      info->time = event->time;
-      info->device = event->device;
+      gdk_event_get_button (event, &info->button);
+      info->time = gdk_event_get_time (event);
+      info->device = gdk_event_get_device (event);
     }
   else
     {


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