1 ///////////////////////////////////////////////////////////////////////////////
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
17 #include "wx/window.h"
18 #include "wx/toplevel.h"
20 #include "wx/gdicmn.h"
21 #include "wx/mac/private.h"
27 // ----------------------------------------------------------------------------
29 // ----------------------------------------------------------------------------
33 wxWindow
* m_currentTargetWindow
;
34 wxDropTarget
* m_currentTarget
;
35 wxDropSource
* m_currentSource
;
39 MacTrackingGlobals gTrackingGlobals
;
41 void wxMacEnsureTrackingHandlersInstalled() ;
43 //----------------------------------------------------------------------------
45 //----------------------------------------------------------------------------
47 wxDropTarget::wxDropTarget( wxDataObject
*data
)
48 : wxDropTargetBase( data
)
50 wxMacEnsureTrackingHandlersInstalled() ;
53 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
) )
110 ItemReference theItem
;
114 CountDragItems((DragReference
)m_currentDrag
, &items
);
115 for (UInt16 index
= 1; index
<= items
&& !supported
; ++index
)
118 GetDragItemReferenceNumber((DragReference
)m_currentDrag
, index
, &theItem
);
119 CountDragItemFlavors( (DragReference
)m_currentDrag
, theItem
, &flavors
) ;
121 for ( UInt16 flavor
= 1 ; flavor
<= flavors
; ++flavor
)
123 result
= GetFlavorType((DragReference
)m_currentDrag
, theItem
, flavor
, &theType
);
124 if ( m_dataObject
->IsSupportedFormat( wxDataFormat( theType
) ) )
136 bool wxDropTarget::GetData()
141 if ( !CurrentDragHasSupportedFormat() )
144 bool transferred
= false ;
145 if ( gTrackingGlobals
.m_currentSource
!= NULL
)
147 wxDataObject
* data
= gTrackingGlobals
.m_currentSource
->GetDataObject() ;
151 size_t formatcount
= data
->GetFormatCount() ;
152 wxDataFormat
*array
= new wxDataFormat
[formatcount
];
153 data
->GetAllFormats( array
);
154 for (size_t i
= 0; !transferred
&& i
< formatcount
; i
++)
156 wxDataFormat format
= array
[i
] ;
157 if ( m_dataObject
->IsSupported( format
) )
159 int size
= data
->GetDataSize( format
);
164 m_dataObject
->SetData(format
, 0 , 0 ) ;
168 char *d
= new char[size
];
169 data
->GetDataHere( format
, (void*) d
);
170 m_dataObject
->SetData( format
, size
, d
) ;
184 ItemReference theItem
;
186 FlavorFlags theFlags
;
188 bool firstFileAdded
= false ;
190 CountDragItems((DragReference
)m_currentDrag
, &items
);
191 for (UInt16 index
= 1; index
<= items
; ++index
)
194 GetDragItemReferenceNumber((DragReference
)m_currentDrag
, index
, &theItem
);
195 CountDragItemFlavors( (DragReference
)m_currentDrag
, theItem
, &flavors
) ;
196 bool hasPreferredFormat
= false ;
197 wxDataFormat preferredFormat
= m_dataObject
->GetPreferredFormat( wxDataObject::Set
) ;
199 for ( UInt16 flavor
= 1 ; flavor
<= flavors
; ++flavor
)
201 result
= GetFlavorType((DragReference
)m_currentDrag
, theItem
, flavor
, &theType
);
202 wxDataFormat
format(theType
) ;
203 if ( preferredFormat
== format
)
205 hasPreferredFormat
= true ;
210 for ( UInt16 flavor
= 1 ; flavor
<= flavors
; ++flavor
)
212 result
= GetFlavorType((DragReference
)m_currentDrag
, theItem
, flavor
, &theType
);
213 wxDataFormat
format(theType
) ;
214 if ( (hasPreferredFormat
&& format
== preferredFormat
) || (!hasPreferredFormat
&& m_dataObject
->IsSupportedFormat( format
)))
216 result
= GetFlavorFlags((DragReference
)m_currentDrag
, theItem
, theType
, &theFlags
);
222 GetFlavorDataSize((DragReference
)m_currentDrag
, theItem
, theType
, &dataSize
);
223 if ( theType
== kScrapFlavorTypeText
)
225 // this increment is only valid for allocating, on the next GetFlavorData
226 // call it is reset again to the original value
229 else if ( theType
== kScrapFlavorTypeUnicode
)
231 // this increment is only valid for allocating, on the next GetFlavorData
232 // call it is reset again to the original value
237 theData
= new char[dataSize
];
238 GetFlavorData((DragReference
)m_currentDrag
, theItem
, theType
, (void*) theData
, &dataSize
, 0L);
239 if ( theType
== kScrapFlavorTypeText
)
241 theData
[dataSize
] = 0 ;
242 m_dataObject
->SetData( wxDataFormat(wxDF_TEXT
), dataSize
, theData
);
245 else if ( theType
== kScrapFlavorTypeUnicode
)
247 theData
[dataSize
] = 0 ;
248 theData
[dataSize
+ 1] = 0 ;
249 m_dataObject
->SetData( wxDataFormat(wxDF_UNICODETEXT
), dataSize
, theData
);
252 else if ( theType
== kDragFlavorTypeHFS
)
254 HFSFlavor
* theFile
= (HFSFlavor
*) theData
;
255 wxString name
= wxMacFSSpec2MacFilename( &theFile
->fileSpec
) ;
256 if ( !firstFileAdded
)
259 ((wxFileDataObject
*)m_dataObject
)->SetData( 0 , "" ) ;
260 firstFileAdded
= true ;
263 ((wxFileDataObject
*)m_dataObject
)->AddFile( name
) ;
267 m_dataObject
->SetData( format
, dataSize
, theData
);
281 //-------------------------------------------------------------------------
283 //-------------------------------------------------------------------------
285 //-----------------------------------------------------------------------------
288 wxDropSource::wxDropSource(wxWindow
*win
,
289 const wxCursor
&cursorCopy
,
290 const wxCursor
&cursorMove
,
291 const wxCursor
&cursorStop
)
292 : wxDropSourceBase(cursorCopy
, cursorMove
, cursorStop
)
294 wxMacEnsureTrackingHandlersInstalled() ;
298 wxDropSource::wxDropSource(wxDataObject
& data
,
300 const wxCursor
&cursorCopy
,
301 const wxCursor
&cursorMove
,
302 const wxCursor
&cursorStop
)
303 : wxDropSourceBase(cursorCopy
, cursorMove
, cursorStop
)
305 wxMacEnsureTrackingHandlersInstalled() ;
310 wxDropSource::~wxDropSource()
314 wxDragResult
wxDropSource::DoDragDrop(int flags
)
316 wxASSERT_MSG( m_data
, wxT("Drop source: no data") );
319 return (wxDragResult
) wxDragNone
;
320 if (m_data
->GetFormatCount() == 0)
321 return (wxDragResult
) wxDragNone
;
324 DragReference theDrag
;
325 RgnHandle dragRegion
;
326 if ((result
= NewDrag(&theDrag
)) != noErr
)
330 size_t formatCount
= m_data
->GetFormatCount() ;
331 wxDataFormat
*formats
= new wxDataFormat
[formatCount
] ;
332 m_data
->GetAllFormats( formats
) ;
333 ItemReference theItem
= 1 ;
335 for ( size_t i
= 0 ; i
< formatCount
; ++i
)
337 size_t dataSize
= m_data
->GetDataSize( formats
[i
] ) ;
338 Ptr dataPtr
= new char[dataSize
] ;
339 m_data
->GetDataHere( formats
[i
] , dataPtr
) ;
340 OSType type
= formats
[i
].GetFormatId() ;
341 if ( type
== 'TEXT' || type
== 'utxt' )
345 dataPtr
[ dataSize
] = 0 ;
346 if ( type
== 'utxt' )
350 dataPtr
[ dataSize
] = 0 ;
353 AddDragItemFlavor(theDrag
, theItem
, type
, dataPtr
, dataSize
, 0);
355 else if (type
== kDragFlavorTypeHFS
)
357 HFSFlavor theFlavor
;
361 wxMacFilename2FSSpec( wxString( dataPtr
, *wxConvCurrent
) , &theFlavor
.fileSpec
) ;
363 memset( &cat
, 0, sizeof(cat
) );
364 cat
.hFileInfo
.ioNamePtr
= theFlavor
.fileSpec
.name
;
365 cat
.hFileInfo
.ioVRefNum
= theFlavor
.fileSpec
.vRefNum
;
366 cat
.hFileInfo
.ioDirID
= theFlavor
.fileSpec
.parID
;
367 cat
.hFileInfo
.ioFDirIndex
= 0;
368 err
= PBGetCatInfoSync(&cat
);
371 theFlavor
.fdFlags
= cat
.hFileInfo
.ioFlFndrInfo
.fdFlags
;
372 if (theFlavor
.fileSpec
.parID
== fsRtParID
)
374 theFlavor
.fileCreator
= 'MACS';
375 theFlavor
.fileType
= 'disk';
377 else if ((cat
.hFileInfo
.ioFlAttrib
& ioDirMask
) != 0)
379 theFlavor
.fileCreator
= 'MACS';
380 theFlavor
.fileType
= 'fold';
384 theFlavor
.fileCreator
= cat
.hFileInfo
.ioFlFndrInfo
.fdCreator
;
385 theFlavor
.fileType
= cat
.hFileInfo
.ioFlFndrInfo
.fdType
;
388 AddDragItemFlavor(theDrag
, theItem
, type
, &theFlavor
, sizeof(theFlavor
), 0);
393 AddDragItemFlavor(theDrag
, theItem
, type
, dataPtr
, dataSize
, 0);
401 dragRegion
= NewRgn();
402 RgnHandle tempRgn
= NewRgn() ;
404 EventRecord
* ev
= NULL
;
406 #if !TARGET_CARBON // TODO
407 ev
= (EventRecord
*) wxTheApp
->MacGetCurrentEvent() ;
412 wxMacConvertEventToRecord( (EventRef
) wxTheApp
->MacGetCurrentEvent() , &rec
) ;
416 const short dragRegionOuterBoundary
= 10 ;
417 const short dragRegionInnerBoundary
= 9 ;
420 dragRegion
, ev
->where
.h
- dragRegionOuterBoundary
,
421 ev
->where
.v
- dragRegionOuterBoundary
,
422 ev
->where
.h
+ dragRegionOuterBoundary
,
423 ev
->where
.v
+ dragRegionOuterBoundary
) ;
426 tempRgn
, ev
->where
.h
- dragRegionInnerBoundary
,
427 ev
->where
.v
- dragRegionInnerBoundary
,
428 ev
->where
.h
+ dragRegionInnerBoundary
,
429 ev
->where
.v
+ dragRegionInnerBoundary
) ;
431 DiffRgn( dragRegion
, tempRgn
, dragRegion
) ;
432 DisposeRgn( tempRgn
) ;
434 // TODO:work with promises in order to return data only when drag
435 // was successfully completed
437 gTrackingGlobals
.m_currentSource
= this ;
438 result
= TrackDrag(theDrag
, ev
, dragRegion
);
439 DisposeRgn(dragRegion
);
440 DisposeDrag(theDrag
);
441 gTrackingGlobals
.m_currentSource
= NULL
;
443 bool optionDown
= GetCurrentKeyModifiers() & optionKey
;
444 wxDragResult dndresult
= wxDragCopy
;
445 if ( flags
!= wxDrag_CopyOnly
)
446 // on mac the option key is always the indication for copy
447 dndresult
= optionDown
? wxDragCopy
: wxDragMove
;
452 bool wxDropSource::MacInstallDefaultCursor(wxDragResult effect
)
454 const wxCursor
& cursor
= GetCursor(effect
);
455 bool result
= cursor
.Ok();
458 cursor
.MacInstall() ;
463 bool gTrackingGlobalsInstalled
= false ;
465 // passing the globals via refcon is not needed by the CFM and later architectures anymore
466 // but I'll leave it in there, just in case...
468 pascal OSErr
wxMacWindowDragTrackingHandler(
469 DragTrackingMessage theMessage
, WindowPtr theWindow
,
470 void *handlerRefCon
, DragReference theDrag
) ;
471 pascal OSErr
wxMacWindowDragReceiveHandler(
472 WindowPtr theWindow
, void *handlerRefCon
,
473 DragReference theDrag
) ;
475 void wxMacEnsureTrackingHandlersInstalled()
477 if ( !gTrackingGlobalsInstalled
)
481 result
= InstallTrackingHandler(NewDragTrackingHandlerUPP(wxMacWindowDragTrackingHandler
), 0L,&gTrackingGlobals
);
482 wxASSERT( result
== noErr
) ;
484 result
= InstallReceiveHandler(NewDragReceiveHandlerUPP(wxMacWindowDragReceiveHandler
), 0L, &gTrackingGlobals
);
485 wxASSERT( result
== noErr
) ;
487 gTrackingGlobalsInstalled
= true ;
491 pascal OSErr
wxMacWindowDragTrackingHandler(
492 DragTrackingMessage theMessage
, WindowPtr theWindow
,
493 void *handlerRefCon
, DragReference theDrag
)
495 MacTrackingGlobals
* trackingGlobals
= (MacTrackingGlobals
*) handlerRefCon
;
496 Point mouse
, localMouse
;
497 DragAttributes attributes
;
498 GetDragAttributes(theDrag
, &attributes
);
499 wxTopLevelWindowMac
* toplevel
= wxFindWinFromMacWindow( theWindow
) ;
501 bool optionDown
= GetCurrentKeyModifiers() & optionKey
;
502 wxDragResult result
= optionDown
? wxDragCopy
: wxDragMove
;
506 case kDragTrackingEnterHandler
:
507 case kDragTrackingLeaveHandler
:
510 case kDragTrackingEnterWindow
:
511 trackingGlobals
->m_currentTargetWindow
= NULL
;
512 trackingGlobals
->m_currentTarget
= NULL
;
515 case kDragTrackingInWindow
:
516 if (toplevel
== NULL
)
519 GetDragMouse(theDrag
, &mouse
, 0L);
521 GlobalToLocal(&localMouse
);
524 wxWindow
*win
= NULL
;
525 ControlPartCode controlPart
;
526 ControlRef control
= wxMacFindControlUnderMouse(
527 toplevel
, localMouse
,
528 theWindow
, &controlPart
) ;
530 win
= wxFindControlFromMacControl( control
) ;
534 int localx
, localy
;
535 localx
= localMouse
.h
;
536 localy
= localMouse
.v
;
539 win
->MacRootWindowToWindow( &localx
, &localy
) ;
540 if ( win
!= trackingGlobals
->m_currentTargetWindow
)
542 if ( trackingGlobals
->m_currentTargetWindow
)
544 // this window is left
545 if ( trackingGlobals
->m_currentTarget
)
547 HideDragHilite( theDrag
);
548 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
549 trackingGlobals
->m_currentTarget
->OnLeave() ;
550 trackingGlobals
->m_currentTarget
= NULL
;
551 trackingGlobals
->m_currentTargetWindow
= NULL
;
557 // this window is entered
558 trackingGlobals
->m_currentTargetWindow
= win
;
559 trackingGlobals
->m_currentTarget
= win
->GetDropTarget() ;
561 if ( trackingGlobals
->m_currentTarget
)
563 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
564 result
= trackingGlobals
->m_currentTarget
->OnEnter( localx
, localy
, result
) ;
567 if ( result
!= wxDragNone
)
572 win
->MacWindowToRootWindow( &x
, &y
) ;
573 RgnHandle hiliteRgn
= NewRgn() ;
574 Rect r
= { y
, x
, y
+ win
->GetSize().y
, x
+ win
->GetSize().x
} ;
575 RectRgn( hiliteRgn
, &r
) ;
576 ShowDragHilite(theDrag
, hiliteRgn
, true);
577 DisposeRgn( hiliteRgn
) ;
584 if ( trackingGlobals
->m_currentTarget
)
586 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
587 trackingGlobals
->m_currentTarget
->OnDragOver( localx
, localy
, result
) ;
591 // set cursor for OnEnter and OnDragOver
592 if ( !trackingGlobals
->m_currentSource
&& trackingGlobals
->m_currentSource
->GiveFeedback( result
) )
594 if ( !trackingGlobals
->m_currentSource
->MacInstallDefaultCursor( result
) )
600 wxCursor
cursor(wxCURSOR_COPY_ARROW
) ;
601 cursor
.MacInstall() ;
607 wxCursor
cursor(wxCURSOR_ARROW
) ;
608 cursor
.MacInstall() ;
614 wxCursor
cursor(wxCURSOR_NO_ENTRY
) ;
615 cursor
.MacInstall() ;
623 // put these here to make gcc happy
631 case kDragTrackingLeaveWindow
:
632 if (trackingGlobals
->m_currentTarget
)
634 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
635 trackingGlobals
->m_currentTarget
->OnLeave() ;
636 HideDragHilite(theDrag
);
637 trackingGlobals
->m_currentTarget
= NULL
;
639 trackingGlobals
->m_currentTargetWindow
= NULL
;
649 pascal OSErr
wxMacWindowDragReceiveHandler(
652 DragReference theDrag
)
654 MacTrackingGlobals
* trackingGlobals
= (MacTrackingGlobals
*)handlerRefCon
;
655 if ( trackingGlobals
->m_currentTarget
)
657 Point mouse
, localMouse
;
660 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
661 GetDragMouse(theDrag
, &mouse
, 0L);
663 GlobalToLocal(&localMouse
);
664 localx
= localMouse
.h
;
665 localy
= localMouse
.v
;
667 // TODO : should we use client coordinates?
668 if ( trackingGlobals
->m_currentTargetWindow
)
669 trackingGlobals
->m_currentTargetWindow
->MacRootWindowToWindow( &localx
, &localy
) ;
670 if ( trackingGlobals
->m_currentTarget
->OnDrop( localx
, localy
) )
672 bool optionDown
= GetCurrentKeyModifiers() & optionKey
;
673 wxDragResult result
= optionDown
? wxDragCopy
: wxDragMove
;
674 trackingGlobals
->m_currentTarget
->OnData( localx
, localy
, result
) ;