1 ///////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxDropTarget class
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
11 #pragma implementation "dnd.h"
16 #if wxUSE_DRAG_AND_DROP
18 #include "wx/window.h"
20 #include "wx/gdicmn.h"
26 #include "gdk/gdkprivate.h"
30 //----------------------------------------------------------------------------
32 //----------------------------------------------------------------------------
34 extern bool g_blockEventsOnDrag
;
36 //----------------------------------------------------------------------------
38 //----------------------------------------------------------------------------
41 static char * gv_xpm
[] = {
55 " ....XX....XX....XX. ",
56 " .XXX.XXX..XXXX..XXX.... ",
57 " .XXXXXXXXXXXXXXXXXXX.XXX. ",
58 " .XXXXXXXXXXXXXXXXXXXXXXXX. ",
59 " .XXXXXXXXXXXXXXXXXXXXXXXX. ",
60 " ..XXXXXXXXXXXXXXXXXXXXXX. ",
61 " .XXXXXXXXXXXXXXXXXX... ",
62 " ..XXXXXXXXXXXXXXXX. ",
63 " .XXXXXXXXXXXXXXXX. ",
64 " .XXXXXXXXXXXXXXXX. ",
65 " .XXXXXXXXXXXXXXXXX. ",
66 " .XXXXXXXXXXXXXXXXX. ",
67 " .XXXXXXXXXXXXXXXXXX. ",
68 " .XXXXXXXXXXXXXXXXXXX. ",
69 " .XXXXXXXXXXXXXXXXXXXXX. ",
70 " .XXXXXXXXXXXXXX.XXXXXXX. ",
71 " .XXXXXXX.XXXXXXX.XXXXXXX. ",
72 " .XXXXXXXX.XXXXXXX.XXXXXXX. ",
73 " .XXXXXXX...XXXXX...XXXXX. ",
74 " .XXXXXXX. ..... ..... ",
82 static char * page_xpm
[] = {
83 /* width height ncolors chars_per_pixel */
92 " ................... ",
93 " .XXXXXXXXXXXXXXXXX.. ",
94 " .XXXXXXXXXXXXXXXXX.o. ",
95 " .XXXXXXXXXXXXXXXXX.oo. ",
96 " .XXXXXXXXXXXXXXXXX.ooo. ",
97 " .XXXXXXXXXXXXXXXXX.oooo. ",
98 " .XXXXXXXXXXXXXXXXX....... ",
99 " .XXXXXOOOOOOOOOOXXXooooo. ",
100 " .XXXXXXXXXXXXXXXXXXooooo. ",
101 " .XXXXXOOOOOOOOOOXXXXXXXX. ",
102 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
103 " .XXXXXXXOOOOOOOOOXXXXXXX. ",
104 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
105 " .XXXXXXOOOOOOOOOOXXXXXXX. ",
106 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
107 " .XXXXXOOOOOOOOOOXXXXXXXX. ",
108 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
109 " .XXXXXXXOOOOOOOOOXXXXXXX. ",
110 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
111 " .XXXXXXOOOOOOOOOOXXXXXXX. ",
112 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
113 " .XXXXXOOOOOOOOOOXXXXXXXX. ",
114 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
115 " .XXXXXXOOOOOOOOOOXXXXXXX. ",
116 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
117 " .XXXXXOOOOOOOXXXXXXXXXXX. ",
118 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
119 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
120 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
121 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
122 " .XXXXXXXXXXXXXXXXXXXXXXX. ",
123 " ......................... "};
126 #if (GTK_MINOR_VERSION > 0)
128 #include "gtk/gtkdnd.h"
129 #include "gtk/gtkselection.h"
131 // ----------------------------------------------------------------------------
133 // ----------------------------------------------------------------------------
135 static void target_drag_leave( GtkWidget
*WXUNUSED(widget
),
136 GdkDragContext
*context
,
137 guint
WXUNUSED(time
),
138 wxDropTarget
*drop_target
)
140 /* inform the wxDropTarget about the current GdkDragContext.
141 this is only valid for the duration of this call */
142 drop_target
->SetDragContext( context
);
144 /* we don't need return values. this event is just for
146 drop_target
->OnLeave();
148 /* this has to be done because GDK has no "drag_enter" event */
149 drop_target
->m_firstMotion
= TRUE
;
151 /* after this, invalidate the drop_target's GdkDragContext */
152 drop_target
->SetDragContext( (GdkDragContext
*) NULL
);
155 // ----------------------------------------------------------------------------
157 // ----------------------------------------------------------------------------
159 static gboolean
target_drag_motion( GtkWidget
*WXUNUSED(widget
),
160 GdkDragContext
*context
,
164 wxDropTarget
*drop_target
)
166 /* Owen Taylor: "if the coordinates not in a drop zone,
167 return FALSE, otherwise call gtk_drag_status() and
170 /* inform the wxDropTarget about the current GdkDragContext.
171 this is only valid for the duration of this call */
172 drop_target
->SetDragContext( context
);
174 if (drop_target
->m_firstMotion
)
176 /* the first "drag_motion" event substitutes a "drag_enter" event */
177 drop_target
->OnEnter();
180 /* give program a chance to react (i.e. to say no by returning FALSE) */
181 bool ret
= drop_target
->OnMove( x
, y
);
183 /* we don't yet handle which "actions" (i.e. copy or move)
184 the target accepts. so far we simply accept the
185 suggested action. TODO. */
187 gdk_drag_status( context
, context
->suggested_action
, time
);
189 /* after this, invalidate the drop_target's GdkDragContext */
190 drop_target
->SetDragContext( (GdkDragContext
*) NULL
);
192 /* this has to be done because GDK has no "drag_enter" event */
193 drop_target
->m_firstMotion
= FALSE
;
198 // ----------------------------------------------------------------------------
200 // ----------------------------------------------------------------------------
202 static gboolean
target_drag_drop( GtkWidget
*widget
,
203 GdkDragContext
*context
,
207 wxDropTarget
*drop_target
)
209 /* Owen Taylor: "if the drop is not in a drop zone,
210 return FALSE, otherwise, if you aren't accepting
211 the drop, call gtk_drag_finish() with success == FALSE
212 otherwise call gtk_drag_data_get()" */
214 /* this seems to make a difference between not accepting
215 due to wrong target area and due to wrong format. let
216 us hope that this is not required.. */
218 /* inform the wxDropTarget about the current GdkDragContext.
219 this is only valid for the duration of this call */
220 drop_target
->SetDragContext( context
);
222 /* inform the wxDropTarget about the current drag widget.
223 this is only valid for the duration of this call */
224 drop_target
->SetDragWidget( widget
);
226 /* inform the wxDropTarget about the current drag time.
227 this is only valid for the duration of this call */
228 drop_target
->SetDragTime( time
);
230 bool ret
= drop_target
->OnDrop( x
, y
);
234 /* this should trigger an "drag_data_received" event */
235 gtk_drag_get_data( widget
,
237 GPOINTER_TO_INT (context
->targets
->data
),
242 /* cancel the whole thing */
243 gtk_drag_finish( context
,
244 FALSE
, /* no success */
245 FALSE
, /* don't delete data on dropping side */
249 /* after this, invalidate the drop_target's GdkDragContext */
250 drop_target
->SetDragContext( (GdkDragContext
*) NULL
);
252 /* after this, invalidate the drop_target's drag widget */
253 drop_target
->SetDragWidget( (GtkWidget
*) NULL
);
255 /* this has to be done because GDK has no "drag_enter" event */
256 drop_target
->m_firstMotion
= TRUE
;
261 // ----------------------------------------------------------------------------
262 // "drag_data_received"
263 // ----------------------------------------------------------------------------
265 static void target_drag_data_received( GtkWidget
*WXUNUSED(widget
),
266 GdkDragContext
*context
,
269 GtkSelectionData
*data
,
270 guint
WXUNUSED(info
),
272 wxDropTarget
*drop_target
)
274 /* Owen Taylor: "call gtk_drag_finish() with
277 /* strangely, we get a "drag_data_received" event even when
278 we don't request them. this checks this. */
279 if (!drop_target
->m_currentDataObject
) return;
281 wxDataObject
*data_object
= drop_target
->m_currentDataObject
;
283 if ((data
->length
<= 0) || (data
->format
!= 8))
285 /* negative data length and non 8-bit data format
286 qualifies for junk */
287 gtk_drag_finish (context
, FALSE
, FALSE
, time
);
291 wxASSERT_MSG( data
->target
== data_object
->GetFormat().GetAtom(), "DnD GetData target mismatch." );
293 if (data_object
->GetFormat().GetType() == wxDF_TEXT
)
295 wxTextDataObject
*text_object
= (wxTextDataObject
*)data_object
;
296 text_object
->SetText( (const char*)data
->data
);
299 if (data_object
->GetFormat().GetType() == wxDF_FILENAME
)
303 if (data_object
->GetFormat().GetType() == wxDF_PRIVATE
)
305 wxPrivateDataObject
*priv_object
= (wxPrivateDataObject
*)data_object
;
306 priv_object
->SetData( (const char*)data
->data
, (size_t)data
->length
);
309 /* tell wxDropTarget that data transfer was successfull */
310 drop_target
->m_dataRetrieveSuccess
= TRUE
;
312 /* tell GTK that data transfer was successfull */
313 gtk_drag_finish( context
, TRUE
, FALSE
, time
);
316 /* tell wxDropTarget that data has arrived (or not) */
317 drop_target
->m_waiting
= FALSE
;
320 // ----------------------------------------------------------------------------
322 // ----------------------------------------------------------------------------
324 wxDropTarget::wxDropTarget()
326 m_firstMotion
= TRUE
;
327 m_dragContext
= (GdkDragContext
*) NULL
;
328 m_dragWidget
= (GtkWidget
*) NULL
;
330 m_currentDataObject
= (wxDataObject
*) NULL
;
331 m_dataRetrieveSuccess
= FALSE
;
334 wxDropTarget::~wxDropTarget()
338 void wxDropTarget::OnEnter()
342 void wxDropTarget::OnLeave()
346 bool wxDropTarget::OnMove( int WXUNUSED(x
), int WXUNUSED(y
) )
351 bool wxDropTarget::OnDrop( int WXUNUSED(x
), int WXUNUSED(y
) )
356 bool wxDropTarget::IsSupported( wxDataFormat format
)
358 if (!m_dragContext
) return FALSE
;
360 GList
*child
= m_dragContext
->targets
;
363 GdkAtom formatAtom
= (GdkAtom
) GPOINTER_TO_INT(child
->data
);
365 /* char *name = gdk_atom_name( formatAtom );
366 if (name) printf( "Format available: %s.\n", name ); */
368 if (formatAtom
== format
.GetAtom()) return TRUE
;
375 bool wxDropTarget::GetData( wxDataObject
*data
)
377 if (!m_dragContext
) return FALSE
;
378 if (!m_dragWidget
) return FALSE
;
380 m_currentDataObject
= data
;
381 m_dataRetrieveSuccess
= FALSE
;
383 /* this should trigger an "drag_data_received" event */
384 gtk_drag_get_data( m_dragWidget
,
386 data
->GetFormat().GetAtom(),
389 /* wait for the "drag_data_received" event */
391 while (m_waiting
) gtk_main_iteration();
393 m_currentDataObject
= (wxDataObject
*) NULL
;
395 return m_dataRetrieveSuccess
;
398 void wxDropTarget::UnregisterWidget( GtkWidget
*widget
)
400 wxCHECK_RET( widget
!= NULL
, "unregister widget is NULL" );
402 gtk_drag_dest_unset( widget
);
404 gtk_signal_disconnect_by_func( GTK_OBJECT(widget
),
405 GTK_SIGNAL_FUNC(target_drag_leave
), (gpointer
) this );
407 gtk_signal_disconnect_by_func( GTK_OBJECT(widget
),
408 GTK_SIGNAL_FUNC(target_drag_motion
), (gpointer
) this );
410 gtk_signal_disconnect_by_func( GTK_OBJECT(widget
),
411 GTK_SIGNAL_FUNC(target_drag_drop
), (gpointer
) this );
413 gtk_signal_disconnect_by_func( GTK_OBJECT(widget
),
414 GTK_SIGNAL_FUNC(target_drag_data_received
), (gpointer
) this );
417 void wxDropTarget::RegisterWidget( GtkWidget
*widget
)
419 wxCHECK_RET( widget
!= NULL
, "register widget is NULL" );
421 /* gtk_drag_dest_set() determines what default behaviour we'd like
422 GTK to supply. we don't want to specify out targets (=formats)
423 or actions in advance (i.e. not GTK_DEST_DEFAULT_MOTION and
424 not GTK_DEST_DEFAULT_DROP). instead we react individually to
425 "drag_motion" and "drag_drop" events. this makes it possible
426 to allow dropping on only a small area. we should set
427 GTK_DEST_DEFAULT_HIGHLIGHT as this will switch on the nice
428 highlighting if dragging over standard controls, but this
429 seems to be broken without the other two. */
431 gtk_drag_dest_set( widget
,
432 (GtkDestDefaults
) 0, /* no default behaviour */
433 (GtkTargetEntry
*) NULL
, /* we don't supply any formats here */
434 0, /* number of targets = 0 */
435 (GdkDragAction
) 0 ); /* we don't supply any actions here */
437 gtk_signal_connect( GTK_OBJECT(widget
), "drag_leave",
438 GTK_SIGNAL_FUNC(target_drag_leave
), (gpointer
) this );
440 gtk_signal_connect( GTK_OBJECT(widget
), "drag_motion",
441 GTK_SIGNAL_FUNC(target_drag_motion
), (gpointer
) this );
443 gtk_signal_connect( GTK_OBJECT(widget
), "drag_drop",
444 GTK_SIGNAL_FUNC(target_drag_drop
), (gpointer
) this );
446 gtk_signal_connect( GTK_OBJECT(widget
), "drag_data_received",
447 GTK_SIGNAL_FUNC(target_drag_data_received
), (gpointer
) this );
450 //-------------------------------------------------------------------------
452 //-------------------------------------------------------------------------
454 bool wxTextDropTarget::OnMove( int WXUNUSED(x
), int WXUNUSED(y
) )
456 return IsSupported( wxDF_TEXT
); // same as "STRING"
459 bool wxTextDropTarget::OnDrop( int x
, int y
)
461 if (!IsSupported( wxDF_TEXT
)) return FALSE
;
463 wxTextDataObject data
;
464 if (!GetData( &data
)) return FALSE
;
466 OnDropText( x
, y
, data
.GetText() );
470 //-------------------------------------------------------------------------
471 // wxPrivateDropTarget
472 //-------------------------------------------------------------------------
474 wxPrivateDropTarget::wxPrivateDropTarget()
476 m_id
= wxTheApp
->GetAppName();
479 wxPrivateDropTarget::wxPrivateDropTarget( const wxString
&id
)
484 bool wxPrivateDropTarget::OnMove( int WXUNUSED(x
), int WXUNUSED(y
) )
486 return IsSupported( m_id
);
489 bool wxPrivateDropTarget::OnDrop( int x
, int y
)
491 if (!IsSupported( m_id
)) return FALSE
;
493 wxPrivateDataObject data
;
494 if (!GetData( &data
)) return FALSE
;
496 OnDropData( x
, y
, data
.GetData(), data
.GetSize() );
501 //----------------------------------------------------------------------------
502 // A drop target which accepts files (dragged from File Manager or Explorer)
503 //----------------------------------------------------------------------------
505 bool wxFileDropTarget::OnMove( int WXUNUSED(x
), int WXUNUSED(y
) )
507 return IsSupported( wxDF_FILENAME
); // same as "file:ALL"
510 bool wxFileDropTarget::OnDrop( int x
, int y
)
512 return IsSupported( wxDF_FILENAME
); // same as "file:ALL"
515 void wxFileDropTarget::OnData( int x
, int y
)
517 wxFileDataObject data
;
518 if (!GetData( &data
)) return;
520 /* get number of substrings /root/mytext.txt/0/root/myothertext.txt/0/0 */
523 size_t size
= data
.GetFiles().Length();
524 char *text
= WXSTRINGCAST data
.GetFiles();
525 for ( i
= 0; i
< size
; i
++)
526 if (text
[i
] == 0) number
++;
528 if (number
== 0) return;
530 char **files
= new char*[number
];
532 text
= WXSTRINGCAST data
.GetFiles();
533 for (i
= 0; i
< number
; i
++)
536 int len
= strlen( text
);
540 OnDropFiles( x
, y
, number
, files
);
545 //-------------------------------------------------------------------------
547 //-------------------------------------------------------------------------
550 wxDropSource::wxDropSource( wxWindow
*win
, const wxIcon
&go
, const wxIcon
&stop
)
552 g_blockEventsOnDrag
= TRUE
;
555 m_widget
= win
->m_widget
;
556 if (win
->m_wxwindow
) m_widget
= win
->m_wxwindow
;
558 m_data
= (wxDataBroker
*) NULL
;
559 m_retValue
= wxDragCancel
;
561 m_defaultCursor
= wxCursor( wxCURSOR_NO_ENTRY
);
562 m_goaheadCursor
= wxCursor( wxCURSOR_HAND
);
565 if (wxNullIcon
== go
) m_goIcon
= wxIcon( page_xpm
);
567 if (wxNullIcon
== stop
) m_stopIcon
= wxIcon( gv_xpm
);
570 wxDropSource::wxDropSource( wxDataObject
*data
, wxWindow
*win
, const wxIcon
&go
, const wxIcon
&stop
)
572 g_blockEventsOnDrag
= TRUE
;
575 m_widget
= win
->m_widget
;
576 if (win
->m_wxwindow
) m_widget
= win
->m_wxwindow
;
577 m_retValue
= wxDragCancel
;
581 m_data
= new wxDataBroker();
586 m_data
= (wxDataBroker
*) NULL
;
589 m_defaultCursor
= wxCursor( wxCURSOR_NO_ENTRY
);
590 m_goaheadCursor
= wxCursor( wxCURSOR_HAND
);
593 if (wxNullIcon
== go
) m_goIcon
= wxIcon( page_xpm
);
595 if (wxNullIcon
== stop
) m_stopIcon
= wxIcon( gv_xpm
);
598 wxDropSource::wxDropSource( wxDataBroker
*data
, wxWindow
*win
)
600 g_blockEventsOnDrag
= TRUE
;
603 m_widget
= win
->m_widget
;
604 if (win
->m_wxwindow
) m_widget
= win
->m_wxwindow
;
605 m_retValue
= wxDragCancel
;
609 m_defaultCursor
= wxCursor( wxCURSOR_NO_ENTRY
);
610 m_goaheadCursor
= wxCursor( wxCURSOR_HAND
);
613 void wxDropSource::SetData( wxDataObject
*data
)
615 if (m_data
) delete m_data
;
619 m_data
= new wxDataBroker();
624 m_data
= (wxDataBroker
*) NULL
;
628 void wxDropSource::SetData( wxDataBroker
*data
)
630 if (m_data
) delete m_data
;
635 wxDropSource::~wxDropSource(void)
637 if (m_data
) delete m_data
;
639 g_blockEventsOnDrag
= FALSE
;
642 wxDragResult
wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove
) )
644 wxASSERT_MSG( m_data
, "wxDragSource: no data" );
646 if (!m_data
) return (wxDragResult
) wxDragNone
;
648 static GtkWidget
*drag_icon
= (GtkWidget
*) NULL
;
649 static GtkWidget
*drop_icon
= (GtkWidget
*) NULL
;
651 GdkPoint hotspot_1
= {0,-5 };
656 drag_icon = shape_create_icon ( m_stopIcon,
657 440, 140, 0,0, GTK_WINDOW_POPUP);
659 gtk_signal_connect (GTK_OBJECT (drag_icon), "destroy",
660 GTK_SIGNAL_FUNC(gtk_widget_destroyed),
663 gtk_widget_hide (drag_icon);
667 GdkPoint hotspot_2
= {-5,-5};
672 drop_icon = shape_create_icon ( m_goIcon,
673 440, 140, 0,0, GTK_WINDOW_POPUP);
675 gtk_signal_connect (GTK_OBJECT (drop_icon), "destroy",
676 GTK_SIGNAL_FUNC(gtk_widget_destroyed),
679 gtk_widget_hide (drop_icon);
687 void wxDropSource::RegisterWindow(void)
692 void wxDropSource::UnregisterWindow(void)
694 if (!m_widget
) return;
700 //----------------------------------------------------------------------------
702 //----------------------------------------------------------------------------
704 GtkWidget
*shape_create_icon ( const wxIcon
&shape
,
711 //-----------------------------------------------------------------------------
713 //-----------------------------------------------------------------------------
715 wxDropSource
*gs_currentDropSource
= (wxDropSource
*) NULL
;
717 //-----------------------------------------------------------------------------
718 // "drop_enter_event"
719 //-----------------------------------------------------------------------------
721 static void gtk_target_enter_callback( GtkWidget
*WXUNUSED(widget
),
722 GdkEventDropEnter
*WXUNUSED(event
),
723 wxDropTarget
*target
)
729 //-----------------------------------------------------------------------------
730 // "drop_leave_event"
731 //-----------------------------------------------------------------------------
733 static void gtk_target_leave_callback( GtkWidget
*WXUNUSED(widget
),
734 GdkEventDropLeave
*WXUNUSED(event
),
735 wxDropTarget
*target
)
741 //-----------------------------------------------------------------------------
742 // "drop_data_available_event"
743 //-----------------------------------------------------------------------------
745 static void gtk_target_callback( GtkWidget
*widget
,
746 GdkEventDropDataAvailable
*event
,
747 wxDropTarget
*target
)
753 gdk_window_get_pointer( widget
->window
, &x
, &y
, (GdkModifierType
*) NULL
);
755 printf( "Drop data is of type %s.\n", event->data_type );
757 target
->OnDrop( x
, y
, (const void*)event
->data
, (size_t)event
->data_numbytes
);
761 g_free (event->data);
762 g_free (event->data_type);
766 // ----------------------------------------------------------------------------
768 // ----------------------------------------------------------------------------
770 wxDropTarget::wxDropTarget()
772 m_format
= (wxDataFormat
*) NULL
;
775 wxDropTarget::~wxDropTarget()
777 if (m_format
) delete m_format
;
780 wxDataFormat
&wxDropTarget::GetFormat(size_t n
) const
785 void wxDropTarget::UnregisterWidget( GtkWidget
*widget
)
789 gtk_signal_disconnect_by_func( GTK_OBJECT(widget
),
790 GTK_SIGNAL_FUNC(gtk_target_callback
), (gpointer
) this );
792 gtk_widget_dnd_drop_set( widget
, FALSE
, (gchar
**) NULL
, 0, FALSE
);
795 void wxDropTarget::RegisterWidget( GtkWidget
*widget
)
800 for ( size_t i
= 0; i
< GetFormatCount(); i
++ )
802 switch (GetFormat(i
).GetType())
806 if (i
> 0) formats
+= ";";
807 formats
+= "text/plain";
813 if (i
> 0) formats
+= ";";
814 formats
+= "file:ALL";
820 if (i
> 0) formats
+= ";";
821 wxPrivateDropTarget
*pdt
= (wxPrivateDropTarget
*)this;
822 formats
+= pdt
->GetId();
831 char *str
= WXSTRINGCAST formats
;
833 gtk_widget_dnd_drop_set( widget
, TRUE
, &str
, valid
, FALSE
);
835 gtk_signal_connect( GTK_OBJECT(widget
), "drop_data_available_event",
836 GTK_SIGNAL_FUNC(gtk_target_callback
), (gpointer
) this );
838 gtk_signal_connect( GTK_OBJECT(widget
), "drop_enter_event",
839 GTK_SIGNAL_FUNC(gtk_target_enter_callback
), (gpointer
) this );
841 gtk_signal_connect( GTK_OBJECT(widget
), "drop_leave_event",
842 GTK_SIGNAL_FUNC(gtk_target_leave_callback
), (gpointer
) this );
845 // ----------------------------------------------------------------------------
847 // ----------------------------------------------------------------------------
849 wxTextDropTarget::wxTextDropTarget()
851 m_format
= new wxDataFormat( wxDF_TEXT
);
854 bool wxTextDropTarget::OnDrop( long x
, long y
, const void *data
, size_t WXUNUSED(size
) )
856 OnDropText( x
, y
, (const char*)data
);
860 bool wxTextDropTarget::OnDropText( long x
, long y
, const char *psz
)
863 printf( "Got dropped text: %s.\n", psz );
864 printf( "At x: %d, y: %d.\n", (int)x, (int)y );
869 size_t wxTextDropTarget::GetFormatCount() const
874 // ----------------------------------------------------------------------------
875 // wxPrivateDropTarget
876 // ----------------------------------------------------------------------------
878 wxPrivateDropTarget::wxPrivateDropTarget()
880 m_id
= wxTheApp
->GetAppName();
881 m_format
= new wxDataFormat( m_id
);
884 void wxPrivateDropTarget::SetId( const wxString
& id
)
887 m_format
->SetId( id
);
890 size_t wxPrivateDropTarget::GetFormatCount() const
895 // ----------------------------------------------------------------------------
897 // ----------------------------------------------------------------------------
899 wxFileDropTarget::wxFileDropTarget()
901 m_format
= new wxDataFormat( wxDF_FILENAME
);
904 bool wxFileDropTarget::OnDropFiles( long x
, long y
, size_t nFiles
, const char * const aszFiles
[] )
906 printf( "Got %d dropped files.\n", (int)nFiles
);
907 printf( "At x: %d, y: %d.\n", (int)x
, (int)y
);
909 for (size_t i
= 0; i
< nFiles
; i
++)
911 printf( aszFiles
[i
] );
918 bool wxFileDropTarget::OnDrop(long x
, long y
, const void *data
, size_t size
)
922 char *text
= (char*) data
;
923 for ( i
= 0; i
< size
; i
++)
924 if (text
[i
] == 0) number
++;
926 if (number
== 0) return TRUE
;
928 char **files
= new char*[number
];
931 for (i
= 0; i
< number
; i
++)
934 int len
= strlen( text
);
938 bool ret
= OnDropFiles( x
, y
, 1, files
);
945 size_t wxFileDropTarget::GetFormatCount() const
950 //-------------------------------------------------------------------------
952 //-------------------------------------------------------------------------
955 shape_motion (GtkWidget
*widget
,
956 GdkEventMotion
* /*event*/);
958 //-----------------------------------------------------------------------------
959 // "drag_request_event"
960 //-----------------------------------------------------------------------------
962 void gtk_drag_callback( GtkWidget
*widget
, GdkEventDragRequest
*event
, wxDropSource
*source
)
964 wxDataBroker
*data
= source
->m_data
;
968 wxNode
*node
= data
->m_dataObjects
.First();
970 wxDataObject
*dobj
= (wxDataObject
*) node
->Data();
972 if ((strcmp(event
->data_type
,"file:ALL") == 0) &&
973 (dobj
->GetFormat().GetType() == wxDF_FILENAME
))
975 wxFileDataObject
*file_object
= (wxFileDataObject
*) dobj
;
977 wxString text
= file_object
->GetFiles();
979 char *s
= WXSTRINGCAST text
;
981 gtk_widget_dnd_data_set( widget
,
984 (int) text
.Length()+1 );
986 source
->m_retValue
= wxDragCopy
;
991 if ((strcmp(event
->data_type
,"text/plain") == 0) &&
992 (dobj
->GetFormat().GetType() == wxDF_TEXT
))
994 wxTextDataObject
*text_object
= (wxTextDataObject
*) dobj
;
996 wxString text
= text_object
->GetText();
998 char *s
= WXSTRINGCAST text
;
1000 gtk_widget_dnd_data_set( widget
,
1003 (int) text
.Length()+1 );
1005 source
->m_retValue
= wxDragCopy
;
1010 if (dobj
->GetFormat().GetType() == wxDF_PRIVATE
)
1012 wxPrivateDataObject
*pdo
= (wxPrivateDataObject
*) dobj
;
1014 if (pdo
->GetId() == event
->data_type
)
1016 gtk_widget_dnd_data_set( widget
,
1018 (unsigned char*) pdo
->GetData(),
1019 (int) pdo
->GetSize() );
1021 source
->m_retValue
= wxDragCopy
;
1027 node
= node
->Next();
1031 wxDropSource::wxDropSource( wxWindow
*win
, const wxIcon
&go
, const wxIcon
&stop
)
1033 g_blockEventsOnDrag
= TRUE
;
1036 m_widget
= win
->m_widget
;
1037 if (win
->m_wxwindow
) m_widget
= win
->m_wxwindow
;
1039 m_data
= (wxDataBroker
*) NULL
;
1040 m_retValue
= wxDragCancel
;
1042 m_defaultCursor
= wxCursor( wxCURSOR_NO_ENTRY
);
1043 m_goaheadCursor
= wxCursor( wxCURSOR_HAND
);
1046 if (wxNullIcon
== go
) m_goIcon
= wxIcon( page_xpm
);
1048 if (wxNullIcon
== stop
) m_stopIcon
= wxIcon( gv_xpm
);
1051 wxDropSource::wxDropSource( wxDataObject
*data
, wxWindow
*win
, const wxIcon
&go
, const wxIcon
&stop
)
1053 g_blockEventsOnDrag
= TRUE
;
1056 m_widget
= win
->m_widget
;
1057 if (win
->m_wxwindow
) m_widget
= win
->m_wxwindow
;
1058 m_retValue
= wxDragCancel
;
1062 m_data
= new wxDataBroker();
1063 m_data
->Add( data
);
1067 m_data
= (wxDataBroker
*) NULL
;
1070 m_defaultCursor
= wxCursor( wxCURSOR_NO_ENTRY
);
1071 m_goaheadCursor
= wxCursor( wxCURSOR_HAND
);
1074 if (wxNullIcon
== go
) m_goIcon
= wxIcon( page_xpm
);
1076 if (wxNullIcon
== stop
) m_stopIcon
= wxIcon( gv_xpm
);
1079 wxDropSource::wxDropSource( wxDataBroker
*data
, wxWindow
*win
)
1081 g_blockEventsOnDrag
= TRUE
;
1084 m_widget
= win
->m_widget
;
1085 if (win
->m_wxwindow
) m_widget
= win
->m_wxwindow
;
1086 m_retValue
= wxDragCancel
;
1090 m_defaultCursor
= wxCursor( wxCURSOR_NO_ENTRY
);
1091 m_goaheadCursor
= wxCursor( wxCURSOR_HAND
);
1094 void wxDropSource::SetData( wxDataObject
*data
)
1096 if (m_data
) delete m_data
;
1100 m_data
= new wxDataBroker();
1101 m_data
->Add( data
);
1105 m_data
= (wxDataBroker
*) NULL
;
1109 void wxDropSource::SetData( wxDataBroker
*data
)
1111 if (m_data
) delete m_data
;
1116 wxDropSource::~wxDropSource(void)
1118 if (m_data
) delete m_data
;
1120 g_blockEventsOnDrag
= FALSE
;
1123 wxDragResult
wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove
) )
1125 if (gdk_dnd
.dnd_grabbed
) return (wxDragResult
) wxDragNone
;
1126 if (gdk_dnd
.drag_really
) return (wxDragResult
) wxDragNone
;
1128 wxASSERT_MSG( m_data
, "wxDragSource: no data" );
1130 if (!m_data
) return (wxDragResult
) wxDragNone
;
1132 static GtkWidget
*drag_icon
= (GtkWidget
*) NULL
;
1133 static GtkWidget
*drop_icon
= (GtkWidget
*) NULL
;
1135 GdkPoint hotspot_1
= {0,-5 };
1139 drag_icon
= shape_create_icon ( m_stopIcon
,
1140 440, 140, 0,0, GTK_WINDOW_POPUP
);
1142 gtk_signal_connect (GTK_OBJECT (drag_icon
), "destroy",
1143 GTK_SIGNAL_FUNC(gtk_widget_destroyed
),
1146 gtk_widget_hide (drag_icon
);
1149 GdkPoint hotspot_2
= {-5,-5};
1153 drop_icon
= shape_create_icon ( m_goIcon
,
1154 440, 140, 0,0, GTK_WINDOW_POPUP
);
1156 gtk_signal_connect (GTK_OBJECT (drop_icon
), "destroy",
1157 GTK_SIGNAL_FUNC(gtk_widget_destroyed
),
1160 gtk_widget_hide (drop_icon
);
1164 gdk_dnd_set_drag_shape( drag_icon
->window
,
1170 GdkWindowPrivate
*wp
= (GdkWindowPrivate
*) m_widget
->window
;
1174 gdk_dnd
.drag_perhaps
= TRUE
;
1176 gdk_dnd
.dnd_drag_start
.x
= 5;
1177 gdk_dnd
.dnd_drag_start
.y
= 5;
1178 gdk_dnd
.real_sw
= wp
;
1180 if (gdk_dnd
.drag_startwindows
)
1182 g_free( gdk_dnd
.drag_startwindows
);
1183 gdk_dnd
.drag_startwindows
= (GdkWindow
**) NULL
;
1185 gdk_dnd
.drag_numwindows
= gdk_dnd
.drag_really
= 0;
1187 XWindowAttributes dnd_winattr
;
1188 XGetWindowAttributes( gdk_display
, wp
->xwindow
, &dnd_winattr
);
1189 wp
->dnd_drag_savedeventmask
= dnd_winattr
.your_event_mask
;
1191 gdk_dnd_drag_addwindow( m_widget
->window
);
1193 GdkEventDragBegin ev
;
1194 ev
.type
= GDK_DRAG_BEGIN
;
1195 ev
.window
= m_widget
->window
;
1197 ev
.u
.flags
.protocol_version
= DND_PROTOCOL_VERSION
;
1199 gdk_event_put( (GdkEvent
*)&ev
);
1201 XGrabPointer( gdk_display
, wp
->xwindow
, False
,
1202 ButtonMotionMask
| ButtonPressMask
| ButtonReleaseMask
| PointerMotionMask
,
1203 GrabModeAsync
, GrabModeAsync
, gdk_root_window
, None
, CurrentTime
);
1205 gdk_dnd_set_drag_cursors( m_defaultCursor
.GetCursor(), m_goaheadCursor
.GetCursor() );
1207 gdk_dnd
.dnd_grabbed
= TRUE
;
1208 gdk_dnd
.drag_really
= 1;
1212 wxGetMousePosition( &x
, &y
);
1214 gdk_dnd_display_drag_cursor( x
, y
, FALSE
, TRUE
);
1216 gs_currentDropSource
= this;
1218 while (gdk_dnd
.drag_really
|| gdk_dnd
.drag_perhaps
) wxYield();
1220 gs_currentDropSource
= (wxDropSource
*) NULL
;
1224 g_blockEventsOnDrag
= FALSE
;
1229 void wxDropSource::RegisterWindow(void)
1231 if (!m_data
) return;
1235 wxNode
*node
= m_data
->m_dataObjects
.First();
1238 wxDataObject
* dobj
= (wxDataObject
*) node
->Data();
1240 switch (dobj
->GetFormat().GetType())
1244 formats
+= "text/plain";
1249 formats
+= "file:ALL";
1254 wxPrivateDataObject
* pdo
= (wxPrivateDataObject
*) m_data
;
1255 formats
+= pdo
->GetId();
1261 node
= node
->Next();
1264 char *str
= WXSTRINGCAST formats
;
1266 gtk_widget_dnd_drag_set( m_widget
, TRUE
, &str
, 1 );
1268 gtk_signal_connect( GTK_OBJECT(m_widget
), "drag_request_event",
1269 GTK_SIGNAL_FUNC(gtk_drag_callback
), (gpointer
)this );
1272 void wxDropSource::UnregisterWindow(void)
1274 if (!m_widget
) return;
1276 gtk_widget_dnd_drag_set( m_widget
, FALSE
, (gchar
**) NULL
, 0 );
1278 gtk_signal_disconnect_by_data( GTK_OBJECT(m_widget
), (gpointer
)this );
1285 static GdkWindow
*root_win
= (GdkWindow
*) NULL
;
1287 typedef struct _cursoroffset
{gint x
,y
;} CursorOffset
;
1290 shape_pressed (GtkWidget
*widget
, GdkEventButton
*event
)
1294 /* ignore double and triple click */
1295 if (event
->type
!= GDK_BUTTON_PRESS
)
1298 p
= (CursorOffset
*)gtk_object_get_user_data (GTK_OBJECT(widget
));
1299 p
->x
= (int) event
->x
;
1300 p
->y
= (int) event
->y
;
1302 gtk_grab_add (widget
);
1303 gdk_pointer_grab (widget
->window
, TRUE
,
1305 (GDK_BUTTON_RELEASE_MASK
|
1306 GDK_BUTTON_MOTION_MASK
|
1307 GDK_POINTER_MOTION_HINT_MASK
),
1309 (GdkCursor
*) NULL
, 0);
1314 shape_released (GtkWidget
*widget
)
1316 gtk_grab_remove (widget
);
1317 gdk_pointer_ungrab (0);
1321 shape_motion (GtkWidget
*widget
,
1322 GdkEventMotion
* /*event*/ )
1326 GdkModifierType mask
;
1328 p
= (CursorOffset
*)gtk_object_get_user_data (GTK_OBJECT (widget
));
1331 * Can't use event->x / event->y here
1332 * because I need absolute coordinates.
1335 gdk_window_get_pointer (root_win
, &xp
, &yp
, &mask
);
1336 gtk_widget_set_uposition (widget
, xp
- p
->x
, yp
- p
->y
);
1338 if (gs_currentDropSource
) gs_currentDropSource
->GiveFeedback( wxDragCopy
, FALSE
);
1342 shape_create_icon (const wxIcon
&shape
,
1350 * GDK_WINDOW_TOPLEVEL works also, giving you a title border
1352 GtkWidget
*window
= gtk_window_new ((GtkWindowType
)window_type
);
1354 GtkWidget
*fixed
= gtk_fixed_new ();
1355 gtk_widget_set_usize (fixed
, 100,100);
1356 gtk_container_add (GTK_CONTAINER (window
), fixed
);
1357 gtk_widget_show (fixed
);
1359 gtk_widget_set_events (window
,
1360 gtk_widget_get_events (window
) |
1361 GDK_BUTTON_MOTION_MASK
|
1362 GDK_POINTER_MOTION_HINT_MASK
|
1363 GDK_BUTTON_PRESS_MASK
);
1365 gtk_widget_realize (window
);
1367 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
1368 if (shape
.GetMask()) mask
= shape
.GetMask()->GetBitmap();
1370 GtkWidget
*pixmap
= gtk_pixmap_new (shape
.GetPixmap(), mask
);
1371 gtk_fixed_put (GTK_FIXED (fixed
), pixmap
, px
,py
);
1372 gtk_widget_show (pixmap
);
1374 gtk_widget_shape_combine_mask (window
, mask
, px
,py
);
1377 gtk_signal_connect (GTK_OBJECT (window
), "button_press_event",
1378 GTK_SIGNAL_FUNC (shape_pressed
),NULL
);
1379 gtk_signal_connect (GTK_OBJECT (window
), "button_release_event",
1380 GTK_SIGNAL_FUNC (shape_released
),NULL
);
1381 gtk_signal_connect (GTK_OBJECT (window
), "motion_notify_event",
1382 GTK_SIGNAL_FUNC (shape_motion
),NULL
);
1384 CursorOffset
*icon_pos
= g_new (CursorOffset
, 1);
1385 gtk_object_set_user_data(GTK_OBJECT(window
), icon_pos
);
1387 gtk_widget_set_uposition (window
, x
, y
);
1388 gtk_widget_show (window
);
1398 // wxUSE_DRAG_AND_DROP