diff options
-rw-r--r-- | ChangeLog | 16 | ||||
-rw-r--r-- | ChangeLog.pre-2-10 | 16 | ||||
-rw-r--r-- | gtk/gtk.symbols | 2 | ||||
-rw-r--r-- | gtk/gtkdnd.c | 79 | ||||
-rw-r--r-- | gtk/gtkdnd.h | 5 | ||||
-rw-r--r-- | gtk/gtknotebook.c | 247 | ||||
-rw-r--r-- | gtk/gtksettings.c | 12 |
7 files changed, 310 insertions, 67 deletions
@@ -1,5 +1,21 @@ 2006-03-22 Matthias Clasen <mclasen@redhat.com> + Improved DND support for GtkNotebook (#332991, Carlos Garnacho) + + * gtk/gtk.symbols: + * gtk/gtkdnd.h: + * gtk/gtkdnd.c: Add a track_motion flag on GtkDragDest + with getter and setter, for cases where the drag destination + is interested in drag motion events independent of targets. + + * gtk/gtksettings.c (gtk_settings_class_init): Add a setting + for the timeout used when expanding during DND. + + * gtk/gtknotebook.c: Use the track_motion flag to switch + notebook tabs when hovering over tabs during DND. + +2006-03-22 Matthias Clasen <mclasen@redhat.com> + * gtk/gtktreeview.c (gtk_tree_view_bin_expose): Use fg_gc to draw the inter-row drop highlight. Also draw the line all the way across, and flip it in RTL mode. (#334906, Ian McDonald) diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 3b424f7bf8..f66998098d 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,5 +1,21 @@ 2006-03-22 Matthias Clasen <mclasen@redhat.com> + Improved DND support for GtkNotebook (#332991, Carlos Garnacho) + + * gtk/gtk.symbols: + * gtk/gtkdnd.h: + * gtk/gtkdnd.c: Add a track_motion flag on GtkDragDest + with getter and setter, for cases where the drag destination + is interested in drag motion events independent of targets. + + * gtk/gtksettings.c (gtk_settings_class_init): Add a setting + for the timeout used when expanding during DND. + + * gtk/gtknotebook.c: Use the track_motion flag to switch + notebook tabs when hovering over tabs during DND. + +2006-03-22 Matthias Clasen <mclasen@redhat.com> + * gtk/gtktreeview.c (gtk_tree_view_bin_expose): Use fg_gc to draw the inter-row drop highlight. Also draw the line all the way across, and flip it in RTL mode. (#334906, Ian McDonald) diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols index a4520a3224..24231aa871 100644 --- a/gtk/gtk.symbols +++ b/gtk/gtk.symbols @@ -996,6 +996,8 @@ gtk_drag_dest_get_target_list gtk_drag_dest_set gtk_drag_dest_set_proxy gtk_drag_dest_set_target_list +gtk_drag_dest_set_track_motion +gtk_drag_dest_get_track_motion gtk_drag_dest_unset gtk_drag_finish gtk_drag_get_data diff --git a/gtk/gtkdnd.c b/gtk/gtkdnd.c index 66a836c751..4ab402dcf4 100644 --- a/gtk/gtkdnd.c +++ b/gtk/gtkdnd.c @@ -131,6 +131,7 @@ struct _GtkDragDestSite guint do_proxy : 1; guint proxy_coords : 1; guint have_drag : 1; + guint track_motion : 1; }; struct _GtkDragDestInfo @@ -1026,6 +1027,8 @@ gtk_drag_dest_set_internal (GtkWidget *widget, g_signal_handlers_disconnect_by_func (widget, gtk_drag_dest_hierarchy_changed, old_site); + + site->track_motion = old_site->track_motion; } if (GTK_WIDGET_REALIZED (widget)) @@ -1272,6 +1275,61 @@ gtk_drag_dest_add_uri_targets (GtkWidget *widget) gtk_target_list_unref (target_list); } +/** + * gtk_drag_dest_set_track_motion: + * @widget: a #GtkWidget that's a drag destination + * @track_motion: whether to accept all targets + * + * Tells the widget to emit ::drag-motion and ::drag-leave + * events regardless of the targets and the %GTK_DEST_DEFAULT_MOTION + * flag. + * + * This may be used when a widget wants to do generic + * actions regardless of the targets that the source offers. + * + * Since: 2.10 + **/ +void +gtk_drag_dest_set_track_motion (GtkWidget *widget, + gboolean track_motion) +{ + GtkDragDestSite *site; + + g_return_if_fail (GTK_IS_WIDGET (widget)); + + site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest"); + + g_return_if_fail (site != NULL); + + site->track_motion = track_motion != FALSE; +} + +/** + * gtk_drag_dest_get_track_motion: + * @widget: a #GtkWidget that's a drag destination + * + * Returns whether the widget has been configured to always + * emit ::drag-motion signals. + * + * Return Value: %TRUE if the widget always emits ::drag-motion events + * + * Since: 2.10 + **/ +gboolean +gtk_drag_dest_get_track_motion (GtkWidget *widget) +{ + GtkDragDestSite *site; + + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + + site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest"); + + if (site) + return site->track_motion; + + return FALSE; +} + /************************************************************* * _gtk_drag_dest_handle_event: * Called from widget event handling code on Drag events @@ -1352,7 +1410,7 @@ _gtk_drag_dest_handle_event (GtkWidget *toplevel, data.callback = (event->type == GDK_DRAG_MOTION) ? gtk_drag_dest_motion : gtk_drag_dest_drop; data.time = event->dnd.time; - + gtk_drag_find_widget (toplevel, &data); if (info->widget && !data.found) @@ -1856,9 +1914,9 @@ gtk_drag_dest_leave (GtkWidget *widget, if ((site->flags & GTK_DEST_DEFAULT_HIGHLIGHT) && site->have_drag) gtk_drag_unhighlight (widget); - if (!(site->flags & GTK_DEST_DEFAULT_MOTION) || site->have_drag) - g_signal_emit_by_name (widget, "drag_leave", - context, time); + if (!(site->flags & GTK_DEST_DEFAULT_MOTION) || site->have_drag || + site->track_motion) + g_signal_emit_by_name (widget, "drag_leave", context, time); site->have_drag = FALSE; } @@ -1935,7 +1993,7 @@ gtk_drag_dest_motion (GtkWidget *widget, { gint i; - for (i=0; i<8; i++) + for (i = 0; i < 8; i++) { if ((site->actions & (1 << i)) && (context->actions & (1 << i))) @@ -1945,7 +2003,7 @@ gtk_drag_dest_motion (GtkWidget *widget, } } } - + if (action && gtk_drag_dest_find_target (widget, context, NULL)) { if (!site->have_drag) @@ -1954,13 +2012,14 @@ gtk_drag_dest_motion (GtkWidget *widget, if (site->flags & GTK_DEST_DEFAULT_HIGHLIGHT) gtk_drag_highlight (widget); } - + gdk_drag_status (context, action, time); } else { gdk_drag_status (context, 0, time); - return TRUE; + if (!site->track_motion) + return TRUE; } } @@ -2055,13 +2114,13 @@ gtk_drag_dest_drop (GtkWidget *widget, if (site->flags & GTK_DEST_DEFAULT_DROP) { GdkAtom target = gtk_drag_dest_find_target (widget, context, NULL); - + if (target == GDK_NONE) { gtk_drag_finish (context, FALSE, FALSE, time); return TRUE; } - else + else gtk_drag_get_data (widget, context, target, time); } diff --git a/gtk/gtkdnd.h b/gtk/gtkdnd.h index e82d6c3063..626ef00597 100644 --- a/gtk/gtkdnd.h +++ b/gtk/gtkdnd.h @@ -1,3 +1,4 @@ +/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */ /* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * @@ -87,6 +88,10 @@ void gtk_drag_dest_add_text_targets (GtkWidget *widget); void gtk_drag_dest_add_image_targets (GtkWidget *widget); void gtk_drag_dest_add_uri_targets (GtkWidget *widget); +void gtk_drag_dest_set_track_motion (GtkWidget *widget, + gboolean track_motion); +gboolean gtk_drag_dest_get_track_motion (GtkWidget *widget); + /* Source side */ void gtk_drag_source_set (GtkWidget *widget, diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c index 016d8eb6ec..b0017891f1 100644 --- a/gtk/gtknotebook.c +++ b/gtk/gtknotebook.c @@ -160,16 +160,21 @@ struct _GtkNotebookPrivate gint mouse_y; gint pressed_button; guint dnd_timer; + guint switch_tab_timer; GtkTargetList *source_targets; gboolean during_detach; gboolean has_scrolled; }; -static const GtkTargetEntry notebook_targets[] = { +static const GtkTargetEntry notebook_source_targets [] = { { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 }, { "application/x-rootwindow-drop", 0, 1 } }; +static const GtkTargetEntry notebook_dest_targets[] = { + { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 } +}; + #ifdef G_DISABLE_CHECKS #define CHECK_FIND_CHILD(notebook, child) \ gtk_notebook_find_child (notebook, child, G_STRLOC) @@ -251,6 +256,9 @@ static gboolean gtk_notebook_drag_motion (GtkWidget *widget, gint x, gint y, guint time); +static void gtk_notebook_drag_leave (GtkWidget *widget, + GdkDragContext *context, + guint time); static gboolean gtk_notebook_drag_drop (GtkWidget *widget, GdkDragContext *context, gint x, @@ -501,6 +509,7 @@ gtk_notebook_class_init (GtkNotebookClass *class) widget_class->style_set = gtk_notebook_style_set; widget_class->drag_begin = gtk_notebook_drag_begin; widget_class->drag_motion = gtk_notebook_drag_motion; + widget_class->drag_leave = gtk_notebook_drag_leave; widget_class->drag_drop = gtk_notebook_drag_drop; widget_class->drag_data_get = gtk_notebook_drag_data_get; widget_class->drag_data_received = gtk_notebook_drag_data_received; @@ -985,13 +994,16 @@ gtk_notebook_init (GtkNotebook *notebook) priv->group_id = -1; priv->pressed_button = -1; priv->dnd_timer = 0; - priv->source_targets = gtk_target_list_new (notebook_targets, - G_N_ELEMENTS (notebook_targets)); + priv->switch_tab_timer = 0; + priv->source_targets = gtk_target_list_new (notebook_source_targets, + G_N_ELEMENTS (notebook_source_targets)); gtk_drag_dest_set (GTK_WIDGET (notebook), GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, - notebook_targets, G_N_ELEMENTS (notebook_targets), + notebook_dest_targets, G_N_ELEMENTS (notebook_dest_targets), GDK_ACTION_MOVE); + + gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE); } static gboolean @@ -1266,7 +1278,13 @@ gtk_notebook_destroy (GtkObject *object) gtk_target_list_unref (priv->source_targets); priv->source_targets = NULL; } - + + if (priv->switch_tab_timer) + { + g_source_remove (priv->switch_tab_timer); + priv->switch_tab_timer = 0; + } + GTK_OBJECT_CLASS (parent_class)->destroy (object); } @@ -2084,7 +2102,7 @@ gtk_notebook_do_arrow (GtkNotebook *notebook, static gboolean gtk_notebook_arrow_button_press (GtkNotebook *notebook, GtkNotebookArrow arrow, - GdkEventButton *event) + gint button) { GtkWidget *widget = GTK_WIDGET (notebook); gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL; @@ -2094,10 +2112,10 @@ gtk_notebook_arrow_button_press (GtkNotebook *notebook, if (!GTK_WIDGET_HAS_FOCUS (widget)) gtk_widget_grab_focus (widget); - notebook->button = event->button; + notebook->button = button; notebook->click_child = arrow; - - if (event->button == 1) + + if (button == 1) { gtk_notebook_do_arrow (notebook, arrow); @@ -2114,9 +2132,9 @@ gtk_notebook_arrow_button_press (GtkNotebook *notebook, notebook->need_timer = TRUE; } } - else if (event->button == 2) + else if (button == 2) gtk_notebook_page_select (notebook, TRUE); - else if (event->button == 3) + else if (button == 3) gtk_notebook_switch_focus_tab (notebook, gtk_notebook_search_page (notebook, NULL, @@ -2195,6 +2213,30 @@ gtk_notebook_scroll (GtkWidget *widget, return TRUE; } +static GList* +get_tab_at_pos (GtkNotebook *notebook, gint x, gint y) +{ + GtkNotebookPage *page; + GList *children = notebook->children; + + while (children) + { + page = children->data; + + if (GTK_WIDGET_VISIBLE (page->child) && + page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) && + (x >= page->allocation.x) && + (y >= page->allocation.y) && + (x <= (page->allocation.x + page->allocation.width)) && + (y <= (page->allocation.y + page->allocation.height))) + return children; + + children = children->next; + } + + return NULL; +} + static gboolean gtk_notebook_button_press (GtkWidget *widget, GdkEventButton *event) @@ -2202,9 +2244,8 @@ gtk_notebook_button_press (GtkWidget *widget, GtkNotebook *notebook = GTK_NOTEBOOK (widget); GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook); GtkNotebookPage *page; - GList *children; + GList *tab; GtkNotebookArrow arrow; - gint num; gint x, y; if (event->type != GDK_BUTTON_PRESS || !notebook->children || @@ -2216,7 +2257,7 @@ gtk_notebook_button_press (GtkWidget *widget, arrow = gtk_notebook_get_arrow (notebook, x, y); if (arrow) - return gtk_notebook_arrow_button_press (notebook, arrow, event); + return gtk_notebook_arrow_button_press (notebook, arrow, event->button); if (event->button == 3 && notebook->menu) { @@ -2229,41 +2270,28 @@ gtk_notebook_button_press (GtkWidget *widget, return FALSE; notebook->button = event->button; - num = 0; - children = notebook->children; - while (children) + if ((tab = get_tab_at_pos (notebook, x, y)) != NULL) { - page = children->data; - - if (GTK_WIDGET_VISIBLE (page->child) && - page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) && - (x >= page->allocation.x) && - (y >= page->allocation.y) && - (x <= (page->allocation.x + page->allocation.width)) && - (y <= (page->allocation.y + page->allocation.height))) - { - gboolean page_changed = page != notebook->cur_page; - gboolean was_focus = gtk_widget_is_focus (widget); + gboolean page_changed, was_focus; + + page = tab->data; + page_changed = page != notebook->cur_page; + was_focus = gtk_widget_is_focus (widget); - gtk_notebook_switch_focus_tab (notebook, children); - gtk_widget_grab_focus (widget); + gtk_notebook_switch_focus_tab (notebook, tab); + gtk_widget_grab_focus (widget); - if (page_changed && !was_focus) - gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD); + if (page_changed && !was_focus) + gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD); - /* save press to possibly begin a drag */ - if (page->reorderable || page->detachable) - { - priv->during_detach = FALSE; - priv->pressed_button = event->button; - gtk_grab_add (widget); - } - - break; + /* save press to possibly begin a drag */ + if (page->reorderable || page->detachable) + { + priv->during_detach = FALSE; + priv->pressed_button = event->button; + gtk_grab_add (widget); } - children = children->next; - num++; } return TRUE; @@ -2800,30 +2828,135 @@ gtk_notebook_drag_begin (GtkWidget *widget, } static gboolean +gtk_notebook_switch_tab_timeout (gpointer data) +{ + GtkNotebook *notebook; + GtkNotebookPrivate *priv; + GList *tab; + gint x, y; + + notebook = GTK_NOTEBOOK (data); + priv = GTK_NOTEBOOK_GET_PRIVATE (notebook); + + priv->switch_tab_timer = 0; + x = priv->mouse_x; + y = priv->mouse_y; + + if ((tab = get_tab_at_pos (notebook, x, y)) != NULL) + { + /* FIXME: hack, we don't want the + * focus to move fom the source widget + */ + notebook->child_has_focus = FALSE; + gtk_notebook_switch_focus_tab (notebook, tab); + } + + return FALSE; +} + +static gboolean gtk_notebook_drag_motion (GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time) { - GtkWidget *source_widget; - gint widget_group, source_widget_group; - - source_widget = gtk_drag_get_source_widget (context); - - g_assert (source_widget); + GtkNotebook *notebook; + GtkNotebookPrivate *priv; + GdkRectangle position; + GtkSettings *settings; + GtkNotebookArrow arrow; + guint timeout; + GdkAtom target, tab_target; + + notebook = GTK_NOTEBOOK (widget); + target = gtk_drag_dest_find_target (widget, context, NULL); + tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"); - widget_group = gtk_notebook_get_group_id (GTK_NOTEBOOK (widget)); - source_widget_group = gtk_notebook_get_group_id (GTK_NOTEBOOK (source_widget)); + if (target == tab_target) + { + gint widget_group, source_widget_group; + GtkWidget *source_widget; - if (widget_group != -1 && - source_widget_group != -1 && - widget_group == source_widget_group) - return TRUE; + source_widget = gtk_drag_get_source_widget (context); - gdk_drag_status (context, 0, time); + g_assert (source_widget); - return FALSE; + widget_group = gtk_notebook_get_group_id (notebook); + source_widget_group = gtk_notebook_get_group_id (GTK_NOTEBOOK (source_widget)); + + if (widget_group != -1 && + source_widget_group != -1 && + widget_group == source_widget_group) + { + gdk_drag_status (context, GDK_ACTION_MOVE, time); + return TRUE; + } + } + + priv = GTK_NOTEBOOK_GET_PRIVATE (widget); + x += widget->allocation.x; + y += widget->allocation.y; + + if (target == tab_target) + { + /* it's a tab, but doesn't share + * ID with this notebook */ + gdk_drag_status (context, 0, time); + } + + if (gtk_notebook_get_event_window_position (notebook, &position) && + x >= position.x && x <= position.x + position.width && + y >= position.y && y <= position.y + position.height) + { + priv->mouse_x = x; + priv->mouse_y = y; + + arrow = gtk_notebook_get_arrow (notebook, x, y); + + if (arrow) + return gtk_notebook_arrow_button_press (notebook, arrow, 1); + + stop_scrolling (notebook); + + if (!priv->switch_tab_timer) + { + settings = gtk_widget_get_settings (widget); + + g_object_get (settings, "gtk-timeout-expand", &timeout, NULL); + priv->switch_tab_timer = g_timeout_add (timeout, + (GSourceFunc) gtk_notebook_switch_tab_timeout, + widget); + } + } + else + { + if (priv->switch_tab_timer) + { + g_source_remove (priv->switch_tab_timer); + priv->switch_tab_timer = 0; + } + } + + return TRUE; +} + +static void +gtk_notebook_drag_leave (GtkWidget *widget, + GdkDragContext *context, + guint time) +{ + GtkNotebookPrivate *priv; + + priv = GTK_NOTEBOOK_GET_PRIVATE (widget); + + if (priv->switch_tab_timer) + { + g_source_remove (priv->switch_tab_timer); + priv->switch_tab_timer = 0; + } + + stop_scrolling (GTK_NOTEBOOK (widget)); } static gboolean diff --git a/gtk/gtksettings.c b/gtk/gtksettings.c index ea2f375ec0..1dd700cbc8 100644 --- a/gtk/gtksettings.c +++ b/gtk/gtksettings.c @@ -34,6 +34,7 @@ #define DEFAULT_TIMEOUT_INITIAL 200 #define DEFAULT_TIMEOUT_REPEAT 20 +#define DEFAULT_TIMEOUT_EXPAND 500 typedef struct _GtkSettingsValuePrivate GtkSettingsValuePrivate; @@ -87,6 +88,7 @@ enum { PROP_SHOW_UNICODE_MENU, PROP_TIMEOUT_INITIAL, PROP_TIMEOUT_REPEAT, + PROP_TIMEOUT_EXPAND, PROP_COLOR_SCHEME, PROP_ENABLE_ANIMATIONS, PROP_TOUCHSCREEN_MODE, @@ -452,6 +454,16 @@ gtk_settings_class_init (GtkSettingsClass *class) g_assert (result == PROP_TIMEOUT_REPEAT); + result = settings_install_property_parser (class, + g_param_spec_int ("gtk-timeout-expand", + P_("Expand timeout"), + P_("Expand value for timeouts, when a widget is expanding a new region"), + 0, G_MAXINT, DEFAULT_TIMEOUT_EXPAND, + GTK_PARAM_READWRITE), + NULL); + + g_assert (result == PROP_TIMEOUT_EXPAND); + /** * GtkSettings:gtk-color-scheme: * |