gimpdnd.c 54.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/* The GIMP -- an 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 2 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
18 19 20 21 22

#include "config.h"

#include <gtk/gtk.h>

23
#include "libgimpwidgets/gimpwidgets.h"
24

25
#include "widgets-types.h"
26

27
#include "core/gimp.h"
28
#include "core/gimpbrush.h"
29
#include "core/gimpbuffer.h"
30 31 32 33 34
#include "core/gimpchannel.h"
#include "core/gimpcontainer.h"
#include "core/gimpdatafactory.h"
#include "core/gimpdrawable.h"
#include "core/gimpgradient.h"
35
#include "core/gimpimage.h"
36
#include "core/gimpimagefile.h"
37 38 39 40
#include "core/gimplayer.h"
#include "core/gimplayermask.h"
#include "core/gimppalette.h"
#include "core/gimppattern.h"
41
#include "core/gimptemplate.h"
42
#include "core/gimptoolinfo.h"
43

Michael Natterer's avatar
Michael Natterer committed
44 45
#include "text/gimpfont.h"

46 47
#include "vectors/gimpvectors.h"

48
#include "gimpdnd.h"
49
#include "gimpview.h"
50
#include "gimpselectiondata.h"
51

52
#include "gimp-intl.h"
53

54

55
#define DRAG_PREVIEW_SIZE 32
56 57
#define DRAG_ICON_OFFSET  -8

58 59 60 61 62 63 64 65
/* #define DEBUG_DND */

#ifdef DEBUG_DND
#define D(stmnt) stmnt
#else
#define D(stmnt)
#endif

66

67 68 69 70 71 72 73 74 75
typedef GtkWidget * (* GimpDndGetIconFunc)  (GtkWidget        *widget,
                                             GCallback         get_data_func,
                                             gpointer          get_data_data);
typedef void        (* GimpDndDragDataFunc) (GtkWidget        *widget,
                                             GCallback         get_data_func,
                                             gpointer          get_data_data,
                                             GtkSelectionData *selection,
                                             GdkAtom           atom);
typedef gboolean    (* GimpDndDropDataFunc) (GtkWidget        *widget,
76 77
                                             gint              x,
                                             gint              y,
78 79 80
                                             GCallback         set_data_func,
                                             gpointer          set_data_data,
                                             GtkSelectionData *selection);
81

82

83 84 85 86 87 88
typedef struct _GimpDndDataDef GimpDndDataDef;

struct _GimpDndDataDef
{
  GtkTargetEntry       target_entry;

89 90 91
  gchar               *get_data_func_name;
  gchar               *get_data_data_name;

92 93 94 95 96 97 98 99
  gchar               *set_data_func_name;
  gchar               *set_data_data_name;

  GimpDndGetIconFunc   get_icon_func;
  GimpDndDragDataFunc  get_data_func;
  GimpDndDropDataFunc  set_data_func;
};

100

101 102 103 104 105 106 107
static GtkWidget * gimp_dnd_get_viewable_icon  (GtkWidget        *widget,
                                                GCallback         get_viewable_func,
                                                gpointer          get_viewable_data);
static GtkWidget * gimp_dnd_get_color_icon     (GtkWidget        *widget,
                                                GCallback         get_color_func,
                                                gpointer          get_color_data);

108 109 110
static void        gimp_dnd_get_uri_list_data  (GtkWidget        *widget,
                                                GCallback         get_uri_list_func,
                                                gpointer          get_uri_list_data,
111 112
                                                GtkSelectionData *selection,
                                                GdkAtom           atom);
113
static gboolean    gimp_dnd_set_uri_list_data  (GtkWidget        *widget,
114 115
                                                gint              x,
                                                gint              y,
116 117
                                                GCallback         set_uri_list_func,
                                                gpointer          set_uri_list_data,
118 119 120 121 122 123 124 125
                                                GtkSelectionData *selection);

static void        gimp_dnd_get_color_data     (GtkWidget        *widget,
                                                GCallback         get_color_func,
                                                gpointer          get_color_data,
                                                GtkSelectionData *selection,
                                                GdkAtom           atom);
static gboolean    gimp_dnd_set_color_data     (GtkWidget        *widget,
126 127
                                                gint              x,
                                                gint              y,
128 129 130 131
                                                GCallback         set_color_func,
                                                gpointer          set_color_data,
                                                GtkSelectionData *selection);

132 133 134
static void        gimp_dnd_get_stream_data    (GtkWidget        *widget,
                                                GCallback         get_stream_func,
                                                gpointer          get_stream_data,
135 136
                                                GtkSelectionData *selection,
                                                GdkAtom           atom);
137
static gboolean    gimp_dnd_set_stream_data    (GtkWidget        *widget,
138 139
                                                gint              x,
                                                gint              y,
140 141
                                                GCallback         set_stream_func,
                                                gpointer          set_stream_data,
142 143 144 145 146 147 148 149
                                                GtkSelectionData *selection);

static void        gimp_dnd_get_image_data     (GtkWidget        *widget,
                                                GCallback         get_image_func,
                                                gpointer          get_image_data,
                                                GtkSelectionData *selection,
                                                GdkAtom           atom);
static gboolean    gimp_dnd_set_image_data     (GtkWidget        *widget,
150 151
                                                gint              x,
                                                gint              y,
152 153 154 155 156 157 158 159 160 161
                                                GCallback         set_image_func,
                                                gpointer          set_image_data,
                                                GtkSelectionData *selection);

static void        gimp_dnd_get_item_data      (GtkWidget        *widget,
                                                GCallback         get_item_func,
                                                gpointer          get_item_data,
                                                GtkSelectionData *selection,
                                                GdkAtom           atom);
static gboolean    gimp_dnd_set_item_data      (GtkWidget        *widget,
162 163
                                                gint              x,
                                                gint              y,
164 165 166 167 168 169 170 171 172 173 174
                                                GCallback         set_item_func,
                                                gpointer          set_item_data,
                                                GtkSelectionData *selection);

static void        gimp_dnd_get_data_data      (GtkWidget        *widget,
                                                GCallback         get_data_func,
                                                gpointer          get_data_data,
                                                GtkSelectionData *selection,
                                                GdkAtom           atom);

static gboolean    gimp_dnd_set_brush_data     (GtkWidget        *widget,
175 176
                                                gint              x,
                                                gint              y,
177 178 179 180
                                                GCallback         set_brush_func,
                                                gpointer          set_brush_data,
                                                GtkSelectionData *selection);
static gboolean    gimp_dnd_set_pattern_data   (GtkWidget        *widget,
181 182
                                                gint              x,
                                                gint              y,
183 184 185 186
                                                GCallback         set_pattern_func,
                                                gpointer          set_pattern_data,
                                                GtkSelectionData *selection);
static gboolean    gimp_dnd_set_gradient_data  (GtkWidget        *widget,
187 188
                                                gint              x,
                                                gint              y,
189 190 191 192
                                                GCallback         set_gradient_func,
                                                gpointer          set_gradient_data,
                                                GtkSelectionData *selection);
static gboolean    gimp_dnd_set_palette_data   (GtkWidget        *widget,
193 194
                                                gint              x,
                                                gint              y,
195 196 197 198
                                                GCallback         set_palette_func,
                                                gpointer          set_palette_data,
                                                GtkSelectionData *selection);
static gboolean    gimp_dnd_set_font_data      (GtkWidget        *widget,
199 200
                                                gint              x,
                                                gint              y,
201 202 203 204
                                                GCallback         set_font_func,
                                                gpointer          set_font_data,
                                                GtkSelectionData *selection);
static gboolean    gimp_dnd_set_buffer_data    (GtkWidget        *widget,
205 206
                                                gint              x,
                                                gint              y,
207 208 209 210
                                                GCallback         set_buffer_func,
                                                gpointer          set_buffer_data,
                                                GtkSelectionData *selection);
static gboolean    gimp_dnd_set_imagefile_data (GtkWidget        *widget,
211 212
                                                gint              x,
                                                gint              y,
213 214 215 216
                                                GCallback         set_imagefile_func,
                                                gpointer          set_imagefile_data,
                                                GtkSelectionData *selection);
static gboolean    gimp_dnd_set_template_data  (GtkWidget        *widget,
217 218
                                                gint              x,
                                                gint              y,
219 220 221 222
                                                GCallback         set_template_func,
                                                gpointer          set_template_data,
                                                GtkSelectionData *selection);
static gboolean    gimp_dnd_set_tool_data      (GtkWidget        *widget,
223 224
                                                gint              x,
                                                gint              y,
225 226 227
                                                GCallback         set_tool_func,
                                                gpointer          set_tool_data,
                                                GtkSelectionData *selection);
228

229

230

231 232 233 234 235 236 237 238 239 240
static GimpDndDataDef dnd_data_defs[] =
{
  {
    { NULL, 0, -1 },

    NULL,
    NULL,

    NULL,
    NULL,
Michael Natterer's avatar
Michael Natterer committed
241
    NULL
242 243
  },

244 245 246
  {
    GIMP_TARGET_URI_LIST,

247 248
    "gimp-dnd-get-uri-list-func",
    "gimp-dnd-get-uri-list-data",
249

250 251
    "gimp-dnd-set-uri-list-func",
    "gimp-dnd-set-uri-list-data",
252 253

    NULL,
254 255
    gimp_dnd_get_uri_list_data,
    gimp_dnd_set_uri_list_data
256 257 258 259 260
  },

  {
    GIMP_TARGET_TEXT_PLAIN,

261 262 263
    NULL,
    NULL,

264 265
    "gimp-dnd-set-uri-list-func",
    "gimp-dnd-set-uri-list-data",
266 267 268

    NULL,
    NULL,
269
    gimp_dnd_set_uri_list_data
270 271 272 273 274
  },

  {
    GIMP_TARGET_NETSCAPE_URL,

275 276 277
    NULL,
    NULL,

278 279
    "gimp-dnd-set-uri-list-func",
    "gimp-dnd-set-uri-list-data",
280 281 282

    NULL,
    NULL,
283
    gimp_dnd_set_uri_list_data
284 285
  },

286 287 288
  {
    GIMP_TARGET_COLOR,

289 290 291
    "gimp-dnd-get-color-func",
    "gimp-dnd-get-color-data",

292 293
    "gimp-dnd-set-color-func",
    "gimp-dnd-set-color-data",
294 295 296 297 298 299

    gimp_dnd_get_color_icon,
    gimp_dnd_get_color_data,
    gimp_dnd_set_color_data
  },

300 301 302 303 304 305 306 307 308 309 310 311 312 313
  {
    GIMP_TARGET_PNG,

    "gimp-dnd-get-png-func",
    "gimp-dnd-get-png-data",

    "gimp-dnd-set-png-func",
    "gimp-dnd-set-png-data",

    gimp_dnd_get_viewable_icon,
    gimp_dnd_get_stream_data,
    gimp_dnd_set_stream_data
  },

314 315 316 317 318 319 320 321 322 323
  {
    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,
324 325
    gimp_dnd_get_stream_data,
    gimp_dnd_set_stream_data
326 327 328 329 330 331 332 333 334 335 336 337
  },

  {
    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,
338 339
    gimp_dnd_get_stream_data,
    gimp_dnd_set_stream_data
340 341
  },

342 343 344
  {
    GIMP_TARGET_IMAGE,

345 346 347
    "gimp-dnd-get-image-func",
    "gimp-dnd-get-image-data",

348 349
    "gimp-dnd-set-image-func",
    "gimp-dnd-set-image-data",
350 351 352 353 354 355

    gimp_dnd_get_viewable_icon,
    gimp_dnd_get_image_data,
    gimp_dnd_set_image_data,
  },

356 357 358
  {
    GIMP_TARGET_LAYER,

359 360 361
    "gimp-dnd-get-layer-func",
    "gimp-dnd-get-layer-data",

362 363
    "gimp-dnd-set-layer-func",
    "gimp-dnd-set-layer-data",
364 365

    gimp_dnd_get_viewable_icon,
366 367
    gimp_dnd_get_item_data,
    gimp_dnd_set_item_data,
368 369 370 371 372
  },

  {
    GIMP_TARGET_CHANNEL,

373 374 375
    "gimp-dnd-get-channel-func",
    "gimp-dnd-get-channel-data",

376 377
    "gimp-dnd-set-channel-func",
    "gimp-dnd-set-channel-data",
378 379

    gimp_dnd_get_viewable_icon,
380 381
    gimp_dnd_get_item_data,
    gimp_dnd_set_item_data,
382 383 384 385 386
  },

  {
    GIMP_TARGET_LAYER_MASK,

387 388 389
    "gimp-dnd-get-layer-mask-func",
    "gimp-dnd-get-layer-mask-data",

390 391
    "gimp-dnd-set-layer-mask-func",
    "gimp-dnd-set-layer-mask-data",
392 393

    gimp_dnd_get_viewable_icon,
394 395
    gimp_dnd_get_item_data,
    gimp_dnd_set_item_data,
396 397
  },

398 399 400 401 402 403
  {
    GIMP_TARGET_COMPONENT,

    NULL,
    NULL,

404 405 406
    NULL,
    NULL,

407 408 409 410 411 412
    NULL,
    NULL,
    NULL,
  },

  {
413
    GIMP_TARGET_VECTORS,
414

415 416 417
    "gimp-dnd-get-vectors-func",
    "gimp-dnd-get-vectors-data",

418 419
    "gimp-dnd-set-vectors-func",
    "gimp-dnd-set-vectors-data",
420

421 422 423
    gimp_dnd_get_viewable_icon,
    gimp_dnd_get_item_data,
    gimp_dnd_set_item_data,
424 425
  },

426 427 428
  {
    GIMP_TARGET_BRUSH,

429 430 431
    "gimp-dnd-get-brush-func",
    "gimp-dnd-get-brush-data",

432 433
    "gimp-dnd-set-brush-func",
    "gimp-dnd-set-brush-data",
434

435
    gimp_dnd_get_viewable_icon,
436
    gimp_dnd_get_data_data,
437 438 439 440 441 442
    gimp_dnd_set_brush_data
  },

  {
    GIMP_TARGET_PATTERN,

443 444 445
    "gimp-dnd-get-pattern-func",
    "gimp-dnd-get-pattern-data",

446 447
    "gimp-dnd-set-pattern-func",
    "gimp-dnd-set-pattern-data",
448

449
    gimp_dnd_get_viewable_icon,
450
    gimp_dnd_get_data_data,
451 452 453 454 455 456
    gimp_dnd_set_pattern_data
  },

  {
    GIMP_TARGET_GRADIENT,

457 458 459
    "gimp-dnd-get-gradient-func",
    "gimp-dnd-get-gradient-data",

460 461
    "gimp-dnd-set-gradient-func",
    "gimp-dnd-set-gradient-data",
462

463
    gimp_dnd_get_viewable_icon,
464
    gimp_dnd_get_data_data,
465 466 467 468 469 470
    gimp_dnd_set_gradient_data
  },

  {
    GIMP_TARGET_PALETTE,

471 472 473
    "gimp-dnd-get-palette-func",
    "gimp-dnd-get-palette-data",

474 475
    "gimp-dnd-set-palette-func",
    "gimp-dnd-set-palette-data",
476

477
    gimp_dnd_get_viewable_icon,
478
    gimp_dnd_get_data_data,
479 480 481
    gimp_dnd_set_palette_data
  },

Michael Natterer's avatar
Michael Natterer committed
482 483 484
  {
    GIMP_TARGET_FONT,

485 486 487
    "gimp-dnd-get-font-func",
    "gimp-dnd-get-font-data",

488 489
    "gimp-dnd-set-font-func",
    "gimp-dnd-set-font-data",
Michael Natterer's avatar
Michael Natterer committed
490 491 492 493 494 495

    gimp_dnd_get_viewable_icon,
    gimp_dnd_get_data_data,
    gimp_dnd_set_font_data
  },

496 497 498
  {
    GIMP_TARGET_BUFFER,

499 500 501
    "gimp-dnd-get-buffer-func",
    "gimp-dnd-get-buffer-data",

502 503
    "gimp-dnd-set-buffer-func",
    "gimp-dnd-set-buffer-data",
504 505 506 507 508 509

    gimp_dnd_get_viewable_icon,
    gimp_dnd_get_data_data,
    gimp_dnd_set_buffer_data
  },

510
  {
511
    GIMP_TARGET_IMAGEFILE,
512

513 514 515
    "gimp-dnd-get-imagefile-func",
    "gimp-dnd-get-imagefile-data",

516 517
    "gimp-dnd-set-imagefile-func",
    "gimp-dnd-set-imagefile-data",
518

519 520 521 522 523
    gimp_dnd_get_viewable_icon,
    gimp_dnd_get_data_data,
    gimp_dnd_set_imagefile_data
  },

524 525 526
  {
    GIMP_TARGET_TEMPLATE,

527 528 529
    "gimp-dnd-get-template-func",
    "gimp-dnd-get-template-data",

530 531
    "gimp-dnd-set-template-func",
    "gimp-dnd-set-template-data",
532 533 534 535 536 537

    gimp_dnd_get_viewable_icon,
    gimp_dnd_get_data_data,
    gimp_dnd_set_template_data
  },

538
  {
539
    GIMP_TARGET_TOOL,
540

541 542 543
    "gimp-dnd-get-tool-func",
    "gimp-dnd-get-tool-data",

544 545
    "gimp-dnd-set-tool-func",
    "gimp-dnd-set-tool-data",
546

547
    gimp_dnd_get_viewable_icon,
548
    gimp_dnd_get_data_data,
549
    gimp_dnd_set_tool_data
550 551 552 553 554 555 556 557
  },

  {
    GIMP_TARGET_DIALOG,

    NULL,
    NULL,

558 559 560
    NULL,
    NULL,

561 562 563
    NULL,
    NULL,
    NULL
564 565
  }
};
566

567

568 569 570 571 572 573 574 575 576 577 578 579 580
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;
}


581 582 583
/********************************/
/*  general data dnd functions  */
/********************************/
584 585

static void
586
gimp_dnd_data_drag_begin (GtkWidget      *widget,
587 588
                          GdkDragContext *context,
                          gpointer        data)
589
{
590 591 592 593 594
  GimpDndType     data_type;
  GimpDndDataDef *dnd_data;
  GCallback       get_data_func = NULL;
  gpointer        get_data_data = NULL;
  GtkWidget      *icon_widget;
595

596 597
  data_type = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
                                                  "gimp-dnd-get-data-type"));
598

599
  if (! data_type)
600 601
    return;

602 603 604 605 606 607 608 609 610
  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);
611

612 613
  if (! get_data_func)
    return;
614

615 616 617
  icon_widget = dnd_data->get_icon_func (widget,
                                         get_data_func,
                                         get_data_data);
618

619 620
  if (icon_widget)
    {
621 622 623 624 625 626 627 628 629 630 631 632 633 634
      GtkWidget *frame;
      GtkWidget *window;

      window = gtk_window_new (GTK_WINDOW_POPUP);
      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);

635 636
      g_object_set_data_full (G_OBJECT (widget), "gimp-dnd-data-widget",
                              window, (GDestroyNotify) gtk_widget_destroy);
637

638
      gtk_drag_set_icon_widget (context, window,
639
                                DRAG_ICON_OFFSET, DRAG_ICON_OFFSET);
640 641 642

      /*  remember for which drag context the widget was made  */
      g_object_set_data (G_OBJECT (window), "gimp-gdk-drag-context", context);
643
    }
644 645 646
}

static void
647
gimp_dnd_data_drag_end (GtkWidget      *widget,
648
                        GdkDragContext *context)
649
{
650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665
  GtkWidget *icon_widget;

  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);
        }
    }
666 667 668
}

static void
669
gimp_dnd_data_drag_handle (GtkWidget        *widget,
670 671 672 673 674
                           GdkDragContext   *context,
                           GtkSelectionData *selection_data,
                           guint             info,
                           guint             time,
                           gpointer          data)
675
{
676 677
  GCallback    get_data_func = NULL;
  gpointer     get_data_data = NULL;
678
  GimpDndType  data_type;
679

680
  D (g_print ("\ngimp_dnd_data_drag_handle(%d)\n", info));
681

682 683 684 685 686
  for (data_type = GIMP_DND_TYPE_NONE + 1;
       data_type <= GIMP_DND_TYPE_LAST;
       data_type++)
    {
      GimpDndDataDef *dnd_data = dnd_data_defs + data_type;
687

688
      if (dnd_data->target_entry.info == info)
689 690
        {
          GdkAtom atom;
691

692 693
          D (g_print ("gimp_dnd_data_drag_handle(%s)\n",
                      dnd_data->target_entry.target));
694

695 696 697
          if (dnd_data->get_data_func_name)
            get_data_func = g_object_get_data (G_OBJECT (widget),
                                               dnd_data->get_data_func_name);
698

699 700 701
          if (dnd_data->get_data_data_name)
            get_data_data = g_object_get_data (G_OBJECT (widget),
                                               dnd_data->get_data_data_name);
702

703 704
          if (! get_data_func)
            return;
705

706
          atom = gdk_atom_intern (dnd_data->target_entry.target, FALSE);
707

708 709 710 711 712
          dnd_data->get_data_func (widget,
                                   get_data_func,
                                   get_data_data,
                                   selection_data,
                                   atom);
713 714 715

          return;
        }
716 717 718 719
    }
}

static void
720
gimp_dnd_data_drop_handle (GtkWidget        *widget,
721 722 723 724 725 726 727
                           GdkDragContext   *context,
                           gint              x,
                           gint              y,
                           GtkSelectionData *selection_data,
                           guint             info,
                           guint             time,
                           gpointer          data)
728
{
729
  GimpDndType data_type;
730

731
  D (g_print ("\ngimp_dnd_data_drop_handle(%d)\n", info));
732

733 734 735 736 737
  if (selection_data->length <= 0)
    {
      gtk_drag_finish (context, FALSE, FALSE, time);
      return;
    }
738

739 740
  for (data_type = GIMP_DND_TYPE_NONE + 1;
       data_type <= GIMP_DND_TYPE_LAST;
741 742
       data_type++)
    {
743 744 745
      GimpDndDataDef *dnd_data = dnd_data_defs + data_type;

      if (dnd_data->target_entry.info == info)
746
        {
747 748 749
          GCallback set_data_func = NULL;
          gpointer  set_data_data = NULL;

750 751
          D (g_print ("gimp_dnd_data_drop_handle(%s)\n",
                      dnd_data->target_entry.target));
752 753 754 755

          if (dnd_data->set_data_func_name)
            set_data_func = g_object_get_data (G_OBJECT (widget),
                                               dnd_data->set_data_func_name);
756

757 758 759
          if (dnd_data->set_data_data_name)
            set_data_data = g_object_get_data (G_OBJECT (widget),
                                               dnd_data->set_data_data_name);
760

761
          if (set_data_func &&
762
              dnd_data->set_data_func (widget, x, y,
763 764
                                       set_data_func,
                                       set_data_data,
765
                                       selection_data))
766 767 768 769
            {
              gtk_drag_finish (context, TRUE, FALSE, time);
              return;
            }
770

771
          gtk_drag_finish (context, FALSE, FALSE, time);
772 773
          return;
        }
774 775 776 777
    }
}

static void
778 779 780 781
gimp_dnd_data_source_add (GimpDndType  data_type,
                          GtkWidget   *widget,
                          GCallback    get_data_func,
                          gpointer     get_data_data)
782
{
783
  GimpDndDataDef *dnd_data;
784
  GtkTargetList  *target_list;
785 786 787 788 789 790 791 792 793
  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,
                         &dnd_data->target_entry, 1,
                         GDK_ACTION_COPY | GDK_ACTION_MOVE);
794 795

  drag_connected =
796 797
    GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
                                        "gimp-dnd-drag-connected"));
798 799 800

  if (! drag_connected)
    {
801
      g_signal_connect (widget, "drag_begin",
802 803
                        G_CALLBACK (gimp_dnd_data_drag_begin),
                        NULL);
804
      g_signal_connect (widget, "drag_end",
805 806
                        G_CALLBACK (gimp_dnd_data_drag_end),
                        NULL);
807
      g_signal_connect (widget, "drag_data_get",
808 809 810
                        G_CALLBACK (gimp_dnd_data_drag_handle),
                        NULL);

811 812
      g_object_set_data (G_OBJECT (widget), "gimp-dnd-drag-connected",
                         GINT_TO_POINTER (TRUE));
813
    }
814

815
  g_object_set_data (G_OBJECT (widget), dnd_data->get_data_func_name,
816
                     get_data_func);
817
  g_object_set_data (G_OBJECT (widget), dnd_data->get_data_data_name,
818
                     get_data_data);
819

820
  /*  remember the first set source type for drag view creation  */
821 822 823 824 825 826 827 828
  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));

  target_list = gtk_drag_source_get_target_list (widget);

  if (target_list)
    {
829 830 831 832 833
      GdkAtom atom = gdk_atom_intern (dnd_data->target_entry.target, TRUE);

      gtk_target_list_add (target_list, atom,
                           dnd_data->target_entry.flags,
                           dnd_data->target_entry.info);
834 835 836 837 838 839 840 841
    }
  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);
    }
842 843
}

844
static void
845 846
gimp_dnd_data_source_remove (GimpDndType  data_type,
                             GtkWidget   *widget)
847
{
848
  GimpDndDataDef *dnd_data;
849
  GtkTargetList  *target_list;
850
  gboolean        drag_connected;
851

852 853 854
  drag_connected =
    GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
                                        "gimp-dnd-drag-connected"));
855 856 857 858

  if (! drag_connected)
    return;

859 860 861 862 863 864 865 866 867 868 869 870 871 872 873
  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);

  target_list = gtk_drag_source_get_target_list (widget);

  if (target_list)
    {
874
      GdkAtom atom = gdk_atom_intern (dnd_data->target_entry.target, TRUE);
875 876 877 878

      if (atom != GDK_NONE)
        gtk_target_list_remove (target_list, atom);
    }
879 880
}

881
static void
Michael Natterer's avatar
Michael Natterer committed
882
gimp_dnd_data_dest_add (GimpDndType  data_type,
883 884 885
                        GtkWidget   *widget,
                        gpointer     set_data_func,
                        gpointer     set_data_data)
886
{
887 888 889
  GimpDndDataDef *dnd_data;
  GtkTargetList  *target_list;
  gboolean        drop_connected;
Michael Natterer's avatar
Michael Natterer committed
890 891 892 893

  /*  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);
894 895

  drop_connected =
896 897
    GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
                                        "gimp-dnd-drop-connected"));
898

899
  if (set_data_func && ! drop_connected)
900
    {
901
      g_signal_connect (widget, "drag_data_received",
902 903
                        G_CALLBACK (gimp_dnd_data_drop_handle),
                        NULL);
904

905 906
      g_object_set_data (G_OBJECT (widget), "gimp-dnd-drop-connected",
                         GINT_TO_POINTER (TRUE));
907 908
    }

909 910
  dnd_data = dnd_data_defs + data_type;

911 912 913 914 915 916 917
  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);
    }
Michael Natterer's avatar
Michael Natterer committed
918 919 920 921

  target_list = gtk_drag_dest_get_target_list (widget);

  if (target_list)
922
    {
923 924 925 926 927
      GdkAtom atom = gdk_atom_intern (dnd_data->target_entry.target, TRUE);

      gtk_target_list_add (target_list, atom,
                           dnd_data->target_entry.flags,
                           dnd_data->target_entry.info);
928
    }
Michael Natterer's avatar
Michael Natterer committed
929
  else
930
    {
931
      target_list = gtk_target_list_new (&dnd_data->target_entry, 1);
932 933

      gtk_drag_dest_set_target_list (widget, target_list);
934 935
      gtk_target_list_unref (target_list);
    }
936 937
}

938
static void
Michael Natterer's avatar
Michael Natterer committed
939 940
gimp_dnd_data_dest_remove (GimpDndType  data_type,
                           GtkWidget   *widget)
941
{
942 943
  GimpDndDataDef *dnd_data;
  GtkTargetList  *target_list;
944

945 946 947 948
  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);
Michael Natterer's avatar
Michael Natterer committed
949 950 951 952 953

  target_list = gtk_drag_dest_get_target_list (widget);

  if (target_list)
    {
954
      GdkAtom atom = gdk_atom_intern (dnd_data->target_entry.target, TRUE);
Michael Natterer's avatar
Michael Natterer committed
955 956

      if (atom != GDK_NONE)
957
        gtk_target_list_remove (target_list, atom);
Michael Natterer's avatar
Michael Natterer committed
958
    }
959 960
}

961

962 963 964
/****************************/
/*  uri list dnd functions  */
/****************************/
965

966
static void
967 968 969 970 971
gimp_dnd_get_uri_list_data (GtkWidget        *widget,
                            GCallback         get_uri_list_func,
                            gpointer          get_uri_list_data,
                            GtkSelectionData *selection,
                            GdkAtom           atom)
972
{
973
  GList *uri_list;
974

975 976
  uri_list = (* (GimpDndDragUriListFunc) get_uri_list_func) (widget,
                                                             get_uri_list_data);
977

978
  if (uri_list)
979
    {
980 981 982
      gimp_selection_data_set_uri_list (selection, atom, uri_list);

      g_list_foreach (uri_list, (GFunc) g_free, NULL);
983
      g_list_free (uri_list);
984 985 986
    }
}

987
static gboolean
988
gimp_dnd_set_uri_list_data (GtkWidget        *widget,
989 990
                            gint              x,
                            gint              y,
991 992 993
                            GCallback         set_uri_list_func,
                            gpointer          set_uri_list_data,
                            GtkSelectionData *selection)
994
{
995
  GList *uri_list = gimp_selection_data_get_uri_list (selection);
996

997 998
  if (! uri_list)
    return FALSE;
999

1000
  (* (GimpDndDropUriListFunc) set_uri_list_func) (widget, x, y, uri_list,
1001
                                                  set_uri_list_data);
1002

1003 1004
  g_list_foreach (uri_list, (GFunc) g_free, NULL);
  g_list_free (uri_list);
1005

1006 1007 1008 1009
  return TRUE;
}

void
1010 1011 1012
gimp_dnd_uri_list_source_add (GtkWidget              *widget,
                              GimpDndDragUriListFunc  get_uri_list_func,
                              gpointer                data)
1013 1014 1015 1016
{
  g_return_if_fail (GTK_IS_WIDGET (widget));

  gimp_dnd_data_source_add (GIMP_DND_TYPE_URI_LIST, widget,
1017
                            G_CALLBACK (get_uri_list_func),
1018
                            data);
1019 1020 1021
}

void
1022
gimp_dnd_uri_list_source_remove (GtkWidget *widget)
1023 1024 1025 1026 1027 1028 1029
{
  g_return_if_fail (GTK_IS_WIDGET (widget));

  gimp_dnd_data_source_remove (GIMP_DND_TYPE_URI_LIST, widget);
}

void
1030 1031 1032
gimp_dnd_uri_list_dest_add (GtkWidget              *widget,
                            GimpDndDropUriListFunc  set_uri_list_func,
                            gpointer                data)
1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044
{
  g_return_if_fail (GTK_IS_WIDGET (widget));

  /*  Set a default drag dest if not already done. Explicitely 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);

1045
  gimp_dnd_data_dest_add (GIMP_DND_TYPE_URI_LIST, widget,
1046
                          G_CALLBACK (set_uri_list_func),
1047
                          data);
1048
  gimp_dnd_data_dest_add (GIMP_DND_TYPE_TEXT_PLAIN, widget,
1049
                          G_CALLBACK (set_uri_list_func),
1050
                          data);
1051
  gimp_dnd_data_dest_add (GIMP_DND_TYPE_NETSCAPE_URL, widget,
1052
                          G_CALLBACK (set_uri_list_func),
1053
                          data);
1054 1055 1056
}

void
1057
gimp_dnd_uri_list_dest_remove (GtkWidget *widget)
1058 1059
{
  g_return_if_fail (GTK_IS_WIDGET (widget));
1060

1061 1062 1063 1064 1065
  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);
}

1066

1067 1068 1069 1070 1071
/*************************/
/*  color dnd functions  */
/*************************/

static GtkWidget *
1072
gimp_dnd_get_color_icon (GtkWidget *widget,
1073 1074
                         GCallback  get_color_func,
                         gpointer   get_color_data)
1075
{
1076 1077
  GtkWidget *color_area;
  GimpRGB    color;
1078

1079
  (* (GimpDndDragColorFunc) get_color_func) (widget, &color, get_color_data);
1080

1081
  color_area = gimp_color_area_new (&color, TRUE, 0);
1082
  gtk_widget_set_size_request (color_area, DRAG_PREVIEW_SIZE, DRAG_PREVIEW_SIZE);
1083

1084
  return color_area;
1085 1086
}

1087 1088 1089 1090 1091 1092
static void
gimp_dnd_get_color_data (GtkWidget        *widget,
                         GCallback         get_color_func,
                         gpointer          get_color_data,
                         GtkSelectionData *selection,
                         GdkAtom           atom)
1093
{
1094
  GimpRGB color;
1095

1096
  (* (GimpDndDragColorFunc) get_color_func) (widget, &color, get_color_data);
1097

1098
  gimp_selection_data_set_color (selection, atom, &color);
1099
}
1100

1101
static gboolean
1102
gimp_dnd_set_color_data (GtkWidget        *widget,
1103 1104
                         gint              x,
                         gint              y,
1105 1106 1107
                         GCallback         set_color_func,
                         gpointer          set_color_data,
                         GtkSelectionData *selection)
1108
{
1109
  GimpRGB color;
1110

1111 1112
  if (! gimp_selection_data_get_color (selection, &color))
    return FALSE;
1113

1114
  (* (GimpDndDropColorFunc) set_color_func) (widget, x, y, &color,
1115
                                             set_color_data);
1116 1117

  return TRUE;
1118 1119 1120
}

void
1121
gimp_dnd_color_source_add (GtkWidget            *widget,
1122 1123
                           GimpDndDragColorFunc  get_color_func,
                           gpointer              data)
1124
{
1125 1126
  g_return_if_fail (GTK_IS_WIDGET (widget));

1127
  gimp_dnd_data_source_add (GIMP_DND_TYPE_COLOR, widget,
1128 1129
                            G_CALLBACK (get_color_func),
                            data);
1130 1131
}

1132 1133 1134
void
gimp_dnd_color_source_remove (GtkWidget *widget)
{
1135 1136
  g_return_if_fail (GTK_IS_WIDGET (widget));

1137 1138 1139
  gimp_dnd_data_source_remove (GIMP_DND_TYPE_COLOR, widget);
}

1140
void
Michael Natterer's avatar
Michael Natterer committed
1141
gimp_dnd_color_dest_add (GtkWidget            *widget,
1142 1143
                         GimpDndDropColorFunc  set_color_func,
                         gpointer              data)
1144
{
1145 1146
  g_return_if_fail (GTK_IS_WIDGET (widget));

Michael Natterer's avatar
Michael Natterer committed
1147
  gimp_dnd_data_dest_add (GIMP_DND_TYPE_COLOR, widget,
1148 1149
                          G_CALLBACK (set_color_func),
                          data);
1150 1151
}

1152
void
Michael Natterer's avatar
Michael Natterer committed
1153
gimp_dnd_color_dest_remove (GtkWidget *widget)
1154
{
1155 1156
  g_return_if_fail (GTK_IS_WIDGET (widget));

Michael Natterer's avatar
Michael Natterer committed
1157
  gimp_dnd_data_dest_remove (GIMP_DND_TYPE_COLOR, widget);
1158 1159
}

1160

1161 1162 1163
/**************************/
/*  stream dnd functions  */
/**************************/
1164

1165
static void
1166 1167 1168 1169 1170
gimp_dnd_get_stream_data (GtkWidget        *widget,
                          GCallback         get_stream_func,
                          gpointer          get_stream_data,
                          GtkSelectionData *selection,
                          GdkAtom           atom)
1171
{
1172 1173
  guchar *stream;
  gsize   stream_length;
1174

1175 1176
  stream = (* (GimpDndDragStreamFunc) get_stream_func) (widget, &stream_length,
                                                        get_stream_data);
1177

1178
  if (stream)
1179
    {
1180 1181
      gimp_selection_data_set_stream (selection, atom, stream, stream_length);
      g_free (stream);
1182
    }
1183 1184
}

1185
static gboolean
1186
gimp_dnd_set_stream_data (GtkWidget        *widget,
1187 1188
                          gint              x,
                          gint              y,
1189 1190 1191
                          GCallback         set_stream_func,
                          gpointer          set_stream_data,
                          GtkSelectionData *selection)
1192
{
1193 1194
  const guchar *stream;
  gsize         stream_length;
1195

1196
  stream = gimp_selection_data_get_stream (selection, &stream_length);
1197

1198
  if (! stream)
1199
    return FALSE;
1200

1201
  (* (GimpDndDropStreamFunc) set_stream_func) (widget, x, y,
1202 1203
                                               stream, stream_length,
                                               set_stream_data);
1204 1205

  return TRUE;
1206 1207 1208
}

void
1209 1210 1211
gimp_dnd_svg_source_add (GtkWidget             *widget,
                         GimpDndDragStreamFunc  get_svg_func,
                         gpointer               data)
1212
{
1213 1214
  g_return_if_fail (GTK_IS_WIDGET (widget));

1215
  gimp_dnd_data_source_add (GIMP_DND_TYPE_SVG, widget,
1216 1217
                            G_CALLBACK (get_svg_func),
                            data);
1218
  gimp_dnd_data_source_add (GIMP_DND_TYPE_SVG_XML, widget,
1219 1220
                            G_CALLBACK (get_svg_func),
                            data);
1221 1222 1223 1224 1225
}

void
gimp_dnd_svg_source_remove (GtkWidget *widget)
{
1226 1227
  g_return_if_fail (GTK_IS_WIDGET (widget));

1228 1229 1230 1231 1232
  gimp_dnd_data_source_remove (GIMP_DND_TYPE_SVG, widget);
  gimp_dnd_data_source_remove (GIMP_DND_TYPE_SVG_XML, widget);
}

void
1233 1234 1235
gimp_dnd_svg_dest_add (GtkWidget             *widget,
                       GimpDndDropStreamFunc  set_svg_func,
                       gpointer               data)
1236
{
1237 1238
  g_return_if_fail (GTK_IS_WIDGET (widget));

1239
  gimp_dnd_data_dest_add (GIMP_DND_TYPE_SVG, widget,
1240 1241
                          G_CALLBACK (set_svg_func),
                          data);
1242
  gimp_dnd_data_dest_add (GIMP_DND_TYPE_SVG_XML, widget,
1243 1244
                          G_CALLBACK (set_svg_func),
                          data);
1245 1246 1247 1248 1249
}

void
gimp_dnd_svg_dest_remove (GtkWidget *widget)
{
1250 1251
  g_return_if_fail (GTK_IS_WIDGET (widget));

1252 1253 1254 1255 1256
  gimp_dnd_data_dest_remove (GIMP_DND_TYPE_SVG, widget);
  gimp_dnd_data_dest_remove (GIMP_DND_TYPE_SVG_XML, widget);
}


1257 1258 1259
/*******************************************/
/*  GimpViewable (by GType) dnd functions  */
/*******************************************/
1260

1261
static GtkWidget *
1262
gimp_dnd_get_viewable_icon (GtkWidget *widget,
1263 1264
                            GCallback  get_viewable_func,
                            gpointer   get_viewable_data)
1265
{
1266
  GtkWidget    *view;
1267 1268 1269
  GimpViewable *viewable;

  viewable = (* (GimpDndDragViewableFunc) get_viewable_func) (widget,
1270
                                                              get_viewable_data);
1271 1272 1273 1274

  if (! viewable)
    return NULL;

1275
  view = gimp_view_new (viewable, DRAG_PREVIEW_SIZE, 0, TRUE);
1276

1277
  return view;
1278 1279
}

1280 1281
static GimpDndType
gimp_dnd_data_type_get_by_g_type (GType type)
1282
{
1283
  GimpDndType dnd_type = GIMP_DND_TYPE_NONE;
1284

1285
  if (g_type_is_a (type, GIMP_TYPE_IMAGE))
1286
    {
1287
      dnd_type = GIMP_DND_TYPE_IMAGE;
1288
    }
1289
  else if (g_type_is_a (type, GIMP_TYPE_LAYER))
1290
    {
1291
      dnd_type = GIMP_DND_TYPE_LAYER;
1292
    }
1293
  else if (g_type_is_a (type, GIMP_TYPE_LAYER_MASK))
1294
    {
1295
      dnd_type = GIMP_DND_TYPE_LAYER_MASK;