[gtk/wip/otte/dnd: 4/8] notebook: Use proper DND



commit 27d7aa14072af75cb0f8257feafded57fc340497
Author: Benjamin Otte <otte redhat com>
Date:   Mon Feb 17 03:58:28 2020 +0100

    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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]