[gtk+/gestures] textview: Use GtkGestureMultiPress for click handling



commit d86cfdc5df7234c0dd5bc099c7cbe21c27336f05
Author: Carlos Garnacho <carlosg gnome org>
Date:   Wed May 7 13:15:30 2014 +0200

    textview: Use GtkGestureMultiPress for click handling
    
    The button press handler is no longer necessary, and most of its
    code has been shuffled into the GtkGestureMultiPress::pressed
    handler.

 gtk/gtktextview.c |  252 +++++++++++++++++++++++++++++------------------------
 1 files changed, 138 insertions(+), 114 deletions(-)
---
diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c
index ffc1f50..08d8fa4 100644
--- a/gtk/gtktextview.c
+++ b/gtk/gtktextview.c
@@ -208,6 +208,8 @@ struct _GtkTextViewPrivate
 
   GtkPixelCache *pixel_cache;
 
+  GtkGesture *multipress_gesture;
+
   /* Default style settings */
   gint pixels_above_lines;
   gint pixels_below_lines;
@@ -259,6 +261,13 @@ struct _GtkTextPendingScroll
   gdouble        yalign;
 };
 
+typedef enum 
+{
+  SELECT_CHARACTERS,
+  SELECT_WORDS,
+  SELECT_LINES
+} SelectionGranularity;
+
 enum
 {
   POPULATE_POPUP,
@@ -338,14 +347,18 @@ static void gtk_text_view_grab_notify          (GtkWidget        *widget,
 static void gtk_text_view_state_flags_changed  (GtkWidget        *widget,
                                                GtkStateFlags     previous_state);
 
+static void gtk_text_view_multipress_gesture_pressed (GtkGestureMultiPress *gesture,
+                                                      gint                  n_press,
+                                                      gdouble               x,
+                                                      gdouble               y,
+                                                      GtkTextView          *text_view);
+
 static gint gtk_text_view_event                (GtkWidget        *widget,
                                                 GdkEvent         *event);
 static gint gtk_text_view_key_press_event      (GtkWidget        *widget,
                                                 GdkEventKey      *event);
 static gint gtk_text_view_key_release_event    (GtkWidget        *widget,
                                                 GdkEventKey      *event);
-static gint gtk_text_view_button_press_event   (GtkWidget        *widget,
-                                                GdkEventButton   *event);
 static gint gtk_text_view_button_release_event (GtkWidget        *widget,
                                                 GdkEventButton   *event);
 static gint gtk_text_view_focus_in_event       (GtkWidget        *widget,
@@ -440,9 +453,10 @@ static void     gtk_text_view_set_attributes_from_style (GtkTextView        *tex
 static void     gtk_text_view_ensure_layout          (GtkTextView        *text_view);
 static void     gtk_text_view_destroy_layout         (GtkTextView        *text_view);
 static void     gtk_text_view_check_keymap_direction (GtkTextView        *text_view);
-static void     gtk_text_view_start_selection_drag   (GtkTextView        *text_view,
-                                                      const GtkTextIter  *iter,
-                                                      GdkEventButton     *event);
+static void     gtk_text_view_start_selection_drag   (GtkTextView          *text_view,
+                                                      const GtkTextIter    *iter,
+                                                      SelectionGranularity  granularity,
+                                                      const GdkEvent       *event);
 static gboolean gtk_text_view_end_selection_drag     (GtkTextView        *text_view);
 static void     gtk_text_view_start_selection_dnd    (GtkTextView        *text_view,
                                                       const GtkTextIter  *iter,
@@ -489,7 +503,7 @@ static void gtk_text_view_set_virtual_cursor_pos (GtkTextView       *text_view,
                                                   gint               y);
 
 static void gtk_text_view_do_popup               (GtkTextView       *text_view,
-                                                 GdkEventButton    *event);
+                                                 const GdkEvent    *event);
 
 static void cancel_pending_scroll                (GtkTextView   *text_view);
 static void gtk_text_view_queue_scroll           (GtkTextView   *text_view,
@@ -665,7 +679,6 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
   widget_class->event = gtk_text_view_event;
   widget_class->key_press_event = gtk_text_view_key_press_event;
   widget_class->key_release_event = gtk_text_view_key_release_event;
-  widget_class->button_press_event = gtk_text_view_button_press_event;
   widget_class->button_release_event = gtk_text_view_button_release_event;
   widget_class->focus_in_event = gtk_text_view_focus_in_event;
   widget_class->focus_out_event = gtk_text_view_focus_out_event;
@@ -1543,6 +1556,14 @@ gtk_text_view_init (GtkTextView *text_view)
 
   /* We handle all our own redrawing */
   gtk_widget_set_redraw_on_allocate (widget, FALSE);
+
+  priv->multipress_gesture = gtk_gesture_multi_press_new (widget);
+  gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (priv->multipress_gesture),
+                                     FALSE);
+  gtk_gesture_attach (priv->multipress_gesture, GTK_PHASE_BUBBLE);
+  g_signal_connect (priv->multipress_gesture, "pressed",
+                    G_CALLBACK (gtk_text_view_multipress_gesture_pressed),
+                    widget);
 }
 
 static void
@@ -3231,6 +3252,9 @@ gtk_text_view_finalize (GObject *object)
   
   cancel_pending_scroll (text_view);
 
+  gtk_gesture_detach (priv->multipress_gesture);
+  g_object_unref (priv->multipress_gesture);
+
   if (priv->tabs)
     pango_tab_array_free (priv->tabs);
   
@@ -5028,26 +5052,37 @@ gtk_text_view_key_release_event (GtkWidget *widget, GdkEventKey *event)
     return GTK_WIDGET_CLASS (gtk_text_view_parent_class)->key_release_event (widget, event);
 }
 
-static gint
-gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
+static void
+gtk_text_view_multipress_gesture_pressed (GtkGestureMultiPress *gesture,
+                                          gint                  n_press,
+                                          gdouble               x,
+                                          gdouble               y,
+                                          GtkTextView          *text_view)
 {
-  GtkTextView *text_view;
+  GdkEventSequence *sequence;
   GtkTextViewPrivate *priv;
-  GdkDevice *device;
+  const GdkEvent *event;
   gboolean is_touchscreen;
+  GdkDevice *device;
+  GtkTextIter iter;
+  guint button;
 
-  text_view = GTK_TEXT_VIEW (widget);
   priv = text_view->priv;
+  sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
+  button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
+  event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
 
-  gtk_widget_grab_focus (widget);
+  gtk_widget_grab_focus (GTK_WIDGET (text_view));
 
-  if (event->window != priv->text_window->bin_window)
+  if (gdk_event_get_window (event) != priv->text_window->bin_window)
     {
       /* Remove selection if any. */
       gtk_text_view_unselect (text_view);
-      return FALSE;
+      return;
     }
 
+  gtk_gesture_set_sequence_state (GTK_GESTURE (gesture), sequence,
+                                  GTK_EVENT_SEQUENCE_CLAIMED);
   gtk_text_view_reset_blink_time (text_view);
   gtk_text_view_selection_bubble_popup_unset (text_view);
 
@@ -5063,98 +5098,97 @@ gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
   is_touchscreen = test_touchscreen ||
                    gdk_device_get_source (device) == GDK_SOURCE_TOUCHSCREEN;
 
-  if (event->type == GDK_BUTTON_PRESS)
-    {
-      gtk_text_view_reset_im_context (text_view);
+  if (n_press == 1)
+    gtk_text_view_reset_im_context (text_view);
 
-      if (gdk_event_triggers_context_menu ((GdkEvent *) event))
-        {
-         gtk_text_view_do_popup (text_view, event);
-         return TRUE;
-        }
-      else if (event->button == GDK_BUTTON_PRIMARY)
-        {
-          /* If we're in the selection, start a drag copy/move of the
-           * selection; otherwise, start creating a new selection.
-           */
-          GtkTextIter iter;
-          GtkTextIter start, end;
+  if (n_press == 1 &&
+      gdk_event_triggers_context_menu (event))
+    {
+      gtk_text_view_do_popup (text_view, event);
+    }
+  else if (button == GDK_BUTTON_MIDDLE &&
+           get_middle_click_paste (text_view))
+    {
+      /* We do not want to scroll back to the insert iter when we paste
+         with the middle button */
+      priv->scroll_after_paste = FALSE;
 
-          gtk_text_layout_get_iter_at_pixel (priv->layout,
-                                             &iter,
-                                             event->x + priv->xoffset,
-                                             event->y + priv->yoffset);
-
-          if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
-                                                    &start, &end) &&
-              gtk_text_iter_in_range (&iter, &start, &end) &&
-              !(event->state &
-                gtk_widget_get_modifier_mask (widget,
-                                              GDK_MODIFIER_INTENT_EXTEND_SELECTION)))
-            {
-              priv->grab_device = event->device;
-              priv->drag_start_x = event->x;
-              priv->drag_start_y = event->y;
-              priv->pending_place_cursor_button = event->button;
-            }
-          else
-            {
-              gtk_text_view_start_selection_drag (text_view, &iter, event);
+      gtk_text_layout_get_iter_at_pixel (priv->layout,
+                                         &iter,
+                                         x + priv->xoffset,
+                                         y + priv->yoffset);
 
-              if (is_touchscreen)
-                {
-                  _gtk_text_view_ensure_text_handles (text_view);
-                  gtk_text_view_update_handles (text_view, GTK_TEXT_HANDLE_MODE_CURSOR);
-                }
-            }
+      gtk_text_buffer_paste_clipboard (get_buffer (text_view),
+                                       gtk_widget_get_clipboard (GTK_WIDGET (text_view),
+                                                                 GDK_SELECTION_PRIMARY),
+                                       &iter,
+                                       priv->editable);
+    }
+  else if (button == GDK_BUTTON_PRIMARY)
+    {
+      GtkTextHandleMode handle_mode = GTK_TEXT_HANDLE_MODE_NONE;
 
-          return TRUE;
-        }
-      else if (event->button == GDK_BUTTON_MIDDLE &&
-               get_middle_click_paste (text_view))
+      switch (n_press)
         {
-          GtkTextIter iter;
-
-          /* We do not want to scroll back to the insert iter when we paste
-             with the middle button */
-          priv->scroll_after_paste = FALSE;
+        case 1:
+          {
+            /* If we're in the selection, start a drag copy/move of the
+             * selection; otherwise, start creating a new selection.
+             */
+            GtkTextIter start, end;
+
+            handle_mode = GTK_TEXT_HANDLE_MODE_CURSOR;
+            gtk_text_layout_get_iter_at_pixel (priv->layout,
+                                               &iter,
+                                               x + priv->xoffset,
+                                               y + priv->yoffset);
+
+            if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
+                                                      &start, &end) &&
+                gtk_text_iter_in_range (&iter, &start, &end) &&
+                !(event->button.state &
+                  gtk_widget_get_modifier_mask (GTK_WIDGET (text_view),
+                                                GDK_MODIFIER_INTENT_EXTEND_SELECTION)))
+              {
+                priv->grab_device = gdk_event_get_device (event);
+                priv->drag_start_x = x;
+                priv->drag_start_y = y;
+                priv->pending_place_cursor_button = button;
+              }
+            else
+              {
+                gtk_text_view_start_selection_drag (text_view, &iter,
+                                                    SELECT_CHARACTERS, event);
+              }
+            break;
+          }
+        case 2:
+        case 3:
+          handle_mode = GTK_TEXT_HANDLE_MODE_SELECTION;
+          gtk_text_view_end_selection_drag (text_view);
 
           gtk_text_layout_get_iter_at_pixel (priv->layout,
                                              &iter,
-                                             event->x + priv->xoffset,
-                                             event->y + priv->yoffset);
+                                             x + priv->xoffset,
+                                             y + priv->yoffset);
 
-          gtk_text_buffer_paste_clipboard (get_buffer (text_view),
-                                          gtk_widget_get_clipboard (widget, GDK_SELECTION_PRIMARY),
-                                          &iter,
-                                          priv->editable);
-          return TRUE;
+          gtk_text_view_start_selection_drag (text_view, &iter,
+                                              n_press == 2 ? SELECT_WORDS : SELECT_LINES,
+                                              event);
+          break;
+        default:
+          break;
         }
-    }
-  else if ((event->type == GDK_2BUTTON_PRESS ||
-           event->type == GDK_3BUTTON_PRESS) &&
-          event->button == GDK_BUTTON_PRIMARY)
-    {
-      GtkTextIter iter;
-
-      gtk_text_view_end_selection_drag (text_view);
-
-      gtk_text_layout_get_iter_at_pixel (priv->layout,
-                                        &iter,
-                                        event->x + priv->xoffset,
-                                        event->y + priv->yoffset);
-
-      gtk_text_view_start_selection_drag (text_view, &iter, event);
 
       if (is_touchscreen)
         {
           _gtk_text_view_ensure_text_handles (text_view);
-          gtk_text_view_update_handles (text_view, GTK_TEXT_HANDLE_MODE_SELECTION);
+          gtk_text_view_update_handles (text_view, handle_mode);
         }
-      return TRUE;
     }
 
-  return FALSE;
+  if (n_press >= 3)
+    gtk_event_controller_reset (GTK_EVENT_CONTROLLER (gesture));
 }
 
 static gint
@@ -6904,13 +6938,6 @@ drag_scan_timeout (gpointer data)
   return TRUE;
 }
 
-typedef enum 
-{
-  SELECT_CHARACTERS,
-  SELECT_WORDS,
-  SELECT_LINES
-} SelectionGranularity;
-
 /*
  * Move @start and @end to the boundaries of the selection unit (indicated by 
  * @granularity) which contained @start initially.
@@ -7080,30 +7107,26 @@ selection_motion_event_handler (GtkTextView    *text_view,
 }
 
 static void
-gtk_text_view_start_selection_drag (GtkTextView       *text_view,
-                                    const GtkTextIter *iter,
-                                    GdkEventButton    *button)
+gtk_text_view_start_selection_drag (GtkTextView          *text_view,
+                                    const GtkTextIter    *iter,
+                                    SelectionGranularity  granularity,
+                                    const GdkEvent       *event)
 {
   GtkTextViewPrivate *priv;
   GtkTextIter cursor, ins, bound;
   GtkTextIter orig_start, orig_end;
   GtkTextBuffer *buffer;
   SelectionData *data;
+  GdkModifierType state;
 
   if (text_view->priv->selection_drag_handler != 0)
     return;
 
   priv = text_view->priv;
   data = g_new0 (SelectionData, 1);
+  data->granularity = granularity;
 
-  if (button->type == GDK_2BUTTON_PRESS)
-    data->granularity = SELECT_WORDS;
-  else if (button->type == GDK_3BUTTON_PRESS)
-    data->granularity = SELECT_LINES;
-  else 
-    data->granularity = SELECT_CHARACTERS;
-
-  priv->grab_device = button->device;
+  priv->grab_device = gdk_event_get_device (event);
   buffer = get_buffer (text_view);
   
   cursor = *iter;
@@ -7112,8 +7135,9 @@ gtk_text_view_start_selection_drag (GtkTextView       *text_view,
   extend_selection (text_view, data->granularity, &ins, &bound);
   orig_start = ins;
   orig_end = bound;
+  gdk_event_get_state (event, &state);
 
-  if (button->state &
+  if (state &
       gtk_widget_get_modifier_mask (GTK_WIDGET (text_view),
                                     GDK_MODIFIER_INTENT_EXTEND_SELECTION))
     {
@@ -8788,7 +8812,7 @@ popup_position_func (GtkMenu   *menu,
 typedef struct
 {
   GtkTextView *text_view;
-  gint button;
+  guint button;
   guint time;
   GdkDevice *device;
 } PopupInfo;
@@ -8910,7 +8934,7 @@ popup_targets_received (GtkClipboard     *clipboard,
 
 static void
 gtk_text_view_do_popup (GtkTextView    *text_view,
-                        GdkEventButton *event)
+                        const GdkEvent *event)
 {
   PopupInfo *info = g_new (PopupInfo, 1);
 
@@ -8922,9 +8946,9 @@ gtk_text_view_do_popup (GtkTextView    *text_view,
   
   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]