1 ///////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxDropTarget, wxDropSource, wxDataObject implementation
8 // Copyright: (c) 1998 AUTHOR
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "dnd.h"
17 #include "wx/window.h"
19 #include "wx/gdicmn.h"
21 #if wxUSE_DRAG_AND_DROP
23 // ----------------------------------------------------------------------------
25 // ----------------------------------------------------------------------------
27 void wxMacEnsureTrackingHandlersInstalled() ;
31 wxWindow
* m_currentTargetWindow
;
32 wxDropTarget
* m_currentTarget
;
33 wxDropSource
* m_currentSource
;
34 } MacTrackingGlobals
;
36 MacTrackingGlobals gTrackingGlobals
;
38 //----------------------------------------------------------------------------
40 //----------------------------------------------------------------------------
42 wxDropTarget::wxDropTarget( wxDataObject
*data
)
43 : wxDropTargetBase( data
)
45 wxMacEnsureTrackingHandlersInstalled() ;
48 wxDragResult
wxDropTarget::OnDragOver( wxCoord
WXUNUSED(x
),
53 return CurrentDragHasSupportedFormat() ? def
: wxDragNone
;
56 bool wxDropTarget::OnDrop( wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
) )
61 return CurrentDragHasSupportedFormat() ;
64 wxDragResult
wxDropTarget::OnData( wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
),
70 if (!CurrentDragHasSupportedFormat())
73 return GetData() ? def
: wxDragNone
;
76 bool wxDropTarget::CurrentDragHasSupportedFormat()
78 bool supported
= false ;
79 if ( gTrackingGlobals
.m_currentSource
!= NULL
)
81 wxDataObject
* data
= gTrackingGlobals
.m_currentSource
->GetDataObject() ;
85 int formatcount
= data
->GetFormatCount() ;
86 wxDataFormat
*array
= new wxDataFormat
[ formatcount
];
87 data
->GetAllFormats( array
);
88 for (size_t i
= 0; !supported
&& i
< formatcount
; i
++)
90 wxDataFormat format
= array
[i
] ;
91 if ( m_dataObject
->IsSupported( format
) )
104 CountDragItems(m_currentDrag
, &items
);
105 for (UInt16 index
= 1; index
<= items
&& supported
== false ; ++index
)
107 ItemReference theItem
;
110 GetDragItemReferenceNumber(m_currentDrag
, index
, &theItem
);
111 CountDragItemFlavors( m_currentDrag
, theItem
, &flavors
) ;
112 for ( UInt16 flavor
= 1 ; flavor
<= flavors
; ++flavor
)
114 result
= GetFlavorType(m_currentDrag
, theItem
, flavor
, &theType
);
115 if ( m_dataObject
->IsSupportedFormat( wxDataFormat( theType
) ) )
126 bool wxDropTarget::GetData()
131 if ( !CurrentDragHasSupportedFormat() )
134 bool transferred
= false ;
135 if ( gTrackingGlobals
.m_currentSource
!= NULL
)
137 wxDataObject
* data
= gTrackingGlobals
.m_currentSource
->GetDataObject() ;
141 int formatcount
= data
->GetFormatCount() ;
142 wxDataFormat
*array
= new wxDataFormat
[ formatcount
];
143 data
->GetAllFormats( array
);
144 for (size_t i
= 0; !transferred
&& i
< formatcount
; i
++)
146 wxDataFormat format
= array
[i
] ;
147 if ( m_dataObject
->IsSupported( format
) )
149 int size
= data
->GetDataSize( format
);
154 m_dataObject
->SetData(format
, 0 , 0 ) ;
158 char *d
= new char[size
];
159 data
->GetDataHere( format
, (void*) d
);
160 m_dataObject
->SetData( format
, size
, d
) ;
172 CountDragItems(m_currentDrag
, &items
);
173 for (UInt16 index
= 1; index
<= items
; ++index
)
175 ItemReference theItem
;
178 GetDragItemReferenceNumber(m_currentDrag
, index
, &theItem
);
179 CountDragItemFlavors( m_currentDrag
, theItem
, &flavors
) ;
180 for ( UInt16 flavor
= 1 ; flavor
<= flavors
; ++flavor
)
182 result
= GetFlavorType(m_currentDrag
, theItem
, flavor
, &theType
);
183 wxDataFormat
format(theType
) ;
184 if ( m_dataObject
->IsSupportedFormat( format
) )
186 FlavorFlags theFlags
;
187 result
= GetFlavorFlags(m_currentDrag
, theItem
, theType
, &theFlags
);
192 GetFlavorDataSize(m_currentDrag
, theItem
, theType
, &dataSize
);
193 if ( theType
== 'TEXT' )
195 theData
= new char[dataSize
];
196 GetFlavorData(m_currentDrag
, theItem
, theType
, (void*) theData
, &dataSize
, 0L);
197 if( theType
== 'TEXT' )
199 theData
[dataSize
]=0 ;
200 if ( wxApp::s_macDefaultEncodingIsPC
)
202 wxMacConvertToPC((char*)theData
) ;
204 m_dataObject
->SetData( format
, dataSize
, theData
);
206 else if ( theType
== kDragFlavorTypeHFS
)
208 HFSFlavor
* theFile
= (HFSFlavor
*) theData
;
209 wxString name
= wxMacFSSpec2MacFilename( &theFile
->fileSpec
) ;
210 m_dataObject
->SetData( format
, name
.Length() + 1, name
) ;
214 m_dataObject
->SetData( format
, dataSize
, theData
);
226 //-------------------------------------------------------------------------
228 //-------------------------------------------------------------------------
230 //-----------------------------------------------------------------------------
233 wxDropSource::wxDropSource(wxWindow
*win
,
234 const wxIcon
&iconCopy
,
235 const wxIcon
&iconMove
,
236 const wxIcon
&iconNone
)
238 wxMacEnsureTrackingHandlersInstalled() ;
242 wxDropSource::wxDropSource(wxDataObject
& data
,
244 const wxIcon
&iconCopy
,
245 const wxIcon
&iconMove
,
246 const wxIcon
&iconNone
)
248 wxMacEnsureTrackingHandlersInstalled() ;
253 wxDropSource::~wxDropSource()
258 wxDragResult
wxDropSource::DoDragDrop( bool allowMove
)
260 wxASSERT_MSG( m_data
, wxT("Drop source: no data") );
263 return (wxDragResult
) wxDragNone
;
265 if (m_data
->GetFormatCount() == 0)
266 return (wxDragResult
) wxDragNone
;
269 DragReference theDrag
;
270 RgnHandle dragRegion
;
271 if (result
= NewDrag(&theDrag
))
276 size_t formatCount
= m_data
->GetFormatCount() ;
277 wxDataFormat
*formats
= new wxDataFormat
[formatCount
] ;
278 m_data
->GetAllFormats( formats
) ;
279 ItemReference theItem
= 1 ;
280 for ( int i
= 0 ; i
< formatCount
; ++i
)
282 size_t dataSize
= m_data
->GetDataSize( formats
[i
] ) ;
283 Ptr dataPtr
= new char[dataSize
] ;
284 m_data
->GetDataHere( formats
[i
] , dataPtr
) ;
285 OSType type
= formats
[i
].GetFormatId() ;
286 if ( type
== 'TEXT' )
289 if ( wxApp::s_macDefaultEncodingIsPC
)
291 wxMacConvertFromPC((char*)dataPtr
) ;
293 AddDragItemFlavor(theDrag
, theItem
, type
, dataPtr
, dataSize
, 0);
295 else if (type
== kDragFlavorTypeHFS
)
297 HFSFlavor theFlavor
;
301 wxMacFilename2FSSpec( dataPtr
, &theFlavor
.fileSpec
) ;
303 cat
.hFileInfo
.ioNamePtr
= theFlavor
.fileSpec
.name
;
304 cat
.hFileInfo
.ioVRefNum
= theFlavor
.fileSpec
.vRefNum
;
305 cat
.hFileInfo
.ioDirID
= theFlavor
.fileSpec
.parID
;
306 cat
.hFileInfo
.ioFDirIndex
= 0;
307 err
= PBGetCatInfoSync(&cat
);
310 theFlavor
.fdFlags
= cat
.hFileInfo
.ioFlFndrInfo
.fdFlags
;
311 if (theFlavor
.fileSpec
.parID
== fsRtParID
) {
312 theFlavor
.fileCreator
= 'MACS';
313 theFlavor
.fileType
= 'disk';
314 } else if ((cat
.hFileInfo
.ioFlAttrib
& ioDirMask
) != 0) {
315 theFlavor
.fileCreator
= 'MACS';
316 theFlavor
.fileType
= 'fold';
318 theFlavor
.fileCreator
= cat
.hFileInfo
.ioFlFndrInfo
.fdCreator
;
319 theFlavor
.fileType
= cat
.hFileInfo
.ioFlFndrInfo
.fdType
;
321 AddDragItemFlavor(theDrag
, theItem
, type
, &theFlavor
, sizeof(theFlavor
), 0);
326 AddDragItemFlavor(theDrag
, theItem
, type
, dataPtr
, dataSize
, 0);
332 dragRegion
= NewRgn();
333 RgnHandle tempRgn
= NewRgn() ;
335 EventRecord
* ev
= wxTheApp
->MacGetCurrentEvent() ;
336 const short dragRegionOuterBoundary
= 10 ;
337 const short dragRegionInnerBoundary
= 9 ;
339 SetRectRgn( dragRegion
, ev
->where
.h
- dragRegionOuterBoundary
,
340 ev
->where
.v
- dragRegionOuterBoundary
,
341 ev
->where
.h
+ dragRegionOuterBoundary
,
342 ev
->where
.v
+ dragRegionOuterBoundary
) ;
344 SetRectRgn( tempRgn
, ev
->where
.h
- dragRegionInnerBoundary
,
345 ev
->where
.v
- dragRegionInnerBoundary
,
346 ev
->where
.h
+ dragRegionInnerBoundary
,
347 ev
->where
.v
+ dragRegionInnerBoundary
) ;
349 DiffRgn( dragRegion
, tempRgn
, dragRegion
) ;
350 DisposeRgn( tempRgn
) ;
352 // TODO:work with promises in order to return data only when drag
353 // was successfully completed
355 gTrackingGlobals
.m_currentSource
= this ;
356 result
= TrackDrag(theDrag
, ev
, dragRegion
);
357 DisposeRgn(dragRegion
);
358 DisposeDrag(theDrag
);
359 gTrackingGlobals
.m_currentSource
= NULL
;
364 bool gTrackingGlobalsInstalled
= false ;
366 // passing the globals via refcon is not needed by the CFM and later architectures anymore
367 // but I'll leave it in there, just in case...
369 pascal OSErr
wxMacWindowDragTrackingHandler(DragTrackingMessage theMessage
, WindowPtr theWindow
,
370 void *handlerRefCon
, DragReference theDrag
) ;
371 pascal OSErr
wxMacWindowDragReceiveHandler(WindowPtr theWindow
, void *handlerRefCon
,
372 DragReference theDrag
) ;
374 void wxMacEnsureTrackingHandlersInstalled()
376 if( !gTrackingGlobalsInstalled
)
380 result
= InstallTrackingHandler(NewDragTrackingHandlerUPP(wxMacWindowDragTrackingHandler
), 0L,&gTrackingGlobals
);
381 wxASSERT( result
== noErr
) ;
382 result
= InstallReceiveHandler(NewDragReceiveHandlerUPP(wxMacWindowDragReceiveHandler
), 0L, &gTrackingGlobals
);
383 wxASSERT( result
== noErr
) ;
385 gTrackingGlobalsInstalled
= true ;
389 pascal OSErr
wxMacWindowDragTrackingHandler(DragTrackingMessage theMessage
, WindowPtr theWindow
,
390 void *handlerRefCon
, DragReference theDrag
)
392 MacTrackingGlobals
* trackingGlobals
= (MacTrackingGlobals
*) handlerRefCon
;
393 Point mouse
, localMouse
;
394 DragAttributes attributes
;
396 GetDragAttributes(theDrag
, &attributes
);
397 wxTopLevelWindowMac
* toplevel
= wxFindWinFromMacWindow( theWindow
) ;
400 case kDragTrackingEnterHandler
:
402 case kDragTrackingLeaveHandler
:
404 case kDragTrackingEnterWindow
:
405 trackingGlobals
->m_currentTargetWindow
= NULL
;
406 trackingGlobals
->m_currentTarget
= NULL
;
408 case kDragTrackingInWindow
:
409 if (toplevel
== NULL
)
412 GetDragMouse(theDrag
, &mouse
, 0L);
414 GlobalToLocal(&localMouse
);
416 // if (attributes & kDragHasLeftSenderWindow)
418 wxPoint
point(localMouse
.h
, localMouse
.v
) ;
419 wxWindow
*win
= NULL
;
420 toplevel
->MacGetWindowFromPointSub( point
, &win
) ;
421 int localx
, localy
;
422 localx
= localMouse
.h
;
423 localy
= localMouse
.v
;
424 //TODO : should we use client coordinates
426 win
->MacRootWindowToWindow( &localx
, &localy
) ;
427 if ( win
!= trackingGlobals
->m_currentTargetWindow
)
429 if ( trackingGlobals
->m_currentTargetWindow
)
431 // this window is left
432 if ( trackingGlobals
->m_currentTarget
)
434 HideDragHilite(theDrag
);
435 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
436 trackingGlobals
->m_currentTarget
->OnLeave() ;
437 trackingGlobals
->m_currentTarget
= NULL
;
438 trackingGlobals
->m_currentTargetWindow
= NULL
;
443 // this window is entered
444 trackingGlobals
->m_currentTargetWindow
= win
;
445 trackingGlobals
->m_currentTarget
= win
->GetDropTarget() ;
446 if ( trackingGlobals
->m_currentTarget
)
448 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
449 if ( trackingGlobals
->m_currentTarget
->OnEnter(
450 localx
, localy
, wxDragCopy
) != wxDragNone
)
454 win
->MacWindowToRootWindow( &x
, &y
) ;
455 RgnHandle hiliteRgn
= NewRgn() ;
456 SetRectRgn( hiliteRgn
, x
, y
, x
+win
->GetSize().x
,y
+win
->GetSize().y
) ;
457 ShowDragHilite(theDrag
, hiliteRgn
, true);
458 DisposeRgn( hiliteRgn
) ;
465 if( trackingGlobals
->m_currentTarget
)
467 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
468 trackingGlobals
->m_currentTarget
->OnDragOver(
469 localx
, localy
, wxDragCopy
) ;
474 // MyTrackItemUnderMouse(localMouse, theWindow);
476 case kDragTrackingLeaveWindow
:
477 if (trackingGlobals
->m_currentTarget
)
479 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
480 trackingGlobals
->m_currentTarget
->OnLeave() ;
481 HideDragHilite(theDrag
);
482 trackingGlobals
->m_currentTarget
= NULL
;
484 trackingGlobals
->m_currentTargetWindow
= NULL
;
490 pascal OSErr
wxMacWindowDragReceiveHandler(WindowPtr theWindow
, void *handlerRefCon
,
491 DragReference theDrag
)
493 MacTrackingGlobals
* trackingGlobals
= (MacTrackingGlobals
*) handlerRefCon
;
494 if ( trackingGlobals
->m_currentTarget
)
496 Point mouse
,localMouse
;
499 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
500 GetDragMouse(theDrag
, &mouse
, 0L);
502 GlobalToLocal(&localMouse
);
503 localx
= localMouse
.h
;
504 localy
= localMouse
.v
;
505 //TODO : should we use client coordinates
506 if ( trackingGlobals
->m_currentTargetWindow
)
507 trackingGlobals
->m_currentTargetWindow
->MacRootWindowToWindow( &localx
, &localy
) ;
508 if ( trackingGlobals
->m_currentTarget
->OnDrop( localx
, localy
) )
510 trackingGlobals
->m_currentTarget
->OnData( localx
, localy
, wxDragCopy
) ;