diff --git a/gtk/gtkcolorswatch.c b/gtk/gtkcolorswatch.c index c88a428c01..c8b7641227 100644 --- a/gtk/gtkcolorswatch.c +++ b/gtk/gtkcolorswatch.c @@ -67,6 +67,7 @@ typedef struct GtkWidget *overlay_widget; GtkWidget *popover; + GtkDropTarget *dest; } GtkColorSwatchPrivate; enum @@ -74,7 +75,8 @@ enum PROP_ZERO, PROP_RGBA, PROP_SELECTABLE, - PROP_HAS_MENU + PROP_HAS_MENU, + PROP_CAN_DROP }; G_DEFINE_TYPE_WITH_PRIVATE (GtkColorSwatch, gtk_color_swatch, GTK_TYPE_WIDGET) @@ -132,36 +134,39 @@ gtk_color_swatch_drag_begin (GtkDragSource *source, } static void -swatch_drag_data_received (GtkWidget *widget, - GdkDrop *drop, - GtkSelectionData *selection_data) +got_color (GObject *source, + GAsyncResult *result, + gpointer data) { - gint length; - guint16 *vals; - GdkRGBA color; + GdkDrop *drop = GDK_DROP (source); + const GValue *value; - length = gtk_selection_data_get_length (selection_data); - - if (length < 0) - return; - - /* We accept drops with the wrong format, since the KDE color - * chooser incorrectly drops application/x-color with format 8. - */ - if (length != 8) + value = gdk_drop_read_value_finish (drop, result, NULL); + if (value) { - g_warning ("Received invalid color data"); - return; + GdkRGBA *color = g_value_get_boxed (value); + gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (data), color); + gdk_drop_finish (drop, GDK_ACTION_COPY); + } + else + gdk_drop_finish (drop, 0); +} + +static gboolean +swatch_drag_drop (GtkDropTarget *dest, + int x, + int y, + GtkColorSwatch *swatch) +{ + GdkDrop *drop = gtk_drop_target_get_drop (dest); + + if (gdk_drop_has_value (drop, GDK_TYPE_RGBA)) + { + gdk_drop_read_value_async (drop, GDK_TYPE_RGBA, G_PRIORITY_DEFAULT, NULL, got_color, swatch); + return TRUE; } - vals = (guint16 *) gtk_selection_data_get_data (selection_data); - - color.red = (gdouble)vals[0] / 0xffff; - color.green = (gdouble)vals[1] / 0xffff; - color.blue = (gdouble)vals[2] / 0xffff; - color.alpha = (gdouble)vals[3] / 0xffff; - - gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (widget), &color); + return FALSE; } static void @@ -423,6 +428,9 @@ swatch_get_property (GObject *object, case PROP_HAS_MENU: g_value_set_boolean (value, priv->has_menu); break; + case PROP_CAN_DROP: + g_value_set_boolean (value, priv->dest != NULL); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -449,6 +457,9 @@ swatch_set_property (GObject *object, case PROP_HAS_MENU: priv->has_menu = g_value_get_boolean (value); break; + case PROP_CAN_DROP: + gtk_color_swatch_set_can_drop (swatch, g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -463,7 +474,8 @@ swatch_finalize (GObject *object) g_free (priv->icon); gtk_widget_unparent (priv->overlay_widget); - + g_clear_pointer (&priv->dest, gtk_drop_target_detach); + G_OBJECT_CLASS (gtk_color_swatch_parent_class)->finalize (object); } @@ -491,7 +503,6 @@ gtk_color_swatch_class_init (GtkColorSwatchClass *class) widget_class->measure = gtk_color_swatch_measure; widget_class->snapshot = swatch_snapshot; - widget_class->drag_data_received = swatch_drag_data_received; widget_class->popup_menu = swatch_popup_menu; widget_class->size_allocate = swatch_size_allocate; widget_class->state_flags_changed = swatch_state_flags_changed; @@ -505,6 +516,9 @@ gtk_color_swatch_class_init (GtkColorSwatchClass *class) g_object_class_install_property (object_class, PROP_HAS_MENU, g_param_spec_boolean ("has-menu", P_("Has Menu"), P_("Whether the swatch should offer customization"), TRUE, GTK_PARAM_READWRITE)); + g_object_class_install_property (object_class, PROP_CAN_DROP, + g_param_spec_boolean ("can-drop", P_("Can Drop"), P_("Whether the swatch should accept drops"), + FALSE, GTK_PARAM_READWRITE)); gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_COLOR_SWATCH_ACCESSIBLE); gtk_widget_class_set_css_name (widget_class, I_("colorswatch")); @@ -653,21 +667,27 @@ void gtk_color_swatch_set_can_drop (GtkColorSwatch *swatch, gboolean can_drop) { - if (can_drop) + GtkColorSwatchPrivate *priv = gtk_color_swatch_get_instance_private (swatch); + + if (can_drop == (priv->dest != NULL)) + return; + + if (can_drop && !priv->dest) { - GdkContentFormats *targets = gdk_content_formats_new (dnd_targets, G_N_ELEMENTS (dnd_targets)); - gtk_drag_dest_set (GTK_WIDGET (swatch), - GTK_DEST_DEFAULT_HIGHLIGHT | - GTK_DEST_DEFAULT_MOTION | - GTK_DEST_DEFAULT_DROP, - targets, - GDK_ACTION_COPY); + GdkContentFormats *targets; + + targets = gdk_content_formats_new (dnd_targets, G_N_ELEMENTS (dnd_targets)); + priv->dest = gtk_drop_target_new (GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT, targets, GDK_ACTION_COPY); + g_signal_connect (priv->dest, "drag-drop", G_CALLBACK (swatch_drag_drop), swatch); + gtk_drop_target_attach (priv->dest, GTK_WIDGET (swatch)); gdk_content_formats_unref (targets); } - else + if (!can_drop && priv->dest) { - gtk_drag_dest_unset (GTK_WIDGET (swatch)); + g_clear_pointer (&priv->dest, gtk_drop_target_detach); } + + g_object_notify (G_OBJECT (swatch), "can-drop"); } void