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.
This commit is contained in:
Carlos Garcia Campos
2011-03-23 17:42:21 +01:00
committed by Carlos Garnacho
parent 83e6e9909e
commit ccbd72dbe4
2 changed files with 120 additions and 11 deletions

View File

@@ -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);
child = gtk_bin_get_child (GTK_BIN (widget));
if (!child)
return FALSE;
return TRUE;
}
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

View File

@@ -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);