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"
132 // ----------------------------------------------------------------------------
134 // ----------------------------------------------------------------------------
136 static void target_drag_leave( GtkWidget
*WXUNUSED(widget
),
137 GdkDragContext
*context
,
138 guint
WXUNUSED(time
),
139 wxDropTarget
*drop_target
)
141 /* inform the wxDropTarget about the current GdkDragContext.
142 this is only valid for the duration of this call */
143 drop_target
->SetDragContext( context
);
145 /* we don't need return values. this event is just for
147 drop_target
->OnLeave();
149 /* this has to be done because GDK has no "drag_enter" event */
150 drop_target
->m_firstMotion
= TRUE
;
152 /* after this, invalidate the drop_target's GdkDragContext */
153 drop_target
->SetDragContext( (GdkDragContext
*) NULL
);
156 // ----------------------------------------------------------------------------
158 // ----------------------------------------------------------------------------
160 static gboolean
target_drag_motion( GtkWidget
*WXUNUSED(widget
),
161 GdkDragContext
*context
,
165 wxDropTarget
*drop_target
)
167 /* Owen Taylor: "if the coordinates not in a drop zone,
168 return FALSE, otherwise call gtk_drag_status() and
171 /* inform the wxDropTarget about the current GdkDragContext.
172 this is only valid for the duration of this call */
173 drop_target
->SetDragContext( context
);
175 if (drop_target
->m_firstMotion
)
177 /* the first "drag_motion" event substitutes a "drag_enter" event */
178 drop_target
->OnEnter();
181 /* give program a chance to react (i.e. to say no by returning FALSE) */
182 bool ret
= drop_target
->OnMove( x
, y
);
184 /* we don't yet handle which "actions" (i.e. copy or move)
185 the target accepts. so far we simply accept the
186 suggested action. TODO. */
188 gdk_drag_status( context
, context
->suggested_action
, time
);
190 /* after this, invalidate the drop_target's GdkDragContext */
191 drop_target
->SetDragContext( (GdkDragContext
*) NULL
);
193 /* this has to be done because GDK has no "drag_enter" event */
194 drop_target
->m_firstMotion
= FALSE
;
199 // ----------------------------------------------------------------------------
201 // ----------------------------------------------------------------------------
203 static gboolean
target_drag_drop( GtkWidget
*widget
,
204 GdkDragContext
*context
,
208 wxDropTarget
*drop_target
)
210 /* Owen Taylor: "if the drop is not in a drop zone,
211 return FALSE, otherwise, if you aren't accepting
212 the drop, call gtk_drag_finish() with success == FALSE
213 otherwise call gtk_drag_data_get()" */
215 // printf( "drop.\n" );
217 /* this seems to make a difference between not accepting
218 due to wrong target area and due to wrong format. let
219 us hope that this is not required.. */
221 /* inform the wxDropTarget about the current GdkDragContext.
222 this is only valid for the duration of this call */
223 drop_target
->SetDragContext( context
);
225 /* inform the wxDropTarget about the current drag widget.
226 this is only valid for the duration of this call */
227 drop_target
->SetDragWidget( widget
);
229 /* inform the wxDropTarget about the current drag time.
230 this is only valid for the duration of this call */
231 drop_target
->SetDragTime( time
);
233 bool ret
= drop_target
->OnDrop( x
, y
);
237 /* cancel the whole thing */
238 gtk_drag_finish( context
,
239 FALSE
, /* no success */
240 FALSE
, /* don't delete data on dropping side */
244 /* after this, invalidate the drop_target's GdkDragContext */
245 drop_target
->SetDragContext( (GdkDragContext
*) NULL
);
247 /* after this, invalidate the drop_target's drag widget */
248 drop_target
->SetDragWidget( (GtkWidget
*) NULL
);
250 /* this has to be done because GDK has no "drag_enter" event */
251 drop_target
->m_firstMotion
= TRUE
;
256 // ----------------------------------------------------------------------------
257 // "drag_data_received"
258 // ----------------------------------------------------------------------------
260 static void target_drag_data_received( GtkWidget
*WXUNUSED(widget
),
261 GdkDragContext
*context
,
264 GtkSelectionData
*data
,
265 guint
WXUNUSED(info
),
267 wxDropTarget
*drop_target
)
269 /* Owen Taylor: "call gtk_drag_finish() with
272 // printf( "data received.\n" );
274 if ((data
->length
<= 0) || (data
->format
!= 8))
276 /* negative data length and non 8-bit data format
277 qualifies for junk */
278 gtk_drag_finish (context
, FALSE
, FALSE
, time
);
283 /* inform the wxDropTarget about the current GtkSelectionData.
284 this is only valid for the duration of this call */
285 drop_target
->SetDragData( data
);
287 if (drop_target
->OnData( x
, y
))
289 /* tell GTK that data transfer was successfull */
290 gtk_drag_finish( context
, TRUE
, FALSE
, time
);
294 /* tell GTK that data transfer was not successfull */
295 gtk_drag_finish( context
, FALSE
, FALSE
, time
);
298 /* after this, invalidate the drop_target's drag data */
299 drop_target
->SetDragData( (GtkSelectionData
*) NULL
);
302 //----------------------------------------------------------------------------
304 //----------------------------------------------------------------------------
306 wxDropTarget::wxDropTarget()
308 m_firstMotion
= TRUE
;
309 m_dragContext
= (GdkDragContext
*) NULL
;
310 m_dragWidget
= (GtkWidget
*) NULL
;
311 m_dragData
= (GtkSelectionData
*) NULL
;
315 wxDropTarget::~wxDropTarget()
319 void wxDropTarget::OnEnter()
323 void wxDropTarget::OnLeave()
327 bool wxDropTarget::OnMove( int WXUNUSED(x
), int WXUNUSED(y
) )
332 bool wxDropTarget::OnDrop( int WXUNUSED(x
), int WXUNUSED(y
) )
337 bool wxDropTarget::OnData( int WXUNUSED(x
), int WXUNUSED(y
) )
342 bool wxDropTarget::RequestData( wxDataFormat format
)
344 if (!m_dragContext
) return FALSE
;
345 if (!m_dragWidget
) return FALSE
;
347 /* this should trigger an "drag_data_received" event */
348 gtk_drag_get_data( m_dragWidget
,
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_object
)
377 if (!m_dragData
) return FALSE
;
379 if (m_dragData
->target
!= data_object
->GetFormat().GetAtom()) return FALSE
;
381 if (data_object
->GetFormat().GetType() == wxDF_TEXT
)
383 wxTextDataObject
*text_object
= (wxTextDataObject
*)data_object
;
384 text_object
->SetText( (const char*)m_dragData
->data
);
387 if (data_object
->GetFormat().GetType() == wxDF_FILENAME
)
391 if (data_object
->GetFormat().GetType() == wxDF_PRIVATE
)
393 wxPrivateDataObject
*priv_object
= (wxPrivateDataObject
*)data_object
;
394 priv_object
->SetData( (const char*)m_dragData
->data
, (size_t)m_dragData
->length
);
400 void wxDropTarget::UnregisterWidget( GtkWidget
*widget
)
402 wxCHECK_RET( widget
!= NULL
, _T("unregister widget is NULL") );
404 gtk_drag_dest_unset( widget
);
406 gtk_signal_disconnect_by_func( GTK_OBJECT(widget
),
407 GTK_SIGNAL_FUNC(target_drag_leave
), (gpointer
) this );
409 gtk_signal_disconnect_by_func( GTK_OBJECT(widget
),
410 GTK_SIGNAL_FUNC(target_drag_motion
), (gpointer
) this );
412 gtk_signal_disconnect_by_func( GTK_OBJECT(widget
),
413 GTK_SIGNAL_FUNC(target_drag_drop
), (gpointer
) this );
415 gtk_signal_disconnect_by_func( GTK_OBJECT(widget
),
416 GTK_SIGNAL_FUNC(target_drag_data_received
), (gpointer
) this );
419 void wxDropTarget::RegisterWidget( GtkWidget
*widget
)
421 wxCHECK_RET( widget
!= NULL
, _T("register widget is NULL") );
423 /* gtk_drag_dest_set() determines what default behaviour we'd like
424 GTK to supply. we don't want to specify out targets (=formats)
425 or actions in advance (i.e. not GTK_DEST_DEFAULT_MOTION and
426 not GTK_DEST_DEFAULT_DROP). instead we react individually to
427 "drag_motion" and "drag_drop" events. this makes it possible
428 to allow dropping on only a small area. we should set
429 GTK_DEST_DEFAULT_HIGHLIGHT as this will switch on the nice
430 highlighting if dragging over standard controls, but this
431 seems to be broken without the other two. */
433 gtk_drag_dest_set( widget
,
434 (GtkDestDefaults
) 0, /* no default behaviour */
435 (GtkTargetEntry
*) NULL
, /* we don't supply any formats here */
436 0, /* number of targets = 0 */
437 (GdkDragAction
) 0 ); /* we don't supply any actions here */
439 gtk_signal_connect( GTK_OBJECT(widget
), "drag_leave",
440 GTK_SIGNAL_FUNC(target_drag_leave
), (gpointer
) this );
442 gtk_signal_connect( GTK_OBJECT(widget
), "drag_motion",
443 GTK_SIGNAL_FUNC(target_drag_motion
), (gpointer
) this );
445 gtk_signal_connect( GTK_OBJECT(widget
), "drag_drop",
446 GTK_SIGNAL_FUNC(target_drag_drop
), (gpointer
) this );
448 gtk_signal_connect( GTK_OBJECT(widget
), "drag_data_received",
449 GTK_SIGNAL_FUNC(target_drag_data_received
), (gpointer
) this );
452 //-------------------------------------------------------------------------
454 //-------------------------------------------------------------------------
456 bool wxTextDropTarget::OnMove( int WXUNUSED(x
), int WXUNUSED(y
) )
458 return IsSupported( wxDF_TEXT
);
461 bool wxTextDropTarget::OnDrop( int WXUNUSED(x
), int WXUNUSED(y
) )
463 if (IsSupported( wxDF_TEXT
))
465 RequestData( wxDF_TEXT
);
472 bool wxTextDropTarget::OnData( int x
, int y
)
474 wxTextDataObject data
;
475 if (!GetData( &data
)) return FALSE
;
477 OnDropText( x
, y
, data
.GetText().mbc_str() );
482 //-------------------------------------------------------------------------
483 // wxPrivateDropTarget
484 //-------------------------------------------------------------------------
486 wxPrivateDropTarget::wxPrivateDropTarget()
488 m_id
= wxTheApp
->GetAppName();
491 wxPrivateDropTarget::wxPrivateDropTarget( const wxString
&id
)
496 bool wxPrivateDropTarget::OnMove( int WXUNUSED(x
), int WXUNUSED(y
) )
498 return IsSupported( m_id
);
501 bool wxPrivateDropTarget::OnDrop( int WXUNUSED(x
), int WXUNUSED(y
) )
503 if (!IsSupported( m_id
))
512 bool wxPrivateDropTarget::OnData( int x
, int y
)
514 if (!IsSupported( m_id
)) return FALSE
;
516 wxPrivateDataObject data
;
517 if (!GetData( &data
)) return FALSE
;
519 OnDropData( x
, y
, data
.GetData(), data
.GetSize() );
524 //----------------------------------------------------------------------------
525 // A drop target which accepts files (dragged from File Manager or Explorer)
526 //----------------------------------------------------------------------------
528 bool wxFileDropTarget::OnMove( int WXUNUSED(x
), int WXUNUSED(y
) )
530 return IsSupported( wxDF_FILENAME
);
533 bool wxFileDropTarget::OnDrop( int x
, int y
)
535 if (IsSupported( wxDF_FILENAME
))
537 RequestData( wxDF_FILENAME
);
544 bool wxFileDropTarget::OnData( int x
, int y
)
546 wxFileDataObject data
;
547 if (!GetData( &data
)) return FALSE
;
549 /* get number of substrings /root/mytext.txt/0/root/myothertext.txt/0/0 */
552 size_t size
= data
.GetFiles().Length();
553 wxChar
*text
= WXSTRINGCAST data
.GetFiles();
554 for ( i
= 0; i
< size
; i
++)
555 if (text
[i
] == 0) number
++;
557 if (number
== 0) return FALSE
;
559 wxChar
**files
= new wxChar
*[number
];
561 text
= WXSTRINGCAST data
.GetFiles();
562 for (i
= 0; i
< number
; i
++)
565 int len
= wxStrlen( text
);
569 OnDropFiles( x
, y
, number
, files
);
576 //----------------------------------------------------------------------------
578 //----------------------------------------------------------------------------
581 source_drag_data_get (GtkWidget
*WXUNUSED(widget
),
582 GdkDragContext
*context
,
583 GtkSelectionData
*selection_data
,
584 guint
WXUNUSED(info
),
585 guint
WXUNUSED(time
),
586 wxDropSource
*drop_source
)
588 // char *name = gdk_atom_name( selection_data->target );
589 // if (name) printf( "Format requested: %s.\n", name );
591 wxNode
*node
= drop_source
->m_data
->m_dataObjects
.First();
594 wxDataObject
*data_object
= (wxDataObject
*) node
->Data();
595 if (data_object
->GetFormat().GetAtom() == selection_data
->target
)
597 size_t data_size
= data_object
->GetSize();
600 guchar
*buffer
= new guchar
[data_size
];
601 data_object
->WriteData( buffer
);
603 gtk_selection_data_set( selection_data
,
604 selection_data
->target
,
611 /* so far only copy, no moves. TODO. */
612 drop_source
->m_retValue
= wxDragCopy
;
621 drop_source
->m_retValue
= wxDragCancel
;
624 //----------------------------------------------------------------------------
625 // "drag_data_delete"
626 //----------------------------------------------------------------------------
628 static void source_drag_data_delete( GtkWidget
*WXUNUSED(widget
),
629 GdkDragContext
*WXUNUSED(context
),
630 wxDropSource
*drop_source
)
632 // printf( "Delete the data!\n" );
634 drop_source
->m_retValue
= wxDragMove
;
637 //----------------------------------------------------------------------------
639 //----------------------------------------------------------------------------
641 static void source_drag_begin( GtkWidget
*WXUNUSED(widget
),
642 GdkDragContext
*WXUNUSED(context
),
643 wxDropSource
*WXUNUSED(drop_source
) )
645 // printf( "drag_begin.\n" );
648 //----------------------------------------------------------------------------
650 //----------------------------------------------------------------------------
652 static void source_drag_end( GtkWidget
*WXUNUSED(widget
),
653 GdkDragContext
*WXUNUSED(context
),
654 wxDropSource
*drop_source
)
656 // printf( "drag_end.\n" );
658 drop_source
->m_waiting
= FALSE
;
661 //---------------------------------------------------------------------------
663 //---------------------------------------------------------------------------
665 wxDropSource::wxDropSource( wxWindow
*win
, const wxIcon
&go
, const wxIcon
&stop
)
667 g_blockEventsOnDrag
= TRUE
;
671 m_widget
= win
->m_widget
;
672 if (win
->m_wxwindow
) m_widget
= win
->m_wxwindow
;
674 m_data
= (wxDataBroker
*) NULL
;
675 m_retValue
= wxDragCancel
;
677 m_defaultCursor
= wxCursor( wxCURSOR_NO_ENTRY
);
678 m_goaheadCursor
= wxCursor( wxCURSOR_HAND
);
681 if (wxNullIcon
== go
) m_goIcon
= wxIcon( page_xpm
);
683 if (wxNullIcon
== stop
) m_stopIcon
= wxIcon( gv_xpm
);
686 wxDropSource::wxDropSource( wxDataObject
*data
, wxWindow
*win
, const wxIcon
&go
, const wxIcon
&stop
)
691 m_widget
= win
->m_widget
;
692 if (win
->m_wxwindow
) m_widget
= win
->m_wxwindow
;
693 m_retValue
= wxDragCancel
;
697 m_data
= new wxDataBroker();
702 m_data
= (wxDataBroker
*) NULL
;
705 m_defaultCursor
= wxCursor( wxCURSOR_NO_ENTRY
);
706 m_goaheadCursor
= wxCursor( wxCURSOR_HAND
);
709 if (wxNullIcon
== go
) m_goIcon
= wxIcon( page_xpm
);
711 if (wxNullIcon
== stop
) m_stopIcon
= wxIcon( gv_xpm
);
714 wxDropSource::wxDropSource( wxDataBroker
*data
, wxWindow
*win
)
717 m_widget
= win
->m_widget
;
718 if (win
->m_wxwindow
) m_widget
= win
->m_wxwindow
;
719 m_retValue
= wxDragCancel
;
723 m_defaultCursor
= wxCursor( wxCURSOR_NO_ENTRY
);
724 m_goaheadCursor
= wxCursor( wxCURSOR_HAND
);
727 void wxDropSource::SetData( wxDataObject
*data
)
729 if (m_data
) delete m_data
;
733 m_data
= new wxDataBroker();
738 m_data
= (wxDataBroker
*) NULL
;
742 void wxDropSource::SetData( wxDataBroker
*data
)
744 if (m_data
) delete m_data
;
749 wxDropSource::~wxDropSource(void)
751 if (m_data
) delete m_data
;
753 g_blockEventsOnDrag
= FALSE
;
756 wxDragResult
wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove
) )
758 wxASSERT_MSG( m_data
, _T("wxDragSource: no data") );
760 if (!m_data
) return (wxDragResult
) wxDragNone
;
762 g_blockEventsOnDrag
= TRUE
;
768 GtkTargetList
*target_list
= gtk_target_list_new( (GtkTargetEntry
*) NULL
, 0 );
769 gtk_target_list_add( target_list
, gdk_atom_intern( "STRING", FALSE
), 0, 0 );
771 GdkEventMotion event
;
772 event
.window
= m_widget
->window
;
775 GdkModifierType state
;
776 gdk_window_get_pointer( event
.window
, &x
, &y
, &state
);
781 /* GTK wants to know which button was pressed which caused the dragging */
782 int button_number
= 0;
783 if (event
.state
& GDK_BUTTON1_MASK
) button_number
= 1;
784 else if (event
.state
& GDK_BUTTON2_MASK
) button_number
= 2;
785 else if (event
.state
& GDK_BUTTON3_MASK
) button_number
= 3;
787 /* don't start dragging if no button is down */
790 GdkDragContext
*context
= gtk_drag_begin( m_widget
,
793 button_number
, /* number of mouse button which started drag */
794 (GdkEvent
*) &event
);
796 wxMask
*mask
= m_goIcon
.GetMask();
797 GdkBitmap
*bm
= (GdkBitmap
*) NULL
;
798 if (mask
) bm
= mask
->GetBitmap();
799 GdkPixmap
*pm
= m_goIcon
.GetPixmap();
801 gtk_drag_set_icon_pixmap( context
,
802 gtk_widget_get_colormap( m_widget
),
810 while (m_waiting
) wxYield();
813 g_blockEventsOnDrag
= FALSE
;
820 void wxDropSource::RegisterWindow()
822 if (!m_widget
) return;
824 gtk_signal_connect( GTK_OBJECT(m_widget
), "drag_data_get",
825 GTK_SIGNAL_FUNC (source_drag_data_get
), (gpointer
) this);
826 gtk_signal_connect (GTK_OBJECT(m_widget
), "drag_data_delete",
827 GTK_SIGNAL_FUNC (source_drag_data_delete
), (gpointer
) this );
828 gtk_signal_connect (GTK_OBJECT(m_widget
), "drag_begin",
829 GTK_SIGNAL_FUNC (source_drag_begin
), (gpointer
) this );
830 gtk_signal_connect (GTK_OBJECT(m_widget
), "drag_end",
831 GTK_SIGNAL_FUNC (source_drag_end
), (gpointer
) this );
835 void wxDropSource::UnregisterWindow()
837 if (!m_widget
) return;
839 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget
),
840 GTK_SIGNAL_FUNC(source_drag_data_get
), (gpointer
) this );
841 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget
),
842 GTK_SIGNAL_FUNC(source_drag_data_delete
), (gpointer
) this );
843 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget
),
844 GTK_SIGNAL_FUNC(source_drag_begin
), (gpointer
) this );
845 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget
),
846 GTK_SIGNAL_FUNC(source_drag_end
), (gpointer
) this );
852 //----------------------------------------------------------------------------
854 //----------------------------------------------------------------------------
856 GtkWidget
*shape_create_icon ( const wxIcon
&shape
,
863 //-----------------------------------------------------------------------------
865 //-----------------------------------------------------------------------------
867 wxDropSource
*gs_currentDropSource
= (wxDropSource
*) NULL
;
869 //-----------------------------------------------------------------------------
870 // "drop_enter_event"
871 //-----------------------------------------------------------------------------
873 static void gtk_target_enter_callback( GtkWidget
*WXUNUSED(widget
),
874 GdkEventDropEnter
*WXUNUSED(event
),
875 wxDropTarget
*target
)
881 //-----------------------------------------------------------------------------
882 // "drop_leave_event"
883 //-----------------------------------------------------------------------------
885 static void gtk_target_leave_callback( GtkWidget
*WXUNUSED(widget
),
886 GdkEventDropLeave
*WXUNUSED(event
),
887 wxDropTarget
*target
)
893 //-----------------------------------------------------------------------------
894 // "drop_data_available_event"
895 //-----------------------------------------------------------------------------
897 static void gtk_target_callback( GtkWidget
*widget
,
898 GdkEventDropDataAvailable
*event
,
899 wxDropTarget
*target
)
905 gdk_window_get_pointer( widget
->window
, &x
, &y
, (GdkModifierType
*) NULL
);
907 printf( "Drop data is of type %s.\n", event->data_type );
909 target
->OnDrop( x
, y
, (const void*)event
->data
, (size_t)event
->data_numbytes
);
913 g_free (event->data);
914 g_free (event->data_type);
918 // ----------------------------------------------------------------------------
920 // ----------------------------------------------------------------------------
922 wxDropTarget::wxDropTarget()
924 m_format
= (wxDataFormat
*) NULL
;
927 wxDropTarget::~wxDropTarget()
929 if (m_format
) delete m_format
;
932 wxDataFormat
&wxDropTarget::GetFormat(size_t n
) const
937 void wxDropTarget::UnregisterWidget( GtkWidget
*widget
)
941 gtk_signal_disconnect_by_func( GTK_OBJECT(widget
),
942 GTK_SIGNAL_FUNC(gtk_target_callback
), (gpointer
) this );
944 gtk_widget_dnd_drop_set( widget
, FALSE
, (gchar
**) NULL
, 0, FALSE
);
947 void wxDropTarget::RegisterWidget( GtkWidget
*widget
)
952 for ( size_t i
= 0; i
< GetFormatCount(); i
++ )
954 switch (GetFormat(i
).GetType())
958 if (i
> 0) formats
+= ";";
959 formats
+= "text/plain";
965 if (i
> 0) formats
+= ";";
966 formats
+= "file:ALL";
972 if (i
> 0) formats
+= ";";
973 wxPrivateDropTarget
*pdt
= (wxPrivateDropTarget
*)this;
974 formats
+= pdt
->GetId();
983 char *str
= WXSTRINGCAST formats
;
985 gtk_widget_dnd_drop_set( widget
, TRUE
, &str
, valid
, FALSE
);
987 gtk_signal_connect( GTK_OBJECT(widget
), "drop_data_available_event",
988 GTK_SIGNAL_FUNC(gtk_target_callback
), (gpointer
) this );
990 gtk_signal_connect( GTK_OBJECT(widget
), "drop_enter_event",
991 GTK_SIGNAL_FUNC(gtk_target_enter_callback
), (gpointer
) this );
993 gtk_signal_connect( GTK_OBJECT(widget
), "drop_leave_event",
994 GTK_SIGNAL_FUNC(gtk_target_leave_callback
), (gpointer
) this );
997 // ----------------------------------------------------------------------------
999 // ----------------------------------------------------------------------------
1001 wxTextDropTarget::wxTextDropTarget()
1003 m_format
= new wxDataFormat( wxDF_TEXT
);
1006 bool wxTextDropTarget::OnDrop( long x
, long y
, const void *data
, size_t WXUNUSED(size
) )
1008 OnDropText( x
, y
, (const char*)data
);
1012 bool wxTextDropTarget::OnDropText( long x
, long y
, const char *psz
)
1015 printf( "Got dropped text: %s.\n", psz );
1016 printf( "At x: %d, y: %d.\n", (int)x, (int)y );
1021 size_t wxTextDropTarget::GetFormatCount() const
1026 // ----------------------------------------------------------------------------
1027 // wxPrivateDropTarget
1028 // ----------------------------------------------------------------------------
1030 wxPrivateDropTarget::wxPrivateDropTarget()
1032 m_id
= wxTheApp
->GetAppName();
1033 m_format
= new wxDataFormat( m_id
);
1036 void wxPrivateDropTarget::SetId( const wxString
& id
)
1039 m_format
->SetId( id
);
1042 size_t wxPrivateDropTarget::GetFormatCount() const
1047 // ----------------------------------------------------------------------------
1049 // ----------------------------------------------------------------------------
1051 wxFileDropTarget::wxFileDropTarget()
1053 m_format
= new wxDataFormat( wxDF_FILENAME
);
1056 bool wxFileDropTarget::OnDropFiles( long x
, long y
, size_t nFiles
, const char * const aszFiles
[] )
1058 printf( "Got %d dropped files.\n", (int)nFiles
);
1059 printf( "At x: %d, y: %d.\n", (int)x
, (int)y
);
1061 for (size_t i
= 0; i
< nFiles
; i
++)
1063 printf( aszFiles
[i
] );
1070 bool wxFileDropTarget::OnDrop(long x
, long y
, const void *data
, size_t size
)
1074 char *text
= (char*) data
;
1075 for ( i
= 0; i
< size
; i
++)
1076 if (text
[i
] == 0) number
++;
1078 if (number
== 0) return TRUE
;
1080 char **files
= new char*[number
];
1082 text
= (char*) data
;
1083 for (i
= 0; i
< number
; i
++)
1086 int len
= strlen( text
);
1090 bool ret
= OnDropFiles( x
, y
, 1, files
);
1097 size_t wxFileDropTarget::GetFormatCount() const
1102 //-------------------------------------------------------------------------
1104 //-------------------------------------------------------------------------
1107 shape_motion (GtkWidget
*widget
,
1108 GdkEventMotion
* /*event*/);
1110 //-----------------------------------------------------------------------------
1111 // "drag_request_event"
1112 //-----------------------------------------------------------------------------
1114 void gtk_drag_callback( GtkWidget
*widget
, GdkEventDragRequest
*event
, wxDropSource
*source
)
1116 wxDataBroker
*data
= source
->m_data
;
1120 wxNode
*node
= data
->m_dataObjects
.First();
1122 wxDataObject
*dobj
= (wxDataObject
*) node
->Data();
1124 if ((strcmp(event
->data_type
,"file:ALL") == 0) &&
1125 (dobj
->GetFormat().GetType() == wxDF_FILENAME
))
1127 wxFileDataObject
*file_object
= (wxFileDataObject
*) dobj
;
1129 wxString text
= file_object
->GetFiles();
1131 char *s
= WXSTRINGCAST text
;
1133 gtk_widget_dnd_data_set( widget
,
1136 (int) text
.Length()+1 );
1138 source
->m_retValue
= wxDragCopy
;
1143 if ((strcmp(event
->data_type
,"text/plain") == 0) &&
1144 (dobj
->GetFormat().GetType() == wxDF_TEXT
))
1146 wxTextDataObject
*text_object
= (wxTextDataObject
*) dobj
;
1148 wxString text
= text_object
->GetText();
1150 char *s
= WXSTRINGCAST text
;
1152 gtk_widget_dnd_data_set( widget
,
1155 (int) text
.Length()+1 );
1157 source
->m_retValue
= wxDragCopy
;
1162 if (dobj
->GetFormat().GetType() == wxDF_PRIVATE
)
1164 wxPrivateDataObject
*pdo
= (wxPrivateDataObject
*) dobj
;
1166 if (pdo
->GetId() == event
->data_type
)
1168 gtk_widget_dnd_data_set( widget
,
1170 (unsigned char*) pdo
->GetData(),
1171 (int) pdo
->GetSize() );
1173 source
->m_retValue
= wxDragCopy
;
1179 node
= node
->Next();
1183 wxDropSource::wxDropSource( wxWindow
*win
, const wxIcon
&go
, const wxIcon
&stop
)
1185 g_blockEventsOnDrag
= TRUE
;
1188 m_widget
= win
->m_widget
;
1189 if (win
->m_wxwindow
) m_widget
= win
->m_wxwindow
;
1191 m_data
= (wxDataBroker
*) NULL
;
1192 m_retValue
= wxDragCancel
;
1194 m_defaultCursor
= wxCursor( wxCURSOR_NO_ENTRY
);
1195 m_goaheadCursor
= wxCursor( wxCURSOR_HAND
);
1198 if (wxNullIcon
== go
) m_goIcon
= wxIcon( page_xpm
);
1200 if (wxNullIcon
== stop
) m_stopIcon
= wxIcon( gv_xpm
);
1203 wxDropSource::wxDropSource( wxDataObject
*data
, wxWindow
*win
, const wxIcon
&go
, const wxIcon
&stop
)
1205 g_blockEventsOnDrag
= TRUE
;
1208 m_widget
= win
->m_widget
;
1209 if (win
->m_wxwindow
) m_widget
= win
->m_wxwindow
;
1210 m_retValue
= wxDragCancel
;
1214 m_data
= new wxDataBroker();
1215 m_data
->Add( data
);
1219 m_data
= (wxDataBroker
*) NULL
;
1222 m_defaultCursor
= wxCursor( wxCURSOR_NO_ENTRY
);
1223 m_goaheadCursor
= wxCursor( wxCURSOR_HAND
);
1226 if (wxNullIcon
== go
) m_goIcon
= wxIcon( page_xpm
);
1228 if (wxNullIcon
== stop
) m_stopIcon
= wxIcon( gv_xpm
);
1231 wxDropSource::wxDropSource( wxDataBroker
*data
, wxWindow
*win
)
1233 g_blockEventsOnDrag
= TRUE
;
1236 m_widget
= win
->m_widget
;
1237 if (win
->m_wxwindow
) m_widget
= win
->m_wxwindow
;
1238 m_retValue
= wxDragCancel
;
1242 m_defaultCursor
= wxCursor( wxCURSOR_NO_ENTRY
);
1243 m_goaheadCursor
= wxCursor( wxCURSOR_HAND
);
1246 void wxDropSource::SetData( wxDataObject
*data
)
1248 if (m_data
) delete m_data
;
1252 m_data
= new wxDataBroker();
1253 m_data
->Add( data
);
1257 m_data
= (wxDataBroker
*) NULL
;
1261 void wxDropSource::SetData( wxDataBroker
*data
)
1263 if (m_data
) delete m_data
;
1268 wxDropSource::~wxDropSource(void)
1270 if (m_data
) delete m_data
;
1272 g_blockEventsOnDrag
= FALSE
;
1275 wxDragResult
wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove
) )
1277 if (gdk_dnd
.dnd_grabbed
) return (wxDragResult
) wxDragNone
;
1278 if (gdk_dnd
.drag_really
) return (wxDragResult
) wxDragNone
;
1280 wxASSERT_MSG( m_data
, "wxDragSource: no data" );
1282 if (!m_data
) return (wxDragResult
) wxDragNone
;
1284 static GtkWidget
*drag_icon
= (GtkWidget
*) NULL
;
1285 static GtkWidget
*drop_icon
= (GtkWidget
*) NULL
;
1287 GdkPoint hotspot_1
= {0,-5 };
1291 drag_icon
= shape_create_icon ( m_stopIcon
,
1292 440, 140, 0,0, GTK_WINDOW_POPUP
);
1294 gtk_signal_connect (GTK_OBJECT (drag_icon
), "destroy",
1295 GTK_SIGNAL_FUNC(gtk_widget_destroyed
),
1298 gtk_widget_hide (drag_icon
);
1301 GdkPoint hotspot_2
= {-5,-5};
1305 drop_icon
= shape_create_icon ( m_goIcon
,
1306 440, 140, 0,0, GTK_WINDOW_POPUP
);
1308 gtk_signal_connect (GTK_OBJECT (drop_icon
), "destroy",
1309 GTK_SIGNAL_FUNC(gtk_widget_destroyed
),
1312 gtk_widget_hide (drop_icon
);
1316 gdk_dnd_set_drag_shape( drag_icon
->window
,
1322 GdkWindowPrivate
*wp
= (GdkWindowPrivate
*) m_widget
->window
;
1326 gdk_dnd
.drag_perhaps
= TRUE
;
1328 gdk_dnd
.dnd_drag_start
.x
= 5;
1329 gdk_dnd
.dnd_drag_start
.y
= 5;
1330 gdk_dnd
.real_sw
= wp
;
1332 if (gdk_dnd
.drag_startwindows
)
1334 g_free( gdk_dnd
.drag_startwindows
);
1335 gdk_dnd
.drag_startwindows
= (GdkWindow
**) NULL
;
1337 gdk_dnd
.drag_numwindows
= gdk_dnd
.drag_really
= 0;
1339 XWindowAttributes dnd_winattr
;
1340 XGetWindowAttributes( gdk_display
, wp
->xwindow
, &dnd_winattr
);
1341 wp
->dnd_drag_savedeventmask
= dnd_winattr
.your_event_mask
;
1343 gdk_dnd_drag_addwindow( m_widget
->window
);
1345 GdkEventDragBegin ev
;
1346 ev
.type
= GDK_DRAG_BEGIN
;
1347 ev
.window
= m_widget
->window
;
1349 ev
.u
.flags
.protocol_version
= DND_PROTOCOL_VERSION
;
1351 gdk_event_put( (GdkEvent
*)&ev
);
1353 XGrabPointer( gdk_display
, wp
->xwindow
, False
,
1354 ButtonMotionMask
| ButtonPressMask
| ButtonReleaseMask
| PointerMotionMask
,
1355 GrabModeAsync
, GrabModeAsync
, gdk_root_window
, None
, CurrentTime
);
1357 gdk_dnd_set_drag_cursors( m_defaultCursor
.GetCursor(), m_goaheadCursor
.GetCursor() );
1359 gdk_dnd
.dnd_grabbed
= TRUE
;
1360 gdk_dnd
.drag_really
= 1;
1364 wxGetMousePosition( &x
, &y
);
1366 gdk_dnd_display_drag_cursor( x
, y
, FALSE
, TRUE
);
1368 gs_currentDropSource
= this;
1370 while (gdk_dnd
.drag_really
|| gdk_dnd
.drag_perhaps
) wxYield();
1372 gs_currentDropSource
= (wxDropSource
*) NULL
;
1376 g_blockEventsOnDrag
= FALSE
;
1381 void wxDropSource::RegisterWindow(void)
1383 if (!m_data
) return;
1387 wxNode
*node
= m_data
->m_dataObjects
.First();
1390 wxDataObject
* dobj
= (wxDataObject
*) node
->Data();
1392 switch (dobj
->GetFormat().GetType())
1396 formats
+= "text/plain";
1401 formats
+= "file:ALL";
1406 wxPrivateDataObject
* pdo
= (wxPrivateDataObject
*) m_data
;
1407 formats
+= pdo
->GetId();
1413 node
= node
->Next();
1416 char *str
= WXSTRINGCAST formats
;
1418 gtk_widget_dnd_drag_set( m_widget
, TRUE
, &str
, 1 );
1420 gtk_signal_connect( GTK_OBJECT(m_widget
), "drag_request_event",
1421 GTK_SIGNAL_FUNC(gtk_drag_callback
), (gpointer
)this );
1424 void wxDropSource::UnregisterWindow(void)
1426 if (!m_widget
) return;
1428 gtk_widget_dnd_drag_set( m_widget
, FALSE
, (gchar
**) NULL
, 0 );
1430 gtk_signal_disconnect_by_data( GTK_OBJECT(m_widget
), (gpointer
)this );
1437 static GdkWindow
*root_win
= (GdkWindow
*) NULL
;
1439 typedef struct _cursoroffset
{gint x
,y
;} CursorOffset
;
1442 shape_pressed (GtkWidget
*widget
, GdkEventButton
*event
)
1446 /* ignore double and triple click */
1447 if (event
->type
!= GDK_BUTTON_PRESS
)
1450 p
= (CursorOffset
*)gtk_object_get_user_data (GTK_OBJECT(widget
));
1451 p
->x
= (int) event
->x
;
1452 p
->y
= (int) event
->y
;
1454 gtk_grab_add (widget
);
1455 gdk_pointer_grab (widget
->window
, TRUE
,
1457 (GDK_BUTTON_RELEASE_MASK
|
1458 GDK_BUTTON_MOTION_MASK
|
1459 GDK_POINTER_MOTION_HINT_MASK
),
1461 (GdkCursor
*) NULL
, 0);
1466 shape_released (GtkWidget
*widget
)
1468 gtk_grab_remove (widget
);
1469 gdk_pointer_ungrab (0);
1473 shape_motion (GtkWidget
*widget
,
1474 GdkEventMotion
* /*event*/ )
1478 GdkModifierType mask
;
1480 p
= (CursorOffset
*)gtk_object_get_user_data (GTK_OBJECT (widget
));
1483 * Can't use event->x / event->y here
1484 * because I need absolute coordinates.
1487 gdk_window_get_pointer (root_win
, &xp
, &yp
, &mask
);
1488 gtk_widget_set_uposition (widget
, xp
- p
->x
, yp
- p
->y
);
1490 if (gs_currentDropSource
) gs_currentDropSource
->GiveFeedback( wxDragCopy
, FALSE
);
1494 shape_create_icon (const wxIcon
&shape
,
1502 * GDK_WINDOW_TOPLEVEL works also, giving you a title border
1504 GtkWidget
*window
= gtk_window_new ((GtkWindowType
)window_type
);
1506 GtkWidget
*fixed
= gtk_fixed_new ();
1507 gtk_widget_set_usize (fixed
, 100,100);
1508 gtk_container_add (GTK_CONTAINER (window
), fixed
);
1509 gtk_widget_show (fixed
);
1511 gtk_widget_set_events (window
,
1512 gtk_widget_get_events (window
) |
1513 GDK_BUTTON_MOTION_MASK
|
1514 GDK_POINTER_MOTION_HINT_MASK
|
1515 GDK_BUTTON_PRESS_MASK
);
1517 gtk_widget_realize (window
);
1519 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
1520 if (shape
.GetMask()) mask
= shape
.GetMask()->GetBitmap();
1522 GtkWidget
*pixmap
= gtk_pixmap_new (shape
.GetPixmap(), mask
);
1523 gtk_fixed_put (GTK_FIXED (fixed
), pixmap
, px
,py
);
1524 gtk_widget_show (pixmap
);
1526 gtk_widget_shape_combine_mask (window
, mask
, px
,py
);
1529 gtk_signal_connect (GTK_OBJECT (window
), "button_press_event",
1530 GTK_SIGNAL_FUNC (shape_pressed
),NULL
);
1531 gtk_signal_connect (GTK_OBJECT (window
), "button_release_event",
1532 GTK_SIGNAL_FUNC (shape_released
),NULL
);
1533 gtk_signal_connect (GTK_OBJECT (window
), "motion_notify_event",
1534 GTK_SIGNAL_FUNC (shape_motion
),NULL
);
1536 CursorOffset
*icon_pos
= g_new (CursorOffset
, 1);
1537 gtk_object_set_user_data(GTK_OBJECT(window
), icon_pos
);
1539 gtk_widget_set_uposition (window
, x
, y
);
1540 gtk_widget_show (window
);
1550 // wxUSE_DRAG_AND_DROP