Gimp/app/widgets/gimpdnd.c
Jehan 5e008eb92f app: show number of dragged layers in dnd box for multi-layer drags.
For single drawable drag, we still display the name of this only layer.

Also apply some basic markups, showing the drawable count as italic
subscript in parentheses to differentiate it from a drawable name.
2020-05-17 18:32:15 +02:00

2783 lines
86 KiB
C

/* 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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include <math.h>
#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_list_icon (GtkWidget *widget,
GdkDragContext *context,
GCallback get_viewable_list_func,
gpointer get_viewable_list_data);
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_item_list_data (GtkWidget *widget,
GdkDragContext *context,
GCallback get_item_func,
gpointer get_item_data,
GtkSelectionData *selection);
static gboolean gimp_dnd_set_item_list_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_NOTEBOOK_TAB,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
},
{
GIMP_TARGET_LAYER_LIST,
"gimp-dnd-get-layer-list-func",
"gimp-dnd-get-layer-list-data",
"gimp-dnd-set-layer-list-func",
"gimp-dnd-set-layer-list-data",
gimp_dnd_get_viewable_list_icon,
gimp_dnd_get_item_list_data,
gimp_dnd_set_item_list_data,
},
};
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,
"xalign", 0.0,
"yalign", 0.5,
"max-width-chars", 30,
"width-chars", MIN (strlen (desc), 10),
"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,
gboolean list)
{
GimpDndType dnd_type = GIMP_DND_TYPE_NONE;
if (g_type_is_a (type, GIMP_TYPE_IMAGE) && ! list)
{
dnd_type = GIMP_DND_TYPE_IMAGE;
}
else if (g_type_is_a (type, GIMP_TYPE_LAYER))
{
dnd_type = list ? GIMP_DND_TYPE_LAYER_LIST : GIMP_DND_TYPE_LAYER;
}
else if (g_type_is_a (type, GIMP_TYPE_LAYER_MASK) && ! list)
{
dnd_type = GIMP_DND_TYPE_LAYER_MASK;
}
else if (g_type_is_a (type, GIMP_TYPE_CHANNEL) && ! list)
{
dnd_type = GIMP_DND_TYPE_CHANNEL;
}
else if (g_type_is_a (type, GIMP_TYPE_VECTORS) && ! list)
{
dnd_type = GIMP_DND_TYPE_VECTORS;
}
else if (g_type_is_a (type, GIMP_TYPE_BRUSH) && ! list)
{
dnd_type = GIMP_DND_TYPE_BRUSH;
}
else if (g_type_is_a (type, GIMP_TYPE_PATTERN) && ! list)
{
dnd_type = GIMP_DND_TYPE_PATTERN;
}
else if (g_type_is_a (type, GIMP_TYPE_GRADIENT) && ! list)
{
dnd_type = GIMP_DND_TYPE_GRADIENT;
}
else if (g_type_is_a (type, GIMP_TYPE_PALETTE) && ! list)
{
dnd_type = GIMP_DND_TYPE_PALETTE;
}
else if (g_type_is_a (type, GIMP_TYPE_FONT) && ! list)
{
dnd_type = GIMP_DND_TYPE_FONT;
}
else if (g_type_is_a (type, GIMP_TYPE_BUFFER) && ! list)
{
dnd_type = GIMP_DND_TYPE_BUFFER;
}
else if (g_type_is_a (type, GIMP_TYPE_IMAGEFILE) && ! list)
{
dnd_type = GIMP_DND_TYPE_IMAGEFILE;
}
else if (g_type_is_a (type, GIMP_TYPE_TEMPLATE) && ! list)
{
dnd_type = GIMP_DND_TYPE_TEMPLATE;
}
else if (g_type_is_a (type, GIMP_TYPE_TOOL_ITEM) && ! list)
{
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, FALSE);
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,
gboolean list_accepted,
GdkDragAction actions)
{
GtkTargetEntry target_entries[2];
GimpDndType dnd_type;
gint target_entries_n = 0;
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
if (list_accepted)
{
dnd_type = gimp_dnd_data_type_get_by_g_type (type, TRUE);
if (dnd_type != GIMP_DND_TYPE_NONE)
{
target_entries[target_entries_n] = dnd_data_defs[dnd_type].target_entry;
target_entries_n++;
}
}
dnd_type = gimp_dnd_data_type_get_by_g_type (type, FALSE);
if (dnd_type != GIMP_DND_TYPE_NONE)
{
target_entries[target_entries_n] = dnd_data_defs[dnd_type].target_entry;
target_entries_n++;
}
if (target_entries_n == 0)
return FALSE;
gtk_drag_dest_set (widget, flags,
(const GtkTargetEntry *) &target_entries,
target_entries_n,
actions);
return TRUE;
}
/**
* gimp_dnd_viewable_source_add:
* @widget:
* @type:
* @get_viewable_func:
* @data:
*
* Sets up @widget as a drag source for a #GimpViewable object, as
* returned by @get_viewable_func on @widget and @data.
*
* @type must be a list type for drag operations.
*/
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, FALSE);
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, FALSE);
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, FALSE);
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, FALSE);
if (dnd_type == GIMP_DND_TYPE_NONE)
return FALSE;
gimp_dnd_data_dest_remove (dnd_type, widget);
return TRUE;
}
GimpViewable *
gimp_dnd_get_drag_viewable (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);
}
/*************************************************/
/* GimpViewable (by GType) GList dnd functions */
/*************************************************/
static GtkWidget *
gimp_dnd_get_viewable_list_icon (GtkWidget *widget,
GdkDragContext *context,
GCallback get_list_func,
gpointer get_list_data)
{
GList *viewables;
GimpViewable *viewable;
GimpContext *gimp_context;
GtkWidget *view;
gchar *desc;
gboolean desc_use_markup = FALSE;
gfloat desc_yalign = 0.5f;
gint desc_width_chars;
viewables = (* (GimpDndDragViewableListFunc) get_list_func) (widget,
&gimp_context,
get_list_data);
if (! viewables)
return NULL;
viewable = viewables->data;
GIMP_LOG (DND, "viewable %p", viewable);
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);
if (g_list_length (viewables) > 1)
{
/* When dragging multiple viewable, just show the first of them in the
* icon box, and the number of viewables being dragged in the
* description label (instead of the viewable name).
*/
desc = g_strdup_printf ("<sup><i>(%d)</i></sup>", g_list_length (viewables));
desc_use_markup = TRUE;
desc_yalign = 0.0f;
desc_width_chars = (gint) log10 (g_list_length (viewables)) + 3;
}
else
{
desc = gimp_viewable_get_description (viewable, NULL);
desc_width_chars = MIN (strlen (desc), 10);
}
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,
"use-markup", desc_use_markup,
"xalign", 0.0,
"yalign", desc_yalign,
"max-width-chars", 30,
"width-chars", desc_width_chars,
"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;
}
/**
* gimp_dnd_viewable_list_source_add:
* @widget:
* @type:
* @get_viewable_func:
* @data:
*
* Sets up @widget as a drag source for a #GList of #GimpViewable
* object, as returned by @get_viewable_func on @widget and @data.
*
* @type must be a list type for drag operations (only GimpLayer so
* far).
*/
gboolean
gimp_dnd_viewable_list_source_add (GtkWidget *widget,
GType type,
GimpDndDragViewableListFunc get_viewable_list_func,
gpointer data)
{
GimpDndType dnd_type;
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
g_return_val_if_fail (get_viewable_list_func != NULL, FALSE);
dnd_type = gimp_dnd_data_type_get_by_g_type (type, TRUE);
if (dnd_type == GIMP_DND_TYPE_NONE)
return FALSE;
gimp_dnd_data_source_add (dnd_type, widget,
G_CALLBACK (get_viewable_list_func),
data);
return TRUE;
}
gboolean
gimp_dnd_viewable_list_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, TRUE);
if (dnd_type == GIMP_DND_TYPE_NONE)
return FALSE;
return gimp_dnd_data_source_remove (dnd_type, widget);
}
gboolean
gimp_dnd_viewable_list_dest_add (GtkWidget *widget,
GType type,
GimpDndDropViewableListFunc 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, TRUE);
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_list_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, TRUE);
if (dnd_type == GIMP_DND_TYPE_NONE)
return FALSE;
gimp_dnd_data_dest_remove (dnd_type, widget);
return TRUE;
}
GList *
gimp_dnd_get_drag_list (GtkWidget *widget)
{
const GimpDndDataDef *dnd_data;
GimpDndType data_type;
GimpDndDragViewableListFunc 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 (GList *) (* 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;
}
/**********************************/
/* GimpItem GList dnd functions */
/**********************************/
static void
gimp_dnd_get_item_list_data (GtkWidget *widget,
GdkDragContext *context,
GCallback get_item_func,
gpointer get_item_data,
GtkSelectionData *selection)
{
GList *items;
GimpContext *gimp_context;
items = (* (GimpDndDragViewableListFunc) get_item_func) (widget, &gimp_context,
get_item_data);
if (items)
gimp_selection_data_set_item_list (selection, items);
g_list_free (items);
}
static gboolean
gimp_dnd_set_item_list_data (GtkWidget *widget,
gint x,
gint y,
GCallback set_item_func,
gpointer set_item_data,
GtkSelectionData *selection)
{
GList *items = gimp_selection_data_get_item_list (selection, the_dnd_gimp);
if (! items)
return FALSE;
(* (GimpDndDropViewableListFunc) set_item_func) (widget, x, y, items,
set_item_data);
g_list_free (items);
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;
}