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"
28 // ----------------------------------------------------------------------------
30 // ----------------------------------------------------------------------------
34 wxWindow
* m_currentTargetWindow
;
35 wxDropTarget
* m_currentTarget
;
36 wxDropSource
* m_currentSource
;
40 MacTrackingGlobals gTrackingGlobals
;
42 void wxMacEnsureTrackingHandlersInstalled() ;
44 //----------------------------------------------------------------------------
46 //----------------------------------------------------------------------------
48 wxDropTarget::wxDropTarget( wxDataObject
*data
)
49 : wxDropTargetBase( data
)
51 wxMacEnsureTrackingHandlersInstalled() ;
54 wxDragResult
wxDropTarget::OnDragOver( wxCoord
WXUNUSED(x
),
58 return CurrentDragHasSupportedFormat() ? def
: wxDragNone
;
61 bool wxDropTarget::OnDrop( wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
) )
63 if (m_dataObject
== NULL
)
66 return CurrentDragHasSupportedFormat() ;
69 wxDragResult
wxDropTarget::OnData( 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 ;
85 if ( gTrackingGlobals
.m_currentSource
!= NULL
)
87 wxDataObject
* data
= gTrackingGlobals
.m_currentSource
->GetDataObject() ;
91 size_t formatcount
= data
->GetFormatCount() ;
92 wxDataFormat
*array
= new wxDataFormat
[formatcount
];
93 data
->GetAllFormats( array
);
94 for (size_t i
= 0; !supported
&& i
< formatcount
; i
++)
96 wxDataFormat format
= array
[i
] ;
97 if ( m_dataObject
->IsSupported( format
) )
112 ItemReference theItem
;
116 CountDragItems( (DragReference
)m_currentDrag
, &items
);
117 for (UInt16 index
= 1; index
<= items
&& !supported
; ++index
)
120 GetDragItemReferenceNumber( (DragReference
)m_currentDrag
, index
, &theItem
);
121 CountDragItemFlavors( (DragReference
)m_currentDrag
, theItem
, &flavors
);
123 for ( UInt16 flavor
= 1 ; flavor
<= flavors
; ++flavor
)
125 result
= GetFlavorType( (DragReference
)m_currentDrag
, theItem
, flavor
, &theType
);
126 if ( m_dataObject
->IsSupportedFormat( wxDataFormat( theType
) ) )
138 bool wxDropTarget::GetData()
140 if (m_dataObject
== NULL
)
143 if ( !CurrentDragHasSupportedFormat() )
146 bool transferred
= false ;
147 if ( gTrackingGlobals
.m_currentSource
!= NULL
)
149 wxDataObject
* data
= gTrackingGlobals
.m_currentSource
->GetDataObject() ;
153 size_t formatcount
= data
->GetFormatCount() ;
154 wxDataFormat
*array
= new wxDataFormat
[formatcount
];
155 data
->GetAllFormats( array
);
156 for (size_t i
= 0; !transferred
&& i
< formatcount
; i
++)
158 wxDataFormat format
= array
[i
] ;
159 if ( m_dataObject
->IsSupported( format
) )
161 int size
= data
->GetDataSize( format
);
166 m_dataObject
->SetData( format
, 0 , 0 );
170 char *d
= new char[size
];
171 data
->GetDataHere( format
, (void*) d
);
172 m_dataObject
->SetData( format
, size
, d
) ;
186 ItemReference theItem
;
188 FlavorFlags theFlags
;
190 bool firstFileAdded
= false ;
192 CountDragItems( (DragReference
)m_currentDrag
, &items
);
193 for (UInt16 index
= 1; index
<= items
; ++index
)
196 GetDragItemReferenceNumber( (DragReference
)m_currentDrag
, index
, &theItem
);
197 CountDragItemFlavors( (DragReference
)m_currentDrag
, theItem
, &flavors
);
198 wxDataFormat preferredFormat
= m_dataObject
->GetPreferredFormat( wxDataObject::Set
);
199 bool hasPreferredFormat
= false ;
201 for ( UInt16 flavor
= 1 ; flavor
<= flavors
; ++flavor
)
203 result
= GetFlavorType( (DragReference
)m_currentDrag
, theItem
, flavor
, &theType
);
204 wxDataFormat
format( theType
);
205 if ( preferredFormat
== format
)
207 hasPreferredFormat
= true ;
212 for ( UInt16 flavor
= 1 ; flavor
<= flavors
; ++flavor
)
214 result
= GetFlavorType( (DragReference
)m_currentDrag
, theItem
, flavor
, &theType
);
215 wxDataFormat
format( theType
) ;
216 if ( (hasPreferredFormat
&& format
== preferredFormat
)
217 || (!hasPreferredFormat
&& m_dataObject
->IsSupportedFormat( format
)))
219 result
= GetFlavorFlags( (DragReference
)m_currentDrag
, theItem
, theType
, &theFlags
);
225 GetFlavorDataSize( (DragReference
)m_currentDrag
, theItem
, theType
, &dataSize
);
226 if ( theType
== kScrapFlavorTypeText
)
228 // this increment is only valid for allocating:
229 // on the next GetFlavorData call it is reset again to the original value
232 else if ( theType
== kScrapFlavorTypeUnicode
)
234 // this increment is only valid for allocating:
235 // on the next GetFlavorData call it is reset again to the original value
240 theData
= new char[dataSize
];
242 GetFlavorData( (DragReference
)m_currentDrag
, theItem
, theType
, (void*) theData
, &dataSize
, 0L );
243 if ( theType
== kScrapFlavorTypeText
)
245 theData
[dataSize
] = 0 ;
246 m_dataObject
->SetData( wxDataFormat(wxDF_TEXT
), dataSize
, theData
);
249 else if ( theType
== kScrapFlavorTypeUnicode
)
251 theData
[dataSize
+ 0] =
252 theData
[dataSize
+ 1] = 0 ;
253 m_dataObject
->SetData( wxDataFormat(wxDF_UNICODETEXT
), dataSize
, theData
);
256 else if ( theType
== kDragFlavorTypeHFS
)
258 wxFileDataObject
*fdo
= dynamic_cast<wxFileDataObject
*>(m_dataObject
);
259 wxASSERT( fdo
!= NULL
);
261 if ((theData
!= NULL
) && (fdo
!= NULL
))
263 HFSFlavor
* theFile
= (HFSFlavor
*) theData
;
264 wxString name
= wxMacFSSpec2MacFilename( &theFile
->fileSpec
) ;
266 if ( !firstFileAdded
)
269 fdo
->SetData( 0 , "" ) ;
270 firstFileAdded
= true ;
274 fdo
->AddFile( name
) ;
279 m_dataObject
->SetData( format
, dataSize
, theData
);
293 //-------------------------------------------------------------------------
295 //-------------------------------------------------------------------------
297 //-----------------------------------------------------------------------------
300 wxDropSource::wxDropSource(wxWindow
*win
,
301 const wxCursor
&cursorCopy
,
302 const wxCursor
&cursorMove
,
303 const wxCursor
&cursorStop
)
304 : wxDropSourceBase(cursorCopy
, cursorMove
, cursorStop
)
306 wxMacEnsureTrackingHandlersInstalled() ;
311 wxDropSource::wxDropSource(wxDataObject
& data
,
313 const wxCursor
&cursorCopy
,
314 const wxCursor
&cursorMove
,
315 const wxCursor
&cursorStop
)
316 : wxDropSourceBase(cursorCopy
, cursorMove
, cursorStop
)
318 wxMacEnsureTrackingHandlersInstalled() ;
324 wxDropSource::~wxDropSource()
328 wxDragResult
wxDropSource::DoDragDrop(int flags
)
330 wxASSERT_MSG( m_data
, wxT("Drop source: no data") );
333 return (wxDragResult
) wxDragNone
;
334 if (m_data
->GetFormatCount() == 0)
335 return (wxDragResult
) wxDragNone
;
338 DragReference theDrag
;
339 RgnHandle dragRegion
;
340 if ((result
= NewDrag(&theDrag
)) != noErr
)
344 size_t formatCount
= m_data
->GetFormatCount() ;
345 wxDataFormat
*formats
= new wxDataFormat
[formatCount
] ;
346 m_data
->GetAllFormats( formats
) ;
347 ItemReference theItem
= 1 ;
349 for ( size_t i
= 0 ; i
< formatCount
; ++i
)
351 size_t dataSize
= m_data
->GetDataSize( formats
[i
] ) ;
352 Ptr dataPtr
= new char[dataSize
] ;
353 m_data
->GetDataHere( formats
[i
] , dataPtr
) ;
354 OSType type
= formats
[i
].GetFormatId() ;
355 if ( type
== 'TEXT' || type
== 'utxt' )
359 dataPtr
[ dataSize
] = 0 ;
360 if ( type
== 'utxt' )
364 dataPtr
[ dataSize
] = 0 ;
367 AddDragItemFlavor( theDrag
, theItem
, type
, dataPtr
, dataSize
, 0 );
369 else if (type
== kDragFlavorTypeHFS
)
371 HFSFlavor theFlavor
;
375 wxMacFilename2FSSpec( wxString( dataPtr
, *wxConvCurrent
), &theFlavor
.fileSpec
) ;
377 memset( &cat
, 0, sizeof(cat
) );
378 cat
.hFileInfo
.ioNamePtr
= theFlavor
.fileSpec
.name
;
379 cat
.hFileInfo
.ioVRefNum
= theFlavor
.fileSpec
.vRefNum
;
380 cat
.hFileInfo
.ioDirID
= theFlavor
.fileSpec
.parID
;
381 cat
.hFileInfo
.ioFDirIndex
= 0;
382 err
= PBGetCatInfoSync( &cat
);
385 theFlavor
.fdFlags
= cat
.hFileInfo
.ioFlFndrInfo
.fdFlags
;
386 if (theFlavor
.fileSpec
.parID
== fsRtParID
)
388 theFlavor
.fileCreator
= 'MACS';
389 theFlavor
.fileType
= 'disk';
391 else if ((cat
.hFileInfo
.ioFlAttrib
& ioDirMask
) != 0)
393 theFlavor
.fileCreator
= 'MACS';
394 theFlavor
.fileType
= 'fold';
398 theFlavor
.fileCreator
= cat
.hFileInfo
.ioFlFndrInfo
.fdCreator
;
399 theFlavor
.fileType
= cat
.hFileInfo
.ioFlFndrInfo
.fdType
;
402 AddDragItemFlavor( theDrag
, theItem
, type
, &theFlavor
, sizeof(theFlavor
), 0 );
407 AddDragItemFlavor( theDrag
, theItem
, type
, dataPtr
, dataSize
, 0 );
415 dragRegion
= NewRgn();
416 RgnHandle tempRgn
= NewRgn() ;
418 EventRecord
* ev
= NULL
;
420 #if !TARGET_CARBON // TODO
421 ev
= (EventRecord
*) wxTheApp
->MacGetCurrentEvent() ;
426 wxMacConvertEventToRecord( (EventRef
) wxTheApp
->MacGetCurrentEvent() , &rec
) ;
430 const short dragRegionOuterBoundary
= 10 ;
431 const short dragRegionInnerBoundary
= 9 ;
434 dragRegion
, ev
->where
.h
- dragRegionOuterBoundary
,
435 ev
->where
.v
- dragRegionOuterBoundary
,
436 ev
->where
.h
+ dragRegionOuterBoundary
,
437 ev
->where
.v
+ dragRegionOuterBoundary
) ;
440 tempRgn
, ev
->where
.h
- dragRegionInnerBoundary
,
441 ev
->where
.v
- dragRegionInnerBoundary
,
442 ev
->where
.h
+ dragRegionInnerBoundary
,
443 ev
->where
.v
+ dragRegionInnerBoundary
) ;
445 DiffRgn( dragRegion
, tempRgn
, dragRegion
) ;
446 DisposeRgn( tempRgn
) ;
448 // TODO: work with promises in order to return data
449 // only when drag was successfully completed
451 gTrackingGlobals
.m_currentSource
= this;
452 result
= TrackDrag( theDrag
, ev
, dragRegion
);
453 DisposeRgn( dragRegion
);
454 DisposeDrag( theDrag
);
455 gTrackingGlobals
.m_currentSource
= NULL
;
457 bool optionDown
= GetCurrentKeyModifiers() & optionKey
;
458 wxDragResult dndresult
= wxDragCopy
;
459 if ( flags
!= wxDrag_CopyOnly
)
460 // on mac the option key is always the indication for copy
461 dndresult
= optionDown
? wxDragCopy
: wxDragMove
;
466 bool wxDropSource::MacInstallDefaultCursor(wxDragResult effect
)
468 const wxCursor
& cursor
= GetCursor(effect
);
469 bool result
= cursor
.Ok();
477 bool gTrackingGlobalsInstalled
= false ;
479 // passing the globals via refcon is not needed by the CFM and later architectures anymore
480 // but I'll leave it in there, just in case...
482 pascal OSErr
wxMacWindowDragTrackingHandler(
483 DragTrackingMessage theMessage
, WindowPtr theWindow
,
484 void *handlerRefCon
, DragReference theDrag
);
485 pascal OSErr
wxMacWindowDragReceiveHandler(
486 WindowPtr theWindow
, void *handlerRefCon
,
487 DragReference theDrag
);
489 void wxMacEnsureTrackingHandlersInstalled()
491 if ( !gTrackingGlobalsInstalled
)
495 result
= InstallTrackingHandler( NewDragTrackingHandlerUPP(wxMacWindowDragTrackingHandler
), 0L, &gTrackingGlobals
);
496 wxASSERT( result
== noErr
);
498 result
= InstallReceiveHandler( NewDragReceiveHandlerUPP(wxMacWindowDragReceiveHandler
), 0L, &gTrackingGlobals
);
499 wxASSERT( result
== noErr
);
501 gTrackingGlobalsInstalled
= true;
505 pascal OSErr
wxMacWindowDragTrackingHandler(
506 DragTrackingMessage theMessage
, WindowPtr theWindow
,
507 void *handlerRefCon
, DragReference theDrag
)
509 MacTrackingGlobals
* trackingGlobals
= (MacTrackingGlobals
*) handlerRefCon
;
511 Point mouse
, localMouse
;
512 DragAttributes attributes
;
514 GetDragAttributes( theDrag
, &attributes
);
516 wxTopLevelWindowMac
* toplevel
= wxFindWinFromMacWindow( theWindow
) ;
518 bool optionDown
= GetCurrentKeyModifiers() & optionKey
;
519 wxDragResult result
= optionDown
? wxDragCopy
: wxDragMove
;
523 case kDragTrackingEnterHandler
:
524 case kDragTrackingLeaveHandler
:
527 case kDragTrackingEnterWindow
:
528 if (trackingGlobals
!= NULL
)
530 trackingGlobals
->m_currentTargetWindow
= NULL
;
531 trackingGlobals
->m_currentTarget
= NULL
;
535 case kDragTrackingInWindow
:
536 if (trackingGlobals
== NULL
)
538 if (toplevel
== NULL
)
541 GetDragMouse( theDrag
, &mouse
, 0L );
543 GlobalToLocal( &localMouse
);
546 wxWindow
*win
= NULL
;
547 ControlPartCode controlPart
;
548 ControlRef control
= wxMacFindControlUnderMouse(
549 toplevel
, localMouse
, theWindow
, &controlPart
) ;
551 win
= wxFindControlFromMacControl( control
) ;
555 int localx
, localy
;
556 localx
= localMouse
.h
;
557 localy
= localMouse
.v
;
560 win
->MacRootWindowToWindow( &localx
, &localy
) ;
561 if ( win
!= trackingGlobals
->m_currentTargetWindow
)
563 if ( trackingGlobals
->m_currentTargetWindow
)
565 // this window is left
566 if ( trackingGlobals
->m_currentTarget
)
568 HideDragHilite( theDrag
);
569 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
);
570 trackingGlobals
->m_currentTarget
->OnLeave();
571 trackingGlobals
->m_currentTarget
= NULL
;
572 trackingGlobals
->m_currentTargetWindow
= NULL
;
578 // this window is entered
579 trackingGlobals
->m_currentTargetWindow
= win
;
580 trackingGlobals
->m_currentTarget
= win
->GetDropTarget() ;
582 if ( trackingGlobals
->m_currentTarget
)
584 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
585 result
= trackingGlobals
->m_currentTarget
->OnEnter( localx
, localy
, result
) ;
588 if ( result
!= wxDragNone
)
593 win
->MacWindowToRootWindow( &x
, &y
) ;
594 RgnHandle hiliteRgn
= NewRgn() ;
595 Rect r
= { y
, x
, y
+ win
->GetSize().y
, x
+ win
->GetSize().x
} ;
596 RectRgn( hiliteRgn
, &r
) ;
597 ShowDragHilite( theDrag
, hiliteRgn
, true );
598 DisposeRgn( hiliteRgn
) ;
605 if ( trackingGlobals
->m_currentTarget
)
607 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
608 trackingGlobals
->m_currentTarget
->OnDragOver( localx
, localy
, result
) ;
612 // set cursor for OnEnter and OnDragOver
613 if ( trackingGlobals
->m_currentSource
&& !trackingGlobals
->m_currentSource
->GiveFeedback( result
) )
615 if ( !trackingGlobals
->m_currentSource
->MacInstallDefaultCursor( result
) )
621 wxCursor
cursor(wxCURSOR_COPY_ARROW
) ;
622 cursor
.MacInstall() ;
628 wxCursor
cursor(wxCURSOR_ARROW
) ;
629 cursor
.MacInstall() ;
635 wxCursor
cursor(wxCURSOR_NO_ENTRY
) ;
636 cursor
.MacInstall() ;
644 // put these here to make gcc happy
652 case kDragTrackingLeaveWindow
:
653 if (trackingGlobals
== NULL
)
656 if (trackingGlobals
->m_currentTarget
)
658 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
);
659 trackingGlobals
->m_currentTarget
->OnLeave();
660 HideDragHilite( theDrag
);
661 trackingGlobals
->m_currentTarget
= NULL
;
663 trackingGlobals
->m_currentTargetWindow
= NULL
;
673 pascal OSErr
wxMacWindowDragReceiveHandler(
676 DragReference theDrag
)
678 MacTrackingGlobals
* trackingGlobals
= (MacTrackingGlobals
*)handlerRefCon
;
679 if ( trackingGlobals
->m_currentTarget
)
681 Point mouse
, localMouse
;
684 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
685 GetDragMouse(theDrag
, &mouse
, 0L);
687 GlobalToLocal(&localMouse
);
688 localx
= localMouse
.h
;
689 localy
= localMouse
.v
;
691 // TODO : should we use client coordinates?
692 if ( trackingGlobals
->m_currentTargetWindow
)
693 trackingGlobals
->m_currentTargetWindow
->MacRootWindowToWindow( &localx
, &localy
) ;
694 if ( trackingGlobals
->m_currentTarget
->OnDrop( localx
, localy
) )
696 bool optionDown
= GetCurrentKeyModifiers() & optionKey
;
697 wxDragResult result
= optionDown
? wxDragCopy
: wxDragMove
;
698 trackingGlobals
->m_currentTarget
->OnData( localx
, localy
, result
) ;