1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/gtk/dnd.cpp 
   3 // Purpose:     wxDropTarget class 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) 1998 Robert Roebling 
   7 // Licence:     wxWindows licence 
   8 /////////////////////////////////////////////////////////////////////////////// 
  10 // For compilers that support precompilation, includes "wx.h". 
  11 #include "wx/wxprec.h" 
  13 #if wxUSE_DRAG_AND_DROP 
  22     #include "wx/window.h" 
  23     #include "wx/gdicmn.h" 
  26 #include "wx/scopeguard.h" 
  30 //---------------------------------------------------------------------------- 
  32 //---------------------------------------------------------------------------- 
  34 extern bool g_blockEventsOnDrag
; 
  36 // the flags used for the last DoDragDrop() 
  37 static long gs_flagsForDrag 
= 0; 
  39 // the trace mask we use with wxLogTrace() - call 
  40 // wxLog::AddTraceMask(TRACE_DND) to enable the trace messages from here 
  41 // (there are quite a few of them, so don't enable this by default) 
  42 #define TRACE_DND "dnd" 
  44 // global variables because GTK+ DnD want to have the 
  45 // mouse event that caused it 
  46 extern GdkEvent 
*g_lastMouseEvent
; 
  47 extern int       g_lastButtonNumber
; 
  49 //---------------------------------------------------------------------------- 
  51 //---------------------------------------------------------------------------- 
  53 /* Copyright (c) Julian Smart */ 
  54 static const char * page_xpm
[] = { 
  55 /* columns rows colors chars-per-pixel */ 
 104 "       56477<<<<8<<9&:X         ", 
 105 "       59642%&*=-;<09&:5        ", 
 106 "       5q9642%&*=-<<<<<#        ", 
 107 "       5qqw777<<<<<88:>+        ", 
 108 "       erqq9642%&*=t;::+        ", 
 109 "       eyrqq9642%&*=t;:O        ", 
 110 "       eyywwww777<<<<t;O        ", 
 111 "       e0yyrqq9642%&*=to        ", 
 112 "       e00yyrqq9642%&*=o        ", 
 113 "       eu0wwwwwww777<&*X        ", 
 114 "       euu00yyrqq9642%&X        ", 
 115 "       eiuu00yyrqq9642%X        ", 
 116 "       eiiwwwwwwwwww742$        ", 
 117 "       eiiiuu00yyrqq964$        ", 
 118 "       eiiiiuu00yyrqq96$        ", 
 119 "       eiiiiiuu00yyrqq95        ", 
 120 "       eiiiiiiuu00yyrqq5        ", 
 121 "       eeeeeeeeeeeeee55e        ", 
 130 // ============================================================================ 
 132 // ============================================================================ 
 134 // ---------------------------------------------------------------------------- 
 135 // convert between GTK+ and wxWidgets DND constants 
 136 // ---------------------------------------------------------------------------- 
 138 static wxDragResult 
ConvertFromGTK(long action
) 
 142         case GDK_ACTION_COPY
: 
 145         case GDK_ACTION_LINK
: 
 148         case GDK_ACTION_MOVE
: 
 155 // ---------------------------------------------------------------------------- 
 157 // ---------------------------------------------------------------------------- 
 160 static void target_drag_leave( GtkWidget 
*WXUNUSED(widget
), 
 161                                GdkDragContext 
*context
, 
 162                                guint 
WXUNUSED(time
), 
 163                                wxDropTarget 
*drop_target 
) 
 165     /* inform the wxDropTarget about the current GdkDragContext. 
 166        this is only valid for the duration of this call */ 
 167     drop_target
->GTKSetDragContext( context 
); 
 169     /* we don't need return values. this event is just for 
 171     drop_target
->OnLeave(); 
 173     /* this has to be done because GDK has no "drag_enter" event */ 
 174     drop_target
->m_firstMotion 
= true; 
 176     /* after this, invalidate the drop_target's GdkDragContext */ 
 177     drop_target
->GTKSetDragContext( NULL 
); 
 181 // ---------------------------------------------------------------------------- 
 183 // ---------------------------------------------------------------------------- 
 186 static gboolean 
target_drag_motion( GtkWidget 
*WXUNUSED(widget
), 
 187                                     GdkDragContext 
*context
, 
 191                                     wxDropTarget 
*drop_target 
) 
 193     /* Owen Taylor: "if the coordinates not in a drop zone, 
 194        return FALSE, otherwise call gtk_drag_status() and 
 198     wxPrintf( "motion\n" ); 
 200     for (tmp_list 
= context
->targets
; tmp_list
; tmp_list 
= tmp_list
->next
) 
 202         wxString atom 
= wxString::FromAscii( gdk_atom_name (GDK_POINTER_TO_ATOM (tmp_list
->data
)) ); 
 203         wxPrintf( "Atom: %s\n", atom 
); 
 207     // Inform the wxDropTarget about the current GdkDragContext. 
 208     // This is only valid for the duration of this call. 
 209     drop_target
->GTKSetDragContext( context 
); 
 211     // Does the source actually accept the data type? 
 212     if (drop_target
->GTKGetMatchingPair() == (GdkAtom
) 0) 
 214         drop_target
->GTKSetDragContext( NULL 
); 
 218     wxDragResult suggested_action 
= drop_target
->GTKFigureOutSuggestedAction(); 
 220     wxDragResult result 
= wxDragNone
; 
 222     if (drop_target
->m_firstMotion
) 
 224         // the first "drag_motion" event substitutes a "drag_enter" event 
 225         result 
= drop_target
->OnEnter( x
, y
, suggested_action 
); 
 229         // give program a chance to react (i.e. to say no by returning FALSE) 
 230         result 
= drop_target
->OnDragOver( x
, y
, suggested_action 
); 
 233     GdkDragAction result_action 
= GDK_ACTION_DEFAULT
; 
 234     if (result 
== wxDragCopy
) 
 235         result_action 
= GDK_ACTION_COPY
; 
 236     else if (result 
== wxDragLink
) 
 237         result_action 
= GDK_ACTION_LINK
; 
 239         result_action 
= GDK_ACTION_MOVE
; 
 241     // is result action actually supported 
 242     bool ret ((result_action 
!= GDK_ACTION_DEFAULT
) && 
 243               (context
->actions 
& result_action
)); 
 246         gdk_drag_status( context
, result_action
, time 
); 
 248     // after this, invalidate the drop_target's GdkDragContext 
 249     drop_target
->GTKSetDragContext( NULL 
); 
 251     // this has to be done because GDK has no "drag_enter" event 
 252     drop_target
->m_firstMotion 
= false; 
 258 // ---------------------------------------------------------------------------- 
 260 // ---------------------------------------------------------------------------- 
 263 static gboolean 
target_drag_drop( GtkWidget 
*widget
, 
 264                                   GdkDragContext 
*context
, 
 268                                   wxDropTarget 
*drop_target 
) 
 270     /* Owen Taylor: "if the drop is not in a drop zone, 
 271        return FALSE, otherwise, if you aren't accepting 
 272        the drop, call gtk_drag_finish() with success == FALSE 
 273        otherwise call gtk_drag_data_get()" */ 
 275     /* inform the wxDropTarget about the current GdkDragContext. 
 276        this is only valid for the duration of this call */ 
 277     drop_target
->GTKSetDragContext( context 
); 
 279     // Does the source actually accept the data type? 
 280     if (drop_target
->GTKGetMatchingPair() == (GdkAtom
) 0) 
 282         // cancel the whole thing 
 283         gtk_drag_finish( context
, 
 285                           FALSE
,        // don't delete data on dropping side 
 288         drop_target
->GTKSetDragContext( NULL 
); 
 290         drop_target
->m_firstMotion 
= true; 
 295     /* inform the wxDropTarget about the current drag widget. 
 296        this is only valid for the duration of this call */ 
 297     drop_target
->GTKSetDragWidget( widget 
); 
 299     /* inform the wxDropTarget about the current drag time. 
 300        this is only valid for the duration of this call */ 
 301     drop_target
->GTKSetDragTime( time 
); 
 303     /* reset the block here as someone might very well 
 304        show a dialog as a reaction to a drop and this 
 305        wouldn't work without events */ 
 306     g_blockEventsOnDrag 
= false; 
 308     bool ret 
= drop_target
->OnDrop( x
, y 
); 
 312         wxLogTrace(TRACE_DND
, wxT( "Drop target: OnDrop returned FALSE") ); 
 314         /* cancel the whole thing */ 
 315         gtk_drag_finish( context
, 
 316                           FALSE
,        /* no success */ 
 317                           FALSE
,        /* don't delete data on dropping side */ 
 322         wxLogTrace(TRACE_DND
, wxT( "Drop target: OnDrop returned true") ); 
 324         GdkAtom format 
= drop_target
->GTKGetMatchingPair(); 
 326         // this does happen somehow, see bug 555111 
 327         wxCHECK_MSG( format
, FALSE
, wxT("no matching GdkAtom for format?") ); 
 329         /* this should trigger an "drag_data_received" event */ 
 330         gtk_drag_get_data( widget
, 
 336     /* after this, invalidate the drop_target's GdkDragContext */ 
 337     drop_target
->GTKSetDragContext( NULL 
); 
 339     /* after this, invalidate the drop_target's drag widget */ 
 340     drop_target
->GTKSetDragWidget( NULL 
); 
 342     /* this has to be done because GDK has no "drag_enter" event */ 
 343     drop_target
->m_firstMotion 
= true; 
 349 // ---------------------------------------------------------------------------- 
 350 // "drag_data_received" 
 351 // ---------------------------------------------------------------------------- 
 354 static void target_drag_data_received( GtkWidget 
*WXUNUSED(widget
), 
 355                                        GdkDragContext 
*context
, 
 358                                        GtkSelectionData 
*data
, 
 359                                        guint 
WXUNUSED(info
), 
 361                                        wxDropTarget 
*drop_target 
) 
 363     /* Owen Taylor: "call gtk_drag_finish() with 
 366     if ((data
->length 
<= 0) || (data
->format 
!= 8)) 
 368         /* negative data length and non 8-bit data format 
 369            qualifies for junk */ 
 370         gtk_drag_finish (context
, FALSE
, FALSE
, time
); 
 375     wxLogTrace(TRACE_DND
, wxT( "Drop target: data received event") ); 
 377     /* inform the wxDropTarget about the current GtkSelectionData. 
 378        this is only valid for the duration of this call */ 
 379     drop_target
->GTKSetDragData( data 
); 
 381     wxDragResult result 
= ConvertFromGTK(context
->action
); 
 383     if ( wxIsDragResultOk( drop_target
->OnData( x
, y
, result 
) ) ) 
 385         wxLogTrace(TRACE_DND
, wxT( "Drop target: OnData returned true") ); 
 387         /* tell GTK that data transfer was successful */ 
 388         gtk_drag_finish( context
, TRUE
, FALSE
, time 
); 
 392         wxLogTrace(TRACE_DND
, wxT( "Drop target: OnData returned FALSE") ); 
 394         /* tell GTK that data transfer was not successful */ 
 395         gtk_drag_finish( context
, FALSE
, FALSE
, time 
); 
 398     /* after this, invalidate the drop_target's drag data */ 
 399     drop_target
->GTKSetDragData( NULL 
); 
 403 //---------------------------------------------------------------------------- 
 405 //---------------------------------------------------------------------------- 
 407 wxDropTarget::wxDropTarget( wxDataObject 
*data 
) 
 408             : wxDropTargetBase( data 
) 
 410     m_firstMotion 
= true; 
 411     m_dragContext 
= NULL
; 
 417 wxDragResult 
wxDropTarget::OnDragOver( wxCoord 
WXUNUSED(x
), 
 424 bool wxDropTarget::OnDrop( wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
) ) 
 429 wxDragResult 
wxDropTarget::OnData( wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
), 
 432     return GetData() ? def 
: wxDragNone
; 
 435 wxDragResult 
wxDropTarget::GTKFigureOutSuggestedAction() 
 440     // GTK+ always supposes that we want to copy the data by default while we 
 441     // might want to move it, so examine not only suggested_action - which is 
 442     // only good if we don't have our own preferences - but also the actions 
 444     wxDragResult suggested_action 
= wxDragNone
; 
 445     if (GetDefaultAction() == wxDragNone
) 
 447         // use default action set by wxDropSource::DoDragDrop() 
 448         if ( (gs_flagsForDrag 
& wxDrag_DefaultMove
) == wxDrag_DefaultMove 
&& 
 449             (m_dragContext
->actions 
& GDK_ACTION_MOVE 
) ) 
 451             // move is requested by the program and allowed by GTK+ - do it, even 
 452             // though suggested_action may be currently wxDragCopy 
 453             suggested_action 
= wxDragMove
; 
 455         else // use whatever GTK+ says we should 
 457             suggested_action 
= ConvertFromGTK(m_dragContext
->suggested_action
); 
 460             // RR: I don't understand the code below: if the drag comes from 
 461             //     a different app, the gs_flagsForDrag is invalid; if it 
 462             //     comes from the same wx app, then GTK+ hopefully won't 
 463             //     suggest something we didn't allow in the frist place 
 465             if ( (suggested_action 
== wxDragMove
) && !(gs_flagsForDrag 
& wxDrag_AllowMove
) ) 
 467                 // we're requested to move but we can't 
 468                 suggested_action 
= wxDragCopy
; 
 473     else if (GetDefaultAction() == wxDragMove 
&& 
 474             (m_dragContext
->actions 
& GDK_ACTION_MOVE
)) 
 477         suggested_action 
= wxDragMove
; 
 481         if (m_dragContext
->actions 
& GDK_ACTION_COPY
) 
 482             suggested_action 
= wxDragCopy
; 
 483         else if (m_dragContext
->actions 
& GDK_ACTION_MOVE
) 
 484             suggested_action 
= wxDragMove
; 
 485         else if (m_dragContext
->actions 
& GDK_ACTION_LINK
) 
 486             suggested_action 
= wxDragLink
; 
 488             suggested_action 
= wxDragNone
; 
 491     return suggested_action
; 
 494 wxDataFormat 
wxDropTarget::GetMatchingPair() 
 496     return wxDataFormat( GTKGetMatchingPair() ); 
 499 GdkAtom 
wxDropTarget::GTKGetMatchingPair(bool quiet
) 
 507     GList 
*child 
= m_dragContext
->targets
; 
 510         GdkAtom formatAtom 
= (GdkAtom
)(child
->data
); 
 511         wxDataFormat 
format( formatAtom 
); 
 515             wxLogTrace(TRACE_DND
, wxT("Drop target: drag has format: %s"), 
 516                        format
.GetId().c_str()); 
 519         if (m_dataObject
->IsSupportedFormat( format 
)) 
 528 bool wxDropTarget::GetData() 
 536     wxDataFormat 
dragFormat( m_dragData
->target 
); 
 538     if (!m_dataObject
->IsSupportedFormat( dragFormat 
)) 
 541     m_dataObject
->SetData( dragFormat
, (size_t)m_dragData
->length
, (const void*)m_dragData
->data 
); 
 546 void wxDropTarget::GtkUnregisterWidget( GtkWidget 
*widget 
) 
 548     wxCHECK_RET( widget 
!= NULL
, wxT("unregister widget is NULL") ); 
 550     gtk_drag_dest_unset( widget 
); 
 552     g_signal_handlers_disconnect_by_func (widget
, 
 553                                           (gpointer
) target_drag_leave
, this); 
 554     g_signal_handlers_disconnect_by_func (widget
, 
 555                                           (gpointer
) target_drag_motion
, this); 
 556     g_signal_handlers_disconnect_by_func (widget
, 
 557                                           (gpointer
) target_drag_drop
, this); 
 558     g_signal_handlers_disconnect_by_func (widget
, 
 559                                           (gpointer
) target_drag_data_received
, this); 
 562 void wxDropTarget::GtkRegisterWidget( GtkWidget 
*widget 
) 
 564     wxCHECK_RET( widget 
!= NULL
, wxT("register widget is NULL") ); 
 566     /* gtk_drag_dest_set() determines what default behaviour we'd like 
 567        GTK to supply. we don't want to specify out targets (=formats) 
 568        or actions in advance (i.e. not GTK_DEST_DEFAULT_MOTION and 
 569        not GTK_DEST_DEFAULT_DROP). instead we react individually to 
 570        "drag_motion" and "drag_drop" events. this makes it possible 
 571        to allow dropping on only a small area. we should set 
 572        GTK_DEST_DEFAULT_HIGHLIGHT as this will switch on the nice 
 573        highlighting if dragging over standard controls, but this 
 574        seems to be broken without the other two. */ 
 576     gtk_drag_dest_set( widget
, 
 577                        (GtkDestDefaults
) 0,         /* no default behaviour */ 
 578                        NULL
,      /* we don't supply any formats here */ 
 579                        0,                           /* number of targets = 0 */ 
 580                        (GdkDragAction
) 0 );         /* we don't supply any actions here */ 
 582     g_signal_connect (widget
, "drag_leave", 
 583                       G_CALLBACK (target_drag_leave
), this); 
 585     g_signal_connect (widget
, "drag_motion", 
 586                       G_CALLBACK (target_drag_motion
), this); 
 588     g_signal_connect (widget
, "drag_drop", 
 589                       G_CALLBACK (target_drag_drop
), this); 
 591     g_signal_connect (widget
, "drag_data_received", 
 592                       G_CALLBACK (target_drag_data_received
), this); 
 595 //---------------------------------------------------------------------------- 
 597 //---------------------------------------------------------------------------- 
 601 source_drag_data_get  (GtkWidget          
*WXUNUSED(widget
), 
 602                        GdkDragContext     
*context
, 
 603                        GtkSelectionData   
*selection_data
, 
 604                        guint               
WXUNUSED(info
), 
 605                        guint               
WXUNUSED(time
), 
 606                        wxDropSource       
*drop_source 
) 
 608     wxDataFormat 
format( selection_data
->target 
); 
 610     wxLogTrace(TRACE_DND
, wxT("Drop source: format requested: %s"), 
 611                format
.GetId().c_str()); 
 613     drop_source
->m_retValue 
= wxDragError
; 
 615     wxDataObject 
*data 
= drop_source
->GetDataObject(); 
 619         wxLogTrace(TRACE_DND
, wxT("Drop source: no data object") ); 
 623     if (!data
->IsSupportedFormat(format
)) 
 625         wxLogTrace(TRACE_DND
, wxT("Drop source: unsupported format") ); 
 629     if (data
->GetDataSize(format
) == 0) 
 631         wxLogTrace(TRACE_DND
, wxT("Drop source: empty data") ); 
 635     size_t size 
= data
->GetDataSize(format
); 
 637 //  printf( "data size: %d.\n", (int)data_size ); 
 639     guchar 
*d 
= new guchar
[size
]; 
 641     if (!data
->GetDataHere( format
, (void*)d 
)) 
 647     drop_source
->m_retValue 
= ConvertFromGTK( context
->action 
); 
 649     gtk_selection_data_set( selection_data
, 
 650                             selection_data
->target
, 
 659 //---------------------------------------------------------------------------- 
 661 //---------------------------------------------------------------------------- 
 664 static void source_drag_end( GtkWidget          
*WXUNUSED(widget
), 
 665                              GdkDragContext     
*WXUNUSED(context
), 
 666                              wxDropSource       
*drop_source 
) 
 668     drop_source
->m_waiting 
= false; 
 672 //----------------------------------------------------------------------------- 
 673 // "configure_event" from m_iconWindow 
 674 //----------------------------------------------------------------------------- 
 678 gtk_dnd_window_configure_callback( GtkWidget 
*WXUNUSED(widget
), GdkEventConfigure 
*WXUNUSED(event
), wxDropSource 
*source 
) 
 680     source
->GiveFeedback( ConvertFromGTK(source
->m_dragContext
->action
) ); 
 686 //--------------------------------------------------------------------------- 
 688 //--------------------------------------------------------------------------- 
 690 wxDropSource::wxDropSource(wxWindow 
*win
, 
 691                            const wxIcon 
&iconCopy
, 
 692                            const wxIcon 
&iconMove
, 
 693                            const wxIcon 
&iconNone
) 
 700     m_widget 
= win
->m_widget
; 
 701     if (win
->m_wxwindow
) m_widget 
= win
->m_wxwindow
; 
 703     m_retValue 
= wxDragNone
; 
 705     SetIcons(iconCopy
, iconMove
, iconNone
); 
 708 wxDropSource::wxDropSource(wxDataObject
& data
, 
 710                            const wxIcon 
&iconCopy
, 
 711                            const wxIcon 
&iconMove
, 
 712                            const wxIcon 
&iconNone
) 
 721     m_widget 
= win
->m_widget
; 
 722     if (win
->m_wxwindow
) m_widget 
= win
->m_wxwindow
; 
 724     m_retValue 
= wxDragNone
; 
 726     SetIcons(iconCopy
, iconMove
, iconNone
); 
 729 void wxDropSource::SetIcons(const wxIcon 
&iconCopy
, 
 730                             const wxIcon 
&iconMove
, 
 731                             const wxIcon 
&iconNone
) 
 733     m_iconCopy 
= iconCopy
; 
 734     m_iconMove 
= iconMove
; 
 735     m_iconNone 
= iconNone
; 
 737     if ( !m_iconCopy
.Ok() ) 
 738         m_iconCopy 
= wxIcon(page_xpm
); 
 739     if ( !m_iconMove
.Ok() ) 
 740         m_iconMove 
= m_iconCopy
; 
 741     if ( !m_iconNone
.Ok() ) 
 742         m_iconNone 
= m_iconCopy
; 
 745 wxDropSource::~wxDropSource() 
 749 void wxDropSource::PrepareIcon( int action
, GdkDragContext 
*context 
) 
 751     // get the right icon to display 
 753     if ( action 
& GDK_ACTION_MOVE 
) 
 755     else if ( action 
& GDK_ACTION_COPY 
) 
 761     if ( icon
->GetMask() ) 
 762         mask 
= icon
->GetMask()->GetBitmap(); 
 766     GdkPixmap 
*pixmap 
= icon
->GetPixmap(); 
 769     gdk_drawable_get_size (pixmap
, &width
, &height
); 
 771     GdkColormap 
*colormap 
= gtk_widget_get_colormap( m_widget 
); 
 772     gtk_widget_push_colormap (colormap
); 
 774     m_iconWindow 
= gtk_window_new (GTK_WINDOW_POPUP
); 
 775     gtk_widget_set_events (m_iconWindow
, GDK_BUTTON_PRESS_MASK 
| GDK_BUTTON_RELEASE_MASK
); 
 776     gtk_widget_set_app_paintable (m_iconWindow
, TRUE
); 
 778     gtk_widget_pop_colormap (); 
 780     gtk_widget_set_size_request (m_iconWindow
, width
, height
); 
 781     gtk_widget_realize (m_iconWindow
); 
 783     g_signal_connect (m_iconWindow
, "configure_event", 
 784                       G_CALLBACK (gtk_dnd_window_configure_callback
), this); 
 786     gdk_window_set_back_pixmap (m_iconWindow
->window
, pixmap
, FALSE
); 
 789         gtk_widget_shape_combine_mask (m_iconWindow
, mask
, 0, 0); 
 791     gtk_drag_set_icon_widget( context
, m_iconWindow
, 0, 0 ); 
 794 wxDragResult 
wxDropSource::DoDragDrop(int flags
) 
 796     wxCHECK_MSG( m_data 
&& m_data
->GetFormatCount(), wxDragNone
, 
 797                  wxT("Drop source: no data") ); 
 800     if (g_blockEventsOnDrag
) 
 803     // don't start dragging if no button is down 
 804     if (g_lastButtonNumber 
== 0) 
 807     // we can only start a drag after a mouse event 
 808     if (g_lastMouseEvent 
== NULL
) 
 811     GTKConnectDragSignals(); 
 812     wxON_BLOCK_EXIT_OBJ0(*this, wxDropSource::GTKDisconnectDragSignals
); 
 816     GtkTargetList 
*target_list 
= gtk_target_list_new( NULL
, 0 ); 
 818     wxDataFormat 
*array 
= new wxDataFormat
[ m_data
->GetFormatCount() ]; 
 819     m_data
->GetAllFormats( array 
); 
 820     size_t count 
= m_data
->GetFormatCount(); 
 821     for (size_t i 
= 0; i 
< count
; i
++) 
 823         GdkAtom atom 
= array
[i
]; 
 824         wxLogTrace(TRACE_DND
, wxT("Drop source: Supported atom %s"), 
 825                    gdk_atom_name( atom 
)); 
 826         gtk_target_list_add( target_list
, atom
, 0, 0 ); 
 830     int allowed_actions 
= GDK_ACTION_COPY
; 
 831     if ( flags 
& wxDrag_AllowMove 
) 
 832         allowed_actions 
|= GDK_ACTION_MOVE
; 
 834     // VZ: as we already use g_blockEventsOnDrag it shouldn't be that bad 
 835     //     to use a global to pass the flags to the drop target but I'd 
 836     //     surely prefer a better way to do it 
 837     gs_flagsForDrag 
= flags
; 
 839     m_retValue 
= wxDragCancel
; 
 841     GdkDragContext 
*context 
= gtk_drag_begin( m_widget
, 
 843                 (GdkDragAction
)allowed_actions
, 
 844                 g_lastButtonNumber
,  // number of mouse button which started drag 
 845                 (GdkEvent
*) g_lastMouseEvent 
); 
 849         // this can happen e.g. if gdk_pointer_grab() failed 
 853     m_dragContext 
= context
; 
 855     PrepareIcon( allowed_actions
, context 
); 
 858         gtk_main_iteration(); 
 860     g_signal_handlers_disconnect_by_func (m_iconWindow
, 
 861                                           (gpointer
) gtk_dnd_window_configure_callback
, this); 
 866 void wxDropSource::GTKConnectDragSignals() 
 871     g_blockEventsOnDrag 
= true; 
 873     g_signal_connect (m_widget
, "drag_data_get", 
 874                       G_CALLBACK (source_drag_data_get
), this); 
 875     g_signal_connect (m_widget
, "drag_end", 
 876                       G_CALLBACK (source_drag_end
), this); 
 880 void wxDropSource::GTKDisconnectDragSignals() 
 885     g_blockEventsOnDrag 
= false; 
 887     g_signal_handlers_disconnect_by_func (m_widget
, 
 888                                           (gpointer
) source_drag_data_get
, 
 890     g_signal_handlers_disconnect_by_func (m_widget
, 
 891                                           (gpointer
) source_drag_end
, 
 896       // wxUSE_DRAG_AND_DROP