1 ///////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxDropTarget, wxDropSource, wxDataObject implementation
4 // Author: Stefan Csomor
8 // Copyright: (c) 1998 Stefan Csomor
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
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"
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 size_t 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((DragReference
)m_currentDrag
, &items
);
105 for (UInt16 index
= 1; index
<= items
&& supported
== false ; ++index
)
107 ItemReference theItem
;
110 GetDragItemReferenceNumber((DragReference
)m_currentDrag
, index
, &theItem
);
111 CountDragItemFlavors( (DragReference
)m_currentDrag
, theItem
, &flavors
) ;
112 for ( UInt16 flavor
= 1 ; flavor
<= flavors
; ++flavor
)
114 result
= GetFlavorType((DragReference
)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 size_t 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 bool firstFileAdded
= false ;
173 CountDragItems((DragReference
)m_currentDrag
, &items
);
174 for (UInt16 index
= 1; index
<= items
; ++index
)
176 ItemReference theItem
;
179 GetDragItemReferenceNumber((DragReference
)m_currentDrag
, index
, &theItem
);
180 CountDragItemFlavors( (DragReference
)m_currentDrag
, theItem
, &flavors
) ;
181 for ( UInt16 flavor
= 1 ; flavor
<= flavors
; ++flavor
)
183 result
= GetFlavorType((DragReference
)m_currentDrag
, theItem
, flavor
, &theType
);
184 wxDataFormat
format(theType
) ;
185 if ( m_dataObject
->IsSupportedFormat( format
) )
187 FlavorFlags theFlags
;
188 result
= GetFlavorFlags((DragReference
)m_currentDrag
, theItem
, theType
, &theFlags
);
193 GetFlavorDataSize((DragReference
)m_currentDrag
, theItem
, theType
, &dataSize
);
194 if ( theType
== 'TEXT' )
196 // this increment is only valid for allocating, on the next GetFlavorData
197 // call it is reset again to the original value
200 theData
= new char[dataSize
];
201 GetFlavorData((DragReference
)m_currentDrag
, theItem
, theType
, (void*) theData
, &dataSize
, 0L);
202 if( theType
== 'TEXT' )
204 theData
[dataSize
]=0 ;
205 wxString
convert( theData
, wxConvLocal
) ;
206 m_dataObject
->SetData( format
, convert
.Length() * sizeof(wxChar
), (const wxChar
*) convert
);
208 else if ( theType
== kDragFlavorTypeHFS
)
210 HFSFlavor
* theFile
= (HFSFlavor
*) theData
;
211 wxString name
= wxMacFSSpec2MacFilename( &theFile
->fileSpec
) ;
212 if ( firstFileAdded
)
213 ((wxFileDataObject
*)m_dataObject
)->AddFile( name
) ;
216 ((wxFileDataObject
*)m_dataObject
)->SetData( 0 , name
.c_str() ) ;
217 firstFileAdded
= true ;
222 m_dataObject
->SetData( format
, dataSize
, theData
);
234 //-------------------------------------------------------------------------
236 //-------------------------------------------------------------------------
238 //-----------------------------------------------------------------------------
241 wxDropSource::wxDropSource(wxWindow
*win
,
242 const wxCursor
&cursorCopy
,
243 const wxCursor
&cursorMove
,
244 const wxCursor
&cursorStop
)
245 : wxDropSourceBase(cursorCopy
, cursorMove
, cursorStop
)
247 wxMacEnsureTrackingHandlersInstalled() ;
251 wxDropSource::wxDropSource(wxDataObject
& data
,
253 const wxCursor
&cursorCopy
,
254 const wxCursor
&cursorMove
,
255 const wxCursor
&cursorStop
)
256 : wxDropSourceBase(cursorCopy
, cursorMove
, cursorStop
)
258 wxMacEnsureTrackingHandlersInstalled() ;
263 wxDropSource::~wxDropSource()
268 wxDragResult
wxDropSource::DoDragDrop(int WXUNUSED(flags
))
270 wxASSERT_MSG( m_data
, wxT("Drop source: no data") );
273 return (wxDragResult
) wxDragNone
;
275 if (m_data
->GetFormatCount() == 0)
276 return (wxDragResult
) wxDragNone
;
279 DragReference theDrag
;
280 RgnHandle dragRegion
;
281 if ((result
= NewDrag(&theDrag
)))
286 size_t formatCount
= m_data
->GetFormatCount() ;
287 wxDataFormat
*formats
= new wxDataFormat
[formatCount
] ;
288 m_data
->GetAllFormats( formats
) ;
289 ItemReference theItem
= 1 ;
290 for ( size_t i
= 0 ; i
< formatCount
; ++i
)
292 size_t dataSize
= m_data
->GetDataSize( formats
[i
] ) ;
293 Ptr dataPtr
= new char[dataSize
] ;
294 m_data
->GetDataHere( formats
[i
] , dataPtr
) ;
295 OSType type
= formats
[i
].GetFormatId() ;
296 if ( type
== 'TEXT' )
299 dataPtr
[ dataSize
] = 0 ;
300 wxString
st( (wxChar
*) dataPtr
) ;
301 wxCharBuffer buf
= st
.mb_str( wxConvLocal
) ;
302 AddDragItemFlavor(theDrag
, theItem
, type
, buf
.data(), strlen(buf
), 0);
304 else if (type
== kDragFlavorTypeHFS
)
306 HFSFlavor theFlavor
;
310 wxMacFilename2FSSpec( dataPtr
, &theFlavor
.fileSpec
) ;
312 cat
.hFileInfo
.ioNamePtr
= theFlavor
.fileSpec
.name
;
313 cat
.hFileInfo
.ioVRefNum
= theFlavor
.fileSpec
.vRefNum
;
314 cat
.hFileInfo
.ioDirID
= theFlavor
.fileSpec
.parID
;
315 cat
.hFileInfo
.ioFDirIndex
= 0;
316 err
= PBGetCatInfoSync(&cat
);
319 theFlavor
.fdFlags
= cat
.hFileInfo
.ioFlFndrInfo
.fdFlags
;
320 if (theFlavor
.fileSpec
.parID
== fsRtParID
) {
321 theFlavor
.fileCreator
= 'MACS';
322 theFlavor
.fileType
= 'disk';
323 } else if ((cat
.hFileInfo
.ioFlAttrib
& ioDirMask
) != 0) {
324 theFlavor
.fileCreator
= 'MACS';
325 theFlavor
.fileType
= 'fold';
327 theFlavor
.fileCreator
= cat
.hFileInfo
.ioFlFndrInfo
.fdCreator
;
328 theFlavor
.fileType
= cat
.hFileInfo
.ioFlFndrInfo
.fdType
;
330 AddDragItemFlavor(theDrag
, theItem
, type
, &theFlavor
, sizeof(theFlavor
), 0);
335 AddDragItemFlavor(theDrag
, theItem
, type
, dataPtr
, dataSize
, 0);
341 dragRegion
= NewRgn();
342 RgnHandle tempRgn
= NewRgn() ;
344 EventRecord
* ev
= NULL
;
345 #if !TARGET_CARBON // TODO
346 ev
= (EventRecord
*) wxTheApp
->MacGetCurrentEvent() ;
350 wxMacConvertEventToRecord( (EventRef
) wxTheApp
->MacGetCurrentEvent() , &rec
) ;
352 const short dragRegionOuterBoundary
= 10 ;
353 const short dragRegionInnerBoundary
= 9 ;
355 SetRectRgn( dragRegion
, ev
->where
.h
- dragRegionOuterBoundary
,
356 ev
->where
.v
- dragRegionOuterBoundary
,
357 ev
->where
.h
+ dragRegionOuterBoundary
,
358 ev
->where
.v
+ dragRegionOuterBoundary
) ;
360 SetRectRgn( tempRgn
, ev
->where
.h
- dragRegionInnerBoundary
,
361 ev
->where
.v
- dragRegionInnerBoundary
,
362 ev
->where
.h
+ dragRegionInnerBoundary
,
363 ev
->where
.v
+ dragRegionInnerBoundary
) ;
365 DiffRgn( dragRegion
, tempRgn
, dragRegion
) ;
366 DisposeRgn( tempRgn
) ;
368 // TODO:work with promises in order to return data only when drag
369 // was successfully completed
371 gTrackingGlobals
.m_currentSource
= this ;
372 result
= TrackDrag(theDrag
, ev
, dragRegion
);
373 DisposeRgn(dragRegion
);
374 DisposeDrag(theDrag
);
375 gTrackingGlobals
.m_currentSource
= NULL
;
379 bool optionDown
= keymap
[1] & 4;
380 wxDragResult dndresult
= optionDown
? wxDragCopy
: wxDragMove
;
384 bool wxDropSource::MacInstallDefaultCursor(wxDragResult effect
)
386 const wxCursor
& cursor
= GetCursor(effect
);
389 cursor
.MacInstall() ;
399 bool gTrackingGlobalsInstalled
= false ;
401 // passing the globals via refcon is not needed by the CFM and later architectures anymore
402 // but I'll leave it in there, just in case...
404 pascal OSErr
wxMacWindowDragTrackingHandler(DragTrackingMessage theMessage
, WindowPtr theWindow
,
405 void *handlerRefCon
, DragReference theDrag
) ;
406 pascal OSErr
wxMacWindowDragReceiveHandler(WindowPtr theWindow
, void *handlerRefCon
,
407 DragReference theDrag
) ;
409 void wxMacEnsureTrackingHandlersInstalled()
411 if( !gTrackingGlobalsInstalled
)
415 result
= InstallTrackingHandler(NewDragTrackingHandlerUPP(wxMacWindowDragTrackingHandler
), 0L,&gTrackingGlobals
);
416 wxASSERT( result
== noErr
) ;
417 result
= InstallReceiveHandler(NewDragReceiveHandlerUPP(wxMacWindowDragReceiveHandler
), 0L, &gTrackingGlobals
);
418 wxASSERT( result
== noErr
) ;
420 gTrackingGlobalsInstalled
= true ;
424 pascal OSErr
wxMacWindowDragTrackingHandler(DragTrackingMessage theMessage
, WindowPtr theWindow
,
425 void *handlerRefCon
, DragReference theDrag
)
427 MacTrackingGlobals
* trackingGlobals
= (MacTrackingGlobals
*) handlerRefCon
;
428 Point mouse
, localMouse
;
429 DragAttributes attributes
;
430 GetDragAttributes(theDrag
, &attributes
);
431 wxTopLevelWindowMac
* toplevel
= wxFindWinFromMacWindow( (WXWindow
) theWindow
) ;
435 bool optionDown
= keymap
[1] & 4;
436 wxDragResult result
= optionDown
? wxDragCopy
: wxDragMove
;
440 case kDragTrackingEnterHandler
:
442 case kDragTrackingLeaveHandler
:
444 case kDragTrackingEnterWindow
:
445 trackingGlobals
->m_currentTargetWindow
= NULL
;
446 trackingGlobals
->m_currentTarget
= NULL
;
448 case kDragTrackingInWindow
:
449 if (toplevel
== NULL
)
452 GetDragMouse(theDrag
, &mouse
, 0L);
454 GlobalToLocal(&localMouse
);
458 // if (attributes & kDragHasLeftSenderWindow)
460 wxPoint
point(localMouse
.h
, localMouse
.v
) ;
461 wxWindow
*win
= NULL
;
462 toplevel
->MacGetWindowFromPointSub( point
, &win
) ;
463 int localx
, localy
;
464 localx
= localMouse
.h
;
465 localy
= localMouse
.v
;
466 //TODO : should we use client coordinates
468 win
->MacRootWindowToWindow( &localx
, &localy
) ;
469 if ( win
!= trackingGlobals
->m_currentTargetWindow
)
471 if ( trackingGlobals
->m_currentTargetWindow
)
473 // this window is left
474 if ( trackingGlobals
->m_currentTarget
)
476 HideDragHilite(theDrag
);
477 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
478 trackingGlobals
->m_currentTarget
->OnLeave() ;
479 trackingGlobals
->m_currentTarget
= NULL
;
480 trackingGlobals
->m_currentTargetWindow
= NULL
;
485 // this window is entered
486 trackingGlobals
->m_currentTargetWindow
= win
;
487 trackingGlobals
->m_currentTarget
= win
->GetDropTarget() ;
490 if ( trackingGlobals
->m_currentTarget
)
492 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
493 result
= trackingGlobals
->m_currentTarget
->OnEnter(
494 localx
, localy
, result
) ;
498 if ( result
!= wxDragNone
)
502 win
->MacWindowToRootWindow( &x
, &y
) ;
503 RgnHandle hiliteRgn
= NewRgn() ;
504 SetRectRgn( hiliteRgn
, x
, y
, x
+win
->GetSize().x
,y
+win
->GetSize().y
) ;
505 ShowDragHilite(theDrag
, hiliteRgn
, true);
506 DisposeRgn( hiliteRgn
) ;
513 if( trackingGlobals
->m_currentTarget
)
515 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
516 trackingGlobals
->m_currentTarget
->OnDragOver(
517 localx
, localy
, result
) ;
521 // set cursor for OnEnter and OnDragOver
522 if ( trackingGlobals
->m_currentSource
&& trackingGlobals
->m_currentSource
->GiveFeedback( result
) == FALSE
)
524 if ( trackingGlobals
->m_currentSource
->MacInstallDefaultCursor( result
) == FALSE
)
530 wxCursor
cursor(wxCURSOR_COPY_ARROW
) ;
531 cursor
.MacInstall() ;
536 wxCursor
cursor(wxCURSOR_ARROW
) ;
537 cursor
.MacInstall() ;
542 wxCursor
cursor(wxCURSOR_NO_ENTRY
) ;
543 cursor
.MacInstall() ;
550 // put these here to make gcc happy
557 // MyTrackItemUnderMouse(localMouse, theWindow);
559 case kDragTrackingLeaveWindow
:
560 if (trackingGlobals
->m_currentTarget
)
562 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
563 trackingGlobals
->m_currentTarget
->OnLeave() ;
564 HideDragHilite(theDrag
);
565 trackingGlobals
->m_currentTarget
= NULL
;
567 trackingGlobals
->m_currentTargetWindow
= NULL
;
573 pascal OSErr
wxMacWindowDragReceiveHandler(WindowPtr theWindow
,
575 DragReference theDrag
)
577 MacTrackingGlobals
* trackingGlobals
= (MacTrackingGlobals
*) handlerRefCon
;
578 if ( trackingGlobals
->m_currentTarget
)
580 Point mouse
,localMouse
;
583 trackingGlobals
->m_currentTarget
->SetCurrentDrag( theDrag
) ;
584 GetDragMouse(theDrag
, &mouse
, 0L);
586 GlobalToLocal(&localMouse
);
587 localx
= localMouse
.h
;
588 localy
= localMouse
.v
;
589 //TODO : should we use client coordinates
590 if ( trackingGlobals
->m_currentTargetWindow
)
591 trackingGlobals
->m_currentTargetWindow
->MacRootWindowToWindow( &localx
, &localy
) ;
592 if ( trackingGlobals
->m_currentTarget
->OnDrop( localx
, localy
) )
596 bool optionDown
= keymap
[1] & 4;
597 wxDragResult result
= optionDown
? wxDragCopy
: wxDragMove
;
598 trackingGlobals
->m_currentTarget
->OnData( localx
, localy
, result
) ;