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