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 /* this should trigger an "drag_data_received" event */
238 gtk_drag_get_data( widget
,
240 GPOINTER_TO_INT (context
->targets
->data
),
245 /* cancel the whole thing */
246 gtk_drag_finish( context
,
247 FALSE
, /* no success */
248 FALSE
, /* don't delete data on dropping side */
252 /* after this, invalidate the drop_target's GdkDragContext */
253 drop_target
->SetDragContext( (GdkDragContext
*) NULL
);
255 /* after this, invalidate the drop_target's drag widget */
256 drop_target
->SetDragWidget( (GtkWidget
*) NULL
);
258 /* this has to be done because GDK has no "drag_enter" event */
259 drop_target
->m_firstMotion
= TRUE
;
264 // ----------------------------------------------------------------------------
265 // "drag_data_received"
266 // ----------------------------------------------------------------------------
268 static void target_drag_data_received( GtkWidget
*WXUNUSED(widget
),
269 GdkDragContext
*context
,
272 GtkSelectionData
*data
,
273 guint
WXUNUSED(info
),
275 wxDropTarget
*drop_target
)
277 /* Owen Taylor: "call gtk_drag_finish() with
280 // printf( "data received.\n" );
282 /* strangely, we get a "drag_data_received" event even when
283 we don't request them. this checks this. */
284 if (!drop_target
->m_currentDataObject
) return;
286 wxDataObject
*data_object
= drop_target
->m_currentDataObject
;
288 if ((data
->length
<= 0) || (data
->format
!= 8))
290 /* negative data length and non 8-bit data format
291 qualifies for junk */
292 gtk_drag_finish (context
, FALSE
, FALSE
, time
);
296 wxASSERT_MSG( data
->target
== data_object
->GetFormat().GetAtom(), "DnD GetData target mismatch." );
298 if (data_object
->GetFormat().GetType() == wxDF_TEXT
)
300 wxTextDataObject
*text_object
= (wxTextDataObject
*)data_object
;
301 text_object
->SetText( (const char*)data
->data
);
304 if (data_object
->GetFormat().GetType() == wxDF_FILENAME
)
308 if (data_object
->GetFormat().GetType() == wxDF_PRIVATE
)
310 wxPrivateDataObject
*priv_object
= (wxPrivateDataObject
*)data_object
;
311 priv_object
->SetData( (const char*)data
->data
, (size_t)data
->length
);
314 /* tell wxDropTarget that data transfer was successfull */
315 drop_target
->m_dataRetrieveSuccess
= TRUE
;
317 /* tell GTK that data transfer was successfull */
318 gtk_drag_finish( context
, TRUE
, FALSE
, time
);
321 /* tell wxDropTarget that data has arrived (or not) */
322 drop_target
->m_waiting
= FALSE
;
325 //----------------------------------------------------------------------------
327 //----------------------------------------------------------------------------
329 wxDropTarget::wxDropTarget()
331 m_firstMotion
= TRUE
;
332 m_dragContext
= (GdkDragContext
*) NULL
;
333 m_dragWidget
= (GtkWidget
*) NULL
;
335 m_currentDataObject
= (wxDataObject
*) NULL
;
336 m_dataRetrieveSuccess
= FALSE
;
339 wxDropTarget::~wxDropTarget()
343 void wxDropTarget::OnEnter()
347 void wxDropTarget::OnLeave()
351 bool wxDropTarget::OnMove( int WXUNUSED(x
), int WXUNUSED(y
) )
356 bool wxDropTarget::OnDrop( int WXUNUSED(x
), int WXUNUSED(y
) )
361 bool wxDropTarget::IsSupported( wxDataFormat format
)
363 if (!m_dragContext
) return FALSE
;
365 GList
*child
= m_dragContext
->targets
;
368 GdkAtom formatAtom
= (GdkAtom
) GPOINTER_TO_INT(child
->data
);
370 // char *name = gdk_atom_name( formatAtom );
371 // if (name) printf( "Format available: %s.\n", name );
373 if (formatAtom
== format
.GetAtom()) return TRUE
;
380 bool wxDropTarget::GetData( wxDataObject
*data
)
382 if (!m_dragContext
) return FALSE
;
383 if (!m_dragWidget
) return FALSE
;
385 m_currentDataObject
= data
;
386 m_dataRetrieveSuccess
= FALSE
;
388 /* this should trigger an "drag_data_received" event */
389 gtk_drag_get_data( m_dragWidget
,
391 data
->GetFormat().GetAtom(),
394 /* wait for the "drag_data_received" event */
396 // printf( "pre wait.\n" );
399 while (m_waiting
) wxYield();
401 // printf( "post wait.\n" );
403 m_currentDataObject
= (wxDataObject
*) NULL
;
405 return m_dataRetrieveSuccess
;
408 void wxDropTarget::UnregisterWidget( GtkWidget
*widget
)
410 wxCHECK_RET( widget
!= NULL
, "unregister widget is NULL" );
412 gtk_drag_dest_unset( widget
);
414 gtk_signal_disconnect_by_func( GTK_OBJECT(widget
),
415 GTK_SIGNAL_FUNC(target_drag_leave
), (gpointer
) this );
417 gtk_signal_disconnect_by_func( GTK_OBJECT(widget
),
418 GTK_SIGNAL_FUNC(target_drag_motion
), (gpointer
) this );
420 gtk_signal_disconnect_by_func( GTK_OBJECT(widget
),
421 GTK_SIGNAL_FUNC(target_drag_drop
), (gpointer
) this );
423 gtk_signal_disconnect_by_func( GTK_OBJECT(widget
),
424 GTK_SIGNAL_FUNC(target_drag_data_received
), (gpointer
) this );
427 void wxDropTarget::RegisterWidget( GtkWidget
*widget
)
429 wxCHECK_RET( widget
!= NULL
, "register widget is NULL" );
431 /* gtk_drag_dest_set() determines what default behaviour we'd like
432 GTK to supply. we don't want to specify out targets (=formats)
433 or actions in advance (i.e. not GTK_DEST_DEFAULT_MOTION and
434 not GTK_DEST_DEFAULT_DROP). instead we react individually to
435 "drag_motion" and "drag_drop" events. this makes it possible
436 to allow dropping on only a small area. we should set
437 GTK_DEST_DEFAULT_HIGHLIGHT as this will switch on the nice
438 highlighting if dragging over standard controls, but this
439 seems to be broken without the other two. */
441 gtk_drag_dest_set( widget
,
442 (GtkDestDefaults
) 0, /* no default behaviour */
443 (GtkTargetEntry
*) NULL
, /* we don't supply any formats here */
444 0, /* number of targets = 0 */
445 (GdkDragAction
) 0 ); /* we don't supply any actions here */
447 gtk_signal_connect( GTK_OBJECT(widget
), "drag_leave",
448 GTK_SIGNAL_FUNC(target_drag_leave
), (gpointer
) this );
450 gtk_signal_connect( GTK_OBJECT(widget
), "drag_motion",
451 GTK_SIGNAL_FUNC(target_drag_motion
), (gpointer
) this );
453 gtk_signal_connect( GTK_OBJECT(widget
), "drag_drop",
454 GTK_SIGNAL_FUNC(target_drag_drop
), (gpointer
) this );
456 gtk_signal_connect( GTK_OBJECT(widget
), "drag_data_received",
457 GTK_SIGNAL_FUNC(target_drag_data_received
), (gpointer
) this );
460 //-------------------------------------------------------------------------
462 //-------------------------------------------------------------------------
464 bool wxTextDropTarget::OnMove( int WXUNUSED(x
), int WXUNUSED(y
) )
466 return IsSupported( wxDF_TEXT
); // same as "STRING"
469 bool wxTextDropTarget::OnDrop( int x
, int y
)
471 if (!IsSupported( wxDF_TEXT
)) return FALSE
;
473 wxTextDataObject data
;
474 if (!GetData( &data
)) return FALSE
;
476 OnDropText( x
, y
, data
.GetText() );
480 //-------------------------------------------------------------------------
481 // wxPrivateDropTarget
482 //-------------------------------------------------------------------------
484 wxPrivateDropTarget::wxPrivateDropTarget()
486 m_id
= wxTheApp
->GetAppName();
489 wxPrivateDropTarget::wxPrivateDropTarget( const wxString
&id
)
494 bool wxPrivateDropTarget::OnMove( int WXUNUSED(x
), int WXUNUSED(y
) )
496 return IsSupported( m_id
);
499 bool wxPrivateDropTarget::OnDrop( int x
, int y
)
501 if (!IsSupported( m_id
)) return FALSE
;
503 wxPrivateDataObject data
;
504 if (!GetData( &data
)) return FALSE
;
506 OnDropData( x
, y
, data
.GetData(), data
.GetSize() );
511 //----------------------------------------------------------------------------
512 // A drop target which accepts files (dragged from File Manager or Explorer)
513 //----------------------------------------------------------------------------
515 bool wxFileDropTarget::OnMove( int WXUNUSED(x
), int WXUNUSED(y
) )
517 return IsSupported( wxDF_FILENAME
); // same as "file:ALL"
520 bool wxFileDropTarget::OnDrop( int x
, int y
)
522 return IsSupported( wxDF_FILENAME
); // same as "file:ALL"
525 void wxFileDropTarget::OnData( int x
, int y
)
527 wxFileDataObject data
;
528 if (!GetData( &data
)) return;
530 /* get number of substrings /root/mytext.txt/0/root/myothertext.txt/0/0 */
533 size_t size
= data
.GetFiles().Length();
534 char *text
= WXSTRINGCAST data
.GetFiles();
535 for ( i
= 0; i
< size
; i
++)
536 if (text
[i
] == 0) number
++;
538 if (number
== 0) return;
540 char **files
= new char*[number
];
542 text
= WXSTRINGCAST data
.GetFiles();
543 for (i
= 0; i
< number
; i
++)
546 int len
= strlen( text
);
550 OnDropFiles( x
, y
, number
, files
);
555 //----------------------------------------------------------------------------
557 //----------------------------------------------------------------------------
560 source_drag_data_get (GtkWidget
*WXUNUSED(widget
),
561 GdkDragContext
*context
,
562 GtkSelectionData
*selection_data
,
563 guint
WXUNUSED(info
),
564 guint
WXUNUSED(time
),
565 wxDropSource
*drop_source
)
567 char *name
= gdk_atom_name( selection_data
->target
);
568 if (name
) printf( "Format requested: %s.\n", name
);
570 wxNode
*node
= drop_source
->m_data
->m_dataObjects
.First();
573 wxDataObject
*data_object
= (wxDataObject
*) node
->Data();
574 if (data_object
->GetFormat().GetAtom() == selection_data
->target
)
576 size_t data_size
= data_object
->GetSize();
579 guchar
*buffer
= new guchar
[data_size
];
580 data_object
->WriteData( buffer
);
582 gtk_selection_data_set( selection_data
,
583 selection_data
->target
,
590 /* so far only copy, no moves. TODO. */
591 drop_source
->m_retValue
= wxDragCopy
;
600 drop_source
->m_retValue
= wxDragCancel
;
603 //----------------------------------------------------------------------------
604 // "drag_data_delete"
605 //----------------------------------------------------------------------------
607 static void source_drag_data_delete( GtkWidget
*WXUNUSED(widget
),
608 GdkDragContext
*WXUNUSED(context
),
609 wxDropSource
*drop_source
)
611 // printf( "Delete the data!\n" );
613 drop_source
->m_retValue
= wxDragMove
;
616 //----------------------------------------------------------------------------
618 //----------------------------------------------------------------------------
620 static void source_drag_begin( GtkWidget
*WXUNUSED(widget
),
621 GdkDragContext
*WXUNUSED(context
),
622 wxDropSource
*WXUNUSED(drop_source
) )
624 // printf( "drag_begin.\n" );
627 //----------------------------------------------------------------------------
629 //----------------------------------------------------------------------------
631 static void source_drag_end( GtkWidget
*WXUNUSED(widget
),
632 GdkDragContext
*WXUNUSED(context
),
633 wxDropSource
*drop_source
)
635 // printf( "drag_end.\n" );
637 drop_source
->m_waiting
= FALSE
;
640 //---------------------------------------------------------------------------
642 //---------------------------------------------------------------------------
644 wxDropSource::wxDropSource( wxWindow
*win
, const wxIcon
&go
, const wxIcon
&stop
)
646 g_blockEventsOnDrag
= TRUE
;
650 m_widget
= win
->m_widget
;
651 if (win
->m_wxwindow
) m_widget
= win
->m_wxwindow
;
653 m_data
= (wxDataBroker
*) NULL
;
654 m_retValue
= wxDragCancel
;
656 m_defaultCursor
= wxCursor( wxCURSOR_NO_ENTRY
);
657 m_goaheadCursor
= wxCursor( wxCURSOR_HAND
);
660 if (wxNullIcon
== go
) m_goIcon
= wxIcon( page_xpm
);
662 if (wxNullIcon
== stop
) m_stopIcon
= wxIcon( gv_xpm
);
665 wxDropSource::wxDropSource( wxDataObject
*data
, wxWindow
*win
, const wxIcon
&go
, const wxIcon
&stop
)
670 m_widget
= win
->m_widget
;
671 if (win
->m_wxwindow
) m_widget
= win
->m_wxwindow
;
672 m_retValue
= wxDragCancel
;
676 m_data
= new wxDataBroker();
681 m_data
= (wxDataBroker
*) NULL
;
684 m_defaultCursor
= wxCursor( wxCURSOR_NO_ENTRY
);
685 m_goaheadCursor
= wxCursor( wxCURSOR_HAND
);
688 if (wxNullIcon
== go
) m_goIcon
= wxIcon( page_xpm
);
690 if (wxNullIcon
== stop
) m_stopIcon
= wxIcon( gv_xpm
);
693 wxDropSource::wxDropSource( wxDataBroker
*data
, wxWindow
*win
)
696 m_widget
= win
->m_widget
;
697 if (win
->m_wxwindow
) m_widget
= win
->m_wxwindow
;
698 m_retValue
= wxDragCancel
;
702 m_defaultCursor
= wxCursor( wxCURSOR_NO_ENTRY
);
703 m_goaheadCursor
= wxCursor( wxCURSOR_HAND
);
706 void wxDropSource::SetData( wxDataObject
*data
)
708 if (m_data
) delete m_data
;
712 m_data
= new wxDataBroker();
717 m_data
= (wxDataBroker
*) NULL
;
721 void wxDropSource::SetData( wxDataBroker
*data
)
723 if (m_data
) delete m_data
;
728 wxDropSource::~wxDropSource(void)
730 if (m_data
) delete m_data
;
732 g_blockEventsOnDrag
= FALSE
;
735 wxDragResult
wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove
) )
737 wxASSERT_MSG( m_data
, "wxDragSource: no data" );
739 if (!m_data
) return (wxDragResult
) wxDragNone
;
741 g_blockEventsOnDrag
= TRUE
;
747 GtkTargetList
*target_list
= gtk_target_list_new( (GtkTargetEntry
*) NULL
, 0 );
748 gtk_target_list_add( target_list
, gdk_atom_intern( "STRING", FALSE
), 0, 0 );
750 GdkEventMotion event
;
751 event
.window
= m_widget
->window
;
754 GdkModifierType state
;
755 gdk_window_get_pointer( event
.window
, &x
, &y
, &state
);
760 /* GTK wants to know which button was pressed which caused the dragging */
761 int button_number
= 0;
762 if (event
.state
& GDK_BUTTON1_MASK
) button_number
= 1;
763 else if (event
.state
& GDK_BUTTON2_MASK
) button_number
= 2;
764 else if (event
.state
& GDK_BUTTON3_MASK
) button_number
= 3;
766 /* don't start dragging if no button is down */
769 GdkDragContext
*context
= gtk_drag_begin( m_widget
,
772 button_number
, /* number of mouse button which started drag */
773 (GdkEvent
*) &event
);
775 wxMask
*mask
= m_goIcon
.GetMask();
776 GdkBitmap
*bm
= (GdkBitmap
*) NULL
;
777 if (mask
) bm
= mask
->GetBitmap();
778 GdkPixmap
*pm
= m_goIcon
.GetPixmap();
780 gtk_drag_set_icon_pixmap( context
,
781 gtk_widget_get_colormap( m_widget
),
787 while (m_waiting
) wxYield();
790 g_blockEventsOnDrag
= FALSE
;
797 void wxDropSource::RegisterWindow()
799 if (!m_widget
) return;
801 gtk_signal_connect( GTK_OBJECT(m_widget
), "drag_data_get",
802 GTK_SIGNAL_FUNC (source_drag_data_get
), (gpointer
) this);
803 gtk_signal_connect (GTK_OBJECT(m_widget
), "drag_data_delete",
804 GTK_SIGNAL_FUNC (source_drag_data_delete
), (gpointer
) this );
805 gtk_signal_connect (GTK_OBJECT(m_widget
), "drag_begin",
806 GTK_SIGNAL_FUNC (source_drag_begin
), (gpointer
) this );
807 gtk_signal_connect (GTK_OBJECT(m_widget
), "drag_end",
808 GTK_SIGNAL_FUNC (source_drag_end
), (gpointer
) this );
812 void wxDropSource::UnregisterWindow()
814 if (!m_widget
) return;
816 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget
),
817 GTK_SIGNAL_FUNC(source_drag_data_get
), (gpointer
) this );
818 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget
),
819 GTK_SIGNAL_FUNC(source_drag_data_delete
), (gpointer
) this );
820 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget
),
821 GTK_SIGNAL_FUNC(source_drag_begin
), (gpointer
) this );
822 gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget
),
823 GTK_SIGNAL_FUNC(source_drag_end
), (gpointer
) this );
829 //----------------------------------------------------------------------------
831 //----------------------------------------------------------------------------
833 GtkWidget
*shape_create_icon ( const wxIcon
&shape
,
840 //-----------------------------------------------------------------------------
842 //-----------------------------------------------------------------------------
844 wxDropSource
*gs_currentDropSource
= (wxDropSource
*) NULL
;
846 //-----------------------------------------------------------------------------
847 // "drop_enter_event"
848 //-----------------------------------------------------------------------------
850 static void gtk_target_enter_callback( GtkWidget
*WXUNUSED(widget
),
851 GdkEventDropEnter
*WXUNUSED(event
),
852 wxDropTarget
*target
)
858 //-----------------------------------------------------------------------------
859 // "drop_leave_event"
860 //-----------------------------------------------------------------------------
862 static void gtk_target_leave_callback( GtkWidget
*WXUNUSED(widget
),
863 GdkEventDropLeave
*WXUNUSED(event
),
864 wxDropTarget
*target
)
870 //-----------------------------------------------------------------------------
871 // "drop_data_available_event"
872 //-----------------------------------------------------------------------------
874 static void gtk_target_callback( GtkWidget
*widget
,
875 GdkEventDropDataAvailable
*event
,
876 wxDropTarget
*target
)
882 gdk_window_get_pointer( widget
->window
, &x
, &y
, (GdkModifierType
*) NULL
);
884 printf( "Drop data is of type %s.\n", event->data_type );
886 target
->OnDrop( x
, y
, (const void*)event
->data
, (size_t)event
->data_numbytes
);
890 g_free (event->data);
891 g_free (event->data_type);
895 // ----------------------------------------------------------------------------
897 // ----------------------------------------------------------------------------
899 wxDropTarget::wxDropTarget()
901 m_format
= (wxDataFormat
*) NULL
;
904 wxDropTarget::~wxDropTarget()
906 if (m_format
) delete m_format
;
909 wxDataFormat
&wxDropTarget::GetFormat(size_t n
) const
914 void wxDropTarget::UnregisterWidget( GtkWidget
*widget
)
918 gtk_signal_disconnect_by_func( GTK_OBJECT(widget
),
919 GTK_SIGNAL_FUNC(gtk_target_callback
), (gpointer
) this );
921 gtk_widget_dnd_drop_set( widget
, FALSE
, (gchar
**) NULL
, 0, FALSE
);
924 void wxDropTarget::RegisterWidget( GtkWidget
*widget
)
929 for ( size_t i
= 0; i
< GetFormatCount(); i
++ )
931 switch (GetFormat(i
).GetType())
935 if (i
> 0) formats
+= ";";
936 formats
+= "text/plain";
942 if (i
> 0) formats
+= ";";
943 formats
+= "file:ALL";
949 if (i
> 0) formats
+= ";";
950 wxPrivateDropTarget
*pdt
= (wxPrivateDropTarget
*)this;
951 formats
+= pdt
->GetId();
960 char *str
= WXSTRINGCAST formats
;
962 gtk_widget_dnd_drop_set( widget
, TRUE
, &str
, valid
, FALSE
);
964 gtk_signal_connect( GTK_OBJECT(widget
), "drop_data_available_event",
965 GTK_SIGNAL_FUNC(gtk_target_callback
), (gpointer
) this );
967 gtk_signal_connect( GTK_OBJECT(widget
), "drop_enter_event",
968 GTK_SIGNAL_FUNC(gtk_target_enter_callback
), (gpointer
) this );
970 gtk_signal_connect( GTK_OBJECT(widget
), "drop_leave_event",
971 GTK_SIGNAL_FUNC(gtk_target_leave_callback
), (gpointer
) this );
974 // ----------------------------------------------------------------------------
976 // ----------------------------------------------------------------------------
978 wxTextDropTarget::wxTextDropTarget()
980 m_format
= new wxDataFormat( wxDF_TEXT
);
983 bool wxTextDropTarget::OnDrop( long x
, long y
, const void *data
, size_t WXUNUSED(size
) )
985 OnDropText( x
, y
, (const char*)data
);
989 bool wxTextDropTarget::OnDropText( long x
, long y
, const char *psz
)
992 printf( "Got dropped text: %s.\n", psz );
993 printf( "At x: %d, y: %d.\n", (int)x, (int)y );
998 size_t wxTextDropTarget::GetFormatCount() const
1003 // ----------------------------------------------------------------------------
1004 // wxPrivateDropTarget
1005 // ----------------------------------------------------------------------------
1007 wxPrivateDropTarget::wxPrivateDropTarget()
1009 m_id
= wxTheApp
->GetAppName();
1010 m_format
= new wxDataFormat( m_id
);
1013 void wxPrivateDropTarget::SetId( const wxString
& id
)
1016 m_format
->SetId( id
);
1019 size_t wxPrivateDropTarget::GetFormatCount() const
1024 // ----------------------------------------------------------------------------
1026 // ----------------------------------------------------------------------------
1028 wxFileDropTarget::wxFileDropTarget()
1030 m_format
= new wxDataFormat( wxDF_FILENAME
);
1033 bool wxFileDropTarget::OnDropFiles( long x
, long y
, size_t nFiles
, const char * const aszFiles
[] )
1035 printf( "Got %d dropped files.\n", (int)nFiles
);
1036 printf( "At x: %d, y: %d.\n", (int)x
, (int)y
);
1038 for (size_t i
= 0; i
< nFiles
; i
++)
1040 printf( aszFiles
[i
] );
1047 bool wxFileDropTarget::OnDrop(long x
, long y
, const void *data
, size_t size
)
1051 char *text
= (char*) data
;
1052 for ( i
= 0; i
< size
; i
++)
1053 if (text
[i
] == 0) number
++;
1055 if (number
== 0) return TRUE
;
1057 char **files
= new char*[number
];
1059 text
= (char*) data
;
1060 for (i
= 0; i
< number
; i
++)
1063 int len
= strlen( text
);
1067 bool ret
= OnDropFiles( x
, y
, 1, files
);
1074 size_t wxFileDropTarget::GetFormatCount() const
1079 //-------------------------------------------------------------------------
1081 //-------------------------------------------------------------------------
1084 shape_motion (GtkWidget
*widget
,
1085 GdkEventMotion
* /*event*/);
1087 //-----------------------------------------------------------------------------
1088 // "drag_request_event"
1089 //-----------------------------------------------------------------------------
1091 void gtk_drag_callback( GtkWidget
*widget
, GdkEventDragRequest
*event
, wxDropSource
*source
)
1093 wxDataBroker
*data
= source
->m_data
;
1097 wxNode
*node
= data
->m_dataObjects
.First();
1099 wxDataObject
*dobj
= (wxDataObject
*) node
->Data();
1101 if ((strcmp(event
->data_type
,"file:ALL") == 0) &&
1102 (dobj
->GetFormat().GetType() == wxDF_FILENAME
))
1104 wxFileDataObject
*file_object
= (wxFileDataObject
*) dobj
;
1106 wxString text
= file_object
->GetFiles();
1108 char *s
= WXSTRINGCAST text
;
1110 gtk_widget_dnd_data_set( widget
,
1113 (int) text
.Length()+1 );
1115 source
->m_retValue
= wxDragCopy
;
1120 if ((strcmp(event
->data_type
,"text/plain") == 0) &&
1121 (dobj
->GetFormat().GetType() == wxDF_TEXT
))
1123 wxTextDataObject
*text_object
= (wxTextDataObject
*) dobj
;
1125 wxString text
= text_object
->GetText();
1127 char *s
= WXSTRINGCAST text
;
1129 gtk_widget_dnd_data_set( widget
,
1132 (int) text
.Length()+1 );
1134 source
->m_retValue
= wxDragCopy
;
1139 if (dobj
->GetFormat().GetType() == wxDF_PRIVATE
)
1141 wxPrivateDataObject
*pdo
= (wxPrivateDataObject
*) dobj
;
1143 if (pdo
->GetId() == event
->data_type
)
1145 gtk_widget_dnd_data_set( widget
,
1147 (unsigned char*) pdo
->GetData(),
1148 (int) pdo
->GetSize() );
1150 source
->m_retValue
= wxDragCopy
;
1156 node
= node
->Next();
1160 wxDropSource::wxDropSource( wxWindow
*win
, const wxIcon
&go
, const wxIcon
&stop
)
1162 g_blockEventsOnDrag
= TRUE
;
1165 m_widget
= win
->m_widget
;
1166 if (win
->m_wxwindow
) m_widget
= win
->m_wxwindow
;
1168 m_data
= (wxDataBroker
*) NULL
;
1169 m_retValue
= wxDragCancel
;
1171 m_defaultCursor
= wxCursor( wxCURSOR_NO_ENTRY
);
1172 m_goaheadCursor
= wxCursor( wxCURSOR_HAND
);
1175 if (wxNullIcon
== go
) m_goIcon
= wxIcon( page_xpm
);
1177 if (wxNullIcon
== stop
) m_stopIcon
= wxIcon( gv_xpm
);
1180 wxDropSource::wxDropSource( wxDataObject
*data
, wxWindow
*win
, const wxIcon
&go
, const wxIcon
&stop
)
1182 g_blockEventsOnDrag
= TRUE
;
1185 m_widget
= win
->m_widget
;
1186 if (win
->m_wxwindow
) m_widget
= win
->m_wxwindow
;
1187 m_retValue
= wxDragCancel
;
1191 m_data
= new wxDataBroker();
1192 m_data
->Add( data
);
1196 m_data
= (wxDataBroker
*) NULL
;
1199 m_defaultCursor
= wxCursor( wxCURSOR_NO_ENTRY
);
1200 m_goaheadCursor
= wxCursor( wxCURSOR_HAND
);
1203 if (wxNullIcon
== go
) m_goIcon
= wxIcon( page_xpm
);
1205 if (wxNullIcon
== stop
) m_stopIcon
= wxIcon( gv_xpm
);
1208 wxDropSource::wxDropSource( wxDataBroker
*data
, wxWindow
*win
)
1210 g_blockEventsOnDrag
= TRUE
;
1213 m_widget
= win
->m_widget
;
1214 if (win
->m_wxwindow
) m_widget
= win
->m_wxwindow
;
1215 m_retValue
= wxDragCancel
;
1219 m_defaultCursor
= wxCursor( wxCURSOR_NO_ENTRY
);
1220 m_goaheadCursor
= wxCursor( wxCURSOR_HAND
);
1223 void wxDropSource::SetData( wxDataObject
*data
)
1225 if (m_data
) delete m_data
;
1229 m_data
= new wxDataBroker();
1230 m_data
->Add( data
);
1234 m_data
= (wxDataBroker
*) NULL
;
1238 void wxDropSource::SetData( wxDataBroker
*data
)
1240 if (m_data
) delete m_data
;
1245 wxDropSource::~wxDropSource(void)
1247 if (m_data
) delete m_data
;
1249 g_blockEventsOnDrag
= FALSE
;
1252 wxDragResult
wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove
) )
1254 if (gdk_dnd
.dnd_grabbed
) return (wxDragResult
) wxDragNone
;
1255 if (gdk_dnd
.drag_really
) return (wxDragResult
) wxDragNone
;
1257 wxASSERT_MSG( m_data
, "wxDragSource: no data" );
1259 if (!m_data
) return (wxDragResult
) wxDragNone
;
1261 static GtkWidget
*drag_icon
= (GtkWidget
*) NULL
;
1262 static GtkWidget
*drop_icon
= (GtkWidget
*) NULL
;
1264 GdkPoint hotspot_1
= {0,-5 };
1268 drag_icon
= shape_create_icon ( m_stopIcon
,
1269 440, 140, 0,0, GTK_WINDOW_POPUP
);
1271 gtk_signal_connect (GTK_OBJECT (drag_icon
), "destroy",
1272 GTK_SIGNAL_FUNC(gtk_widget_destroyed
),
1275 gtk_widget_hide (drag_icon
);
1278 GdkPoint hotspot_2
= {-5,-5};
1282 drop_icon
= shape_create_icon ( m_goIcon
,
1283 440, 140, 0,0, GTK_WINDOW_POPUP
);
1285 gtk_signal_connect (GTK_OBJECT (drop_icon
), "destroy",
1286 GTK_SIGNAL_FUNC(gtk_widget_destroyed
),
1289 gtk_widget_hide (drop_icon
);
1293 gdk_dnd_set_drag_shape( drag_icon
->window
,
1299 GdkWindowPrivate
*wp
= (GdkWindowPrivate
*) m_widget
->window
;
1303 gdk_dnd
.drag_perhaps
= TRUE
;
1305 gdk_dnd
.dnd_drag_start
.x
= 5;
1306 gdk_dnd
.dnd_drag_start
.y
= 5;
1307 gdk_dnd
.real_sw
= wp
;
1309 if (gdk_dnd
.drag_startwindows
)
1311 g_free( gdk_dnd
.drag_startwindows
);
1312 gdk_dnd
.drag_startwindows
= (GdkWindow
**) NULL
;
1314 gdk_dnd
.drag_numwindows
= gdk_dnd
.drag_really
= 0;
1316 XWindowAttributes dnd_winattr
;
1317 XGetWindowAttributes( gdk_display
, wp
->xwindow
, &dnd_winattr
);
1318 wp
->dnd_drag_savedeventmask
= dnd_winattr
.your_event_mask
;
1320 gdk_dnd_drag_addwindow( m_widget
->window
);
1322 GdkEventDragBegin ev
;
1323 ev
.type
= GDK_DRAG_BEGIN
;
1324 ev
.window
= m_widget
->window
;
1326 ev
.u
.flags
.protocol_version
= DND_PROTOCOL_VERSION
;
1328 gdk_event_put( (GdkEvent
*)&ev
);
1330 XGrabPointer( gdk_display
, wp
->xwindow
, False
,
1331 ButtonMotionMask
| ButtonPressMask
| ButtonReleaseMask
| PointerMotionMask
,
1332 GrabModeAsync
, GrabModeAsync
, gdk_root_window
, None
, CurrentTime
);
1334 gdk_dnd_set_drag_cursors( m_defaultCursor
.GetCursor(), m_goaheadCursor
.GetCursor() );
1336 gdk_dnd
.dnd_grabbed
= TRUE
;
1337 gdk_dnd
.drag_really
= 1;
1341 wxGetMousePosition( &x
, &y
);
1343 gdk_dnd_display_drag_cursor( x
, y
, FALSE
, TRUE
);
1345 gs_currentDropSource
= this;
1347 while (gdk_dnd
.drag_really
|| gdk_dnd
.drag_perhaps
) wxYield();
1349 gs_currentDropSource
= (wxDropSource
*) NULL
;
1353 g_blockEventsOnDrag
= FALSE
;
1358 void wxDropSource::RegisterWindow(void)
1360 if (!m_data
) return;
1364 wxNode
*node
= m_data
->m_dataObjects
.First();
1367 wxDataObject
* dobj
= (wxDataObject
*) node
->Data();
1369 switch (dobj
->GetFormat().GetType())
1373 formats
+= "text/plain";
1378 formats
+= "file:ALL";
1383 wxPrivateDataObject
* pdo
= (wxPrivateDataObject
*) m_data
;
1384 formats
+= pdo
->GetId();
1390 node
= node
->Next();
1393 char *str
= WXSTRINGCAST formats
;
1395 gtk_widget_dnd_drag_set( m_widget
, TRUE
, &str
, 1 );
1397 gtk_signal_connect( GTK_OBJECT(m_widget
), "drag_request_event",
1398 GTK_SIGNAL_FUNC(gtk_drag_callback
), (gpointer
)this );
1401 void wxDropSource::UnregisterWindow(void)
1403 if (!m_widget
) return;
1405 gtk_widget_dnd_drag_set( m_widget
, FALSE
, (gchar
**) NULL
, 0 );
1407 gtk_signal_disconnect_by_data( GTK_OBJECT(m_widget
), (gpointer
)this );
1414 static GdkWindow
*root_win
= (GdkWindow
*) NULL
;
1416 typedef struct _cursoroffset
{gint x
,y
;} CursorOffset
;
1419 shape_pressed (GtkWidget
*widget
, GdkEventButton
*event
)
1423 /* ignore double and triple click */
1424 if (event
->type
!= GDK_BUTTON_PRESS
)
1427 p
= (CursorOffset
*)gtk_object_get_user_data (GTK_OBJECT(widget
));
1428 p
->x
= (int) event
->x
;
1429 p
->y
= (int) event
->y
;
1431 gtk_grab_add (widget
);
1432 gdk_pointer_grab (widget
->window
, TRUE
,
1434 (GDK_BUTTON_RELEASE_MASK
|
1435 GDK_BUTTON_MOTION_MASK
|
1436 GDK_POINTER_MOTION_HINT_MASK
),
1438 (GdkCursor
*) NULL
, 0);
1443 shape_released (GtkWidget
*widget
)
1445 gtk_grab_remove (widget
);
1446 gdk_pointer_ungrab (0);
1450 shape_motion (GtkWidget
*widget
,
1451 GdkEventMotion
* /*event*/ )
1455 GdkModifierType mask
;
1457 p
= (CursorOffset
*)gtk_object_get_user_data (GTK_OBJECT (widget
));
1460 * Can't use event->x / event->y here
1461 * because I need absolute coordinates.
1464 gdk_window_get_pointer (root_win
, &xp
, &yp
, &mask
);
1465 gtk_widget_set_uposition (widget
, xp
- p
->x
, yp
- p
->y
);
1467 if (gs_currentDropSource
) gs_currentDropSource
->GiveFeedback( wxDragCopy
, FALSE
);
1471 shape_create_icon (const wxIcon
&shape
,
1479 * GDK_WINDOW_TOPLEVEL works also, giving you a title border
1481 GtkWidget
*window
= gtk_window_new ((GtkWindowType
)window_type
);
1483 GtkWidget
*fixed
= gtk_fixed_new ();
1484 gtk_widget_set_usize (fixed
, 100,100);
1485 gtk_container_add (GTK_CONTAINER (window
), fixed
);
1486 gtk_widget_show (fixed
);
1488 gtk_widget_set_events (window
,
1489 gtk_widget_get_events (window
) |
1490 GDK_BUTTON_MOTION_MASK
|
1491 GDK_POINTER_MOTION_HINT_MASK
|
1492 GDK_BUTTON_PRESS_MASK
);
1494 gtk_widget_realize (window
);
1496 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
1497 if (shape
.GetMask()) mask
= shape
.GetMask()->GetBitmap();
1499 GtkWidget
*pixmap
= gtk_pixmap_new (shape
.GetPixmap(), mask
);
1500 gtk_fixed_put (GTK_FIXED (fixed
), pixmap
, px
,py
);
1501 gtk_widget_show (pixmap
);
1503 gtk_widget_shape_combine_mask (window
, mask
, px
,py
);
1506 gtk_signal_connect (GTK_OBJECT (window
), "button_press_event",
1507 GTK_SIGNAL_FUNC (shape_pressed
),NULL
);
1508 gtk_signal_connect (GTK_OBJECT (window
), "button_release_event",
1509 GTK_SIGNAL_FUNC (shape_released
),NULL
);
1510 gtk_signal_connect (GTK_OBJECT (window
), "motion_notify_event",
1511 GTK_SIGNAL_FUNC (shape_motion
),NULL
);
1513 CursorOffset
*icon_pos
= g_new (CursorOffset
, 1);
1514 gtk_object_set_user_data(GTK_OBJECT(window
), icon_pos
);
1516 gtk_widget_set_uposition (window
, x
, y
);
1517 gtk_widget_show (window
);
1527 // wxUSE_DRAG_AND_DROP