/* GIMP - The GNU Image Manipulation Program * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "config.h" #include #include #include "libgimpcolor/gimpcolor.h" #include "libgimpwidgets/gimpwidgets.h" #include "widgets-types.h" #include "config/gimpcoreconfig.h" #include "core/gimp.h" #include "core/gimpbrush.h" #include "core/gimpbuffer.h" #include "core/gimpchannel.h" #include "core/gimpcontainer.h" #include "core/gimpdatafactory.h" #include "core/gimpdrawable.h" #include "core/gimpgradient.h" #include "core/gimpimage.h" #include "core/gimpimagefile.h" #include "core/gimplayer.h" #include "core/gimplayermask.h" #include "core/gimppalette.h" #include "core/gimppattern.h" #include "core/gimptemplate.h" #include "core/gimptoolitem.h" #include "text/gimpfont.h" #include "vectors/gimpvectors.h" #include "gimpdnd.h" #include "gimpdnd-xds.h" #include "gimppixbuf.h" #include "gimpselectiondata.h" #include "gimpview.h" #include "gimpviewrendererimage.h" #include "gimp-log.h" #include "gimp-intl.h" #define DRAG_PREVIEW_SIZE GIMP_VIEW_SIZE_LARGE #define DRAG_ICON_OFFSET -8 typedef GtkWidget * (* GimpDndGetIconFunc) (GtkWidget *widget, GdkDragContext *context, GCallback get_data_func, gpointer get_data_data); typedef void (* GimpDndDragDataFunc) (GtkWidget *widget, GdkDragContext *context, GCallback get_data_func, gpointer get_data_data, GtkSelectionData *selection); typedef gboolean (* GimpDndDropDataFunc) (GtkWidget *widget, gint x, gint y, GCallback set_data_func, gpointer set_data_data, GtkSelectionData *selection); typedef struct _GimpDndDataDef GimpDndDataDef; struct _GimpDndDataDef { GtkTargetEntry target_entry; const gchar *get_data_func_name; const gchar *get_data_data_name; const gchar *set_data_func_name; const gchar *set_data_data_name; GimpDndGetIconFunc get_icon_func; GimpDndDragDataFunc get_data_func; GimpDndDropDataFunc set_data_func; }; static GtkWidget * gimp_dnd_get_viewable_icon (GtkWidget *widget, GdkDragContext *context, GCallback get_viewable_func, gpointer get_viewable_data); static GtkWidget * gimp_dnd_get_component_icon (GtkWidget *widget, GdkDragContext *context, GCallback get_comp_func, gpointer get_comp_data); static GtkWidget * gimp_dnd_get_color_icon (GtkWidget *widget, GdkDragContext *context, GCallback get_color_func, gpointer get_color_data); static void gimp_dnd_get_uri_list_data (GtkWidget *widget, GdkDragContext *context, GCallback get_uri_list_func, gpointer get_uri_list_data, GtkSelectionData *selection); static gboolean gimp_dnd_set_uri_list_data (GtkWidget *widget, gint x, gint y, GCallback set_uri_list_func, gpointer set_uri_list_data, GtkSelectionData *selection); static void gimp_dnd_get_xds_data (GtkWidget *widget, GdkDragContext *context, GCallback get_image_func, gpointer get_image_data, GtkSelectionData *selection); static void gimp_dnd_get_color_data (GtkWidget *widget, GdkDragContext *context, GCallback get_color_func, gpointer get_color_data, GtkSelectionData *selection); static gboolean gimp_dnd_set_color_data (GtkWidget *widget, gint x, gint y, GCallback set_color_func, gpointer set_color_data, GtkSelectionData *selection); static void gimp_dnd_get_stream_data (GtkWidget *widget, GdkDragContext *context, GCallback get_stream_func, gpointer get_stream_data, GtkSelectionData *selection); static gboolean gimp_dnd_set_stream_data (GtkWidget *widget, gint x, gint y, GCallback set_stream_func, gpointer set_stream_data, GtkSelectionData *selection); static void gimp_dnd_get_pixbuf_data (GtkWidget *widget, GdkDragContext *context, GCallback get_pixbuf_func, gpointer get_pixbuf_data, GtkSelectionData *selection); static gboolean gimp_dnd_set_pixbuf_data (GtkWidget *widget, gint x, gint y, GCallback set_pixbuf_func, gpointer set_pixbuf_data, GtkSelectionData *selection); static void gimp_dnd_get_component_data (GtkWidget *widget, GdkDragContext *context, GCallback get_comp_func, gpointer get_comp_data, GtkSelectionData *selection); static gboolean gimp_dnd_set_component_data (GtkWidget *widget, gint x, gint y, GCallback set_comp_func, gpointer set_comp_data, GtkSelectionData *selection); static void gimp_dnd_get_image_data (GtkWidget *widget, GdkDragContext *context, GCallback get_image_func, gpointer get_image_data, GtkSelectionData *selection); static gboolean gimp_dnd_set_image_data (GtkWidget *widget, gint x, gint y, GCallback set_image_func, gpointer set_image_data, GtkSelectionData *selection); static void gimp_dnd_get_item_data (GtkWidget *widget, GdkDragContext *context, GCallback get_item_func, gpointer get_item_data, GtkSelectionData *selection); static gboolean gimp_dnd_set_item_data (GtkWidget *widget, gint x, gint y, GCallback set_item_func, gpointer set_item_data, GtkSelectionData *selection); static void gimp_dnd_get_object_data (GtkWidget *widget, GdkDragContext *context, GCallback get_object_func, gpointer get_object_data, GtkSelectionData *selection); static gboolean gimp_dnd_set_brush_data (GtkWidget *widget, gint x, gint y, GCallback set_brush_func, gpointer set_brush_data, GtkSelectionData *selection); static gboolean gimp_dnd_set_pattern_data (GtkWidget *widget, gint x, gint y, GCallback set_pattern_func, gpointer set_pattern_data, GtkSelectionData *selection); static gboolean gimp_dnd_set_gradient_data (GtkWidget *widget, gint x, gint y, GCallback set_gradient_func, gpointer set_gradient_data, GtkSelectionData *selection); static gboolean gimp_dnd_set_palette_data (GtkWidget *widget, gint x, gint y, GCallback set_palette_func, gpointer set_palette_data, GtkSelectionData *selection); static gboolean gimp_dnd_set_font_data (GtkWidget *widget, gint x, gint y, GCallback set_font_func, gpointer set_font_data, GtkSelectionData *selection); static gboolean gimp_dnd_set_buffer_data (GtkWidget *widget, gint x, gint y, GCallback set_buffer_func, gpointer set_buffer_data, GtkSelectionData *selection); static gboolean gimp_dnd_set_imagefile_data (GtkWidget *widget, gint x, gint y, GCallback set_imagefile_func, gpointer set_imagefile_data, GtkSelectionData *selection); static gboolean gimp_dnd_set_template_data (GtkWidget *widget, gint x, gint y, GCallback set_template_func, gpointer set_template_data, GtkSelectionData *selection); static gboolean gimp_dnd_set_tool_item_data (GtkWidget *widget, gint x, gint y, GCallback set_tool_item_func, gpointer set_tool_item_data, GtkSelectionData *selection); static const GimpDndDataDef dnd_data_defs[] = { { { NULL, 0, -1 }, NULL, NULL, NULL, NULL, NULL }, { GIMP_TARGET_URI_LIST, "gimp-dnd-get-uri-list-func", "gimp-dnd-get-uri-list-data", "gimp-dnd-set-uri-list-func", "gimp-dnd-set-uri-list-data", NULL, gimp_dnd_get_uri_list_data, gimp_dnd_set_uri_list_data }, { GIMP_TARGET_TEXT_PLAIN, NULL, NULL, "gimp-dnd-set-uri-list-func", "gimp-dnd-set-uri-list-data", NULL, NULL, gimp_dnd_set_uri_list_data }, { GIMP_TARGET_NETSCAPE_URL, NULL, NULL, "gimp-dnd-set-uri-list-func", "gimp-dnd-set-uri-list-data", NULL, NULL, gimp_dnd_set_uri_list_data }, { GIMP_TARGET_XDS, "gimp-dnd-get-xds-func", "gimp-dnd-get-xds-data", NULL, NULL, gimp_dnd_get_viewable_icon, gimp_dnd_get_xds_data, NULL }, { GIMP_TARGET_COLOR, "gimp-dnd-get-color-func", "gimp-dnd-get-color-data", "gimp-dnd-set-color-func", "gimp-dnd-set-color-data", gimp_dnd_get_color_icon, gimp_dnd_get_color_data, gimp_dnd_set_color_data }, { GIMP_TARGET_SVG, "gimp-dnd-get-svg-func", "gimp-dnd-get-svg-data", "gimp-dnd-set-svg-func", "gimp-dnd-set-svg-data", gimp_dnd_get_viewable_icon, gimp_dnd_get_stream_data, gimp_dnd_set_stream_data }, { GIMP_TARGET_SVG_XML, "gimp-dnd-get-svg-xml-func", "gimp-dnd-get-svg-xml-data", "gimp-dnd-set-svg-xml-func", "gimp-dnd-set-svg-xml-data", gimp_dnd_get_viewable_icon, gimp_dnd_get_stream_data, gimp_dnd_set_stream_data }, { GIMP_TARGET_PIXBUF, "gimp-dnd-get-pixbuf-func", "gimp-dnd-get-pixbuf-data", "gimp-dnd-set-pixbuf-func", "gimp-dnd-set-pixbuf-data", gimp_dnd_get_viewable_icon, gimp_dnd_get_pixbuf_data, gimp_dnd_set_pixbuf_data }, { GIMP_TARGET_IMAGE, "gimp-dnd-get-image-func", "gimp-dnd-get-image-data", "gimp-dnd-set-image-func", "gimp-dnd-set-image-data", gimp_dnd_get_viewable_icon, gimp_dnd_get_image_data, gimp_dnd_set_image_data, }, { GIMP_TARGET_COMPONENT, "gimp-dnd-get-component-func", "gimp-dnd-get-component-data", "gimp-dnd-set-component-func", "gimp-dnd-set-component-data", gimp_dnd_get_component_icon, gimp_dnd_get_component_data, gimp_dnd_set_component_data, }, { GIMP_TARGET_LAYER, "gimp-dnd-get-layer-func", "gimp-dnd-get-layer-data", "gimp-dnd-set-layer-func", "gimp-dnd-set-layer-data", gimp_dnd_get_viewable_icon, gimp_dnd_get_item_data, gimp_dnd_set_item_data, }, { GIMP_TARGET_CHANNEL, "gimp-dnd-get-channel-func", "gimp-dnd-get-channel-data", "gimp-dnd-set-channel-func", "gimp-dnd-set-channel-data", gimp_dnd_get_viewable_icon, gimp_dnd_get_item_data, gimp_dnd_set_item_data, }, { GIMP_TARGET_LAYER_MASK, "gimp-dnd-get-layer-mask-func", "gimp-dnd-get-layer-mask-data", "gimp-dnd-set-layer-mask-func", "gimp-dnd-set-layer-mask-data", gimp_dnd_get_viewable_icon, gimp_dnd_get_item_data, gimp_dnd_set_item_data, }, { GIMP_TARGET_VECTORS, "gimp-dnd-get-vectors-func", "gimp-dnd-get-vectors-data", "gimp-dnd-set-vectors-func", "gimp-dnd-set-vectors-data", gimp_dnd_get_viewable_icon, gimp_dnd_get_item_data, gimp_dnd_set_item_data, }, { GIMP_TARGET_BRUSH, "gimp-dnd-get-brush-func", "gimp-dnd-get-brush-data", "gimp-dnd-set-brush-func", "gimp-dnd-set-brush-data", gimp_dnd_get_viewable_icon, gimp_dnd_get_object_data, gimp_dnd_set_brush_data }, { GIMP_TARGET_PATTERN, "gimp-dnd-get-pattern-func", "gimp-dnd-get-pattern-data", "gimp-dnd-set-pattern-func", "gimp-dnd-set-pattern-data", gimp_dnd_get_viewable_icon, gimp_dnd_get_object_data, gimp_dnd_set_pattern_data }, { GIMP_TARGET_GRADIENT, "gimp-dnd-get-gradient-func", "gimp-dnd-get-gradient-data", "gimp-dnd-set-gradient-func", "gimp-dnd-set-gradient-data", gimp_dnd_get_viewable_icon, gimp_dnd_get_object_data, gimp_dnd_set_gradient_data }, { GIMP_TARGET_PALETTE, "gimp-dnd-get-palette-func", "gimp-dnd-get-palette-data", "gimp-dnd-set-palette-func", "gimp-dnd-set-palette-data", gimp_dnd_get_viewable_icon, gimp_dnd_get_object_data, gimp_dnd_set_palette_data }, { GIMP_TARGET_FONT, "gimp-dnd-get-font-func", "gimp-dnd-get-font-data", "gimp-dnd-set-font-func", "gimp-dnd-set-font-data", gimp_dnd_get_viewable_icon, gimp_dnd_get_object_data, gimp_dnd_set_font_data }, { GIMP_TARGET_BUFFER, "gimp-dnd-get-buffer-func", "gimp-dnd-get-buffer-data", "gimp-dnd-set-buffer-func", "gimp-dnd-set-buffer-data", gimp_dnd_get_viewable_icon, gimp_dnd_get_object_data, gimp_dnd_set_buffer_data }, { GIMP_TARGET_IMAGEFILE, "gimp-dnd-get-imagefile-func", "gimp-dnd-get-imagefile-data", "gimp-dnd-set-imagefile-func", "gimp-dnd-set-imagefile-data", gimp_dnd_get_viewable_icon, gimp_dnd_get_object_data, gimp_dnd_set_imagefile_data }, { GIMP_TARGET_TEMPLATE, "gimp-dnd-get-template-func", "gimp-dnd-get-template-data", "gimp-dnd-set-template-func", "gimp-dnd-set-template-data", gimp_dnd_get_viewable_icon, gimp_dnd_get_object_data, gimp_dnd_set_template_data }, { GIMP_TARGET_TOOL_ITEM, "gimp-dnd-get-tool-item-func", "gimp-dnd-get-tool-item-data", "gimp-dnd-set-tool-item-func", "gimp-dnd-set-tool-item-data", gimp_dnd_get_viewable_icon, gimp_dnd_get_object_data, gimp_dnd_set_tool_item_data }, { GIMP_TARGET_DIALOG, NULL, NULL, NULL, NULL, NULL, NULL, NULL } }; static Gimp *the_dnd_gimp = NULL; void gimp_dnd_init (Gimp *gimp) { g_return_if_fail (GIMP_IS_GIMP (gimp)); g_return_if_fail (the_dnd_gimp == NULL); the_dnd_gimp = gimp; } /**********************/ /* helper functions */ /**********************/ static void gimp_dnd_target_list_add (GtkTargetList *list, const GtkTargetEntry *entry) { GdkAtom atom = gdk_atom_intern (entry->target, FALSE); guint info; if (! gtk_target_list_find (list, atom, &info) || info != entry->info) { gtk_target_list_add (list, atom, entry->flags, entry->info); } } /********************************/ /* general data dnd functions */ /********************************/ static void gimp_dnd_data_drag_begin (GtkWidget *widget, GdkDragContext *context, gpointer data) { const GimpDndDataDef *dnd_data; GimpDndType data_type; GCallback get_data_func = NULL; gpointer get_data_data = NULL; GtkWidget *icon_widget; data_type = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "gimp-dnd-get-data-type")); GIMP_LOG (DND, "data type %d", data_type); if (! data_type) return; dnd_data = dnd_data_defs + data_type; if (dnd_data->get_data_func_name) get_data_func = g_object_get_data (G_OBJECT (widget), dnd_data->get_data_func_name); if (dnd_data->get_data_data_name) get_data_data = g_object_get_data (G_OBJECT (widget), dnd_data->get_data_data_name); if (! get_data_func) return; icon_widget = dnd_data->get_icon_func (widget, context, get_data_func, get_data_data); if (icon_widget) { GtkWidget *frame; GtkWidget *window; window = gtk_window_new (GTK_WINDOW_POPUP); gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_DND); gtk_window_set_screen (GTK_WINDOW (window), gtk_widget_get_screen (widget)); gtk_widget_realize (window); frame = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT); gtk_container_add (GTK_CONTAINER (window), frame); gtk_widget_show (frame); gtk_container_add (GTK_CONTAINER (frame), icon_widget); gtk_widget_show (icon_widget); g_object_set_data_full (G_OBJECT (widget), "gimp-dnd-data-widget", window, (GDestroyNotify) gtk_widget_destroy); gtk_drag_set_icon_widget (context, window, DRAG_ICON_OFFSET, DRAG_ICON_OFFSET); /* remember for which drag context the widget was made */ g_object_set_data (G_OBJECT (window), "gimp-gdk-drag-context", context); } } static void gimp_dnd_data_drag_end (GtkWidget *widget, GdkDragContext *context) { GimpDndType data_type; GtkWidget *icon_widget; data_type = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "gimp-dnd-get-data-type")); GIMP_LOG (DND, "data type %d", data_type); icon_widget = g_object_get_data (G_OBJECT (widget), "gimp-dnd-data-widget"); if (icon_widget) { /* destroy the icon_widget only if it was made for this drag * context. See bug #139337. */ if (g_object_get_data (G_OBJECT (icon_widget), "gimp-gdk-drag-context") == (gpointer) context) { g_object_set_data (G_OBJECT (widget), "gimp-dnd-data-widget", NULL); } } } static void gimp_dnd_data_drag_handle (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time, gpointer data) { GCallback get_data_func = NULL; gpointer get_data_data = NULL; GimpDndType data_type; GIMP_LOG (DND, "data type %d", info); for (data_type = GIMP_DND_TYPE_NONE + 1; data_type <= GIMP_DND_TYPE_LAST; data_type++) { const GimpDndDataDef *dnd_data = dnd_data_defs + data_type; if (dnd_data->target_entry.info == info) { GIMP_LOG (DND, "target %s", dnd_data->target_entry.target); if (dnd_data->get_data_func_name) get_data_func = g_object_get_data (G_OBJECT (widget), dnd_data->get_data_func_name); if (dnd_data->get_data_data_name) get_data_data = g_object_get_data (G_OBJECT (widget), dnd_data->get_data_data_name); if (! get_data_func) return; dnd_data->get_data_func (widget, context, get_data_func, get_data_data, selection_data); return; } } } static void gimp_dnd_data_drop_handle (GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time, gpointer data) { GimpDndType data_type; GIMP_LOG (DND, "data type %d", info); if (gtk_selection_data_get_length (selection_data) <= 0) { gtk_drag_finish (context, FALSE, FALSE, time); return; } for (data_type = GIMP_DND_TYPE_NONE + 1; data_type <= GIMP_DND_TYPE_LAST; data_type++) { const GimpDndDataDef *dnd_data = dnd_data_defs + data_type; if (dnd_data->target_entry.info == info) { GCallback set_data_func = NULL; gpointer set_data_data = NULL; GIMP_LOG (DND, "target %s", dnd_data->target_entry.target); if (dnd_data->set_data_func_name) set_data_func = g_object_get_data (G_OBJECT (widget), dnd_data->set_data_func_name); if (dnd_data->set_data_data_name) set_data_data = g_object_get_data (G_OBJECT (widget), dnd_data->set_data_data_name); if (set_data_func && dnd_data->set_data_func (widget, x, y, set_data_func, set_data_data, selection_data)) { gtk_drag_finish (context, TRUE, FALSE, time); return; } gtk_drag_finish (context, FALSE, FALSE, time); return; } } } static void gimp_dnd_data_source_add (GimpDndType data_type, GtkWidget *widget, GCallback get_data_func, gpointer get_data_data) { const GimpDndDataDef *dnd_data; gboolean drag_connected; dnd_data = dnd_data_defs + data_type; /* set a default drag source if not already done */ if (! g_object_get_data (G_OBJECT (widget), "gtk-site-data")) gtk_drag_source_set (widget, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK, NULL, 0, GDK_ACTION_COPY | GDK_ACTION_MOVE); drag_connected = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "gimp-dnd-drag-connected")); if (! drag_connected) { g_signal_connect (widget, "drag-begin", G_CALLBACK (gimp_dnd_data_drag_begin), NULL); g_signal_connect (widget, "drag-end", G_CALLBACK (gimp_dnd_data_drag_end), NULL); g_signal_connect (widget, "drag-data-get", G_CALLBACK (gimp_dnd_data_drag_handle), NULL); g_object_set_data (G_OBJECT (widget), "gimp-dnd-drag-connected", GINT_TO_POINTER (TRUE)); } g_object_set_data (G_OBJECT (widget), dnd_data->get_data_func_name, get_data_func); g_object_set_data (G_OBJECT (widget), dnd_data->get_data_data_name, get_data_data); /* remember the first set source type for drag view creation */ if (! g_object_get_data (G_OBJECT (widget), "gimp-dnd-get-data-type")) g_object_set_data (G_OBJECT (widget), "gimp-dnd-get-data-type", GINT_TO_POINTER (data_type)); if (dnd_data->target_entry.target) { GtkTargetList *target_list; target_list = gtk_drag_source_get_target_list (widget); if (target_list) { gimp_dnd_target_list_add (target_list, &dnd_data->target_entry); } else { target_list = gtk_target_list_new (&dnd_data->target_entry, 1); gtk_drag_source_set_target_list (widget, target_list); gtk_target_list_unref (target_list); } } } static gboolean gimp_dnd_data_source_remove (GimpDndType data_type, GtkWidget *widget) { const GimpDndDataDef *dnd_data; gboolean drag_connected; gboolean list_changed = FALSE; drag_connected = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "gimp-dnd-drag-connected")); if (! drag_connected) return FALSE; dnd_data = dnd_data_defs + data_type; g_object_set_data (G_OBJECT (widget), dnd_data->get_data_func_name, NULL); g_object_set_data (G_OBJECT (widget), dnd_data->get_data_data_name, NULL); /* remove the dnd type remembered for the dnd icon */ if (data_type == GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "gimp-dnd-get-data-type"))) g_object_set_data (G_OBJECT (widget), "gimp-dnd-get-data-type", NULL); if (dnd_data->target_entry.target) { /* Don't just remove the target from the existing list, create a * new list without the target and replace the old list. The * source's target list is part of a drag operation's state, but * only by reference, it's not copied. So when we change the * list, we would change the state of that ongoing drag, making * it impossible to drop anything. See bug #676522. */ GtkTargetList *target_list = gtk_drag_source_get_target_list (widget); if (target_list) { GtkTargetList *new_list; GtkTargetEntry *targets; gint n_targets_old; gint n_targets_new; gint i; targets = gtk_target_table_new_from_list (target_list, &n_targets_old); new_list = gtk_target_list_new (NULL, 0); for (i = 0; i < n_targets_old; i++) { if (targets[i].info != data_type) { gtk_target_list_add (new_list, gdk_atom_intern (targets[i].target, FALSE), targets[i].flags, targets[i].info); } } gtk_target_table_free (targets, n_targets_old); targets = gtk_target_table_new_from_list (new_list, &n_targets_new); gtk_target_table_free (targets, n_targets_new); if (n_targets_old != n_targets_new) { list_changed = TRUE; if (n_targets_new > 0) gtk_drag_source_set_target_list (widget, new_list); else gtk_drag_source_set_target_list (widget, NULL); } gtk_target_list_unref (new_list); } } return list_changed; } static void gimp_dnd_data_dest_add (GimpDndType data_type, GtkWidget *widget, gpointer set_data_func, gpointer set_data_data) { const GimpDndDataDef *dnd_data; gboolean drop_connected; /* set a default drag dest if not already done */ if (! g_object_get_data (G_OBJECT (widget), "gtk-drag-dest")) gtk_drag_dest_set (widget, GTK_DEST_DEFAULT_ALL, NULL, 0, GDK_ACTION_COPY); drop_connected = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "gimp-dnd-drop-connected")); if (set_data_func && ! drop_connected) { g_signal_connect (widget, "drag-data-received", G_CALLBACK (gimp_dnd_data_drop_handle), NULL); g_object_set_data (G_OBJECT (widget), "gimp-dnd-drop-connected", GINT_TO_POINTER (TRUE)); } dnd_data = dnd_data_defs + data_type; if (set_data_func) { g_object_set_data (G_OBJECT (widget), dnd_data->set_data_func_name, set_data_func); g_object_set_data (G_OBJECT (widget), dnd_data->set_data_data_name, set_data_data); } if (dnd_data->target_entry.target) { GtkTargetList *target_list; target_list = gtk_drag_dest_get_target_list (widget); if (target_list) { gimp_dnd_target_list_add (target_list, &dnd_data->target_entry); } else { target_list = gtk_target_list_new (&dnd_data->target_entry, 1); gtk_drag_dest_set_target_list (widget, target_list); gtk_target_list_unref (target_list); } } } static void gimp_dnd_data_dest_remove (GimpDndType data_type, GtkWidget *widget) { const GimpDndDataDef *dnd_data; dnd_data = dnd_data_defs + data_type; g_object_set_data (G_OBJECT (widget), dnd_data->set_data_func_name, NULL); g_object_set_data (G_OBJECT (widget), dnd_data->set_data_data_name, NULL); if (dnd_data->target_entry.target) { GtkTargetList *target_list; target_list = gtk_drag_dest_get_target_list (widget); if (target_list) { GdkAtom atom = gdk_atom_intern (dnd_data->target_entry.target, TRUE); if (atom != GDK_NONE) gtk_target_list_remove (target_list, atom); } } } /****************************/ /* uri list dnd functions */ /****************************/ static void gimp_dnd_get_uri_list_data (GtkWidget *widget, GdkDragContext *context, GCallback get_uri_list_func, gpointer get_uri_list_data, GtkSelectionData *selection) { GList *uri_list; uri_list = (* (GimpDndDragUriListFunc) get_uri_list_func) (widget, get_uri_list_data); GIMP_LOG (DND, "uri_list %p", uri_list); if (uri_list) { gimp_selection_data_set_uri_list (selection, uri_list); g_list_free_full (uri_list, (GDestroyNotify) g_free); } } static gboolean gimp_dnd_set_uri_list_data (GtkWidget *widget, gint x, gint y, GCallback set_uri_list_func, gpointer set_uri_list_data, GtkSelectionData *selection) { GList *uri_list = gimp_selection_data_get_uri_list (selection); GIMP_LOG (DND, "uri_list %p", uri_list); if (! uri_list) return FALSE; (* (GimpDndDropUriListFunc) set_uri_list_func) (widget, x, y, uri_list, set_uri_list_data); g_list_free_full (uri_list, (GDestroyNotify) g_free); return TRUE; } void gimp_dnd_uri_list_source_add (GtkWidget *widget, GimpDndDragUriListFunc get_uri_list_func, gpointer data) { g_return_if_fail (GTK_IS_WIDGET (widget)); gimp_dnd_data_source_add (GIMP_DND_TYPE_URI_LIST, widget, G_CALLBACK (get_uri_list_func), data); } void gimp_dnd_uri_list_source_remove (GtkWidget *widget) { g_return_if_fail (GTK_IS_WIDGET (widget)); gimp_dnd_data_source_remove (GIMP_DND_TYPE_URI_LIST, widget); } void gimp_dnd_uri_list_dest_add (GtkWidget *widget, GimpDndDropUriListFunc set_uri_list_func, gpointer data) { g_return_if_fail (GTK_IS_WIDGET (widget)); /* Set a default drag dest if not already done. Explicitly set * COPY and MOVE for file drag destinations. Some file managers * such as Konqueror only offer MOVE by default. */ if (! g_object_get_data (G_OBJECT (widget), "gtk-drag-dest")) gtk_drag_dest_set (widget, GTK_DEST_DEFAULT_ALL, NULL, 0, GDK_ACTION_COPY | GDK_ACTION_MOVE); gimp_dnd_data_dest_add (GIMP_DND_TYPE_URI_LIST, widget, G_CALLBACK (set_uri_list_func), data); gimp_dnd_data_dest_add (GIMP_DND_TYPE_TEXT_PLAIN, widget, G_CALLBACK (set_uri_list_func), data); gimp_dnd_data_dest_add (GIMP_DND_TYPE_NETSCAPE_URL, widget, G_CALLBACK (set_uri_list_func), data); } void gimp_dnd_uri_list_dest_remove (GtkWidget *widget) { g_return_if_fail (GTK_IS_WIDGET (widget)); gimp_dnd_data_dest_remove (GIMP_DND_TYPE_URI_LIST, widget); gimp_dnd_data_dest_remove (GIMP_DND_TYPE_TEXT_PLAIN, widget); gimp_dnd_data_dest_remove (GIMP_DND_TYPE_NETSCAPE_URL, widget); } /******************************/ /* Direct Save Protocol (XDS) */ /******************************/ static void gimp_dnd_get_xds_data (GtkWidget *widget, GdkDragContext *context, GCallback get_image_func, gpointer get_image_data, GtkSelectionData *selection) { GimpImage *image; GimpContext *gimp_context; image = g_object_get_data (G_OBJECT (context), "gimp-dnd-viewable"); if (! image) image = (GimpImage *) (* (GimpDndDragViewableFunc) get_image_func) (widget, &gimp_context, get_image_data); GIMP_LOG (DND, "image %p", image); if (image) gimp_dnd_xds_save_image (context, image, selection); } static void gimp_dnd_xds_drag_begin (GtkWidget *widget, GdkDragContext *context) { const GimpDndDataDef *dnd_data = dnd_data_defs + GIMP_DND_TYPE_XDS; GCallback get_data_func; gpointer get_data_data; get_data_func = g_object_get_data (G_OBJECT (widget), dnd_data->get_data_func_name); get_data_data = g_object_get_data (G_OBJECT (widget), dnd_data->get_data_data_name); if (get_data_func) { GimpImage *image; GimpContext *gimp_context; image = (GimpImage *) (* (GimpDndDragViewableFunc) get_data_func) (widget, &gimp_context, get_data_data); GIMP_LOG (DND, "image %p", image); gimp_dnd_xds_source_set (context, image); } } static void gimp_dnd_xds_drag_end (GtkWidget *widget, GdkDragContext *context) { gimp_dnd_xds_source_set (context, NULL); } void gimp_dnd_xds_source_add (GtkWidget *widget, GimpDndDragViewableFunc get_image_func, gpointer data) { gulong handler; g_return_if_fail (GTK_IS_WIDGET (widget)); gimp_dnd_data_source_add (GIMP_DND_TYPE_XDS, widget, G_CALLBACK (get_image_func), data); handler = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget), "gimp-dnd-xds-drag-begin")); if (! handler) { handler = g_signal_connect (widget, "drag-begin", G_CALLBACK (gimp_dnd_xds_drag_begin), NULL); g_object_set_data (G_OBJECT (widget), "gimp-dnd-xds-drag-begin", GUINT_TO_POINTER (handler)); } handler = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget), "gimp-dnd-xds-drag-end")); if (! handler) { handler = g_signal_connect (widget, "drag-end", G_CALLBACK (gimp_dnd_xds_drag_end), NULL); g_object_set_data (G_OBJECT (widget), "gimp-dnd-xds-drag-end", GUINT_TO_POINTER (handler)); } } void gimp_dnd_xds_source_remove (GtkWidget *widget) { gulong handler; g_return_if_fail (GTK_IS_WIDGET (widget)); handler = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget), "gimp-dnd-xds-drag-begin")); if (handler) { g_signal_handler_disconnect (widget, handler); g_object_set_data (G_OBJECT (widget), "gimp-dnd-xds-drag-begin", NULL); } handler = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget), "gimp-dnd-xds-drag-end")); if (handler) { g_signal_handler_disconnect (widget, handler); g_object_set_data (G_OBJECT (widget), "gimp-dnd-xds-drag-end", NULL); } gimp_dnd_data_source_remove (GIMP_DND_TYPE_XDS, widget); } /*************************/ /* color dnd functions */ /*************************/ static GtkWidget * gimp_dnd_get_color_icon (GtkWidget *widget, GdkDragContext *context, GCallback get_color_func, gpointer get_color_data) { GtkWidget *color_area; GimpRGB color; (* (GimpDndDragColorFunc) get_color_func) (widget, &color, get_color_data); GIMP_LOG (DND, "called"); g_object_set_data_full (G_OBJECT (context), "gimp-dnd-color", g_memdup (&color, sizeof (GimpRGB)), (GDestroyNotify) g_free); color_area = gimp_color_area_new (&color, GIMP_COLOR_AREA_SMALL_CHECKS, 0); gimp_color_area_set_color_config (GIMP_COLOR_AREA (color_area), the_dnd_gimp->config->color_management); gtk_widget_set_size_request (color_area, DRAG_PREVIEW_SIZE, DRAG_PREVIEW_SIZE); return color_area; } static void gimp_dnd_get_color_data (GtkWidget *widget, GdkDragContext *context, GCallback get_color_func, gpointer get_color_data, GtkSelectionData *selection) { GimpRGB *c; GimpRGB color; c = g_object_get_data (G_OBJECT (context), "gimp-dnd-color"); if (c) color = *c; else (* (GimpDndDragColorFunc) get_color_func) (widget, &color, get_color_data); GIMP_LOG (DND, "called"); gimp_selection_data_set_color (selection, &color); } static gboolean gimp_dnd_set_color_data (GtkWidget *widget, gint x, gint y, GCallback set_color_func, gpointer set_color_data, GtkSelectionData *selection) { GimpRGB color; GIMP_LOG (DND, "called"); if (! gimp_selection_data_get_color (selection, &color)) return FALSE; (* (GimpDndDropColorFunc) set_color_func) (widget, x, y, &color, set_color_data); return TRUE; } void gimp_dnd_color_source_add (GtkWidget *widget, GimpDndDragColorFunc get_color_func, gpointer data) { g_return_if_fail (GTK_IS_WIDGET (widget)); gimp_dnd_data_source_add (GIMP_DND_TYPE_COLOR, widget, G_CALLBACK (get_color_func), data); } void gimp_dnd_color_source_remove (GtkWidget *widget) { g_return_if_fail (GTK_IS_WIDGET (widget)); gimp_dnd_data_source_remove (GIMP_DND_TYPE_COLOR, widget); } void gimp_dnd_color_dest_add (GtkWidget *widget, GimpDndDropColorFunc set_color_func, gpointer data) { g_return_if_fail (GTK_IS_WIDGET (widget)); gimp_dnd_data_dest_add (GIMP_DND_TYPE_COLOR, widget, G_CALLBACK (set_color_func), data); } void gimp_dnd_color_dest_remove (GtkWidget *widget) { g_return_if_fail (GTK_IS_WIDGET (widget)); gimp_dnd_data_dest_remove (GIMP_DND_TYPE_COLOR, widget); } /**************************/ /* stream dnd functions */ /**************************/ static void gimp_dnd_get_stream_data (GtkWidget *widget, GdkDragContext *context, GCallback get_stream_func, gpointer get_stream_data, GtkSelectionData *selection) { guchar *stream; gsize stream_length; stream = (* (GimpDndDragStreamFunc) get_stream_func) (widget, &stream_length, get_stream_data); GIMP_LOG (DND, "stream %p, length %" G_GSIZE_FORMAT, stream, stream_length); if (stream) { gimp_selection_data_set_stream (selection, stream, stream_length); g_free (stream); } } static gboolean gimp_dnd_set_stream_data (GtkWidget *widget, gint x, gint y, GCallback set_stream_func, gpointer set_stream_data, GtkSelectionData *selection) { const guchar *stream; gsize stream_length; stream = gimp_selection_data_get_stream (selection, &stream_length); GIMP_LOG (DND, "stream %p, length %" G_GSIZE_FORMAT, stream, stream_length); if (! stream) return FALSE; (* (GimpDndDropStreamFunc) set_stream_func) (widget, x, y, stream, stream_length, set_stream_data); return TRUE; } void gimp_dnd_svg_source_add (GtkWidget *widget, GimpDndDragStreamFunc get_svg_func, gpointer data) { g_return_if_fail (GTK_IS_WIDGET (widget)); gimp_dnd_data_source_add (GIMP_DND_TYPE_SVG, widget, G_CALLBACK (get_svg_func), data); gimp_dnd_data_source_add (GIMP_DND_TYPE_SVG_XML, widget, G_CALLBACK (get_svg_func), data); } void gimp_dnd_svg_source_remove (GtkWidget *widget) { g_return_if_fail (GTK_IS_WIDGET (widget)); gimp_dnd_data_source_remove (GIMP_DND_TYPE_SVG, widget); gimp_dnd_data_source_remove (GIMP_DND_TYPE_SVG_XML, widget); } void gimp_dnd_svg_dest_add (GtkWidget *widget, GimpDndDropStreamFunc set_svg_func, gpointer data) { g_return_if_fail (GTK_IS_WIDGET (widget)); gimp_dnd_data_dest_add (GIMP_DND_TYPE_SVG, widget, G_CALLBACK (set_svg_func), data); gimp_dnd_data_dest_add (GIMP_DND_TYPE_SVG_XML, widget, G_CALLBACK (set_svg_func), data); } void gimp_dnd_svg_dest_remove (GtkWidget *widget) { g_return_if_fail (GTK_IS_WIDGET (widget)); gimp_dnd_data_dest_remove (GIMP_DND_TYPE_SVG, widget); gimp_dnd_data_dest_remove (GIMP_DND_TYPE_SVG_XML, widget); } /**************************/ /* pixbuf dnd functions */ /**************************/ static void gimp_dnd_get_pixbuf_data (GtkWidget *widget, GdkDragContext *context, GCallback get_pixbuf_func, gpointer get_pixbuf_data, GtkSelectionData *selection) { GdkPixbuf *pixbuf; pixbuf = (* (GimpDndDragPixbufFunc) get_pixbuf_func) (widget, get_pixbuf_data); GIMP_LOG (DND, "pixbuf %p", pixbuf); if (pixbuf) { gimp_set_busy (the_dnd_gimp); gtk_selection_data_set_pixbuf (selection, pixbuf); g_object_unref (pixbuf); gimp_unset_busy (the_dnd_gimp); } } static gboolean gimp_dnd_set_pixbuf_data (GtkWidget *widget, gint x, gint y, GCallback set_pixbuf_func, gpointer set_pixbuf_data, GtkSelectionData *selection) { GdkPixbuf *pixbuf; gimp_set_busy (the_dnd_gimp); pixbuf = gtk_selection_data_get_pixbuf (selection); gimp_unset_busy (the_dnd_gimp); GIMP_LOG (DND, "pixbuf %p", pixbuf); if (! pixbuf) return FALSE; (* (GimpDndDropPixbufFunc) set_pixbuf_func) (widget, x, y, pixbuf, set_pixbuf_data); g_object_unref (pixbuf); return TRUE; } void gimp_dnd_pixbuf_source_add (GtkWidget *widget, GimpDndDragPixbufFunc get_pixbuf_func, gpointer data) { GtkTargetList *target_list; g_return_if_fail (GTK_IS_WIDGET (widget)); gimp_dnd_data_source_add (GIMP_DND_TYPE_PIXBUF, widget, G_CALLBACK (get_pixbuf_func), data); target_list = gtk_drag_source_get_target_list (widget); if (target_list) gtk_target_list_ref (target_list); else target_list = gtk_target_list_new (NULL, 0); gimp_pixbuf_targets_add (target_list, GIMP_DND_TYPE_PIXBUF, TRUE); gtk_drag_source_set_target_list (widget, target_list); gtk_target_list_unref (target_list); } void gimp_dnd_pixbuf_source_remove (GtkWidget *widget) { GtkTargetList *target_list; g_return_if_fail (GTK_IS_WIDGET (widget)); gimp_dnd_data_source_remove (GIMP_DND_TYPE_PIXBUF, widget); target_list = gtk_drag_source_get_target_list (widget); if (target_list) gimp_pixbuf_targets_remove (target_list); } void gimp_dnd_pixbuf_dest_add (GtkWidget *widget, GimpDndDropPixbufFunc set_pixbuf_func, gpointer data) { GtkTargetList *target_list; g_return_if_fail (GTK_IS_WIDGET (widget)); gimp_dnd_data_dest_add (GIMP_DND_TYPE_PIXBUF, widget, G_CALLBACK (set_pixbuf_func), data); target_list = gtk_drag_dest_get_target_list (widget); if (target_list) gtk_target_list_ref (target_list); else target_list = gtk_target_list_new (NULL, 0); gimp_pixbuf_targets_add (target_list, GIMP_DND_TYPE_PIXBUF, FALSE); gtk_drag_dest_set_target_list (widget, target_list); gtk_target_list_unref (target_list); } void gimp_dnd_pixbuf_dest_remove (GtkWidget *widget) { GtkTargetList *target_list; g_return_if_fail (GTK_IS_WIDGET (widget)); gimp_dnd_data_dest_remove (GIMP_DND_TYPE_PIXBUF, widget); target_list = gtk_drag_dest_get_target_list (widget); if (target_list) gimp_pixbuf_targets_remove (target_list); } /*****************************/ /* component dnd functions */ /*****************************/ static GtkWidget * gimp_dnd_get_component_icon (GtkWidget *widget, GdkDragContext *context, GCallback get_comp_func, gpointer get_comp_data) { GtkWidget *view; GimpImage *image; GimpContext *gimp_context; GimpChannelType channel; image = (* (GimpDndDragComponentFunc) get_comp_func) (widget, &gimp_context, &channel, get_comp_data); GIMP_LOG (DND, "image %p, component %d", image, channel); if (! image) return NULL; g_object_set_data_full (G_OBJECT (context), "gimp-dnd-viewable", g_object_ref (image), (GDestroyNotify) g_object_unref); g_object_set_data (G_OBJECT (context), "gimp-dnd-component", GINT_TO_POINTER (channel)); view = gimp_view_new (gimp_context, GIMP_VIEWABLE (image), DRAG_PREVIEW_SIZE, 0, TRUE); GIMP_VIEW_RENDERER_IMAGE (GIMP_VIEW (view)->renderer)->channel = channel; return view; } static void gimp_dnd_get_component_data (GtkWidget *widget, GdkDragContext *context, GCallback get_comp_func, gpointer get_comp_data, GtkSelectionData *selection) { GimpImage *image; GimpContext *gimp_context; GimpChannelType channel = 0; image = g_object_get_data (G_OBJECT (context), "gimp-dnd-viewable"); channel = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context), "gimp-dnd-component")); if (! image) image = (* (GimpDndDragComponentFunc) get_comp_func) (widget, &gimp_context, &channel, get_comp_data); GIMP_LOG (DND, "image %p, component %d", image, channel); if (image) gimp_selection_data_set_component (selection, image, channel); } static gboolean gimp_dnd_set_component_data (GtkWidget *widget, gint x, gint y, GCallback set_comp_func, gpointer set_comp_data, GtkSelectionData *selection) { GimpImage *image; GimpChannelType channel = 0; image = gimp_selection_data_get_component (selection, the_dnd_gimp, &channel); GIMP_LOG (DND, "image %p, component %d", image, channel); if (! image) return FALSE; (* (GimpDndDropComponentFunc) set_comp_func) (widget, x, y, image, channel, set_comp_data); return TRUE; } void gimp_dnd_component_source_add (GtkWidget *widget, GimpDndDragComponentFunc get_comp_func, gpointer data) { g_return_if_fail (GTK_IS_WIDGET (widget)); gimp_dnd_data_source_add (GIMP_DND_TYPE_COMPONENT, widget, G_CALLBACK (get_comp_func), data); } void gimp_dnd_component_source_remove (GtkWidget *widget) { g_return_if_fail (GTK_IS_WIDGET (widget)); gimp_dnd_data_source_remove (GIMP_DND_TYPE_COMPONENT, widget); } void gimp_dnd_component_dest_add (GtkWidget *widget, GimpDndDropComponentFunc set_comp_func, gpointer data) { g_return_if_fail (GTK_IS_WIDGET (widget)); gimp_dnd_data_dest_add (GIMP_DND_TYPE_COMPONENT, widget, G_CALLBACK (set_comp_func), data); } void gimp_dnd_component_dest_remove (GtkWidget *widget) { g_return_if_fail (GTK_IS_WIDGET (widget)); gimp_dnd_data_dest_remove (GIMP_DND_TYPE_COMPONENT, widget); } /*******************************************/ /* GimpViewable (by GType) dnd functions */ /*******************************************/ static GtkWidget * gimp_dnd_get_viewable_icon (GtkWidget *widget, GdkDragContext *context, GCallback get_viewable_func, gpointer get_viewable_data) { GimpViewable *viewable; GimpContext *gimp_context; GtkWidget *view; gchar *desc; viewable = (* (GimpDndDragViewableFunc) get_viewable_func) (widget, &gimp_context, get_viewable_data); GIMP_LOG (DND, "viewable %p", viewable); if (! viewable) return NULL; g_object_set_data_full (G_OBJECT (context), "gimp-dnd-viewable", g_object_ref (viewable), (GDestroyNotify) g_object_unref); view = gimp_view_new (gimp_context, viewable, DRAG_PREVIEW_SIZE, 0, TRUE); desc = gimp_viewable_get_description (viewable, NULL); if (desc) { GtkWidget *hbox; GtkWidget *label; hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3); gtk_container_set_border_width (GTK_CONTAINER (hbox), 3); gtk_box_pack_start (GTK_BOX (hbox), view, FALSE, FALSE, 0); gtk_widget_show (view); label = g_object_new (GTK_TYPE_LABEL, "label", desc, "xpad", 3, "xalign", 0.0, "yalign", 0.5, "max-width-chars", 30, "ellipsize", PANGO_ELLIPSIZE_END, NULL); g_free (desc); gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); gtk_widget_show (label); return hbox; } return view; } static GimpDndType gimp_dnd_data_type_get_by_g_type (GType type) { GimpDndType dnd_type = GIMP_DND_TYPE_NONE; if (g_type_is_a (type, GIMP_TYPE_IMAGE)) { dnd_type = GIMP_DND_TYPE_IMAGE; } else if (g_type_is_a (type, GIMP_TYPE_LAYER)) { dnd_type = GIMP_DND_TYPE_LAYER; } else if (g_type_is_a (type, GIMP_TYPE_LAYER_MASK)) { dnd_type = GIMP_DND_TYPE_LAYER_MASK; } else if (g_type_is_a (type, GIMP_TYPE_CHANNEL)) { dnd_type = GIMP_DND_TYPE_CHANNEL; } else if (g_type_is_a (type, GIMP_TYPE_VECTORS)) { dnd_type = GIMP_DND_TYPE_VECTORS; } else if (g_type_is_a (type, GIMP_TYPE_BRUSH)) { dnd_type = GIMP_DND_TYPE_BRUSH; } else if (g_type_is_a (type, GIMP_TYPE_PATTERN)) { dnd_type = GIMP_DND_TYPE_PATTERN; } else if (g_type_is_a (type, GIMP_TYPE_GRADIENT)) { dnd_type = GIMP_DND_TYPE_GRADIENT; } else if (g_type_is_a (type, GIMP_TYPE_PALETTE)) { dnd_type = GIMP_DND_TYPE_PALETTE; } else if (g_type_is_a (type, GIMP_TYPE_FONT)) { dnd_type = GIMP_DND_TYPE_FONT; } else if (g_type_is_a (type, GIMP_TYPE_BUFFER)) { dnd_type = GIMP_DND_TYPE_BUFFER; } else if (g_type_is_a (type, GIMP_TYPE_IMAGEFILE)) { dnd_type = GIMP_DND_TYPE_IMAGEFILE; } else if (g_type_is_a (type, GIMP_TYPE_TEMPLATE)) { dnd_type = GIMP_DND_TYPE_TEMPLATE; } else if (g_type_is_a (type, GIMP_TYPE_TOOL_ITEM)) { dnd_type = GIMP_DND_TYPE_TOOL_ITEM; } return dnd_type; } gboolean gimp_dnd_drag_source_set_by_type (GtkWidget *widget, GdkModifierType start_button_mask, GType type, GdkDragAction actions) { GimpDndType dnd_type; g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); dnd_type = gimp_dnd_data_type_get_by_g_type (type); if (dnd_type == GIMP_DND_TYPE_NONE) return FALSE; gtk_drag_source_set (widget, start_button_mask, &dnd_data_defs[dnd_type].target_entry, 1, actions); return TRUE; } gboolean gimp_dnd_drag_dest_set_by_type (GtkWidget *widget, GtkDestDefaults flags, GType type, GdkDragAction actions) { GimpDndType dnd_type; g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); dnd_type = gimp_dnd_data_type_get_by_g_type (type); if (dnd_type == GIMP_DND_TYPE_NONE) return FALSE; gtk_drag_dest_set (widget, flags, &dnd_data_defs[dnd_type].target_entry, 1, actions); return TRUE; } gboolean gimp_dnd_viewable_source_add (GtkWidget *widget, GType type, GimpDndDragViewableFunc get_viewable_func, gpointer data) { GimpDndType dnd_type; g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); g_return_val_if_fail (get_viewable_func != NULL, FALSE); dnd_type = gimp_dnd_data_type_get_by_g_type (type); if (dnd_type == GIMP_DND_TYPE_NONE) return FALSE; gimp_dnd_data_source_add (dnd_type, widget, G_CALLBACK (get_viewable_func), data); return TRUE; } gboolean gimp_dnd_viewable_source_remove (GtkWidget *widget, GType type) { GimpDndType dnd_type; g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); dnd_type = gimp_dnd_data_type_get_by_g_type (type); if (dnd_type == GIMP_DND_TYPE_NONE) return FALSE; return gimp_dnd_data_source_remove (dnd_type, widget); } gboolean gimp_dnd_viewable_dest_add (GtkWidget *widget, GType type, GimpDndDropViewableFunc set_viewable_func, gpointer data) { GimpDndType dnd_type; g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); dnd_type = gimp_dnd_data_type_get_by_g_type (type); if (dnd_type == GIMP_DND_TYPE_NONE) return FALSE; gimp_dnd_data_dest_add (dnd_type, widget, G_CALLBACK (set_viewable_func), data); return TRUE; } gboolean gimp_dnd_viewable_dest_remove (GtkWidget *widget, GType type) { GimpDndType dnd_type; g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); dnd_type = gimp_dnd_data_type_get_by_g_type (type); if (dnd_type == GIMP_DND_TYPE_NONE) return FALSE; gimp_dnd_data_dest_remove (dnd_type, widget); return TRUE; } GimpViewable * gimp_dnd_get_drag_data (GtkWidget *widget) { const GimpDndDataDef *dnd_data; GimpDndType data_type; GimpDndDragViewableFunc get_data_func = NULL; gpointer get_data_data = NULL; GimpContext *context; g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); data_type = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "gimp-dnd-get-data-type")); if (! data_type) return NULL; dnd_data = dnd_data_defs + data_type; if (dnd_data->get_data_func_name) get_data_func = g_object_get_data (G_OBJECT (widget), dnd_data->get_data_func_name); if (dnd_data->get_data_data_name) get_data_data = g_object_get_data (G_OBJECT (widget), dnd_data->get_data_data_name); if (! get_data_func) return NULL; return (GimpViewable *) (* get_data_func) (widget, &context, get_data_data); } /*****************************/ /* GimpImage dnd functions */ /*****************************/ static void gimp_dnd_get_image_data (GtkWidget *widget, GdkDragContext *context, GCallback get_image_func, gpointer get_image_data, GtkSelectionData *selection) { GimpImage *image; GimpContext *gimp_context; image = g_object_get_data (G_OBJECT (context), "gimp-dnd-viewable"); if (! image) image = (GimpImage *) (* (GimpDndDragViewableFunc) get_image_func) (widget, &gimp_context, get_image_data); GIMP_LOG (DND, "image %p", image); if (image) gimp_selection_data_set_image (selection, image); } static gboolean gimp_dnd_set_image_data (GtkWidget *widget, gint x, gint y, GCallback set_image_func, gpointer set_image_data, GtkSelectionData *selection) { GimpImage *image = gimp_selection_data_get_image (selection, the_dnd_gimp); GIMP_LOG (DND, "image %p", image); if (! image) return FALSE; (* (GimpDndDropViewableFunc) set_image_func) (widget, x, y, GIMP_VIEWABLE (image), set_image_data); return TRUE; } /****************************/ /* GimpItem dnd functions */ /****************************/ static void gimp_dnd_get_item_data (GtkWidget *widget, GdkDragContext *context, GCallback get_item_func, gpointer get_item_data, GtkSelectionData *selection) { GimpItem *item; GimpContext *gimp_context; item = g_object_get_data (G_OBJECT (context), "gimp-dnd-viewable"); if (! item) item = (GimpItem *) (* (GimpDndDragViewableFunc) get_item_func) (widget, &gimp_context, get_item_data); GIMP_LOG (DND, "item %p", item); if (item) gimp_selection_data_set_item (selection, item); } static gboolean gimp_dnd_set_item_data (GtkWidget *widget, gint x, gint y, GCallback set_item_func, gpointer set_item_data, GtkSelectionData *selection) { GimpItem *item = gimp_selection_data_get_item (selection, the_dnd_gimp); GIMP_LOG (DND, "item %p", item); if (! item) return FALSE; (* (GimpDndDropViewableFunc) set_item_func) (widget, x, y, GIMP_VIEWABLE (item), set_item_data); return TRUE; } /******************************/ /* GimpObject dnd functions */ /******************************/ static void gimp_dnd_get_object_data (GtkWidget *widget, GdkDragContext *context, GCallback get_object_func, gpointer get_object_data, GtkSelectionData *selection) { GimpObject *object; GimpContext *gimp_context; object = g_object_get_data (G_OBJECT (context), "gimp-dnd-viewable"); if (! object) object = (GimpObject *) (* (GimpDndDragViewableFunc) get_object_func) (widget, &gimp_context, get_object_data); GIMP_LOG (DND, "object %p", object); if (GIMP_IS_OBJECT (object)) gimp_selection_data_set_object (selection, object); } /*****************************/ /* GimpBrush dnd functions */ /*****************************/ static gboolean gimp_dnd_set_brush_data (GtkWidget *widget, gint x, gint y, GCallback set_brush_func, gpointer set_brush_data, GtkSelectionData *selection) { GimpBrush *brush = gimp_selection_data_get_brush (selection, the_dnd_gimp); GIMP_LOG (DND, "brush %p", brush); if (! brush) return FALSE; (* (GimpDndDropViewableFunc) set_brush_func) (widget, x, y, GIMP_VIEWABLE (brush), set_brush_data); return TRUE; } /*******************************/ /* GimpPattern dnd functions */ /*******************************/ static gboolean gimp_dnd_set_pattern_data (GtkWidget *widget, gint x, gint y, GCallback set_pattern_func, gpointer set_pattern_data, GtkSelectionData *selection) { GimpPattern *pattern = gimp_selection_data_get_pattern (selection, the_dnd_gimp); GIMP_LOG (DND, "pattern %p", pattern); if (! pattern) return FALSE; (* (GimpDndDropViewableFunc) set_pattern_func) (widget, x, y, GIMP_VIEWABLE (pattern), set_pattern_data); return TRUE; } /********************************/ /* GimpGradient dnd functions */ /********************************/ static gboolean gimp_dnd_set_gradient_data (GtkWidget *widget, gint x, gint y, GCallback set_gradient_func, gpointer set_gradient_data, GtkSelectionData *selection) { GimpGradient *gradient = gimp_selection_data_get_gradient (selection, the_dnd_gimp); GIMP_LOG (DND, "gradient %p", gradient); if (! gradient) return FALSE; (* (GimpDndDropViewableFunc) set_gradient_func) (widget, x, y, GIMP_VIEWABLE (gradient), set_gradient_data); return TRUE; } /*******************************/ /* GimpPalette dnd functions */ /*******************************/ static gboolean gimp_dnd_set_palette_data (GtkWidget *widget, gint x, gint y, GCallback set_palette_func, gpointer set_palette_data, GtkSelectionData *selection) { GimpPalette *palette = gimp_selection_data_get_palette (selection, the_dnd_gimp); GIMP_LOG (DND, "palette %p", palette); if (! palette) return FALSE; (* (GimpDndDropViewableFunc) set_palette_func) (widget, x, y, GIMP_VIEWABLE (palette), set_palette_data); return TRUE; } /****************************/ /* GimpFont dnd functions */ /****************************/ static gboolean gimp_dnd_set_font_data (GtkWidget *widget, gint x, gint y, GCallback set_font_func, gpointer set_font_data, GtkSelectionData *selection) { GimpFont *font = gimp_selection_data_get_font (selection, the_dnd_gimp); GIMP_LOG (DND, "font %p", font); if (! font) return FALSE; (* (GimpDndDropViewableFunc) set_font_func) (widget, x, y, GIMP_VIEWABLE (font), set_font_data); return TRUE; } /******************************/ /* GimpBuffer dnd functions */ /******************************/ static gboolean gimp_dnd_set_buffer_data (GtkWidget *widget, gint x, gint y, GCallback set_buffer_func, gpointer set_buffer_data, GtkSelectionData *selection) { GimpBuffer *buffer = gimp_selection_data_get_buffer (selection, the_dnd_gimp); GIMP_LOG (DND, "buffer %p", buffer); if (! buffer) return FALSE; (* (GimpDndDropViewableFunc) set_buffer_func) (widget, x, y, GIMP_VIEWABLE (buffer), set_buffer_data); return TRUE; } /*********************************/ /* GimpImagefile dnd functions */ /*********************************/ static gboolean gimp_dnd_set_imagefile_data (GtkWidget *widget, gint x, gint y, GCallback set_imagefile_func, gpointer set_imagefile_data, GtkSelectionData *selection) { GimpImagefile *imagefile = gimp_selection_data_get_imagefile (selection, the_dnd_gimp); GIMP_LOG (DND, "imagefile %p", imagefile); if (! imagefile) return FALSE; (* (GimpDndDropViewableFunc) set_imagefile_func) (widget, x, y, GIMP_VIEWABLE (imagefile), set_imagefile_data); return TRUE; } /********************************/ /* GimpTemplate dnd functions */ /********************************/ static gboolean gimp_dnd_set_template_data (GtkWidget *widget, gint x, gint y, GCallback set_template_func, gpointer set_template_data, GtkSelectionData *selection) { GimpTemplate *template = gimp_selection_data_get_template (selection, the_dnd_gimp); GIMP_LOG (DND, "template %p", template); if (! template) return FALSE; (* (GimpDndDropViewableFunc) set_template_func) (widget, x, y, GIMP_VIEWABLE (template), set_template_data); return TRUE; } /*********************************/ /* GimpToolEntry dnd functions */ /*********************************/ static gboolean gimp_dnd_set_tool_item_data (GtkWidget *widget, gint x, gint y, GCallback set_tool_item_func, gpointer set_tool_item_data, GtkSelectionData *selection) { GimpToolItem *tool_item = gimp_selection_data_get_tool_item (selection, the_dnd_gimp); GIMP_LOG (DND, "tool_item %p", tool_item); if (! tool_item) return FALSE; (* (GimpDndDropViewableFunc) set_tool_item_func) (widget, x, y, GIMP_VIEWABLE (tool_item), set_tool_item_data); return TRUE; }