]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/dnd.cpp
Backgrounds work again
[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() );
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
595 if (data_size > 0)
596 {
597 guchar *buffer = new guchar[data_size];
598 data_object->WriteData( buffer );
599
600 gtk_selection_data_set( selection_data,
601 selection_data->target,
602 8, /* 8-bit */
603 buffer,
604 data_size );
605
606 free( buffer );
607
608 /* so far only copy, no moves. TODO. */
609 drop_source->m_retValue = wxDragCopy;
610
611 return;
612 }
613 }
614
615 node = node->Next();
616 }
617
618 drop_source->m_retValue = wxDragCancel;
619 }
620
621 //----------------------------------------------------------------------------
622 // "drag_data_delete"
623 //----------------------------------------------------------------------------
624
625 static void source_drag_data_delete( GtkWidget *WXUNUSED(widget),
626 GdkDragContext *WXUNUSED(context),
627 wxDropSource *drop_source )
628 {
629 // printf( "Delete the data!\n" );
630
631 drop_source->m_retValue = wxDragMove;
632 }
633
634 //----------------------------------------------------------------------------
635 // "drag_begin"
636 //----------------------------------------------------------------------------
637
638 static void source_drag_begin( GtkWidget *WXUNUSED(widget),
639 GdkDragContext *WXUNUSED(context),
640 wxDropSource *WXUNUSED(drop_source) )
641 {
642 // printf( "drag_begin.\n" );
643 }
644
645 //----------------------------------------------------------------------------
646 // "drag_end"
647 //----------------------------------------------------------------------------
648
649 static void source_drag_end( GtkWidget *WXUNUSED(widget),
650 GdkDragContext *WXUNUSED(context),
651 wxDropSource *drop_source )
652 {
653 // printf( "drag_end.\n" );
654
655 drop_source->m_waiting = FALSE;
656 }
657
658 //---------------------------------------------------------------------------
659 // wxDropSource
660 //---------------------------------------------------------------------------
661
662 wxDropSource::wxDropSource( wxWindow *win, const wxIcon &go, const wxIcon &stop )
663 {
664 g_blockEventsOnDrag = TRUE;
665 m_waiting = TRUE;
666
667 m_window = win;
668 m_widget = win->m_widget;
669 if (win->m_wxwindow) m_widget = win->m_wxwindow;
670
671 m_data = (wxDataBroker*) NULL;
672 m_retValue = wxDragCancel;
673
674 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
675 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
676
677 m_goIcon = go;
678 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
679 m_stopIcon = stop;
680 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
681 }
682
683 wxDropSource::wxDropSource( wxDataObject *data, wxWindow *win, const wxIcon &go, const wxIcon &stop )
684 {
685 m_waiting = TRUE;
686
687 m_window = win;
688 m_widget = win->m_widget;
689 if (win->m_wxwindow) m_widget = win->m_wxwindow;
690 m_retValue = wxDragCancel;
691
692 if (data)
693 {
694 m_data = new wxDataBroker();
695 m_data->Add( data );
696 }
697 else
698 {
699 m_data = (wxDataBroker*) NULL;
700 }
701
702 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
703 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
704
705 m_goIcon = go;
706 if (wxNullIcon == go) m_goIcon = wxIcon( page_xpm );
707 m_stopIcon = stop;
708 if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
709 }
710
711 wxDropSource::wxDropSource( wxDataBroker *data, wxWindow *win )
712 {
713 m_window = win;
714 m_widget = win->m_widget;
715 if (win->m_wxwindow) m_widget = win->m_wxwindow;
716 m_retValue = wxDragCancel;
717
718 m_data = data;
719
720 m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
721 m_goaheadCursor = wxCursor( wxCURSOR_HAND );
722 }
723
724 void wxDropSource::SetData( wxDataObject *data )
725 {
726 if (m_data) delete m_data;
727
728 if (data)
729 {
730 m_data = new wxDataBroker();
731 m_data->Add( data );
732 }
733 else
734 {
735 m_data = (wxDataBroker*) NULL;
736 }
737 }
738
739 void wxDropSource::SetData( wxDataBroker *data )
740 {
741 if (m_data) delete m_data;
742
743 m_data = data;
744 }
745
746 wxDropSource::~wxDropSource(void)
747 {
748 if (m_data) delete m_data;
749
750 g_blockEventsOnDrag = FALSE;
751 }
752
753 wxDragResult wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove) )
754 {
755 wxASSERT_MSG( m_data, _T("wxDragSource: no data") );
756
757 if (!m_data) return (wxDragResult) wxDragNone;
758
759 g_blockEventsOnDrag = TRUE;
760
761 RegisterWindow();
762
763 m_waiting = TRUE;
764
765 GtkTargetList *target_list = gtk_target_list_new( (GtkTargetEntry*) NULL, 0 );
766 gtk_target_list_add( target_list, gdk_atom_intern( "STRING", FALSE ), 0, 0 );
767
768 GdkEventMotion event;
769 event.window = m_widget->window;
770 int x = 0;
771 int y = 0;
772 GdkModifierType state;
773 gdk_window_get_pointer( event.window, &x, &y, &state );
774 event.x = x;
775 event.y = y;
776 event.state = state;
777
778 /* GTK wants to know which button was pressed which caused the dragging */
779 int button_number = 0;
780 if (event.state & GDK_BUTTON1_MASK) button_number = 1;
781 else if (event.state & GDK_BUTTON2_MASK) button_number = 2;
782 else if (event.state & GDK_BUTTON3_MASK) button_number = 3;
783
784 /* don't start dragging if no button is down */
785 if (button_number)
786 {
787 GdkDragContext *context = gtk_drag_begin( m_widget,
788 target_list,
789 GDK_ACTION_COPY,
790 button_number, /* number of mouse button which started drag */
791 (GdkEvent*) &event );
792
793 wxMask *mask = m_goIcon.GetMask();
794 GdkBitmap *bm = (GdkBitmap *) NULL;
795 if (mask) bm = mask->GetBitmap();
796 GdkPixmap *pm = m_goIcon.GetPixmap();
797
798 gtk_drag_set_icon_pixmap( context,
799 gtk_widget_get_colormap( m_widget ),
800 pm,
801 bm,
802 0,
803 0 );
804
805 gdk_flush();
806
807 while (m_waiting) wxYield();
808 }
809
810 g_blockEventsOnDrag = FALSE;
811
812 UnregisterWindow();
813
814 return m_retValue;
815 }
816
817 void wxDropSource::RegisterWindow()
818 {
819 if (!m_widget) return;
820
821 gtk_signal_connect( GTK_OBJECT(m_widget), "drag_data_get",
822 GTK_SIGNAL_FUNC (source_drag_data_get), (gpointer) this);
823 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_data_delete",
824 GTK_SIGNAL_FUNC (source_drag_data_delete), (gpointer) this );
825 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_begin",
826 GTK_SIGNAL_FUNC (source_drag_begin), (gpointer) this );
827 gtk_signal_connect (GTK_OBJECT(m_widget), "drag_end",
828 GTK_SIGNAL_FUNC (source_drag_end), (gpointer) this );
829
830 }
831
832 void wxDropSource::UnregisterWindow()
833 {
834 if (!m_widget) return;
835
836 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
837 GTK_SIGNAL_FUNC(source_drag_data_get), (gpointer) this );
838 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
839 GTK_SIGNAL_FUNC(source_drag_data_delete), (gpointer) this );
840 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
841 GTK_SIGNAL_FUNC(source_drag_begin), (gpointer) this );
842 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
843 GTK_SIGNAL_FUNC(source_drag_end), (gpointer) this );
844 }
845
846 #endif
847
848 // wxUSE_DRAG_AND_DROP