X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/9fa72bd2a637cee761c56e2ce61cec3e43c62765..2e334012b4babcf063fbe79540c4c154cd54ab2b:/src/gtk/dnd.cpp diff --git a/src/gtk/dnd.cpp b/src/gtk/dnd.cpp index a6922b83ee..2c54f0805d 100644 --- a/src/gtk/dnd.cpp +++ b/src/gtk/dnd.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Name: dnd.cpp +// Name: src/gtk/dnd.cpp // Purpose: wxDropTarget class // Author: Robert Roebling // Id: $Id$ @@ -10,38 +10,22 @@ // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" -#include "wx/dnd.h" -#include "wx/log.h" - - #if wxUSE_DRAG_AND_DROP -#include "wx/window.h" -#include "wx/app.h" -#include "wx/gdicmn.h" -#include "wx/intl.h" -#include "wx/utils.h" - -#include "wx/gtk/private.h" - -#include - -#include -#include - -//----------------------------------------------------------------------------- -// idle system -//----------------------------------------------------------------------------- +#include "wx/dnd.h" -extern void wxapp_install_idle_handler(); -extern bool g_isIdle; +#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 -//----------------------------------------------------------------------------- -// thread system -//----------------------------------------------------------------------------- +#include "wx/scopeguard.h" -#if wxUSE_THREADS -#endif +#include //---------------------------------------------------------------------------- // global data @@ -52,10 +36,17 @@ extern bool g_blockEventsOnDrag; // the flags used for the last DoDragDrop() static long gs_flagsForDrag = 0; +#ifdef __WXDEBUG__ // 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) static const wxChar *TRACE_DND = _T("dnd"); +#endif + +// global variables because GTK+ DnD want to have the +// mouse event that caused it +extern GdkEvent *g_lastMouseEvent; +extern int g_lastButtonNumber; //---------------------------------------------------------------------------- // standard icons @@ -173,8 +164,6 @@ static void target_drag_leave( GtkWidget *WXUNUSED(widget), 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 ); @@ -203,12 +192,20 @@ static gboolean target_drag_motion( GtkWidget *WXUNUSED(widget), 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" */ +#if 0 + wxPrintf( "motion\n" ); + GList *tmp_list; + for (tmp_list = context->targets; tmp_list; tmp_list = tmp_list->next) + { + wxString atom = wxString::FromAscii( gdk_atom_name (GDK_POINTER_TO_ATOM (tmp_list->data)) ); + wxPrintf( "Atom: %s\n", atom ); + } +#endif + /* inform the wxDropTarget about the current GdkDragContext. this is only valid for the duration of this call */ drop_target->SetDragContext( context ); @@ -221,27 +218,28 @@ static gboolean target_drag_motion( GtkWidget *WXUNUSED(widget), if (drop_target->GetDefaultAction() == wxDragNone) { // use default action set by wxDropSource::DoDragDrop() - if ( (gs_flagsForDrag & wxDrag_DefaultMove) == wxDrag_DefaultMove && + 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; + // 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 @@ -301,15 +299,11 @@ static gboolean target_drag_drop( GtkWidget *widget, 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.. */ @@ -340,7 +334,9 @@ static gboolean target_drag_drop( GtkWidget *widget, if (!ret) { +#ifdef __WXDEBUG__ wxLogTrace(TRACE_DND, wxT( "Drop target: OnDrop returned FALSE") ); +#endif /* cancel the whole thing */ gtk_drag_finish( context, @@ -350,7 +346,9 @@ static gboolean target_drag_drop( GtkWidget *widget, } else { - wxLogTrace(TRACE_DND, wxT( "Drop target: OnDrop returned TRUE") ); +#ifdef __WXDEBUG__ + wxLogTrace(TRACE_DND, wxT( "Drop target: OnDrop returned true") ); +#endif #if wxUSE_THREADS /* disable GUI threads */ @@ -359,7 +357,7 @@ static gboolean target_drag_drop( GtkWidget *widget, GdkAtom format = drop_target->GetMatchingPair(); // this does happen somehow, see bug 555111 - wxCHECK_MSG( format, FALSE, _T("no matching GdkAtom for format?") ) + wxCHECK_MSG( format, FALSE, _T("no matching GdkAtom for format?") ); /* GdkDragAction action = GDK_ACTION_MOVE; @@ -404,8 +402,6 @@ static void target_drag_data_received( GtkWidget *WXUNUSED(widget), guint time, wxDropTarget *drop_target ) { - if (g_isIdle) wxapp_install_idle_handler(); - /* Owen Taylor: "call gtk_drag_finish() with success == TRUE" */ @@ -418,7 +414,9 @@ static void target_drag_data_received( GtkWidget *WXUNUSED(widget), return; } +#ifdef __WXDEBUG__ wxLogTrace(TRACE_DND, wxT( "Drop target: data received event") ); +#endif /* inform the wxDropTarget about the current GtkSelectionData. this is only valid for the duration of this call */ @@ -428,14 +426,18 @@ static void target_drag_data_received( GtkWidget *WXUNUSED(widget), if ( wxIsDragResultOk( drop_target->OnData( x, y, result ) ) ) { - wxLogTrace(TRACE_DND, wxT( "Drop target: OnData returned TRUE") ); +#ifdef __WXDEBUG__ + wxLogTrace(TRACE_DND, wxT( "Drop target: OnData returned true") ); +#endif /* tell GTK that data transfer was successful */ gtk_drag_finish( context, TRUE, FALSE, time ); } else { +#ifdef __WXDEBUG__ wxLogTrace(TRACE_DND, wxT( "Drop target: OnData returned FALSE") ); +#endif /* tell GTK that data transfer was not successful */ gtk_drag_finish( context, FALSE, FALSE, time ); @@ -603,12 +605,12 @@ source_drag_data_get (GtkWidget *WXUNUSED(widget), guint WXUNUSED(time), wxDropSource *drop_source ) { - if (g_isIdle) wxapp_install_idle_handler(); - wxDataFormat format( selection_data->target ); +#ifdef __WXDEBUG__ wxLogTrace(TRACE_DND, wxT("Drop source: format requested: %s"), format.GetId().c_str()); +#endif drop_source->m_retValue = wxDragCancel; @@ -616,20 +618,26 @@ source_drag_data_get (GtkWidget *WXUNUSED(widget), if (!data) { +#ifdef __WXDEBUG__ wxLogTrace(TRACE_DND, wxT("Drop source: no data object") ); - return; +#endif + return; } if (!data->IsSupportedFormat(format)) { +#ifdef __WXDEBUG__ wxLogTrace(TRACE_DND, wxT("Drop source: unsupported format") ); - return; +#endif + return; } if (data->GetDataSize(format) == 0) { +#ifdef __WXDEBUG__ wxLogTrace(TRACE_DND, wxT("Drop source: empty data") ); - return; +#endif + return; } size_t size = data->GetDataSize(format); @@ -662,38 +670,6 @@ source_drag_data_get (GtkWidget *WXUNUSED(widget), } } -//---------------------------------------------------------------------------- -// "drag_data_delete" -//---------------------------------------------------------------------------- - -extern "C" { -static void source_drag_data_delete( GtkWidget *WXUNUSED(widget), - GdkDragContext *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" //---------------------------------------------------------------------------- @@ -703,8 +679,6 @@ 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; @@ -719,9 +693,6 @@ 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; @@ -811,18 +782,18 @@ void wxDropSource::PrepareIcon( int action, GdkDragContext *context ) GdkPixmap *pixmap = icon->GetPixmap(); gint width,height; - gdk_window_get_size (pixmap, &width, &height); + gdk_drawable_get_size (pixmap, &width, &height); GdkColormap *colormap = gtk_widget_get_colormap( m_widget ); 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_set_app_paintable (m_iconWindow, TRUE); gtk_widget_pop_colormap (); - gtk_widget_set_usize (m_iconWindow, width, height); + gtk_widget_set_size_request (m_iconWindow, width, height); gtk_widget_realize (m_iconWindow); g_signal_connect (m_iconWindow, "configure_event", @@ -845,10 +816,16 @@ wxDragResult wxDropSource::DoDragDrop(int flags) if (g_blockEventsOnDrag) return wxDragNone; - // disabled for now - g_blockEventsOnDrag = true; + // 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; - RegisterWindow(); + GTKConnectDragSignals(); + wxON_BLOCK_EXIT_OBJ0(*this, wxDropSource::GTKDisconnectDragSignals); m_waiting = true; @@ -860,102 +837,72 @@ wxDragResult wxDropSource::DoDragDrop(int flags) for (size_t i = 0; i < count; i++) { GdkAtom atom = array[i]; +#ifdef __WXDEBUG__ wxLogTrace(TRACE_DND, wxT("Drop source: Supported atom %s"), gdk_atom_name( atom )); - gtk_target_list_add( target_list, atom, 0, 0 ); +#endif + gtk_target_list_add( target_list, atom, 0, 0 ); } delete[] array; - GdkEventMotion event; - event.window = m_widget->window; - int x = 0; - int y = 0; - GdkModifierType state; - gdk_window_get_pointer( event.window, &x, &y, &state ); - event.x = x; - event.y = y; - event.state = state; - event.time = (guint32)GDK_CURRENT_TIME; - - /* GTK wants to know which button was pressed which caused the dragging */ - int button_number = 0; - if (event.state & GDK_BUTTON1_MASK) button_number = 1; - else if (event.state & GDK_BUTTON2_MASK) button_number = 2; - else if (event.state & GDK_BUTTON3_MASK) button_number = 3; - -#if wxUSE_THREADS - /* disable GUI threads */ -#endif - - /* don't start dragging if no button is down */ - if (button_number) - { - int action = GDK_ACTION_COPY; - if ( flags & wxDrag_AllowMove ) - action |= GDK_ACTION_MOVE; + 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; + // 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, + GdkDragContext *context = gtk_drag_begin( m_widget, target_list, (GdkDragAction)action, - button_number, /* number of mouse button which started drag */ - (GdkEvent*) &event ); - - m_dragContext = context; - - PrepareIcon( action, context ); + g_lastButtonNumber, // number of mouse button which started drag + (GdkEvent*) g_lastMouseEvent ); - while (m_waiting) - gtk_main_iteration(); - - m_retValue = ConvertFromGTK(context->action); - if ( m_retValue == wxDragNone ) - m_retValue = wxDragCancel; + if ( !context ) + { + // this can happen e.g. if gdk_pointer_grab() failed + return wxDragError; } -#if wxUSE_THREADS - /* re-enable GUI threads */ -#endif + m_dragContext = context; - g_blockEventsOnDrag = false; + PrepareIcon( action, context ); - UnregisterWindow(); + while (m_waiting) + gtk_main_iteration(); + + m_retValue = ConvertFromGTK(context->action); + if ( m_retValue == wxDragNone ) + m_retValue = wxDragCancel; return m_retValue; } -void wxDropSource::RegisterWindow() +void wxDropSource::GTKConnectDragSignals() { - if (!m_widget) return; + if (!m_widget) + return; + + g_blockEventsOnDrag = true; g_signal_connect (m_widget, "drag_data_get", G_CALLBACK (source_drag_data_get), this); - g_signal_connect (m_widget, "drag_data_delete", - G_CALLBACK (source_drag_data_delete), this); - g_signal_connect (m_widget, "drag_begin", - G_CALLBACK (source_drag_begin), this); g_signal_connect (m_widget, "drag_end", G_CALLBACK (source_drag_end), this); } -void wxDropSource::UnregisterWindow() +void wxDropSource::GTKDisconnectDragSignals() { if (!m_widget) return; + g_blockEventsOnDrag = false; + g_signal_handlers_disconnect_by_func (m_widget, (gpointer) source_drag_data_get, this); - g_signal_handlers_disconnect_by_func (m_widget, - (gpointer) source_drag_data_delete, - this); - g_signal_handlers_disconnect_by_func (m_widget, - (gpointer) source_drag_begin, - this); g_signal_handlers_disconnect_by_func (m_widget, (gpointer) source_drag_end, this);