minor change: disable debug messages flood from OnDragOver
[wxWidgets.git] / src / gtk1 / dnd.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: dnd.cpp
3 // Purpose: wxDropTarget class
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __GNUG__
11 #pragma implementation "dnd.h"
12 #endif
13
14 #include "wx/dnd.h"
15
16 #if wxUSE_DRAG_AND_DROP
17
18 #include "wx/window.h"
19 #include "wx/app.h"
20 #include "wx/gdicmn.h"
21 #include "wx/intl.h"
22 #include "wx/utils.h"
23
24 #include "gdk/gdk.h"
25 #include "gtk/gtk.h"
26 #include "gdk/gdkprivate.h"
27
28 #include "gtk/gtkdnd.h"
29 #include "gtk/gtkselection.h"
30
31 //-----------------------------------------------------------------------------
32 // idle system
33 //-----------------------------------------------------------------------------
34
35 extern void wxapp_install_idle_handler();
36 extern bool g_isIdle;
37
38 //-----------------------------------------------------------------------------
39 // thread system
40 //-----------------------------------------------------------------------------
41
42 #if wxUSE_THREADS
43 extern void wxapp_install_thread_wakeup();
44 extern void wxapp_uninstall_thread_wakeup();
45 #endif
46
47 //----------------------------------------------------------------------------
48 // global data
49 //----------------------------------------------------------------------------
50
51 extern bool g_blockEventsOnDrag;
52
53 //----------------------------------------------------------------------------
54 // standard icons
55 //----------------------------------------------------------------------------
56
57 /* XPM */
58 static char * gv_xpm[] = {
59 "40 34 3 1",
60 " s None c None",
61 ". c black",
62 "X c white",
63 " ",
64 " ",
65 " ...... ",
66 " ..XXXXXX.. ",
67 " .XXXXXXXXXX. ",
68 " .XXXXXXXXXXXX. ",
69 " .XXXXXXXXXXXX. ",
70 " .XXXXXXXXXXXXXX. ",
71 " .XXX..XXXX..XXX. ",
72 " ....XX....XX....XX. ",
73 " .XXX.XXX..XXXX..XXX.... ",
74 " .XXXXXXXXXXXXXXXXXXX.XXX. ",
75 " .XXXXXXXXXXXXXXXXXXXXXXXX. ",
76 " .XXXXXXXXXXXXXXXXXXXXXXXX. ",
77 " ..XXXXXXXXXXXXXXXXXXXXXX. ",
78 " .XXXXXXXXXXXXXXXXXX... ",
79 " ..XXXXXXXXXXXXXXXX. ",
80 " .XXXXXXXXXXXXXXXX. ",
81 " .XXXXXXXXXXXXXXXX. ",
82 " .XXXXXXXXXXXXXXXXX. ",
83 " .XXXXXXXXXXXXXXXXX. ",
84 " .XXXXXXXXXXXXXXXXXX. ",
85 " .XXXXXXXXXXXXXXXXXXX. ",
86 " .XXXXXXXXXXXXXXXXXXXXX. ",
87 " .XXXXXXXXXXXXXX.XXXXXXX. ",
88 " .XXXXXXX.XXXXXXX.XXXXXXX. ",
89 " .XXXXXXXX.XXXXXXX.XXXXXXX. ",
90 " .XXXXXXX...XXXXX...XXXXX. ",
91 " .XXXXXXX. ..... ..... ",
92 " ..XXXX.. ",
93 " .... ",
94 " ",
95 " ",
96 " "};
97
98 /* XPM */
99 static char * page_xpm[] = {
100 /* width height ncolors chars_per_pixel */
101 "32 32 5 1",
102 /* colors */
103 " s None c None",
104 ". c black",
105 "X c wheat",
106 "o c tan",
107 "O c #6699FF",
108 /* pixels */
109 " ................... ",
110 " .XXXXXXXXXXXXXXXXX.. ",
111 " .XXXXXXXXXXXXXXXXX.o. ",
112 " .XXXXXXXXXXXXXXXXX.oo. ",
113 " .XXXXXXXXXXXXXXXXX.ooo. ",
114 " .XXXXXXXXXXXXXXXXX.oooo. ",
115 " .XXXXXXXXXXXXXXXXX....... ",
116 " .XXXXXOOOOOOOOOOXXXooooo. ",
117 " .XXXXXXXXXXXXXXXXXXooooo. ",
118 " .XXXXXOOOOOOOOOOXXXXXXXX. ",
119 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
120 " .XXXXXXXOOOOOOOOOXXXXXXX. ",
121 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
122 " .XXXXXXOOOOOOOOOOXXXXXXX. ",
123 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
124 " .XXXXXOOOOOOOOOOXXXXXXXX. ",
125 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
126 " .XXXXXXXOOOOOOOOOXXXXXXX. ",
127 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
128 " .XXXXXXOOOOOOOOOOXXXXXXX. ",
129 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
130 " .XXXXXOOOOOOOOOOXXXXXXXX. ",
131 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
132 " .XXXXXXOOOOOOOOOOXXXXXXX. ",
133 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
134 " .XXXXXOOOOOOOXXXXXXXXXXX. ",
135 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
136 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
137 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
138 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
139 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
140 " ......................... "};
141
142
143
144 // ----------------------------------------------------------------------------
145 // "drag_leave"
146 // ----------------------------------------------------------------------------
147
148 static void target_drag_leave( GtkWidget *WXUNUSED(widget),
149 GdkDragContext *context,
150 guint WXUNUSED(time),
151 wxDropTarget *drop_target )
152 {
153 if (g_isIdle) wxapp_install_idle_handler();
154
155 /* inform the wxDropTarget about the current GdkDragContext.
156 this is only valid for the duration of this call */
157 drop_target->SetDragContext( context );
158
159 /* we don't need return values. this event is just for
160 information */
161 drop_target->OnLeave();
162
163 /* this has to be done because GDK has no "drag_enter" event */
164 drop_target->m_firstMotion = TRUE;
165
166 /* after this, invalidate the drop_target's GdkDragContext */
167 drop_target->SetDragContext( (GdkDragContext*) NULL );
168 }
169
170 // ----------------------------------------------------------------------------
171 // "drag_motion"
172 // ----------------------------------------------------------------------------
173
174 static gboolean target_drag_motion( GtkWidget *WXUNUSED(widget),
175 GdkDragContext *context,
176 gint x,
177 gint y,
178 guint time,
179 wxDropTarget *drop_target )
180 {
181 if (g_isIdle) wxapp_install_idle_handler();
182
183 /* Owen Taylor: "if the coordinates not in a drop zone,
184 return FALSE, otherwise call gtk_drag_status() and
185 return TRUE" */
186
187 /* inform the wxDropTarget about the current GdkDragContext.
188 this is only valid for the duration of this call */
189 drop_target->SetDragContext( context );
190
191 /* TODO: what should be the default behaviour? Copy or move? */
192 wxDragResult result = wxDragMove;
193
194 if (drop_target->m_firstMotion)
195 {
196 /* the first "drag_motion" event substitutes a "drag_enter" event */
197 result = drop_target->OnEnter( x, y, result );
198 }
199 else
200 {
201 /* give program a chance to react (i.e. to say no by returning FALSE) */
202 result = drop_target->OnDragOver( x, y, result );
203 }
204
205 /* we don't yet handle which "actions" (i.e. copy or move)
206 the target accepts. so far we simply accept the
207 suggested action. TODO. */
208 bool ret = result != wxDragNone;
209 if (ret)
210 gdk_drag_status( context, context->suggested_action, time );
211
212 /* after this, invalidate the drop_target's GdkDragContext */
213 drop_target->SetDragContext( (GdkDragContext*) NULL );
214
215 /* this has to be done because GDK has no "drag_enter" event */
216 drop_target->m_firstMotion = FALSE;
217
218 return ret;
219 }
220
221 // ----------------------------------------------------------------------------
222 // "drag_drop"
223 // ----------------------------------------------------------------------------
224
225 static gboolean target_drag_drop( GtkWidget *widget,
226 GdkDragContext *context,
227 gint x,
228 gint y,
229 guint time,
230 wxDropTarget *drop_target )
231 {
232 if (g_isIdle) wxapp_install_idle_handler();
233
234 /* Owen Taylor: "if the drop is not in a drop zone,
235 return FALSE, otherwise, if you aren't accepting
236 the drop, call gtk_drag_finish() with success == FALSE
237 otherwise call gtk_drag_data_get()" */
238
239 // printf( "drop.\n" );
240
241 /* this seems to make a difference between not accepting
242 due to wrong target area and due to wrong format. let
243 us hope that this is not required.. */
244
245 /* inform the wxDropTarget about the current GdkDragContext.
246 this is only valid for the duration of this call */
247 drop_target->SetDragContext( context );
248
249 /* inform the wxDropTarget about the current drag widget.
250 this is only valid for the duration of this call */
251 drop_target->SetDragWidget( widget );
252
253 /* inform the wxDropTarget about the current drag time.
254 this is only valid for the duration of this call */
255 drop_target->SetDragTime( time );
256
257 bool ret = drop_target->OnDrop( x, y );
258
259 if (!ret)
260 {
261 wxLogDebug( wxT( "Drop target: OnDrop returned TRUE") );
262
263 /* cancel the whole thing */
264 gtk_drag_finish( context,
265 FALSE, /* no success */
266 FALSE, /* don't delete data on dropping side */
267 time );
268 }
269 else
270 {
271 wxLogDebug( wxT( "Drop target: OnDrop returned TRUE") );
272
273 #if wxUSE_THREADS
274 /* disable GUI threads */
275 wxapp_uninstall_thread_wakeup();
276 #endif
277
278 GdkAtom format = drop_target->GetMatchingPair();
279 wxASSERT( format );
280
281 /* this should trigger an "drag_data_received" event */
282 gtk_drag_get_data( widget,
283 context,
284 format,
285 time );
286
287 #if wxUSE_THREADS
288 /* re-enable GUI threads */
289 wxapp_install_thread_wakeup();
290 #endif
291 }
292
293 /* after this, invalidate the drop_target's GdkDragContext */
294 drop_target->SetDragContext( (GdkDragContext*) NULL );
295
296 /* after this, invalidate the drop_target's drag widget */
297 drop_target->SetDragWidget( (GtkWidget*) NULL );
298
299 /* this has to be done because GDK has no "drag_enter" event */
300 drop_target->m_firstMotion = TRUE;
301
302 return ret;
303 }
304
305 // ----------------------------------------------------------------------------
306 // "drag_data_received"
307 // ----------------------------------------------------------------------------
308
309 static void target_drag_data_received( GtkWidget *WXUNUSED(widget),
310 GdkDragContext *context,
311 gint x,
312 gint y,
313 GtkSelectionData *data,
314 guint WXUNUSED(info),
315 guint time,
316 wxDropTarget *drop_target )
317 {
318 if (g_isIdle) wxapp_install_idle_handler();
319
320 /* Owen Taylor: "call gtk_drag_finish() with
321 success == TRUE" */
322
323
324 if ((data->length <= 0) || (data->format != 8))
325 {
326 /* negative data length and non 8-bit data format
327 qualifies for junk */
328 gtk_drag_finish (context, FALSE, FALSE, time);
329
330 return;
331 }
332
333 wxLogDebug( wxT( "Drop target: data received event") );
334
335 /* inform the wxDropTarget about the current GtkSelectionData.
336 this is only valid for the duration of this call */
337 drop_target->SetDragData( data );
338
339 if (drop_target->OnData( x, y ))
340 {
341 wxLogDebug( wxT( "Drop target: OnData returned TRUE") );
342
343 /* tell GTK that data transfer was successfull */
344 gtk_drag_finish( context, TRUE, FALSE, time );
345 }
346 else
347 {
348 wxLogDebug( wxT( "Drop target: OnData returned FALSE") );
349
350 /* tell GTK that data transfer was not successfull */
351 gtk_drag_finish( context, FALSE, FALSE, time );
352 }
353
354 /* after this, invalidate the drop_target's drag data */
355 drop_target->SetDragData( (GtkSelectionData*) NULL );
356 }
357
358 //----------------------------------------------------------------------------
359 // wxDropTarget
360 //----------------------------------------------------------------------------
361
362 wxDropTarget::wxDropTarget( wxDataObject *data )
363 : wxDropTargetBase( data )
364 {
365 m_firstMotion = TRUE;
366 m_dragContext = (GdkDragContext*) NULL;
367 m_dragWidget = (GtkWidget*) NULL;
368 m_dragData = (GtkSelectionData*) NULL;
369 m_dragTime = 0;
370 }
371
372 wxDragResult wxDropTarget::OnDragOver( wxCoord WXUNUSED(x),
373 wxCoord WXUNUSED(y),
374 wxDragResult def )
375 {
376 // GetMatchingPair() checks for m_dataObject too, no need to do it here
377
378 // disable the debug message from GetMatchingPair() - there are too many
379 // of them otherwise
380 #ifdef __WXDEBUG__
381 wxLogNull noLog;
382 #endif // Debug
383
384 return (GetMatchingPair() != (GdkAtom) 0) ? def : wxDragNone;
385 }
386
387 bool wxDropTarget::OnDrop( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y) )
388 {
389 if (!m_dataObject)
390 return FALSE;
391
392 return (GetMatchingPair() != (GdkAtom) 0);
393 }
394
395 bool wxDropTarget::OnData( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y) )
396 {
397 if (!m_dataObject)
398 return FALSE;
399
400 if (GetMatchingPair() == (GdkAtom) 0)
401 return FALSE;
402
403 return GetData();
404 }
405
406 GdkAtom wxDropTarget::GetMatchingPair()
407 {
408 if (!m_dataObject)
409 return (GdkAtom) 0;
410
411 if (!m_dragContext)
412 return (GdkAtom) 0;
413
414 GList *child = m_dragContext->targets;
415 while (child)
416 {
417 GdkAtom formatAtom = (GdkAtom) GPOINTER_TO_INT(child->data);
418 wxDataFormat format( formatAtom );
419
420 #ifdef __WXDEBUG__
421 char *name = gdk_atom_name( formatAtom );
422 wxLogDebug("Drop target: drag has format: %s", name ? name : "unnamed");
423 #endif // Debug
424
425 if (m_dataObject->IsSupportedFormat( format ))
426 return formatAtom;
427
428 child = child->next;
429 }
430
431 return (GdkAtom) 0;
432 }
433
434 bool wxDropTarget::GetData()
435 {
436 if (!m_dragData)
437 return FALSE;
438
439 if (!m_dataObject)
440 return FALSE;
441
442 wxDataFormat dragFormat( m_dragData->target );
443
444 if (!m_dataObject->IsSupportedFormat( dragFormat ))
445 return FALSE;
446
447 if (dragFormat.GetType() == wxDF_TEXT)
448 {
449 wxTextDataObject *text_object = (wxTextDataObject*)m_dataObject;
450 text_object->SetText( (const char*)m_dragData->data );
451 return TRUE;
452 }
453
454 if (dragFormat.GetType() == wxDF_FILENAME)
455 {
456 wxFileDataObject *file_object = (wxFileDataObject*)m_dataObject;
457 file_object->SetData( 0, (const char*)m_dragData->data );
458 return TRUE;
459 }
460
461 m_dataObject->SetData( dragFormat, (size_t)m_dragData->length, (const void*)m_dragData->data );
462
463 return TRUE;
464 }
465
466 void wxDropTarget::UnregisterWidget( GtkWidget *widget )
467 {
468 wxCHECK_RET( widget != NULL, wxT("unregister widget is NULL") );
469
470 gtk_drag_dest_unset( widget );
471
472 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
473 GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this );
474
475 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
476 GTK_SIGNAL_FUNC(target_drag_motion), (gpointer) this );
477
478 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
479 GTK_SIGNAL_FUNC(target_drag_drop), (gpointer) this );
480
481 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
482 GTK_SIGNAL_FUNC(target_drag_data_received), (gpointer) this );
483 }
484
485 void wxDropTarget::RegisterWidget( GtkWidget *widget )
486 {
487 wxCHECK_RET( widget != NULL, wxT("register widget is NULL") );
488
489 /* gtk_drag_dest_set() determines what default behaviour we'd like
490 GTK to supply. we don't want to specify out targets (=formats)
491 or actions in advance (i.e. not GTK_DEST_DEFAULT_MOTION and
492 not GTK_DEST_DEFAULT_DROP). instead we react individually to
493 "drag_motion" and "drag_drop" events. this makes it possible
494 to allow dropping on only a small area. we should set
495 GTK_DEST_DEFAULT_HIGHLIGHT as this will switch on the nice
496 highlighting if dragging over standard controls, but this
497 seems to be broken without the other two. */
498
499 gtk_drag_dest_set( widget,
500 (GtkDestDefaults) 0, /* no default behaviour */
501 (GtkTargetEntry*) NULL, /* we don't supply any formats here */
502 0, /* number of targets = 0 */
503 (GdkDragAction) 0 ); /* we don't supply any actions here */
504
505 gtk_signal_connect( GTK_OBJECT(widget), "drag_leave",
506 GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this );
507
508 gtk_signal_connect( GTK_OBJECT(widget), "drag_motion",
509 GTK_SIGNAL_FUNC(target_drag_motion), (gpointer) this );
510
511 gtk_signal_connect( GTK_OBJECT(widget), "drag_drop",
512 GTK_SIGNAL_FUNC(target_drag_drop), (gpointer) this );
513
514 gtk_signal_connect( GTK_OBJECT(widget), "drag_data_received",
515 GTK_SIGNAL_FUNC(target_drag_data_received), (gpointer) this );
516 }
517
518 // ----------------------------------------------------------------------------
519 // wxTextDropTarget
520 // ----------------------------------------------------------------------------
521
522 wxTextDropTarget::wxTextDropTarget()
523 : wxDropTarget(new wxTextDataObject)
524 {
525 }
526
527 bool wxTextDropTarget::OnData(wxCoord x, wxCoord y)
528 {
529 if ( !GetData() )
530 return FALSE;
531
532 return OnDropText(x, y, ((wxTextDataObject *)m_dataObject)->GetText());
533 }
534
535 // ----------------------------------------------------------------------------
536 // wxFileDropTarget
537 // ----------------------------------------------------------------------------
538
539 wxFileDropTarget::wxFileDropTarget()
540 : wxDropTarget(new wxFileDataObject)
541 {
542 }
543
544 bool wxFileDropTarget::OnData(wxCoord x, wxCoord y)
545 {
546 if ( !GetData() )
547 return FALSE;
548
549 return OnDropFiles(x, y,
550 ((wxFileDataObject *)m_dataObject)->GetFilenames());
551 }
552
553 //----------------------------------------------------------------------------
554 // "drag_data_get"
555 //----------------------------------------------------------------------------
556
557 static void
558 source_drag_data_get (GtkWidget *WXUNUSED(widget),
559 GdkDragContext *context,
560 GtkSelectionData *selection_data,
561 guint WXUNUSED(info),
562 guint WXUNUSED(time),
563 wxDropSource *drop_source )
564 {
565 if (g_isIdle) wxapp_install_idle_handler();
566
567 wxDataFormat format( selection_data->target );
568
569 wxLogDebug( wxT("Drop source: format requested: %s"), format.GetId().c_str() );
570
571 drop_source->m_retValue = wxDragCancel;
572
573 wxDataObject *data = drop_source->GetDataObject();
574
575 if (!data)
576 {
577 wxLogDebug( wxT("Drop source: no data object") );
578 return;
579 }
580
581 if (!data->IsSupportedFormat(format))
582 {
583 wxLogDebug( wxT("Drop source: unsupported format") );
584 return;
585 }
586
587 if (data->GetDataSize(format) == 0)
588 {
589 wxLogDebug( wxT("Drop source: empty data") );
590 return;
591 }
592
593 size_t size = data->GetDataSize(format);
594
595 // printf( "data size: %d.\n", (int)data_size );
596
597 guchar *d = new guchar[size];
598
599 if (!data->GetDataHere( format, (void*)d ))
600 {
601 delete[] d;
602 return;
603 }
604
605 #if wxUSE_THREADS
606 /* disable GUI threads */
607 wxapp_uninstall_thread_wakeup();
608 #endif
609
610 gtk_selection_data_set( selection_data,
611 selection_data->target,
612 8, // 8-bit
613 d,
614 size );
615
616 #if wxUSE_THREADS
617 /* enable GUI threads */
618 wxapp_install_thread_wakeup();
619 #endif
620
621 delete[] d;
622
623 /* so far only copy, no moves. TODO. */
624 drop_source->m_retValue = wxDragCopy;
625 }
626
627 //----------------------------------------------------------------------------
628 // "drag_data_delete"
629 //----------------------------------------------------------------------------
630
631 static void source_drag_data_delete( GtkWidget *WXUNUSED(widget),
632 GdkDragContext *WXUNUSED(context),
633 wxDropSource *drop_source )
634 {
635 if (g_isIdle) wxapp_install_idle_handler();
636
637 // printf( "Delete the data!\n" );
638
639 drop_source->m_retValue = wxDragMove;
640 }
641
642 //----------------------------------------------------------------------------
643 // "drag_begin"
644 //----------------------------------------------------------------------------
645
646 static void source_drag_begin( GtkWidget *WXUNUSED(widget),
647 GdkDragContext *WXUNUSED(context),
648 wxDropSource *WXUNUSED(drop_source) )
649 {
650 if (g_isIdle) wxapp_install_idle_handler();
651
652 // printf( "drag_begin.\n" );
653 }
654
655 //----------------------------------------------------------------------------
656 // "drag_end"
657 //----------------------------------------------------------------------------
658
659 static void source_drag_end( GtkWidget *WXUNUSED(widget),
660 GdkDragContext *WXUNUSED(context),
661 wxDropSource *drop_source )
662 {
663 if (g_isIdle) wxapp_install_idle_handler();
664
665 // printf( "drag_end.\n" );
666
667 drop_source->m_waiting = FALSE;
668 }
669
670 //---------------------------------------------------------------------------
671 // wxDropSource
672 //---------------------------------------------------------------------------
673
674 wxDropSource::wxDropSource( wxWindow *win, const wxIcon &go, const wxIcon &stop )
675 {
676 g_blockEventsOnDrag = TRUE;
677 m_waiting = TRUE;
678
679 m_window = win;
680 m_widget = win->m_widget;
681 if (win->m_wxwindow) m_widget = win->m_wxwindow;
682
683 m_retValue = wxDragCancel;
684
685 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
686 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
687
688 m_goIcon = go;
689 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
690 m_stopIcon = stop;
691 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
692 }
693
694 wxDropSource::wxDropSource( wxDataObject& data, wxWindow *win,
695 const wxIcon &go, const wxIcon &stop )
696 {
697 m_waiting = TRUE;
698
699 SetData( data );
700
701 m_window = win;
702 m_widget = win->m_widget;
703 if (win->m_wxwindow) m_widget = win->m_wxwindow;
704 m_retValue = wxDragCancel;
705
706 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
707 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
708
709 m_goIcon = go;
710 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
711 m_stopIcon = stop;
712 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
713 }
714
715 wxDropSource::~wxDropSource()
716 {
717 g_blockEventsOnDrag = FALSE;
718 }
719
720 wxDragResult wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove) )
721 {
722 wxASSERT_MSG( m_data, wxT("wxDragSource: no data") );
723
724 if (!m_data)
725 return (wxDragResult) wxDragNone;
726
727 if (m_data->GetFormatCount() == 0)
728 return (wxDragResult) wxDragNone;
729
730 g_blockEventsOnDrag = TRUE;
731
732 RegisterWindow();
733
734 m_waiting = TRUE;
735
736 GtkTargetList *target_list = gtk_target_list_new( (GtkTargetEntry*) NULL, 0 );
737
738 wxDataFormat *array = new wxDataFormat[ m_data->GetFormatCount() ];
739 m_data->GetAllFormats( array );
740 for (size_t i = 0; i < m_data->GetFormatCount(); i++)
741 {
742 GdkAtom atom = array[i];
743 wxLogDebug( wxT("Supported atom %s"), gdk_atom_name( atom ) );
744 gtk_target_list_add( target_list, atom, 0, 0 );
745 }
746 delete[] array;
747
748 GdkEventMotion event;
749 event.window = m_widget->window;
750 int x = 0;
751 int y = 0;
752 GdkModifierType state;
753 gdk_window_get_pointer( event.window, &x, &y, &state );
754 event.x = x;
755 event.y = y;
756 event.state = state;
757 event.time = GDK_CURRENT_TIME;
758
759 /* GTK wants to know which button was pressed which caused the dragging */
760 int button_number = 0;
761 if (event.state & GDK_BUTTON1_MASK) button_number = 1;
762 else if (event.state & GDK_BUTTON2_MASK) button_number = 2;
763 else if (event.state & GDK_BUTTON3_MASK) button_number = 3;
764
765 #if wxUSE_THREADS
766 /* disable GUI threads */
767 wxapp_uninstall_thread_wakeup();
768 #endif
769
770 /* don't start dragging if no button is down */
771 if (button_number)
772 {
773 GdkDragContext *context = gtk_drag_begin( m_widget,
774 target_list,
775 GDK_ACTION_COPY,
776 button_number, /* number of mouse button which started drag */
777 (GdkEvent*) &event );
778
779 wxMask *mask = m_goIcon.GetMask();
780 GdkBitmap *bm = (GdkBitmap *) NULL;
781 if (mask) bm = mask->GetBitmap();
782 GdkPixmap *pm = m_goIcon.GetPixmap();
783
784 gtk_drag_set_icon_pixmap( context,
785 gtk_widget_get_colormap( m_widget ),
786 pm,
787 bm,
788 0,
789 0 );
790
791 while (m_waiting) gtk_main_iteration();;
792 }
793
794 #if wxUSE_THREADS
795 /* re-enable GUI threads */
796 wxapp_install_thread_wakeup();
797 #endif
798
799 g_blockEventsOnDrag = FALSE;
800
801 UnregisterWindow();
802
803 return m_retValue;
804 }
805
806 void wxDropSource::RegisterWindow()
807 {
808 if (!m_widget) return;
809
810 gtk_signal_connect( GTK_OBJECT(m_widget), "drag_data_get",
811 GTK_SIGNAL_FUNC (source_drag_data_get), (gpointer) this);
812 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_data_delete",
813 GTK_SIGNAL_FUNC (source_drag_data_delete), (gpointer) this );
814 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_begin",
815 GTK_SIGNAL_FUNC (source_drag_begin), (gpointer) this );
816 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_end",
817 GTK_SIGNAL_FUNC (source_drag_end), (gpointer) this );
818
819 }
820
821 void wxDropSource::UnregisterWindow()
822 {
823 if (!m_widget) return;
824
825 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
826 GTK_SIGNAL_FUNC(source_drag_data_get), (gpointer) this );
827 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
828 GTK_SIGNAL_FUNC(source_drag_data_delete), (gpointer) this );
829 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
830 GTK_SIGNAL_FUNC(source_drag_begin), (gpointer) this );
831 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
832 GTK_SIGNAL_FUNC(source_drag_end), (gpointer) this );
833 }
834
835 #endif
836
837 // wxUSE_DRAG_AND_DROP