[gtk+/multitouch-for-3.4: 6/89] scrolledwindow: Allow selections and drag-and-drop when kinetic scrolling is enabled



commit ccbd72dbe4dbbd8339a534daf8b631cf5fb09da8
Author: Carlos Garcia Campos <cgarcia igalia com>
Date:   Wed Mar 23 17:42:21 2011 +0100

    scrolledwindow: Allow selections and drag-and-drop when kinetic scrolling is enabled
    
    If the scrolling doesn't start after a long press, the scrolling is
    cancelled and events are handled by child widget normally.

 gtk/gtkscrolledwindow.c      |   67 +++++++++++++++++++++++++++++++++++++-----
 tests/testkineticscrolling.c |   64 ++++++++++++++++++++++++++++++++++++++--
 2 files changed, 120 insertions(+), 11 deletions(-)
---
diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
index c9a1ee1..8aaebc2 100644
--- a/gtk/gtkscrolledwindow.c
+++ b/gtk/gtkscrolledwindow.c
@@ -165,6 +165,7 @@ struct _GtkScrolledWindowPrivate
 
   /* Kinetic scrolling */
   GdkWindow             *event_window;
+  GdkEvent              *button_press_event;
   guint                  kinetic_scrolling_enabled : 1;
   guint                  in_drag                   : 1;
   guint                  hmoving                   : 1;
@@ -172,6 +173,7 @@ struct _GtkScrolledWindowPrivate
   guint                  button_press_id;
   guint                  motion_notify_id;
   guint                  button_release_id;
+  guint                  press_and_hold_id;
   MotionEventList        motion_events;
   GtkTimeline           *deceleration_timeline;
   gdouble                dx;
@@ -1104,9 +1106,9 @@ gtk_scrolled_window_set_kinetic_scrolling (GtkScrolledWindow *scrolled_window,
         gdk_window_show (priv->event_window);
       motion_event_list_init (&priv->motion_events, 3);
       priv->button_press_id =
-              g_signal_connect (scrolled_window, "captured_event",
-                                G_CALLBACK (gtk_scrolled_window_button_press_event),
-                                NULL);
+        g_signal_connect (scrolled_window, "captured-event",
+                          G_CALLBACK (gtk_scrolled_window_button_press_event),
+                          NULL);
     }
   else
     {
@@ -1140,6 +1142,11 @@ gtk_scrolled_window_set_kinetic_scrolling (GtkScrolledWindow *scrolled_window,
           g_signal_handler_disconnect (scrolled_window, priv->button_release_id);
           priv->button_release_id = 0;
         }
+      if (priv->press_and_hold_id > 0)
+        {
+          g_signal_handler_disconnect (scrolled_window, priv->press_and_hold_id);
+          priv->press_and_hold_id = 0;
+        }
       motion_event_list_clear (&priv->motion_events);
       if (priv->event_window)
         gdk_window_hide (priv->event_window);
@@ -1211,6 +1218,18 @@ gtk_scrolled_window_destroy (GtkWidget *widget)
       g_signal_handler_disconnect (widget, priv->button_release_id);
       priv->button_release_id = 0;
     }
+  if (priv->press_and_hold_id > 0)
+    {
+      g_signal_handler_disconnect (widget, priv->press_and_hold_id);
+      priv->press_and_hold_id = 0;
+    }
+
+  if (priv->button_press_event)
+    {
+      gdk_event_free (priv->button_press_event);
+      priv->button_press_event = NULL;
+    }
+
   motion_event_list_clear (&priv->motion_events);
 
   GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->destroy (widget);
@@ -2725,6 +2744,10 @@ gtk_scrolled_window_button_release_event (GtkWidget *widget,
   if (event->button != 1)
     return FALSE;
 
+  child = gtk_bin_get_child (GTK_BIN (widget));
+  if (!child)
+    return FALSE;
+
   gdk_device_ungrab (gdk_event_get_device (_event), event->time);
 
   if (priv->motion_notify_id > 0)
@@ -2739,11 +2762,31 @@ gtk_scrolled_window_button_release_event (GtkWidget *widget,
     }
 
   if (!priv->in_drag)
-    return FALSE;
+    {
+      /* There hasn't been scrolling at all, so just let the
+       * child widget handle the events normally
+       */
+      if (priv->button_press_event)
+        {
+          g_signal_handler_block (widget, priv->button_press_id);
+          gtk_main_do_event (priv->button_press_event);
+          g_signal_handler_unblock (widget, priv->button_press_id);
+          gdk_event_free (priv->button_press_event);
+          priv->button_press_event = NULL;
+          gtk_main_do_event (_event);
+
+          return TRUE;
+        }
 
-  child = gtk_bin_get_child (GTK_BIN (widget));
-  if (!child)
-    return FALSE;
+      return FALSE;
+    }
+  priv->in_drag = FALSE;
+
+  if (priv->button_press_event)
+    {
+      gdk_event_free (priv->button_press_event);
+      priv->button_press_event = NULL;
+    }
 
   distance = gtk_scrolled_window_get_deceleration_distance (scrolled_window, event->x_root, event->y_root);
   gtk_scrolled_window_start_deceleration (scrolled_window, distance);
@@ -2789,6 +2832,12 @@ gtk_scrolled_window_motion_notify_event (GtkWidget *widget,
         return FALSE;
     }
 
+  if (priv->button_press_event)
+    {
+      gdk_event_free (priv->button_press_event);
+      priv->button_press_event = NULL;
+    }
+
   motion = motion_event_list_last (&priv->motion_events);
 
   hadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
@@ -2885,7 +2934,9 @@ gtk_scrolled_window_button_press_event (GtkWidget *widget,
   else
     priv->in_drag = FALSE;
 
-  return FALSE;
+  priv->button_press_event = gdk_event_copy (_event);
+
+  return TRUE;
 }
 
 static gboolean
diff --git a/tests/testkineticscrolling.c b/tests/testkineticscrolling.c
index 693825a..6410ce5 100644
--- a/tests/testkineticscrolling.c
+++ b/tests/testkineticscrolling.c
@@ -1,5 +1,15 @@
 #include <gtk/gtk.h>
 
+enum
+{
+  TARGET_GTK_TREE_MODEL_ROW
+};
+
+static GtkTargetEntry row_targets[] =
+{
+  { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP, TARGET_GTK_TREE_MODEL_ROW }
+};
+
 static void
 on_button_clicked (GtkWidget *widget, gpointer data)
 {
@@ -12,6 +22,9 @@ kinetic_scrolling (void)
   GtkWidget *window, *swindow, *table;
   GtkWidget *label;
   GtkWidget *vbox, *button;
+  GtkWidget *treeview;
+  GtkCellRenderer *renderer;
+  GtkListStore *store;
   GtkWidget *textview;
   gint i;
 
@@ -20,18 +33,23 @@ kinetic_scrolling (void)
   g_signal_connect (window, "delete_event",
                     G_CALLBACK (gtk_main_quit), NULL);
 
-  table = gtk_table_new (2, 2, FALSE);
+  table = gtk_table_new (2, 3, FALSE);
 
   label = gtk_label_new ("Non scrollable widget using viewport");
   gtk_table_attach (GTK_TABLE (table), label,
                     0, 1, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
   gtk_widget_show (label);
 
-  label = gtk_label_new ("Scrollable widget");
+  label = gtk_label_new ("Scrollable widget: TreeView");
   gtk_table_attach (GTK_TABLE (table), label,
                     1, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
   gtk_widget_show (label);
 
+  label = gtk_label_new ("Scrollable widget: TextView");
+  gtk_table_attach (GTK_TABLE (table), label,
+                    2, 3, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
+  gtk_widget_show (label);
+
   vbox = gtk_vbox_new (FALSE, 1);
   for (i = 0; i < 80; i++)
     {
@@ -55,6 +73,46 @@ kinetic_scrolling (void)
                              0, 1, 1, 2);
   gtk_widget_show (swindow);
 
+  treeview = gtk_tree_view_new ();
+  gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (treeview),
+                                          GDK_BUTTON1_MASK,
+                                          row_targets,
+                                          G_N_ELEMENTS (row_targets),
+                                          GDK_ACTION_MOVE | GDK_ACTION_COPY);
+  gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (treeview),
+                                        row_targets,
+                                        G_N_ELEMENTS (row_targets),
+                                        GDK_ACTION_MOVE | GDK_ACTION_COPY);
+
+  renderer = gtk_cell_renderer_text_new ();
+  g_object_set (renderer, "editable", TRUE, NULL);
+  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
+                                               0, "Title",
+                                               renderer,
+                                               "text", 0,
+                                               NULL);
+  store = gtk_list_store_new (1, G_TYPE_STRING);
+  for (i = 0; i < 80; i++)
+    {
+      GtkTreeIter iter;
+      gchar *label = g_strdup_printf ("Row number %d", i);
+
+      gtk_list_store_append (store, &iter);
+      gtk_list_store_set (store, &iter, 0, label, -1);
+      g_free (label);
+    }
+  gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store));
+  g_object_unref (store);
+
+  swindow = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_kinetic_scrolling (GTK_SCROLLED_WINDOW (swindow), TRUE);
+  gtk_container_add (GTK_CONTAINER (swindow), treeview);
+  gtk_widget_show (treeview);
+
+  gtk_table_attach_defaults (GTK_TABLE (table), swindow,
+                             1, 2, 1, 2);
+  gtk_widget_show (swindow);
+
   textview = gtk_text_view_new ();
   swindow = gtk_scrolled_window_new (NULL, NULL);
   gtk_scrolled_window_set_kinetic_scrolling (GTK_SCROLLED_WINDOW (swindow), TRUE);
@@ -62,7 +120,7 @@ kinetic_scrolling (void)
   gtk_widget_show (textview);
 
   gtk_table_attach_defaults (GTK_TABLE (table), swindow,
-                             1, 2, 1, 2);
+                             2, 3, 1, 2);
   gtk_widget_show (swindow);
 
   gtk_container_add (GTK_CONTAINER (window), table);



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