Changed two conflicting defines in defs.h
[wxWidgets.git] / src / gtk / 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 if (drop_target->m_firstMotion)
192 {
193 /* the first "drag_motion" event substitutes a "drag_enter" event */
194 drop_target->OnEnter();
195 }
196
197 /* give program a chance to react (i.e. to say no by returning FALSE) */
198 bool ret = drop_target->OnMove( x, y );
199
200 /* we don't yet handle which "actions" (i.e. copy or move)
201 the target accepts. so far we simply accept the
202 suggested action. TODO. */
203 if (ret)
204 gdk_drag_status( context, context->suggested_action, time );
205
206 /* after this, invalidate the drop_target's GdkDragContext */
207 drop_target->SetDragContext( (GdkDragContext*) NULL );
208
209 /* this has to be done because GDK has no "drag_enter" event */
210 drop_target->m_firstMotion = FALSE;
211
212 return ret;
213 }
214
215 // ----------------------------------------------------------------------------
216 // "drag_drop"
217 // ----------------------------------------------------------------------------
218
219 static gboolean target_drag_drop( GtkWidget *widget,
220 GdkDragContext *context,
221 gint x,
222 gint y,
223 guint time,
224 wxDropTarget *drop_target )
225 {
226 if (g_isIdle) wxapp_install_idle_handler();
227
228 /* Owen Taylor: "if the drop is not in a drop zone,
229 return FALSE, otherwise, if you aren't accepting
230 the drop, call gtk_drag_finish() with success == FALSE
231 otherwise call gtk_drag_data_get()" */
232
233 // printf( "drop.\n" );
234
235 /* this seems to make a difference between not accepting
236 due to wrong target area and due to wrong format. let
237 us hope that this is not required.. */
238
239 /* inform the wxDropTarget about the current GdkDragContext.
240 this is only valid for the duration of this call */
241 drop_target->SetDragContext( context );
242
243 /* inform the wxDropTarget about the current drag widget.
244 this is only valid for the duration of this call */
245 drop_target->SetDragWidget( widget );
246
247 /* inform the wxDropTarget about the current drag time.
248 this is only valid for the duration of this call */
249 drop_target->SetDragTime( time );
250
251 bool ret = drop_target->OnDrop( x, y );
252
253 if (!ret)
254 {
255 /* cancel the whole thing */
256 gtk_drag_finish( context,
257 FALSE, /* no success */
258 FALSE, /* don't delete data on dropping side */
259 time );
260 }
261
262 /* after this, invalidate the drop_target's GdkDragContext */
263 drop_target->SetDragContext( (GdkDragContext*) NULL );
264
265 /* after this, invalidate the drop_target's drag widget */
266 drop_target->SetDragWidget( (GtkWidget*) NULL );
267
268 /* this has to be done because GDK has no "drag_enter" event */
269 drop_target->m_firstMotion = TRUE;
270
271 return ret;
272 }
273
274 // ----------------------------------------------------------------------------
275 // "drag_data_received"
276 // ----------------------------------------------------------------------------
277
278 static void target_drag_data_received( GtkWidget *WXUNUSED(widget),
279 GdkDragContext *context,
280 gint x,
281 gint y,
282 GtkSelectionData *data,
283 guint WXUNUSED(info),
284 guint time,
285 wxDropTarget *drop_target )
286 {
287 if (g_isIdle) wxapp_install_idle_handler();
288
289 /* Owen Taylor: "call gtk_drag_finish() with
290 success == TRUE" */
291
292
293 if ((data->length <= 0) || (data->format != 8))
294 {
295 /* negative data length and non 8-bit data format
296 qualifies for junk */
297 gtk_drag_finish (context, FALSE, FALSE, time);
298
299 return;
300 }
301
302 wxLogDebug( wxT( "Drop target: data received") );
303
304 /* inform the wxDropTarget about the current GtkSelectionData.
305 this is only valid for the duration of this call */
306 drop_target->SetDragData( data );
307
308 if (drop_target->OnData( x, y ))
309 {
310 /* tell GTK that data transfer was successfull */
311 gtk_drag_finish( context, TRUE, FALSE, time );
312 }
313 else
314 {
315 /* tell GTK that data transfer was not successfull */
316 gtk_drag_finish( context, FALSE, FALSE, time );
317 }
318
319 /* after this, invalidate the drop_target's drag data */
320 drop_target->SetDragData( (GtkSelectionData*) NULL );
321 }
322
323 //----------------------------------------------------------------------------
324 // wxDropTarget
325 //----------------------------------------------------------------------------
326
327 wxDropTarget::wxDropTarget()
328 {
329 m_firstMotion = TRUE;
330 m_dragContext = (GdkDragContext*) NULL;
331 m_dragWidget = (GtkWidget*) NULL;
332 m_dragData = (GtkSelectionData*) NULL;
333 m_dragTime = 0;
334 }
335
336 wxDropTarget::~wxDropTarget()
337 {
338 }
339
340 void wxDropTarget::OnEnter()
341 {
342 }
343
344 void wxDropTarget::OnLeave()
345 {
346 }
347
348 bool wxDropTarget::OnMove( long WXUNUSED(x), long WXUNUSED(y) )
349 {
350 if (GetFormatCount() == 0)
351 return FALSE;
352
353 for (size_t i = 0; i < GetFormatCount(); i++)
354 {
355 if (IsSupported( GetFormat(i) ))
356 return TRUE;
357 }
358
359 return FALSE;
360 }
361
362 bool wxDropTarget::OnDrop( long WXUNUSED(x), long WXUNUSED(y) )
363 {
364 if (GetFormatCount() == 0)
365 return FALSE;
366
367 for (size_t i = 0; i < GetFormatCount(); i++)
368 {
369 if (IsSupported( GetFormat(i) ))
370 {
371 RequestData( GetFormat(i) );
372 return TRUE;
373 }
374 }
375
376 return FALSE;
377 }
378
379 bool wxDropTarget::OnData( long WXUNUSED(x), long WXUNUSED(y) )
380 {
381 return FALSE;
382 }
383
384 bool wxDropTarget::RequestData( wxDataFormat format )
385 {
386 if (!m_dragContext) return FALSE;
387 if (!m_dragWidget) return FALSE;
388
389 /*
390 wxPrintf( wxT("format: %s.\n"), format.GetId().c_str() );
391 if (format.GetType() == wxDF_PRIVATE) wxPrintf( wxT("private data.\n") );
392 if (format.GetType() == wxDF_TEXT) wxPrintf( wxT("text data.\n") );
393 */
394
395 #if wxUSE_THREADS
396 /* disable GUI threads */
397 wxapp_uninstall_thread_wakeup();
398 #endif
399
400 /* this should trigger an "drag_data_received" event */
401 gtk_drag_get_data( m_dragWidget,
402 m_dragContext,
403 format,
404 m_dragTime );
405
406 #if wxUSE_THREADS
407 /* re-enable GUI threads */
408 wxapp_install_thread_wakeup();
409 #endif
410
411 return TRUE;
412 }
413
414 bool wxDropTarget::IsSupported( wxDataFormat format )
415 {
416 if (!m_dragContext) return FALSE;
417
418 GList *child = m_dragContext->targets;
419 while (child)
420 {
421 GdkAtom formatAtom = (GdkAtom) GPOINTER_TO_INT(child->data);
422
423 #ifdef __WXDEBUG__
424 char *name = gdk_atom_name( formatAtom );
425 if (name) wxLogDebug( "Drop target: drag has format: %s", name );
426 #endif
427
428 if (formatAtom == format) return TRUE;
429 child = child->next;
430 }
431
432 return FALSE;
433 }
434
435 bool wxDropTarget::GetData( wxDataObject *data_object )
436 {
437 if (!m_dragData) return FALSE;
438
439 if (m_dragData->target != data_object->GetFormat()) return FALSE;
440
441 if (data_object->GetFormat().GetType() == wxDF_TEXT)
442 {
443 wxTextDataObject *text_object = (wxTextDataObject*)data_object;
444 text_object->SetText( (const char*)m_dragData->data );
445 } else
446
447 if (data_object->GetFormat().GetType() == wxDF_FILENAME)
448 {
449 } else
450
451 if (data_object->GetFormat().GetType() == wxDF_PRIVATE)
452 {
453 wxPrivateDataObject *priv_object = (wxPrivateDataObject*)data_object;
454 priv_object->SetData( (const char*)m_dragData->data, (size_t)m_dragData->length );
455 }
456
457 return TRUE;
458 }
459
460 void wxDropTarget::UnregisterWidget( GtkWidget *widget )
461 {
462 wxCHECK_RET( widget != NULL, wxT("unregister widget is NULL") );
463
464 gtk_drag_dest_unset( widget );
465
466 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
467 GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this );
468
469 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
470 GTK_SIGNAL_FUNC(target_drag_motion), (gpointer) this );
471
472 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
473 GTK_SIGNAL_FUNC(target_drag_drop), (gpointer) this );
474
475 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
476 GTK_SIGNAL_FUNC(target_drag_data_received), (gpointer) this );
477 }
478
479 void wxDropTarget::RegisterWidget( GtkWidget *widget )
480 {
481 wxCHECK_RET( widget != NULL, wxT("register widget is NULL") );
482
483 /* gtk_drag_dest_set() determines what default behaviour we'd like
484 GTK to supply. we don't want to specify out targets (=formats)
485 or actions in advance (i.e. not GTK_DEST_DEFAULT_MOTION and
486 not GTK_DEST_DEFAULT_DROP). instead we react individually to
487 "drag_motion" and "drag_drop" events. this makes it possible
488 to allow dropping on only a small area. we should set
489 GTK_DEST_DEFAULT_HIGHLIGHT as this will switch on the nice
490 highlighting if dragging over standard controls, but this
491 seems to be broken without the other two. */
492
493 gtk_drag_dest_set( widget,
494 (GtkDestDefaults) 0, /* no default behaviour */
495 (GtkTargetEntry*) NULL, /* we don't supply any formats here */
496 0, /* number of targets = 0 */
497 (GdkDragAction) 0 ); /* we don't supply any actions here */
498
499 gtk_signal_connect( GTK_OBJECT(widget), "drag_leave",
500 GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this );
501
502 gtk_signal_connect( GTK_OBJECT(widget), "drag_motion",
503 GTK_SIGNAL_FUNC(target_drag_motion), (gpointer) this );
504
505 gtk_signal_connect( GTK_OBJECT(widget), "drag_drop",
506 GTK_SIGNAL_FUNC(target_drag_drop), (gpointer) this );
507
508 gtk_signal_connect( GTK_OBJECT(widget), "drag_data_received",
509 GTK_SIGNAL_FUNC(target_drag_data_received), (gpointer) this );
510 }
511
512 //-------------------------------------------------------------------------
513 // wxTextDropTarget
514 //-------------------------------------------------------------------------
515
516 bool wxTextDropTarget::OnData( long x, long y )
517 {
518 wxTextDataObject data;
519 if (!GetData( &data )) return FALSE;
520
521 OnDropText( x, y, data.GetText() );
522
523 return TRUE;
524 }
525
526 //-------------------------------------------------------------------------
527 // wxPrivateDropTarget
528 //-------------------------------------------------------------------------
529
530 /*
531 wxPrivateDropTarget::wxPrivateDropTarget()
532 {
533 m_id = wxTheApp->GetAppName();
534 }
535
536 wxPrivateDropTarget::wxPrivateDropTarget( const wxString &id )
537 {
538 m_id = id;
539 }
540
541 bool wxPrivateDropTarget::OnMove( long WXUNUSED(x), long WXUNUSED(y) )
542 {
543 return IsSupported( m_id );
544 }
545
546 bool wxPrivateDropTarget::OnDrop( long WXUNUSED(x), long WXUNUSED(y) )
547 {
548 if (!IsSupported( m_id ))
549 {
550 RequestData( m_id );
551 return FALSE;
552 }
553
554 return FALSE;
555 }
556
557 bool wxPrivateDropTarget::OnData( long x, long y )
558 {
559 if (!IsSupported( m_id )) return FALSE;
560
561 wxPrivateDataObject data;
562 if (!GetData( &data )) return FALSE;
563
564 OnDropData( x, y, data.GetData(), data.GetSize() );
565
566 return TRUE;
567 }
568 */
569
570 //----------------------------------------------------------------------------
571 // A drop target which accepts files (dragged from File Manager or Explorer)
572 //----------------------------------------------------------------------------
573
574 bool wxFileDropTarget::OnData( long x, long y )
575 {
576 wxFileDataObject data;
577 if (!GetData( &data )) return FALSE;
578
579 // get number of substrings /root/mytext.txt/0/root/myothertext.txt/0/0
580 size_t number = 0;
581 size_t i;
582 size_t size = data.GetFiles().Length();
583 wxChar *text = WXSTRINGCAST data.GetFiles();
584 for ( i = 0; i < size; i++)
585 if (text[i] == 0) number++;
586
587 if (number == 0) return FALSE;
588
589 wxChar **files = new wxChar*[number];
590
591 text = WXSTRINGCAST data.GetFiles();
592 for (i = 0; i < number; i++)
593 {
594 files[i] = text;
595 int len = wxStrlen( text );
596 text += len+1;
597 }
598
599 OnDropFiles( x, y, number, files );
600
601 free( files );
602
603 return TRUE;
604 }
605
606 //----------------------------------------------------------------------------
607 // "drag_data_get"
608 //----------------------------------------------------------------------------
609
610 static void
611 source_drag_data_get (GtkWidget *WXUNUSED(widget),
612 GdkDragContext *context,
613 GtkSelectionData *selection_data,
614 guint WXUNUSED(info),
615 guint WXUNUSED(time),
616 wxDropSource *drop_source )
617 {
618 if (g_isIdle) wxapp_install_idle_handler();
619
620 #ifdef __WXDEBUG__
621 char *name = gdk_atom_name( selection_data->target );
622 if (name) wxLogDebug( wxT("Drop source: format requested: %s"), name );
623 #endif
624
625 drop_source->m_retValue = wxDragCancel;
626
627 wxDataObject *data = drop_source->m_data;
628
629 if (!data)
630 return;
631
632 if (!data->IsSupportedFormat(selection_data->target))
633 return;
634
635 if (data->GetDataSize(selection_data->target) == 0)
636 return;
637
638 size_t size = data->GetDataSize(selection_data->target);
639
640 // printf( "data size: %d.\n", (int)data_size );
641
642 guchar *d = new guchar[size];
643
644 if (!data->GetDataHere( selection_data->target, (void*)d ))
645 {
646 free( d );
647 return;
648 }
649
650 #if wxUSE_THREADS
651 /* disable GUI threads */
652 wxapp_uninstall_thread_wakeup();
653 #endif
654
655 gtk_selection_data_set( selection_data,
656 selection_data->target,
657 8, // 8-bit
658 d,
659 size );
660
661 #if wxUSE_THREADS
662 /* enable GUI threads */
663 wxapp_install_thread_wakeup();
664 #endif
665
666 free( d );
667
668 /* so far only copy, no moves. TODO. */
669 drop_source->m_retValue = wxDragCopy;
670 }
671
672 //----------------------------------------------------------------------------
673 // "drag_data_delete"
674 //----------------------------------------------------------------------------
675
676 static void source_drag_data_delete( GtkWidget *WXUNUSED(widget),
677 GdkDragContext *WXUNUSED(context),
678 wxDropSource *drop_source )
679 {
680 if (g_isIdle) wxapp_install_idle_handler();
681
682 // printf( "Delete the data!\n" );
683
684 drop_source->m_retValue = wxDragMove;
685 }
686
687 //----------------------------------------------------------------------------
688 // "drag_begin"
689 //----------------------------------------------------------------------------
690
691 static void source_drag_begin( GtkWidget *WXUNUSED(widget),
692 GdkDragContext *WXUNUSED(context),
693 wxDropSource *WXUNUSED(drop_source) )
694 {
695 if (g_isIdle) wxapp_install_idle_handler();
696
697 // printf( "drag_begin.\n" );
698 }
699
700 //----------------------------------------------------------------------------
701 // "drag_end"
702 //----------------------------------------------------------------------------
703
704 static void source_drag_end( GtkWidget *WXUNUSED(widget),
705 GdkDragContext *WXUNUSED(context),
706 wxDropSource *drop_source )
707 {
708 if (g_isIdle) wxapp_install_idle_handler();
709
710 // printf( "drag_end.\n" );
711
712 drop_source->m_waiting = FALSE;
713 }
714
715 //---------------------------------------------------------------------------
716 // wxDropSource
717 //---------------------------------------------------------------------------
718
719 wxDropSource::wxDropSource( wxWindow *win, const wxIcon &go, const wxIcon &stop )
720 {
721 g_blockEventsOnDrag = TRUE;
722 m_waiting = TRUE;
723
724 m_window = win;
725 m_widget = win->m_widget;
726 if (win->m_wxwindow) m_widget = win->m_wxwindow;
727
728 m_data = (wxDataObject*) NULL;
729 m_retValue = wxDragCancel;
730
731 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
732 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
733
734 m_goIcon = go;
735 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
736 m_stopIcon = stop;
737 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
738 }
739
740 wxDropSource::wxDropSource( wxDataObject& data, wxWindow *win,
741 const wxIcon &go, const wxIcon &stop )
742 {
743 m_waiting = TRUE;
744
745 m_window = win;
746 m_widget = win->m_widget;
747 if (win->m_wxwindow) m_widget = win->m_wxwindow;
748 m_retValue = wxDragCancel;
749
750 m_data = &data;
751
752 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
753 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
754
755 m_goIcon = go;
756 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
757 m_stopIcon = stop;
758 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
759 }
760
761 void wxDropSource::SetData( wxDataObject& data )
762 {
763 if (m_data)
764 delete m_data;
765
766 m_data = &data;
767 }
768
769 wxDropSource::~wxDropSource()
770 {
771 if (m_data)
772 // delete m_data;
773
774 g_blockEventsOnDrag = FALSE;
775 }
776
777 wxDragResult wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove) )
778 {
779 wxASSERT_MSG( m_data, wxT("wxDragSource: no data") );
780
781 if (!m_data)
782 return (wxDragResult) wxDragNone;
783
784 if (m_data->GetFormatCount() == 0)
785 return (wxDragResult) wxDragNone;
786
787 g_blockEventsOnDrag = TRUE;
788
789 RegisterWindow();
790
791 m_waiting = TRUE;
792
793 GtkTargetList *target_list = gtk_target_list_new( (GtkTargetEntry*) NULL, 0 );
794
795 wxDataFormat *array = new wxDataFormat[ m_data->GetFormatCount() ];
796 m_data->GetAllFormats( array, TRUE );
797 for (size_t i = 0; i < m_data->GetFormatCount(); i++)
798 {
799 GdkAtom atom = array[i];
800 wxLogDebug( wxT("Supported atom %s"), gdk_atom_name( atom ) );
801 gtk_target_list_add( target_list, atom, 0, 0 );
802 }
803 delete[] array;
804
805 GdkEventMotion event;
806 event.window = m_widget->window;
807 int x = 0;
808 int y = 0;
809 GdkModifierType state;
810 gdk_window_get_pointer( event.window, &x, &y, &state );
811 event.x = x;
812 event.y = y;
813 event.state = state;
814 event.time = GDK_CURRENT_TIME;
815
816 /* GTK wants to know which button was pressed which caused the dragging */
817 int button_number = 0;
818 if (event.state & GDK_BUTTON1_MASK) button_number = 1;
819 else if (event.state & GDK_BUTTON2_MASK) button_number = 2;
820 else if (event.state & GDK_BUTTON3_MASK) button_number = 3;
821
822 #if wxUSE_THREADS
823 /* disable GUI threads */
824 wxapp_uninstall_thread_wakeup();
825 #endif
826
827 /* don't start dragging if no button is down */
828 if (button_number)
829 {
830 GdkDragContext *context = gtk_drag_begin( m_widget,
831 target_list,
832 GDK_ACTION_COPY,
833 button_number, /* number of mouse button which started drag */
834 (GdkEvent*) &event );
835
836 wxMask *mask = m_goIcon.GetMask();
837 GdkBitmap *bm = (GdkBitmap *) NULL;
838 if (mask) bm = mask->GetBitmap();
839 GdkPixmap *pm = m_goIcon.GetPixmap();
840
841 gtk_drag_set_icon_pixmap( context,
842 gtk_widget_get_colormap( m_widget ),
843 pm,
844 bm,
845 0,
846 0 );
847
848 while (m_waiting) gtk_main_iteration();;
849 }
850
851 #if wxUSE_THREADS
852 /* re-enable GUI threads */
853 wxapp_install_thread_wakeup();
854 #endif
855
856 g_blockEventsOnDrag = FALSE;
857
858 UnregisterWindow();
859
860 return m_retValue;
861 }
862
863 void wxDropSource::RegisterWindow()
864 {
865 if (!m_widget) return;
866
867 gtk_signal_connect( GTK_OBJECT(m_widget), "drag_data_get",
868 GTK_SIGNAL_FUNC (source_drag_data_get), (gpointer) this);
869 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_data_delete",
870 GTK_SIGNAL_FUNC (source_drag_data_delete), (gpointer) this );
871 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_begin",
872 GTK_SIGNAL_FUNC (source_drag_begin), (gpointer) this );
873 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_end",
874 GTK_SIGNAL_FUNC (source_drag_end), (gpointer) this );
875
876 }
877
878 void wxDropSource::UnregisterWindow()
879 {
880 if (!m_widget) return;
881
882 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
883 GTK_SIGNAL_FUNC(source_drag_data_get), (gpointer) this );
884 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
885 GTK_SIGNAL_FUNC(source_drag_data_delete), (gpointer) this );
886 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
887 GTK_SIGNAL_FUNC(source_drag_begin), (gpointer) this );
888 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
889 GTK_SIGNAL_FUNC(source_drag_end), (gpointer) this );
890 }
891
892 #endif
893
894 // wxUSE_DRAG_AND_DROP