dnd: Remove gdk_content_provider_new_with_callback()

Content providers are meant to be immutable, apart from very special
cases, but in those cases they need to emit
gdk_content_provider_content_changed().

Having a constructor that just uses a get_func invites abuse of this
by not making developers aware of those requirments.
In fact, all users in GTK failed to do this.

Instead, code should use the GtkDragSource::prepare signal to create
content providers when needed.

The same problem exists with gdk_content_provider_new_with_formats(),
but this commit doesn't touch that.
This commit is contained in:
Benjamin Otte 2020-02-16 16:22:37 +01:00
parent dbad440468
commit da83457a60
6 changed files with 48 additions and 172 deletions

View File

@ -138,23 +138,18 @@ drag_begin (GtkDragSource *source,
}
}
static void
get_texture (GValue *value,
gpointer data)
{
GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (data));
if (GDK_IS_TEXTURE (paintable))
g_value_set_object (value, paintable);
}
static GdkContentProvider *
prepare_drag (GtkDragSource *source,
double x,
double y,
GtkWidget *image)
{
return gdk_content_provider_new_with_callback (GDK_TYPE_TEXTURE, get_texture, image, NULL);
GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (image));
if (!GDK_IS_TEXTURE (paintable))
return NULL;
return gdk_content_provider_new_typed (GDK_TYPE_TEXTURE, paintable);
}
static void

View File

@ -406,47 +406,53 @@ drag_begin (GtkDragSource *source,
}
}
static void
get_texture (GValue *value,
gpointer data)
static GdkContentProvider *
drag_prepare_texture (GtkDragSource *source,
double x,
double y,
GtkWidget *widget)
{
GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (data));
GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (widget));
if (GDK_IS_TEXTURE (paintable))
g_value_set_object (value, paintable);
if (!GDK_IS_TEXTURE (paintable))
return NULL;
return gdk_content_provider_new_typed (GDK_TYPE_TEXTURE, paintable);
}
static void
get_file (GValue *value,
gpointer data)
static GdkContentProvider *
drag_prepare_file (GtkDragSource *source,
double x,
double y,
GtkWidget *widget)
{
GdkContentProvider *content;
GtkIconTheme *icon_theme;
const char *name;
GtkIconPaintable *info;
name = gtk_image_get_icon_name (GTK_IMAGE (data));
icon_theme = gtk_icon_theme_get_for_display (gtk_widget_get_display (GTK_WIDGET (data)));
name = gtk_image_get_icon_name (GTK_IMAGE (widget));
icon_theme = gtk_icon_theme_get_for_display (gtk_widget_get_display (widget));
info = gtk_icon_theme_lookup_icon (icon_theme,
name,
NULL,
32, 1,
gtk_widget_get_direction (GTK_WIDGET (data)),
gtk_widget_get_direction (widget),
0);
g_value_take_object (value, gtk_icon_paintable_get_file (info));
content = gdk_content_provider_new_typed (G_TYPE_FILE, gtk_icon_paintable_get_file (info));
g_object_unref (info);
return content;
}
static void
setup_image_dnd (GtkWidget *image)
{
GdkContentProvider *content;
GtkDragSource *source;
source = gtk_drag_source_new ();
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, "prepare", G_CALLBACK (drag_prepare_texture), image);
g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), image);
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (source));
}
@ -454,14 +460,10 @@ setup_image_dnd (GtkWidget *image)
static void
setup_scalable_image_dnd (GtkWidget *image)
{
GdkContentProvider *content;
GtkDragSource *source;
source = gtk_drag_source_new ();
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);
g_signal_connect (source, "prepare", G_CALLBACK (drag_prepare_file), image);
g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), image);
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (source));
}

View File

@ -322,118 +322,6 @@ gdk_content_provider_new_for_bytes (const char *mime_type,
return GDK_CONTENT_PROVIDER (content);
}
#define GDK_TYPE_CONTENT_PROVIDER_CALLBACK (gdk_content_provider_callback_get_type ())
#define GDK_CONTENT_PROVIDER_CALLBACK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_CONTENT_PROVIDER_CALLBACK, GdkContentProviderCallback))
typedef struct _GdkContentProviderCallback GdkContentProviderCallback;
typedef struct _GdkContentProviderCallbackClass GdkContentProviderCallbackClass;
struct _GdkContentProviderCallback
{
GdkContentProvider parent;
GType type;
GdkContentProviderGetValueFunc func;
gpointer data;
GDestroyNotify notify;
};
struct _GdkContentProviderCallbackClass
{
GdkContentProviderClass parent_class;
};
GType gdk_content_provider_callback_get_type (void) G_GNUC_CONST;
G_DEFINE_TYPE (GdkContentProviderCallback, gdk_content_provider_callback, GDK_TYPE_CONTENT_PROVIDER)
static GdkContentFormats *
gdk_content_provider_callback_ref_formats (GdkContentProvider *provider)
{
GdkContentProviderCallback *callback = GDK_CONTENT_PROVIDER_CALLBACK (provider);
return gdk_content_formats_new_for_gtype (callback->type);
}
static gboolean
gdk_content_provider_callback_get_value (GdkContentProvider *provider,
GValue *value,
GError **error)
{
GdkContentProviderCallback *callback = GDK_CONTENT_PROVIDER_CALLBACK (provider);
if (G_VALUE_HOLDS (value, callback->type) && callback->func != NULL)
{
callback->func (value, callback->data);
return TRUE;
}
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;
}
static void
gdk_content_provider_callback_init (GdkContentProviderCallback *content)
{
}
/**
* gdk_content_provider_new_for_callback: (constructor)
* @type: the type that the callback provides
* @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.
*
* Returns: a new #GdkContentProvider
**/
GdkContentProvider *
gdk_content_provider_new_with_callback (GType type,
GdkContentProviderGetValueFunc func,
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);
}
#define GDK_TYPE_CONTENT_PROVIDER_CALLBACK2 (gdk_content_provider_callback2_get_type ())
#define GDK_CONTENT_PROVIDER_CALLBACK2(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_CONTENT_PROVIDER_CALLBACK2, GdkContentProviderCallback2))

View File

@ -38,15 +38,6 @@ GDK_AVAILABLE_IN_ALL
GdkContentProvider * gdk_content_provider_new_for_bytes (const char *mime_type,
GBytes *bytes);
typedef void (*GdkContentProviderGetValueFunc) (GValue *value,
gpointer data);
GDK_AVAILABLE_IN_ALL
GdkContentProvider * gdk_content_provider_new_with_callback (GType type,
GdkContentProviderGetValueFunc func,
gpointer data,
GDestroyNotify notify);
typedef GBytes * (*GdkContentProviderGetBytesFunc) (const char *mime_type,
gpointer data);

View File

@ -285,12 +285,15 @@ gtk_color_button_drag_begin (GtkDragSource *source,
g_object_unref (paintable);
}
static void
get_rgba_value (GValue *value,
gpointer data)
static GdkContentProvider *
gtk_color_button_drag_prepare (GtkDragSource *source,
double x,
double y,
GtkColorButton *button)
{
GtkColorButtonPrivate *priv = gtk_color_button_get_instance_private (GTK_COLOR_BUTTON (data));
g_value_set_boxed (value, &priv->rgba);
GtkColorButtonPrivate *priv = gtk_color_button_get_instance_private (button);
return gdk_content_provider_new_typed (GDK_TYPE_RGBA, &priv->rgba);
}
static void
@ -300,7 +303,6 @@ gtk_color_button_init (GtkColorButton *button)
PangoLayout *layout;
PangoRectangle rect;
GdkContentFormats *targets;
GdkContentProvider *content;
GtkDragSource *source;
GtkDropTarget *dest;
@ -333,9 +335,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, NULL);
gtk_drag_source_set_content (source, content);
g_object_unref (content);
g_signal_connect (source, "prepare", G_CALLBACK (gtk_color_button_drag_prepare), button);
g_signal_connect (source, "drag-begin", G_CALLBACK (gtk_color_button_drag_begin), button);
gtk_widget_add_controller (priv->button, GTK_EVENT_CONTROLLER (source));

View File

@ -578,12 +578,15 @@ static const char *dnd_targets[] = {
"application/x-color"
};
static void
get_rgba_value (GValue *value,
gpointer data)
static GdkContentProvider *
gtk_color_swatch_drag_prepare (GtkDragSource *source,
double x,
double y,
GtkColorSwatch *swatch)
{
GtkColorSwatchPrivate *priv = gtk_color_swatch_get_instance_private (GTK_COLOR_SWATCH (data));
g_value_set_boxed (value, &priv->color);
GtkColorSwatchPrivate *priv = gtk_color_swatch_get_instance_private (swatch);
return gdk_content_provider_new_typed (GDK_TYPE_RGBA, &priv->color);
}
void
@ -594,13 +597,10 @@ gtk_color_swatch_set_rgba (GtkColorSwatch *swatch,
if (!priv->has_color)
{
GdkContentProvider *content;
GtkDragSource *source;
source = gtk_drag_source_new ();
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, "prepare", G_CALLBACK (gtk_color_swatch_drag_prepare), swatch);
g_signal_connect (source, "drag-begin", G_CALLBACK (gtk_color_swatch_drag_begin), swatch);
gtk_widget_add_controller (GTK_WIDGET (swatch), GTK_EVENT_CONTROLLER (source));