summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog22
-rw-r--r--gtk/gtkdnd.c38
-rw-r--r--gtk/gtkenums.h9
-rw-r--r--gtk/gtkmarshalers.list1
-rw-r--r--gtk/gtknotebook.c88
-rw-r--r--gtk/gtkwidget.c27
6 files changed, 135 insertions, 50 deletions
diff --git a/ChangeLog b/ChangeLog
index b1142860ec..d66beb1dda 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2006-12-28 Carlos Garnacho <carlosg@gnome.org>
+
+ Make GtkNotebook able to drop detached tabs anywhere. Bug #360225.
+
+ * gtk/gtkwidget.c (gtk_widget_class_init): add "drag-failed" signal.
+ * gtk/gtkmarshalers.list: add new marshaler definition.
+ * gtk/gtkenums.h: add GtkDragResult enum.
+
+ * gtk/gtkdnd.c (gtk_drag_drop_finished): emit "drag-failed" if DND
+ operation wasn't successful.
+ (_gtk_drag_source_handle_event) (gtk_drag_drop)
+ (gtk_drag_selection_get) (gtk_drag_cancel) (gtk_drag_key_cb)
+ (gtk_drag_grab_broken_event_cb) (gtk_drag_grab_notify_cb)
+ (gtk_drag_button_release_cb) (gtk_drag_abort_timeout): tell
+ gtk_drag_drop_finished() the operation result.
+
+ * gtk/gtknotebook.c (gtk_notebook_drag_failed): new function.
+ (gtk_notebook_drag_data_get): do not call window creation hook here.
+ (gtk_notebook_init): do not set "application/x-rootwindow-drop"
+ target, instead connect to "drag-failed".
+ (gtk_notebook_draw_focus): fix potential crasher if cur_page is NULL.
+
2006-12-28 Mikael Hallendal <micke@imendio.com>
* gdk/quartz/gdkevents-quartz.c: Factored out the event loop
diff --git a/gtk/gtkdnd.c b/gtk/gtkdnd.c
index 939f5f2cde..a30da5e5e1 100644
--- a/gtk/gtkdnd.c
+++ b/gtk/gtkdnd.c
@@ -252,9 +252,10 @@ static void gtk_drag_source_release_selections (GtkDragSourceInfo *info,
static void gtk_drag_drop (GtkDragSourceInfo *info,
guint32 time);
static void gtk_drag_drop_finished (GtkDragSourceInfo *info,
- gboolean success,
+ GtkDragResult result,
guint time);
static void gtk_drag_cancel (GtkDragSourceInfo *info,
+ GtkDragResult result,
guint32 time);
static gboolean gtk_drag_source_event_cb (GtkWidget *widget,
@@ -2974,7 +2975,7 @@ set_icon_stock_pixbuf (GdkDragContext *context,
gtk_widget_pop_colormap ();
gtk_widget_set_events (window, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
- gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE);
+ gtk_widget_set_app_paintable (window, TRUE);
if (stock_id)
{
@@ -3333,7 +3334,7 @@ _gtk_drag_source_handle_event (GtkWidget *widget,
break;
case GDK_DROP_FINISHED:
- gtk_drag_drop_finished (info, TRUE, event->dnd.time);
+ gtk_drag_drop_finished (info, GTK_DRAG_RESULT_SUCCESS, event->dnd.time);
break;
default:
g_assert_not_reached ();
@@ -3413,9 +3414,12 @@ gtk_drag_source_check_selection (GtkDragSourceInfo *info,
static void
gtk_drag_drop_finished (GtkDragSourceInfo *info,
- gboolean success,
+ GtkDragResult result,
guint time)
{
+ gboolean success;
+
+ success = (result == GTK_DRAG_RESULT_SUCCESS);
gtk_drag_source_release_selections (info, time);
if (info->proxy_dest)
@@ -3427,6 +3431,10 @@ gtk_drag_drop_finished (GtkDragSourceInfo *info,
}
else
{
+ if (!success)
+ g_signal_emit_by_name (info->widget, "drag_failed",
+ info->context, result, &success);
+
if (success)
{
gtk_drag_source_info_destroy (info);
@@ -3518,12 +3526,12 @@ gtk_drag_drop (GtkDragSourceInfo *info,
time);
/* FIXME: Should we check for length >= 0 here? */
- gtk_drag_drop_finished (info, TRUE, time);
+ gtk_drag_drop_finished (info, GTK_DRAG_RESULT_SUCCESS, time);
return;
}
tmp_list = tmp_list->next;
}
- gtk_drag_drop_finished (info, FALSE, time);
+ gtk_drag_drop_finished (info, GTK_DRAG_RESULT_NO_TARGET, time);
}
else
{
@@ -3635,11 +3643,11 @@ gtk_drag_selection_get (GtkWidget *widget,
gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
break;
case TARGET_MOTIF_SUCCESS:
- gtk_drag_drop_finished (info, TRUE, time);
+ gtk_drag_drop_finished (info, GTK_DRAG_RESULT_SUCCESS, time);
gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
break;
case TARGET_MOTIF_FAILURE:
- gtk_drag_drop_finished (info, FALSE, time);
+ gtk_drag_drop_finished (info, GTK_DRAG_RESULT_NO_TARGET, time);
gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
break;
default:
@@ -3975,11 +3983,11 @@ gtk_drag_end (GtkDragSourceInfo *info, guint32 time)
*************************************************************/
static void
-gtk_drag_cancel (GtkDragSourceInfo *info, guint32 time)
+gtk_drag_cancel (GtkDragSourceInfo *info, GtkDragResult result, guint32 time)
{
gtk_drag_end (info, time);
gdk_drag_abort (info->context, time);
- gtk_drag_drop_finished (info, FALSE, time);
+ gtk_drag_drop_finished (info, result, time);
}
/*************************************************************
@@ -4044,7 +4052,7 @@ gtk_drag_key_cb (GtkWidget *widget,
switch (event->keyval)
{
case GDK_Escape:
- gtk_drag_cancel (info, event->time);
+ gtk_drag_cancel (info, GTK_DRAG_RESULT_USER_CANCELLED, event->time);
return TRUE;
case GDK_space:
@@ -4118,7 +4126,7 @@ gtk_drag_grab_broken_event_cb (GtkWidget *widget,
|| event->grab_window == info->ipc_widget->window)
return FALSE;
- gtk_drag_cancel (info, gtk_get_current_event_time ());
+ gtk_drag_cancel (info, GTK_DRAG_RESULT_GRAB_BROKEN, gtk_get_current_event_time ());
return TRUE;
}
@@ -4134,7 +4142,7 @@ gtk_drag_grab_notify_cb (GtkWidget *widget,
/* We have to block callbacks to avoid recursion here, because
gtk_drag_cancel calls gtk_grab_remove (via gtk_drag_end) */
g_signal_handlers_block_by_func (widget, gtk_drag_grab_notify_cb, data);
- gtk_drag_cancel (info, gtk_get_current_event_time ());
+ gtk_drag_cancel (info, GTK_DRAG_RESULT_GRAB_BROKEN, gtk_get_current_event_time ());
g_signal_handlers_unblock_by_func (widget, gtk_drag_grab_notify_cb, data);
}
}
@@ -4165,7 +4173,7 @@ gtk_drag_button_release_cb (GtkWidget *widget,
}
else
{
- gtk_drag_cancel (info, event->time);
+ gtk_drag_cancel (info, GTK_DRAG_RESULT_NO_TARGET, event->time);
}
return TRUE;
@@ -4181,7 +4189,7 @@ gtk_drag_abort_timeout (gpointer data)
time = info->proxy_dest->proxy_drop_time;
info->drop_timeout = 0;
- gtk_drag_drop_finished (info, FALSE, time);
+ gtk_drag_drop_finished (info, GTK_DRAG_RESULT_TIMEOUT_EXPIRED, time);
return FALSE;
}
diff --git a/gtk/gtkenums.h b/gtk/gtkenums.h
index 85bfd38f82..a3a5e068ce 100644
--- a/gtk/gtkenums.h
+++ b/gtk/gtkenums.h
@@ -514,6 +514,15 @@ typedef enum {
GTK_TREE_VIEW_GRID_LINES_BOTH
} GtkTreeViewGridLines;
+typedef enum {
+ GTK_DRAG_RESULT_SUCCESS,
+ GTK_DRAG_RESULT_NO_TARGET,
+ GTK_DRAG_RESULT_USER_CANCELLED,
+ GTK_DRAG_RESULT_TIMEOUT_EXPIRED,
+ GTK_DRAG_RESULT_GRAB_BROKEN,
+ GTK_DRAG_RESULT_ERROR
+} GtkDragResult;
+
G_END_DECLS
#endif /* __GTK_ENUMS_H__ */
diff --git a/gtk/gtkmarshalers.list b/gtk/gtkmarshalers.list
index c11f42b741..c1510ec2fe 100644
--- a/gtk/gtkmarshalers.list
+++ b/gtk/gtkmarshalers.list
@@ -34,6 +34,7 @@ BOOLEAN:OBJECT,BOXED
BOOLEAN:OBJECT,BOXED,BOXED
BOOLEAN:OBJECT,OBJECT,OBJECT
BOOLEAN:OBJECT,STRING,STRING
+BOOLEAN:OBJECT,ENUM
BOOLEAN:INT
BOOLEAN:INT,INT
BOOLEAN:INT,INT,INT
diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c
index 85d9953fd1..23abb59217 100644
--- a/gtk/gtknotebook.c
+++ b/gtk/gtknotebook.c
@@ -184,13 +184,8 @@ struct _GtkNotebookPrivate
guint has_scrolled : 1;
};
-static const GtkTargetEntry notebook_source_targets [] = {
+static const GtkTargetEntry notebook_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
@@ -267,6 +262,10 @@ static void gtk_notebook_drag_begin (GtkWidget *widget,
GdkDragContext *context);
static void gtk_notebook_drag_end (GtkWidget *widget,
GdkDragContext *context);
+static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
+ GdkDragContext *context,
+ GtkDragResult result,
+ gpointer data);
static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
GdkDragContext *context,
gint x,
@@ -406,6 +405,11 @@ static gboolean focus_child_in (GtkNotebook *notebook,
GtkDirectionType direction);
static void stop_scrolling (GtkNotebook *notebook);
+static void do_detach_tab (GtkNotebook *from,
+ GtkNotebook *to,
+ GtkWidget *child,
+ gint x,
+ gint y);
static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
@@ -1000,8 +1004,8 @@ gtk_notebook_init (GtkNotebook *notebook)
priv->pressed_button = -1;
priv->dnd_timer = 0;
priv->switch_tab_timer = 0;
- priv->source_targets = gtk_target_list_new (notebook_source_targets,
- G_N_ELEMENTS (notebook_source_targets));
+ priv->source_targets = gtk_target_list_new (notebook_targets,
+ G_N_ELEMENTS (notebook_targets));
priv->operation = DRAG_OPERATION_NONE;
priv->detached_tab = NULL;
priv->during_detach = FALSE;
@@ -1009,9 +1013,12 @@ gtk_notebook_init (GtkNotebook *notebook)
gtk_drag_dest_set (GTK_WIDGET (notebook),
GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
- notebook_dest_targets, G_N_ELEMENTS (notebook_dest_targets),
+ notebook_targets, G_N_ELEMENTS (notebook_targets),
GDK_ACTION_MOVE);
+ g_signal_connect (G_OBJECT (notebook), "drag-failed",
+ G_CALLBACK (gtk_notebook_drag_failed), NULL);
+
gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
}
@@ -1470,6 +1477,7 @@ gtk_notebook_get_property (GObject *object,
* gtk_notebook_style_set
* gtk_notebook_drag_begin
* gtk_notebook_drag_end
+ * gtk_notebook_drag_failed
* gtk_notebook_drag_motion
* gtk_notebook_drag_drop
* gtk_notebook_drag_data_get
@@ -2975,8 +2983,8 @@ gtk_notebook_draw_focus (GtkWidget *widget,
GtkNotebook *notebook = GTK_NOTEBOOK (widget);
if (GTK_WIDGET_HAS_FOCUS (widget) && GTK_WIDGET_DRAWABLE (widget) &&
- notebook->cur_page->tab_label->window == event->window &&
- notebook->show_tabs && notebook->cur_page)
+ notebook->show_tabs && notebook->cur_page &&
+ notebook->cur_page->tab_label->window == event->window)
{
GtkNotebookPage *page;
GdkRectangle area;
@@ -3107,6 +3115,38 @@ gtk_notebook_drag_end (GtkWidget *widget,
}
static gboolean
+gtk_notebook_drag_failed (GtkWidget *widget,
+ GdkDragContext *context,
+ GtkDragResult result,
+ gpointer data)
+{
+ if (result == GTK_DRAG_RESULT_NO_TARGET)
+ {
+ GtkNotebookPrivate *priv;
+ GtkNotebook *notebook, *dest_notebook;
+ GdkDisplay *display;
+ gint x, y;
+
+ notebook = GTK_NOTEBOOK (widget);
+ priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
+
+ display = gtk_widget_get_display (widget);
+ gdk_display_get_pointer (display, NULL, &x, &y, NULL);
+
+ dest_notebook = (* window_creation_hook) (notebook,
+ priv->detached_tab->child,
+ x, y,
+ window_creation_hook_data);
+ if (dest_notebook)
+ do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
gtk_notebook_switch_tab_timeout (gpointer data)
{
GtkNotebook *notebook;
@@ -3332,40 +3372,18 @@ gtk_notebook_drag_data_get (GtkWidget *widget,
guint info,
guint time)
{
- GtkNotebook *dest_notebook, *notebook;
GtkNotebookPrivate *priv;
- if (data->target != gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB") &&
- (data->target != gdk_atom_intern_static_string ("application/x-rootwindow-drop") ||
- !window_creation_hook))
- return;
-
- notebook = GTK_NOTEBOOK (widget);
- priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
-
if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
{
+ priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
+
gtk_selection_data_set (data,
data->target,
8,
(void*) &priv->detached_tab->child,
sizeof (gpointer));
}
- else
- {
- GdkDisplay *display;
- gint x, y;
-
- display = gtk_widget_get_display (widget);
- gdk_display_get_pointer (display, NULL, &x, &y, NULL);
-
- dest_notebook = (* window_creation_hook) (notebook,
- priv->detached_tab->child,
- x, y,
- window_creation_hook_data);
- if (dest_notebook)
- do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
- }
}
static void
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index f021bf028d..7a727433d8 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -122,6 +122,7 @@ enum {
GRAB_BROKEN,
COMPOSITED_CHANGED,
KEYNAV_FAILED,
+ DRAG_FAILED,
LAST_SIGNAL
};
@@ -1125,6 +1126,32 @@ gtk_widget_class_init (GtkWidgetClass *klass)
GDK_TYPE_DRAG_CONTEXT);
/**
+ * GtkWidget::drag-failed:
+ * @widget: the object which received the signal.
+ * @drag_context: the drag context.
+ * @result: the result of the drag operation.
+ *
+ * The ::drag-failed signal is emitted on the drag source when a drag has
+ * failed. The signal handler may hook custom code to handle a failed DND
+ * operation based on the type of error, it returns %TRUE is the failure has
+ * been already handled (not showing the default "drag operation failed"
+ * animation), otherwise it returns %FALSE.
+ *
+ * Return value: %TRUE if the failed drag operation has been already handled.
+ *
+ * Since: 2.12
+ */
+ widget_signals[DRAG_FAILED] =
+ g_signal_new (I_("drag_failed"),
+ G_TYPE_FROM_CLASS (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ 0, _gtk_boolean_handled_accumulator, NULL,
+ _gtk_marshal_BOOLEAN__OBJECT_ENUM,
+ G_TYPE_BOOLEAN, 2,
+ GDK_TYPE_DRAG_CONTEXT,
+ GTK_TYPE_DRAG_RESULT);
+
+ /**
* GtkWidget::drag-motion:
* @widget: the object which received the signal.
* @drag_context: the drag context