1 /////////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     wxDropTarget, wxDropSource, wxDataObject implementation 
   4 // Author:      Stefan Csomor 
   8 // Copyright:   (c) 1998 Stefan Csomor 
   9 // Licence:     wxWindows licence 
  10 /////////////////////////////////////////////////////////////////////////////// 
  13 #pragma implementation "dnd.h" 
  18 #if wxUSE_DRAG_AND_DROP 
  21 #include "wx/window.h" 
  22 #include "wx/toplevel.h" 
  24 #include "wx/gdicmn.h" 
  25 #include "wx/mac/private.h" 
  27 // ---------------------------------------------------------------------------- 
  29 // ---------------------------------------------------------------------------- 
  31 void wxMacEnsureTrackingHandlersInstalled() ; 
  35     wxWindow
* m_currentTargetWindow 
; 
  36     wxDropTarget
* m_currentTarget 
; 
  37     wxDropSource
* m_currentSource 
; 
  38 } MacTrackingGlobals 
; 
  40 MacTrackingGlobals gTrackingGlobals 
;  
  42 //---------------------------------------------------------------------------- 
  44 //---------------------------------------------------------------------------- 
  46 wxDropTarget::wxDropTarget( wxDataObject 
*data 
) 
  47             : wxDropTargetBase( data 
) 
  49     wxMacEnsureTrackingHandlersInstalled() ; 
  52 wxDragResult 
wxDropTarget::OnDragOver( wxCoord 
WXUNUSED(x
), 
  57     return CurrentDragHasSupportedFormat() ? def 
: wxDragNone
; 
  60 bool wxDropTarget::OnDrop( wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
) ) 
  65     return CurrentDragHasSupportedFormat() ; 
  68 wxDragResult 
wxDropTarget::OnData( wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
), 
  74     if (!CurrentDragHasSupportedFormat()) 
  77     return GetData() ? def 
: wxDragNone
; 
  80 bool wxDropTarget::CurrentDragHasSupportedFormat()  
  82     bool supported 
= false ; 
  83     if ( gTrackingGlobals
.m_currentSource 
!= NULL 
) 
  85         wxDataObject
* data 
= gTrackingGlobals
.m_currentSource
->GetDataObject() ; 
  89             size_t formatcount 
= data
->GetFormatCount() ; 
  90             wxDataFormat 
*array 
= new wxDataFormat
[ formatcount  
]; 
  91             data
->GetAllFormats( array 
); 
  92             for (size_t i 
= 0; !supported 
&& i 
< formatcount 
; i
++) 
  94                 wxDataFormat format 
= array
[i
] ; 
  95                 if ( m_dataObject
->IsSupported( format 
) )  
 108         CountDragItems((DragReference
)m_currentDrag
, &items
); 
 109         for (UInt16 index 
= 1; index 
<= items 
&& supported 
== false ; ++index
)  
 111             ItemReference theItem
; 
 114             GetDragItemReferenceNumber((DragReference
)m_currentDrag
, index
, &theItem
); 
 115             CountDragItemFlavors( (DragReference
)m_currentDrag
, theItem 
, &flavors 
) ; 
 116             for ( UInt16 flavor 
= 1 ; flavor 
<= flavors 
; ++flavor 
) 
 118                 result 
= GetFlavorType((DragReference
)m_currentDrag
, theItem
, flavor 
, &theType
); 
 119                 if ( m_dataObject
->IsSupportedFormat( wxDataFormat( theType 
) ) ) 
 130 bool wxDropTarget::GetData() 
 135     if ( !CurrentDragHasSupportedFormat() ) 
 138     bool transferred 
= false ;    
 139     if ( gTrackingGlobals
.m_currentSource 
!= NULL 
) 
 141         wxDataObject
* data 
= gTrackingGlobals
.m_currentSource
->GetDataObject() ; 
 145             size_t formatcount 
= data
->GetFormatCount() ; 
 146             wxDataFormat 
*array 
= new wxDataFormat
[ formatcount  
]; 
 147             data
->GetAllFormats( array 
); 
 148             for (size_t i 
= 0; !transferred 
&& i 
< formatcount 
; i
++) 
 150                 wxDataFormat format 
= array
[i
] ; 
 151                 if ( m_dataObject
->IsSupported( format 
) )  
 153                     int size 
= data
->GetDataSize( format 
); 
 158                         m_dataObject
->SetData(format 
, 0 , 0 ) ; 
 162                         char *d 
= new char[size
]; 
 163                         data
->GetDataHere( format 
, (void*) d 
); 
 164                         m_dataObject
->SetData( format 
, size 
, d 
) ; 
 176         bool firstFileAdded 
= false ; 
 177         CountDragItems((DragReference
)m_currentDrag
, &items
); 
 178         for (UInt16 index 
= 1; index 
<= items
; ++index
)  
 180             ItemReference theItem
; 
 183             GetDragItemReferenceNumber((DragReference
)m_currentDrag
, index
, &theItem
); 
 184             CountDragItemFlavors( (DragReference
)m_currentDrag
, theItem 
, &flavors 
) ; 
 185             for ( UInt16 flavor 
= 1 ; flavor 
<= flavors 
; ++flavor 
) 
 187                 result 
= GetFlavorType((DragReference
)m_currentDrag
, theItem
, flavor 
, &theType
); 
 188                 wxDataFormat 
format(theType
) ; 
 189                 if ( m_dataObject
->IsSupportedFormat( format 
) ) 
 191                     FlavorFlags theFlags
; 
 192                     result 
= GetFlavorFlags((DragReference
)m_currentDrag
, theItem
, theType
, &theFlags
); 
 197                         GetFlavorDataSize((DragReference
)m_currentDrag
, theItem
, theType
, &dataSize
); 
 198                         if ( theType 
== 'TEXT' ) 
 200                             // this increment is only valid for allocating, on the next GetFlavorData 
 201                             // call it is reset again to the original value 
 204                         theData 
= new char[dataSize
]; 
 205                         GetFlavorData((DragReference
)m_currentDrag
, theItem
, theType
, (void*) theData
, &dataSize
, 0L);  
 206                         if( theType 
== 'TEXT' ) 
 208                             theData
[dataSize
]=0 ;  
 209                             wxString 
convert( theData 
, wxConvLocal 
) ;     
 210                             m_dataObject
->SetData( format
, convert
.Length() * sizeof(wxChar
), (const wxChar
*) convert 
); 
 212                         else if ( theType 
== kDragFlavorTypeHFS 
) 
 214                             HFSFlavor
* theFile 
= (HFSFlavor
*) theData 
; 
 215                             wxString name 
= wxMacFSSpec2MacFilename( &theFile
->fileSpec 
) ; 
 216                             if (  firstFileAdded 
) 
 217                                 ((wxFileDataObject
*)m_dataObject
)->AddFile( name 
) ; 
 220                                 ((wxFileDataObject
*)m_dataObject
)->SetData( 0 , name
.c_str() ) ; 
 221                                 firstFileAdded 
= true ;     
 226                             m_dataObject
->SetData( format
, dataSize
, theData 
); 
 238 //------------------------------------------------------------------------- 
 240 //------------------------------------------------------------------------- 
 242 //----------------------------------------------------------------------------- 
 245 wxDropSource::wxDropSource(wxWindow 
*win
, 
 246                            const wxCursor 
&cursorCopy
, 
 247                            const wxCursor 
&cursorMove
, 
 248                            const wxCursor 
&cursorStop
) 
 249             : wxDropSourceBase(cursorCopy
, cursorMove
, cursorStop
) 
 251     wxMacEnsureTrackingHandlersInstalled() ; 
 255 wxDropSource::wxDropSource(wxDataObject
& data
, 
 257                            const wxCursor 
&cursorCopy
, 
 258                            const wxCursor 
&cursorMove
, 
 259                            const wxCursor 
&cursorStop
) 
 260             : wxDropSourceBase(cursorCopy
, cursorMove
, cursorStop
) 
 262     wxMacEnsureTrackingHandlersInstalled() ; 
 267 wxDropSource::~wxDropSource() 
 272 wxDragResult 
wxDropSource::DoDragDrop(int WXUNUSED(flags
)) 
 274     wxASSERT_MSG( m_data
, wxT("Drop source: no data") ); 
 277         return (wxDragResult
) wxDragNone
; 
 279     if (m_data
->GetFormatCount() == 0) 
 280         return (wxDragResult
) wxDragNone
; 
 283     DragReference theDrag
; 
 284     RgnHandle dragRegion
; 
 285     if ((result 
= NewDrag(&theDrag
))) 
 290     size_t formatCount 
= m_data
->GetFormatCount() ; 
 291     wxDataFormat 
*formats 
= new wxDataFormat
[formatCount
] ; 
 292     m_data
->GetAllFormats( formats 
) ; 
 293     ItemReference theItem 
= 1 ; 
 294     for ( size_t i 
= 0 ; i 
< formatCount 
; ++i 
) 
 296         size_t dataSize 
= m_data
->GetDataSize( formats
[i
] ) ; 
 297         Ptr dataPtr 
= new char[dataSize
] ; 
 298         m_data
->GetDataHere( formats
[i
] , dataPtr 
) ; 
 299         OSType type 
= formats
[i
].GetFormatId() ; 
 300         if ( type 
== 'TEXT' ) 
 303             dataPtr
[ dataSize 
] = 0 ; 
 304             wxString 
st( (wxChar
*) dataPtr 
) ; 
 305             wxCharBuffer buf 
= st
.mb_str( wxConvLocal
) ; 
 306             AddDragItemFlavor(theDrag
, theItem
, type 
, buf
.data(), strlen(buf
), 0); 
 308         else if (type 
== kDragFlavorTypeHFS 
) 
 310             HFSFlavor  theFlavor 
; 
 314             wxMacFilename2FSSpec( dataPtr 
, &theFlavor
.fileSpec 
) ; 
 316             cat
.hFileInfo
.ioNamePtr 
= theFlavor
.fileSpec
.name
; 
 317             cat
.hFileInfo
.ioVRefNum 
= theFlavor
.fileSpec
.vRefNum
; 
 318             cat
.hFileInfo
.ioDirID 
= theFlavor
.fileSpec
.parID
; 
 319             cat
.hFileInfo
.ioFDirIndex 
= 0; 
 320             err 
= PBGetCatInfoSync(&cat
); 
 323                 theFlavor
.fdFlags 
= cat
.hFileInfo
.ioFlFndrInfo
.fdFlags
; 
 324                 if (theFlavor
.fileSpec
.parID 
== fsRtParID
) { 
 325                     theFlavor
.fileCreator 
= 'MACS'; 
 326                     theFlavor
.fileType 
= 'disk'; 
 327                 } else if ((cat
.hFileInfo
.ioFlAttrib 
& ioDirMask
) != 0) { 
 328                     theFlavor
.fileCreator 
= 'MACS'; 
 329                     theFlavor
.fileType 
= 'fold'; 
 331                     theFlavor
.fileCreator 
= cat
.hFileInfo
.ioFlFndrInfo
.fdCreator
; 
 332                     theFlavor
.fileType 
= cat
.hFileInfo
.ioFlFndrInfo
.fdType
; 
 334                 AddDragItemFlavor(theDrag
, theItem
, type 
, &theFlavor
, sizeof(theFlavor
), 0);   
 339             AddDragItemFlavor(theDrag
, theItem
, type 
, dataPtr
, dataSize
, 0);       
 345     dragRegion 
= NewRgn(); 
 346     RgnHandle tempRgn 
= NewRgn() ; 
 348     EventRecord
* ev 
= NULL 
; 
 349 #if !TARGET_CARBON // TODO 
 350     ev 
= (EventRecord
*) wxTheApp
->MacGetCurrentEvent() ; 
 354     wxMacConvertEventToRecord( (EventRef
) wxTheApp
->MacGetCurrentEvent() , &rec 
) ; 
 356     const short dragRegionOuterBoundary 
= 10 ; 
 357     const short dragRegionInnerBoundary 
= 9 ; 
 359     SetRectRgn( dragRegion 
, ev
->where
.h 
- dragRegionOuterBoundary 
,  
 360         ev
->where
.v  
- dragRegionOuterBoundary 
, 
 361         ev
->where
.h 
+ dragRegionOuterBoundary 
,  
 362         ev
->where
.v 
+ dragRegionOuterBoundary 
) ; 
 364     SetRectRgn( tempRgn 
, ev
->where
.h 
- dragRegionInnerBoundary 
,  
 365         ev
->where
.v  
- dragRegionInnerBoundary 
, 
 366         ev
->where
.h 
+ dragRegionInnerBoundary 
,  
 367         ev
->where
.v 
+ dragRegionInnerBoundary 
) ; 
 369     DiffRgn( dragRegion 
, tempRgn 
, dragRegion 
) ; 
 370     DisposeRgn( tempRgn 
) ;     
 372     // TODO:work with promises in order to return data only when drag 
 373     // was successfully completed 
 375     gTrackingGlobals
.m_currentSource 
= this ; 
 376     result 
= TrackDrag(theDrag
, ev 
, dragRegion
); 
 377     DisposeRgn(dragRegion
); 
 378     DisposeDrag(theDrag
); 
 379     gTrackingGlobals
.m_currentSource 
= NULL 
; 
 383     bool optionDown 
= keymap
[1] & 4; 
 384     wxDragResult dndresult 
= optionDown 
? wxDragCopy 
: wxDragMove
; 
 388 bool wxDropSource::MacInstallDefaultCursor(wxDragResult effect
) 
 390     const wxCursor
& cursor 
= GetCursor(effect
); 
 393         cursor
.MacInstall() ; 
 403 bool gTrackingGlobalsInstalled 
= false ; 
 405 // passing the globals via refcon is not needed by the CFM and later architectures anymore 
 406 // but I'll leave it in there, just in case... 
 408 pascal OSErr 
wxMacWindowDragTrackingHandler(DragTrackingMessage theMessage
, WindowPtr theWindow
, 
 409   void *handlerRefCon
, DragReference theDrag
) ; 
 410 pascal OSErr 
wxMacWindowDragReceiveHandler(WindowPtr theWindow
, void *handlerRefCon
, 
 411 DragReference theDrag
) ; 
 413 void wxMacEnsureTrackingHandlersInstalled() 
 415     if( !gTrackingGlobalsInstalled 
) 
 419         result 
= InstallTrackingHandler(NewDragTrackingHandlerUPP(wxMacWindowDragTrackingHandler
), 0L,&gTrackingGlobals
); 
 420         wxASSERT( result 
== noErr 
) ; 
 421         result 
= InstallReceiveHandler(NewDragReceiveHandlerUPP(wxMacWindowDragReceiveHandler
), 0L, &gTrackingGlobals
); 
 422         wxASSERT( result 
== noErr 
) ; 
 424         gTrackingGlobalsInstalled 
= true ; 
 428 pascal OSErr 
wxMacWindowDragTrackingHandler(DragTrackingMessage theMessage
, WindowPtr theWindow
, 
 429   void *handlerRefCon
, DragReference theDrag
) 
 431     MacTrackingGlobals
* trackingGlobals 
= (MacTrackingGlobals
*) handlerRefCon
; 
 432     Point mouse
, localMouse
; 
 433     DragAttributes attributes
; 
 434     GetDragAttributes(theDrag
, &attributes
); 
 435     wxTopLevelWindowMac
* toplevel 
= wxFindWinFromMacWindow( (WXWindow
) theWindow 
) ;  
 439     bool optionDown 
= keymap
[1] & 4; 
 440     wxDragResult result 
= optionDown 
? wxDragCopy 
: wxDragMove
; 
 444         case kDragTrackingEnterHandler
: 
 446         case kDragTrackingLeaveHandler
: 
 448         case kDragTrackingEnterWindow
: 
 449             trackingGlobals
->m_currentTargetWindow 
= NULL 
; 
 450             trackingGlobals
->m_currentTarget 
= NULL 
; 
 452         case kDragTrackingInWindow
: 
 453             if (toplevel 
== NULL
) 
 456             GetDragMouse(theDrag
, &mouse
, 0L); 
 458             GlobalToLocal(&localMouse
); 
 462 //            if (attributes & kDragHasLeftSenderWindow)  
 464                 wxPoint 
point(localMouse
.h 
, localMouse
.v
) ; 
 465                 wxWindow 
*win 
= NULL 
; 
 466                 toplevel
->MacGetWindowFromPointSub( point 
, &win 
) ; 
 467                 int localx 
, localy 
; 
 468                 localx 
= localMouse
.h 
; 
 469                 localy 
= localMouse
.v 
; 
 470                 //TODO : should we use client coordinates 
 472                     win
->MacRootWindowToWindow( &localx 
, &localy 
) ; 
 473                 if ( win 
!= trackingGlobals
->m_currentTargetWindow 
) 
 475                     if ( trackingGlobals
->m_currentTargetWindow 
) 
 477                         // this window is left 
 478                         if ( trackingGlobals
->m_currentTarget 
) 
 480                             HideDragHilite(theDrag
); 
 481                             trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag 
) ; 
 482                             trackingGlobals
->m_currentTarget
->OnLeave() ; 
 483                             trackingGlobals
->m_currentTarget 
= NULL
; 
 484                             trackingGlobals
->m_currentTargetWindow 
= NULL 
; 
 489                         // this window is entered 
 490                         trackingGlobals
->m_currentTargetWindow 
= win 
; 
 491                         trackingGlobals
->m_currentTarget 
= win
->GetDropTarget() ; 
 494                                 if ( trackingGlobals
->m_currentTarget 
) 
 496                                 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag 
) ; 
 497                                 result 
= trackingGlobals
->m_currentTarget
->OnEnter( 
 498                                         localx 
, localy 
, result 
) ; 
 502                             if ( result 
!= wxDragNone 
) 
 506                                 win
->MacWindowToRootWindow( &x 
, &y 
) ; 
 507                                 RgnHandle hiliteRgn 
= NewRgn() ; 
 508                                 SetRectRgn( hiliteRgn 
, x 
, y 
, x
+win
->GetSize().x 
,y
+win
->GetSize().y
) ; 
 509                                 ShowDragHilite(theDrag
, hiliteRgn
, true); 
 510                                 DisposeRgn( hiliteRgn 
) ; 
 517                     if( trackingGlobals
->m_currentTarget 
) 
 519                         trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag 
) ; 
 520                         trackingGlobals
->m_currentTarget
->OnDragOver( 
 521                             localx 
, localy 
, result 
) ; 
 525                 // set cursor for OnEnter and OnDragOver 
 526                 if ( trackingGlobals
->m_currentSource 
&& trackingGlobals
->m_currentSource
->GiveFeedback( result 
) == FALSE 
) 
 528                   if ( trackingGlobals
->m_currentSource
->MacInstallDefaultCursor( result 
) == FALSE 
) 
 534                                   wxCursor 
cursor(wxCURSOR_COPY_ARROW
) ; 
 535                                   cursor
.MacInstall() ; 
 540                                   wxCursor 
cursor(wxCURSOR_ARROW
) ; 
 541                                   cursor
.MacInstall() ; 
 546                                   wxCursor 
cursor(wxCURSOR_NO_ENTRY
) ; 
 547                                   cursor
.MacInstall() ; 
 554                               // put these here to make gcc happy 
 561             // MyTrackItemUnderMouse(localMouse, theWindow); 
 563         case kDragTrackingLeaveWindow
: 
 564             if (trackingGlobals
->m_currentTarget
)  
 566                 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag 
) ; 
 567                 trackingGlobals
->m_currentTarget
->OnLeave() ; 
 568                 HideDragHilite(theDrag
); 
 569                 trackingGlobals
->m_currentTarget 
= NULL 
; 
 571             trackingGlobals
->m_currentTargetWindow 
= NULL 
; 
 577 pascal OSErr 
wxMacWindowDragReceiveHandler(WindowPtr theWindow
, 
 579                                            DragReference theDrag
) 
 581     MacTrackingGlobals
* trackingGlobals 
= (MacTrackingGlobals
*) handlerRefCon
; 
 582     if ( trackingGlobals
->m_currentTarget 
) 
 584         Point mouse
,localMouse 
; 
 587         trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag 
) ; 
 588         GetDragMouse(theDrag
, &mouse
, 0L); 
 590         GlobalToLocal(&localMouse
); 
 591         localx 
= localMouse
.h 
; 
 592         localy 
= localMouse
.v 
; 
 593         //TODO : should we use client coordinates 
 594         if ( trackingGlobals
->m_currentTargetWindow 
) 
 595             trackingGlobals
->m_currentTargetWindow
->MacRootWindowToWindow( &localx 
, &localy 
) ; 
 596         if ( trackingGlobals
->m_currentTarget
->OnDrop( localx 
, localy 
) ) 
 600             bool optionDown 
= keymap
[1] & 4; 
 601             wxDragResult result 
= optionDown 
? wxDragCopy 
: wxDragMove
; 
 602             trackingGlobals
->m_currentTarget
->OnData( localx 
, localy 
, result 
) ;