[gtk+/touchscreens: 19/65] gtk: Clean up press-and-hold code



commit 78a2a7a2cd5c0229b29806e8e5b2aa97566aa42e
Author: Carlos Garnacho <carlosg gnome org>
Date:   Tue Nov 1 12:19:19 2011 +0100

    gtk: Clean up press-and-hold code
    
    The press and hold animation now fully relies on style context
    transitions, finishing the p-a-h operation right after it
    finishes. There's also no need to connect to ::drag-begin as
    ::grab-notify will also tell when a grab begins.

 gtk/gtkwidget.c |  223 ++++++++++++++++++++++++++-----------------------------
 1 files changed, 104 insertions(+), 119 deletions(-)
---
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 4d2aba8..9071596 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -539,17 +539,16 @@ struct _GtkStateData
 
 typedef struct
 {
-  /* timeout */
-  guint press_and_hold_id;
+  /* The widget */
+  GtkWidget *widget;
 
   /* animation */
   GtkWidget *popup;
-  guint animation_id;
+  guint delay_animation_id;
 
   /* signal handlers */
   guint motion_id;
   guint button_release_id;
-  guint drag_begin_id;
   guint grab_notify_id;
 
   gint start_x;
@@ -667,12 +666,8 @@ static gboolean         gtk_widget_real_can_activate_accel      (GtkWidget *widg
 static void             gtk_widget_real_set_has_tooltip         (GtkWidget *widget,
 								 gboolean   has_tooltip,
 								 gboolean   force);
-static gboolean         gtk_widget_press_and_hold_cancel        (GtkWidget         *widget,
-                                                                 gpointer           unused,
-                                                                 PressAndHoldData  *data);
-static gboolean         gtk_widget_press_and_hold_button_press_event (GtkWidget      *widget,
-                                                                      GdkEventButton *button,
-                                                                      gpointer        user_data);
+static gboolean         gtk_widget_press_and_hold_start         (GtkWidget      *widget,
+                                                                 GdkEventButton *button);
 static void             gtk_widget_buildable_interface_init     (GtkBuildableIface *iface);
 static void             gtk_widget_buildable_set_name           (GtkBuildable     *buildable,
                                                                  const gchar      *name);
@@ -6003,9 +5998,12 @@ _gtk_widget_captured_event (GtkWidget *widget,
 
   g_object_ref (widget);
 
-  /* Make sure we always handle press and hold */
   if (event->type == GDK_BUTTON_PRESS)
-    gtk_widget_press_and_hold_button_press_event (widget, (GdkEventButton *)event, NULL);
+    {
+      /* Handle press and hold */
+      gtk_widget_press_and_hold_start (widget,
+                                       (GdkEventButton *)event);
+    }
 
   g_signal_emit (widget, widget_signals[CAPTURED_EVENT], 0, event, &return_val);
   return_val |= !WIDGET_REALIZED_FOR_EVENT (widget, event);
@@ -6875,11 +6873,17 @@ press_and_hold_data_free (PressAndHoldData *data)
   if (data->popup)
     gtk_widget_destroy (data->popup);
 
-  if (data->press_and_hold_id)
-    g_source_remove (data->press_and_hold_id);
+  if (data->delay_animation_id)
+    g_source_remove (data->delay_animation_id);
+
+  if (data->motion_id)
+    g_signal_handler_disconnect (data->widget, data->motion_id);
+
+  if (data->button_release_id)
+    g_signal_handler_disconnect (data->widget, data->button_release_id);
 
-  if (data->animation_id)
-    g_source_remove (data->animation_id);
+  if (data->grab_notify_id)
+    g_signal_handler_disconnect (data->widget, data->grab_notify_id);
 
   g_slice_free (PressAndHoldData, data);
 }
@@ -6903,39 +6907,31 @@ gtk_widget_get_press_and_hold_data (GtkWidget *widget)
   if (!data)
     {
       data = g_slice_new0 (PressAndHoldData);
+      data->widget = widget;
       gtk_widget_set_press_and_hold_data (widget, data);
     }
 
   return data;
 }
 
-static inline void
-gtk_widget_press_and_hold_finish (GtkWidget        *widget,
-                                  PressAndHoldData *data)
+static gboolean
+gtk_widget_press_and_hold_cancel (GtkWidget *widget)
 {
-  if (data->popup)
-    gtk_widget_destroy (data->popup);
-  data->popup = NULL;
-
-  if (data->motion_id)
-    g_signal_handler_disconnect (widget, data->motion_id);
-  data->motion_id = 0;
+  PressAndHoldData *data;
+  gboolean return_value;
 
-  if (data->button_release_id)
-    g_signal_handler_disconnect (widget, data->button_release_id);
-  data->button_release_id = 0;
+  data = gtk_widget_peek_press_and_hold_data (widget);
+  g_assert (data != NULL);
 
-  if (data->drag_begin_id)
-    g_signal_handler_disconnect (widget, data->drag_begin_id);
-  data->drag_begin_id = 0;
+  g_signal_emit (widget, widget_signals[PRESS_AND_HOLD],
+                 0,
+                 GTK_PRESS_AND_HOLD_CANCEL,
+                 -1, -1,
+                 &return_value);
 
-  if (data->press_and_hold_id)
-    g_source_remove (data->press_and_hold_id);
-  data->press_and_hold_id = 0;
+  gtk_widget_set_press_and_hold_data (widget, NULL);
 
-  if (data->animation_id)
-    g_source_remove (data->animation_id);
-  data->animation_id = 0;
+  return FALSE;
 }
 
 static gboolean
@@ -6946,7 +6942,8 @@ gtk_widget_press_and_hold_button_release (GtkWidget        *widget,
   if (_event->type != GDK_BUTTON_RELEASE)
     return FALSE;
 
-  gtk_widget_press_and_hold_cancel (widget, NULL, data);
+  if (data->device == gdk_event_get_device (_event))
+    gtk_widget_press_and_hold_cancel (widget);
 
   return FALSE;
 }
@@ -6958,7 +6955,7 @@ gtk_widget_press_and_hold_grab_notify (GtkWidget        *widget,
 {
   if (data->device &&
       gtk_widget_device_is_shadowed (widget, data->device))
-    gtk_widget_press_and_hold_cancel (widget, NULL, data);
+    gtk_widget_press_and_hold_cancel (widget);
 }
 
 static gboolean
@@ -6967,18 +6964,16 @@ gtk_widget_press_and_hold_motion_notify (GtkWidget        *widget,
                                          PressAndHoldData *data)
 {
   GdkEventMotion *event;
+  GdkDevice *device;
 
   if (_event->type != GDK_MOTION_NOTIFY)
     return FALSE;
 
   event = (GdkEventMotion *)_event;
+  device = gdk_event_get_device (_event);
 
-  if (!data->press_and_hold_id)
-    {
-      gtk_widget_press_and_hold_finish (widget, data);
-
-      return FALSE;
-    }
+  if (data->device != device)
+    return FALSE;
 
   _gtk_widget_find_at_coords (event->window, event->x, event->y,
                               &data->current_x, &data->current_y);
@@ -6987,22 +6982,19 @@ gtk_widget_press_and_hold_motion_notify (GtkWidget        *widget,
   if (gtk_drag_check_threshold (widget, data->start_x, data->start_y,
                                 data->current_x, data->current_y))
     {
-      gtk_widget_press_and_hold_cancel (widget, NULL, data);
+      gtk_widget_press_and_hold_cancel (widget);
 
       return FALSE;
     }
 
   if (data->popup)
     {
-      gint x, y;
       guint cursor_size;
 
-      gdk_window_get_device_position (gdk_screen_get_root_window (gtk_widget_get_screen (widget)),
-                                      data->device, &x, &y, NULL);
       cursor_size = gdk_display_get_default_cursor_size (gtk_widget_get_display (widget));
       gtk_window_move (GTK_WINDOW (data->popup),
-                       x - cursor_size / 2,
-                       y - cursor_size / 2);
+                       event->x_root - cursor_size / 2,
+                       event->y_root - cursor_size / 2);
     }
 
   return FALSE;
@@ -7013,30 +7005,36 @@ gtk_widget_press_and_hold_timeout (gpointer user_data)
 {
   gboolean return_value;
   GtkWidget *widget = GTK_WIDGET (user_data);
-  PressAndHoldData *data = gtk_widget_peek_press_and_hold_data (widget);
+  PressAndHoldData *data;
 
-  /* Done, clean up and emit the trigger signal */
-  gtk_widget_press_and_hold_finish (widget, data);
-  _gtk_widget_grab_notify (widget, FALSE);
+  data = gtk_widget_peek_press_and_hold_data (widget);
+  g_assert (data != NULL);
 
+  /* Done, clean up and emit the trigger signal */
   g_signal_emit (widget, widget_signals[PRESS_AND_HOLD],
                  0,
                  GTK_PRESS_AND_HOLD_TRIGGER,
                  data->current_x, data->current_y,
                  &return_value);
 
+  gtk_widget_set_press_and_hold_data (widget, NULL);
+
   return FALSE;
 }
 
 static gboolean
-press_and_hold_animation_draw (GtkWidget        *widget,
-                               cairo_t          *cr,
-                               PressAndHoldData *data)
+press_and_hold_animation_draw (GtkWidget *widget,
+                               cairo_t   *cr,
+                               gpointer   user_data)
 {
+  PressAndHoldData *data;
   GtkStyleContext *context;
   GtkStateFlags state;
   gint width, height;
 
+  data = gtk_widget_peek_press_and_hold_data (GTK_WIDGET (user_data));
+  g_assert (data != NULL);
+
   width = gtk_widget_get_allocated_width (widget);
   height = gtk_widget_get_allocated_height (widget);
 
@@ -7044,6 +7042,17 @@ press_and_hold_animation_draw (GtkWidget        *widget,
   state = gtk_widget_get_state_flags (widget);
   gtk_style_context_set_state (context, state);
 
+  if (!gtk_style_context_state_is_running (context, GTK_STATE_FLAG_ACTIVE, NULL))
+    {
+      /* The animation just finished, so hide the widget
+       * and finish the press and hold operation.
+       */
+      gdk_threads_add_idle (gtk_widget_press_and_hold_timeout,
+                            user_data);
+      gtk_widget_hide (widget);
+      return FALSE;
+    }
+
   if (!gtk_widget_is_composited (widget))
     {
       cairo_t *mask_cr;
@@ -7062,9 +7071,13 @@ press_and_hold_animation_draw (GtkWidget        *widget,
 
       cairo_surface_destroy (mask);
     }
-
-  cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
-  cairo_paint (cr);
+  else
+    {
+      cairo_save (cr);
+      cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+      cairo_paint (cr);
+      cairo_restore (cr);
+    }
 
   gtk_render_activity (context, cr, 0, 0, width, height);
 
@@ -7075,22 +7088,23 @@ static gboolean
 gtk_widget_press_and_hold_begin_animation_timeout (gpointer user_data)
 {
   GtkWidget *widget = GTK_WIDGET (user_data);
-  PressAndHoldData *data = gtk_widget_peek_press_and_hold_data (widget);
+  PressAndHoldData *data;
   gint x, y;
   guint cursor_size;
 
-  if (data->popup)
-    {
-      gtk_widget_set_state_flags (GTK_WIDGET (data->popup),
-                                  GTK_STATE_FLAG_ACTIVE, FALSE);
-      gdk_window_get_device_position (gdk_screen_get_root_window (gtk_widget_get_screen (widget)),
-                                      data->device, &x, &y, NULL);
-      cursor_size = gdk_display_get_default_cursor_size (gtk_widget_get_display (widget));
-      gtk_window_move (GTK_WINDOW (data->popup),
-                       x - cursor_size / 2,
-                       y - cursor_size / 2);
-      gtk_widget_show (data->popup);
-    }
+  data = gtk_widget_peek_press_and_hold_data (widget);
+  g_assert (data != NULL);
+
+  gdk_window_get_device_position (gdk_screen_get_root_window (gtk_widget_get_screen (widget)),
+                                  data->device, &x, &y, NULL);
+  cursor_size = gdk_display_get_default_cursor_size (gtk_widget_get_display (widget));
+  gtk_window_move (GTK_WINDOW (data->popup),
+                   x - cursor_size / 2,
+                   y - cursor_size / 2);
+  gtk_widget_show (data->popup);
+
+  gtk_widget_set_state_flags (GTK_WIDGET (data->popup),
+                              GTK_STATE_FLAG_ACTIVE, FALSE);
 
   return FALSE;
 }
@@ -7112,38 +7126,18 @@ gtk_widget_press_and_hold_query (GtkWidget *widget,
 }
 
 static gboolean
-gtk_widget_press_and_hold_cancel (GtkWidget        *widget,
-                                  gpointer          unused,
-                                  PressAndHoldData *data)
+gtk_widget_press_and_hold_start (GtkWidget      *widget,
+                                 GdkEventButton *event)
 {
-  gboolean return_value;
+  PressAndHoldData *data = gtk_widget_peek_press_and_hold_data (widget);
 
-  if (!data->press_and_hold_id)
+  /* Press and hold already in process? */
+  if (data)
     return FALSE;
 
-  gtk_widget_press_and_hold_finish (widget, data);
-
-  g_signal_emit (widget, widget_signals[PRESS_AND_HOLD],
-                 0,
-                 GTK_PRESS_AND_HOLD_CANCEL,
-                 -1, -1,
-                 &return_value);
-
-  return FALSE;
-}
+  data = gtk_widget_get_press_and_hold_data (widget);
 
-static gboolean
-gtk_widget_press_and_hold_button_press_event (GtkWidget      *widget,
-                                              GdkEventButton *event,
-                                              gpointer        user_data)
-{
-  PressAndHoldData *data = gtk_widget_get_press_and_hold_data (widget);
-
-  if (!data)
-    return FALSE;
-
-  if (gtk_widget_press_and_hold_query (widget, event->x, event->y)
-      && !data->press_and_hold_id)
+  if (gtk_widget_press_and_hold_query (widget, event->x, event->y))
     {
       gint timeout, begin_ani_timeout;
       GdkScreen *screen;
@@ -7178,7 +7172,7 @@ gtk_widget_press_and_hold_button_press_event (GtkWidget      *widget,
 
       g_signal_connect (data->popup, "draw",
                         G_CALLBACK (press_and_hold_animation_draw),
-                        data);
+                        widget);
 
       cursor_size = gdk_display_get_default_cursor_size (gtk_widget_get_display (widget));
       gtk_window_resize (GTK_WINDOW (data->popup), cursor_size, cursor_size);
@@ -7188,33 +7182,24 @@ gtk_widget_press_and_hold_button_press_event (GtkWidget      *widget,
       cairo_region_destroy (region);
 
       /* delay loading the animation by the double click timeout */
-      data->animation_id =
+      data->delay_animation_id =
         gdk_threads_add_timeout (begin_ani_timeout,
                                  gtk_widget_press_and_hold_begin_animation_timeout,
                                  widget);
 
       data->motion_id =
-              g_signal_connect (widget, "captured-event",
-                                G_CALLBACK (gtk_widget_press_and_hold_motion_notify),
-                                data);
+        g_signal_connect (widget, "captured-event",
+                          G_CALLBACK (gtk_widget_press_and_hold_motion_notify),
+                          data);
       data->button_release_id =
-              g_signal_connect (widget, "captured-event",
-                                G_CALLBACK (gtk_widget_press_and_hold_button_release),
-                                data);
-      data->drag_begin_id =
-              g_signal_connect (widget, "drag-begin",
-                                G_CALLBACK (gtk_widget_press_and_hold_cancel),
-                                data);
-
+        g_signal_connect (widget, "captured-event",
+                          G_CALLBACK (gtk_widget_press_and_hold_button_release),
+                          data);
       data->grab_notify_id =
         g_signal_connect (widget, "grab-notify",
                           G_CALLBACK (gtk_widget_press_and_hold_grab_notify),
                           data);
 
-      data->press_and_hold_id =
-              gdk_threads_add_timeout (timeout,
-                                       gtk_widget_press_and_hold_timeout,
-                                       widget);
       data->device = gdk_event_get_device ((GdkEvent *) event);
     }
 



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