Files
wxWidgets/src/gtk1/dnd.cpp
Vadim Zeitlin 3f66f6a5b3 Remove all lines containing cvs/svn "$Id$" keyword.
This keyword is not expanded by Git which means it's not replaced with the
correct revision value in the releases made using git-based scripts and it's
confusing to have lines with unexpanded "$Id$" in the released files. As
expanding them with Git is not that simple (it could be done with git archive
and export-subst attribute) and there are not many benefits in having them in
the first place, just remove all these lines.

If nothing else, this will make an eventual transition to Git simpler.

Closes #14487.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74602 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2013-07-26 16:02:46 +00:00

939 lines
28 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Name: src/gtk1/dnd.cpp
// Purpose: wxDropTarget class
// Author: Robert Roebling
// Copyright: (c) 1998 Robert Roebling
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#if wxUSE_DRAG_AND_DROP
#include "wx/dnd.h"
#ifndef WX_PRECOMP
#include "wx/intl.h"
#include "wx/log.h"
#include "wx/app.h"
#include "wx/utils.h"
#include "wx/window.h"
#include "wx/gdicmn.h"
#endif
#include "wx/gtk1/private.h"
#include <gdk/gdkprivate.h>
#include <gtk/gtkdnd.h>
#include <gtk/gtkselection.h>
//-----------------------------------------------------------------------------
// idle system
//-----------------------------------------------------------------------------
extern void wxapp_install_idle_handler();
extern bool g_isIdle;
//----------------------------------------------------------------------------
// global data
//----------------------------------------------------------------------------
extern bool g_blockEventsOnDrag;
// the flags used for the last DoDragDrop()
static long gs_flagsForDrag = 0;
// the trace mask we use with wxLogTrace() - call
// wxLog::AddTraceMask(TRACE_DND) to enable the trace messages from here
// (there are quite a few of them, so don't enable this by default)
#define TRACE_DND wxT("dnd")
// global variables because GTK+ DnD want to have the
// mouse event that caused it
extern GdkEvent *g_lastMouseEvent;
extern int g_lastButtonNumber;
//----------------------------------------------------------------------------
// standard icons
//----------------------------------------------------------------------------
/* Copyright (c) Julian Smart */
static const char * page_xpm[] = {
/* columns rows colors chars-per-pixel */
"32 32 37 1",
"5 c #7198D9",
", c #769CDA",
"2 c #DCE6F6",
"i c #FFFFFF",
"e c #779DDB",
": c #9AB6E4",
"9 c #EAF0FA",
"- c #B1C7EB",
"$ c #6992D7",
"y c #F7F9FD",
"= c #BED0EE",
"q c #F0F5FC",
"; c #A8C0E8",
"@ c #366BC2",
" c None",
"u c #FDFEFF",
"8 c #5987D3",
"* c #C4D5F0",
"7 c #7CA0DC",
"O c #487BCE",
"< c #6B94D7",
"& c #CCDAF2",
"> c #89A9DF",
"3 c #5584D1",
"w c #82A5DE",
"1 c #3F74CB",
"+ c #3A70CA",
". c #3569BF",
"% c #D2DFF4",
"# c #3366BB",
"r c #F5F8FD",
"0 c #FAFCFE",
"4 c #DFE8F7",
"X c #5E8AD4",
"o c #5282D0",
"t c #B8CCEC",
"6 c #E5EDF9",
/* pixels */
" ",
" ",
" ",
" ",
" ",
" .XXXooOO++@# ",
" $%&*=-;::>,<1 ",
" $2%&*=-;::><:3 ",
" $42%&*=-;::<&:3 ",
" 56477<<<<8<<9&:X ",
" 59642%&*=-;<09&:5 ",
" 5q9642%&*=-<<<<<# ",
" 5qqw777<<<<<88:>+ ",
" erqq9642%&*=t;::+ ",
" eyrqq9642%&*=t;:O ",
" eyywwww777<<<<t;O ",
" e0yyrqq9642%&*=to ",
" e00yyrqq9642%&*=o ",
" eu0wwwwwww777<&*X ",
" euu00yyrqq9642%&X ",
" eiuu00yyrqq9642%X ",
" eiiwwwwwwwwww742$ ",
" eiiiuu00yyrqq964$ ",
" eiiiiuu00yyrqq96$ ",
" eiiiiiuu00yyrqq95 ",
" eiiiiiiuu00yyrqq5 ",
" eeeeeeeeeeeeee55e ",
" ",
" ",
" ",
" ",
" "
};
// ============================================================================
// private functions
// ============================================================================
// ----------------------------------------------------------------------------
// convert between GTK+ and wxWidgets DND constants
// ----------------------------------------------------------------------------
static wxDragResult ConvertFromGTK(long action)
{
switch ( action )
{
case GDK_ACTION_COPY:
return wxDragCopy;
case GDK_ACTION_LINK:
return wxDragLink;
case GDK_ACTION_MOVE:
return wxDragMove;
}
return wxDragNone;
}
// ----------------------------------------------------------------------------
// "drag_leave"
// ----------------------------------------------------------------------------
extern "C" {
static void target_drag_leave( GtkWidget *WXUNUSED(widget),
GdkDragContext *context,
guint WXUNUSED(time),
wxDropTarget *drop_target )
{
if (g_isIdle) wxapp_install_idle_handler();
/* 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( NULL );
}
}
// ----------------------------------------------------------------------------
// "drag_motion"
// ----------------------------------------------------------------------------
extern "C" {
static gboolean target_drag_motion( GtkWidget *WXUNUSED(widget),
GdkDragContext *context,
gint x,
gint y,
guint time,
wxDropTarget *drop_target )
{
if (g_isIdle) wxapp_install_idle_handler();
/* 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 );
// GTK+ always supposes that we want to copy the data by default while we
// might want to move it, so examine not only suggested_action - which is
// only good if we don't have our own preferences - but also the actions
// field
wxDragResult result;
if (drop_target->GetDefaultAction() == wxDragNone)
{
// use default action set by wxDropSource::DoDragDrop()
if ( (gs_flagsForDrag & wxDrag_DefaultMove) == wxDrag_DefaultMove &&
(context->actions & GDK_ACTION_MOVE ) )
{
// move is requested by the program and allowed by GTK+ - do it, even
// though suggested_action may be currently wxDragCopy
result = wxDragMove;
}
else // use whatever GTK+ says we should
{
result = ConvertFromGTK(context->suggested_action);
if ( (result == wxDragMove) && !(gs_flagsForDrag & wxDrag_AllowMove) )
{
// we're requested to move but we can't
result = wxDragCopy;
}
}
}
else if (drop_target->GetDefaultAction() == wxDragMove &&
(context->actions & GDK_ACTION_MOVE))
{
result = wxDragMove;
}
else
{
if (context->actions & GDK_ACTION_COPY)
result = wxDragCopy;
else if (context->actions & GDK_ACTION_MOVE)
result = wxDragMove;
else
result = wxDragNone;
}
if (drop_target->m_firstMotion)
{
/* the first "drag_motion" event substitutes a "drag_enter" event */
result = drop_target->OnEnter( x, y, result );
}
else
{
/* give program a chance to react (i.e. to say no by returning FALSE) */
result = drop_target->OnDragOver( x, y, result );
}
bool ret = wxIsDragResultOk( result );
if (ret)
{
GdkDragAction action;
if (result == wxDragCopy)
action = GDK_ACTION_COPY;
else if (result == wxDragLink)
action = GDK_ACTION_LINK;
else
action = GDK_ACTION_MOVE;
gdk_drag_status( context, action, time );
}
/* after this, invalidate the drop_target's GdkDragContext */
drop_target->SetDragContext( NULL );
/* this has to be done because GDK has no "drag_enter" event */
drop_target->m_firstMotion = false;
return ret;
}
}
// ----------------------------------------------------------------------------
// "drag_drop"
// ----------------------------------------------------------------------------
extern "C" {
static gboolean target_drag_drop( GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
guint time,
wxDropTarget *drop_target )
{
if (g_isIdle) wxapp_install_idle_handler();
/* 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()" */
// printf( "drop.\n" );
/* 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.. */
/* 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 );
/*
wxDragResult result = wxDragMove;
if (context->suggested_action == GDK_ACTION_COPY) result = wxDragCopy;
*/
/* reset the block here as someone might very well
show a dialog as a reaction to a drop and this
wouldn't work without events */
g_blockEventsOnDrag = false;
bool ret = drop_target->OnDrop( x, y );
if (!ret)
{
wxLogTrace(TRACE_DND, wxT( "Drop target: OnDrop returned FALSE") );
/* cancel the whole thing */
gtk_drag_finish( context,
FALSE, /* no success */
FALSE, /* don't delete data on dropping side */
time );
}
else
{
wxLogTrace(TRACE_DND, wxT( "Drop target: OnDrop returned TRUE") );
#if wxUSE_THREADS
/* disable GUI threads */
#endif
GdkAtom format = drop_target->GetMatchingPair();
// this does happen somehow, see bug 555111
wxCHECK_MSG( format, FALSE, wxT("no matching GdkAtom for format?") );
/*
GdkDragAction action = GDK_ACTION_MOVE;
if (result == wxDragCopy) action == GDK_ACTION_COPY;
context->action = action;
*/
/* this should trigger an "drag_data_received" event */
gtk_drag_get_data( widget,
context,
format,
time );
#if wxUSE_THREADS
/* re-enable GUI threads */
#endif
}
/* after this, invalidate the drop_target's GdkDragContext */
drop_target->SetDragContext( NULL );
/* after this, invalidate the drop_target's drag widget */
drop_target->SetDragWidget( NULL );
/* this has to be done because GDK has no "drag_enter" event */
drop_target->m_firstMotion = true;
return ret;
}
}
// ----------------------------------------------------------------------------
// "drag_data_received"
// ----------------------------------------------------------------------------
extern "C" {
static void target_drag_data_received( GtkWidget *WXUNUSED(widget),
GdkDragContext *context,
gint x,
gint y,
GtkSelectionData *data,
guint WXUNUSED(info),
guint time,
wxDropTarget *drop_target )
{
if (g_isIdle) wxapp_install_idle_handler();
/* Owen Taylor: "call gtk_drag_finish() with
success == TRUE" */
if ((data->length <= 0) || (data->format != 8))
{
/* negative data length and non 8-bit data format
qualifies for junk */
gtk_drag_finish (context, FALSE, FALSE, time);
return;
}
wxLogTrace(TRACE_DND, wxT( "Drop target: data received event") );
/* inform the wxDropTarget about the current GtkSelectionData.
this is only valid for the duration of this call */
drop_target->SetDragData( data );
wxDragResult result = ConvertFromGTK(context->action);
if ( wxIsDragResultOk( drop_target->OnData( x, y, result ) ) )
{
wxLogTrace(TRACE_DND, wxT( "Drop target: OnData returned TRUE") );
/* tell GTK that data transfer was successful */
gtk_drag_finish( context, TRUE, FALSE, time );
}
else
{
wxLogTrace(TRACE_DND, wxT( "Drop target: OnData returned FALSE") );
/* tell GTK that data transfer was not successful */
gtk_drag_finish( context, FALSE, FALSE, time );
}
/* after this, invalidate the drop_target's drag data */
drop_target->SetDragData( NULL );
}
}
//----------------------------------------------------------------------------
// wxDropTarget
//----------------------------------------------------------------------------
wxDropTarget::wxDropTarget( wxDataObject *data )
: wxDropTargetBase( data )
{
m_firstMotion = true;
m_dragContext = NULL;
m_dragWidget = NULL;
m_dragData = NULL;
m_dragTime = 0;
}
wxDragResult wxDropTarget::OnDragOver( wxCoord WXUNUSED(x),
wxCoord WXUNUSED(y),
wxDragResult def )
{
// GetMatchingPair() checks for m_dataObject too, no need to do it here
// disable the debug message from GetMatchingPair() by passing true to it
return (GetMatchingPair(true) != (GdkAtom) 0) ? def : wxDragNone;
}
bool wxDropTarget::OnDrop( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y) )
{
if (!m_dataObject)
return false;
return (GetMatchingPair() != (GdkAtom) 0);
}
wxDragResult wxDropTarget::OnData( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y),
wxDragResult def )
{
if (!m_dataObject)
return wxDragNone;
if (GetMatchingPair() == (GdkAtom) 0)
return wxDragNone;
return GetData() ? def : wxDragNone;
}
GdkAtom wxDropTarget::GetMatchingPair(bool quiet)
{
if (!m_dataObject)
return (GdkAtom) 0;
if (!m_dragContext)
return (GdkAtom) 0;
GList *child = m_dragContext->targets;
while (child)
{
GdkAtom formatAtom = GPOINTER_TO_INT(child->data);
wxDataFormat format( formatAtom );
if ( !quiet )
{
wxLogTrace(TRACE_DND, wxT("Drop target: drag has format: %s"),
format.GetId().c_str());
}
if (m_dataObject->IsSupportedFormat( format ))
return formatAtom;
child = child->next;
}
return (GdkAtom) 0;
}
bool wxDropTarget::GetData()
{
if (!m_dragData)
return false;
if (!m_dataObject)
return false;
wxDataFormat dragFormat( m_dragData->target );
if (!m_dataObject->IsSupportedFormat( dragFormat ))
return false;
m_dataObject->SetData( dragFormat, (size_t)m_dragData->length, (const void*)m_dragData->data );
return true;
}
void wxDropTarget::UnregisterWidget( GtkWidget *widget )
{
wxCHECK_RET( widget != NULL, wxT("unregister widget is NULL") );
gtk_drag_dest_unset( widget );
gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
GTK_SIGNAL_FUNC(target_drag_leave), (gpointer) this );
gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
GTK_SIGNAL_FUNC(target_drag_motion), (gpointer) this );
gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
GTK_SIGNAL_FUNC(target_drag_drop), (gpointer) this );
gtk_signal_disconnect_by_func( GTK_OBJECT(widget),
GTK_SIGNAL_FUNC(target_drag_data_received), (gpointer) this );
}
void wxDropTarget::RegisterWidget( GtkWidget *widget )
{
wxCHECK_RET( widget != NULL, wxT("register widget is NULL") );
/* 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,
(GtkDestDefaults) 0, /* no default behaviour */
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 );
gtk_signal_connect( GTK_OBJECT(widget), "drag_motion",
GTK_SIGNAL_FUNC(target_drag_motion), (gpointer) this );
gtk_signal_connect( GTK_OBJECT(widget), "drag_drop",
GTK_SIGNAL_FUNC(target_drag_drop), (gpointer) this );
gtk_signal_connect( GTK_OBJECT(widget), "drag_data_received",
GTK_SIGNAL_FUNC(target_drag_data_received), (gpointer) this );
}
//----------------------------------------------------------------------------
// "drag_data_get"
//----------------------------------------------------------------------------
extern "C" {
static void
source_drag_data_get (GtkWidget *WXUNUSED(widget),
GdkDragContext *WXUNUSED(context),
GtkSelectionData *selection_data,
guint WXUNUSED(info),
guint WXUNUSED(time),
wxDropSource *drop_source )
{
if (g_isIdle) wxapp_install_idle_handler();
wxDataFormat format( selection_data->target );
wxLogTrace(TRACE_DND, wxT("Drop source: format requested: %s"),
format.GetId().c_str());
drop_source->m_retValue = wxDragCancel;
wxDataObject *data = drop_source->GetDataObject();
if (!data)
{
wxLogTrace(TRACE_DND, wxT("Drop source: no data object") );
return;
}
if (!data->IsSupportedFormat(format))
{
wxLogTrace(TRACE_DND, wxT("Drop source: unsupported format") );
return;
}
if (data->GetDataSize(format) == 0)
{
wxLogTrace(TRACE_DND, wxT("Drop source: empty data") );
return;
}
size_t size = data->GetDataSize(format);
// printf( "data size: %d.\n", (int)data_size );
guchar *d = new guchar[size];
if (!data->GetDataHere( format, (void*)d ))
{
delete[] d;
return;
}
#if wxUSE_THREADS
/* disable GUI threads */
#endif
gtk_selection_data_set( selection_data,
selection_data->target,
8, // 8-bit
d,
size );
#if wxUSE_THREADS
/* enable GUI threads */
#endif
delete[] d;
}
}
//----------------------------------------------------------------------------
// "drag_data_delete"
//----------------------------------------------------------------------------
extern "C" {
static void source_drag_data_delete( GtkWidget *WXUNUSED(widget),
GdkDragContext *WXUNUSED(context),
wxDropSource *WXUNUSED(drop_source) )
{
if (g_isIdle)
wxapp_install_idle_handler();
// printf( "Drag source: drag_data_delete\n" );
}
}
//----------------------------------------------------------------------------
// "drag_begin"
//----------------------------------------------------------------------------
extern "C" {
static void source_drag_begin( GtkWidget *WXUNUSED(widget),
GdkDragContext *WXUNUSED(context),
wxDropSource *WXUNUSED(drop_source) )
{
if (g_isIdle)
wxapp_install_idle_handler();
// printf( "Drag source: drag_begin.\n" );
}
}
//----------------------------------------------------------------------------
// "drag_end"
//----------------------------------------------------------------------------
extern "C" {
static void source_drag_end( GtkWidget *WXUNUSED(widget),
GdkDragContext *WXUNUSED(context),
wxDropSource *drop_source )
{
if (g_isIdle) wxapp_install_idle_handler();
// printf( "Drag source: drag_end.\n" );
drop_source->m_waiting = false;
}
}
//-----------------------------------------------------------------------------
// "configure_event" from m_iconWindow
//-----------------------------------------------------------------------------
extern "C" {
static gint
gtk_dnd_window_configure_callback( GtkWidget *WXUNUSED(widget), GdkEventConfigure *WXUNUSED(event), wxDropSource *source )
{
if (g_isIdle)
wxapp_install_idle_handler();
source->GiveFeedback( ConvertFromGTK(source->m_dragContext->action) );
return 0;
}
}
//---------------------------------------------------------------------------
// wxDropSource
//---------------------------------------------------------------------------
wxDropSource::wxDropSource(wxWindow *win,
const wxIcon &iconCopy,
const wxIcon &iconMove,
const wxIcon &iconNone)
{
m_waiting = true;
m_iconWindow = NULL;
m_window = win;
m_widget = win->m_widget;
if (win->m_wxwindow) m_widget = win->m_wxwindow;
m_retValue = wxDragCancel;
SetIcons(iconCopy, iconMove, iconNone);
}
wxDropSource::wxDropSource(wxDataObject& data,
wxWindow *win,
const wxIcon &iconCopy,
const wxIcon &iconMove,
const wxIcon &iconNone)
{
m_waiting = true;
SetData( data );
m_iconWindow = NULL;
m_window = win;
m_widget = win->m_widget;
if (win->m_wxwindow) m_widget = win->m_wxwindow;
m_retValue = wxDragCancel;
SetIcons(iconCopy, iconMove, iconNone);
}
void wxDropSource::SetIcons(const wxIcon &iconCopy,
const wxIcon &iconMove,
const wxIcon &iconNone)
{
m_iconCopy = iconCopy;
m_iconMove = iconMove;
m_iconNone = iconNone;
if ( !m_iconCopy.IsOk() )
m_iconCopy = wxIcon(page_xpm);
if ( !m_iconMove.IsOk() )
m_iconMove = m_iconCopy;
if ( !m_iconNone.IsOk() )
m_iconNone = m_iconCopy;
}
wxDropSource::~wxDropSource()
{
}
void wxDropSource::PrepareIcon( int action, GdkDragContext *context )
{
// get the right icon to display
wxIcon *icon = NULL;
if ( action & GDK_ACTION_MOVE )
icon = &m_iconMove;
else if ( action & GDK_ACTION_COPY )
icon = &m_iconCopy;
else
icon = &m_iconNone;
GdkBitmap *mask;
if ( icon->GetMask() )
mask = icon->GetMask()->GetBitmap();
else
mask = NULL;
GdkPixmap *pixmap = icon->GetPixmap();
gint width,height;
gdk_window_get_size (pixmap, &width, &height);
GdkColormap *colormap = gtk_widget_get_colormap( m_widget );
gtk_widget_push_visual (gdk_colormap_get_visual (colormap));
gtk_widget_push_colormap (colormap);
m_iconWindow = gtk_window_new (GTK_WINDOW_POPUP);
gtk_widget_set_events (m_iconWindow, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
gtk_widget_set_app_paintable (GTK_WIDGET (m_iconWindow), TRUE);
gtk_widget_pop_visual ();
gtk_widget_pop_colormap ();
gtk_widget_set_usize (m_iconWindow, width, height);
gtk_widget_realize (m_iconWindow);
gtk_signal_connect( GTK_OBJECT(m_iconWindow), "configure_event",
GTK_SIGNAL_FUNC(gtk_dnd_window_configure_callback), (gpointer)this );
gdk_window_set_back_pixmap (m_iconWindow->window, pixmap, FALSE);
if (mask)
gtk_widget_shape_combine_mask (m_iconWindow, mask, 0, 0);
gtk_drag_set_icon_widget( context, m_iconWindow, 0, 0 );
}
wxDragResult wxDropSource::DoDragDrop(int flags)
{
wxCHECK_MSG( m_data && m_data->GetFormatCount(), wxDragNone,
wxT("Drop source: no data") );
// still in drag
if (g_blockEventsOnDrag)
return wxDragNone;
// don't start dragging if no button is down
if (g_lastButtonNumber == 0)
return wxDragNone;
// we can only start a drag after a mouse event
if (g_lastMouseEvent == NULL)
return wxDragNone;
// disabled for now
g_blockEventsOnDrag = true;
RegisterWindow();
m_waiting = true;
GtkTargetList *target_list = gtk_target_list_new( NULL, 0 );
wxDataFormat *array = new wxDataFormat[ m_data->GetFormatCount() ];
m_data->GetAllFormats( array );
size_t count = m_data->GetFormatCount();
for (size_t i = 0; i < count; i++)
{
GdkAtom atom = array[i];
wxLogTrace(TRACE_DND, wxT("Drop source: Supported atom %s"), gdk_atom_name( atom ));
gtk_target_list_add( target_list, atom, 0, 0 );
}
delete[] array;
int action = GDK_ACTION_COPY;
if ( flags & wxDrag_AllowMove )
action |= GDK_ACTION_MOVE;
// VZ: as we already use g_blockEventsOnDrag it shouldn't be that bad
// to use a global to pass the flags to the drop target but I'd
// surely prefer a better way to do it
gs_flagsForDrag = flags;
GdkDragContext *context = gtk_drag_begin( m_widget,
target_list,
(GdkDragAction)action,
g_lastButtonNumber, // number of mouse button which started drag
(GdkEvent*) g_lastMouseEvent );
m_dragContext = context;
PrepareIcon( action, context );
while (m_waiting)
gtk_main_iteration();
m_retValue = ConvertFromGTK(context->action);
if ( m_retValue == wxDragNone )
m_retValue = wxDragCancel;
g_blockEventsOnDrag = false;
UnregisterWindow();
return m_retValue;
}
void wxDropSource::RegisterWindow()
{
if (!m_widget) return;
gtk_signal_connect( GTK_OBJECT(m_widget), "drag_data_get",
GTK_SIGNAL_FUNC (source_drag_data_get), (gpointer) this);
gtk_signal_connect (GTK_OBJECT(m_widget), "drag_data_delete",
GTK_SIGNAL_FUNC (source_drag_data_delete), (gpointer) this );
gtk_signal_connect (GTK_OBJECT(m_widget), "drag_begin",
GTK_SIGNAL_FUNC (source_drag_begin), (gpointer) this );
gtk_signal_connect (GTK_OBJECT(m_widget), "drag_end",
GTK_SIGNAL_FUNC (source_drag_end), (gpointer) this );
}
void wxDropSource::UnregisterWindow()
{
if (!m_widget) return;
gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
GTK_SIGNAL_FUNC(source_drag_data_get), (gpointer) this );
gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
GTK_SIGNAL_FUNC(source_drag_data_delete), (gpointer) this );
gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
GTK_SIGNAL_FUNC(source_drag_begin), (gpointer) this );
gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget),
GTK_SIGNAL_FUNC(source_drag_end), (gpointer) this );
}
#endif
// wxUSE_DRAG_AND_DROP