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"
15 #include "wx/window.h"
17 #include "wx/gdicmn.h"
20 #include "gdk/gdkprivate.h"
24 // ----------------------------------------------------------------------------
26 // ----------------------------------------------------------------------------
28 extern bool g_blockEventsOnDrag
;
31 #if (GTK_MINOR_VERSION == 1)
32 #if (GTK_MICRO_VERSION >= 3)
33 #define NEW_GTK_DND_CODE
37 #ifdef NEW_GTK_DND_CODE
39 #include "gtk/gtkdnd.h"
40 #include "gtk/gtkselection.h"
42 // ----------------------------------------------------------------------------
44 // ----------------------------------------------------------------------------
46 static void target_drag_leave( GtkWidget
*WXUNUSED(widget
),
47 GdkDragContext
*WXUNUSED(context
),
48 guint
WXUNUSED(time
) )
53 // ----------------------------------------------------------------------------
55 // ----------------------------------------------------------------------------
57 static gboolean
target_drag_motion( GtkWidget
*WXUNUSED(widget
),
58 GdkDragContext
*context
,
63 printf( "motion.\n" );
64 gdk_drag_status( context
, context
->suggested_action
, time
);
68 // ----------------------------------------------------------------------------
70 // ----------------------------------------------------------------------------
72 static gboolean
target_drag_drop( GtkWidget
*widget
,
73 GdkDragContext
*context
,
78 printf( "drop at: %d,%d.\n", x
, y
);
82 gtk_drag_get_data( widget
,
84 GPOINTER_TO_INT (context
->targets
->data
),
90 // ----------------------------------------------------------------------------
91 // "drag_data_received"
92 // ----------------------------------------------------------------------------
94 static void target_drag_data_received( GtkWidget
*WXUNUSED(widget
),
95 GdkDragContext
*context
,
98 GtkSelectionData
*data
,
102 printf( "data receive at: %d,%d.\n", x
, y
);
104 if ((data
->length
>= 0) && (data
->format
== 8))
106 wxString str
= (const char*)data
->data
;
107 printf( "Received %s\n.", WXSTRINGCAST str
);
108 gtk_drag_finish( context
, TRUE
, FALSE
, time
);
112 gtk_drag_finish (context
, FALSE
, FALSE
, time
);
115 // ----------------------------------------------------------------------------
117 // ----------------------------------------------------------------------------
119 wxDropTarget
::wxDropTarget()
123 wxDropTarget
::~wxDropTarget()
127 void wxDropTarget
::UnregisterWidget( GtkWidget
*widget
)
129 wxCHECK_RET( widget
!= NULL
, "unregister widget is NULL" );
131 gtk_drag_dest_set( widget
,
133 (GtkTargetEntry
*) NULL
,
137 gtk_signal_disconnect_by_func( GTK_OBJECT(widget
),
138 GTK_SIGNAL_FUNC(target_drag_leave
), (gpointer
) this );
140 gtk_signal_disconnect_by_func( GTK_OBJECT(widget
),
141 GTK_SIGNAL_FUNC(target_drag_motion
), (gpointer
) this );
143 gtk_signal_disconnect_by_func( GTK_OBJECT(widget
),
144 GTK_SIGNAL_FUNC(target_drag_drop
), (gpointer
) this );
146 gtk_signal_disconnect_by_func( GTK_OBJECT(widget
),
147 GTK_SIGNAL_FUNC(target_drag_data_received
), (gpointer
) this );
150 void wxDropTarget
::RegisterWidget( GtkWidget
*widget
)
152 wxCHECK_RET( widget
!= NULL
, "register widget is NULL" );
154 GtkTargetEntry format
;
159 for ( size_t i
= 0; i
< GetFormatCount(); i
++ )
161 wxDataFormat df
= GetFormat( i
);
165 format
.target
= "text/plain";
169 format
.target
= "file:ALL";
177 wxASSERT_MSG( valid
!= 0, "No valid DnD format supported." );
179 gtk_drag_dest_set( widget
,
180 GTK_DEST_DEFAULT_ALL
,
183 (GdkDragAction
)(GDK_ACTION_COPY
| GDK_ACTION_MOVE
) );
185 gtk_signal_connect( GTK_OBJECT(widget
), "drag_leave",
186 GTK_SIGNAL_FUNC(target_drag_leave
), (gpointer
) this );
188 gtk_signal_connect( GTK_OBJECT(widget
), "drag_motion",
189 GTK_SIGNAL_FUNC(target_drag_motion
), (gpointer
) this );
191 gtk_signal_connect( GTK_OBJECT(widget
), "drag_drop",
192 GTK_SIGNAL_FUNC(target_drag_drop
), (gpointer
) this );
194 gtk_signal_connect( GTK_OBJECT(widget
), "drag_data_received",
195 GTK_SIGNAL_FUNC(target_drag_data_received
), (gpointer
) this );
198 // ----------------------------------------------------------------------------
200 // ----------------------------------------------------------------------------
202 bool wxTextDropTarget
::OnDrop( long x
, long y
, const void *data
, size_t WXUNUSED(size
) )
204 OnDropText( x
, y
, (const char*)data
);
208 bool wxTextDropTarget
::OnDropText( long x
, long y
, const char *psz
)
210 printf( "Got dropped text: %s.\n", psz
);
211 printf( "At x: %d, y: %d.\n", (int)x
, (int)y
);
215 size_t wxTextDropTarget
::GetFormatCount() const
220 wxDataFormat wxTextDropTarget
::GetFormat(size_t WXUNUSED(n
)) const
225 // ----------------------------------------------------------------------------
227 // ----------------------------------------------------------------------------
229 bool wxFileDropTarget
::OnDropFiles( long x
, long y
, size_t nFiles
, const char * const aszFiles
[] )
231 printf( "Got %d dropped files.\n", (int)nFiles
);
232 printf( "At x: %d, y: %d.\n", (int)x
, (int)y
);
233 for (size_t i
= 0; i
< nFiles
; i
++)
235 printf( aszFiles
[i
] );
241 bool wxFileDropTarget
::OnDrop(long x
, long y
, const void *data
, size_t size
)
244 char *text
= (char*) data
;
245 for (size_t i
= 0; i
< size
; i
++)
246 if (text
[i
] == 0) number
++;
248 if (number
== 0) return TRUE
;
250 char **files
= new char*[number
];
253 for (size_t i
= 0; i
< number
; i
++)
256 int len
= strlen( text
);
260 bool ret
= OnDropFiles( x
, y
, 1, files
);
267 size_t wxFileDropTarget
::GetFormatCount() const
272 wxDataFormat wxFileDropTarget
::GetFormat(size_t WXUNUSED(n
)) const
274 return wxDF_FILENAME
;
277 //-------------------------------------------------------------------------
279 //-------------------------------------------------------------------------
281 wxDropSource
::wxDropSource( wxWindow
*win
)
283 g_blockEventsOnDrag
= TRUE
;
286 m_widget
= win
->m_widget
;
287 if (win
->m_wxwindow
) m_widget
= win
->m_wxwindow
;
289 m_data
= (wxDataObject
*) NULL
;
290 m_retValue
= wxDragCancel
;
292 m_defaultCursor
= wxCursor( wxCURSOR_NO_ENTRY
);
293 m_goaheadCursor
= wxCursor( wxCURSOR_HAND
);
296 wxDropSource
::wxDropSource( wxDataObject
&data
, wxWindow
*win
)
298 g_blockEventsOnDrag
= TRUE
;
301 m_widget
= win
->m_widget
;
302 if (win
->m_wxwindow
) m_widget
= win
->m_wxwindow
;
303 m_retValue
= wxDragCancel
;
307 m_defaultCursor
= wxCursor( wxCURSOR_NO_ENTRY
);
308 m_goaheadCursor
= wxCursor( wxCURSOR_HAND
);
311 void wxDropSource
::SetData( wxDataObject
&data
)
316 wxDropSource
::~wxDropSource(void)
318 // if (m_data) delete m_data;
320 g_blockEventsOnDrag
= FALSE
;
323 wxDragResult wxDropSource
::DoDragDrop( bool WXUNUSED(bAllowMove
) )
325 wxASSERT_MSG( m_data
, "wxDragSource: no data" );
327 if (!m_data
) return (wxDragResult
) wxDragNone
;
328 if (m_data
->GetDataSize() == 0) return (wxDragResult
) wxDragNone
;
336 g_blockEventsOnDrag
= FALSE
;
341 void wxDropSource
::RegisterWindow(void)
347 wxDataFormat df
= m_data
->GetPreferredFormat();
352 formats
+= "text/plain";
355 formats
+= "file:ALL";
361 char *str
= WXSTRINGCAST formats
;
366 void wxDropSource
::UnregisterWindow(void)
368 if (!m_widget
) return;
378 //-----------------------------------------------------------------------------
379 // "drop_data_available_event"
380 //-----------------------------------------------------------------------------
382 static void gtk_target_callback( GtkWidget
*widget
,
383 GdkEventDropDataAvailable
*event
,
384 wxDropTarget
*target
)
390 gdk_window_get_pointer( widget
->window
, &x
, &y
, (GdkModifierType
*) NULL
);
392 printf( "Drop data is of type %s.\n", event
->data_type
);
394 target
->OnDrop( x
, y
, (const void*)event
->data
, (size_t)event
->data_numbytes
);
398 g_free (event->data);
399 g_free (event->data_type);
403 // ----------------------------------------------------------------------------
405 // ----------------------------------------------------------------------------
407 wxDropTarget
::wxDropTarget()
411 wxDropTarget
::~wxDropTarget()
415 void wxDropTarget
::UnregisterWidget( GtkWidget
*widget
)
419 gtk_signal_disconnect_by_func( GTK_OBJECT(widget
),
420 GTK_SIGNAL_FUNC(gtk_target_callback
), (gpointer
) this );
422 gtk_widget_dnd_drop_set( widget
, FALSE
, (gchar
**) NULL
, 0, FALSE
);
425 void wxDropTarget
::RegisterWidget( GtkWidget
*widget
)
430 for ( size_t i
= 0; i
< GetFormatCount(); i
++ )
432 wxDataFormat df
= GetFormat( i
);
436 if (i
> 0) formats
+= ";";
437 formats
+= "text/plain";
441 if (i
> 0) formats
+= ";";
442 formats
+= "file:ALL";
450 char *str
= WXSTRINGCAST formats
;
452 gtk_widget_dnd_drop_set( widget
, TRUE
, &str
, valid
, FALSE
);
454 gtk_signal_connect( GTK_OBJECT(widget
), "drop_data_available_event",
455 GTK_SIGNAL_FUNC(gtk_target_callback
), (gpointer
) this );
458 // ----------------------------------------------------------------------------
460 // ----------------------------------------------------------------------------
462 bool wxTextDropTarget
::OnDrop( long x
, long y
, const void *data
, size_t WXUNUSED(size
) )
464 OnDropText( x
, y
, (const char*)data
);
468 bool wxTextDropTarget
::OnDropText( long x
, long y
, const char *psz
)
470 printf( "Got dropped text: %s.\n", psz
);
471 printf( "At x: %d, y: %d.\n", (int)x
, (int)y
);
475 size_t wxTextDropTarget
::GetFormatCount() const
480 wxDataFormat wxTextDropTarget
::GetFormat(size_t WXUNUSED(n
)) const
485 // ----------------------------------------------------------------------------
487 // ----------------------------------------------------------------------------
489 bool wxFileDropTarget
::OnDropFiles( long x
, long y
, size_t nFiles
, const char * const aszFiles
[] )
491 printf( "Got %d dropped files.\n", (int)nFiles
);
492 printf( "At x: %d, y: %d.\n", (int)x
, (int)y
);
493 for (size_t i
= 0; i
< nFiles
; i
++)
495 printf( aszFiles
[i
] );
501 bool wxFileDropTarget
::OnDrop(long x
, long y
, const void *data
, size_t size
)
504 char *text
= (char*) data
;
505 for (size_t i
= 0; i
< size
; i
++)
506 if (text
[i
] == 0) number
++;
508 if (number
== 0) return TRUE
;
510 char **files
= new char*[number
];
513 for (size_t i
= 0; i
< number
; i
++)
516 int len
= strlen( text
);
520 bool ret
= OnDropFiles( x
, y
, 1, files
);
527 size_t wxFileDropTarget
::GetFormatCount() const
532 wxDataFormat wxFileDropTarget
::GetFormat(size_t WXUNUSED(n
)) const
534 return wxDF_FILENAME
;
537 //-------------------------------------------------------------------------
539 //-------------------------------------------------------------------------
541 //-----------------------------------------------------------------------------
544 void gtk_drag_callback( GtkWidget
*widget
, GdkEvent
*event
, wxDropSource
*source
)
546 printf( "Data requested for dropping.\n" );
548 wxDataObject
*data
= source
->m_data
;
550 size_t size
= data
->GetDataSize();
551 char *ptr
= new char[size
];
552 data
->GetDataHere( ptr
);
554 gtk_widget_dnd_data_set( widget
, event
, ptr
, size
);
558 source
->m_retValue
= wxDragCopy
;
561 wxDropSource
::wxDropSource( wxWindow
*win
)
563 g_blockEventsOnDrag
= TRUE
;
566 m_widget
= win
->m_widget
;
567 if (win
->m_wxwindow
) m_widget
= win
->m_wxwindow
;
569 m_data
= (wxDataObject
*) NULL
;
570 m_retValue
= wxDragCancel
;
572 m_defaultCursor
= wxCursor( wxCURSOR_NO_ENTRY
);
573 m_goaheadCursor
= wxCursor( wxCURSOR_HAND
);
576 wxDropSource
::wxDropSource( wxDataObject
&data
, wxWindow
*win
)
578 g_blockEventsOnDrag
= TRUE
;
581 m_widget
= win
->m_widget
;
582 if (win
->m_wxwindow
) m_widget
= win
->m_wxwindow
;
583 m_retValue
= wxDragCancel
;
587 m_defaultCursor
= wxCursor( wxCURSOR_NO_ENTRY
);
588 m_goaheadCursor
= wxCursor( wxCURSOR_HAND
);
591 void wxDropSource
::SetData( wxDataObject
&data
)
596 wxDropSource
::~wxDropSource(void)
598 // if (m_data) delete m_data;
600 g_blockEventsOnDrag
= FALSE
;
603 wxDragResult wxDropSource
::DoDragDrop( bool WXUNUSED(bAllowMove
) )
605 if (gdk_dnd
.dnd_grabbed
) return (wxDragResult
) wxDragNone
;
606 if (gdk_dnd
.drag_really
) return (wxDragResult
) wxDragNone
;
608 wxASSERT_MSG( m_data
, "wxDragSource: no data" );
610 if (!m_data
) return (wxDragResult
) wxDragNone
;
611 if (m_data
->GetDataSize() == 0) return (wxDragResult
) wxDragNone
;
613 GdkWindowPrivate
*wp
= (GdkWindowPrivate
*) m_widget
->window
;
617 gdk_dnd
.drag_perhaps
= TRUE
;
619 gdk_dnd
.dnd_drag_start
.x
= 5;
620 gdk_dnd
.dnd_drag_start
.y
= 5;
621 gdk_dnd
.real_sw
= wp
;
623 if (gdk_dnd
.drag_startwindows
)
625 g_free( gdk_dnd
.drag_startwindows
);
626 gdk_dnd
.drag_startwindows
= (GdkWindow
**) NULL
;
628 gdk_dnd
.drag_numwindows
= gdk_dnd
.drag_really
= 0;
630 XWindowAttributes dnd_winattr
;
631 XGetWindowAttributes( gdk_display
, wp
->xwindow
, &dnd_winattr
);
632 wp
->dnd_drag_savedeventmask
= dnd_winattr
.your_event_mask
;
634 gdk_dnd_drag_addwindow( m_widget
->window
);
636 GdkEventDragBegin ev
;
637 ev
.type
= GDK_DRAG_BEGIN
;
638 ev
.window
= m_widget
->window
;
640 ev
.u
.flags
.protocol_version
= DND_PROTOCOL_VERSION
;
642 gdk_event_put( (GdkEvent
*)&ev
);
644 XGrabPointer( gdk_display
, wp
->xwindow
, False
,
645 ButtonMotionMask
| ButtonPressMask
| ButtonReleaseMask
| PointerMotionMask
,
646 GrabModeAsync
, GrabModeAsync
, gdk_root_window
, None
, CurrentTime
);
648 gdk_dnd_set_drag_cursors( m_defaultCursor
.GetCursor(), m_goaheadCursor
.GetCursor() );
650 gdk_dnd
.dnd_grabbed
= TRUE
;
651 gdk_dnd
.drag_really
= 1;
655 gdk_window_get_pointer( m_widget
->window
, &x
, &y
, (GdkModifierType
*) NULL
);
657 gdk_dnd_display_drag_cursor( x
, y
, FALSE
, TRUE
);
659 while (gdk_dnd
.drag_really
|| gdk_dnd
.drag_perhaps
) wxYield();
663 g_blockEventsOnDrag
= FALSE
;
668 void wxDropSource
::RegisterWindow(void)
674 wxDataFormat df
= m_data
->GetPreferredFormat();
679 formats
+= "text/plain";
682 formats
+= "file:ALL";
688 char *str
= WXSTRINGCAST formats
;
690 gtk_widget_dnd_drag_set( m_widget
, TRUE
, &str
, 1 );
692 gtk_signal_connect( GTK_OBJECT(m_widget
), "drag_request_event",
693 GTK_SIGNAL_FUNC(gtk_drag_callback
), (gpointer
)this );
696 void wxDropSource
::UnregisterWindow(void)
698 if (!m_widget
) return;
700 gtk_widget_dnd_drag_set( m_widget
, FALSE
, (gchar
**) NULL
, 0 );
702 gtk_signal_disconnect_by_data( GTK_OBJECT(m_widget
), (gpointer
)this );