1 /////////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     wxDropTarget class 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) 1998 Robert Roebling 
   7 // Licence:     wxWindows licence 
   8 /////////////////////////////////////////////////////////////////////////////// 
  11     #pragma implementation "dnd.h" 
  16 #if wxUSE_DRAG_AND_DROP 
  18 #include "wx/window.h" 
  20 #include "wx/gdicmn.h" 
  26 #include <gdk/gdkprivate.h> 
  28 #include <gtk/gtkdnd.h> 
  29 #include <gtk/gtkselection.h> 
  31 //----------------------------------------------------------------------------- 
  33 //----------------------------------------------------------------------------- 
  35 extern void wxapp_install_idle_handler(); 
  38 //----------------------------------------------------------------------------- 
  40 //----------------------------------------------------------------------------- 
  43 extern void wxapp_install_thread_wakeup(); 
  44 extern void wxapp_uninstall_thread_wakeup(); 
  47 //---------------------------------------------------------------------------- 
  49 //---------------------------------------------------------------------------- 
  51 extern bool g_blockEventsOnDrag
; 
  53 // the trace mask we use with wxLogTrace() - call 
  54 // wxLog::AddTraceMask(TRACE_DND) to enable the trace messages from here 
  55 // (there are quite a few of them, so don't enable this by default) 
  56 static const wxChar 
*TRACE_DND 
= _T("dnd"); 
  58 //---------------------------------------------------------------------------- 
  60 //---------------------------------------------------------------------------- 
  63 static char * page_xpm
[] = { 
  64 /* width height ncolors chars_per_pixel */ 
  73 "    ...................         ", 
  74 "    .XXXXXXXXXXXXXXXXX..        ", 
  75 "    .XXXXXXXXXXXXXXXXX.o.       ", 
  76 "    .XXXXXXXXXXXXXXXXX.oo.      ", 
  77 "    .XXXXXXXXXXXXXXXXX.ooo.     ", 
  78 "    .XXXXXXXXXXXXXXXXX.oooo.    ", 
  79 "    .XXXXXXXXXXXXXXXXX.......   ", 
  80 "    .XXXXXOOOOOOOOOOXXXooooo.   ", 
  81 "    .XXXXXXXXXXXXXXXXXXooooo.   ", 
  82 "    .XXXXXOOOOOOOOOOXXXXXXXX.   ", 
  83 "    .XXXXXXXXXXXXXXXXXXXXXXX.   ", 
  84 "    .XXXXXXXOOOOOOOOOXXXXXXX.   ", 
  85 "    .XXXXXXXXXXXXXXXXXXXXXXX.   ", 
  86 "    .XXXXXXOOOOOOOOOOXXXXXXX.   ", 
  87 "    .XXXXXXXXXXXXXXXXXXXXXXX.   ", 
  88 "    .XXXXXOOOOOOOOOOXXXXXXXX.   ", 
  89 "    .XXXXXXXXXXXXXXXXXXXXXXX.   ", 
  90 "    .XXXXXXXOOOOOOOOOXXXXXXX.   ", 
  91 "    .XXXXXXXXXXXXXXXXXXXXXXX.   ", 
  92 "    .XXXXXXOOOOOOOOOOXXXXXXX.   ", 
  93 "    .XXXXXXXXXXXXXXXXXXXXXXX.   ", 
  94 "    .XXXXXOOOOOOOOOOXXXXXXXX.   ", 
  95 "    .XXXXXXXXXXXXXXXXXXXXXXX.   ", 
  96 "    .XXXXXXOOOOOOOOOOXXXXXXX.   ", 
  97 "    .XXXXXXXXXXXXXXXXXXXXXXX.   ", 
  98 "    .XXXXXOOOOOOOXXXXXXXXXXX.   ", 
  99 "    .XXXXXXXXXXXXXXXXXXXXXXX.   ", 
 100 "    .XXXXXXXXXXXXXXXXXXXXXXX.   ", 
 101 "    .XXXXXXXXXXXXXXXXXXXXXXX.   ", 
 102 "    .XXXXXXXXXXXXXXXXXXXXXXX.   ", 
 103 "    .XXXXXXXXXXXXXXXXXXXXXXX.   ", 
 104 "    .........................   "}; 
 108 // ---------------------------------------------------------------------------- 
 110 // ---------------------------------------------------------------------------- 
 112 static void target_drag_leave( GtkWidget 
*WXUNUSED(widget
), 
 113                                GdkDragContext 
*context
, 
 114                                guint 
WXUNUSED(time
), 
 115                                wxDropTarget 
*drop_target 
) 
 117     if (g_isIdle
) wxapp_install_idle_handler(); 
 119     /* inform the wxDropTarget about the current GdkDragContext. 
 120        this is only valid for the duration of this call */ 
 121     drop_target
->SetDragContext( context 
); 
 123     /* we don't need return values. this event is just for 
 125     drop_target
->OnLeave(); 
 127     /* this has to be done because GDK has no "drag_enter" event */ 
 128     drop_target
->m_firstMotion 
= TRUE
; 
 130     /* after this, invalidate the drop_target's GdkDragContext */ 
 131     drop_target
->SetDragContext( (GdkDragContext
*) NULL 
); 
 134 // ---------------------------------------------------------------------------- 
 136 // ---------------------------------------------------------------------------- 
 138 static gboolean 
target_drag_motion( GtkWidget 
*WXUNUSED(widget
), 
 139                                     GdkDragContext 
*context
, 
 143                                     wxDropTarget 
*drop_target 
) 
 145     if (g_isIdle
) wxapp_install_idle_handler(); 
 147     /* Owen Taylor: "if the coordinates not in a drop zone, 
 148        return FALSE, otherwise call gtk_drag_status() and 
 151     /* inform the wxDropTarget about the current GdkDragContext. 
 152        this is only valid for the duration of this call */ 
 153     drop_target
->SetDragContext( context 
); 
 156     if ( context
->suggested_action 
== GDK_ACTION_COPY 
) 
 161     if (drop_target
->m_firstMotion
) 
 163         /* the first "drag_motion" event substitutes a "drag_enter" event */ 
 164         result 
= drop_target
->OnEnter( x
, y
, result 
); 
 168         /* give program a chance to react (i.e. to say no by returning FALSE) */ 
 169         result 
= drop_target
->OnDragOver( x
, y
, result 
); 
 172     bool ret 
= wxIsDragResultOk( result 
); 
 175         GdkDragAction action
; 
 176         if (result 
== wxDragCopy
) 
 177             action 
= GDK_ACTION_COPY
; 
 179             action 
= GDK_ACTION_MOVE
; 
 181         gdk_drag_status( context
, action
, time 
); 
 184     /* after this, invalidate the drop_target's GdkDragContext */ 
 185     drop_target
->SetDragContext( (GdkDragContext
*) NULL 
); 
 187     /* this has to be done because GDK has no "drag_enter" event */ 
 188     drop_target
->m_firstMotion 
= FALSE
; 
 193 // ---------------------------------------------------------------------------- 
 195 // ---------------------------------------------------------------------------- 
 197 static gboolean 
target_drag_drop( GtkWidget 
*widget
, 
 198                                   GdkDragContext 
*context
, 
 202                                   wxDropTarget 
*drop_target 
) 
 204     if (g_isIdle
) wxapp_install_idle_handler(); 
 206     /* Owen Taylor: "if the drop is not in a drop zone, 
 207        return FALSE, otherwise, if you aren't accepting 
 208        the drop, call gtk_drag_finish() with success == FALSE 
 209        otherwise call gtk_drag_data_get()" */ 
 211 //    printf( "drop.\n" ); 
 213     /* this seems to make a difference between not accepting 
 214        due to wrong target area and due to wrong format. let 
 215        us hope that this is not required.. */ 
 217     /* inform the wxDropTarget about the current GdkDragContext. 
 218        this is only valid for the duration of this call */ 
 219     drop_target
->SetDragContext( context 
); 
 221     /* inform the wxDropTarget about the current drag widget. 
 222        this is only valid for the duration of this call */ 
 223     drop_target
->SetDragWidget( widget 
); 
 225     /* inform the wxDropTarget about the current drag time. 
 226        this is only valid for the duration of this call */ 
 227     drop_target
->SetDragTime( time 
); 
 230     wxDragResult result = wxDragMove; 
 231     if (context->suggested_action == GDK_ACTION_COPY) result = wxDragCopy; 
 234     /* reset the block here as someone might very well 
 235        show a dialog as a reaction to a drop and this 
 236        wouldn't work without events */ 
 237     g_blockEventsOnDrag 
= FALSE
; 
 239     bool ret 
= drop_target
->OnDrop( x
, y 
); 
 243         wxLogTrace(TRACE_DND
, wxT( "Drop target: OnDrop returned FALSE") ); 
 245         /* cancel the whole thing */ 
 246         gtk_drag_finish( context
, 
 247                           FALSE
,        /* no success */ 
 248                           FALSE
,        /* don't delete data on dropping side */ 
 253         wxLogTrace(TRACE_DND
, wxT( "Drop target: OnDrop returned TRUE") ); 
 256         /* disable GUI threads */ 
 257         wxapp_uninstall_thread_wakeup(); 
 260         GdkAtom format 
= drop_target
->GetMatchingPair(); 
 264         GdkDragAction action = GDK_ACTION_MOVE; 
 265         if (result == wxDragCopy) action == GDK_ACTION_COPY; 
 266         context->action = action; 
 268         /* this should trigger an "drag_data_received" event */ 
 269         gtk_drag_get_data( widget
, 
 275         /* re-enable GUI threads */ 
 276         wxapp_install_thread_wakeup(); 
 280     /* after this, invalidate the drop_target's GdkDragContext */ 
 281     drop_target
->SetDragContext( (GdkDragContext
*) NULL 
); 
 283     /* after this, invalidate the drop_target's drag widget */ 
 284     drop_target
->SetDragWidget( (GtkWidget
*) NULL 
); 
 286     /* this has to be done because GDK has no "drag_enter" event */ 
 287     drop_target
->m_firstMotion 
= TRUE
; 
 292 // ---------------------------------------------------------------------------- 
 293 // "drag_data_received" 
 294 // ---------------------------------------------------------------------------- 
 296 static void target_drag_data_received( GtkWidget 
*WXUNUSED(widget
), 
 297                                        GdkDragContext 
*context
, 
 300                                        GtkSelectionData 
*data
, 
 301                                        guint 
WXUNUSED(info
), 
 303                                        wxDropTarget 
*drop_target 
) 
 305     if (g_isIdle
) wxapp_install_idle_handler(); 
 307     /* Owen Taylor: "call gtk_drag_finish() with 
 310     if ((data
->length 
<= 0) || (data
->format 
!= 8)) 
 312         /* negative data length and non 8-bit data format 
 313            qualifies for junk */ 
 314         gtk_drag_finish (context
, FALSE
, FALSE
, time
); 
 319     wxLogTrace(TRACE_DND
, wxT( "Drop target: data received event") ); 
 321     /* inform the wxDropTarget about the current GtkSelectionData. 
 322        this is only valid for the duration of this call */ 
 323     drop_target
->SetDragData( data 
); 
 326     if ( context
->suggested_action 
== GDK_ACTION_COPY 
) 
 331     if ( wxIsDragResultOk( drop_target
->OnData( x
, y
, result 
) ) ) 
 333         wxLogTrace(TRACE_DND
, wxT( "Drop target: OnData returned TRUE") ); 
 335         /* tell GTK that data transfer was successfull */ 
 336         gtk_drag_finish( context
, TRUE
, FALSE
, time 
); 
 340         wxLogTrace(TRACE_DND
, wxT( "Drop target: OnData returned FALSE") ); 
 342         /* tell GTK that data transfer was not successfull */ 
 343         gtk_drag_finish( context
, FALSE
, FALSE
, time 
); 
 346     /* after this, invalidate the drop_target's drag data */ 
 347     drop_target
->SetDragData( (GtkSelectionData
*) NULL 
); 
 350 //---------------------------------------------------------------------------- 
 352 //---------------------------------------------------------------------------- 
 354 wxDropTarget::wxDropTarget( wxDataObject 
*data 
) 
 355             : wxDropTargetBase( data 
) 
 357     m_firstMotion 
= TRUE
; 
 358     m_dragContext 
= (GdkDragContext
*) NULL
; 
 359     m_dragWidget 
= (GtkWidget
*) NULL
; 
 360     m_dragData 
= (GtkSelectionData
*) NULL
; 
 364 wxDragResult 
wxDropTarget::OnDragOver( wxCoord 
WXUNUSED(x
), 
 368     // GetMatchingPair() checks for m_dataObject too, no need to do it here 
 370     // disable the debug message from GetMatchingPair() - there are too many 
 376     return (GetMatchingPair() != (GdkAtom
) 0) ? def 
: wxDragNone
; 
 379 bool wxDropTarget::OnDrop( wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
) ) 
 384     return (GetMatchingPair() != (GdkAtom
) 0); 
 387 wxDragResult 
wxDropTarget::OnData( wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
), 
 393     if (GetMatchingPair() == (GdkAtom
) 0) 
 396     return GetData() ? def 
: wxDragNone
; 
 399 GdkAtom 
wxDropTarget::GetMatchingPair() 
 407     GList 
*child 
= m_dragContext
->targets
; 
 410         GdkAtom formatAtom 
= (GdkAtom
) GPOINTER_TO_INT(child
->data
); 
 411         wxDataFormat 
format( formatAtom 
); 
 414         wxLogTrace(TRACE_DND
, wxT("Drop target: drag has format: %s"), 
 415                    format
.GetId().c_str()); 
 418         if (m_dataObject
->IsSupportedFormat( format 
)) 
 427 bool wxDropTarget::GetData() 
 435     wxDataFormat 
dragFormat( m_dragData
->target 
); 
 437     if (!m_dataObject
->IsSupportedFormat( dragFormat 
)) 
 440     m_dataObject
->SetData( dragFormat
, (size_t)m_dragData
->length
, (const void*)m_dragData
->data 
); 
 445 void wxDropTarget::UnregisterWidget( GtkWidget 
*widget 
) 
 447     wxCHECK_RET( widget 
!= NULL
, wxT("unregister widget is NULL") ); 
 449     gtk_drag_dest_unset( widget 
); 
 451     gtk_signal_disconnect_by_func( GTK_OBJECT(widget
), 
 452                       GTK_SIGNAL_FUNC(target_drag_leave
), (gpointer
) this ); 
 454     gtk_signal_disconnect_by_func( GTK_OBJECT(widget
), 
 455                       GTK_SIGNAL_FUNC(target_drag_motion
), (gpointer
) this ); 
 457     gtk_signal_disconnect_by_func( GTK_OBJECT(widget
), 
 458                       GTK_SIGNAL_FUNC(target_drag_drop
), (gpointer
) this ); 
 460     gtk_signal_disconnect_by_func( GTK_OBJECT(widget
), 
 461                       GTK_SIGNAL_FUNC(target_drag_data_received
), (gpointer
) this ); 
 464 void wxDropTarget::RegisterWidget( GtkWidget 
*widget 
) 
 466     wxCHECK_RET( widget 
!= NULL
, wxT("register widget is NULL") ); 
 468     /* gtk_drag_dest_set() determines what default behaviour we'd like 
 469        GTK to supply. we don't want to specify out targets (=formats) 
 470        or actions in advance (i.e. not GTK_DEST_DEFAULT_MOTION and 
 471        not GTK_DEST_DEFAULT_DROP). instead we react individually to 
 472        "drag_motion" and "drag_drop" events. this makes it possible 
 473        to allow dropping on only a small area. we should set 
 474        GTK_DEST_DEFAULT_HIGHLIGHT as this will switch on the nice 
 475        highlighting if dragging over standard controls, but this 
 476        seems to be broken without the other two. */ 
 478     gtk_drag_dest_set( widget
, 
 479                        (GtkDestDefaults
) 0,         /* no default behaviour */ 
 480                        (GtkTargetEntry
*) NULL
,      /* we don't supply any formats here */ 
 481                        0,                           /* number of targets = 0 */ 
 482                        (GdkDragAction
) 0 );         /* we don't supply any actions here */ 
 484     gtk_signal_connect( GTK_OBJECT(widget
), "drag_leave", 
 485                       GTK_SIGNAL_FUNC(target_drag_leave
), (gpointer
) this ); 
 487     gtk_signal_connect( GTK_OBJECT(widget
), "drag_motion", 
 488                       GTK_SIGNAL_FUNC(target_drag_motion
), (gpointer
) this ); 
 490     gtk_signal_connect( GTK_OBJECT(widget
), "drag_drop", 
 491                       GTK_SIGNAL_FUNC(target_drag_drop
), (gpointer
) this ); 
 493     gtk_signal_connect( GTK_OBJECT(widget
), "drag_data_received", 
 494                       GTK_SIGNAL_FUNC(target_drag_data_received
), (gpointer
) this ); 
 497 //---------------------------------------------------------------------------- 
 499 //---------------------------------------------------------------------------- 
 502 source_drag_data_get  (GtkWidget          
*WXUNUSED(widget
), 
 503                        GdkDragContext     
*WXUNUSED(context
), 
 504                        GtkSelectionData   
*selection_data
, 
 505                        guint               
WXUNUSED(info
), 
 506                        guint               
WXUNUSED(time
), 
 507                        wxDropSource       
*drop_source 
) 
 509     if (g_isIdle
) wxapp_install_idle_handler(); 
 511     wxDataFormat 
format( selection_data
->target 
); 
 513     wxLogTrace(TRACE_DND
, wxT("Drop source: format requested: %s"), 
 514                format
.GetId().c_str()); 
 516     drop_source
->m_retValue 
= wxDragCancel
; 
 518     wxDataObject 
*data 
= drop_source
->GetDataObject(); 
 522         wxLogTrace(TRACE_DND
, wxT("Drop source: no data object") ); 
 526     if (!data
->IsSupportedFormat(format
)) 
 528         wxLogTrace(TRACE_DND
, wxT("Drop source: unsupported format") ); 
 532     if (data
->GetDataSize(format
) == 0) 
 534         wxLogTrace(TRACE_DND
, wxT("Drop source: empty data") ); 
 538     size_t size 
= data
->GetDataSize(format
); 
 540 //  printf( "data size: %d.\n", (int)data_size ); 
 542     guchar 
*d 
= new guchar
[size
]; 
 544     if (!data
->GetDataHere( format
, (void*)d 
)) 
 551     /* disable GUI threads */ 
 552     wxapp_uninstall_thread_wakeup(); 
 555                 gtk_selection_data_set( selection_data
, 
 556                                         selection_data
->target
, 
 562     /* enable GUI threads */ 
 563     wxapp_install_thread_wakeup(); 
 569 //---------------------------------------------------------------------------- 
 570 // "drag_data_delete" 
 571 //---------------------------------------------------------------------------- 
 573 static void source_drag_data_delete( GtkWidget 
*WXUNUSED(widget
), 
 574                                      GdkDragContext 
*context
, 
 575                                      wxDropSource 
*WXUNUSED(drop_source
) ) 
 578         wxapp_install_idle_handler(); 
 580     // printf( "Drag source: drag_data_delete\n" ); 
 583 //---------------------------------------------------------------------------- 
 585 //---------------------------------------------------------------------------- 
 587 static void source_drag_begin( GtkWidget          
*WXUNUSED(widget
), 
 588                                GdkDragContext     
*WXUNUSED(context
), 
 589                                wxDropSource       
*WXUNUSED(drop_source
) ) 
 592         wxapp_install_idle_handler(); 
 594     // printf( "Drag source: drag_begin.\n" ); 
 597 //---------------------------------------------------------------------------- 
 599 //---------------------------------------------------------------------------- 
 601 static void source_drag_end( GtkWidget          
*WXUNUSED(widget
), 
 602                              GdkDragContext     
*WXUNUSED(context
), 
 603                              wxDropSource       
*drop_source 
) 
 605     if (g_isIdle
) wxapp_install_idle_handler(); 
 607     // printf( "Drag source: drag_end.\n" ); 
 609     drop_source
->m_waiting 
= FALSE
; 
 612 //----------------------------------------------------------------------------- 
 613 // "configure_event" from m_iconWindow 
 614 //----------------------------------------------------------------------------- 
 617 gtk_dnd_window_configure_callback( GtkWidget 
*WXUNUSED(widget
), GdkEventConfigure 
*WXUNUSED(event
), wxDropSource 
*source 
) 
 620         wxapp_install_idle_handler(); 
 622     wxDragResult action 
= wxDragNone
; 
 623     if (source
->m_dragContext
->action 
== GDK_ACTION_COPY
) action 
= wxDragCopy
; 
 624     if (source
->m_dragContext
->action 
== GDK_ACTION_MOVE
) action 
= wxDragMove
; 
 626     source
->GiveFeedback( action 
); 
 631 //--------------------------------------------------------------------------- 
 633 //--------------------------------------------------------------------------- 
 635 wxDropSource::wxDropSource(wxWindow 
*win
, 
 636                            const wxIcon 
&iconCopy
, 
 637                            const wxIcon 
&iconMove
, 
 638                            const wxIcon 
&iconNone
) 
 642     m_iconWindow 
= (GtkWidget
*) NULL
; 
 645     m_widget 
= win
->m_widget
; 
 646     if (win
->m_wxwindow
) m_widget 
= win
->m_wxwindow
; 
 648     m_retValue 
= wxDragCancel
; 
 650     SetIcons(iconCopy
, iconMove
, iconNone
); 
 653 wxDropSource::wxDropSource(wxDataObject
& data
, 
 655                            const wxIcon 
&iconCopy
, 
 656                            const wxIcon 
&iconMove
, 
 657                            const wxIcon 
&iconNone
) 
 663     m_iconWindow 
= (GtkWidget
*) NULL
; 
 666     m_widget 
= win
->m_widget
; 
 667     if (win
->m_wxwindow
) m_widget 
= win
->m_wxwindow
; 
 669     m_retValue 
= wxDragCancel
; 
 671     SetIcons(iconCopy
, iconMove
, iconNone
); 
 674 void wxDropSource::SetIcons(const wxIcon 
&iconCopy
, 
 675                             const wxIcon 
&iconMove
, 
 676                             const wxIcon 
&iconNone
) 
 678     m_iconCopy 
= iconCopy
; 
 679     m_iconMove 
= iconMove
; 
 680     m_iconNone 
= iconNone
; 
 682     if ( !m_iconCopy
.Ok() ) 
 683         m_iconCopy 
= wxIcon(page_xpm
); 
 684     if ( !m_iconMove
.Ok() ) 
 685         m_iconMove 
= m_iconCopy
; 
 686     if ( !m_iconNone
.Ok() ) 
 687         m_iconNone 
= m_iconCopy
; 
 690 wxDropSource::~wxDropSource() 
 694 void wxDropSource::PrepareIcon( int action
, GdkDragContext 
*context 
) 
 696     // get the right icon to display 
 698     if ( action 
& GDK_ACTION_MOVE 
) 
 700     else if ( action 
& GDK_ACTION_COPY 
) 
 706     if ( icon
->GetMask() ) 
 707         mask 
= icon
->GetMask()->GetBitmap(); 
 709         mask 
= (GdkBitmap 
*)NULL
; 
 711     GdkPixmap 
*pixmap 
= icon
->GetPixmap(); 
 714     gdk_window_get_size (pixmap
, &width
, &height
); 
 716     GdkColormap 
*colormap 
= gtk_widget_get_colormap( m_widget 
); 
 718     gtk_widget_push_visual (gdk_colormap_get_visual (colormap
)); 
 720     gtk_widget_push_colormap (colormap
); 
 722     m_iconWindow 
= gtk_window_new (GTK_WINDOW_POPUP
); 
 723     gtk_widget_set_events (m_iconWindow
, GDK_BUTTON_PRESS_MASK 
| GDK_BUTTON_RELEASE_MASK
); 
 724     gtk_widget_set_app_paintable (GTK_WIDGET (m_iconWindow
), TRUE
); 
 727     gtk_widget_pop_visual (); 
 729     gtk_widget_pop_colormap (); 
 731     gtk_widget_set_usize (m_iconWindow
, width
, height
); 
 732     gtk_widget_realize (m_iconWindow
); 
 734     gtk_signal_connect( GTK_OBJECT(m_iconWindow
), "configure_event", 
 735         GTK_SIGNAL_FUNC(gtk_dnd_window_configure_callback
), (gpointer
)this ); 
 737     gdk_window_set_back_pixmap (m_iconWindow
->window
, pixmap
, FALSE
); 
 740         gtk_widget_shape_combine_mask (m_iconWindow
, mask
, 0, 0); 
 742     gtk_drag_set_icon_widget( context
, m_iconWindow
, 0, 0 ); 
 745 wxDragResult 
wxDropSource::DoDragDrop( bool allowMove 
) 
 747     wxASSERT_MSG( m_data
, wxT("Drop source: no data") ); 
 750         return (wxDragResult
) wxDragNone
; 
 752     if (m_data
->GetFormatCount() == 0) 
 753         return (wxDragResult
) wxDragNone
; 
 756     if (g_blockEventsOnDrag
) 
 757         return (wxDragResult
) wxDragNone
; 
 760     g_blockEventsOnDrag 
= TRUE
; 
 766     GtkTargetList 
*target_list 
= gtk_target_list_new( (GtkTargetEntry
*) NULL
, 0 ); 
 768     wxDataFormat 
*array 
= new wxDataFormat
[ m_data
->GetFormatCount() ]; 
 769     m_data
->GetAllFormats( array 
); 
 770     for (size_t i 
= 0; i 
< m_data
->GetFormatCount(); i
++) 
 772         GdkAtom atom 
= array
[i
]; 
 773         wxLogTrace(TRACE_DND
, wxT("Drop source: Supported atom %s"), gdk_atom_name( atom 
)); 
 774         gtk_target_list_add( target_list
, atom
, 0, 0 ); 
 778     GdkEventMotion event
; 
 779     event
.window 
= m_widget
->window
; 
 782     GdkModifierType state
; 
 783     gdk_window_get_pointer( event
.window
, &x
, &y
, &state 
); 
 787     event
.time 
= (guint32
)GDK_CURRENT_TIME
; 
 789     /* GTK wants to know which button was pressed which caused the dragging */ 
 790     int button_number 
= 0; 
 791     if (event
.state 
& GDK_BUTTON1_MASK
) button_number 
= 1; 
 792     else if (event
.state 
& GDK_BUTTON2_MASK
) button_number 
= 2; 
 793     else if (event
.state 
& GDK_BUTTON3_MASK
) button_number 
= 3; 
 796     /* disable GUI threads */ 
 797     wxapp_uninstall_thread_wakeup(); 
 800     /* don't start dragging if no button is down */ 
 803         int action 
= GDK_ACTION_COPY
; 
 805             action 
|= GDK_ACTION_MOVE
; 
 806         GdkDragContext 
*context 
= gtk_drag_begin( m_widget
, 
 808                 (GdkDragAction
)action
, 
 809                 button_number
,  /* number of mouse button which started drag */ 
 810                 (GdkEvent
*) &event 
); 
 812         m_dragContext 
= context
; 
 814         PrepareIcon( action
, context 
); 
 816         while (m_waiting
) gtk_main_iteration(); 
 818         if (context
->action 
== GDK_ACTION_COPY
) 
 819             m_retValue 
= wxDragCopy
; 
 820         if (context
->action 
== GDK_ACTION_MOVE
) 
 821             m_retValue 
= wxDragMove
; 
 825     /* re-enable GUI threads */ 
 826     wxapp_install_thread_wakeup(); 
 829     g_blockEventsOnDrag 
= FALSE
; 
 836 void wxDropSource::RegisterWindow() 
 838     if (!m_widget
) return; 
 840     gtk_signal_connect( GTK_OBJECT(m_widget
), "drag_data_get", 
 841                       GTK_SIGNAL_FUNC (source_drag_data_get
), (gpointer
) this); 
 842     gtk_signal_connect (GTK_OBJECT(m_widget
), "drag_data_delete", 
 843                       GTK_SIGNAL_FUNC (source_drag_data_delete
),  (gpointer
) this ); 
 844     gtk_signal_connect (GTK_OBJECT(m_widget
), "drag_begin", 
 845                       GTK_SIGNAL_FUNC (source_drag_begin
),  (gpointer
) this ); 
 846     gtk_signal_connect (GTK_OBJECT(m_widget
), "drag_end", 
 847                       GTK_SIGNAL_FUNC (source_drag_end
),  (gpointer
) this ); 
 851 void wxDropSource::UnregisterWindow() 
 853     if (!m_widget
) return; 
 855     gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget
), 
 856                       GTK_SIGNAL_FUNC(source_drag_data_get
), (gpointer
) this ); 
 857     gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget
), 
 858                       GTK_SIGNAL_FUNC(source_drag_data_delete
), (gpointer
) this ); 
 859     gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget
), 
 860                       GTK_SIGNAL_FUNC(source_drag_begin
), (gpointer
) this ); 
 861     gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget
), 
 862                       GTK_SIGNAL_FUNC(source_drag_end
), (gpointer
) this ); 
 866       // wxUSE_DRAG_AND_DROP