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/gtk/private.h" 
  28 #include <gdk/gdkprivate.h> 
  30 #include <gtk/gtkdnd.h> 
  31 #include <gtk/gtkselection.h> 
  33 //---------------------------------------------------------------------------- 
  35 //---------------------------------------------------------------------------- 
  37 extern bool g_blockEventsOnDrag
; 
  39 // the flags used for the last DoDragDrop() 
  40 static long gs_flagsForDrag 
= 0; 
  42 // the trace mask we use with wxLogTrace() - call 
  43 // wxLog::AddTraceMask(TRACE_DND) to enable the trace messages from here 
  44 // (there are quite a few of them, so don't enable this by default) 
  45 static const wxChar 
*TRACE_DND 
= _T("dnd"); 
  47 //---------------------------------------------------------------------------- 
  49 //---------------------------------------------------------------------------- 
  51 /* Copyright (c) Julian Smart */ 
  52 static const char * page_xpm
[] = { 
  53 /* columns rows colors chars-per-pixel */ 
 102 "       56477<<<<8<<9&:X         ", 
 103 "       59642%&*=-;<09&:5        ", 
 104 "       5q9642%&*=-<<<<<#        ", 
 105 "       5qqw777<<<<<88:>+        ", 
 106 "       erqq9642%&*=t;::+        ", 
 107 "       eyrqq9642%&*=t;:O        ", 
 108 "       eyywwww777<<<<t;O        ", 
 109 "       e0yyrqq9642%&*=to        ", 
 110 "       e00yyrqq9642%&*=o        ", 
 111 "       eu0wwwwwww777<&*X        ", 
 112 "       euu00yyrqq9642%&X        ", 
 113 "       eiuu00yyrqq9642%X        ", 
 114 "       eiiwwwwwwwwww742$        ", 
 115 "       eiiiuu00yyrqq964$        ", 
 116 "       eiiiiuu00yyrqq96$        ", 
 117 "       eiiiiiuu00yyrqq95        ", 
 118 "       eiiiiiiuu00yyrqq5        ", 
 119 "       eeeeeeeeeeeeee55e        ", 
 128 // ============================================================================ 
 130 // ============================================================================ 
 132 // ---------------------------------------------------------------------------- 
 133 // convert between GTK+ and wxWidgets DND constants 
 134 // ---------------------------------------------------------------------------- 
 136 static wxDragResult 
ConvertFromGTK(long action
) 
 140         case GDK_ACTION_COPY
: 
 143         case GDK_ACTION_LINK
: 
 146         case GDK_ACTION_MOVE
: 
 153 // ---------------------------------------------------------------------------- 
 155 // ---------------------------------------------------------------------------- 
 158 static void target_drag_leave( GtkWidget 
*WXUNUSED(widget
), 
 159                                GdkDragContext 
*context
, 
 160                                guint 
WXUNUSED(time
), 
 161                                wxDropTarget 
*drop_target 
) 
 163     if (g_isIdle
) wxapp_install_idle_handler(); 
 165     /* inform the wxDropTarget about the current GdkDragContext. 
 166        this is only valid for the duration of this call */ 
 167     drop_target
->SetDragContext( 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
->SetDragContext( (GdkDragContext
*) NULL 
); 
 181 // ---------------------------------------------------------------------------- 
 183 // ---------------------------------------------------------------------------- 
 186 static gboolean 
target_drag_motion( GtkWidget 
*WXUNUSED(widget
), 
 187                                     GdkDragContext 
*context
, 
 191                                     wxDropTarget 
*drop_target 
) 
 193     if (g_isIdle
) wxapp_install_idle_handler(); 
 195     /* Owen Taylor: "if the coordinates not in a drop zone, 
 196        return FALSE, otherwise call gtk_drag_status() and 
 199     /* inform the wxDropTarget about the current GdkDragContext. 
 200        this is only valid for the duration of this call */ 
 201     drop_target
->SetDragContext( context 
); 
 203     // GTK+ always supposes that we want to copy the data by default while we 
 204     // might want to move it, so examine not only suggested_action - which is 
 205     // only good if we don't have our own preferences - but also the actions 
 208     if (drop_target
->GetDefaultAction() == wxDragNone
) 
 210         // use default action set by wxDropSource::DoDragDrop() 
 211     if ( (gs_flagsForDrag 
& wxDrag_DefaultMove
) == wxDrag_DefaultMove 
&& 
 212             (context
->actions 
& GDK_ACTION_MOVE 
) ) 
 214         // move is requested by the program and allowed by GTK+ - do it, even 
 215         // though suggested_action may be currently wxDragCopy 
 218     else // use whatever GTK+ says we should 
 220         result 
= ConvertFromGTK(context
->suggested_action
); 
 222         if ( (result 
== wxDragMove
) && !(gs_flagsForDrag 
& wxDrag_AllowMove
) ) 
 224             // we're requested to move but we can't 
 229     else if (drop_target
->GetDefaultAction() == wxDragMove 
&& 
 230                 (context
->actions 
& GDK_ACTION_MOVE
)) 
 236         if (context
->actions 
& GDK_ACTION_COPY
) 
 238         else if (context
->actions 
& GDK_ACTION_MOVE
) 
 244     if (drop_target
->m_firstMotion
) 
 246         /* the first "drag_motion" event substitutes a "drag_enter" event */ 
 247         result 
= drop_target
->OnEnter( x
, y
, result 
); 
 251         /* give program a chance to react (i.e. to say no by returning FALSE) */ 
 252         result 
= drop_target
->OnDragOver( x
, y
, result 
); 
 255     bool ret 
= wxIsDragResultOk( result 
); 
 258         GdkDragAction action
; 
 259         if (result 
== wxDragCopy
) 
 260             action 
= GDK_ACTION_COPY
; 
 261         else if (result 
== wxDragLink
) 
 262             action 
= GDK_ACTION_LINK
; 
 264             action 
= GDK_ACTION_MOVE
; 
 266         gdk_drag_status( context
, action
, time 
); 
 269     /* after this, invalidate the drop_target's GdkDragContext */ 
 270     drop_target
->SetDragContext( (GdkDragContext
*) NULL 
); 
 272     /* this has to be done because GDK has no "drag_enter" event */ 
 273     drop_target
->m_firstMotion 
= false; 
 279 // ---------------------------------------------------------------------------- 
 281 // ---------------------------------------------------------------------------- 
 284 static gboolean 
target_drag_drop( GtkWidget 
*widget
, 
 285                                   GdkDragContext 
*context
, 
 289                                   wxDropTarget 
*drop_target 
) 
 291     if (g_isIdle
) wxapp_install_idle_handler(); 
 293     /* Owen Taylor: "if the drop is not in a drop zone, 
 294        return FALSE, otherwise, if you aren't accepting 
 295        the drop, call gtk_drag_finish() with success == FALSE 
 296        otherwise call gtk_drag_data_get()" */ 
 298 //    printf( "drop.\n" ); 
 300     /* this seems to make a difference between not accepting 
 301        due to wrong target area and due to wrong format. let 
 302        us hope that this is not required.. */ 
 304     /* inform the wxDropTarget about the current GdkDragContext. 
 305        this is only valid for the duration of this call */ 
 306     drop_target
->SetDragContext( context 
); 
 308     /* inform the wxDropTarget about the current drag widget. 
 309        this is only valid for the duration of this call */ 
 310     drop_target
->SetDragWidget( widget 
); 
 312     /* inform the wxDropTarget about the current drag time. 
 313        this is only valid for the duration of this call */ 
 314     drop_target
->SetDragTime( time 
); 
 317     wxDragResult result = wxDragMove; 
 318     if (context->suggested_action == GDK_ACTION_COPY) result = wxDragCopy; 
 321     /* reset the block here as someone might very well 
 322        show a dialog as a reaction to a drop and this 
 323        wouldn't work without events */ 
 324     g_blockEventsOnDrag 
= false; 
 326     bool ret 
= drop_target
->OnDrop( x
, y 
); 
 330         wxLogTrace(TRACE_DND
, wxT( "Drop target: OnDrop returned FALSE") ); 
 332         /* cancel the whole thing */ 
 333         gtk_drag_finish( context
, 
 334                           FALSE
,        /* no success */ 
 335                           FALSE
,        /* don't delete data on dropping side */ 
 340         wxLogTrace(TRACE_DND
, wxT( "Drop target: OnDrop returned true") ); 
 343         /* disable GUI threads */ 
 346         GdkAtom format 
= drop_target
->GetMatchingPair(); 
 348         // this does happen somehow, see bug 555111 
 349         wxCHECK_MSG( format
, FALSE
, _T("no matching GdkAtom for format?") ); 
 352         GdkDragAction action = GDK_ACTION_MOVE; 
 353         if (result == wxDragCopy) action == GDK_ACTION_COPY; 
 354         context->action = action; 
 356         /* this should trigger an "drag_data_received" event */ 
 357         gtk_drag_get_data( widget
, 
 363         /* re-enable GUI threads */ 
 367     /* after this, invalidate the drop_target's GdkDragContext */ 
 368     drop_target
->SetDragContext( (GdkDragContext
*) NULL 
); 
 370     /* after this, invalidate the drop_target's drag widget */ 
 371     drop_target
->SetDragWidget( (GtkWidget
*) NULL 
); 
 373     /* this has to be done because GDK has no "drag_enter" event */ 
 374     drop_target
->m_firstMotion 
= true; 
 380 // ---------------------------------------------------------------------------- 
 381 // "drag_data_received" 
 382 // ---------------------------------------------------------------------------- 
 385 static void target_drag_data_received( GtkWidget 
*WXUNUSED(widget
), 
 386                                        GdkDragContext 
*context
, 
 389                                        GtkSelectionData 
*data
, 
 390                                        guint 
WXUNUSED(info
), 
 392                                        wxDropTarget 
*drop_target 
) 
 394     if (g_isIdle
) wxapp_install_idle_handler(); 
 396     /* Owen Taylor: "call gtk_drag_finish() with 
 399     if ((data
->length 
<= 0) || (data
->format 
!= 8)) 
 401         /* negative data length and non 8-bit data format 
 402            qualifies for junk */ 
 403         gtk_drag_finish (context
, FALSE
, FALSE
, time
); 
 408     wxLogTrace(TRACE_DND
, wxT( "Drop target: data received event") ); 
 410     /* inform the wxDropTarget about the current GtkSelectionData. 
 411        this is only valid for the duration of this call */ 
 412     drop_target
->SetDragData( data 
); 
 414     wxDragResult result 
= ConvertFromGTK(context
->action
); 
 416     if ( wxIsDragResultOk( drop_target
->OnData( x
, y
, result 
) ) ) 
 418         wxLogTrace(TRACE_DND
, wxT( "Drop target: OnData returned true") ); 
 420         /* tell GTK that data transfer was successful */ 
 421         gtk_drag_finish( context
, TRUE
, FALSE
, time 
); 
 425         wxLogTrace(TRACE_DND
, wxT( "Drop target: OnData returned FALSE") ); 
 427         /* tell GTK that data transfer was not successful */ 
 428         gtk_drag_finish( context
, FALSE
, FALSE
, time 
); 
 431     /* after this, invalidate the drop_target's drag data */ 
 432     drop_target
->SetDragData( (GtkSelectionData
*) NULL 
); 
 436 //---------------------------------------------------------------------------- 
 438 //---------------------------------------------------------------------------- 
 440 wxDropTarget::wxDropTarget( wxDataObject 
*data 
) 
 441             : wxDropTargetBase( data 
) 
 443     m_firstMotion 
= true; 
 444     m_dragContext 
= (GdkDragContext
*) NULL
; 
 445     m_dragWidget 
= (GtkWidget
*) NULL
; 
 446     m_dragData 
= (GtkSelectionData
*) NULL
; 
 450 wxDragResult 
wxDropTarget::OnDragOver( wxCoord 
WXUNUSED(x
), 
 454     // GetMatchingPair() checks for m_dataObject too, no need to do it here 
 456     // disable the debug message from GetMatchingPair() - there are too many 
 462     return (GetMatchingPair() != (GdkAtom
) 0) ? def 
: wxDragNone
; 
 465 bool wxDropTarget::OnDrop( wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
) ) 
 470     return (GetMatchingPair() != (GdkAtom
) 0); 
 473 wxDragResult 
wxDropTarget::OnData( wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
), 
 479     if (GetMatchingPair() == (GdkAtom
) 0) 
 482     return GetData() ? def 
: wxDragNone
; 
 485 GdkAtom 
wxDropTarget::GetMatchingPair() 
 493     GList 
*child 
= m_dragContext
->targets
; 
 496         GdkAtom formatAtom 
= (GdkAtom
)(child
->data
); 
 497         wxDataFormat 
format( formatAtom 
); 
 500         wxLogTrace(TRACE_DND
, wxT("Drop target: drag has format: %s"), 
 501                    format
.GetId().c_str()); 
 504         if (m_dataObject
->IsSupportedFormat( format 
)) 
 513 bool wxDropTarget::GetData() 
 521     wxDataFormat 
dragFormat( m_dragData
->target 
); 
 523     if (!m_dataObject
->IsSupportedFormat( dragFormat 
)) 
 526     m_dataObject
->SetData( dragFormat
, (size_t)m_dragData
->length
, (const void*)m_dragData
->data 
); 
 531 void wxDropTarget::UnregisterWidget( GtkWidget 
*widget 
) 
 533     wxCHECK_RET( widget 
!= NULL
, wxT("unregister widget is NULL") ); 
 535     gtk_drag_dest_unset( widget 
); 
 537     g_signal_handlers_disconnect_by_func (widget
, 
 538                                           (gpointer
) target_drag_leave
, this); 
 539     g_signal_handlers_disconnect_by_func (widget
, 
 540                                           (gpointer
) target_drag_motion
, this); 
 541     g_signal_handlers_disconnect_by_func (widget
, 
 542                                           (gpointer
) target_drag_drop
, this); 
 543     g_signal_handlers_disconnect_by_func (widget
, 
 544                                           (gpointer
) target_drag_data_received
, this); 
 547 void wxDropTarget::RegisterWidget( GtkWidget 
*widget 
) 
 549     wxCHECK_RET( widget 
!= NULL
, wxT("register widget is NULL") ); 
 551     /* gtk_drag_dest_set() determines what default behaviour we'd like 
 552        GTK to supply. we don't want to specify out targets (=formats) 
 553        or actions in advance (i.e. not GTK_DEST_DEFAULT_MOTION and 
 554        not GTK_DEST_DEFAULT_DROP). instead we react individually to 
 555        "drag_motion" and "drag_drop" events. this makes it possible 
 556        to allow dropping on only a small area. we should set 
 557        GTK_DEST_DEFAULT_HIGHLIGHT as this will switch on the nice 
 558        highlighting if dragging over standard controls, but this 
 559        seems to be broken without the other two. */ 
 561     gtk_drag_dest_set( widget
, 
 562                        (GtkDestDefaults
) 0,         /* no default behaviour */ 
 563                        (GtkTargetEntry
*) NULL
,      /* we don't supply any formats here */ 
 564                        0,                           /* number of targets = 0 */ 
 565                        (GdkDragAction
) 0 );         /* we don't supply any actions here */ 
 567     g_signal_connect (widget
, "drag_leave", 
 568                       G_CALLBACK (target_drag_leave
), this); 
 570     g_signal_connect (widget
, "drag_motion", 
 571                       G_CALLBACK (target_drag_motion
), this); 
 573     g_signal_connect (widget
, "drag_drop", 
 574                       G_CALLBACK (target_drag_drop
), this); 
 576     g_signal_connect (widget
, "drag_data_received", 
 577                       G_CALLBACK (target_drag_data_received
), this); 
 580 //---------------------------------------------------------------------------- 
 582 //---------------------------------------------------------------------------- 
 586 source_drag_data_get  (GtkWidget          
*WXUNUSED(widget
), 
 587                        GdkDragContext     
*WXUNUSED(context
), 
 588                        GtkSelectionData   
*selection_data
, 
 589                        guint               
WXUNUSED(info
), 
 590                        guint               
WXUNUSED(time
), 
 591                        wxDropSource       
*drop_source 
) 
 593     if (g_isIdle
) wxapp_install_idle_handler(); 
 595     wxDataFormat 
format( selection_data
->target 
); 
 597     wxLogTrace(TRACE_DND
, wxT("Drop source: format requested: %s"), 
 598                format
.GetId().c_str()); 
 600     drop_source
->m_retValue 
= wxDragCancel
; 
 602     wxDataObject 
*data 
= drop_source
->GetDataObject(); 
 606         wxLogTrace(TRACE_DND
, wxT("Drop source: no data object") ); 
 610     if (!data
->IsSupportedFormat(format
)) 
 612         wxLogTrace(TRACE_DND
, wxT("Drop source: unsupported format") ); 
 616     if (data
->GetDataSize(format
) == 0) 
 618         wxLogTrace(TRACE_DND
, wxT("Drop source: empty data") ); 
 622     size_t size 
= data
->GetDataSize(format
); 
 624 //  printf( "data size: %d.\n", (int)data_size ); 
 626     guchar 
*d 
= new guchar
[size
]; 
 628     if (!data
->GetDataHere( format
, (void*)d 
)) 
 635     /* disable GUI threads */ 
 638     gtk_selection_data_set( selection_data
, 
 639                             selection_data
->target
, 
 645     /* enable GUI threads */ 
 652 //---------------------------------------------------------------------------- 
 653 // "drag_data_delete" 
 654 //---------------------------------------------------------------------------- 
 657 static void source_drag_data_delete( GtkWidget 
*WXUNUSED(widget
), 
 658                                      GdkDragContext 
*context
, 
 659                                      wxDropSource 
*WXUNUSED(drop_source
) ) 
 662         wxapp_install_idle_handler(); 
 664     // printf( "Drag source: drag_data_delete\n" ); 
 668 //---------------------------------------------------------------------------- 
 670 //---------------------------------------------------------------------------- 
 673 static void source_drag_begin( GtkWidget          
*WXUNUSED(widget
), 
 674                                GdkDragContext     
*WXUNUSED(context
), 
 675                                wxDropSource       
*WXUNUSED(drop_source
) ) 
 678         wxapp_install_idle_handler(); 
 680     // printf( "Drag source: drag_begin.\n" ); 
 684 //---------------------------------------------------------------------------- 
 686 //---------------------------------------------------------------------------- 
 689 static void source_drag_end( GtkWidget          
*WXUNUSED(widget
), 
 690                              GdkDragContext     
*WXUNUSED(context
), 
 691                              wxDropSource       
*drop_source 
) 
 693     if (g_isIdle
) wxapp_install_idle_handler(); 
 695     // printf( "Drag source: drag_end.\n" ); 
 697     drop_source
->m_waiting 
= false; 
 701 //----------------------------------------------------------------------------- 
 702 // "configure_event" from m_iconWindow 
 703 //----------------------------------------------------------------------------- 
 707 gtk_dnd_window_configure_callback( GtkWidget 
*WXUNUSED(widget
), GdkEventConfigure 
*WXUNUSED(event
), wxDropSource 
*source 
) 
 710         wxapp_install_idle_handler(); 
 712     source
->GiveFeedback( ConvertFromGTK(source
->m_dragContext
->action
) ); 
 718 //--------------------------------------------------------------------------- 
 720 //--------------------------------------------------------------------------- 
 722 wxDropSource::wxDropSource(wxWindow 
*win
, 
 723                            const wxIcon 
&iconCopy
, 
 724                            const wxIcon 
&iconMove
, 
 725                            const wxIcon 
&iconNone
) 
 729     m_iconWindow 
= (GtkWidget
*) NULL
; 
 732     m_widget 
= win
->m_widget
; 
 733     if (win
->m_wxwindow
) m_widget 
= win
->m_wxwindow
; 
 735     m_retValue 
= wxDragCancel
; 
 737     SetIcons(iconCopy
, iconMove
, iconNone
); 
 740 wxDropSource::wxDropSource(wxDataObject
& data
, 
 742                            const wxIcon 
&iconCopy
, 
 743                            const wxIcon 
&iconMove
, 
 744                            const wxIcon 
&iconNone
) 
 750     m_iconWindow 
= (GtkWidget
*) NULL
; 
 753     m_widget 
= win
->m_widget
; 
 754     if (win
->m_wxwindow
) m_widget 
= win
->m_wxwindow
; 
 756     m_retValue 
= wxDragCancel
; 
 758     SetIcons(iconCopy
, iconMove
, iconNone
); 
 761 void wxDropSource::SetIcons(const wxIcon 
&iconCopy
, 
 762                             const wxIcon 
&iconMove
, 
 763                             const wxIcon 
&iconNone
) 
 765     m_iconCopy 
= iconCopy
; 
 766     m_iconMove 
= iconMove
; 
 767     m_iconNone 
= iconNone
; 
 769     if ( !m_iconCopy
.Ok() ) 
 770         m_iconCopy 
= wxIcon(page_xpm
); 
 771     if ( !m_iconMove
.Ok() ) 
 772         m_iconMove 
= m_iconCopy
; 
 773     if ( !m_iconNone
.Ok() ) 
 774         m_iconNone 
= m_iconCopy
; 
 777 wxDropSource::~wxDropSource() 
 781 void wxDropSource::PrepareIcon( int action
, GdkDragContext 
*context 
) 
 783     // get the right icon to display 
 785     if ( action 
& GDK_ACTION_MOVE 
) 
 787     else if ( action 
& GDK_ACTION_COPY 
) 
 793     if ( icon
->GetMask() ) 
 794         mask 
= icon
->GetMask()->GetBitmap(); 
 796         mask 
= (GdkBitmap 
*)NULL
; 
 798     GdkPixmap 
*pixmap 
= icon
->GetPixmap(); 
 801     gdk_drawable_get_size (pixmap
, &width
, &height
); 
 803     GdkColormap 
*colormap 
= gtk_widget_get_colormap( m_widget 
); 
 804     gtk_widget_push_colormap (colormap
); 
 806     m_iconWindow 
= gtk_window_new (GTK_WINDOW_POPUP
); 
 807     gtk_widget_set_events (m_iconWindow
, GDK_BUTTON_PRESS_MASK 
| GDK_BUTTON_RELEASE_MASK
); 
 808     gtk_widget_set_app_paintable (GTK_WIDGET (m_iconWindow
), TRUE
); 
 810     gtk_widget_pop_colormap (); 
 812     gtk_widget_set_size_request (m_iconWindow
, width
, height
); 
 813     gtk_widget_realize (m_iconWindow
); 
 815     g_signal_connect (m_iconWindow
, "configure_event", 
 816                       G_CALLBACK (gtk_dnd_window_configure_callback
), this); 
 818     gdk_window_set_back_pixmap (m_iconWindow
->window
, pixmap
, FALSE
); 
 821         gtk_widget_shape_combine_mask (m_iconWindow
, mask
, 0, 0); 
 823     gtk_drag_set_icon_widget( context
, m_iconWindow
, 0, 0 ); 
 826 wxDragResult 
wxDropSource::DoDragDrop(int flags
) 
 828     wxCHECK_MSG( m_data 
&& m_data
->GetFormatCount(), wxDragNone
, 
 829                  wxT("Drop source: no data") ); 
 832     if (g_blockEventsOnDrag
) 
 836     g_blockEventsOnDrag 
= true; 
 842     GtkTargetList 
*target_list 
= gtk_target_list_new( (GtkTargetEntry
*) NULL
, 0 ); 
 844     wxDataFormat 
*array 
= new wxDataFormat
[ m_data
->GetFormatCount() ]; 
 845     m_data
->GetAllFormats( array 
); 
 846     size_t count 
= m_data
->GetFormatCount(); 
 847     for (size_t i 
= 0; i 
< count
; i
++) 
 849         GdkAtom atom 
= array
[i
]; 
 850         wxLogTrace(TRACE_DND
, wxT("Drop source: Supported atom %s"), gdk_atom_name( atom 
)); 
 851         gtk_target_list_add( target_list
, atom
, 0, 0 ); 
 855     GdkEventMotion event
; 
 856     event
.window 
= m_widget
->window
; 
 859     GdkModifierType state
; 
 860     gdk_window_get_pointer( event
.window
, &x
, &y
, &state 
); 
 864     event
.time 
= (guint32
)GDK_CURRENT_TIME
; 
 866     /* GTK wants to know which button was pressed which caused the dragging */ 
 867     int button_number 
= 0; 
 868     if (event
.state 
& GDK_BUTTON1_MASK
) button_number 
= 1; 
 869     else if (event
.state 
& GDK_BUTTON2_MASK
) button_number 
= 2; 
 870     else if (event
.state 
& GDK_BUTTON3_MASK
) button_number 
= 3; 
 873     /* disable GUI threads */ 
 876     /* don't start dragging if no button is down */ 
 879         int action 
= GDK_ACTION_COPY
; 
 880         if ( flags 
& wxDrag_AllowMove 
) 
 881             action 
|= GDK_ACTION_MOVE
; 
 883         // VZ: as we already use g_blockEventsOnDrag it shouldn't be that bad 
 884         //     to use a global to pass the flags to the drop target but I'd 
 885         //     surely prefer a better way to do it 
 886         gs_flagsForDrag 
= flags
; 
 888         GdkDragContext 
*context 
= gtk_drag_begin( m_widget
, 
 890                 (GdkDragAction
)action
, 
 891                 button_number
,  /* number of mouse button which started drag */ 
 892                 (GdkEvent
*) &event 
); 
 894         m_dragContext 
= context
; 
 896         PrepareIcon( action
, context 
); 
 899             gtk_main_iteration(); 
 901         m_retValue 
= ConvertFromGTK(context
->action
); 
 902         if ( m_retValue 
== wxDragNone 
) 
 903             m_retValue 
= wxDragCancel
; 
 907     /* re-enable GUI threads */ 
 910     g_blockEventsOnDrag 
= false; 
 917 void wxDropSource::RegisterWindow() 
 919     if (!m_widget
) return; 
 921     g_signal_connect (m_widget
, "drag_data_get", 
 922                       G_CALLBACK (source_drag_data_get
), this); 
 923     g_signal_connect (m_widget
, "drag_data_delete", 
 924                       G_CALLBACK (source_drag_data_delete
), this); 
 925     g_signal_connect (m_widget
, "drag_begin", 
 926                       G_CALLBACK (source_drag_begin
), this); 
 927     g_signal_connect (m_widget
, "drag_end", 
 928                       G_CALLBACK (source_drag_end
), this); 
 932 void wxDropSource::UnregisterWindow() 
 937     g_signal_handlers_disconnect_by_func (m_widget
, 
 938                                           (gpointer
) source_drag_data_get
, 
 940     g_signal_handlers_disconnect_by_func (m_widget
, 
 941                                           (gpointer
) source_drag_data_delete
, 
 943     g_signal_handlers_disconnect_by_func (m_widget
, 
 944                                           (gpointer
) source_drag_begin
, 
 946     g_signal_handlers_disconnect_by_func (m_widget
, 
 947                                           (gpointer
) source_drag_end
, 
 952       // wxUSE_DRAG_AND_DROP