1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/mac/carbon/dnd.cpp 
   3 // Purpose:     wxDropTarget, wxDropSource implementations 
   4 // Author:      Stefan Csomor 
   8 // Copyright:   (c) 1998 Stefan Csomor 
   9 // Licence:     wxWindows licence 
  10 /////////////////////////////////////////////////////////////////////////////// 
  12 #include "wx/wxprec.h" 
  14 #if wxUSE_DRAG_AND_DROP 
  20     #include "wx/toplevel.h" 
  21     #include "wx/gdicmn.h" 
  24 #include "wx/mac/private.h" 
  26 // ---------------------------------------------------------------------------- 
  28 // ---------------------------------------------------------------------------- 
  32     wxWindow 
*m_currentTargetWindow
; 
  33     wxDropTarget 
*m_currentTarget
; 
  34     wxDropSource 
*m_currentSource
; 
  35     wxDragResult m_result
; 
  39 MacTrackingGlobals gTrackingGlobals
; 
  41 void wxMacEnsureTrackingHandlersInstalled(); 
  43 //---------------------------------------------------------------------------- 
  45 //---------------------------------------------------------------------------- 
  47 wxDropTarget::wxDropTarget( wxDataObject 
*data 
) 
  48             : wxDropTargetBase( data 
) 
  50     wxMacEnsureTrackingHandlersInstalled(); 
  53 wxDragResult 
wxDropTarget::OnDragOver( 
  54     wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
), 
  57     return CurrentDragHasSupportedFormat() ? def 
: wxDragNone
; 
  60 bool wxDropTarget::OnDrop( wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
) ) 
  62     if (m_dataObject 
== NULL
) 
  65     return CurrentDragHasSupportedFormat(); 
  68 wxDragResult 
wxDropTarget::OnData( 
  69     wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
), 
  72     if (m_dataObject 
== NULL
) 
  75     if (!CurrentDragHasSupportedFormat()) 
  78     return GetData() ? def 
: wxDragNone
; 
  81 bool wxDropTarget::CurrentDragHasSupportedFormat() 
  83     bool supported 
= false; 
  84     if (m_dataObject 
== NULL
) 
  87     if ( gTrackingGlobals
.m_currentSource 
!= NULL 
) 
  89         wxDataObject
* data 
= gTrackingGlobals
.m_currentSource
->GetDataObject(); 
  93             size_t formatcount 
= data
->GetFormatCount(); 
  94             wxDataFormat 
*array 
= new wxDataFormat
[formatcount
]; 
  95             data
->GetAllFormats( array 
); 
  96             for (size_t i 
= 0; !supported 
&& i 
< formatcount
; i
++) 
  98                 wxDataFormat format 
= array
[i
]; 
  99                 if ( m_dataObject
->IsSupported( format 
) ) 
 112         PasteboardRef   pasteboard
; 
 114         if ( GetDragPasteboard( (DragReference
)m_currentDrag
, &pasteboard 
) == noErr 
) 
 116             supported 
= m_dataObject
->HasDataInPasteboard( pasteboard 
); 
 123 bool wxDropTarget::GetData() 
 125     if (m_dataObject 
== NULL
) 
 128     if ( !CurrentDragHasSupportedFormat() ) 
 131     bool transferred 
= false; 
 132     if ( gTrackingGlobals
.m_currentSource 
!= NULL 
) 
 134         wxDataObject
* data 
= gTrackingGlobals
.m_currentSource
->GetDataObject(); 
 138             size_t formatcount 
= data
->GetFormatCount(); 
 139             wxDataFormat 
*array 
= new wxDataFormat
[formatcount
]; 
 140             data
->GetAllFormats( array 
); 
 141             for (size_t i 
= 0; !transferred 
&& i 
< formatcount
; i
++) 
 143                 wxDataFormat format 
= array
[i
]; 
 144                 if ( m_dataObject
->IsSupported( format 
) ) 
 146                     int size 
= data
->GetDataSize( format 
); 
 151                         m_dataObject
->SetData( format
, 0, 0 ); 
 155                         char *d 
= new char[size
]; 
 156                         data
->GetDataHere( format
, (void*)d 
); 
 157                         m_dataObject
->SetData( format
, size
, d 
); 
 169         PasteboardRef   pasteboard
; 
 171         if ( GetDragPasteboard(  (DragReference
)m_currentDrag
, &pasteboard 
) == noErr 
) 
 173             transferred 
= m_dataObject
->GetFromPasteboard( pasteboard 
); 
 180 //------------------------------------------------------------------------- 
 182 //------------------------------------------------------------------------- 
 184 //----------------------------------------------------------------------------- 
 187 wxDropSource::wxDropSource(wxWindow 
*win
, 
 188                            const wxCursor 
&cursorCopy
, 
 189                            const wxCursor 
&cursorMove
, 
 190                            const wxCursor 
&cursorStop
) 
 191             : wxDropSourceBase(cursorCopy
, cursorMove
, cursorStop
) 
 193     wxMacEnsureTrackingHandlersInstalled(); 
 198 wxDropSource::wxDropSource(wxDataObject
& data
, 
 200                            const wxCursor 
&cursorCopy
, 
 201                            const wxCursor 
&cursorMove
, 
 202                            const wxCursor 
&cursorStop
) 
 203             : wxDropSourceBase(cursorCopy
, cursorMove
, cursorStop
) 
 205     wxMacEnsureTrackingHandlersInstalled(); 
 211 wxDropSource::~wxDropSource() 
 215 OSStatus 
wxMacPromiseKeeper(PasteboardRef 
WXUNUSED(inPasteboard
), 
 216                             PasteboardItemID 
WXUNUSED(inItem
), 
 217                             CFStringRef 
WXUNUSED(inFlavorType
), 
 218                             void * WXUNUSED(inContext
)) 
 220     OSStatus  err 
= noErr
; 
 222     // we might add promises here later, inContext is the wxDropSource* 
 227 wxDragResult 
wxDropSource::DoDragDrop(int flags
) 
 229     wxASSERT_MSG( m_data
, wxT("Drop source: no data") ); 
 231     if ((m_data 
== NULL
) || (m_data
->GetFormatCount() == 0)) 
 232         return (wxDragResult
)wxDragNone
; 
 234     DragReference theDrag
; 
 235     RgnHandle dragRegion
; 
 236     OSStatus err 
= noErr
; 
 237     PasteboardRef   pasteboard
; 
 241     err 
= PasteboardCreate( kPasteboardUniqueName
, &pasteboard 
); 
 245     // we add a dummy promise keeper because of strange messages when linking against carbon debug 
 246     err 
= PasteboardSetPromiseKeeper( pasteboard
, wxMacPromiseKeeper
, this ); 
 249         CFRelease( pasteboard 
); 
 253     err 
= PasteboardClear( pasteboard 
); 
 256         CFRelease( pasteboard 
); 
 259     PasteboardSynchronize( pasteboard 
); 
 261     m_data
->AddToPasteboard( pasteboard
, 1 ); 
 263     if (NewDragWithPasteboard( pasteboard 
, &theDrag
) != noErr
) 
 265         CFRelease( pasteboard 
); 
 269     dragRegion 
= NewRgn(); 
 270     RgnHandle tempRgn 
= NewRgn(); 
 273     ConvertEventRefToEventRecord(  (EventRef
) wxTheApp
->MacGetCurrentEvent(), &rec 
); 
 275     const short dragRegionOuterBoundary 
= 10; 
 276     const short dragRegionInnerBoundary 
= 9; 
 280         rec
.where
.h 
- dragRegionOuterBoundary
, 
 281         rec
.where
.v  
- dragRegionOuterBoundary
, 
 282         rec
.where
.h 
+ dragRegionOuterBoundary
, 
 283         rec
.where
.v 
+ dragRegionOuterBoundary 
); 
 287         rec
.where
.h 
- dragRegionInnerBoundary
, 
 288         rec
.where
.v 
- dragRegionInnerBoundary
, 
 289         rec
.where
.h 
+ dragRegionInnerBoundary
, 
 290         rec
.where
.v 
+ dragRegionInnerBoundary 
); 
 292     DiffRgn( dragRegion
, tempRgn
, dragRegion 
); 
 293     DisposeRgn( tempRgn 
); 
 295     // TODO: work with promises in order to return data 
 296     // only when drag was successfully completed 
 298     gTrackingGlobals
.m_currentSource 
= this; 
 299     gTrackingGlobals
.m_result 
= wxDragNone
; 
 300     gTrackingGlobals
.m_flags 
= flags
; 
 302     err 
= TrackDrag( theDrag
, &rec
, dragRegion 
); 
 304     DisposeRgn( dragRegion 
); 
 305     DisposeDrag( theDrag 
); 
 306     CFRelease( pasteboard 
); 
 307     gTrackingGlobals
.m_currentSource 
= NULL
; 
 309     return gTrackingGlobals
.m_result
; 
 312 bool wxDropSource::MacInstallDefaultCursor(wxDragResult effect
) 
 314     const wxCursor
& cursor 
= GetCursor(effect
); 
 315     bool result 
= cursor
.Ok(); 
 323 bool gTrackingGlobalsInstalled 
= false; 
 325 // passing the globals via refcon is not needed by the CFM and later architectures anymore 
 326 // but I'll leave it in there, just in case... 
 328 pascal OSErr 
wxMacWindowDragTrackingHandler( 
 329     DragTrackingMessage theMessage
, WindowPtr theWindow
, 
 330     void *handlerRefCon
, DragReference theDrag 
); 
 331 pascal OSErr 
wxMacWindowDragReceiveHandler( 
 332     WindowPtr theWindow
, void *handlerRefCon
, 
 333     DragReference theDrag 
); 
 335 void wxMacEnsureTrackingHandlersInstalled() 
 337     if ( !gTrackingGlobalsInstalled 
) 
 341         err 
= InstallTrackingHandler( NewDragTrackingHandlerUPP(wxMacWindowDragTrackingHandler
), 0L, &gTrackingGlobals 
); 
 344         err 
= InstallReceiveHandler( NewDragReceiveHandlerUPP(wxMacWindowDragReceiveHandler
), 0L, &gTrackingGlobals 
); 
 347         gTrackingGlobalsInstalled 
= true; 
 351 pascal OSErr 
wxMacWindowDragTrackingHandler( 
 352     DragTrackingMessage theMessage
, WindowPtr theWindow
, 
 353     void *handlerRefCon
, DragReference theDrag 
) 
 355     MacTrackingGlobals
* trackingGlobals 
= (MacTrackingGlobals
*) handlerRefCon
; 
 357     Point mouse
, localMouse
; 
 358     DragAttributes attributes
; 
 360     GetDragAttributes( theDrag
, &attributes 
); 
 362     wxTopLevelWindowMac
* toplevel 
= wxFindWinFromMacWindow( theWindow 
); 
 364     bool optionDown 
= GetCurrentKeyModifiers() & optionKey
; 
 365     wxDragResult result 
= optionDown 
? wxDragCopy 
: wxDragMove
; 
 369         case kDragTrackingEnterHandler
: 
 370         case kDragTrackingLeaveHandler
: 
 373         case kDragTrackingEnterWindow
: 
 374             if (trackingGlobals 
!= NULL
) 
 376                 trackingGlobals
->m_currentTargetWindow 
= NULL
; 
 377                 trackingGlobals
->m_currentTarget 
= NULL
; 
 381         case kDragTrackingInWindow
: 
 382             if (trackingGlobals 
== NULL
) 
 384             if (toplevel 
== NULL
) 
 387             GetDragMouse( theDrag
, &mouse
, 0L ); 
 389             wxMacGlobalToLocal( theWindow
, &localMouse 
); 
 392                 wxWindow 
*win 
= NULL
; 
 393                 ControlPartCode controlPart
; 
 394                 ControlRef control 
= FindControlUnderMouse( localMouse
, theWindow
, &controlPart 
); 
 396                     win 
= wxFindControlFromMacControl( control 
); 
 401                 localx 
= localMouse
.h
; 
 402                 localy 
= localMouse
.v
; 
 405                     win
->MacRootWindowToWindow( &localx
, &localy 
); 
 406                 if ( win 
!= trackingGlobals
->m_currentTargetWindow 
) 
 408                     if ( trackingGlobals
->m_currentTargetWindow 
) 
 410                         // this window is left 
 411                         if ( trackingGlobals
->m_currentTarget 
) 
 414                             HideDragHilite( theDrag 
); 
 416                             trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag 
); 
 417                             trackingGlobals
->m_currentTarget
->OnLeave(); 
 418                             trackingGlobals
->m_currentTarget 
= NULL
; 
 419                             trackingGlobals
->m_currentTargetWindow 
= NULL
; 
 425                         // this window is entered 
 426                         trackingGlobals
->m_currentTargetWindow 
= win
; 
 427                         trackingGlobals
->m_currentTarget 
= win
->GetDropTarget(); 
 429                             if ( trackingGlobals
->m_currentTarget 
) 
 431                                 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag 
); 
 432                                 result 
= trackingGlobals
->m_currentTarget
->OnEnter( localx
, localy
, result 
); 
 435                             if ( result 
!= wxDragNone 
) 
 440                                 win
->MacWindowToRootWindow( &x
, &y 
); 
 441                                 RgnHandle hiliteRgn 
= NewRgn(); 
 442                                 Rect r 
= { y
, x
, y 
+ win
->GetSize().y
, x 
+ win
->GetSize().x 
}; 
 443                                 RectRgn( hiliteRgn
, &r 
); 
 445                                 ShowDragHilite( theDrag
, hiliteRgn
, true ); 
 447                                 DisposeRgn( hiliteRgn 
); 
 454                     if ( trackingGlobals
->m_currentTarget 
) 
 456                         trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag 
); 
 457                         result 
= trackingGlobals
->m_currentTarget
->OnDragOver( localx
, localy
, result 
); 
 461                 // set cursor for OnEnter and OnDragOver 
 462                 if ( trackingGlobals
->m_currentSource 
&& !trackingGlobals
->m_currentSource
->GiveFeedback( result 
) ) 
 464                   if ( !trackingGlobals
->m_currentSource
->MacInstallDefaultCursor( result 
) ) 
 466                       int cursorID 
= wxCURSOR_NONE
; 
 471                               cursorID 
= wxCURSOR_COPY_ARROW
; 
 475                               cursorID 
= wxCURSOR_ARROW
; 
 479                               cursorID 
= wxCURSOR_NO_ENTRY
; 
 486                               // put these here to make gcc happy 
 490                       if (cursorID 
!= wxCURSOR_NONE
) 
 492                           wxCursor 
cursor( cursorID 
); 
 500         case kDragTrackingLeaveWindow
: 
 501             if (trackingGlobals 
== NULL
) 
 504             if (trackingGlobals
->m_currentTarget
) 
 506                 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag 
); 
 507                 trackingGlobals
->m_currentTarget
->OnLeave(); 
 509                 HideDragHilite( theDrag 
); 
 511                 trackingGlobals
->m_currentTarget 
= NULL
; 
 513             trackingGlobals
->m_currentTargetWindow 
= NULL
; 
 523 pascal OSErr 
wxMacWindowDragReceiveHandler( 
 526     DragReference theDrag
) 
 528     MacTrackingGlobals
* trackingGlobals 
= (MacTrackingGlobals
*)handlerRefCon
; 
 529     if ( trackingGlobals
->m_currentTarget 
) 
 531         Point mouse
, localMouse
; 
 534         trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag 
); 
 535         GetDragMouse( theDrag
, &mouse
, 0L ); 
 537         wxMacGlobalToLocal( theWindow
, &localMouse 
); 
 538         localx 
= localMouse
.h
; 
 539         localy 
= localMouse
.v
; 
 541         // TODO : should we use client coordinates? 
 542         if ( trackingGlobals
->m_currentTargetWindow 
) 
 543             trackingGlobals
->m_currentTargetWindow
->MacRootWindowToWindow( &localx
, &localy 
); 
 544         if ( trackingGlobals
->m_currentTarget
->OnDrop( localx
, localy 
) ) 
 546             // the option key indicates copy in Mac UI, if it's not pressed do 
 547             // move by default if it's allowed at all 
 549                 result 
= !(trackingGlobals
->m_flags 
& wxDrag_AllowMove
) || 
 550                             (GetCurrentKeyModifiers() & optionKey
) 
 553             trackingGlobals
->m_result 
= 
 554                 trackingGlobals
->m_currentTarget
->OnData( localx
, localy
, result 
); 
 561 #endif // wxUSE_DRAG_AND_DROP