From 829e3e8d3d177f5323e1ed7eec733f33a10a0df8 Mon Sep 17 00:00:00 2001 From: Robert Roebling Date: Mon, 12 Apr 1999 22:56:14 +0000 Subject: [PATCH] wxDropTarget starts to work git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@2117 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/gtk/dnd.h | 22 +++- include/wx/gtk1/dnd.h | 22 +++- samples/dnd/dnd.cpp | 2 +- src/gtk/dnd.cpp | 268 ++++++++++++++++++++++++++++++------------ src/gtk1/dnd.cpp | 268 ++++++++++++++++++++++++++++++------------ 5 files changed, 423 insertions(+), 159 deletions(-) diff --git a/include/wx/gtk/dnd.h b/include/wx/gtk/dnd.h index 3c918bad23..a546b66b12 100644 --- a/include/wx/gtk/dnd.h +++ b/include/wx/gtk/dnd.h @@ -113,15 +113,19 @@ public: /* may be overridden to react to events */ virtual void OnEnter(); virtual void OnLeave(); + + /* may be overridden to reject certain formats or drops + on certain areas */ virtual bool OnMove( int x, int y ); - /* has te be overridden to get data */ + /* has to be overridden to accept drop. call GetData() to + indicate the format you request and get the data. */ virtual bool OnDrop( int x, int y ); - /* called to query formats available */ + /* called to query what formats are available */ bool IsSupported( wxDataFormat format ); - /* fill data with data on the clipboard (if available) */ + /* fill data with data from the dragging source */ bool GetData( wxDataObject *data ); // implementation @@ -129,10 +133,17 @@ public: void RegisterWidget( GtkWidget *widget ); void UnregisterWidget( GtkWidget *widget ); - GdkDragContext *m_dragContext; + GdkDragContext *m_dragContext; + GtkWidget *m_dragWidget; + guint m_dragTime; + bool m_firstMotion; /* gdk has no "gdk_drag_enter" event */ + bool m_waiting; /* asynchronous process */ + bool m_dataRetrieveSuccess; + wxDataObject *m_currentDataObject; void SetDragContext( GdkDragContext *dc ) { m_dragContext = dc; } - GdkDragContext *GetDragContext() { return m_dragContext; } + void SetDragWidget( GtkWidget *w ) { m_dragWidget = w; } + void SetDragTime( guint time ) { m_dragTime = time; } }; //------------------------------------------------------------------------- @@ -197,6 +208,7 @@ public: virtual bool OnMove( int x, int y ); virtual bool OnDrop( int x, int y ); + virtual void OnData( int x, int y ); /* you have to override OnDropFiles to get at the file names */ virtual bool OnDropFiles( int x, int y, size_t nFiles, const char * const aszFiles[] ) = 0; diff --git a/include/wx/gtk1/dnd.h b/include/wx/gtk1/dnd.h index 3c918bad23..a546b66b12 100644 --- a/include/wx/gtk1/dnd.h +++ b/include/wx/gtk1/dnd.h @@ -113,15 +113,19 @@ public: /* may be overridden to react to events */ virtual void OnEnter(); virtual void OnLeave(); + + /* may be overridden to reject certain formats or drops + on certain areas */ virtual bool OnMove( int x, int y ); - /* has te be overridden to get data */ + /* has to be overridden to accept drop. call GetData() to + indicate the format you request and get the data. */ virtual bool OnDrop( int x, int y ); - /* called to query formats available */ + /* called to query what formats are available */ bool IsSupported( wxDataFormat format ); - /* fill data with data on the clipboard (if available) */ + /* fill data with data from the dragging source */ bool GetData( wxDataObject *data ); // implementation @@ -129,10 +133,17 @@ public: void RegisterWidget( GtkWidget *widget ); void UnregisterWidget( GtkWidget *widget ); - GdkDragContext *m_dragContext; + GdkDragContext *m_dragContext; + GtkWidget *m_dragWidget; + guint m_dragTime; + bool m_firstMotion; /* gdk has no "gdk_drag_enter" event */ + bool m_waiting; /* asynchronous process */ + bool m_dataRetrieveSuccess; + wxDataObject *m_currentDataObject; void SetDragContext( GdkDragContext *dc ) { m_dragContext = dc; } - GdkDragContext *GetDragContext() { return m_dragContext; } + void SetDragWidget( GtkWidget *w ) { m_dragWidget = w; } + void SetDragTime( guint time ) { m_dragTime = time; } }; //------------------------------------------------------------------------- @@ -197,6 +208,7 @@ public: virtual bool OnMove( int x, int y ); virtual bool OnDrop( int x, int y ); + virtual void OnData( int x, int y ); /* you have to override OnDropFiles to get at the file names */ virtual bool OnDropFiles( int x, int y, size_t nFiles, const char * const aszFiles[] ) = 0; diff --git a/samples/dnd/dnd.cpp b/samples/dnd/dnd.cpp index d034080d1c..64244a8a00 100644 --- a/samples/dnd/dnd.cpp +++ b/samples/dnd/dnd.cpp @@ -239,7 +239,7 @@ void DnDFrame::OnPaint(wxPaintEvent& /*event*/) wxPaintDC dc(this); dc.SetFont( wxFont( 24, wxDECORATIVE, wxNORMAL, wxNORMAL, FALSE, "charter" ) ); - dc.DrawText( "Drag text from here!", 20, h-22 ); + dc.DrawText( "Drag text from here!", 20, h-35 ); } void DnDFrame::OnDrag(wxCommandEvent& /* event */) diff --git a/src/gtk/dnd.cpp b/src/gtk/dnd.cpp index ff56d90299..00f4e0d90a 100644 --- a/src/gtk/dnd.cpp +++ b/src/gtk/dnd.cpp @@ -135,11 +135,21 @@ static char * page_xpm[] = { static void target_drag_leave( GtkWidget *WXUNUSED(widget), GdkDragContext *context, guint WXUNUSED(time), - wxDropTarget *dt ) + wxDropTarget *drop_target ) { - dt->SetDragContext( context ); - dt->OnLeave(); - dt->SetDragContext( (GdkDragContext*) NULL ); + /* inform the wxDropTarget about the current GdkDragContext. + this is only valid for the duration of this call */ + drop_target->SetDragContext( context ); + + /* we don't need return values. this event is just for + information */ + drop_target->OnLeave(); + + /* this has to be done because GDK has no "drag_enter" event */ + drop_target->m_firstMotion = TRUE; + + /* after this, invalidate the drop_target's GdkDragContext */ + drop_target->SetDragContext( (GdkDragContext*) NULL ); } // ---------------------------------------------------------------------------- @@ -151,21 +161,38 @@ static gboolean target_drag_motion( GtkWidget *WXUNUSED(widget), gint x, gint y, guint time, - wxDropTarget *dt ) + wxDropTarget *drop_target ) { - dt->SetDragContext( context ); + /* Owen Taylor: "if the coordinates not in a drop zone, + return FALSE, otherwise call gtk_drag_status() and + return TRUE" */ + + /* inform the wxDropTarget about the current GdkDragContext. + this is only valid for the duration of this call */ + drop_target->SetDragContext( context ); - if (dt->OnMove( x, y )) + if (drop_target->m_firstMotion) { - gdk_drag_status( context, context->suggested_action, time ); - } - else - { - gdk_drag_status( context, (GdkDragAction)0, time ); + /* the first "drag_motion" event substitutes a "drag_enter" event */ + drop_target->OnEnter(); } - dt->SetDragContext( (GdkDragContext*) NULL ); - return TRUE; + /* give program a chance to react (i.e. to say no by returning FALSE) */ + bool ret = drop_target->OnMove( x, y ); + + /* we don't yet handle which "actions" (i.e. copy or move) + the target accepts. so far we simply accept the + suggested action. TODO. */ + if (ret) + gdk_drag_status( context, context->suggested_action, time ); + + /* after this, invalidate the drop_target's GdkDragContext */ + drop_target->SetDragContext( (GdkDragContext*) NULL ); + + /* this has to be done because GDK has no "drag_enter" event */ + drop_target->m_firstMotion = FALSE; + + return ret; } // ---------------------------------------------------------------------------- @@ -176,18 +203,59 @@ static gboolean target_drag_drop( GtkWidget *widget, GdkDragContext *context, gint x, gint y, - guint time ) + guint time, + wxDropTarget *drop_target ) { - printf( "drop at: %d,%d.\n", x, y ); + /* Owen Taylor: "if the drop is not in a drop zone, + return FALSE, otherwise, if you aren't accepting + the drop, call gtk_drag_finish() with success == FALSE + otherwise call gtk_drag_data_get()" */ + + /* this seems to make a difference between not accepting + due to wrong target area and due to wrong format. let + us hope that this is not required.. */ - if (context->targets) + /* inform the wxDropTarget about the current GdkDragContext. + this is only valid for the duration of this call */ + drop_target->SetDragContext( context ); + + /* inform the wxDropTarget about the current drag widget. + this is only valid for the duration of this call */ + drop_target->SetDragWidget( widget ); + + /* inform the wxDropTarget about the current drag time. + this is only valid for the duration of this call */ + drop_target->SetDragTime( time ); + + bool ret = drop_target->OnDrop( x, y ); + + if (ret) { + /* this should trigger an "drag_data_received" event */ gtk_drag_get_data( widget, context, GPOINTER_TO_INT (context->targets->data), time ); } - return FALSE; + else + { + /* cancel the whole thing */ + gtk_drag_finish( context, + FALSE, /* no success */ + FALSE, /* don't delete data on dropping side */ + time ); + } + + /* after this, invalidate the drop_target's GdkDragContext */ + drop_target->SetDragContext( (GdkDragContext*) NULL ); + + /* after this, invalidate the drop_target's drag widget */ + drop_target->SetDragWidget( (GtkWidget*) NULL ); + + /* this has to be done because GDK has no "drag_enter" event */ + drop_target->m_firstMotion = TRUE; + + return ret; } // ---------------------------------------------------------------------------- @@ -200,19 +268,53 @@ static void target_drag_data_received( GtkWidget *WXUNUSED(widget), gint y, GtkSelectionData *data, guint WXUNUSED(info), - guint time ) + guint time, + wxDropTarget *drop_target ) { - printf( "data receive at: %d,%d.\n", x, y ); - - if ((data->length >= 0) && (data->format == 8)) + /* Owen Taylor: "call gtk_drag_finish() with + success == TRUE" */ + + /* strangely, we get a "drag_data_received" event even when + we don't request them. this checks this. */ + if (!drop_target->m_currentDataObject) return; + + wxDataObject *data_object = drop_target->m_currentDataObject; + + if ((data->length <= 0) || (data->format != 8)) { - wxString str = (const char*)data->data; - printf( "Received %s\n.", WXSTRINGCAST str ); + /* negative data length and non 8-bit data format + qualifies for junk */ + gtk_drag_finish (context, FALSE, FALSE, time); + } + else + { + wxASSERT_MSG( data->target == data_object->GetFormat().GetAtom(), "DnD GetData target mismatch." ); + + if (data_object->GetFormat().GetType() == wxDF_TEXT) + { + wxTextDataObject *text_object = (wxTextDataObject*)data_object; + text_object->SetText( (const char*)data->data ); + } else + + if (data_object->GetFormat().GetType() == wxDF_FILENAME) + { + } else + + if (data_object->GetFormat().GetType() == wxDF_PRIVATE) + { + wxPrivateDataObject *priv_object = (wxPrivateDataObject*)data_object; + priv_object->SetData( (const char*)data->data, (size_t)data->length ); + } + + /* tell wxDropTarget that data transfer was successfull */ + drop_target->m_dataRetrieveSuccess = TRUE; + + /* tell GTK that data transfer was successfull */ gtk_drag_finish( context, TRUE, FALSE, time ); - return; } - - gtk_drag_finish (context, FALSE, FALSE, time); + + /* tell wxDropTarget that data has arrived (or not) */ + drop_target->m_waiting = FALSE; } // ---------------------------------------------------------------------------- @@ -221,6 +323,12 @@ static void target_drag_data_received( GtkWidget *WXUNUSED(widget), wxDropTarget::wxDropTarget() { + m_firstMotion = TRUE; + m_dragContext = (GdkDragContext*) NULL; + m_dragWidget = (GtkWidget*) NULL; + m_dragTime = 0; + m_currentDataObject = (wxDataObject*) NULL; + m_dataRetrieveSuccess = FALSE; } wxDropTarget::~wxDropTarget() @@ -235,54 +343,63 @@ void wxDropTarget::OnLeave() { } -bool wxDropTarget::OnMove( int x, int y ) +bool wxDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) ) { - printf( "generic move %d %d.\n", x, y ); - return TRUE; } -bool wxDropTarget::OnDrop( int x, int y ) +bool wxDropTarget::OnDrop( int WXUNUSED(x), int WXUNUSED(y) ) { - printf( "generic drop %d %d.\n", x, y ); - - return TRUE; + return FALSE; } bool wxDropTarget::IsSupported( wxDataFormat format ) { - printf( "generic is supported.\n" ); - if (!m_dragContext) return FALSE; GList *child = m_dragContext->targets; while (child) { GdkAtom formatAtom = (GdkAtom) GPOINTER_TO_INT(child->data); - char *name = gdk_atom_name( formatAtom ); - if (name) printf( "Format available: %s.\n", name ); - + +/* char *name = gdk_atom_name( formatAtom ); + if (name) printf( "Format available: %s.\n", name ); */ + + if (formatAtom == format.GetAtom()) return TRUE; child = child->next; } - - - return TRUE; + + return FALSE; } bool wxDropTarget::GetData( wxDataObject *data ) { - return FALSE; + if (!m_dragContext) return FALSE; + if (!m_dragWidget) return FALSE; + + m_currentDataObject = data; + m_dataRetrieveSuccess = FALSE; + + /* this should trigger an "drag_data_received" event */ + gtk_drag_get_data( m_dragWidget, + m_dragContext, + data->GetFormat().GetAtom(), + m_dragTime ); + + /* wait for the "drag_data_received" event */ + m_waiting = TRUE; + while (m_waiting) gtk_main_iteration(); + + m_currentDataObject = (wxDataObject*) NULL; + + return m_dataRetrieveSuccess; } void wxDropTarget::UnregisterWidget( GtkWidget *widget ) { wxCHECK_RET( widget != NULL, "unregister widget is NULL" ); - gtk_drag_dest_set( widget, - (GtkDestDefaults) 0, - (GtkTargetEntry*) NULL, - 0, - (GdkDragAction) 0 ); + gtk_drag_dest_unset( widget ); gtk_signal_disconnect_by_func( GTK_OBJECT(widget), GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this ); @@ -301,18 +418,21 @@ void wxDropTarget::RegisterWidget( GtkWidget *widget ) { wxCHECK_RET( widget != NULL, "register widget is NULL" ); - GtkTargetEntry format; - format.info = 0; - format.flags = 0; - char buf[100]; - strcpy( buf, "text/plain" ); - format.target = buf; + /* gtk_drag_dest_set() determines what default behaviour we'd like + GTK to supply. we don't want to specify out targets (=formats) + or actions in advance (i.e. not GTK_DEST_DEFAULT_MOTION and + not GTK_DEST_DEFAULT_DROP). instead we react individually to + "drag_motion" and "drag_drop" events. this makes it possible + to allow dropping on only a small area. we should set + GTK_DEST_DEFAULT_HIGHLIGHT as this will switch on the nice + highlighting if dragging over standard controls, but this + seems to be broken without the other two. */ gtk_drag_dest_set( widget, - GTK_DEST_DEFAULT_ALL, - &format, - 1, - (GdkDragAction)(GDK_ACTION_COPY | GDK_ACTION_MOVE) ); + (GtkDestDefaults) 0, /* no default behaviour */ + (GtkTargetEntry*) NULL, /* we don't supply any formats here */ + 0, /* number of targets = 0 */ + (GdkDragAction) 0 ); /* we don't supply any actions here */ gtk_signal_connect( GTK_OBJECT(widget), "drag_leave", GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this ); @@ -333,21 +453,18 @@ void wxDropTarget::RegisterWidget( GtkWidget *widget ) bool wxTextDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) ) { - printf( "text move.\n" ); - - return IsSupported( wxDF_TEXT ); // same as "TEXT" + return IsSupported( wxDF_TEXT ); // same as "STRING" } bool wxTextDropTarget::OnDrop( int x, int y ) { - printf( "text drop.\n" ); - if (!IsSupported( wxDF_TEXT )) return FALSE; - + wxTextDataObject data; if (!GetData( &data )) return FALSE; - return OnDropText( x, y, data.GetText() ); + OnDropText( x, y, data.GetText() ); + return TRUE; } //------------------------------------------------------------------------- @@ -372,11 +489,13 @@ bool wxPrivateDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) ) bool wxPrivateDropTarget::OnDrop( int x, int y ) { if (!IsSupported( m_id )) return FALSE; - + wxPrivateDataObject data; if (!GetData( &data )) return FALSE; - return OnDropData( x, y, data.GetData(), data.GetSize() ); + OnDropData( x, y, data.GetData(), data.GetSize() ); + + return TRUE; } //---------------------------------------------------------------------------- @@ -390,10 +509,13 @@ bool wxFileDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) ) bool wxFileDropTarget::OnDrop( int x, int y ) { - if (!IsSupported( wxDF_FILENAME )) return FALSE; - + return IsSupported( wxDF_FILENAME ); // same as "file:ALL" +} + +void wxFileDropTarget::OnData( int x, int y ) +{ wxFileDataObject data; - if (!GetData( &data )) return FALSE; + if (!GetData( &data )) return; /* get number of substrings /root/mytext.txt/0/root/myothertext.txt/0/0 */ size_t number = 0; @@ -403,7 +525,7 @@ bool wxFileDropTarget::OnDrop( int x, int y ) for ( i = 0; i < size; i++) if (text[i] == 0) number++; - if (number == 0) return TRUE; + if (number == 0) return; char **files = new char*[number]; @@ -415,11 +537,9 @@ bool wxFileDropTarget::OnDrop( int x, int y ) text += len+1; } - bool ret = OnDropFiles( x, y, number, files ); + OnDropFiles( x, y, number, files ); free( files ); - - return ret; } //------------------------------------------------------------------------- diff --git a/src/gtk1/dnd.cpp b/src/gtk1/dnd.cpp index ff56d90299..00f4e0d90a 100644 --- a/src/gtk1/dnd.cpp +++ b/src/gtk1/dnd.cpp @@ -135,11 +135,21 @@ static char * page_xpm[] = { static void target_drag_leave( GtkWidget *WXUNUSED(widget), GdkDragContext *context, guint WXUNUSED(time), - wxDropTarget *dt ) + wxDropTarget *drop_target ) { - dt->SetDragContext( context ); - dt->OnLeave(); - dt->SetDragContext( (GdkDragContext*) NULL ); + /* inform the wxDropTarget about the current GdkDragContext. + this is only valid for the duration of this call */ + drop_target->SetDragContext( context ); + + /* we don't need return values. this event is just for + information */ + drop_target->OnLeave(); + + /* this has to be done because GDK has no "drag_enter" event */ + drop_target->m_firstMotion = TRUE; + + /* after this, invalidate the drop_target's GdkDragContext */ + drop_target->SetDragContext( (GdkDragContext*) NULL ); } // ---------------------------------------------------------------------------- @@ -151,21 +161,38 @@ static gboolean target_drag_motion( GtkWidget *WXUNUSED(widget), gint x, gint y, guint time, - wxDropTarget *dt ) + wxDropTarget *drop_target ) { - dt->SetDragContext( context ); + /* Owen Taylor: "if the coordinates not in a drop zone, + return FALSE, otherwise call gtk_drag_status() and + return TRUE" */ + + /* inform the wxDropTarget about the current GdkDragContext. + this is only valid for the duration of this call */ + drop_target->SetDragContext( context ); - if (dt->OnMove( x, y )) + if (drop_target->m_firstMotion) { - gdk_drag_status( context, context->suggested_action, time ); - } - else - { - gdk_drag_status( context, (GdkDragAction)0, time ); + /* the first "drag_motion" event substitutes a "drag_enter" event */ + drop_target->OnEnter(); } - dt->SetDragContext( (GdkDragContext*) NULL ); - return TRUE; + /* give program a chance to react (i.e. to say no by returning FALSE) */ + bool ret = drop_target->OnMove( x, y ); + + /* we don't yet handle which "actions" (i.e. copy or move) + the target accepts. so far we simply accept the + suggested action. TODO. */ + if (ret) + gdk_drag_status( context, context->suggested_action, time ); + + /* after this, invalidate the drop_target's GdkDragContext */ + drop_target->SetDragContext( (GdkDragContext*) NULL ); + + /* this has to be done because GDK has no "drag_enter" event */ + drop_target->m_firstMotion = FALSE; + + return ret; } // ---------------------------------------------------------------------------- @@ -176,18 +203,59 @@ static gboolean target_drag_drop( GtkWidget *widget, GdkDragContext *context, gint x, gint y, - guint time ) + guint time, + wxDropTarget *drop_target ) { - printf( "drop at: %d,%d.\n", x, y ); + /* Owen Taylor: "if the drop is not in a drop zone, + return FALSE, otherwise, if you aren't accepting + the drop, call gtk_drag_finish() with success == FALSE + otherwise call gtk_drag_data_get()" */ + + /* this seems to make a difference between not accepting + due to wrong target area and due to wrong format. let + us hope that this is not required.. */ - if (context->targets) + /* inform the wxDropTarget about the current GdkDragContext. + this is only valid for the duration of this call */ + drop_target->SetDragContext( context ); + + /* inform the wxDropTarget about the current drag widget. + this is only valid for the duration of this call */ + drop_target->SetDragWidget( widget ); + + /* inform the wxDropTarget about the current drag time. + this is only valid for the duration of this call */ + drop_target->SetDragTime( time ); + + bool ret = drop_target->OnDrop( x, y ); + + if (ret) { + /* this should trigger an "drag_data_received" event */ gtk_drag_get_data( widget, context, GPOINTER_TO_INT (context->targets->data), time ); } - return FALSE; + else + { + /* cancel the whole thing */ + gtk_drag_finish( context, + FALSE, /* no success */ + FALSE, /* don't delete data on dropping side */ + time ); + } + + /* after this, invalidate the drop_target's GdkDragContext */ + drop_target->SetDragContext( (GdkDragContext*) NULL ); + + /* after this, invalidate the drop_target's drag widget */ + drop_target->SetDragWidget( (GtkWidget*) NULL ); + + /* this has to be done because GDK has no "drag_enter" event */ + drop_target->m_firstMotion = TRUE; + + return ret; } // ---------------------------------------------------------------------------- @@ -200,19 +268,53 @@ static void target_drag_data_received( GtkWidget *WXUNUSED(widget), gint y, GtkSelectionData *data, guint WXUNUSED(info), - guint time ) + guint time, + wxDropTarget *drop_target ) { - printf( "data receive at: %d,%d.\n", x, y ); - - if ((data->length >= 0) && (data->format == 8)) + /* Owen Taylor: "call gtk_drag_finish() with + success == TRUE" */ + + /* strangely, we get a "drag_data_received" event even when + we don't request them. this checks this. */ + if (!drop_target->m_currentDataObject) return; + + wxDataObject *data_object = drop_target->m_currentDataObject; + + if ((data->length <= 0) || (data->format != 8)) { - wxString str = (const char*)data->data; - printf( "Received %s\n.", WXSTRINGCAST str ); + /* negative data length and non 8-bit data format + qualifies for junk */ + gtk_drag_finish (context, FALSE, FALSE, time); + } + else + { + wxASSERT_MSG( data->target == data_object->GetFormat().GetAtom(), "DnD GetData target mismatch." ); + + if (data_object->GetFormat().GetType() == wxDF_TEXT) + { + wxTextDataObject *text_object = (wxTextDataObject*)data_object; + text_object->SetText( (const char*)data->data ); + } else + + if (data_object->GetFormat().GetType() == wxDF_FILENAME) + { + } else + + if (data_object->GetFormat().GetType() == wxDF_PRIVATE) + { + wxPrivateDataObject *priv_object = (wxPrivateDataObject*)data_object; + priv_object->SetData( (const char*)data->data, (size_t)data->length ); + } + + /* tell wxDropTarget that data transfer was successfull */ + drop_target->m_dataRetrieveSuccess = TRUE; + + /* tell GTK that data transfer was successfull */ gtk_drag_finish( context, TRUE, FALSE, time ); - return; } - - gtk_drag_finish (context, FALSE, FALSE, time); + + /* tell wxDropTarget that data has arrived (or not) */ + drop_target->m_waiting = FALSE; } // ---------------------------------------------------------------------------- @@ -221,6 +323,12 @@ static void target_drag_data_received( GtkWidget *WXUNUSED(widget), wxDropTarget::wxDropTarget() { + m_firstMotion = TRUE; + m_dragContext = (GdkDragContext*) NULL; + m_dragWidget = (GtkWidget*) NULL; + m_dragTime = 0; + m_currentDataObject = (wxDataObject*) NULL; + m_dataRetrieveSuccess = FALSE; } wxDropTarget::~wxDropTarget() @@ -235,54 +343,63 @@ void wxDropTarget::OnLeave() { } -bool wxDropTarget::OnMove( int x, int y ) +bool wxDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) ) { - printf( "generic move %d %d.\n", x, y ); - return TRUE; } -bool wxDropTarget::OnDrop( int x, int y ) +bool wxDropTarget::OnDrop( int WXUNUSED(x), int WXUNUSED(y) ) { - printf( "generic drop %d %d.\n", x, y ); - - return TRUE; + return FALSE; } bool wxDropTarget::IsSupported( wxDataFormat format ) { - printf( "generic is supported.\n" ); - if (!m_dragContext) return FALSE; GList *child = m_dragContext->targets; while (child) { GdkAtom formatAtom = (GdkAtom) GPOINTER_TO_INT(child->data); - char *name = gdk_atom_name( formatAtom ); - if (name) printf( "Format available: %s.\n", name ); - + +/* char *name = gdk_atom_name( formatAtom ); + if (name) printf( "Format available: %s.\n", name ); */ + + if (formatAtom == format.GetAtom()) return TRUE; child = child->next; } - - - return TRUE; + + return FALSE; } bool wxDropTarget::GetData( wxDataObject *data ) { - return FALSE; + if (!m_dragContext) return FALSE; + if (!m_dragWidget) return FALSE; + + m_currentDataObject = data; + m_dataRetrieveSuccess = FALSE; + + /* this should trigger an "drag_data_received" event */ + gtk_drag_get_data( m_dragWidget, + m_dragContext, + data->GetFormat().GetAtom(), + m_dragTime ); + + /* wait for the "drag_data_received" event */ + m_waiting = TRUE; + while (m_waiting) gtk_main_iteration(); + + m_currentDataObject = (wxDataObject*) NULL; + + return m_dataRetrieveSuccess; } void wxDropTarget::UnregisterWidget( GtkWidget *widget ) { wxCHECK_RET( widget != NULL, "unregister widget is NULL" ); - gtk_drag_dest_set( widget, - (GtkDestDefaults) 0, - (GtkTargetEntry*) NULL, - 0, - (GdkDragAction) 0 ); + gtk_drag_dest_unset( widget ); gtk_signal_disconnect_by_func( GTK_OBJECT(widget), GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this ); @@ -301,18 +418,21 @@ void wxDropTarget::RegisterWidget( GtkWidget *widget ) { wxCHECK_RET( widget != NULL, "register widget is NULL" ); - GtkTargetEntry format; - format.info = 0; - format.flags = 0; - char buf[100]; - strcpy( buf, "text/plain" ); - format.target = buf; + /* gtk_drag_dest_set() determines what default behaviour we'd like + GTK to supply. we don't want to specify out targets (=formats) + or actions in advance (i.e. not GTK_DEST_DEFAULT_MOTION and + not GTK_DEST_DEFAULT_DROP). instead we react individually to + "drag_motion" and "drag_drop" events. this makes it possible + to allow dropping on only a small area. we should set + GTK_DEST_DEFAULT_HIGHLIGHT as this will switch on the nice + highlighting if dragging over standard controls, but this + seems to be broken without the other two. */ gtk_drag_dest_set( widget, - GTK_DEST_DEFAULT_ALL, - &format, - 1, - (GdkDragAction)(GDK_ACTION_COPY | GDK_ACTION_MOVE) ); + (GtkDestDefaults) 0, /* no default behaviour */ + (GtkTargetEntry*) NULL, /* we don't supply any formats here */ + 0, /* number of targets = 0 */ + (GdkDragAction) 0 ); /* we don't supply any actions here */ gtk_signal_connect( GTK_OBJECT(widget), "drag_leave", GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this ); @@ -333,21 +453,18 @@ void wxDropTarget::RegisterWidget( GtkWidget *widget ) bool wxTextDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) ) { - printf( "text move.\n" ); - - return IsSupported( wxDF_TEXT ); // same as "TEXT" + return IsSupported( wxDF_TEXT ); // same as "STRING" } bool wxTextDropTarget::OnDrop( int x, int y ) { - printf( "text drop.\n" ); - if (!IsSupported( wxDF_TEXT )) return FALSE; - + wxTextDataObject data; if (!GetData( &data )) return FALSE; - return OnDropText( x, y, data.GetText() ); + OnDropText( x, y, data.GetText() ); + return TRUE; } //------------------------------------------------------------------------- @@ -372,11 +489,13 @@ bool wxPrivateDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) ) bool wxPrivateDropTarget::OnDrop( int x, int y ) { if (!IsSupported( m_id )) return FALSE; - + wxPrivateDataObject data; if (!GetData( &data )) return FALSE; - return OnDropData( x, y, data.GetData(), data.GetSize() ); + OnDropData( x, y, data.GetData(), data.GetSize() ); + + return TRUE; } //---------------------------------------------------------------------------- @@ -390,10 +509,13 @@ bool wxFileDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) ) bool wxFileDropTarget::OnDrop( int x, int y ) { - if (!IsSupported( wxDF_FILENAME )) return FALSE; - + return IsSupported( wxDF_FILENAME ); // same as "file:ALL" +} + +void wxFileDropTarget::OnData( int x, int y ) +{ wxFileDataObject data; - if (!GetData( &data )) return FALSE; + if (!GetData( &data )) return; /* get number of substrings /root/mytext.txt/0/root/myothertext.txt/0/0 */ size_t number = 0; @@ -403,7 +525,7 @@ bool wxFileDropTarget::OnDrop( int x, int y ) for ( i = 0; i < size; i++) if (text[i] == 0) number++; - if (number == 0) return TRUE; + if (number == 0) return; char **files = new char*[number]; @@ -415,11 +537,9 @@ bool wxFileDropTarget::OnDrop( int x, int y ) text += len+1; } - bool ret = OnDropFiles( x, y, number, files ); + OnDropFiles( x, y, number, files ); free( files ); - - return ret; } //------------------------------------------------------------------------- -- 2.47.2