gimpdnd.c 69.4 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 49
/*  #define DEBUG_DND  */

50
#include "gimpdnd.h"
51
#include "gimpdnd-xds.h"
52
#include "gimppixbuf.h"
53
#include "gimpselectiondata.h"
54
#include "gimpview.h"
55
#include "gimpviewrendererimage.h"
56

57
#include "gimp-intl.h"
58

59

60 61
#define DRAG_PREVIEW_SIZE  GIMP_VIEW_SIZE_LARGE
#define DRAG_ICON_OFFSET   -8
62

63 64 65 66 67 68 69

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

70

71 72 73 74
typedef GtkWidget * (* GimpDndGetIconFunc)  (GtkWidget        *widget,
                                             GCallback         get_data_func,
                                             gpointer          get_data_data);
typedef void        (* GimpDndDragDataFunc) (GtkWidget        *widget,
75
                                             GdkDragContext   *context,
76 77
                                             GCallback         get_data_func,
                                             gpointer          get_data_data,
78
                                             GtkSelectionData *selection);
79
typedef gboolean    (* GimpDndDropDataFunc) (GtkWidget        *widget,
80 81
                                             gint              x,
                                             gint              y,
82 83 84
                                             GCallback         set_data_func,
                                             gpointer          set_data_data,
                                             GtkSelectionData *selection);
85

86

87 88 89 90 91 92
typedef struct _GimpDndDataDef GimpDndDataDef;

struct _GimpDndDataDef
{
  GtkTargetEntry       target_entry;

93 94
  const gchar         *get_data_func_name;
  const gchar         *get_data_data_name;
95

96 97
  const gchar         *set_data_func_name;
  const gchar         *set_data_data_name;
98 99 100 101 102 103

  GimpDndGetIconFunc   get_icon_func;
  GimpDndDragDataFunc  get_data_func;
  GimpDndDropDataFunc  set_data_func;
};

104

105 106 107
static GtkWidget * gimp_dnd_get_viewable_icon  (GtkWidget        *widget,
                                                GCallback         get_viewable_func,
                                                gpointer          get_viewable_data);
108 109 110
static GtkWidget * gimp_dnd_get_component_icon (GtkWidget        *widget,
                                                GCallback         get_comp_func,
                                                gpointer          get_comp_data);
111 112 113 114
static GtkWidget * gimp_dnd_get_color_icon     (GtkWidget        *widget,
                                                GCallback         get_color_func,
                                                gpointer          get_color_data);

115
static void        gimp_dnd_get_uri_list_data  (GtkWidget        *widget,
116
                                                GdkDragContext   *context,
117 118
                                                GCallback         get_uri_list_func,
                                                gpointer          get_uri_list_data,
119
                                                GtkSelectionData *selection);
120
static gboolean    gimp_dnd_set_uri_list_data  (GtkWidget        *widget,
121 122
                                                gint              x,
                                                gint              y,
123 124
                                                GCallback         set_uri_list_func,
                                                gpointer          set_uri_list_data,
125 126
                                                GtkSelectionData *selection);

127 128 129 130
static void        gimp_dnd_get_xds_data       (GtkWidget        *widget,
                                                GdkDragContext   *context,
                                                GCallback         get_image_func,
                                                gpointer          get_image_data,
131
                                                GtkSelectionData *selection);
132

133
static void        gimp_dnd_get_color_data     (GtkWidget        *widget,
134
                                                GdkDragContext   *context,
135 136
                                                GCallback         get_color_func,
                                                gpointer          get_color_data,
137
                                                GtkSelectionData *selection);
138
static gboolean    gimp_dnd_set_color_data     (GtkWidget        *widget,
139 140
                                                gint              x,
                                                gint              y,
141 142 143 144
                                                GCallback         set_color_func,
                                                gpointer          set_color_data,
                                                GtkSelectionData *selection);

145
static void        gimp_dnd_get_stream_data    (GtkWidget        *widget,
146
                                                GdkDragContext   *context,
147 148
                                                GCallback         get_stream_func,
                                                gpointer          get_stream_data,
149
                                                GtkSelectionData *selection);
150
static gboolean    gimp_dnd_set_stream_data    (GtkWidget        *widget,
151 152
                                                gint              x,
                                                gint              y,
153 154
                                                GCallback         set_stream_func,
                                                gpointer          set_stream_data,
155 156
                                                GtkSelectionData *selection);

157 158 159 160 161 162 163 164 165 166 167
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);
168
static void        gimp_dnd_get_component_data (GtkWidget        *widget,
169
                                                GdkDragContext   *context,
170 171
                                                GCallback         get_comp_func,
                                                gpointer          get_comp_data,
172
                                                GtkSelectionData *selection);
173 174 175 176 177 178 179
static gboolean    gimp_dnd_set_component_data (GtkWidget        *widget,
                                                gint              x,
                                                gint              y,
                                                GCallback         set_comp_func,
                                                gpointer          set_comp_data,
                                                GtkSelectionData *selection);

180
static void        gimp_dnd_get_image_data     (GtkWidget        *widget,
181
                                                GdkDragContext   *context,
182 183
                                                GCallback         get_image_func,
                                                gpointer          get_image_data,
184
                                                GtkSelectionData *selection);
185
static gboolean    gimp_dnd_set_image_data     (GtkWidget        *widget,
186 187
                                                gint              x,
                                                gint              y,
188 189 190 191 192
                                                GCallback         set_image_func,
                                                gpointer          set_image_data,
                                                GtkSelectionData *selection);

static void        gimp_dnd_get_item_data      (GtkWidget        *widget,
193
                                                GdkDragContext   *context,
194 195
                                                GCallback         get_item_func,
                                                gpointer          get_item_data,
196
                                                GtkSelectionData *selection);
197
static gboolean    gimp_dnd_set_item_data      (GtkWidget        *widget,
198 199
                                                gint              x,
                                                gint              y,
200 201 202 203
                                                GCallback         set_item_func,
                                                gpointer          set_item_data,
                                                GtkSelectionData *selection);

204
static void        gimp_dnd_get_object_data    (GtkWidget        *widget,
205
                                                GdkDragContext   *context,
206 207
                                                GCallback         get_object_func,
                                                gpointer          get_object_data,
208
                                                GtkSelectionData *selection);
209 210

static gboolean    gimp_dnd_set_brush_data     (GtkWidget        *widget,
211 212
                                                gint              x,
                                                gint              y,
213 214 215 216
                                                GCallback         set_brush_func,
                                                gpointer          set_brush_data,
                                                GtkSelectionData *selection);
static gboolean    gimp_dnd_set_pattern_data   (GtkWidget        *widget,
217 218
                                                gint              x,
                                                gint              y,
219 220 221 222
                                                GCallback         set_pattern_func,
                                                gpointer          set_pattern_data,
                                                GtkSelectionData *selection);
static gboolean    gimp_dnd_set_gradient_data  (GtkWidget        *widget,
223 224
                                                gint              x,
                                                gint              y,
225 226 227 228
                                                GCallback         set_gradient_func,
                                                gpointer          set_gradient_data,
                                                GtkSelectionData *selection);
static gboolean    gimp_dnd_set_palette_data   (GtkWidget        *widget,
229 230
                                                gint              x,
                                                gint              y,
231 232 233 234
                                                GCallback         set_palette_func,
                                                gpointer          set_palette_data,
                                                GtkSelectionData *selection);
static gboolean    gimp_dnd_set_font_data      (GtkWidget        *widget,
235 236
                                                gint              x,
                                                gint              y,
237 238 239 240
                                                GCallback         set_font_func,
                                                gpointer          set_font_data,
                                                GtkSelectionData *selection);
static gboolean    gimp_dnd_set_buffer_data    (GtkWidget        *widget,
241 242
                                                gint              x,
                                                gint              y,
243 244 245 246
                                                GCallback         set_buffer_func,
                                                gpointer          set_buffer_data,
                                                GtkSelectionData *selection);
static gboolean    gimp_dnd_set_imagefile_data (GtkWidget        *widget,
247 248
                                                gint              x,
                                                gint              y,
249 250 251 252
                                                GCallback         set_imagefile_func,
                                                gpointer          set_imagefile_data,
                                                GtkSelectionData *selection);
static gboolean    gimp_dnd_set_template_data  (GtkWidget        *widget,
253 254
                                                gint              x,
                                                gint              y,
255 256 257
                                                GCallback         set_template_func,
                                                gpointer          set_template_data,
                                                GtkSelectionData *selection);
258
static gboolean    gimp_dnd_set_tool_info_data (GtkWidget        *widget,
259 260
                                                gint              x,
                                                gint              y,
261 262
                                                GCallback         set_tool_info_func,
                                                gpointer          set_tool_info_data,
263
                                                GtkSelectionData *selection);
264

265

266

267
static const GimpDndDataDef dnd_data_defs[] =
268 269 270 271 272 273 274 275 276
{
  {
    { NULL, 0, -1 },

    NULL,
    NULL,

    NULL,
    NULL,
Michael Natterer's avatar
Michael Natterer committed
277
    NULL
278 279
  },

280 281 282
  {
    GIMP_TARGET_URI_LIST,

283 284
    "gimp-dnd-get-uri-list-func",
    "gimp-dnd-get-uri-list-data",
285

286 287
    "gimp-dnd-set-uri-list-func",
    "gimp-dnd-set-uri-list-data",
288 289

    NULL,
290 291
    gimp_dnd_get_uri_list_data,
    gimp_dnd_set_uri_list_data
292 293 294 295 296
  },

  {
    GIMP_TARGET_TEXT_PLAIN,

297 298 299
    NULL,
    NULL,

300 301
    "gimp-dnd-set-uri-list-func",
    "gimp-dnd-set-uri-list-data",
302 303 304

    NULL,
    NULL,
305
    gimp_dnd_set_uri_list_data
306 307 308 309 310
  },

  {
    GIMP_TARGET_NETSCAPE_URL,

311 312 313
    NULL,
    NULL,

314 315
    "gimp-dnd-set-uri-list-func",
    "gimp-dnd-set-uri-list-data",
316 317 318

    NULL,
    NULL,
319
    gimp_dnd_set_uri_list_data
320 321
  },

322 323 324 325 326 327 328 329 330 331 332 333 334 335
  {
    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
  },

336 337 338
  {
    GIMP_TARGET_COLOR,

339 340 341
    "gimp-dnd-get-color-func",
    "gimp-dnd-get-color-data",

342 343
    "gimp-dnd-set-color-func",
    "gimp-dnd-set-color-data",
344 345 346 347 348 349

    gimp_dnd_get_color_icon,
    gimp_dnd_get_color_data,
    gimp_dnd_set_color_data
  },

350 351 352 353 354 355 356 357 358 359
  {
    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,
360 361
    gimp_dnd_get_stream_data,
    gimp_dnd_set_stream_data
362 363 364 365 366 367 368 369 370 371 372 373
  },

  {
    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,
374 375
    gimp_dnd_get_stream_data,
    gimp_dnd_set_stream_data
376 377
  },

378 379 380 381 382 383 384 385 386 387 388 389 390 391
  {
    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
  },

392 393 394
  {
    GIMP_TARGET_IMAGE,

395 396 397
    "gimp-dnd-get-image-func",
    "gimp-dnd-get-image-data",

398 399
    "gimp-dnd-set-image-func",
    "gimp-dnd-set-image-data",
400 401 402 403 404 405

    gimp_dnd_get_viewable_icon,
    gimp_dnd_get_image_data,
    gimp_dnd_set_image_data,
  },

406 407 408 409 410 411 412 413 414
  {
    GIMP_TARGET_COMPONENT,

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

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

415
    gimp_dnd_get_component_icon,
416 417 418 419
    gimp_dnd_get_component_data,
    gimp_dnd_set_component_data,
  },

420 421 422
  {
    GIMP_TARGET_LAYER,

423 424 425
    "gimp-dnd-get-layer-func",
    "gimp-dnd-get-layer-data",

426 427
    "gimp-dnd-set-layer-func",
    "gimp-dnd-set-layer-data",
428 429

    gimp_dnd_get_viewable_icon,
430 431
    gimp_dnd_get_item_data,
    gimp_dnd_set_item_data,
432 433 434 435 436
  },

  {
    GIMP_TARGET_CHANNEL,

437 438 439
    "gimp-dnd-get-channel-func",
    "gimp-dnd-get-channel-data",

440 441
    "gimp-dnd-set-channel-func",
    "gimp-dnd-set-channel-data",
442 443

    gimp_dnd_get_viewable_icon,
444 445
    gimp_dnd_get_item_data,
    gimp_dnd_set_item_data,
446 447 448 449 450
  },

  {
    GIMP_TARGET_LAYER_MASK,

451 452 453
    "gimp-dnd-get-layer-mask-func",
    "gimp-dnd-get-layer-mask-data",

454 455
    "gimp-dnd-set-layer-mask-func",
    "gimp-dnd-set-layer-mask-data",
456 457

    gimp_dnd_get_viewable_icon,
458 459
    gimp_dnd_get_item_data,
    gimp_dnd_set_item_data,
460 461
  },

462
  {
463
    GIMP_TARGET_VECTORS,
464

465 466 467
    "gimp-dnd-get-vectors-func",
    "gimp-dnd-get-vectors-data",

468 469
    "gimp-dnd-set-vectors-func",
    "gimp-dnd-set-vectors-data",
470

471 472 473
    gimp_dnd_get_viewable_icon,
    gimp_dnd_get_item_data,
    gimp_dnd_set_item_data,
474 475
  },

476 477 478
  {
    GIMP_TARGET_BRUSH,

479 480 481
    "gimp-dnd-get-brush-func",
    "gimp-dnd-get-brush-data",

482 483
    "gimp-dnd-set-brush-func",
    "gimp-dnd-set-brush-data",
484

485
    gimp_dnd_get_viewable_icon,
486
    gimp_dnd_get_object_data,
487 488 489 490 491 492
    gimp_dnd_set_brush_data
  },

  {
    GIMP_TARGET_PATTERN,

493 494 495
    "gimp-dnd-get-pattern-func",
    "gimp-dnd-get-pattern-data",

496 497
    "gimp-dnd-set-pattern-func",
    "gimp-dnd-set-pattern-data",
498

499
    gimp_dnd_get_viewable_icon,
500
    gimp_dnd_get_object_data,
501 502 503 504 505 506
    gimp_dnd_set_pattern_data
  },

  {
    GIMP_TARGET_GRADIENT,

507 508 509
    "gimp-dnd-get-gradient-func",
    "gimp-dnd-get-gradient-data",

510 511
    "gimp-dnd-set-gradient-func",
    "gimp-dnd-set-gradient-data",
512

513
    gimp_dnd_get_viewable_icon,
514
    gimp_dnd_get_object_data,
515 516 517 518 519 520
    gimp_dnd_set_gradient_data
  },

  {
    GIMP_TARGET_PALETTE,

521 522 523
    "gimp-dnd-get-palette-func",
    "gimp-dnd-get-palette-data",

524 525
    "gimp-dnd-set-palette-func",
    "gimp-dnd-set-palette-data",
526

527
    gimp_dnd_get_viewable_icon,
528
    gimp_dnd_get_object_data,
529 530 531
    gimp_dnd_set_palette_data
  },

Michael Natterer's avatar
Michael Natterer committed
532 533 534
  {
    GIMP_TARGET_FONT,

535 536 537
    "gimp-dnd-get-font-func",
    "gimp-dnd-get-font-data",

538 539
    "gimp-dnd-set-font-func",
    "gimp-dnd-set-font-data",
Michael Natterer's avatar
Michael Natterer committed
540 541

    gimp_dnd_get_viewable_icon,
542
    gimp_dnd_get_object_data,
Michael Natterer's avatar
Michael Natterer committed
543 544 545
    gimp_dnd_set_font_data
  },

546 547 548
  {
    GIMP_TARGET_BUFFER,

549 550 551
    "gimp-dnd-get-buffer-func",
    "gimp-dnd-get-buffer-data",

552 553
    "gimp-dnd-set-buffer-func",
    "gimp-dnd-set-buffer-data",
554 555

    gimp_dnd_get_viewable_icon,
556
    gimp_dnd_get_object_data,
557 558 559
    gimp_dnd_set_buffer_data
  },

560
  {
561
    GIMP_TARGET_IMAGEFILE,
562

563 564 565
    "gimp-dnd-get-imagefile-func",
    "gimp-dnd-get-imagefile-data",

566 567
    "gimp-dnd-set-imagefile-func",
    "gimp-dnd-set-imagefile-data",
568

569
    gimp_dnd_get_viewable_icon,
570
    gimp_dnd_get_object_data,
571 572 573
    gimp_dnd_set_imagefile_data
  },

574 575 576
  {
    GIMP_TARGET_TEMPLATE,

577 578 579
    "gimp-dnd-get-template-func",
    "gimp-dnd-get-template-data",

580 581
    "gimp-dnd-set-template-func",
    "gimp-dnd-set-template-data",
582 583

    gimp_dnd_get_viewable_icon,
584
    gimp_dnd_get_object_data,
585 586 587
    gimp_dnd_set_template_data
  },

588
  {
589
    GIMP_TARGET_TOOL_INFO,
590

591 592
    "gimp-dnd-get-tool-info-func",
    "gimp-dnd-get-tool-info-data",
593

594 595
    "gimp-dnd-set-tool-info-func",
    "gimp-dnd-set-tool-info-data",
596

597
    gimp_dnd_get_viewable_icon,
598 599
    gimp_dnd_get_object_data,
    gimp_dnd_set_tool_info_data
600 601 602 603 604 605 606 607
  },

  {
    GIMP_TARGET_DIALOG,

    NULL,
    NULL,

608 609 610
    NULL,
    NULL,

611 612 613
    NULL,
    NULL,
    NULL
614 615
  }
};
616

617

618 619 620 621 622 623 624 625 626 627 628 629 630
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;
}


631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648
/**********************/
/*  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);
    }
}


649 650 651
/********************************/
/*  general data dnd functions  */
/********************************/
652 653

static void
654
gimp_dnd_data_drag_begin (GtkWidget      *widget,
655 656
                          GdkDragContext *context,
                          gpointer        data)
657
{
658 659 660 661 662
  const GimpDndDataDef *dnd_data;
  GimpDndType           data_type;
  GCallback             get_data_func = NULL;
  gpointer              get_data_data = NULL;
  GtkWidget            *icon_widget;
663

664 665
  data_type = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
                                                  "gimp-dnd-get-data-type"));
666

667
  D (g_printerr ("\ngimp_dnd_data_drag_begin (%d)\n", data_type));
668

669
  if (! data_type)
670 671
    return;

672 673 674 675 676 677 678 679 680
  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);
681

682 683
  if (! get_data_func)
    return;
684

685 686 687
  icon_widget = dnd_data->get_icon_func (widget,
                                         get_data_func,
                                         get_data_data);
688

689 690
  if (icon_widget)
    {
691 692 693 694 695 696 697 698 699 700 701 702 703 704
      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);

705 706
      g_object_set_data_full (G_OBJECT (widget), "gimp-dnd-data-widget",
                              window, (GDestroyNotify) gtk_widget_destroy);
707

708
      gtk_drag_set_icon_widget (context, window,
709
                                DRAG_ICON_OFFSET, DRAG_ICON_OFFSET);
710 711 712

      /*  remember for which drag context the widget was made  */
      g_object_set_data (G_OBJECT (window), "gimp-gdk-drag-context", context);
713
    }
714 715 716
}

static void
717
gimp_dnd_data_drag_end (GtkWidget      *widget,
718
                        GdkDragContext *context)
719
{
720 721
  GtkWidget *icon_widget;

722
  D (g_printerr ("\ngimp_dnd_data_drag_end\n"));
723

724 725 726 727 728 729 730 731 732 733 734 735 736 737
  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);
        }
    }
738 739 740
}

static void
741
gimp_dnd_data_drag_handle (GtkWidget        *widget,
742 743 744 745 746
                           GdkDragContext   *context,
                           GtkSelectionData *selection_data,
                           guint             info,
                           guint             time,
                           gpointer          data)
747
{
748 749
  GCallback    get_data_func = NULL;
  gpointer     get_data_data = NULL;
750
  GimpDndType  data_type;
751

752
  D (g_printerr ("\ngimp_dnd_data_drag_handle(%d)\n", info));
753

754 755 756 757
  for (data_type = GIMP_DND_TYPE_NONE + 1;
       data_type <= GIMP_DND_TYPE_LAST;
       data_type++)
    {
758
      const GimpDndDataDef *dnd_data = dnd_data_defs + data_type;
759

760
      if (dnd_data->target_entry.info == info)
761
        {
762 763
          D (g_printerr ("gimp_dnd_data_drag_handle(%s)\n",
                         dnd_data->target_entry.target));
764

765 766 767
          if (dnd_data->get_data_func_name)
            get_data_func = g_object_get_data (G_OBJECT (widget),
                                               dnd_data->get_data_func_name);
768

769 770 771
          if (dnd_data->get_data_data_name)
            get_data_data = g_object_get_data (G_OBJECT (widget),
                                               dnd_data->get_data_data_name);
772

773 774
          if (! get_data_func)
            return;
775

776
          dnd_data->get_data_func (widget,
777
                                   context,
778 779
                                   get_data_func,
                                   get_data_data,
780
                                   selection_data);
781 782 783

          return;
        }
784 785 786 787
    }
}

static void
788
gimp_dnd_data_drop_handle (GtkWidget        *widget,
789 790 791 792 793 794 795
                           GdkDragContext   *context,
                           gint              x,
                           gint              y,
                           GtkSelectionData *selection_data,
                           guint             info,
                           guint             time,
                           gpointer          data)
796
{
797
  GimpDndType data_type;
798

799
  D (g_printerr ("\ngimp_dnd_data_drop_handle(%d)\n", info));
800

801 802 803 804 805
  if (selection_data->length <= 0)
    {
      gtk_drag_finish (context, FALSE, FALSE, time);
      return;
    }
806

807 808
  for (data_type = GIMP_DND_TYPE_NONE + 1;
       data_type <= GIMP_DND_TYPE_LAST;
809 810
       data_type++)
    {
811
      const GimpDndDataDef *dnd_data = dnd_data_defs + data_type;
812 813

      if (dnd_data->target_entry.info == info)
814
        {
815 816 817
          GCallback set_data_func = NULL;
          gpointer  set_data_data = NULL;

818 819
          D (g_printerr ("gimp_dnd_data_drop_handle(%s)\n",
                         dnd_data->target_entry.target));
820 821 822 823

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

825 826 827
          if (dnd_data->set_data_data_name)
            set_data_data = g_object_get_data (G_OBJECT (widget),
                                               dnd_data->set_data_data_name);
828

829
          if (set_data_func &&
830
              dnd_data->set_data_func (widget, x, y,
831 832
                                       set_data_func,
                                       set_data_data,
833
                                       selection_data))
834 835 836 837
            {
              gtk_drag_finish (context, TRUE, FALSE, time);
              return;
            }
838

839
          gtk_drag_finish (context, FALSE, FALSE, time);
840 841
          return;
        }
842 843 844 845
    }
}

static void
846 847 848 849
gimp_dnd_data_source_add (GimpDndType  data_type,
                          GtkWidget   *widget,
                          GCallback    get_data_func,
                          gpointer     get_data_data)
850
{
851 852
  const GimpDndDataDef *dnd_data;
  gboolean              drag_connected;
853 854 855 856 857 858

  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,
859
                         NULL, 0,
860
                         GDK_ACTION_COPY | GDK_ACTION_MOVE);
861 862

  drag_connected =
863 864
    GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
                                        "gimp-dnd-drag-connected"));
865 866 867

  if (! drag_connected)
    {
868
      g_signal_connect (widget, "drag_begin",
869 870
                        G_CALLBACK (gimp_dnd_data_drag_begin),
                        NULL);
871
      g_signal_connect (widget, "drag_end",
872 873
                        G_CALLBACK (gimp_dnd_data_drag_end),
                        NULL);
874
      g_signal_connect (widget, "drag_data_get",
875 876 877
                        G_CALLBACK (gimp_dnd_data_drag_handle),
                        NULL);

878 879
      g_object_set_data (G_OBJECT (widget), "gimp-dnd-drag-connected",
                         GINT_TO_POINTER (TRUE));
880
    }
881

882
  g_object_set_data (G_OBJECT (widget), dnd_data->get_data_func_name,
883
                     get_data_func);
884
  g_object_set_data (G_OBJECT (widget), dnd_data->get_data_data_name,
885
                     get_data_data);
886

887
  /*  remember the first set source type for drag view creation  */
888 889 890 891
  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));

892
  if (dnd_data->target_entry.target)
893
    {
894
      GtkTargetList *target_list;
895

896 897 898 899 900 901 902 903 904 905 906 907 908
      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);
        }
909
    }
910 911
}

912
static void
913 914
gimp_dnd_data_source_remove (GimpDndType  data_type,
                             GtkWidget   *widget)
915
{
916 917
  const GimpDndDataDef *dnd_data;
  gboolean              drag_connected;
918

919 920 921
  drag_connected =
    GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
                                        "gimp-dnd-drag-connected"));
922 923 924 925

  if (! drag_connected)
    return;

926 927 928 929 930 931 932 933 934 935 936
  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);

937
  if (dnd_data->target_entry.target)
938
    {
939 940 941
      GtkTargetList *target_list;

      target_list = gtk_drag_source_get_target_list (widget);
942

943 944 945 946 947 948 949
      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);
        }
950
    }
951 952
}

953
static void
Michael Natterer's avatar
Michael Natterer committed
954
gimp_dnd_data_dest_add (GimpDndType  data_type,
955 956 957
                        GtkWidget   *widget,
                        gpointer     set_data_func,
                        gpointer     set_data_data)
958
{
959 960
  const GimpDndDataDef *dnd_data;
  gboolean              drop_connected;
Michael Natterer's avatar
Michael Natterer committed
961 962 963 964

  /*  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);
965 966

  drop_connected =
967 968
    GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
                                        "gimp-dnd-drop-connected"));
969

970
  if (set_data_func && ! drop_connected)
971
    {
972
      g_signal_connect (widget, "drag_data_received",
973 974
                        G_CALLBACK (gimp_dnd_data_drop_handle),
                        NULL);
975

976 977
      g_object_set_data (G_OBJECT (widget), "gimp-dnd-drop-connected",
                         GINT_TO_POINTER (TRUE));
978 979
    }

980 981
  dnd_data = dnd_data_defs + data_type;

982 983 984 985 986 987 988
  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
989

990
  if (dnd_data->target_entry.target)
991
    {
992 993 994
      GtkTargetList *target_list;

      target_list = gtk_drag_dest_get_target_list (widget);
995

996 997 998 999 1000 1001 1002 1003 1004 1005 1006
      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);
        }
1007
    }
1008 1009
}

1010
static void
Michael Natterer's avatar
Michael Natterer committed
1011 1012
gimp_dnd_data_dest_remove (GimpDndType  data_type,
                           GtkWidget   *widget)
1013
{
1014
  const GimpDndDataDef *dnd_data;
1015

1016 1017 1018 1019
  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
1020

1021
  if (dnd_data->target_entry.target)
Michael Natterer's avatar
Michael Natterer committed
1022
    {
1023 1024 1025 1026 1027 1028 1029
      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);
Michael Natterer's avatar
Michael Natterer committed
1030

1031 1032 1033
          if (atom != GDK_NONE)
            gtk_target_list_remove (target_list, atom);
        }
Michael Natterer's avatar
Michael Natterer committed
1034
    }
1035 1036
}

1037

1038 1039 1040
/****************************/
/*  uri list dnd functions  */
/****************************/
1041

1042
static void
1043
gimp_dnd_get_uri_list_data (GtkWidget        *widget,
1044
                            GdkDragContext   *context,
1045 1046
                            GCallback         get_uri_list_func,
                            gpointer          get_uri_list_data,
1047
                            GtkSelectionData *selection)
1048
{
1049
  GList *uri_list;
1050

1051 1052
  uri_list = (* (GimpDndDragUriListFunc) get_uri_list_func) (widget,
                                                             get_uri_list_data);
1053

1054
  if (uri_list)
1055
    {
1056
      gimp_selection_data_set_uri_list (selection, uri_list);
1057 1058

      g_list_foreach (uri_list, (GFunc) g_free, NULL);
1059
      g_list_free (uri_list);
1060 1061 1062
    }
}

1063
static gboolean
1064
gimp_dnd_set_uri_list_data (GtkWidget        *widget,
1065 1066
                            gint              x,
                            gint              y,
1067 1068 1069
                            GCallback         set_uri_list_func,
                            gpointer          set_uri_list_data,
                            GtkSelectionData *selection)
1070
{
1071
  GList *uri_list = gimp_selection_data_get_uri_list (selection);
1072

1073 1074
  if (! uri_list)
    return FALSE;
1075

1076
  (* (GimpDndDropUriListFunc) set_uri_list_func) (widget, x, y, uri_list,
1077
                                                  set_uri_list_data);
1078

1079 1080
  g_list_foreach (uri_list, (GFunc) g_free, NULL);
  g_list_free (uri_list);
1081

1082 1083 1084 1085
  return TRUE;
}

void
1086 1087 1088
gimp_dnd_uri_list_source_add (GtkWidget              *widget,
                              GimpDndDragUriListFunc  get_uri_list_func,
                              gpointer                data)
1089 1090 1091 1092
{
  g_return_if_fail (GTK_IS_WIDGET (widget));

  gimp_dnd_data_source_add (GIMP_DND_TYPE_URI_LIST, widget,
1093
                            G_CALLBACK (get_uri_list_func),
1094
                            data);
1095 1096 1097
}

void
1098
gimp_dnd_uri_list_source_remove (GtkWidget *widget)
1099 1100 1101 1102 1103 1104 1105
{
  g_return_if_fail (GTK_IS_WIDGET (widget));

  gimp_dnd_data_source_remove (GIMP_DND_TYPE_URI_LIST, widget);
}

void
1106 1107 1108
gimp_dnd_uri_list_dest_add (GtkWidget              *widget,
                            GimpDndDropUriListFunc  set_uri_list_func,
                            gpointer                data)
1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120
{
  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);

1121
  gimp_dnd_data_dest_add (GIMP_DND_TYPE_URI_LIST, widget,
1122
                          G_CALLBACK (set_uri_list_func),
1123
                          data);
1124
  gimp_dnd_data_dest_add (GIMP_DND_TYPE_TEXT_PLAIN, widget,
1125
                          G_CALLBACK (set_uri_list_func),
1126
                          data);
1127
  gimp_dnd_data_dest_add (GIMP_DND_TYPE_NETSCAPE_URL, widget,
1128
                          G_CALLBACK (set_uri_list_func),
1129
                          data);
1130 1131 1132
}

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

1137 1138 1139 1140 1141
  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);
}

1142

1143 1144 1145 1146 1147 1148 1149 1150 1151
/******************************/
/* Direct Save Protocol (XDS) */
/******************************/

static void
gimp_dnd_get_xds_data (GtkWidget        *widget,
                       GdkDragContext   *context,
                       GCallback         get_image_func,
                       gpointer          get_image_data,
1152
                       GtkSelectionData *selection)
1153 1154 1155 1156 1157 1158 1159
{
  GimpImage *image;

  image = (GimpImage *)
    (* (GimpDndDragViewableFunc) get_image_func) (widget, get_image_data);

  if (image)
1160
    gimp_dnd_xds_save_image (context, image, selection);
1161 1162 1163 1164
}

static void
gimp_dnd_xds_drag_begin (GtkWidget      *widget,
1165
                         GdkDragContext *context)
1166
{
1167 1168 1169
  const GimpDndDataDef *dnd_data = dnd_data_defs + GIMP_DND_TYPE_XDS;
  GCallback             get_data_func;
  gpointer              get_data_data;
1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184

  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 = (GimpImage *)
        (* (GimpDndDragViewableFunc) get_data_func) (widget, get_data_data);

      gimp_dnd_xds_source_set (context, image);
    }
}

1185 1186 1187 1188 1189 1190 1191
static void
gimp_dnd_xds_drag_end (GtkWidget      *widget,
                       GdkDragContext *context)
{
  gimp_dnd_xds_source_set (context, NULL);
}

1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215
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));
    }
1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227

  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));
    }
1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244
}

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);
    }

1245 1246 1247 1248 1249 1250 1251 1252
  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);
    }

1253 1254 1255 1256
  gimp_dnd_data_source_remove (GIMP_DND_TYPE_XDS, widget);
}


1257 1258 1259 1260 1261
/*************************/
/*  color dnd functions  */
/*************************/

static GtkWidget *
1262
gimp_dnd_get_color_icon (GtkWidget *widget,
1263 1264
                         GCallback  get_color_func,
                         gpointer   get_color_data)
1265
{
1266 1267
  GtkWidget *color_area;
  GimpRGB    color;
1268

1269
  (* (GimpDndDragColorFunc) get_color_func) (widget, &color, get_color_data);
1270

1271 1272 1273
  color_area = gimp_color_area_new (&color, GIMP_COLOR_AREA_SMALL_CHECKS, 0);
  gtk_widget_set_size_request (color_area,
                               DRAG_PREVIEW_SIZE, DRAG_PREVIEW_SIZE);
1274

1275
  return color_area;
1276 1277
}

1278 1279
static void
gimp_dnd_get_color_data (GtkWidget        *widget,
1280
                         GdkDragContext   *context,
1281 1282
                         GCallback         get_color_func,
                         gpointer          get_color_data,
1283
                         GtkSelectionData *selection)
1284
{
1285
  GimpRGB color;
1286

1287
  (* (GimpDndDragColorFunc) get_color_func) (widget, &color, get_color_data);
1288

1289
  gimp_selection_data_set_color (selection, &color);
1290
}
1291

1292
static gboolean
1293
gimp_dnd_set_color_data (GtkWidget        *widget,
1294 1295
                         gint              x,
                         gint              y,
1296 1297 1298
                         GCallback         set_color_func,
                         gpointer          set_color_data,
                         GtkSelectionData *selection)
1299
{
1300
  GimpRGB color;
1301

1302 1303
  if (! gimp_selection_data_get_color (selection, &color))
    return FALSE;
1304

1305
  (* (GimpDndDropColorFunc) set_color_func) (widget, x, y, &color,
1306
                                             set_color_data);
1307 1308

  return TRUE;
1309 1310 1311
}

void
1312
gimp_dnd_color_source_add (GtkWidget            *widget,
1313 1314
                           GimpDndDragColorFunc  get_color_func,
                           gpointer              data)
1315
{
1316 1317
  g_return_if_fail (GTK_IS_WIDGET (widget));

1318
  gimp_dnd_data_source_add (GIMP_DND_TYPE_COLOR, widget,
Michael Natterer's avatar