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