[gtk+/multitouch: 11/123] scrolledwindow: Allow selections and drag-and-drop when kinetic scrolling is enabled
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/multitouch: 11/123] scrolledwindow: Allow selections and drag-and-drop when kinetic scrolling is enabled
- Date: Mon, 16 Jan 2012 18:43:10 +0000 (UTC)
commit 26b8258c2e511083f6bd3a8024ba7205c8b50251
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 | 126 +++++++++++++++++++++++++++++++++++++++--
tests/testkineticscrolling.c | 64 ++++++++++++++++++++-
2 files changed, 180 insertions(+), 10 deletions(-)
---
diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
index 1f1a74b..03b3465 100644
--- a/gtk/gtkscrolledwindow.c
+++ b/gtk/gtkscrolledwindow.c
@@ -168,6 +168,7 @@ struct _GtkScrolledWindowPrivate
/* Kinetic scrolling */
GdkWindow *event_window;
+ GdkEvent *button_press_event;
guint kinetic_scrolling_enabled : 1;
guint in_drag : 1;
guint hmoving : 1;
@@ -175,6 +176,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;
@@ -230,6 +232,10 @@ static gboolean gtk_scrolled_window_scroll_event (GtkWidget *widge
GdkEventScroll *event);
static gboolean gtk_scrolled_window_button_press_event (GtkWidget *widget,
GdkEvent *event);
+static gboolean gtk_scrolled_window_press_and_hold (GtkWidget *widget,
+ GtkPressAndHoldAction action,
+ gint x,
+ gint y);
static gboolean gtk_scrolled_window_focus (GtkWidget *widget,
GtkDirectionType direction);
static void gtk_scrolled_window_add (GtkContainer *container,
@@ -1125,9 +1131,14 @@ 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);
+ priv->press_and_hold_id =
+ g_signal_connect (scrolled_window, "press-and-hold",
+ G_CALLBACK (gtk_scrolled_window_press_and_hold),
+ NULL);
+
/* Hide the scrollbars */
gtk_scrolled_window_auto_hide_scrollbars_start (scrolled_window,
AUTO_HIDE_SCROLLBARS_TIMEOUT);
@@ -1164,6 +1175,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);
@@ -1242,6 +1258,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_scrolled_window_auto_hide_scrollbars_stop (scrolled_window);
@@ -2795,6 +2823,61 @@ gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window,
}
static gboolean
+gtk_scrolled_window_press_and_hold (GtkWidget *widget,
+ GtkPressAndHoldAction action,
+ gint x,
+ gint y)
+{
+ GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
+ GtkScrolledWindowPrivate *priv = scrolled_window->priv;
+
+ switch (action)
+ {
+ case GTK_PRESS_AND_HOLD_QUERY:
+ return !priv->in_drag;
+ case GTK_PRESS_AND_HOLD_TRIGGER:
+ /* Cancel the scrolling and send the button press
+ * event to the child widget
+ */
+
+ gdk_device_ungrab (gdk_event_get_device (priv->button_press_event), GDK_CURRENT_TIME);
+
+ if (priv->motion_notify_id > 0)
+ {
+ g_signal_handler_disconnect (scrolled_window, priv->motion_notify_id);
+ priv->motion_notify_id = 0;
+ }
+ if (priv->button_release_id > 0)
+ {
+ g_signal_handler_disconnect (scrolled_window, priv->button_release_id);
+ priv->button_release_id = 0;
+ }
+
+ /* We are going to synthesize the button press event so that
+ * it can be handled by child widget, but we don't want to
+ * handle it, so block both button-press and and press-and-hold
+ * during this button press
+ */
+ g_signal_handler_block (scrolled_window, priv->button_press_id);
+ g_signal_handler_block (scrolled_window, priv->press_and_hold_id);
+
+ gtk_main_do_event (priv->button_press_event);
+
+ g_signal_handler_unblock (scrolled_window, priv->button_press_id);
+ g_signal_handler_unblock (scrolled_window, priv->press_and_hold_id);
+ gdk_event_free (priv->button_press_event);
+ priv->button_press_event = NULL;
+ break;
+ case GTK_PRESS_AND_HOLD_CANCEL:
+ default:
+ break;
+ }
+
+ /* Doesn't really matter in this case */
+ return FALSE;
+}
+
+static gboolean
gtk_scrolled_window_button_release_event (GtkWidget *widget,
GdkEvent *_event)
{
@@ -2812,6 +2895,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)
@@ -2829,13 +2916,30 @@ gtk_scrolled_window_button_release_event (GtkWidget *widget,
{
gtk_scrolled_window_auto_hide_scrollbars_start (scrolled_window,
AUTO_HIDE_SCROLLBARS_TIMEOUT);
+ /* 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;
+ }
+
return FALSE;
}
priv->in_drag = FALSE;
- child = gtk_bin_get_child (GTK_BIN (widget));
- if (!child)
- return 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);
@@ -2881,6 +2985,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));
@@ -2983,7 +3093,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]