wxDropTarget starts to work

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@2117 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robert Roebling
1999-04-12 22:56:14 +00:00
parent 6b769f3d1f
commit 829e3e8d3d
5 changed files with 425 additions and 161 deletions

View File

@@ -113,15 +113,19 @@ public:
/* may be overridden to react to events */ /* may be overridden to react to events */
virtual void OnEnter(); virtual void OnEnter();
virtual void OnLeave(); virtual void OnLeave();
/* may be overridden to reject certain formats or drops
on certain areas */
virtual bool OnMove( int x, int y ); 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 ); virtual bool OnDrop( int x, int y );
/* called to query formats available */ /* called to query what formats are available */
bool IsSupported( wxDataFormat format ); 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 ); bool GetData( wxDataObject *data );
// implementation // implementation
@@ -129,10 +133,17 @@ public:
void RegisterWidget( GtkWidget *widget ); void RegisterWidget( GtkWidget *widget );
void UnregisterWidget( 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; } 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 OnMove( int x, int y );
virtual bool OnDrop( 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 */ /* 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; virtual bool OnDropFiles( int x, int y, size_t nFiles, const char * const aszFiles[] ) = 0;

View File

@@ -113,15 +113,19 @@ public:
/* may be overridden to react to events */ /* may be overridden to react to events */
virtual void OnEnter(); virtual void OnEnter();
virtual void OnLeave(); virtual void OnLeave();
/* may be overridden to reject certain formats or drops
on certain areas */
virtual bool OnMove( int x, int y ); 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 ); virtual bool OnDrop( int x, int y );
/* called to query formats available */ /* called to query what formats are available */
bool IsSupported( wxDataFormat format ); 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 ); bool GetData( wxDataObject *data );
// implementation // implementation
@@ -129,10 +133,17 @@ public:
void RegisterWidget( GtkWidget *widget ); void RegisterWidget( GtkWidget *widget );
void UnregisterWidget( 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; } 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 OnMove( int x, int y );
virtual bool OnDrop( 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 */ /* 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; virtual bool OnDropFiles( int x, int y, size_t nFiles, const char * const aszFiles[] ) = 0;

View File

@@ -239,7 +239,7 @@ void DnDFrame::OnPaint(wxPaintEvent& /*event*/)
wxPaintDC dc(this); wxPaintDC dc(this);
dc.SetFont( wxFont( 24, wxDECORATIVE, wxNORMAL, wxNORMAL, FALSE, "charter" ) ); 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 */) void DnDFrame::OnDrag(wxCommandEvent& /* event */)

View File

@@ -135,11 +135,21 @@ static char * page_xpm[] = {
static void target_drag_leave( GtkWidget *WXUNUSED(widget), static void target_drag_leave( GtkWidget *WXUNUSED(widget),
GdkDragContext *context, GdkDragContext *context,
guint WXUNUSED(time), guint WXUNUSED(time),
wxDropTarget *dt ) wxDropTarget *drop_target )
{ {
dt->SetDragContext( context ); /* inform the wxDropTarget about the current GdkDragContext.
dt->OnLeave(); this is only valid for the duration of this call */
dt->SetDragContext( (GdkDragContext*) NULL ); 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 x,
gint y, gint y,
guint time, 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)
{ {
/* the first "drag_motion" event substitutes a "drag_enter" event */
drop_target->OnEnter();
}
/* 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 ); gdk_drag_status( context, context->suggested_action, time );
}
else
{
gdk_drag_status( context, (GdkDragAction)0, time );
}
dt->SetDragContext( (GdkDragContext*) NULL ); /* after this, invalidate the drop_target's GdkDragContext */
return TRUE; 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, GdkDragContext *context,
gint x, gint x,
gint y, 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, gtk_drag_get_data( widget,
context, context,
GPOINTER_TO_INT (context->targets->data), GPOINTER_TO_INT (context->targets->data),
time ); 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, gint y,
GtkSelectionData *data, GtkSelectionData *data,
guint WXUNUSED(info), guint WXUNUSED(info),
guint time ) guint time,
wxDropTarget *drop_target )
{ {
printf( "data receive at: %d,%d.\n", x, y ); /* Owen Taylor: "call gtk_drag_finish() with
success == TRUE" */
if ((data->length >= 0) && (data->format == 8))
/* 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; /* negative data length and non 8-bit data format
printf( "Received %s\n.", WXSTRINGCAST str ); qualifies for junk */
gtk_drag_finish( context, TRUE, FALSE, time ); gtk_drag_finish (context, FALSE, FALSE, time);
return;
} }
else
gtk_drag_finish (context, FALSE, FALSE, time); {
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 );
}
/* 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() 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() 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; 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 FALSE;
return TRUE;
} }
bool wxDropTarget::IsSupported( wxDataFormat format ) bool wxDropTarget::IsSupported( wxDataFormat format )
{ {
printf( "generic is supported.\n" );
if (!m_dragContext) return FALSE; if (!m_dragContext) return FALSE;
GList *child = m_dragContext->targets; GList *child = m_dragContext->targets;
while (child) while (child)
{ {
GdkAtom formatAtom = (GdkAtom) GPOINTER_TO_INT(child->data); 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; child = child->next;
} }
return FALSE;
return TRUE;
} }
bool wxDropTarget::GetData( wxDataObject *data ) 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 ) void wxDropTarget::UnregisterWidget( GtkWidget *widget )
{ {
wxCHECK_RET( widget != NULL, "unregister widget is NULL" ); wxCHECK_RET( widget != NULL, "unregister widget is NULL" );
gtk_drag_dest_set( widget, gtk_drag_dest_unset( widget );
(GtkDestDefaults) 0,
(GtkTargetEntry*) NULL,
0,
(GdkDragAction) 0 );
gtk_signal_disconnect_by_func( GTK_OBJECT(widget), gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this ); 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" ); wxCHECK_RET( widget != NULL, "register widget is NULL" );
GtkTargetEntry format; /* gtk_drag_dest_set() determines what default behaviour we'd like
format.info = 0; GTK to supply. we don't want to specify out targets (=formats)
format.flags = 0; or actions in advance (i.e. not GTK_DEST_DEFAULT_MOTION and
char buf[100]; not GTK_DEST_DEFAULT_DROP). instead we react individually to
strcpy( buf, "text/plain" ); "drag_motion" and "drag_drop" events. this makes it possible
format.target = buf; 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_drag_dest_set( widget,
GTK_DEST_DEFAULT_ALL, (GtkDestDefaults) 0, /* no default behaviour */
&format, (GtkTargetEntry*) NULL, /* we don't supply any formats here */
1, 0, /* number of targets = 0 */
(GdkDragAction)(GDK_ACTION_COPY | GDK_ACTION_MOVE) ); (GdkDragAction) 0 ); /* we don't supply any actions here */
gtk_signal_connect( GTK_OBJECT(widget), "drag_leave", gtk_signal_connect( GTK_OBJECT(widget), "drag_leave",
GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this ); 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) ) bool wxTextDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
{ {
printf( "text move.\n" ); return IsSupported( wxDF_TEXT ); // same as "STRING"
return IsSupported( wxDF_TEXT ); // same as "TEXT"
} }
bool wxTextDropTarget::OnDrop( int x, int y ) bool wxTextDropTarget::OnDrop( int x, int y )
{ {
printf( "text drop.\n" );
if (!IsSupported( wxDF_TEXT )) return FALSE; if (!IsSupported( wxDF_TEXT )) return FALSE;
wxTextDataObject data; wxTextDataObject data;
if (!GetData( &data )) return FALSE; 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 ) bool wxPrivateDropTarget::OnDrop( int x, int y )
{ {
if (!IsSupported( m_id )) return FALSE; if (!IsSupported( m_id )) return FALSE;
wxPrivateDataObject data; wxPrivateDataObject data;
if (!GetData( &data )) return FALSE; 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 ) 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; wxFileDataObject data;
if (!GetData( &data )) return FALSE; if (!GetData( &data )) return;
/* get number of substrings /root/mytext.txt/0/root/myothertext.txt/0/0 */ /* get number of substrings /root/mytext.txt/0/root/myothertext.txt/0/0 */
size_t number = 0; size_t number = 0;
@@ -403,7 +525,7 @@ bool wxFileDropTarget::OnDrop( int x, int y )
for ( i = 0; i < size; i++) for ( i = 0; i < size; i++)
if (text[i] == 0) number++; if (text[i] == 0) number++;
if (number == 0) return TRUE; if (number == 0) return;
char **files = new char*[number]; char **files = new char*[number];
@@ -415,11 +537,9 @@ bool wxFileDropTarget::OnDrop( int x, int y )
text += len+1; text += len+1;
} }
bool ret = OnDropFiles( x, y, number, files ); OnDropFiles( x, y, number, files );
free( files ); free( files );
return ret;
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------

View File

@@ -135,11 +135,21 @@ static char * page_xpm[] = {
static void target_drag_leave( GtkWidget *WXUNUSED(widget), static void target_drag_leave( GtkWidget *WXUNUSED(widget),
GdkDragContext *context, GdkDragContext *context,
guint WXUNUSED(time), guint WXUNUSED(time),
wxDropTarget *dt ) wxDropTarget *drop_target )
{ {
dt->SetDragContext( context ); /* inform the wxDropTarget about the current GdkDragContext.
dt->OnLeave(); this is only valid for the duration of this call */
dt->SetDragContext( (GdkDragContext*) NULL ); 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 x,
gint y, gint y,
guint time, 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)
{ {
/* the first "drag_motion" event substitutes a "drag_enter" event */
drop_target->OnEnter();
}
/* 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 ); gdk_drag_status( context, context->suggested_action, time );
}
else
{
gdk_drag_status( context, (GdkDragAction)0, time );
}
dt->SetDragContext( (GdkDragContext*) NULL ); /* after this, invalidate the drop_target's GdkDragContext */
return TRUE; 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, GdkDragContext *context,
gint x, gint x,
gint y, 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, gtk_drag_get_data( widget,
context, context,
GPOINTER_TO_INT (context->targets->data), GPOINTER_TO_INT (context->targets->data),
time ); 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, gint y,
GtkSelectionData *data, GtkSelectionData *data,
guint WXUNUSED(info), guint WXUNUSED(info),
guint time ) guint time,
wxDropTarget *drop_target )
{ {
printf( "data receive at: %d,%d.\n", x, y ); /* Owen Taylor: "call gtk_drag_finish() with
success == TRUE" */
if ((data->length >= 0) && (data->format == 8))
/* 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; /* negative data length and non 8-bit data format
printf( "Received %s\n.", WXSTRINGCAST str ); qualifies for junk */
gtk_drag_finish( context, TRUE, FALSE, time ); gtk_drag_finish (context, FALSE, FALSE, time);
return;
} }
else
gtk_drag_finish (context, FALSE, FALSE, time); {
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 );
}
/* 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() 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() 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; 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 FALSE;
return TRUE;
} }
bool wxDropTarget::IsSupported( wxDataFormat format ) bool wxDropTarget::IsSupported( wxDataFormat format )
{ {
printf( "generic is supported.\n" );
if (!m_dragContext) return FALSE; if (!m_dragContext) return FALSE;
GList *child = m_dragContext->targets; GList *child = m_dragContext->targets;
while (child) while (child)
{ {
GdkAtom formatAtom = (GdkAtom) GPOINTER_TO_INT(child->data); 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; child = child->next;
} }
return FALSE;
return TRUE;
} }
bool wxDropTarget::GetData( wxDataObject *data ) 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 ) void wxDropTarget::UnregisterWidget( GtkWidget *widget )
{ {
wxCHECK_RET( widget != NULL, "unregister widget is NULL" ); wxCHECK_RET( widget != NULL, "unregister widget is NULL" );
gtk_drag_dest_set( widget, gtk_drag_dest_unset( widget );
(GtkDestDefaults) 0,
(GtkTargetEntry*) NULL,
0,
(GdkDragAction) 0 );
gtk_signal_disconnect_by_func( GTK_OBJECT(widget), gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this ); 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" ); wxCHECK_RET( widget != NULL, "register widget is NULL" );
GtkTargetEntry format; /* gtk_drag_dest_set() determines what default behaviour we'd like
format.info = 0; GTK to supply. we don't want to specify out targets (=formats)
format.flags = 0; or actions in advance (i.e. not GTK_DEST_DEFAULT_MOTION and
char buf[100]; not GTK_DEST_DEFAULT_DROP). instead we react individually to
strcpy( buf, "text/plain" ); "drag_motion" and "drag_drop" events. this makes it possible
format.target = buf; 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_drag_dest_set( widget,
GTK_DEST_DEFAULT_ALL, (GtkDestDefaults) 0, /* no default behaviour */
&format, (GtkTargetEntry*) NULL, /* we don't supply any formats here */
1, 0, /* number of targets = 0 */
(GdkDragAction)(GDK_ACTION_COPY | GDK_ACTION_MOVE) ); (GdkDragAction) 0 ); /* we don't supply any actions here */
gtk_signal_connect( GTK_OBJECT(widget), "drag_leave", gtk_signal_connect( GTK_OBJECT(widget), "drag_leave",
GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this ); 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) ) bool wxTextDropTarget::OnMove( int WXUNUSED(x), int WXUNUSED(y) )
{ {
printf( "text move.\n" ); return IsSupported( wxDF_TEXT ); // same as "STRING"
return IsSupported( wxDF_TEXT ); // same as "TEXT"
} }
bool wxTextDropTarget::OnDrop( int x, int y ) bool wxTextDropTarget::OnDrop( int x, int y )
{ {
printf( "text drop.\n" );
if (!IsSupported( wxDF_TEXT )) return FALSE; if (!IsSupported( wxDF_TEXT )) return FALSE;
wxTextDataObject data; wxTextDataObject data;
if (!GetData( &data )) return FALSE; 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 ) bool wxPrivateDropTarget::OnDrop( int x, int y )
{ {
if (!IsSupported( m_id )) return FALSE; if (!IsSupported( m_id )) return FALSE;
wxPrivateDataObject data; wxPrivateDataObject data;
if (!GetData( &data )) return FALSE; 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 ) 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; wxFileDataObject data;
if (!GetData( &data )) return FALSE; if (!GetData( &data )) return;
/* get number of substrings /root/mytext.txt/0/root/myothertext.txt/0/0 */ /* get number of substrings /root/mytext.txt/0/root/myothertext.txt/0/0 */
size_t number = 0; size_t number = 0;
@@ -403,7 +525,7 @@ bool wxFileDropTarget::OnDrop( int x, int y )
for ( i = 0; i < size; i++) for ( i = 0; i < size; i++)
if (text[i] == 0) number++; if (text[i] == 0) number++;
if (number == 0) return TRUE; if (number == 0) return;
char **files = new char*[number]; char **files = new char*[number];
@@ -415,11 +537,9 @@ bool wxFileDropTarget::OnDrop( int x, int y )
text += len+1; text += len+1;
} }
bool ret = OnDropFiles( x, y, number, files ); OnDropFiles( x, y, number, files );
free( files ); free( files );
return ret;
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------