]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/dnd.cpp
Menu/toolbar event handling now tries the window with the focus first.
[wxWidgets.git] / src / gtk / dnd.cpp
CommitLineData
c801d85f
KB
1///////////////////////////////////////////////////////////////////////////////
2// Name: dnd.cpp
3// Purpose: wxDropTarget class
4// Author: Robert Roebling
a81258be 5// Id: $Id$
01111366
RR
6// Copyright: (c) 1998 Robert Roebling
7// Licence: wxWindows licence
c801d85f
KB
8///////////////////////////////////////////////////////////////////////////////
9
10#ifdef __GNUG__
11#pragma implementation "dnd.h"
12#endif
13
14#include "wx/dnd.h"
ac57418f 15
06cfab17 16#if wxUSE_DRAG_AND_DROP
ac57418f 17
c801d85f
KB
18#include "wx/window.h"
19#include "wx/app.h"
20#include "wx/gdicmn.h"
b527aac5
RR
21#include "wx/intl.h"
22#include "wx/utils.h"
c801d85f 23
83624f79
RR
24#include "gdk/gdk.h"
25#include "gtk/gtk.h"
c801d85f
KB
26#include "gdk/gdkprivate.h"
27
28#include <X11/Xlib.h>
29
22d5903e
RR
30//----------------------------------------------------------------------------
31// global data
32//----------------------------------------------------------------------------
c801d85f
KB
33
34extern bool g_blockEventsOnDrag;
35
22d5903e
RR
36//----------------------------------------------------------------------------
37// standard icons
38//----------------------------------------------------------------------------
39
40/* XPM */
41static char * gv_xpm[] = {
42"40 34 3 1",
43" s None c None",
44". c black",
45"X c white",
46" ",
47" ",
48" ...... ",
49" ..XXXXXX.. ",
50" .XXXXXXXXXX. ",
51" .XXXXXXXXXXXX. ",
52" .XXXXXXXXXXXX. ",
53" .XXXXXXXXXXXXXX. ",
54" .XXX..XXXX..XXX. ",
55" ....XX....XX....XX. ",
56" .XXX.XXX..XXXX..XXX.... ",
57" .XXXXXXXXXXXXXXXXXXX.XXX. ",
58" .XXXXXXXXXXXXXXXXXXXXXXXX. ",
59" .XXXXXXXXXXXXXXXXXXXXXXXX. ",
60" ..XXXXXXXXXXXXXXXXXXXXXX. ",
61" .XXXXXXXXXXXXXXXXXX... ",
62" ..XXXXXXXXXXXXXXXX. ",
63" .XXXXXXXXXXXXXXXX. ",
64" .XXXXXXXXXXXXXXXX. ",
65" .XXXXXXXXXXXXXXXXX. ",
66" .XXXXXXXXXXXXXXXXX. ",
67" .XXXXXXXXXXXXXXXXXX. ",
68" .XXXXXXXXXXXXXXXXXXX. ",
69" .XXXXXXXXXXXXXXXXXXXXX. ",
70" .XXXXXXXXXXXXXX.XXXXXXX. ",
71" .XXXXXXX.XXXXXXX.XXXXXXX. ",
72" .XXXXXXXX.XXXXXXX.XXXXXXX. ",
73" .XXXXXXX...XXXXX...XXXXX. ",
74" .XXXXXXX. ..... ..... ",
75" ..XXXX.. ",
76" .... ",
77" ",
78" ",
79" "};
80
81/* XPM */
82static char * page_xpm[] = {
83/* width height ncolors chars_per_pixel */
84"32 32 5 1",
85/* colors */
86" s None c None",
87". c black",
88"X c wheat",
89"o c tan",
90"O c #6699FF",
91/* pixels */
92" ................... ",
93" .XXXXXXXXXXXXXXXXX.. ",
94" .XXXXXXXXXXXXXXXXX.o. ",
95" .XXXXXXXXXXXXXXXXX.oo. ",
96" .XXXXXXXXXXXXXXXXX.ooo. ",
97" .XXXXXXXXXXXXXXXXX.oooo. ",
98" .XXXXXXXXXXXXXXXXX....... ",
99" .XXXXXOOOOOOOOOOXXXooooo. ",
100" .XXXXXXXXXXXXXXXXXXooooo. ",
101" .XXXXXOOOOOOOOOOXXXXXXXX. ",
102" .XXXXXXXXXXXXXXXXXXXXXXX. ",
103" .XXXXXXXOOOOOOOOOXXXXXXX. ",
104" .XXXXXXXXXXXXXXXXXXXXXXX. ",
105" .XXXXXXOOOOOOOOOOXXXXXXX. ",
106" .XXXXXXXXXXXXXXXXXXXXXXX. ",
107" .XXXXXOOOOOOOOOOXXXXXXXX. ",
108" .XXXXXXXXXXXXXXXXXXXXXXX. ",
109" .XXXXXXXOOOOOOOOOXXXXXXX. ",
110" .XXXXXXXXXXXXXXXXXXXXXXX. ",
111" .XXXXXXOOOOOOOOOOXXXXXXX. ",
112" .XXXXXXXXXXXXXXXXXXXXXXX. ",
113" .XXXXXOOOOOOOOOOXXXXXXXX. ",
114" .XXXXXXXXXXXXXXXXXXXXXXX. ",
115" .XXXXXXOOOOOOOOOOXXXXXXX. ",
116" .XXXXXXXXXXXXXXXXXXXXXXX. ",
117" .XXXXXOOOOOOOXXXXXXXXXXX. ",
118" .XXXXXXXXXXXXXXXXXXXXXXX. ",
119" .XXXXXXXXXXXXXXXXXXXXXXX. ",
120" .XXXXXXXXXXXXXXXXXXXXXXX. ",
121" .XXXXXXXXXXXXXXXXXXXXXXX. ",
122" .XXXXXXXXXXXXXXXXXXXXXXX. ",
123" ......................... "};
124
125
d6086ea6 126#if (GTK_MINOR_VERSION > 0)
f5368809 127
33a5bc52
RR
128#include "gtk/gtkdnd.h"
129#include "gtk/gtkselection.h"
130
131// ----------------------------------------------------------------------------
132// "drag_leave"
133// ----------------------------------------------------------------------------
134
135static void target_drag_leave( GtkWidget *WXUNUSED(widget),
d6086ea6
RR
136 GdkDragContext *context,
137 guint WXUNUSED(time),
138 wxDropTarget *dt )
33a5bc52 139{
d6086ea6
RR
140 dt->SetDragContext( context );
141 dt->OnLeave();
142 dt->SetDragContext( (GdkDragContext*) NULL );
33a5bc52
RR
143}
144
145// ----------------------------------------------------------------------------
146// "drag_motion"
147// ----------------------------------------------------------------------------
148
149static gboolean target_drag_motion( GtkWidget *WXUNUSED(widget),
150 GdkDragContext *context,
d6086ea6
RR
151 gint x,
152 gint y,
153 guint time,
154 wxDropTarget *dt )
33a5bc52 155{
d6086ea6
RR
156 dt->SetDragContext( context );
157
158 if (dt->OnMove( x, y ))
159 {
160 gdk_drag_status( context, context->suggested_action, time );
161 }
162 else
163 {
164 gdk_drag_status( context, (GdkDragAction)0, time );
165 }
166
167 dt->SetDragContext( (GdkDragContext*) NULL );
33a5bc52
RR
168 return TRUE;
169}
170
171// ----------------------------------------------------------------------------
172// "drag_drop"
173// ----------------------------------------------------------------------------
174
175static gboolean target_drag_drop( GtkWidget *widget,
176 GdkDragContext *context,
177 gint x,
178 gint y,
179 guint time )
180{
181 printf( "drop at: %d,%d.\n", x, y );
182
183 if (context->targets)
184 {
185 gtk_drag_get_data( widget,
186 context,
187 GPOINTER_TO_INT (context->targets->data),
188 time );
189 }
190 return FALSE;
191}
192
193// ----------------------------------------------------------------------------
194// "drag_data_received"
195// ----------------------------------------------------------------------------
196
197static void target_drag_data_received( GtkWidget *WXUNUSED(widget),
198 GdkDragContext *context,
199 gint x,
200 gint y,
201 GtkSelectionData *data,
202 guint WXUNUSED(info),
203 guint time )
204{
205 printf( "data receive at: %d,%d.\n", x, y );
206
207 if ((data->length >= 0) && (data->format == 8))
208 {
ab8884ac
RR
209 wxString str = (const char*)data->data;
210 printf( "Received %s\n.", WXSTRINGCAST str );
211 gtk_drag_finish( context, TRUE, FALSE, time );
212 return;
33a5bc52
RR
213 }
214
215 gtk_drag_finish (context, FALSE, FALSE, time);
216}
217
218// ----------------------------------------------------------------------------
219// wxDropTarget
220// ----------------------------------------------------------------------------
221
f5368809
RR
222wxDropTarget::wxDropTarget()
223{
224}
225
226wxDropTarget::~wxDropTarget()
227{
228}
229
d6086ea6
RR
230void wxDropTarget::OnEnter()
231{
232}
233
234void wxDropTarget::OnLeave()
235{
236}
237
238bool wxDropTarget::OnMove( int x, int y )
239{
22d5903e
RR
240 printf( "generic move %d %d.\n", x, y );
241
d6086ea6
RR
242 return TRUE;
243}
244
245bool wxDropTarget::OnDrop( int x, int y )
246{
22d5903e
RR
247 printf( "generic drop %d %d.\n", x, y );
248
d6086ea6
RR
249 return TRUE;
250}
251
252bool wxDropTarget::IsSupported( wxDataFormat format )
22d5903e
RR
253{
254 printf( "generic is supported.\n" );
255
256 if (!m_dragContext) return FALSE;
257
258 GList *child = m_dragContext->targets;
259 while (child)
260 {
261 GdkAtom formatAtom = (GdkAtom) GPOINTER_TO_INT(child->data);
262 char *name = gdk_atom_name( formatAtom );
263 if (name) printf( "Format available: %s.\n", name );
264
265 child = child->next;
266 }
267
268
d6086ea6
RR
269 return TRUE;
270}
271
272bool wxDropTarget::GetData( wxDataObject *data )
273{
274 return FALSE;
275}
276
f5368809
RR
277void wxDropTarget::UnregisterWidget( GtkWidget *widget )
278{
d6086ea6 279 wxCHECK_RET( widget != NULL, "unregister widget is NULL" );
f5368809 280
d6086ea6 281 gtk_drag_dest_set( widget,
33a5bc52
RR
282 (GtkDestDefaults) 0,
283 (GtkTargetEntry*) NULL,
284 0,
285 (GdkDragAction) 0 );
286
d6086ea6 287 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
33a5bc52
RR
288 GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this );
289
d6086ea6 290 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
33a5bc52
RR
291 GTK_SIGNAL_FUNC(target_drag_motion), (gpointer) this );
292
d6086ea6 293 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
33a5bc52
RR
294 GTK_SIGNAL_FUNC(target_drag_drop), (gpointer) this );
295
d6086ea6 296 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
33a5bc52 297 GTK_SIGNAL_FUNC(target_drag_data_received), (gpointer) this );
f5368809
RR
298}
299
300void wxDropTarget::RegisterWidget( GtkWidget *widget )
301{
d6086ea6 302 wxCHECK_RET( widget != NULL, "register widget is NULL" );
f5368809 303
d6086ea6
RR
304 GtkTargetEntry format;
305 format.info = 0;
306 format.flags = 0;
307 char buf[100];
308 strcpy( buf, "text/plain" );
22d5903e 309 format.target = buf;
f5368809 310
d6086ea6 311 gtk_drag_dest_set( widget,
33a5bc52
RR
312 GTK_DEST_DEFAULT_ALL,
313 &format,
314 1,
315 (GdkDragAction)(GDK_ACTION_COPY | GDK_ACTION_MOVE) );
316
d6086ea6 317 gtk_signal_connect( GTK_OBJECT(widget), "drag_leave",
33a5bc52
RR
318 GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this );
319
d6086ea6 320 gtk_signal_connect( GTK_OBJECT(widget), "drag_motion",
33a5bc52
RR
321 GTK_SIGNAL_FUNC(target_drag_motion), (gpointer) this );
322
d6086ea6 323 gtk_signal_connect( GTK_OBJECT(widget), "drag_drop",
33a5bc52
RR
324 GTK_SIGNAL_FUNC(target_drag_drop), (gpointer) this );
325
d6086ea6 326 gtk_signal_connect( GTK_OBJECT(widget), "drag_data_received",
33a5bc52 327 GTK_SIGNAL_FUNC(target_drag_data_received), (gpointer) this );
f5368809
RR
328}
329
d6086ea6 330//-------------------------------------------------------------------------
f5368809 331// wxTextDropTarget
d6086ea6 332//-------------------------------------------------------------------------
f5368809 333
d6086ea6 334bool wxTextDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
f5368809 335{
22d5903e
RR
336 printf( "text move.\n" );
337
d6086ea6 338 return IsSupported( wxDF_TEXT ); // same as "TEXT"
f5368809
RR
339}
340
d6086ea6 341bool wxTextDropTarget::OnDrop( int x, int y )
f5368809 342{
22d5903e
RR
343 printf( "text drop.\n" );
344
d6086ea6 345 if (!IsSupported( wxDF_TEXT )) return FALSE;
f5368809 346
d6086ea6
RR
347 wxTextDataObject data;
348 if (!GetData( &data )) return FALSE;
f5368809 349
d6086ea6 350 return OnDropText( x, y, data.GetText() );
f5368809
RR
351}
352
353//-------------------------------------------------------------------------
d6086ea6 354// wxPrivateDropTarget
f5368809
RR
355//-------------------------------------------------------------------------
356
d6086ea6 357wxPrivateDropTarget::wxPrivateDropTarget()
f5368809 358{
d6086ea6 359 m_id = wxTheApp->GetAppName();
f5368809
RR
360}
361
d6086ea6 362wxPrivateDropTarget::wxPrivateDropTarget( const wxString &id )
f5368809 363{
d6086ea6 364 m_id = id;
f5368809
RR
365}
366
d6086ea6 367bool wxPrivateDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
f5368809 368{
d6086ea6 369 return IsSupported( m_id );
f5368809
RR
370}
371
d6086ea6 372bool wxPrivateDropTarget::OnDrop( int x, int y )
f5368809 373{
d6086ea6 374 if (!IsSupported( m_id )) return FALSE;
f5368809 375
d6086ea6
RR
376 wxPrivateDataObject data;
377 if (!GetData( &data )) return FALSE;
378
379 return OnDropData( x, y, data.GetData(), data.GetSize() );
f5368809 380}
d6086ea6
RR
381
382//----------------------------------------------------------------------------
383// A drop target which accepts files (dragged from File Manager or Explorer)
384//----------------------------------------------------------------------------
385
386bool wxFileDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
f5368809 387{
d6086ea6 388 return IsSupported( wxDF_FILENAME ); // same as "file:ALL"
f5368809
RR
389}
390
d6086ea6 391bool wxFileDropTarget::OnDrop( int x, int y )
f5368809 392{
d6086ea6
RR
393 if (!IsSupported( wxDF_FILENAME )) return FALSE;
394
395 wxFileDataObject data;
396 if (!GetData( &data )) return FALSE;
397
398 /* get number of substrings /root/mytext.txt/0/root/myothertext.txt/0/0 */
399 size_t number = 0;
400 size_t i;
401 size_t size = data.GetFiles().Length();
402 char *text = WXSTRINGCAST data.GetFiles();
403 for ( i = 0; i < size; i++)
404 if (text[i] == 0) number++;
405
406 if (number == 0) return TRUE;
f5368809 407
d6086ea6 408 char **files = new char*[number];
f5368809 409
d6086ea6
RR
410 text = WXSTRINGCAST data.GetFiles();
411 for (i = 0; i < number; i++)
f5368809 412 {
d6086ea6
RR
413 files[i] = text;
414 int len = strlen( text );
415 text += len+1;
f5368809 416 }
f5368809 417
d6086ea6
RR
418 bool ret = OnDropFiles( x, y, number, files );
419
420 free( files );
f5368809 421
d6086ea6 422 return ret;
f5368809
RR
423}
424
d6086ea6
RR
425//-------------------------------------------------------------------------
426// wxDropSource
427//-------------------------------------------------------------------------
33a5bc52 428
22d5903e
RR
429
430wxDropSource::wxDropSource( wxWindow *win, const wxIcon &go, const wxIcon &stop )
431{
432 g_blockEventsOnDrag = TRUE;
433
434 m_window = win;
435 m_widget = win->m_widget;
436 if (win->m_wxwindow) m_widget = win->m_wxwindow;
437
438 m_data = (wxDataBroker*) NULL;
439 m_retValue = wxDragCancel;
440
441 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
442 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
443
444 m_goIcon = go;
445 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
446 m_stopIcon = stop;
447 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
448}
449
450wxDropSource::wxDropSource( wxDataObject *data, wxWindow *win, const wxIcon &go, const wxIcon &stop )
451{
452 g_blockEventsOnDrag = TRUE;
453
454 m_window = win;
455 m_widget = win->m_widget;
456 if (win->m_wxwindow) m_widget = win->m_wxwindow;
457 m_retValue = wxDragCancel;
458
459 if (data)
460 {
461 m_data = new wxDataBroker();
462 m_data->Add( data );
463 }
464 else
465 {
466 m_data = (wxDataBroker*) NULL;
467 }
468
469 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
470 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
471
472 m_goIcon = go;
473 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
474 m_stopIcon = stop;
475 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
476}
477
478wxDropSource::wxDropSource( wxDataBroker *data, wxWindow *win )
479{
480 g_blockEventsOnDrag = TRUE;
481
482 m_window = win;
483 m_widget = win->m_widget;
484 if (win->m_wxwindow) m_widget = win->m_wxwindow;
485 m_retValue = wxDragCancel;
486
487 m_data = data;
488
489 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
490 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
491}
492
493void wxDropSource::SetData( wxDataObject *data )
494{
495 if (m_data) delete m_data;
496
497 if (data)
498 {
499 m_data = new wxDataBroker();
500 m_data->Add( data );
501 }
502 else
503 {
504 m_data = (wxDataBroker*) NULL;
505 }
506}
507
508void wxDropSource::SetData( wxDataBroker *data )
509{
510 if (m_data) delete m_data;
511
512 m_data = data;
513}
514
515wxDropSource::~wxDropSource(void)
516{
517 if (m_data) delete m_data;
518
519 g_blockEventsOnDrag = FALSE;
520}
521
522wxDragResult wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove) )
523{
524 wxASSERT_MSG( m_data, "wxDragSource: no data" );
525
526 if (!m_data) return (wxDragResult) wxDragNone;
527
528 static GtkWidget *drag_icon = (GtkWidget*) NULL;
529 static GtkWidget *drop_icon = (GtkWidget*) NULL;
530
531 GdkPoint hotspot_1 = {0,-5 };
532
533 if (!drag_icon)
534 {
535/*
536 drag_icon = shape_create_icon ( m_stopIcon,
537 440, 140, 0,0, GTK_WINDOW_POPUP);
538
539 gtk_signal_connect (GTK_OBJECT (drag_icon), "destroy",
540 GTK_SIGNAL_FUNC(gtk_widget_destroyed),
541 &drag_icon);
542
543 gtk_widget_hide (drag_icon);
544*/
545 }
546
547 GdkPoint hotspot_2 = {-5,-5};
548
549 if (!drop_icon)
550 {
551/*
552 drop_icon = shape_create_icon ( m_goIcon,
553 440, 140, 0,0, GTK_WINDOW_POPUP);
554
555 gtk_signal_connect (GTK_OBJECT (drop_icon), "destroy",
556 GTK_SIGNAL_FUNC(gtk_widget_destroyed),
557 &drop_icon);
558
559 gtk_widget_hide (drop_icon);
560*/
561 }
562
563
564 return FALSE;
565}
566
567void wxDropSource::RegisterWindow(void)
568{
569 if (!m_data) return;
570}
571
572void wxDropSource::UnregisterWindow(void)
573{
574 if (!m_widget) return;
575}
576
577
33a5bc52
RR
578#else // NEW_CODE
579
22d5903e
RR
580//----------------------------------------------------------------------------
581// forward
582//----------------------------------------------------------------------------
583
e4677d31 584GtkWidget *shape_create_icon ( const wxIcon &shape,
a802c3a1
RR
585 gint x,
586 gint y,
587 gint px,
588 gint py,
589 gint window_type);
590
b666df2c
RR
591//-----------------------------------------------------------------------------
592// globals
593//-----------------------------------------------------------------------------
594
595wxDropSource *gs_currentDropSource = (wxDropSource*) NULL;
596
597//-----------------------------------------------------------------------------
598// "drop_enter_event"
599//-----------------------------------------------------------------------------
600
601static void gtk_target_enter_callback( GtkWidget *WXUNUSED(widget),
602 GdkEventDropEnter *WXUNUSED(event),
603 wxDropTarget *target )
604{
605 if (target)
606 target->OnEnter();
607}
608
609//-----------------------------------------------------------------------------
610// "drop_leave_event"
611//-----------------------------------------------------------------------------
612
613static void gtk_target_leave_callback( GtkWidget *WXUNUSED(widget),
614 GdkEventDropLeave *WXUNUSED(event),
615 wxDropTarget *target )
616{
617 if (target)
618 target->OnLeave();
619}
620
33a5bc52
RR
621//-----------------------------------------------------------------------------
622// "drop_data_available_event"
623//-----------------------------------------------------------------------------
624
625static void gtk_target_callback( GtkWidget *widget,
626 GdkEventDropDataAvailable *event,
627 wxDropTarget *target )
628{
629 if (target)
630 {
631 int x = 0;
632 int y = 0;
633 gdk_window_get_pointer( widget->window, &x, &y, (GdkModifierType *) NULL );
ab8884ac
RR
634/*
635 printf( "Drop data is of type %s.\n", event->data_type );
636*/
33a5bc52
RR
637 target->OnDrop( x, y, (const void*)event->data, (size_t)event->data_numbytes );
638 }
639
640/*
641 g_free (event->data);
642 g_free (event->data_type);
643*/
644}
f5368809 645
c801d85f
KB
646// ----------------------------------------------------------------------------
647// wxDropTarget
648// ----------------------------------------------------------------------------
649
650wxDropTarget::wxDropTarget()
651{
0d2a2b60 652 m_format = (wxDataFormat*) NULL;
ff7b1510 653}
c801d85f
KB
654
655wxDropTarget::~wxDropTarget()
656{
0d2a2b60
RR
657 if (m_format) delete m_format;
658}
659
660wxDataFormat &wxDropTarget::GetFormat(size_t n) const
661{
662 return (*m_format);
ff7b1510 663}
c801d85f 664
c801d85f
KB
665void wxDropTarget::UnregisterWidget( GtkWidget *widget )
666{
33a5bc52 667 if (!widget) return;
e3e65dac 668
33a5bc52
RR
669 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
670 GTK_SIGNAL_FUNC(gtk_target_callback), (gpointer) this );
671
672 gtk_widget_dnd_drop_set( widget, FALSE, (gchar **) NULL, 0, FALSE );
ff7b1510 673}
c801d85f 674
e3e65dac
RR
675void wxDropTarget::RegisterWidget( GtkWidget *widget )
676{
33a5bc52
RR
677 wxString formats;
678 int valid = 0;
e3e65dac 679
33a5bc52 680 for ( size_t i = 0; i < GetFormatCount(); i++ )
e3e65dac 681 {
0d2a2b60 682 switch (GetFormat(i).GetType())
33a5bc52
RR
683 {
684 case wxDF_TEXT:
ab8884ac
RR
685 {
686 if (i > 0) formats += ";";
687 formats += "text/plain";
688 valid++;
689 break;
690 }
691 case wxDF_FILENAME:
692 {
693 if (i > 0) formats += ";";
694 formats += "file:ALL";
695 valid++;
696 break;
697 }
698 case wxDF_PRIVATE:
699 {
700 if (i > 0) formats += ";";
701 wxPrivateDropTarget *pdt = (wxPrivateDropTarget *)this;
ab8884ac
RR
702 formats += pdt->GetId();
703 valid++;
704 break;
705 }
706 default:
33a5bc52
RR
707 break;
708 }
ff7b1510 709 }
e3e65dac 710
33a5bc52 711 char *str = WXSTRINGCAST formats;
ab8884ac 712
33a5bc52
RR
713 gtk_widget_dnd_drop_set( widget, TRUE, &str, valid, FALSE );
714
715 gtk_signal_connect( GTK_OBJECT(widget), "drop_data_available_event",
716 GTK_SIGNAL_FUNC(gtk_target_callback), (gpointer) this );
b666df2c
RR
717
718 gtk_signal_connect( GTK_OBJECT(widget), "drop_enter_event",
719 GTK_SIGNAL_FUNC(gtk_target_enter_callback), (gpointer) this );
720
721 gtk_signal_connect( GTK_OBJECT(widget), "drop_leave_event",
722 GTK_SIGNAL_FUNC(gtk_target_leave_callback), (gpointer) this );
ff7b1510 723}
e3e65dac 724
c801d85f
KB
725// ----------------------------------------------------------------------------
726// wxTextDropTarget
727// ----------------------------------------------------------------------------
728
0d2a2b60
RR
729wxTextDropTarget::wxTextDropTarget()
730{
731 m_format = new wxDataFormat( wxDF_TEXT );
732}
733
dc86cb34 734bool wxTextDropTarget::OnDrop( long x, long y, const void *data, size_t WXUNUSED(size) )
c801d85f 735{
33a5bc52
RR
736 OnDropText( x, y, (const char*)data );
737 return TRUE;
ff7b1510 738}
c801d85f
KB
739
740bool wxTextDropTarget::OnDropText( long x, long y, const char *psz )
741{
ab8884ac 742/*
33a5bc52
RR
743 printf( "Got dropped text: %s.\n", psz );
744 printf( "At x: %d, y: %d.\n", (int)x, (int)y );
ab8884ac 745*/
33a5bc52 746 return TRUE;
ff7b1510 747}
c801d85f 748
e3e65dac 749size_t wxTextDropTarget::GetFormatCount() const
c801d85f 750{
33a5bc52 751 return 1;
e3e65dac
RR
752}
753
ab8884ac
RR
754// ----------------------------------------------------------------------------
755// wxPrivateDropTarget
756// ----------------------------------------------------------------------------
757
758wxPrivateDropTarget::wxPrivateDropTarget()
759{
760 m_id = wxTheApp->GetAppName();
0d2a2b60 761 m_format = new wxDataFormat( m_id );
ab8884ac
RR
762}
763
0d2a2b60 764void wxPrivateDropTarget::SetId( const wxString& id )
ab8884ac 765{
0d2a2b60
RR
766 m_id = id;
767 m_format->SetId( id );
ab8884ac
RR
768}
769
0d2a2b60 770size_t wxPrivateDropTarget::GetFormatCount() const
ab8884ac 771{
0d2a2b60 772 return 1;
ab8884ac
RR
773}
774
e3e65dac
RR
775// ----------------------------------------------------------------------------
776// wxFileDropTarget
777// ----------------------------------------------------------------------------
778
0d2a2b60
RR
779wxFileDropTarget::wxFileDropTarget()
780{
781 m_format = new wxDataFormat( wxDF_FILENAME );
782}
783
e5403d7c 784bool wxFileDropTarget::OnDropFiles( long x, long y, size_t nFiles, const char * const aszFiles[] )
e3e65dac 785{
33a5bc52
RR
786 printf( "Got %d dropped files.\n", (int)nFiles );
787 printf( "At x: %d, y: %d.\n", (int)x, (int)y );
ab8884ac 788
33a5bc52
RR
789 for (size_t i = 0; i < nFiles; i++)
790 {
791 printf( aszFiles[i] );
792 printf( "\n" );
793 }
ab8884ac 794
33a5bc52 795 return TRUE;
e3e65dac
RR
796}
797
dc86cb34 798bool wxFileDropTarget::OnDrop(long x, long y, const void *data, size_t size )
e3e65dac 799{
33a5bc52 800 size_t number = 0;
4dba84be 801 size_t i;
33a5bc52 802 char *text = (char*) data;
4dba84be 803 for ( i = 0; i < size; i++)
33a5bc52 804 if (text[i] == 0) number++;
e5403d7c 805
33a5bc52 806 if (number == 0) return TRUE;
e5403d7c 807
33a5bc52 808 char **files = new char*[number];
e5403d7c 809
33a5bc52 810 text = (char*) data;
4dba84be 811 for (i = 0; i < number; i++)
33a5bc52
RR
812 {
813 files[i] = text;
814 int len = strlen( text );
815 text += len+1;
816 }
e3e65dac 817
33a5bc52 818 bool ret = OnDropFiles( x, y, 1, files );
e5403d7c 819
33a5bc52 820 free( files );
e5403d7c 821
33a5bc52 822 return ret;
e3e65dac
RR
823}
824
825size_t wxFileDropTarget::GetFormatCount() const
826{
33a5bc52 827 return 1;
e3e65dac
RR
828}
829
c801d85f 830//-------------------------------------------------------------------------
e3e65dac 831// wxDropSource
c801d85f
KB
832//-------------------------------------------------------------------------
833
b527aac5
RR
834static void
835shape_motion (GtkWidget *widget,
b666df2c 836 GdkEventMotion * /*event*/);
b527aac5 837
c801d85f 838//-----------------------------------------------------------------------------
0d2a2b60
RR
839// "drag_request_event"
840//-----------------------------------------------------------------------------
c801d85f 841
0d2a2b60 842void gtk_drag_callback( GtkWidget *widget, GdkEventDragRequest *event, wxDropSource *source )
c801d85f 843{
0d2a2b60
RR
844 wxDataBroker *data = source->m_data;
845
846 if (!data) return;
847
848 wxNode *node = data->m_dataObjects.First();
8b53e5a2 849 {
0d2a2b60
RR
850 wxDataObject *dobj = (wxDataObject*) node->Data();
851
852 if ((strcmp(event->data_type,"file:ALL") == 0) &&
853 (dobj->GetFormat().GetType() == wxDF_FILENAME))
8b53e5a2 854 {
0d2a2b60 855 wxFileDataObject *file_object = (wxFileDataObject*) dobj;
8b53e5a2 856
0d2a2b60 857 wxString text = file_object->GetFiles();
8b53e5a2 858
2830bf19
RR
859 char *s = WXSTRINGCAST text;
860
8b53e5a2 861 gtk_widget_dnd_data_set( widget,
0d2a2b60 862 (GdkEvent*)event,
2830bf19
RR
863 (unsigned char*) s,
864 (int) text.Length()+1 );
8b53e5a2 865
0d2a2b60
RR
866 source->m_retValue = wxDragCopy;
867
868 return;
8b53e5a2
RR
869 }
870
0d2a2b60
RR
871 if ((strcmp(event->data_type,"text/plain") == 0) &&
872 (dobj->GetFormat().GetType() == wxDF_TEXT))
8b53e5a2 873 {
0d2a2b60 874 wxTextDataObject *text_object = (wxTextDataObject*) dobj;
8b53e5a2 875
0d2a2b60 876 wxString text = text_object->GetText();
8b53e5a2 877
2830bf19
RR
878 char *s = WXSTRINGCAST text;
879
8b53e5a2 880 gtk_widget_dnd_data_set( widget,
0d2a2b60 881 (GdkEvent*)event,
2830bf19
RR
882 (unsigned char*) s,
883 (int) text.Length()+1 );
8b53e5a2 884
0d2a2b60
RR
885 source->m_retValue = wxDragCopy;
886
887 return;
8b53e5a2
RR
888 }
889
0d2a2b60 890 if (dobj->GetFormat().GetType() == wxDF_PRIVATE)
8b53e5a2 891 {
0d2a2b60
RR
892 wxPrivateDataObject *pdo = (wxPrivateDataObject*) dobj;
893
894 if (pdo->GetId() == event->data_type)
895 {
896 gtk_widget_dnd_data_set( widget,
897 (GdkEvent*)event,
898 (unsigned char*) pdo->GetData(),
899 (int) pdo->GetSize() );
900
901 source->m_retValue = wxDragCopy;
902
903 return;
904 }
8b53e5a2 905 }
0d2a2b60
RR
906
907 node = node->Next();
8b53e5a2 908 }
ff7b1510 909}
c801d85f 910
e4677d31 911wxDropSource::wxDropSource( wxWindow *win, const wxIcon &go, const wxIcon &stop )
c801d85f 912{
ab8884ac 913 g_blockEventsOnDrag = TRUE;
e3e65dac 914
ab8884ac
RR
915 m_window = win;
916 m_widget = win->m_widget;
917 if (win->m_wxwindow) m_widget = win->m_wxwindow;
c801d85f 918
0d2a2b60 919 m_data = (wxDataBroker*) NULL;
ab8884ac 920 m_retValue = wxDragCancel;
e3e65dac 921
ab8884ac
RR
922 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
923 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
e4677d31
RR
924
925 m_goIcon = go;
926 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
927 m_stopIcon = stop;
928 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
ff7b1510 929}
c801d85f 930
e4677d31 931wxDropSource::wxDropSource( wxDataObject *data, wxWindow *win, const wxIcon &go, const wxIcon &stop )
c801d85f 932{
ab8884ac 933 g_blockEventsOnDrag = TRUE;
e3e65dac 934
ab8884ac
RR
935 m_window = win;
936 m_widget = win->m_widget;
937 if (win->m_wxwindow) m_widget = win->m_wxwindow;
938 m_retValue = wxDragCancel;
e3e65dac 939
0d2a2b60
RR
940 if (data)
941 {
942 m_data = new wxDataBroker();
943 m_data->Add( data );
944 }
945 else
946 {
947 m_data = (wxDataBroker*) NULL;
948 }
e3e65dac 949
ab8884ac
RR
950 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
951 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
e4677d31
RR
952
953 m_goIcon = go;
954 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
955 m_stopIcon = stop;
956 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
ff7b1510 957}
e3e65dac 958
0d2a2b60
RR
959wxDropSource::wxDropSource( wxDataBroker *data, wxWindow *win )
960{
961 g_blockEventsOnDrag = TRUE;
962
963 m_window = win;
964 m_widget = win->m_widget;
965 if (win->m_wxwindow) m_widget = win->m_wxwindow;
966 m_retValue = wxDragCancel;
967
968 m_data = data;
969
970 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
971 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
972}
973
974void wxDropSource::SetData( wxDataObject *data )
975{
976 if (m_data) delete m_data;
977
978 if (data)
979 {
980 m_data = new wxDataBroker();
981 m_data->Add( data );
982 }
983 else
984 {
985 m_data = (wxDataBroker*) NULL;
986 }
987}
988
989void wxDropSource::SetData( wxDataBroker *data )
c801d85f 990{
0d2a2b60
RR
991 if (m_data) delete m_data;
992
993 m_data = data;
ff7b1510 994}
c801d85f 995
e3e65dac 996wxDropSource::~wxDropSource(void)
c801d85f 997{
0d2a2b60 998 if (m_data) delete m_data;
e3e65dac 999
ab8884ac 1000 g_blockEventsOnDrag = FALSE;
ff7b1510 1001}
e3e65dac 1002
46ccb510 1003wxDragResult wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove) )
e3e65dac 1004{
ab8884ac
RR
1005 if (gdk_dnd.dnd_grabbed) return (wxDragResult) wxDragNone;
1006 if (gdk_dnd.drag_really) return (wxDragResult) wxDragNone;
e3e65dac 1007
ab8884ac 1008 wxASSERT_MSG( m_data, "wxDragSource: no data" );
b6af8d80 1009
ab8884ac 1010 if (!m_data) return (wxDragResult) wxDragNone;
c801d85f 1011
ab8884ac
RR
1012 static GtkWidget *drag_icon = (GtkWidget*) NULL;
1013 static GtkWidget *drop_icon = (GtkWidget*) NULL;
a802c3a1 1014
ab8884ac 1015 GdkPoint hotspot_1 = {0,-5 };
a802c3a1 1016
ab8884ac
RR
1017 if (!drag_icon)
1018 {
e4677d31 1019 drag_icon = shape_create_icon ( m_stopIcon,
a802c3a1
RR
1020 440, 140, 0,0, GTK_WINDOW_POPUP);
1021
1022 gtk_signal_connect (GTK_OBJECT (drag_icon), "destroy",
1023 GTK_SIGNAL_FUNC(gtk_widget_destroyed),
1024 &drag_icon);
1025
1026 gtk_widget_hide (drag_icon);
ab8884ac 1027 }
a802c3a1 1028
ab8884ac 1029 GdkPoint hotspot_2 = {-5,-5};
a802c3a1 1030
ab8884ac
RR
1031 if (!drop_icon)
1032 {
e4677d31 1033 drop_icon = shape_create_icon ( m_goIcon,
a802c3a1
RR
1034 440, 140, 0,0, GTK_WINDOW_POPUP);
1035
1036 gtk_signal_connect (GTK_OBJECT (drop_icon), "destroy",
1037 GTK_SIGNAL_FUNC(gtk_widget_destroyed),
1038 &drop_icon);
1039
1040 gtk_widget_hide (drop_icon);
ab8884ac 1041 }
b527aac5 1042
a802c3a1 1043
b527aac5 1044 gdk_dnd_set_drag_shape( drag_icon->window,
a802c3a1
RR
1045 &hotspot_1,
1046 drop_icon->window,
1047 &hotspot_2);
1048
1049
ab8884ac 1050 GdkWindowPrivate *wp = (GdkWindowPrivate*) m_widget->window;
c801d85f 1051
ab8884ac 1052 RegisterWindow();
c801d85f 1053
ab8884ac 1054 gdk_dnd.drag_perhaps = TRUE;
c801d85f 1055
ab8884ac
RR
1056 gdk_dnd.dnd_drag_start.x = 5;
1057 gdk_dnd.dnd_drag_start.y = 5;
1058 gdk_dnd.real_sw = wp;
c801d85f 1059
ab8884ac
RR
1060 if (gdk_dnd.drag_startwindows)
1061 {
1062 g_free( gdk_dnd.drag_startwindows );
1063 gdk_dnd.drag_startwindows = (GdkWindow **) NULL;
1064 }
1065 gdk_dnd.drag_numwindows = gdk_dnd.drag_really = 0;
c801d85f 1066
ab8884ac
RR
1067 XWindowAttributes dnd_winattr;
1068 XGetWindowAttributes( gdk_display, wp->xwindow, &dnd_winattr );
1069 wp->dnd_drag_savedeventmask = dnd_winattr.your_event_mask;
c801d85f 1070
ab8884ac 1071 gdk_dnd_drag_addwindow( m_widget->window );
c801d85f 1072
ab8884ac
RR
1073 GdkEventDragBegin ev;
1074 ev.type = GDK_DRAG_BEGIN;
1075 ev.window = m_widget->window;
1076 ev.u.allflags = 0;
1077 ev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
c801d85f 1078
ab8884ac 1079 gdk_event_put( (GdkEvent*)&ev );
c801d85f 1080
ab8884ac
RR
1081 XGrabPointer( gdk_display, wp->xwindow, False,
1082 ButtonMotionMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
1083 GrabModeAsync, GrabModeAsync, gdk_root_window, None, CurrentTime );
c801d85f 1084
ab8884ac 1085 gdk_dnd_set_drag_cursors( m_defaultCursor.GetCursor(), m_goaheadCursor.GetCursor() );
c801d85f 1086
ab8884ac
RR
1087 gdk_dnd.dnd_grabbed = TRUE;
1088 gdk_dnd.drag_really = 1;
e3e65dac 1089
ab8884ac
RR
1090 int x = 0;
1091 int y = 0;
1092 wxGetMousePosition( &x, &y );
e3e65dac 1093
ab8884ac 1094 gdk_dnd_display_drag_cursor( x, y, FALSE, TRUE );
b666df2c
RR
1095
1096 gs_currentDropSource = this;
1097
ab8884ac 1098 while (gdk_dnd.drag_really || gdk_dnd.drag_perhaps) wxYield();
b666df2c
RR
1099
1100 gs_currentDropSource = (wxDropSource*) NULL;
c801d85f 1101
ab8884ac 1102 UnregisterWindow();
e3e65dac 1103
ab8884ac 1104 g_blockEventsOnDrag = FALSE;
30dea054 1105
ab8884ac 1106 return m_retValue;
ff7b1510 1107}
c801d85f 1108
e3e65dac 1109void wxDropSource::RegisterWindow(void)
c801d85f 1110{
ab8884ac 1111 if (!m_data) return;
c801d85f 1112
ab8884ac 1113 wxString formats;
e3e65dac 1114
0d2a2b60
RR
1115 wxNode *node = m_data->m_dataObjects.First();
1116 while (node)
e3e65dac 1117 {
0d2a2b60
RR
1118 wxDataObject* dobj = (wxDataObject*) node->Data();
1119
1120 switch (dobj->GetFormat().GetType())
1121 {
1122 case wxDF_TEXT:
1123 {
1124 formats += "text/plain";
1125 break;
1126 }
1127 case wxDF_FILENAME:
1128 {
1129 formats += "file:ALL";
1130 break;
1131 }
1132 case wxDF_PRIVATE:
1133 {
1134 wxPrivateDataObject* pdo = (wxPrivateDataObject*) m_data;
1135 formats += pdo->GetId();
1136 break;
1137 }
1138 default:
1139 break;
ab8884ac 1140 }
0d2a2b60 1141 node = node->Next();
e3e65dac 1142 }
c801d85f 1143
ab8884ac 1144 char *str = WXSTRINGCAST formats;
c801d85f 1145
ab8884ac 1146 gtk_widget_dnd_drag_set( m_widget, TRUE, &str, 1 );
c801d85f 1147
ab8884ac
RR
1148 gtk_signal_connect( GTK_OBJECT(m_widget), "drag_request_event",
1149 GTK_SIGNAL_FUNC(gtk_drag_callback), (gpointer)this );
ff7b1510 1150}
c801d85f 1151
e3e65dac 1152void wxDropSource::UnregisterWindow(void)
c801d85f 1153{
ab8884ac 1154 if (!m_widget) return;
c801d85f 1155
ab8884ac 1156 gtk_widget_dnd_drag_set( m_widget, FALSE, (gchar **) NULL, 0 );
e3e65dac 1157
ab8884ac 1158 gtk_signal_disconnect_by_data( GTK_OBJECT(m_widget), (gpointer)this );
ff7b1510 1159}
f5368809 1160
a802c3a1
RR
1161
1162/*
1163 * Shaped Windows
1164 */
bbe0af5b 1165static GdkWindow *root_win = (GdkWindow*) NULL;
a802c3a1
RR
1166
1167typedef struct _cursoroffset {gint x,y;} CursorOffset;
1168
1169static void
1170shape_pressed (GtkWidget *widget, GdkEventButton *event)
1171{
1172 CursorOffset *p;
1173
1174 /* ignore double and triple click */
1175 if (event->type != GDK_BUTTON_PRESS)
1176 return;
1177
b527aac5 1178 p = (CursorOffset *)gtk_object_get_user_data (GTK_OBJECT(widget));
a802c3a1
RR
1179 p->x = (int) event->x;
1180 p->y = (int) event->y;
1181
1182 gtk_grab_add (widget);
1183 gdk_pointer_grab (widget->window, TRUE,
b527aac5
RR
1184 (GdkEventMask)
1185 (GDK_BUTTON_RELEASE_MASK |
1186 GDK_BUTTON_MOTION_MASK |
1187 GDK_POINTER_MOTION_HINT_MASK),
bbe0af5b
RR
1188 (GdkWindow*)NULL,
1189 (GdkCursor*) NULL, 0);
a802c3a1
RR
1190}
1191
1192
1193static void
1194shape_released (GtkWidget *widget)
1195{
1196 gtk_grab_remove (widget);
1197 gdk_pointer_ungrab (0);
1198}
1199
1200static void
1201shape_motion (GtkWidget *widget,
b666df2c 1202 GdkEventMotion * /*event*/ )
a802c3a1
RR
1203{
1204 gint xp, yp;
1205 CursorOffset * p;
1206 GdkModifierType mask;
1207
b527aac5 1208 p = (CursorOffset *)gtk_object_get_user_data (GTK_OBJECT (widget));
a802c3a1
RR
1209
1210 /*
1211 * Can't use event->x / event->y here
1212 * because I need absolute coordinates.
1213 */
b666df2c 1214
a802c3a1
RR
1215 gdk_window_get_pointer (root_win, &xp, &yp, &mask);
1216 gtk_widget_set_uposition (widget, xp - p->x, yp - p->y);
b666df2c
RR
1217
1218 if (gs_currentDropSource) gs_currentDropSource->GiveFeedback( wxDragCopy, FALSE );
a802c3a1
RR
1219}
1220
1221GtkWidget *
e4677d31 1222shape_create_icon (const wxIcon &shape,
a802c3a1
RR
1223 gint x,
1224 gint y,
1225 gint px,
1226 gint py,
1227 gint window_type)
1228{
a802c3a1
RR
1229 /*
1230 * GDK_WINDOW_TOPLEVEL works also, giving you a title border
1231 */
e4677d31 1232 GtkWidget *window = gtk_window_new ((GtkWindowType)window_type);
a802c3a1 1233
e4677d31 1234 GtkWidget *fixed = gtk_fixed_new ();
a802c3a1
RR
1235 gtk_widget_set_usize (fixed, 100,100);
1236 gtk_container_add (GTK_CONTAINER (window), fixed);
1237 gtk_widget_show (fixed);
1238
1239 gtk_widget_set_events (window,
1240 gtk_widget_get_events (window) |
1241 GDK_BUTTON_MOTION_MASK |
1242 GDK_POINTER_MOTION_HINT_MASK |
1243 GDK_BUTTON_PRESS_MASK);
1244
1245 gtk_widget_realize (window);
1246
e4677d31
RR
1247 GdkBitmap *mask = (GdkBitmap*) NULL;
1248 if (shape.GetMask()) mask = shape.GetMask()->GetBitmap();
a802c3a1 1249
e4677d31 1250 GtkWidget *pixmap = gtk_pixmap_new (shape.GetPixmap(), mask);
a802c3a1
RR
1251 gtk_fixed_put (GTK_FIXED (fixed), pixmap, px,py);
1252 gtk_widget_show (pixmap);
1253
e4677d31 1254 gtk_widget_shape_combine_mask (window, mask, px,py);
a802c3a1
RR
1255
1256
1257 gtk_signal_connect (GTK_OBJECT (window), "button_press_event",
1258 GTK_SIGNAL_FUNC (shape_pressed),NULL);
1259 gtk_signal_connect (GTK_OBJECT (window), "button_release_event",
1260 GTK_SIGNAL_FUNC (shape_released),NULL);
1261 gtk_signal_connect (GTK_OBJECT (window), "motion_notify_event",
1262 GTK_SIGNAL_FUNC (shape_motion),NULL);
1263
e4677d31 1264 CursorOffset*icon_pos = g_new (CursorOffset, 1);
a802c3a1
RR
1265 gtk_object_set_user_data(GTK_OBJECT(window), icon_pos);
1266
1267 gtk_widget_set_uposition (window, x, y);
1268 gtk_widget_show (window);
1269
1270 return window;
1271}
1272
f5368809
RR
1273#endif
1274 // NEW_GTK_DND_CODE
1275
ac57418f
RR
1276#endif
1277
1278 // wxUSE_DRAG_AND_DROP