1 ///////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxDropTarget, wxDropSource, wxDataObject implementation
8 // Copyright: (c) 1998 AUTHOR
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"
26 // ----------------------------------------------------------------------------
28 // ----------------------------------------------------------------------------
30 void wxMacEnsureTrackingHandlersInstalled() ;
34 wxWindow
* m_currentTargetWindow
;
35 wxDropTarget
* m_currentTarget
;
36 wxDropSource
* m_currentSource
;
37 } MacTrackingGlobals
;
39 MacTrackingGlobals gTrackingGlobals
;
41 //----------------------------------------------------------------------------
43 //----------------------------------------------------------------------------
45 wxDropTarget::wxDropTarget( wxDataObject
*data
)
46 : wxDropTargetBase( data
)
48 wxMacEnsureTrackingHandlersInstalled() ;
51 wxDragResult
wxDropTarget::OnDragOver( wxCoord
WXUNUSED(x
),
56 return CurrentDragHasSupportedFormat() ? def
: wxDragNone
;
59 bool wxDropTarget::OnDrop( wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
) )
64 return CurrentDragHasSupportedFormat() ;
67 wxDragResult
wxDropTarget::OnData( wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
),
73 if (!CurrentDragHasSupportedFormat())
76 return GetData() ? def
: wxDragNone
;
79 bool wxDropTarget::CurrentDragHasSupportedFormat()
81 bool supported
= false ;
82 if ( gTrackingGlobals
.m_currentSource
!= NULL
)
84 wxDataObject
* data
= gTrackingGlobals
.m_currentSource
->GetDataObject() ;
88 int formatcount
= data
->GetFormatCount() ;
89 wxDataFormat
*array
= new wxDataFormat
[ formatcount
];
90 data
->GetAllFormats( array
);
91 for (size_t i
= 0; !supported
&& i
< formatcount
; i
++)
93 wxDataFormat format
= array
[i
] ;
94 if ( m_dataObject
->IsSupported( format
) )
107 CountDragItems(m_currentDrag
, &items
);
108 for (UInt16 index
= 1; index
<= items
&& supported
== false ; ++index
)
110 ItemReference theItem
;
113 GetDragItemReferenceNumber(m_currentDrag
, index
, &theItem
);
114 CountDragItemFlavors( m_currentDrag
, theItem
, &flavors
) ;
115 for ( UInt16 flavor
= 1 ; flavor
<= flavors
; ++flavor
)
117 result
= GetFlavorType(m_currentDrag
, theItem
, flavor
, &theType
);
118 if ( m_dataObject
->IsSupportedFormat( wxDataFormat( theType
) ) )
129 bool wxDropTarget::GetData()
134 if ( !CurrentDragHasSupportedFormat() )
137 bool transferred
= false ;
138 if ( gTrackingGlobals
.m_currentSource
!= NULL
)
140 wxDataObject
* data
= gTrackingGlobals
.m_currentSource
->GetDataObject() ;
144 int formatcount
= data
->GetFormatCount() ;
145 wxDataFormat
*array
= new wxDataFormat
[ formatcount
];
146 data
->GetAllFormats( array
);
147 for (size_t i
= 0; !transferred
&& i
< formatcount
; i
++)
149 wxDataFormat format
= array
[i
] ;
150 if ( m_dataObject
->IsSupported( format
) )
152 int size
= data
->GetDataSize( format
);
157 m_dataObject
->SetData(format
, 0 , 0 ) ;
161 char *d
= new char[size
];
162 data
->GetDataHere( format
, (void*) d
);
163 m_dataObject
->SetData( format
, size
, d
) ;
175 CountDragItems(m_currentDrag
, &items
);
176 for (UInt16 index
= 1; index
<= items
; ++index
)
178 ItemReference theItem
;
181 GetDragItemReferenceNumber(m_currentDrag
, index
, &theItem
);
182 CountDragItemFlavors( m_currentDrag
, theItem
, &flavors
) ;
183 for ( UInt16 flavor
= 1 ; flavor
<= flavors
; ++flavor
)
185 result
= GetFlavorType(m_currentDrag
, theItem
, flavor
, &theType
);
186 wxDataFormat
format(theType
) ;
187 if ( m_dataObject
->IsSupportedFormat( format
) )
189 FlavorFlags theFlags
;
190 result
= GetFlavorFlags(m_currentDrag
, theItem
, theType
, &theFlags
);
195 GetFlavorDataSize(m_currentDrag
, theItem
, theType
, &dataSize
);
196 if ( theType
== 'TEXT' )
198 theData
= new char[dataSize
];
199 GetFlavorData(m_currentDrag
, theItem
, theType
, (void*) theData
, &dataSize
, 0L);
200 if( theType
== 'TEXT' )
202 theData
[dataSize
]=0 ;
203 if ( wxApp::s_macDefaultEncodingIsPC
)
205 wxMacConvertToPC((char*)theData
) ;
207 m_dataObject
->SetData( format
, dataSize
, theData
);
209 else if ( theType
== kDragFlavorTypeHFS
)
211 HFSFlavor
* theFile
= (HFSFlavor
*) theData
;
212 wxString name
= wxMacFSSpec2MacFilename( &theFile
->fileSpec
) ;
213 m_dataObject
->SetData( format
, name
.Length() + 1, name
) ;
217 m_dataObject
->SetData( format
, dataSize
, theData
);
229 //-------------------------------------------------------------------------
231 //-------------------------------------------------------------------------
233 //-----------------------------------------------------------------------------
236 wxDropSource::wxDropSource(wxWindow
*win
,
237 const wxIcon
&iconCopy
,
238 const wxIcon
&iconMove
,
239 const wxIcon
&iconNone
)
241 wxMacEnsureTrackingHandlersInstalled() ;
245 wxDropSource::wxDropSource(wxDataObject
& data
,
247 const wxIcon
&iconCopy
,
248 const wxIcon
&iconMove
,
249 const wxIcon
&iconNone
)
251 wxMacEnsureTrackingHandlersInstalled() ;
256 wxDropSource::~wxDropSource()
261 wxDragResult
wxDropSource::DoDragDrop( bool allowMove
)
263 wxASSERT_MSG( m_data
, wxT("Drop source: no data") );
266 return (wxDragResult
) wxDragNone
;
268 if (m_data
->GetFormatCount() == 0)
269 return (wxDragResult
) wxDragNone
;
272 DragReference theDrag
;
273 RgnHandle dragRegion
;
274 if (result
= NewDrag(&theDrag
))
279 size_t formatCount
= m_data
->GetFormatCount() ;
280 wxDataFormat
*formats
= new wxDataFormat
[formatCount
] ;
281 m_data
->GetAllFormats( formats
) ;
282 ItemReference theItem
= 1 ;
283 for ( int i
= 0 ; i
< formatCount
; ++i
)
285 size_t dataSize
= m_data
->GetDataSize( formats
[i
] ) ;
286 Ptr dataPtr
= new char[dataSize
] ;
287 m_data
->GetDataHere( formats
[i
] , dataPtr
) ;
288 OSType type
= formats
[i
].GetFormatId() ;
289 if ( type
== 'TEXT' )
292 if ( wxApp::s_macDefaultEncodingIsPC
)
294 wxMacConvertFromPC((char*)dataPtr
) ;
296 AddDragItemFlavor(theDrag
, theItem
, type
, dataPtr
, dataSize
, 0);
298 else if (type
== kDragFlavorTypeHFS
)
300 HFSFlavor theFlavor
;
304 wxMacFilename2FSSpec( dataPtr
, &theFlavor
.fileSpec
) ;
306 cat
.hFileInfo
.ioNamePtr
= theFlavor
.fileSpec
.name
;
307 cat
.hFileInfo
.ioVRefNum
= theFlavor
.fileSpec
.vRefNum
;
308 cat
.hFileInfo
.ioDirID
= theFlavor
.fileSpec
.parID
;
309 cat
.hFileInfo
.ioFDirIndex
= 0;
310 err
= PBGetCatInfoSync(&cat
);
313 theFlavor
.fdFlags
= cat
.hFileInfo
.ioFlFndrInfo
.fdFlags
;
314 if (theFlavor
.fileSpec
.parID
== fsRtParID
) {
315 theFlavor
.fileCreator
= 'MACS';
316 theFlavor
.fileType
= 'disk';
317 } else if ((cat
.hFileInfo
.ioFlAttrib
& ioDirMask
) != 0) {
318 theFlavor
.fileCreator
= 'MACS';
319 theFlavor
.fileType
= 'fold';
321 theFlavor
.fileCreator
= cat
.hFileInfo
.ioFlFndrInfo
.fdCreator
;
322 theFlavor
.fileType
= cat
.hFileInfo
.ioFlFndrInfo
.fdType
;
324 AddDragItemFlavor(theDrag
, theItem
, type
, &theFlavor
, sizeof(theFlavor
), 0);
329 AddDragItemFlavor(theDrag
, theItem
, type
, dataPtr
, dataSize
, 0);
335 dragRegion
= NewRgn();
336 RgnHandle tempRgn
= NewRgn() ;
338 EventRecord
* ev
= wxTheApp
->MacGetCurrentEvent() ;
339 const short dragRegionOuterBoundary
= 10 ;
340 const short dragRegionInnerBoundary
= 9 ;
342 SetRectRgn( dragRegion
, ev
->where
.h
- dragRegionOuterBoundary
,
343 ev
->where
.v
- dragRegionOuterBoundary
,
344 ev
->where
.h
+ dragRegionOuterBoundary
,
345 ev
->where
.v
+ dragRegionOuterBoundary
) ;
347 SetRectRgn( tempRgn
, ev
->where
.h
- dragRegionInnerBoundary
,
348 ev
->where
.v
- dragRegionInnerBoundary
,
349 ev
->where
.h
+ dragRegionInnerBoundary
,
350 ev
->where
.v
+ dragRegionInnerBoundary
) ;
352 DiffRgn( dragRegion
, tempRgn
, dragRegion
) ;
353 DisposeRgn( tempRgn
) ;
355 // TODO:work with promises in order to return data only when drag
356 // was successfully completed
358 gTrackingGlobals
.m_currentSource
= this ;
359 result
= TrackDrag(theDrag
, ev
, dragRegion
);
360 DisposeRgn(dragRegion
);
361 DisposeDrag(theDrag
);
362 gTrackingGlobals
.m_currentSource
= NULL
;
367 bool gTrackingGlobalsInstalled
= false ;
369 // passing the globals via refcon is not needed by the CFM and later architectures anymore
370 // but I'll leave it in there, just in case...
372 pascal OSErr
wxMacWindowDragTrackingHandler(DragTrackingMessage theMessage
, WindowPtr theWindow
,
373 void *handlerRefCon
, DragReference theDrag
) ;
374 pascal OSErr
wxMacWindowDragReceiveHandler(WindowPtr theWindow
, void *handlerRefCon
,
375 DragReference theDrag
) ;
377 void wxMacEnsureTrackingHandlersInstalled()
379 if( !gTrackingGlobalsInstalled
)
383 result
= InstallTrackingHandler(NewDragTrackingHandlerUPP(wxMacWindowDragTrackingHandler
), 0L,&gTrackingGlobals
);
384 wxASSERT( result
== noErr
) ;
385 result
= InstallReceiveHandler(NewDragReceiveHandlerUPP(wxMacWindowDragReceiveHandler
), 0L, &gTrackingGlobals
);
386 wxASSERT( result
== noErr
) ;
388 gTrackingGlobalsInstalled
= true ;
392 pascal OSErr
wxMacWindowDragTrackingHandler(DragTrackingMessage theMessage
, WindowPtr theWindow
,
393 void *handlerRefCon
, DragReference theDrag
)
395 MacTrackingGlobals
* trackingGlobals
= (MacTrackingGlobals
*) handlerRefCon
;
396 Point mouse
, localMouse
;
397 DragAttributes attributes
;
399 GetDragAttributes(theDrag
, &attributes
);
400 wxTopLevelWindowMac
* toplevel
= wxFindWinFromMacWindow( theWindow
) ;
403 case kDragTrackingEnterHandler
:
405 case kDragTrackingLeaveHandler
:
407 case kDragTrackingEnterWindow
:
408 trackingGlobals
->m_currentTargetWindow
= NULL
;
409 trackingGlobals
->m_currentTarget
= NULL
;
411 case kDragTrackingInWindow
:
412 if (toplevel
== NULL
)
415 GetDragMouse(theDrag
, &mouse
, 0L);
417 GlobalToLocal(&localMouse
);
419 // if (attributes & kDragHasLeftSenderWindow)
421 wxPoint
point(localMouse
.h
, localMouse
.v
) ;
422 wxWindow
*win
= NULL
;
423 toplevel
->MacGetWindowFromPointSub( point
, &win
) ;
424 int localx
, localy
;
425 localx
= localMouse
.h
;
426 localy
= localMouse
.v
;
427 //TODO : should we use client coordinates
429 win
->MacRootWindowToWindow( &localx
, &localy
) ;
430 if ( win
!= trackingGlobals
->m_currentTargetWindow
)
432 if ( trackingGlobals
->m_currentTargetWindow
)
434 // this window is left
435 if ( trackingGlobals
->m_currentTarget
)
437 HideDragHilite(theDrag
);
438 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
439 trackingGlobals
->m_currentTarget
->OnLeave() ;
440 trackingGlobals
->m_currentTarget
= NULL
;
441 trackingGlobals
->m_currentTargetWindow
= NULL
;
446 // this window is entered
447 trackingGlobals
->m_currentTargetWindow
= win
;
448 trackingGlobals
->m_currentTarget
= win
->GetDropTarget() ;
449 if ( trackingGlobals
->m_currentTarget
)
451 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
452 if ( trackingGlobals
->m_currentTarget
->OnEnter(
453 localx
, localy
, wxDragCopy
) != wxDragNone
)
457 win
->MacWindowToRootWindow( &x
, &y
) ;
458 RgnHandle hiliteRgn
= NewRgn() ;
459 SetRectRgn( hiliteRgn
, x
, y
, x
+win
->GetSize().x
,y
+win
->GetSize().y
) ;
460 ShowDragHilite(theDrag
, hiliteRgn
, true);
461 DisposeRgn( hiliteRgn
) ;
468 if( trackingGlobals
->m_currentTarget
)
470 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
471 trackingGlobals
->m_currentTarget
->OnDragOver(
472 localx
, localy
, wxDragCopy
) ;
477 // MyTrackItemUnderMouse(localMouse, theWindow);
479 case kDragTrackingLeaveWindow
:
480 if (trackingGlobals
->m_currentTarget
)
482 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
483 trackingGlobals
->m_currentTarget
->OnLeave() ;
484 HideDragHilite(theDrag
);
485 trackingGlobals
->m_currentTarget
= NULL
;
487 trackingGlobals
->m_currentTargetWindow
= NULL
;
493 pascal OSErr
wxMacWindowDragReceiveHandler(WindowPtr theWindow
, void *handlerRefCon
,
494 DragReference theDrag
)
496 MacTrackingGlobals
* trackingGlobals
= (MacTrackingGlobals
*) handlerRefCon
;
497 if ( trackingGlobals
->m_currentTarget
)
499 Point mouse
,localMouse
;
502 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
503 GetDragMouse(theDrag
, &mouse
, 0L);
505 GlobalToLocal(&localMouse
);
506 localx
= localMouse
.h
;
507 localy
= localMouse
.v
;
508 //TODO : should we use client coordinates
509 if ( trackingGlobals
->m_currentTargetWindow
)
510 trackingGlobals
->m_currentTargetWindow
->MacRootWindowToWindow( &localx
, &localy
) ;
511 if ( trackingGlobals
->m_currentTarget
->OnDrop( localx
, localy
) )
513 trackingGlobals
->m_currentTarget
->OnData( localx
, localy
, wxDragCopy
) ;