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"
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 if ( wxApp::s_macDefaultEncodingIsPC
)
211 wxMacConvertToPC((char*)theData
,(char*)theData
,dataSize
) ;
213 m_dataObject
->SetData( format
, dataSize
, theData
);
215 else if ( theType
== kDragFlavorTypeHFS
)
217 HFSFlavor
* theFile
= (HFSFlavor
*) theData
;
218 wxString name
= wxMacFSSpec2MacFilename( &theFile
->fileSpec
) ;
219 if ( firstFileAdded
)
220 ((wxFileDataObject
*)m_dataObject
)->AddFile( name
) ;
223 ((wxFileDataObject
*)m_dataObject
)->SetData( 0 , name
.c_str() ) ;
224 firstFileAdded
= true ;
229 m_dataObject
->SetData( format
, dataSize
, theData
);
241 //-------------------------------------------------------------------------
243 //-------------------------------------------------------------------------
245 //-----------------------------------------------------------------------------
248 wxDropSource::wxDropSource(wxWindow
*win
,
249 const wxIcon
&iconCopy
,
250 const wxIcon
&iconMove
,
251 const wxIcon
&iconNone
)
253 wxMacEnsureTrackingHandlersInstalled() ;
257 wxDropSource::wxDropSource(wxDataObject
& data
,
259 const wxIcon
&iconCopy
,
260 const wxIcon
&iconMove
,
261 const wxIcon
&iconNone
)
263 wxMacEnsureTrackingHandlersInstalled() ;
268 wxDropSource::~wxDropSource()
273 wxDragResult
wxDropSource::DoDragDrop(int WXUNUSED(flags
))
275 wxASSERT_MSG( m_data
, wxT("Drop source: no data") );
278 return (wxDragResult
) wxDragNone
;
280 if (m_data
->GetFormatCount() == 0)
281 return (wxDragResult
) wxDragNone
;
284 DragReference theDrag
;
285 RgnHandle dragRegion
;
286 if ((result
= NewDrag(&theDrag
)))
291 size_t formatCount
= m_data
->GetFormatCount() ;
292 wxDataFormat
*formats
= new wxDataFormat
[formatCount
] ;
293 m_data
->GetAllFormats( formats
) ;
294 ItemReference theItem
= 1 ;
295 for ( size_t i
= 0 ; i
< formatCount
; ++i
)
297 size_t dataSize
= m_data
->GetDataSize( formats
[i
] ) ;
298 Ptr dataPtr
= new char[dataSize
] ;
299 m_data
->GetDataHere( formats
[i
] , dataPtr
) ;
300 OSType type
= formats
[i
].GetFormatId() ;
301 if ( type
== 'TEXT' )
304 if ( wxApp::s_macDefaultEncodingIsPC
)
306 wxMacConvertFromPC((char*)dataPtr
,(char*)dataPtr
,dataSize
) ;
308 AddDragItemFlavor(theDrag
, theItem
, type
, dataPtr
, dataSize
, 0);
310 else if (type
== kDragFlavorTypeHFS
)
312 HFSFlavor theFlavor
;
316 wxMacFilename2FSSpec( dataPtr
, &theFlavor
.fileSpec
) ;
318 cat
.hFileInfo
.ioNamePtr
= theFlavor
.fileSpec
.name
;
319 cat
.hFileInfo
.ioVRefNum
= theFlavor
.fileSpec
.vRefNum
;
320 cat
.hFileInfo
.ioDirID
= theFlavor
.fileSpec
.parID
;
321 cat
.hFileInfo
.ioFDirIndex
= 0;
322 err
= PBGetCatInfoSync(&cat
);
325 theFlavor
.fdFlags
= cat
.hFileInfo
.ioFlFndrInfo
.fdFlags
;
326 if (theFlavor
.fileSpec
.parID
== fsRtParID
) {
327 theFlavor
.fileCreator
= 'MACS';
328 theFlavor
.fileType
= 'disk';
329 } else if ((cat
.hFileInfo
.ioFlAttrib
& ioDirMask
) != 0) {
330 theFlavor
.fileCreator
= 'MACS';
331 theFlavor
.fileType
= 'fold';
333 theFlavor
.fileCreator
= cat
.hFileInfo
.ioFlFndrInfo
.fdCreator
;
334 theFlavor
.fileType
= cat
.hFileInfo
.ioFlFndrInfo
.fdType
;
336 AddDragItemFlavor(theDrag
, theItem
, type
, &theFlavor
, sizeof(theFlavor
), 0);
341 AddDragItemFlavor(theDrag
, theItem
, type
, dataPtr
, dataSize
, 0);
347 dragRegion
= NewRgn();
348 RgnHandle tempRgn
= NewRgn() ;
350 EventRecord
* ev
= NULL
;
351 #if !TARGET_CARBON // TODO
352 ev
= (EventRecord
*) wxTheApp
->MacGetCurrentEvent() ;
356 wxMacConvertEventToRecord( (EventRef
) wxTheApp
->MacGetCurrentEvent() , &rec
) ;
358 const short dragRegionOuterBoundary
= 10 ;
359 const short dragRegionInnerBoundary
= 9 ;
361 SetRectRgn( dragRegion
, ev
->where
.h
- dragRegionOuterBoundary
,
362 ev
->where
.v
- dragRegionOuterBoundary
,
363 ev
->where
.h
+ dragRegionOuterBoundary
,
364 ev
->where
.v
+ dragRegionOuterBoundary
) ;
366 SetRectRgn( tempRgn
, ev
->where
.h
- dragRegionInnerBoundary
,
367 ev
->where
.v
- dragRegionInnerBoundary
,
368 ev
->where
.h
+ dragRegionInnerBoundary
,
369 ev
->where
.v
+ dragRegionInnerBoundary
) ;
371 DiffRgn( dragRegion
, tempRgn
, dragRegion
) ;
372 DisposeRgn( tempRgn
) ;
374 // TODO:work with promises in order to return data only when drag
375 // was successfully completed
377 gTrackingGlobals
.m_currentSource
= this ;
378 result
= TrackDrag(theDrag
, ev
, dragRegion
);
379 DisposeRgn(dragRegion
);
380 DisposeDrag(theDrag
);
381 gTrackingGlobals
.m_currentSource
= NULL
;
386 bool gTrackingGlobalsInstalled
= false ;
388 // passing the globals via refcon is not needed by the CFM and later architectures anymore
389 // but I'll leave it in there, just in case...
391 pascal OSErr
wxMacWindowDragTrackingHandler(DragTrackingMessage theMessage
, WindowPtr theWindow
,
392 void *handlerRefCon
, DragReference theDrag
) ;
393 pascal OSErr
wxMacWindowDragReceiveHandler(WindowPtr theWindow
, void *handlerRefCon
,
394 DragReference theDrag
) ;
396 void wxMacEnsureTrackingHandlersInstalled()
398 if( !gTrackingGlobalsInstalled
)
402 result
= InstallTrackingHandler(NewDragTrackingHandlerUPP(wxMacWindowDragTrackingHandler
), 0L,&gTrackingGlobals
);
403 wxASSERT( result
== noErr
) ;
404 result
= InstallReceiveHandler(NewDragReceiveHandlerUPP(wxMacWindowDragReceiveHandler
), 0L, &gTrackingGlobals
);
405 wxASSERT( result
== noErr
) ;
407 gTrackingGlobalsInstalled
= true ;
411 pascal OSErr
wxMacWindowDragTrackingHandler(DragTrackingMessage theMessage
, WindowPtr theWindow
,
412 void *handlerRefCon
, DragReference theDrag
)
414 MacTrackingGlobals
* trackingGlobals
= (MacTrackingGlobals
*) handlerRefCon
;
415 Point mouse
, localMouse
;
416 DragAttributes attributes
;
417 GetDragAttributes(theDrag
, &attributes
);
418 wxTopLevelWindowMac
* toplevel
= wxFindWinFromMacWindow( theWindow
) ;
421 case kDragTrackingEnterHandler
:
423 case kDragTrackingLeaveHandler
:
425 case kDragTrackingEnterWindow
:
426 trackingGlobals
->m_currentTargetWindow
= NULL
;
427 trackingGlobals
->m_currentTarget
= NULL
;
429 case kDragTrackingInWindow
:
430 if (toplevel
== NULL
)
433 GetDragMouse(theDrag
, &mouse
, 0L);
435 GlobalToLocal(&localMouse
);
437 // if (attributes & kDragHasLeftSenderWindow)
439 wxPoint
point(localMouse
.h
, localMouse
.v
) ;
440 wxWindow
*win
= NULL
;
441 toplevel
->MacGetWindowFromPointSub( point
, &win
) ;
442 int localx
, localy
;
443 localx
= localMouse
.h
;
444 localy
= localMouse
.v
;
445 //TODO : should we use client coordinates
447 win
->MacRootWindowToWindow( &localx
, &localy
) ;
448 if ( win
!= trackingGlobals
->m_currentTargetWindow
)
450 if ( trackingGlobals
->m_currentTargetWindow
)
452 // this window is left
453 if ( trackingGlobals
->m_currentTarget
)
455 HideDragHilite(theDrag
);
456 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
457 trackingGlobals
->m_currentTarget
->OnLeave() ;
458 trackingGlobals
->m_currentTarget
= NULL
;
459 trackingGlobals
->m_currentTargetWindow
= NULL
;
464 // this window is entered
465 trackingGlobals
->m_currentTargetWindow
= win
;
466 trackingGlobals
->m_currentTarget
= win
->GetDropTarget() ;
467 if ( trackingGlobals
->m_currentTarget
)
469 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
470 if ( trackingGlobals
->m_currentTarget
->OnEnter(
471 localx
, localy
, wxDragCopy
) != wxDragNone
)
475 win
->MacWindowToRootWindow( &x
, &y
) ;
476 RgnHandle hiliteRgn
= NewRgn() ;
477 SetRectRgn( hiliteRgn
, x
, y
, x
+win
->GetSize().x
,y
+win
->GetSize().y
) ;
478 ShowDragHilite(theDrag
, hiliteRgn
, true);
479 DisposeRgn( hiliteRgn
) ;
486 if( trackingGlobals
->m_currentTarget
)
488 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
489 trackingGlobals
->m_currentTarget
->OnDragOver(
490 localx
, localy
, wxDragCopy
) ;
495 // MyTrackItemUnderMouse(localMouse, theWindow);
497 case kDragTrackingLeaveWindow
:
498 if (trackingGlobals
->m_currentTarget
)
500 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
501 trackingGlobals
->m_currentTarget
->OnLeave() ;
502 HideDragHilite(theDrag
);
503 trackingGlobals
->m_currentTarget
= NULL
;
505 trackingGlobals
->m_currentTargetWindow
= NULL
;
511 pascal OSErr
wxMacWindowDragReceiveHandler(WindowPtr theWindow
,
513 DragReference theDrag
)
515 MacTrackingGlobals
* trackingGlobals
= (MacTrackingGlobals
*) handlerRefCon
;
516 if ( trackingGlobals
->m_currentTarget
)
518 Point mouse
,localMouse
;
521 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
522 GetDragMouse(theDrag
, &mouse
, 0L);
524 GlobalToLocal(&localMouse
);
525 localx
= localMouse
.h
;
526 localy
= localMouse
.v
;
527 //TODO : should we use client coordinates
528 if ( trackingGlobals
->m_currentTargetWindow
)
529 trackingGlobals
->m_currentTargetWindow
->MacRootWindowToWindow( &localx
, &localy
) ;
530 if ( trackingGlobals
->m_currentTarget
->OnDrop( localx
, localy
) )
532 trackingGlobals
->m_currentTarget
->OnData( localx
, localy
, wxDragCopy
) ;