little doc updates
[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 // 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 return;
277 }
278
279 /* inform the wxDropTarget about the current GtkSelectionData.
280 this is only valid for the duration of this call */
281 drop_target->SetDragData( data );
282
283 if (drop_target->OnData( x, y ))
284 {
285 /* tell GTK that data transfer was successfull */
286 gtk_drag_finish( context, TRUE, FALSE, time );
287 }
288 else
289 {
290 /* tell GTK that data transfer was not successfull */
291 gtk_drag_finish( context, FALSE, FALSE, time );
292 }
293
294 /* after this, invalidate the drop_target's drag data */
295 drop_target->SetDragData( (GtkSelectionData*) NULL );
296 }
297
298 //----------------------------------------------------------------------------
299 // wxDropTarget
300 //----------------------------------------------------------------------------
301
302 wxDropTarget::wxDropTarget()
303 {
304 m_firstMotion = TRUE;
305 m_dragContext = (GdkDragContext*) NULL;
306 m_dragWidget = (GtkWidget*) NULL;
307 m_dragData = (GtkSelectionData*) NULL;
308 m_dragTime = 0;
309 }
310
311 wxDropTarget::~wxDropTarget()
312 {
313 }
314
315 void wxDropTarget::OnEnter()
316 {
317 }
318
319 void wxDropTarget::OnLeave()
320 {
321 }
322
323 bool wxDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
324 {
325 return TRUE;
326 }
327
328 bool wxDropTarget::OnDrop( int WXUNUSED(x), int WXUNUSED(y) )
329 {
330 return FALSE;
331 }
332
333 bool wxDropTarget::OnData( int WXUNUSED(x), int WXUNUSED(y) )
334 {
335 return FALSE;
336 }
337
338 bool wxDropTarget::RequestData( wxDataFormat format )
339 {
340 if (!m_dragContext) return FALSE;
341 if (!m_dragWidget) return FALSE;
342
343 /* this should trigger an "drag_data_received" event */
344 gtk_drag_get_data( m_dragWidget,
345 m_dragContext,
346 format.GetAtom(),
347 m_dragTime );
348
349 return TRUE;
350 }
351
352 bool wxDropTarget::IsSupported( wxDataFormat format )
353 {
354 if (!m_dragContext) return FALSE;
355
356 GList *child = m_dragContext->targets;
357 while (child)
358 {
359 GdkAtom formatAtom = (GdkAtom) GPOINTER_TO_INT(child->data);
360
361 // char *name = gdk_atom_name( formatAtom );
362 // if (name) printf( "Format available: %s.\n", name );
363
364 if (formatAtom == format.GetAtom()) return TRUE;
365 child = child->next;
366 }
367
368 return FALSE;
369 }
370
371 bool wxDropTarget::GetData( wxDataObject *data_object )
372 {
373 if (!m_dragData) return FALSE;
374
375 if (m_dragData->target != data_object->GetFormat().GetAtom()) return FALSE;
376
377 if (data_object->GetFormat().GetType() == wxDF_TEXT)
378 {
379 wxTextDataObject *text_object = (wxTextDataObject*)data_object;
380 text_object->SetText( (const char*)m_dragData->data );
381 } else
382
383 if (data_object->GetFormat().GetType() == wxDF_FILENAME)
384 {
385 } else
386
387 if (data_object->GetFormat().GetType() == wxDF_PRIVATE)
388 {
389 wxPrivateDataObject *priv_object = (wxPrivateDataObject*)data_object;
390 priv_object->SetData( (const char*)m_dragData->data, (size_t)m_dragData->length );
391 }
392
393 return TRUE;
394 }
395
396 void wxDropTarget::UnregisterWidget( GtkWidget *widget )
397 {
398 wxCHECK_RET( widget != NULL, _T("unregister widget is NULL") );
399
400 gtk_drag_dest_unset( widget );
401
402 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
403 GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this );
404
405 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
406 GTK_SIGNAL_FUNC(target_drag_motion), (gpointer) this );
407
408 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
409 GTK_SIGNAL_FUNC(target_drag_drop), (gpointer) this );
410
411 gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
412 GTK_SIGNAL_FUNC(target_drag_data_received), (gpointer) this );
413 }
414
415 void wxDropTarget::RegisterWidget( GtkWidget *widget )
416 {
417 wxCHECK_RET( widget != NULL, _T("register widget is NULL") );
418
419 /* gtk_drag_dest_set() determines what default behaviour we'd like
420 GTK to supply. we don't want to specify out targets (=formats)
421 or actions in advance (i.e. not GTK_DEST_DEFAULT_MOTION and
422 not GTK_DEST_DEFAULT_DROP). instead we react individually to
423 "drag_motion" and "drag_drop" events. this makes it possible
424 to allow dropping on only a small area. we should set
425 GTK_DEST_DEFAULT_HIGHLIGHT as this will switch on the nice
426 highlighting if dragging over standard controls, but this
427 seems to be broken without the other two. */
428
429 gtk_drag_dest_set( widget,
430 (GtkDestDefaults) 0, /* no default behaviour */
431 (GtkTargetEntry*) NULL, /* we don't supply any formats here */
432 0, /* number of targets = 0 */
433 (GdkDragAction) 0 ); /* we don't supply any actions here */
434
435 gtk_signal_connect( GTK_OBJECT(widget), "drag_leave",
436 GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this );
437
438 gtk_signal_connect( GTK_OBJECT(widget), "drag_motion",
439 GTK_SIGNAL_FUNC(target_drag_motion), (gpointer) this );
440
441 gtk_signal_connect( GTK_OBJECT(widget), "drag_drop",
442 GTK_SIGNAL_FUNC(target_drag_drop), (gpointer) this );
443
444 gtk_signal_connect( GTK_OBJECT(widget), "drag_data_received",
445 GTK_SIGNAL_FUNC(target_drag_data_received), (gpointer) this );
446 }
447
448 //-------------------------------------------------------------------------
449 // wxTextDropTarget
450 //-------------------------------------------------------------------------
451
452 bool wxTextDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
453 {
454 return IsSupported( wxDF_TEXT );
455 }
456
457 bool wxTextDropTarget::OnDrop( int WXUNUSED(x), int WXUNUSED(y) )
458 {
459 if (IsSupported( wxDF_TEXT ))
460 {
461 RequestData( wxDF_TEXT );
462 return TRUE;
463 }
464
465 return FALSE;
466 }
467
468 bool wxTextDropTarget::OnData( int x, int y )
469 {
470 wxTextDataObject data;
471 if (!GetData( &data )) return FALSE;
472
473 OnDropText( x, y, data.GetText().mbc_str() );
474
475 return TRUE;
476 }
477
478 //-------------------------------------------------------------------------
479 // wxPrivateDropTarget
480 //-------------------------------------------------------------------------
481
482 wxPrivateDropTarget::wxPrivateDropTarget()
483 {
484 m_id = wxTheApp->GetAppName();
485 }
486
487 wxPrivateDropTarget::wxPrivateDropTarget( const wxString &id )
488 {
489 m_id = id;
490 }
491
492 bool wxPrivateDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
493 {
494 return IsSupported( m_id );
495 }
496
497 bool wxPrivateDropTarget::OnDrop( int WXUNUSED(x), int WXUNUSED(y) )
498 {
499 if (!IsSupported( m_id ))
500 {
501 RequestData( m_id );
502 return FALSE;
503 }
504
505 return FALSE;
506 }
507
508 bool wxPrivateDropTarget::OnData( int x, int y )
509 {
510 if (!IsSupported( m_id )) return FALSE;
511
512 wxPrivateDataObject data;
513 if (!GetData( &data )) return FALSE;
514
515 OnDropData( x, y, data.GetData(), data.GetSize() );
516
517 return TRUE;
518 }
519
520 //----------------------------------------------------------------------------
521 // A drop target which accepts files (dragged from File Manager or Explorer)
522 //----------------------------------------------------------------------------
523
524 bool wxFileDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
525 {
526 return IsSupported( wxDF_FILENAME );
527 }
528
529 bool wxFileDropTarget::OnDrop( int x, int y )
530 {
531 if (IsSupported( wxDF_FILENAME ))
532 {
533 RequestData( wxDF_FILENAME );
534 return TRUE;
535 }
536
537 return FALSE;
538 }
539
540 bool wxFileDropTarget::OnData( int x, int y )
541 {
542 wxFileDataObject data;
543 if (!GetData( &data )) return FALSE;
544
545 /* get number of substrings /root/mytext.txt/0/root/myothertext.txt/0/0 */
546 size_t number = 0;
547 size_t i;
548 size_t size = data.GetFiles().Length();
549 wxChar *text = WXSTRINGCAST data.GetFiles();
550 for ( i = 0; i < size; i++)
551 if (text[i] == 0) number++;
552
553 if (number == 0) return FALSE;
554
555 wxChar **files = new wxChar*[number];
556
557 text = WXSTRINGCAST data.GetFiles();
558 for (i = 0; i < number; i++)
559 {
560 files[i] = text;
561 int len = wxStrlen( text );
562 text += len+1;
563 }
564
565 OnDropFiles( x, y, number, files );
566
567 free( files );
568
569 return TRUE;
570 }
571
572 //----------------------------------------------------------------------------
573 // "drag_data_get"
574 //----------------------------------------------------------------------------
575
576 static void
577 source_drag_data_get (GtkWidget *WXUNUSED(widget),
578 GdkDragContext *context,
579 GtkSelectionData *selection_data,
580 guint WXUNUSED(info),
581 guint WXUNUSED(time),
582 wxDropSource *drop_source )
583 {
584 // char *name = gdk_atom_name( selection_data->target );
585 // if (name) printf( "Format requested: %s.\n", name );
586
587 wxNode *node = drop_source->m_data->m_dataObjects.First();
588 while (node)
589 {
590 wxDataObject *data_object = (wxDataObject*) node->Data();
591 if (data_object->GetFormat().GetAtom() == selection_data->target)
592 {
593 size_t data_size = data_object->GetSize();
594 if (data_size > 0)
595 {
596 guchar *buffer = new guchar[data_size];
597 data_object->WriteData( buffer );
598
599 gtk_selection_data_set( selection_data,
600 selection_data->target,
601 8, /* 8-bit */
602 buffer,
603 data_size );
604
605 free( buffer );
606
607 /* so far only copy, no moves. TODO. */
608 drop_source->m_retValue = wxDragCopy;
609
610 return;
611 }
612 }
613
614 node = node->Next();
615 }
616
617 drop_source->m_retValue = wxDragCancel;
618 }
619
620 //----------------------------------------------------------------------------
621 // "drag_data_delete"
622 //----------------------------------------------------------------------------
623
624 static void source_drag_data_delete( GtkWidget *WXUNUSED(widget),
625 GdkDragContext *WXUNUSED(context),
626 wxDropSource *drop_source )
627 {
628 // printf( "Delete the data!\n" );
629
630 drop_source->m_retValue = wxDragMove;
631 }
632
633 //----------------------------------------------------------------------------
634 // "drag_begin"
635 //----------------------------------------------------------------------------
636
637 static void source_drag_begin( GtkWidget *WXUNUSED(widget),
638 GdkDragContext *WXUNUSED(context),
639 wxDropSource *WXUNUSED(drop_source) )
640 {
641 // printf( "drag_begin.\n" );
642 }
643
644 //----------------------------------------------------------------------------
645 // "drag_end"
646 //----------------------------------------------------------------------------
647
648 static void source_drag_end( GtkWidget *WXUNUSED(widget),
649 GdkDragContext *WXUNUSED(context),
650 wxDropSource *drop_source )
651 {
652 // printf( "drag_end.\n" );
653
654 drop_source->m_waiting = FALSE;
655 }
656
657 //---------------------------------------------------------------------------
658 // wxDropSource
659 //---------------------------------------------------------------------------
660
661 wxDropSource::wxDropSource( wxWindow *win, const wxIcon &go, const wxIcon &stop )
662 {
663 g_blockEventsOnDrag = TRUE;
664 m_waiting = TRUE;
665
666 m_window = win;
667 m_widget = win->m_widget;
668 if (win->m_wxwindow) m_widget = win->m_wxwindow;
669
670 m_data = (wxDataBroker*) NULL;
671 m_retValue = wxDragCancel;
672
673 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
674 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
675
676 m_goIcon = go;
677 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
678 m_stopIcon = stop;
679 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
680 }
681
682 wxDropSource::wxDropSource( wxDataObject *data, wxWindow *win, const wxIcon &go, const wxIcon &stop )
683 {
684 m_waiting = TRUE;
685
686 m_window = win;
687 m_widget = win->m_widget;
688 if (win->m_wxwindow) m_widget = win->m_wxwindow;
689 m_retValue = wxDragCancel;
690
691 if (data)
692 {
693 m_data = new wxDataBroker();
694 m_data->Add( data );
695 }
696 else
697 {
698 m_data = (wxDataBroker*) NULL;
699 }
700
701 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
702 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
703
704 m_goIcon = go;
705 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
706 m_stopIcon = stop;
707 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
708 }
709
710 wxDropSource::wxDropSource( wxDataBroker *data, wxWindow *win )
711 {
712 m_window = win;
713 m_widget = win->m_widget;
714 if (win->m_wxwindow) m_widget = win->m_wxwindow;
715 m_retValue = wxDragCancel;
716
717 m_data = data;
718
719 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
720 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
721 }
722
723 void wxDropSource::SetData( wxDataObject *data )
724 {
725 if (m_data) delete m_data;
726
727 if (data)
728 {
729 m_data = new wxDataBroker();
730 m_data->Add( data );
731 }
732 else
733 {
734 m_data = (wxDataBroker*) NULL;
735 }
736 }
737
738 void wxDropSource::SetData( wxDataBroker *data )
739 {
740 if (m_data) delete m_data;
741
742 m_data = data;
743 }
744
745 wxDropSource::~wxDropSource(void)
746 {
747 if (m_data) delete m_data;
748
749 g_blockEventsOnDrag = FALSE;
750 }
751
752 wxDragResult wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove) )
753 {
754 wxASSERT_MSG( m_data, _T("wxDragSource: no data") );
755
756 if (!m_data) return (wxDragResult) wxDragNone;
757
758 g_blockEventsOnDrag = TRUE;
759
760 RegisterWindow();
761
762 m_waiting = TRUE;
763
764 GtkTargetList *target_list = gtk_target_list_new( (GtkTargetEntry*) NULL, 0 );
765 gtk_target_list_add( target_list, gdk_atom_intern( "STRING", FALSE ), 0, 0 );
766
767 GdkEventMotion event;
768 event.window = m_widget->window;
769 int x = 0;
770 int y = 0;
771 GdkModifierType state;
772 gdk_window_get_pointer( event.window, &x, &y, &state );
773 event.x = x;
774 event.y = y;
775 event.state = state;
776
777 /* GTK wants to know which button was pressed which caused the dragging */
778 int button_number = 0;
779 if (event.state & GDK_BUTTON1_MASK) button_number = 1;
780 else if (event.state & GDK_BUTTON2_MASK) button_number = 2;
781 else if (event.state & GDK_BUTTON3_MASK) button_number = 3;
782
783 /* don't start dragging if no button is down */
784 if (button_number)
785 {
786 GdkDragContext *context = gtk_drag_begin( m_widget,
787 target_list,
788 GDK_ACTION_COPY,
789 button_number, /* number of mouse button which started drag */
790 (GdkEvent*) &event );
791
792 wxMask *mask = m_goIcon.GetMask();
793 GdkBitmap *bm = (GdkBitmap *) NULL;
794 if (mask) bm = mask->GetBitmap();
795 GdkPixmap *pm = m_goIcon.GetPixmap();
796
797 gtk_drag_set_icon_pixmap( context,
798 gtk_widget_get_colormap( m_widget ),
799 pm,
800 bm,
801 0,
802 0 );
803
804 gdk_flush();
805
806 while (m_waiting) wxYield();
807 }
808
809 g_blockEventsOnDrag = FALSE;
810
811 UnregisterWindow();
812
813 return m_retValue;
814 }
815
816 void wxDropSource::RegisterWindow()
817 {
818 if (!m_widget) return;
819
820 gtk_signal_connect( GTK_OBJECT(m_widget), "drag_data_get",
821 GTK_SIGNAL_FUNC (source_drag_data_get), (gpointer) this);
822 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_data_delete",
823 GTK_SIGNAL_FUNC (source_drag_data_delete), (gpointer) this );
824 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_begin",
825 GTK_SIGNAL_FUNC (source_drag_begin), (gpointer) this );
826 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_end",
827 GTK_SIGNAL_FUNC (source_drag_end), (gpointer) this );
828
829 }
830
831 void wxDropSource::UnregisterWindow()
832 {
833 if (!m_widget) return;
834
835 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
836 GTK_SIGNAL_FUNC(source_drag_data_get), (gpointer) this );
837 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
838 GTK_SIGNAL_FUNC(source_drag_data_delete), (gpointer) this );
839 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
840 GTK_SIGNAL_FUNC(source_drag_begin), (gpointer) this );
841 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
842 GTK_SIGNAL_FUNC(source_drag_end), (gpointer) this );
843 }
844
845 #endif
846
847 // wxUSE_DRAG_AND_DROP