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