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.
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user