From 27d7aa14072af75cb0f8257feafded57fc340497 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Mon, 17 Feb 2020 03:58:28 +0100 Subject: [PATCH] notebook: Use proper DND Actually use GValues for the DND operation instead of sending GBytes of pointer addresses through pipes. This is a bit complicated because we need to special-case rootwindow drops, because they're handled on the source side, so we need a custom ContentProvider. --- gtk/gtknotebook.c | 185 +++++++++++++++++++++++++++------------------- 1 file changed, 111 insertions(+), 74 deletions(-) diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c index 1d9370649a..d627c735b2 100644 --- a/gtk/gtknotebook.c +++ b/gtk/gtknotebook.c @@ -235,7 +235,6 @@ struct _GtkNotebookPrivate GtkNotebookDragOperation operation; GtkNotebookPage *cur_page; GtkNotebookPage *detached_tab; - GdkContentFormats *source_targets; GtkWidget *action_widget[N_ACTION_WIDGETS]; GtkWidget *menu; GtkWidget *menu_box; @@ -645,15 +644,105 @@ gtk_notebook_page_class_init (GtkNotebookPageClass *class) } -static const char *src_notebook_targets [] = { - "GTK_NOTEBOOK_TAB", - "application/x-rootwindow-drop" +#define GTK_TYPE_NOTEBOOK_ROOT_CONTENT (gtk_notebook_root_content_get_type ()) +#define GTK_NOTEBOOK_ROOT_CONTENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_NOTEBOOK_ROOT_CONTENT, GtkNotebookRootContent)) +#define GTK_IS_NOTEBOOK_ROOT_CONTENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_NOTEBOOK_ROOT_CONTENT)) + +typedef struct _GtkNotebookRootContent GtkNotebookRootContent; +typedef struct _GtkNotebookRootContentClass GtkNotebookRootContentClass; + +struct _GtkNotebookRootContent +{ + GdkContentProvider parent_instance; + + GtkNotebook *notebook; }; -static const char *dst_notebook_targets [] = { - "GTK_NOTEBOOK_TAB" +struct _GtkNotebookRootContentClass +{ + GdkContentProviderClass parent_class; }; +static GdkContentFormats * +gtk_notebook_root_content_ref_formats (GdkContentProvider *provider) +{ + return gdk_content_formats_new ((const char *[1]) { "application/x-rootwindow-drop" }, 1); +} + +GType gtk_notebook_root_content_get_type (void); + +G_DEFINE_TYPE (GtkNotebookRootContent, gtk_notebook_root_content, GDK_TYPE_CONTENT_PROVIDER) + +static void +gtk_notebook_root_content_write_mime_type_async (GdkContentProvider *provider, + const char *mime_type, + GOutputStream *stream, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GtkNotebookRootContent *self = GTK_NOTEBOOK_ROOT_CONTENT (provider); + GtkNotebookPrivate *priv = self->notebook->priv; + GTask *task; + + priv->rootwindow_drop = TRUE; + + task = g_task_new (self, cancellable, callback, user_data); + g_task_set_priority (task, io_priority); + g_task_set_source_tag (task, gtk_notebook_root_content_write_mime_type_async); + g_task_return_boolean (task, TRUE); + g_object_unref (task); +} + +static gboolean +gtk_notebook_root_content_write_mime_type_finish (GdkContentProvider *provider, + GAsyncResult *result, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (result), error); +} + +static void +gtk_notebook_root_content_finalize (GObject *object) +{ + GtkNotebookRootContent *self = GTK_NOTEBOOK_ROOT_CONTENT (object); + + g_object_unref (self->notebook); + + G_OBJECT_CLASS (gtk_notebook_root_content_parent_class)->finalize (object); +} + +static void +gtk_notebook_root_content_class_init (GtkNotebookRootContentClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + GdkContentProviderClass *provider_class = GDK_CONTENT_PROVIDER_CLASS (class); + + object_class->finalize = gtk_notebook_root_content_finalize; + + provider_class->ref_formats = gtk_notebook_root_content_ref_formats; + provider_class->write_mime_type_async = gtk_notebook_root_content_write_mime_type_async; + provider_class->write_mime_type_finish = gtk_notebook_root_content_write_mime_type_finish; +} + +static void +gtk_notebook_root_content_init (GtkNotebookRootContent *self) +{ +} + +static GdkContentProvider * +gtk_notebook_root_content_new (GtkNotebook *notebook) +{ + GtkNotebookRootContent *result; + + result = g_object_new (GTK_TYPE_NOTEBOOK_ROOT_CONTENT, NULL); + + result->notebook = g_object_ref (notebook); + + return GDK_CONTENT_PROVIDER (result); +} + /*** GtkNotebook Methods ***/ static gboolean gtk_notebook_select_page (GtkNotebook *notebook, gboolean move_focus); @@ -713,8 +802,6 @@ static gboolean gtk_notebook_drag_drop (GtkDropTarget *dest, GdkDrop *drop, int x, int y); -static GBytes * gtk_notebook_drag_data_get (const char *mime_type, - gpointer data); /*** GtkContainer Methods ***/ static void gtk_notebook_add (GtkContainer *container, @@ -1321,8 +1408,6 @@ gtk_notebook_init (GtkNotebook *notebook) priv->pressed_button = 0; priv->dnd_timer = 0; priv->switch_tab_timer = 0; - priv->source_targets = gdk_content_formats_new (src_notebook_targets, - G_N_ELEMENTS (src_notebook_targets)); priv->operation = DRAG_OPERATION_NONE; priv->detached_tab = NULL; priv->has_scrolled = FALSE; @@ -1347,7 +1432,7 @@ gtk_notebook_init (GtkNotebook *notebook) gtk_widget_set_vexpand (priv->stack_widget, TRUE); gtk_widget_set_parent (priv->stack_widget, GTK_WIDGET (notebook)); - dest = gtk_drop_target_new (gdk_content_formats_new (dst_notebook_targets, G_N_ELEMENTS (dst_notebook_targets)), GDK_ACTION_MOVE); + dest = gtk_drop_target_new (gdk_content_formats_new_for_gtype (GTK_TYPE_NOTEBOOK_PAGE), GDK_ACTION_MOVE); g_signal_connect (dest, "drag-motion", G_CALLBACK (gtk_notebook_drag_motion), NULL); g_signal_connect (dest, "drag-leave", G_CALLBACK (gtk_notebook_drag_leave), NULL); g_signal_connect (dest, "drag-drop", G_CALLBACK (gtk_notebook_drag_drop), NULL); @@ -1843,11 +1928,6 @@ gtk_notebook_destroy (GtkWidget *widget) if (priv->pages) g_list_model_items_changed (G_LIST_MODEL (priv->pages), 0, g_list_length (priv->children), 0); - if (priv->source_targets) - { - gdk_content_formats_unref (priv->source_targets); - priv->source_targets = NULL; - } remove_switch_tab_timer (notebook); @@ -2877,10 +2957,10 @@ gtk_notebook_motion (GtkEventController *controller, surface = gtk_native_get_surface (gtk_widget_get_native (GTK_WIDGET (notebook))); device = gtk_get_current_event_device (); - content = gdk_content_provider_new_with_formats (priv->source_targets, - gtk_notebook_drag_data_get, - widget, - NULL); + content = gdk_content_provider_new_union ((GdkContentProvider *[2]) { + gtk_notebook_root_content_new (notebook), + gdk_content_provider_new_typed (GTK_TYPE_NOTEBOOK_PAGE, priv->cur_page) + }, 2); drag = gdk_drag_begin (surface, device, content, GDK_ACTION_MOVE, priv->drag_begin_x, priv->drag_begin_y); g_object_unref (content); @@ -3241,13 +3321,11 @@ gtk_notebook_drag_motion (GtkDropTarget *dest, GtkNotebook *notebook = GTK_NOTEBOOK (widget); GtkNotebookPrivate *priv = notebook->priv; graphene_rect_t position; - GdkAtom target, tab_target; + GdkContentFormats *formats; GList *tab; - target = gtk_drop_target_find_mimetype (dest); - tab_target = g_intern_static_string ("GTK_NOTEBOOK_TAB"); - - if (target == tab_target) + formats = gtk_drop_target_get_formats (dest); + if (gdk_content_formats_contain_gtype (formats, GTK_TYPE_NOTEBOOK_PAGE)) { GQuark group, source_group; GtkWidget *source_child; @@ -3320,34 +3398,26 @@ gtk_notebook_drag_leave (GtkDropTarget *dest) } static void -got_page (GObject *source, +got_page (GObject *source, GAsyncResult *result, - gpointer data) + gpointer data) { GtkNotebook *notebook = GTK_NOTEBOOK (data); GdkDrop *drop = GDK_DROP (source); GdkDrag *drag = gdk_drop_get_drag (drop); GtkWidget *source_widget; - GInputStream *stream; - const char *mime_type; + const GValue *value; source_widget = GTK_WIDGET (drag ? g_object_get_data (G_OBJECT (drag), "gtk-notebook-drag-origin") : NULL); - stream = gdk_drop_read_finish (drop, result, &mime_type, NULL); + value = gdk_drop_read_value_finish (drop, result, NULL); - if (stream) + if (value) { - GBytes *bytes; - GtkWidget **child; + GtkNotebookPage *page = g_value_get_object (value); - bytes = g_input_stream_read_bytes (stream, sizeof (gpointer), NULL, NULL); - child = (gpointer)g_bytes_get_data (bytes, NULL); - - do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child); + do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, page->child); gdk_drop_finish (drop, GDK_ACTION_MOVE); - - g_bytes_unref (bytes); - g_object_unref (stream); } else gdk_drop_finish (drop, 0); @@ -3364,21 +3434,16 @@ gtk_notebook_drag_drop (GtkDropTarget *dest, GtkNotebook *notebook = GTK_NOTEBOOK (widget); GdkDrag *drag = gdk_drop_get_drag (drop); GtkWidget *source_widget; - GdkAtom target, tab_target; source_widget = GTK_WIDGET (drag ? g_object_get_data (G_OBJECT (drag), "gtk-notebook-drag-origin") : NULL); - target = gtk_drop_target_find_mimetype (dest); - tab_target = g_intern_static_string ("GTK_NOTEBOOK_TAB"); - if (GTK_IS_NOTEBOOK (source_widget) && - target == tab_target && (gdk_drop_get_actions (drop) & GDK_ACTION_MOVE)) { notebook->priv->mouse_x = x; notebook->priv->mouse_y = y; - gdk_drop_read_async (drop, (const char *[]) { "GTK_NOTEBOOK_TAB", NULL }, G_PRIORITY_DEFAULT, NULL, got_page, notebook); + gdk_drop_read_value_async (drop, GTK_TYPE_NOTEBOOK_PAGE, G_PRIORITY_DEFAULT, NULL, got_page, notebook); return TRUE; } @@ -3467,34 +3532,6 @@ do_detach_tab (GtkNotebook *from, gtk_notebook_set_current_page (to, page_num); } -static GBytes * -gtk_notebook_drag_data_get (const char *mime_type, - gpointer data) -{ - GtkNotebook *notebook = GTK_NOTEBOOK (data); - GtkNotebookPrivate *priv = notebook->priv; - GtkSelectionData sdata = { 0, }; - - sdata.target = g_intern_string (mime_type); - - if (sdata.target == g_intern_static_string ("GTK_NOTEBOOK_TAB")) - { - gtk_selection_data_set (&sdata, - sdata.target, - 8, - (void*) &priv->detached_tab->child, - sizeof (gpointer)); - priv->rootwindow_drop = FALSE; - } - else if (sdata.target == g_intern_static_string ("application/x-rootwindow-drop")) - { - gtk_selection_data_set (&sdata, sdata.target, 8, NULL, 0); - priv->rootwindow_drop = TRUE; - } - - return g_bytes_new_take (sdata.data, sdata.length); -} - /* Private GtkContainer Methods : * * gtk_notebook_add