From cdd7e4c5ec8f44d80c886a071984eaf85b5eed69 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Tue, 11 Feb 2020 17:24:01 +0000 Subject: [PATCH] Add a notify function to GdkContentProvider The callback-based content providers need a GDestroyNotify function to free the data passed to them on construction, otherwise they are going to leak. --- demos/gtk-demo/clipboard.c | 2 +- demos/icon-browser/iconbrowserwin.c | 4 +- gdk/gdkcontentproviderimpl.c | 58 ++++++++++++++++++++++++++--- gdk/gdkcontentproviderimpl.h | 6 ++- gtk/gtkcolorbutton.c | 2 +- gtk/gtkcolorswatch.c | 3 +- gtk/gtkiconview.c | 5 ++- gtk/gtknotebook.c | 3 +- gtk/gtkplacessidebar.c | 3 +- gtk/gtktreeview.c | 5 ++- tests/testdnd2.c | 2 +- 11 files changed, 74 insertions(+), 19 deletions(-) diff --git a/demos/gtk-demo/clipboard.c b/demos/gtk-demo/clipboard.c index e71fb47047..c5a83d7e05 100644 --- a/demos/gtk-demo/clipboard.c +++ b/demos/gtk-demo/clipboard.c @@ -154,7 +154,7 @@ prepare_drag (GtkDragSource *source, double y, GtkWidget *image) { - return gdk_content_provider_new_with_callback (GDK_TYPE_TEXTURE, get_texture, image); + return gdk_content_provider_new_with_callback (GDK_TYPE_TEXTURE, get_texture, image, NULL); } static void diff --git a/demos/icon-browser/iconbrowserwin.c b/demos/icon-browser/iconbrowserwin.c index c0fe825031..d094c029d1 100644 --- a/demos/icon-browser/iconbrowserwin.c +++ b/demos/icon-browser/iconbrowserwin.c @@ -444,7 +444,7 @@ setup_image_dnd (GtkWidget *image) GtkDragSource *source; source = gtk_drag_source_new (); - content = gdk_content_provider_new_with_callback (GDK_TYPE_TEXTURE, get_texture, image); + content = gdk_content_provider_new_with_callback (GDK_TYPE_TEXTURE, get_texture, image, NULL); gtk_drag_source_set_content (source, content); g_object_unref (content); g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), image); @@ -458,7 +458,7 @@ setup_scalable_image_dnd (GtkWidget *image) GtkDragSource *source; source = gtk_drag_source_new (); - content = gdk_content_provider_new_with_callback (G_TYPE_FILE, get_file, image); + content = gdk_content_provider_new_with_callback (G_TYPE_FILE, get_file, image, NULL); gtk_drag_source_set_content (source, content); g_object_unref (content); diff --git a/gdk/gdkcontentproviderimpl.c b/gdk/gdkcontentproviderimpl.c index c114e8c3b2..e5c86a396c 100644 --- a/gdk/gdkcontentproviderimpl.c +++ b/gdk/gdkcontentproviderimpl.c @@ -295,6 +295,7 @@ struct _GdkContentProviderCallback GType type; GdkContentProviderGetValueFunc func; gpointer data; + GDestroyNotify notify; }; struct _GdkContentProviderCallbackClass @@ -330,10 +331,28 @@ gdk_content_provider_callback_get_value (GdkContentProvider *provider, return GDK_CONTENT_PROVIDER_CLASS (gdk_content_provider_callback_parent_class)->get_value (provider, value, error); } +static void +gdk_content_provider_callback_dispose (GObject *gobject) +{ + GdkContentProviderCallback *self = GDK_CONTENT_PROVIDER_CALLBACK (gobject); + + if (self->notify != NULL) + self->notify (self->data); + + self->func = NULL; + self->data = NULL; + self->notify = NULL; + + G_OBJECT_CLASS (gdk_content_provider_callback_parent_class)->dispose (gobject); +} + static void gdk_content_provider_callback_class_init (GdkContentProviderCallbackClass *class) { GdkContentProviderClass *provider_class = GDK_CONTENT_PROVIDER_CLASS (class); + GObjectClass *gobject_class = G_OBJECT_CLASS (class); + + gobject_class->dispose = gdk_content_provider_callback_dispose; provider_class->ref_formats = gdk_content_provider_callback_ref_formats; provider_class->get_value = gdk_content_provider_callback_get_value; @@ -345,10 +364,12 @@ gdk_content_provider_callback_init (GdkContentProviderCallback *content) } /** - * gdk_content_provider_new_for_callback: + * gdk_content_provider_new_for_callback: (constructor) * @type: the type that the callback provides - * @func: callback to populate a #GValue + * @func: (not nullable): callback to populate a #GValue * @data: (closure): data that gets passed to @func + * @notify: a function to be called to free @data when the content provider + * goes away * * Create a content provider that provides data that is provided via a callback. * @@ -357,14 +378,18 @@ gdk_content_provider_callback_init (GdkContentProviderCallback *content) GdkContentProvider * gdk_content_provider_new_with_callback (GType type, GdkContentProviderGetValueFunc func, - gpointer data) + gpointer data, + GDestroyNotify notify) { GdkContentProviderCallback *content; + g_return_val_if_fail (func != NULL, NULL); + content = g_object_new (GDK_TYPE_CONTENT_PROVIDER_CALLBACK, NULL); content->type = type; content->func = func; content->data = data; + content->notify = notify; return GDK_CONTENT_PROVIDER (content); } @@ -382,6 +407,7 @@ struct _GdkContentProviderCallback2 GdkContentFormats *formats; GdkContentProviderGetBytesFunc func; gpointer data; + GDestroyNotify notify; }; struct _GdkContentProviderCallback2Class @@ -472,10 +498,28 @@ gdk_content_provider_callback2_write_mime_type_finish (GdkContentProvider *provi return g_task_propagate_boolean (G_TASK (result), error); } +static void +gdk_content_provider_callback2_dispose (GObject *gobject) +{ + GdkContentProviderCallback2 *self = GDK_CONTENT_PROVIDER_CALLBACK2 (gobject); + + if (self->notify != NULL) + self->notify (self->data); + + self->notify = NULL; + self->data = NULL; + self->func = NULL; + + G_OBJECT_CLASS (gdk_content_provider_callback2_parent_class)->dispose (gobject); +} + static void gdk_content_provider_callback2_class_init (GdkContentProviderCallback2Class *class) { GdkContentProviderClass *provider_class = GDK_CONTENT_PROVIDER_CLASS (class); + GObjectClass *gobject_class = G_OBJECT_CLASS (class); + + gobject_class->dispose = gdk_content_provider_callback2_dispose; provider_class->ref_formats = gdk_content_provider_callback2_ref_formats; provider_class->write_mime_type_async = gdk_content_provider_callback2_write_mime_type_async; @@ -491,7 +535,9 @@ gdk_content_provider_callback2_init (GdkContentProviderCallback2 *content) * gdk_content_provider_new_with_formats: * @formats: formats to advertise * @func: callback to populate a #GValue - * @data: data that gets passed to @func + * @data: (closure func): data that gets passed to @func + * @notify: a function called to free @data when the content provider + * goes away * * Create a content provider that provides data that is provided via a callback. * @@ -500,13 +546,15 @@ gdk_content_provider_callback2_init (GdkContentProviderCallback2 *content) GdkContentProvider * gdk_content_provider_new_with_formats (GdkContentFormats *formats, GdkContentProviderGetBytesFunc func, - gpointer data) + gpointer data, + GDestroyNotify notify) { GdkContentProviderCallback2 *content; content = g_object_new (GDK_TYPE_CONTENT_PROVIDER_CALLBACK2, NULL); content->formats = gdk_content_formats_union_serialize_mime_types (gdk_content_formats_ref (formats)); content->func = func; content->data = data; + content->notify = notify; return GDK_CONTENT_PROVIDER (content); } diff --git a/gdk/gdkcontentproviderimpl.h b/gdk/gdkcontentproviderimpl.h index 19ac6969e1..cea0b6b667 100644 --- a/gdk/gdkcontentproviderimpl.h +++ b/gdk/gdkcontentproviderimpl.h @@ -41,7 +41,8 @@ typedef void (*GdkContentProviderGetValueFunc) (GValue *value, GDK_AVAILABLE_IN_ALL GdkContentProvider * gdk_content_provider_new_with_callback (GType type, GdkContentProviderGetValueFunc func, - gpointer data); + gpointer data, + GDestroyNotify notify); typedef GBytes * (*GdkContentProviderGetBytesFunc) (const char *mime_type, gpointer data); @@ -49,7 +50,8 @@ typedef GBytes * (*GdkContentProviderGetBytesFunc) (const char *mime_type, GDK_AVAILABLE_IN_ALL GdkContentProvider * gdk_content_provider_new_with_formats (GdkContentFormats *formats, GdkContentProviderGetBytesFunc func, - gpointer data); + gpointer data, + GDestroyNotify notify); G_END_DECLS diff --git a/gtk/gtkcolorbutton.c b/gtk/gtkcolorbutton.c index 77e5086941..7ae781cd47 100644 --- a/gtk/gtkcolorbutton.c +++ b/gtk/gtkcolorbutton.c @@ -333,7 +333,7 @@ gtk_color_button_init (GtkColorButton *button) gdk_content_formats_unref (targets); source = gtk_drag_source_new (); - content = gdk_content_provider_new_with_callback (GDK_TYPE_RGBA, get_rgba_value, button); + content = gdk_content_provider_new_with_callback (GDK_TYPE_RGBA, get_rgba_value, button, NULL); gtk_drag_source_set_content (source, content); g_object_unref (content); g_signal_connect (source, "drag-begin", G_CALLBACK (gtk_color_button_drag_begin), button); diff --git a/gtk/gtkcolorswatch.c b/gtk/gtkcolorswatch.c index 270556ed78..e66caa63e3 100644 --- a/gtk/gtkcolorswatch.c +++ b/gtk/gtkcolorswatch.c @@ -598,7 +598,7 @@ gtk_color_swatch_set_rgba (GtkColorSwatch *swatch, GtkDragSource *source; source = gtk_drag_source_new (); - content = gdk_content_provider_new_with_callback (GDK_TYPE_RGBA, get_rgba_value, swatch); + content = gdk_content_provider_new_with_callback (GDK_TYPE_RGBA, get_rgba_value, swatch, NULL); gtk_drag_source_set_content (source, content); g_object_unref (content); g_signal_connect (source, "drag-begin", G_CALLBACK (gtk_color_swatch_drag_begin), swatch); @@ -618,7 +618,6 @@ gtk_color_swatch_set_rgba (GtkColorSwatch *swatch, { gtk_widget_add_css_class (GTK_WIDGET (swatch), "dark"); gtk_widget_remove_css_class (GTK_WIDGET (swatch), "light"); - } gtk_widget_queue_draw (GTK_WIDGET (swatch)); diff --git a/gtk/gtkiconview.c b/gtk/gtkiconview.c index 1d8c7901ea..1cd7b1c3a7 100644 --- a/gtk/gtkiconview.c +++ b/gtk/gtkiconview.c @@ -6055,7 +6055,8 @@ gtk_icon_view_maybe_begin_drag (GtkIconView *icon_view, content = gdk_content_provider_new_with_formats (icon_view->priv->source_formats, gtk_icon_view_drag_data_get, - icon_view); + icon_view, + NULL); drag = gdk_drag_begin (surface, device, @@ -6064,7 +6065,7 @@ gtk_icon_view_maybe_begin_drag (GtkIconView *icon_view, icon_view->priv->press_start_x, icon_view->priv->press_start_y); - g_object_unref (content); + g_object_unref (content); g_signal_connect (drag, "dnd-finished", G_CALLBACK (gtk_icon_view_dnd_finished_cb), icon_view); diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c index 57fd7172f1..6f7894defe 100644 --- a/gtk/gtknotebook.c +++ b/gtk/gtknotebook.c @@ -2882,7 +2882,8 @@ gtk_notebook_motion (GtkEventController *controller, content = gdk_content_provider_new_with_formats (priv->source_targets, gtk_notebook_drag_data_get, - widget); + widget, + NULL); drag = gdk_drag_begin (surface, device, content, GDK_ACTION_MOVE, priv->drag_begin_x, priv->drag_begin_y); g_object_unref (content); diff --git a/gtk/gtkplacessidebar.c b/gtk/gtkplacessidebar.c index 4ed3f3ae3c..92bee5066f 100644 --- a/gtk/gtkplacessidebar.c +++ b/gtk/gtkplacessidebar.c @@ -3759,7 +3759,8 @@ on_row_dragged (GtkGestureDrag *gesture, content = gdk_content_provider_new_with_formats (sidebar->source_targets, drag_data_get_callback, - sidebar); + sidebar, + NULL); surface = gtk_native_get_surface (gtk_widget_get_native (GTK_WIDGET (sidebar))); device = gtk_gesture_get_device (GTK_GESTURE (gesture)); diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c index 011a97c99c..27b0576477 100644 --- a/gtk/gtktreeview.c +++ b/gtk/gtktreeview.c @@ -7109,7 +7109,10 @@ gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view) surface = gtk_native_get_surface (gtk_widget_get_native (GTK_WIDGET (tree_view))); device = gtk_gesture_get_device (GTK_GESTURE (tree_view->drag_gesture)), - content = gdk_content_provider_new_with_formats (di->source_formats, gtk_tree_view_drag_data_get, tree_view); + content = gdk_content_provider_new_with_formats (di->source_formats, + gtk_tree_view_drag_data_get, + tree_view, + NULL); drag = gdk_drag_begin (surface, device, content, di->source_actions, start_x, start_y); diff --git a/tests/testdnd2.c b/tests/testdnd2.c index 5341459989..84ba7abc6e 100644 --- a/tests/testdnd2.c +++ b/tests/testdnd2.c @@ -399,7 +399,7 @@ make_image (const gchar *icon_name, int hotspot) gdk_content_formats_builder_add_gtype (builder, G_TYPE_STRING); formats = gdk_content_formats_builder_free_to_formats (builder); - content = gdk_content_provider_new_with_formats (formats, get_data, image); + content = gdk_content_provider_new_with_formats (formats, get_data, image, NULL); source = gtk_drag_source_new (); gtk_drag_source_set_content (source, content); gtk_drag_source_set_actions (source, GDK_ACTION_COPY|GDK_ACTION_MOVE|GDK_ACTION_ASK);