From 2a697827e18e06aa2727cc6dbab5e05154127392 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Mon, 2 Mar 2020 03:11:14 +0100 Subject: [PATCH] dragicon: Add gtk_drag_icon_create_widget_for_value() ... and use it to set a drag icon. --- docs/reference/gtk/gtk4-sections.txt | 3 ++ gtk/gtkdragicon.c | 64 ++++++++++++++++++++++++++++ gtk/gtkdragicon.h | 2 + gtk/gtkdragsource.c | 64 ++++++++++++++++++++-------- 4 files changed, 116 insertions(+), 17 deletions(-) diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index 419b28193c..689ac2b024 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -6885,6 +6885,9 @@ gtk_drag_icon_set_child gtk_drag_icon_get_child gtk_drag_icon_set_from_paintable + +gtk_drag_icon_create_widget_for_value + GTK_TYPE_DRAG_ICON GTK_DRAG_ICON diff --git a/gtk/gtkdragicon.c b/gtk/gtkdragicon.c index 4e1afa522a..a01e088946 100644 --- a/gtk/gtkdragicon.c +++ b/gtk/gtkdragicon.c @@ -29,6 +29,11 @@ #include "gtkpicture.h" #include "gtkcssnumbervalueprivate.h" +/* for the drag icons */ +#include "gtkcolorswatchprivate.h" +#include "gtklabel.h" +#include "gtktextutil.h" + /** * SECTION:gtkdragicon @@ -497,3 +502,62 @@ gtk_drag_icon_get_child (GtkDragIcon *self) return self->child; } +/** + * gtk_drag_icon_create_widget_for_value: + * @value: a #GValue + * + * Creates a widget that can be used as a drag icon for the given + * @value. + * + * If GTK does not know how to create a widget for a given value, + * it will return %NULL. + * + * This method is used to set the default drag icon on drag'n'drop + * operations started by #GtkDragSource, so you don't need to set + * a drag icon using this function there. + * + * Returns: (nullable) (transfer full): A new #GtkWidget + * for displaying @value as a drag icon. + **/ +GtkWidget * +gtk_drag_icon_create_widget_for_value (const GValue *value) +{ + g_return_val_if_fail (G_IS_VALUE (value), NULL); + + if (G_VALUE_HOLDS (value, G_TYPE_STRING)) + { + return gtk_label_new (g_value_get_string (value)); + } + else if (G_VALUE_HOLDS (value, GDK_TYPE_RGBA)) + { + GtkWidget *swatch; + + swatch = gtk_color_swatch_new (); + gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (swatch), g_value_get_boxed (value)); + + return swatch; + } + else if (G_VALUE_HOLDS (value, GTK_TYPE_TEXT_BUFFER)) + { + GtkTextBuffer *buffer = g_value_get_object (value); + GtkTextIter start, end; + GdkPaintable *paintable; + GtkWidget *picture; + + if (buffer == NULL || !gtk_text_buffer_get_selection_bounds (buffer, &start, &end)) + return NULL; + + picture = gtk_picture_new (); + paintable = gtk_text_util_create_rich_drag_icon (picture, buffer, &start, &end); + gtk_picture_set_paintable (GTK_PICTURE (picture), paintable); + gtk_picture_set_can_shrink (GTK_PICTURE (picture), FALSE); + g_object_unref (paintable); + + return picture; + } + else + { + return NULL; + } +} + diff --git a/gtk/gtkdragicon.h b/gtk/gtkdragicon.h index b8c70d6f86..3be995773a 100644 --- a/gtk/gtkdragicon.h +++ b/gtk/gtkdragicon.h @@ -52,6 +52,8 @@ void gtk_drag_icon_set_from_paintable (GdkDrag *drag, int hot_x, int hot_y); +GtkWidget * gtk_drag_icon_create_widget_for_value (const GValue *value); + G_END_DECLS diff --git a/gtk/gtkdragsource.c b/gtk/gtkdragsource.c index 6b6c4d38de..017bee493c 100644 --- a/gtk/gtkdragsource.c +++ b/gtk/gtkdragsource.c @@ -439,6 +439,52 @@ gtk_drag_source_cancel_cb (GdkDrag *drag, drag_end (source, FALSE); } +static void +gtk_drag_source_ensure_icon (GtkDragSource *self, + GdkDrag *drag) +{ + GdkContentProvider *provider; + GtkWidget *icon, *child; + GdkContentFormats *formats; + const GType *types; + gsize i, n_types; + + icon = gtk_drag_icon_get_for_drag (drag); + /* If an icon has been set already, we don't need to set one. */ + if (gtk_drag_icon_get_child (GTK_DRAG_ICON (icon))) + return; + + gdk_drag_set_hotspot (drag, -2, -2); + + provider = gdk_drag_get_content (drag); + formats = gdk_content_provider_ref_formats (provider); + types = gdk_content_formats_get_gtypes (formats, &n_types); + for (i = 0; i < n_types; i++) + { + GValue value = G_VALUE_INIT; + + g_value_init (&value, types[i]); + if (gdk_content_provider_get_value (provider, &value, NULL)) + { + child = gtk_drag_icon_create_widget_for_value (&value); + + if (child) + { + gtk_drag_icon_set_child (GTK_DRAG_ICON (icon), child); + g_value_unset (&value); + gdk_content_formats_unref (formats); + return; + } + } + g_value_unset (&value); + } + + gdk_content_formats_unref (formats); + child = gtk_image_new_from_icon_name ("text-x-generic"); + gtk_image_set_icon_size (GTK_IMAGE (child), GTK_ICON_SIZE_LARGE); + gtk_drag_icon_set_child (GTK_DRAG_ICON (icon), child); +} + static void gtk_drag_source_drag_begin (GtkDragSource *source) { @@ -481,23 +527,7 @@ gtk_drag_source_drag_begin (GtkDragSource *source) g_signal_emit (source, signals[DRAG_BEGIN], 0, source->drag); - if (!source->paintable) - { - GtkIconTheme *theme; - - theme = gtk_icon_theme_get_for_display (gtk_widget_get_display (widget)); - source->paintable = GDK_PAINTABLE(gtk_icon_theme_lookup_icon (theme, - "text-x-generic", - NULL, - 32, - 1, - gtk_widget_get_direction (widget), - 0)); - source->hot_x = 0; - source->hot_y = 0; - } - - gtk_drag_icon_set_from_paintable (source->drag, source->paintable, source->hot_x, source->hot_y); + gtk_drag_source_ensure_icon (source, source->drag); g_signal_connect (source->drag, "dnd-finished", G_CALLBACK (gtk_drag_source_dnd_finished_cb), source);