notebook: return TRUE for drag-motion event when over tabs

The GtkNotebook drag-motion event handler may install a timeout when
hovering over a tab, in order to switch to it.
On the other hand it's desirable for applications to use the empty tab
area as a drop target, so the drag-motion handler returns FALSE
(also in case it installs the switch tab timeout), as explained in
https://bugzilla.gnome.org/show_bug.cgi?id=350665.

Unfortunately, applications can use the tab label widget (or a child
of it) as a different drop target area, and install their own
drag-motion handler there.
In this scenario, the timeout will still be installed by GtkNotebook's
handler, but since it returns FALSE, it will never get the matching
drag-leave event, causing it to trigger also when the mouse pointer
moved elsewhere before it expired.

Fix this by returning TRUE from drag-motion when the event is over a
tab. Note that this makes automatic tab switching not work anymore when
drag and drop is handled in the tab label widget; applications are
expected to also handle tab switching if desired in such a case.

https://bugzilla.gnome.org/show_bug.cgi?id=684415
This commit is contained in:
Cosimo Cecchi 2012-09-19 20:56:26 -04:00
parent 42da600eb1
commit 852d4d618c

View File

@ -150,6 +150,7 @@ struct _GtkNotebookPrivate
guint dnd_timer; guint dnd_timer;
guint switch_tab_timer; guint switch_tab_timer;
GList *switch_tab;
guint32 timer; guint32 timer;
guint32 timestamp; guint32 timestamp;
@ -3696,20 +3697,20 @@ gtk_notebook_switch_tab_timeout (gpointer data)
{ {
GtkNotebook *notebook = GTK_NOTEBOOK (data); GtkNotebook *notebook = GTK_NOTEBOOK (data);
GtkNotebookPrivate *priv = notebook->priv; GtkNotebookPrivate *priv = notebook->priv;
GList *tab; GList *switch_tab;
gint x, y;
priv->switch_tab_timer = 0; priv->switch_tab_timer = 0;
x = priv->mouse_x;
y = priv->mouse_y;
if ((tab = get_tab_at_pos (notebook, x, y)) != NULL) switch_tab = priv->switch_tab;
priv->switch_tab = NULL;
if (switch_tab)
{ {
/* FIXME: hack, we don't want the /* FIXME: hack, we don't want the
* focus to move fom the source widget * focus to move fom the source widget
*/ */
priv->child_has_focus = FALSE; priv->child_has_focus = FALSE;
gtk_notebook_switch_focus_tab (notebook, tab); gtk_notebook_switch_focus_tab (notebook, switch_tab);
} }
return FALSE; return FALSE;
@ -3730,6 +3731,8 @@ gtk_notebook_drag_motion (GtkWidget *widget,
GtkNotebookArrow arrow; GtkNotebookArrow arrow;
guint timeout; guint timeout;
GdkAtom target, tab_target; GdkAtom target, tab_target;
GList *tab;
gboolean retval = FALSE;
gtk_widget_get_allocation (widget, &allocation); gtk_widget_get_allocation (widget, &allocation);
@ -3741,7 +3744,9 @@ gtk_notebook_drag_motion (GtkWidget *widget,
priv->click_child = arrow; priv->click_child = arrow;
gtk_notebook_set_scroll_timer (notebook); gtk_notebook_set_scroll_timer (notebook);
gdk_drag_status (context, 0, time); gdk_drag_status (context, 0, time);
return TRUE;
retval = TRUE;
goto out;
} }
stop_scrolling (notebook); stop_scrolling (notebook);
@ -3754,6 +3759,8 @@ gtk_notebook_drag_motion (GtkWidget *widget,
GtkNotebook *source; GtkNotebook *source;
GtkWidget *source_child; GtkWidget *source_child;
retval = TRUE;
source = GTK_NOTEBOOK (gtk_drag_get_source_widget (context)); source = GTK_NOTEBOOK (gtk_drag_get_source_widget (context));
source_child = source->priv->cur_page->child; source_child = source->priv->cur_page->child;
@ -3765,7 +3772,7 @@ gtk_notebook_drag_motion (GtkWidget *widget,
gtk_widget_is_ancestor (widget, source_child))) gtk_widget_is_ancestor (widget, source_child)))
{ {
gdk_drag_status (context, GDK_ACTION_MOVE, time); gdk_drag_status (context, GDK_ACTION_MOVE, time);
return TRUE; goto out;
} }
else else
{ {
@ -3780,11 +3787,19 @@ gtk_notebook_drag_motion (GtkWidget *widget,
if (gtk_notebook_get_event_window_position (notebook, &position) && if (gtk_notebook_get_event_window_position (notebook, &position) &&
x >= position.x && x <= position.x + position.width && x >= position.x && x <= position.x + position.width &&
y >= position.y && y <= position.y + position.height) y >= position.y && y <= position.y + position.height &&
(tab = get_tab_at_pos (notebook, x, y)))
{ {
priv->mouse_x = x; priv->mouse_x = x;
priv->mouse_y = y; priv->mouse_y = y;
retval = TRUE;
if (tab != priv->switch_tab)
remove_switch_tab_timer (notebook);
priv->switch_tab = tab;
if (!priv->switch_tab_timer) if (!priv->switch_tab_timer)
{ {
settings = gtk_widget_get_settings (widget); settings = gtk_widget_get_settings (widget);
@ -3800,7 +3815,8 @@ gtk_notebook_drag_motion (GtkWidget *widget,
remove_switch_tab_timer (notebook); remove_switch_tab_timer (notebook);
} }
return (target == tab_target) ? TRUE : FALSE; out:
return retval;
} }
static void static void
@ -3809,7 +3825,6 @@ gtk_notebook_drag_leave (GtkWidget *widget,
guint time) guint time)
{ {
GtkNotebook *notebook = GTK_NOTEBOOK (widget); GtkNotebook *notebook = GTK_NOTEBOOK (widget);
GtkNotebookPrivate *priv = notebook->priv;
remove_switch_tab_timer (notebook); remove_switch_tab_timer (notebook);
stop_scrolling (notebook); stop_scrolling (notebook);
@ -4977,6 +4992,8 @@ gtk_notebook_real_remove (GtkNotebook *notebook,
if (priv->detached_tab == list->data) if (priv->detached_tab == list->data)
priv->detached_tab = NULL; priv->detached_tab = NULL;
if (priv->switch_tab == list)
priv->switch_tab = NULL;
if (list == priv->first_tab) if (list == priv->first_tab)
priv->first_tab = next_list; priv->first_tab = next_list;