1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/carbon/dnd.cpp
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
20 #include "wx/toplevel.h"
21 #include "wx/gdicmn.h"
24 #include "wx/osx/private.h"
26 // ----------------------------------------------------------------------------
28 // ----------------------------------------------------------------------------
32 wxWindow
*m_currentTargetWindow
;
33 wxDropTarget
*m_currentTarget
;
34 wxDropSource
*m_currentSource
;
35 wxDragResult m_result
;
39 MacTrackingGlobals gTrackingGlobals
;
41 void wxMacEnsureTrackingHandlersInstalled();
43 OSStatus
wxMacPromiseKeeper(PasteboardRef
WXUNUSED(inPasteboard
),
44 PasteboardItemID
WXUNUSED(inItem
),
45 CFStringRef
WXUNUSED(inFlavorType
),
46 void * WXUNUSED(inContext
))
50 // we might add promises here later, inContext is the wxDropSource*
55 wxDropTarget::wxDropTarget( wxDataObject
*data
)
56 : wxDropTargetBase( data
)
58 wxMacEnsureTrackingHandlersInstalled();
62 //-------------------------------------------------------------------------
64 //-------------------------------------------------------------------------
66 wxDropSource::wxDropSource(wxWindow
*win
,
67 const wxCursor
&cursorCopy
,
68 const wxCursor
&cursorMove
,
69 const wxCursor
&cursorStop
)
70 : wxDropSourceBase(cursorCopy
, cursorMove
, cursorStop
)
72 wxMacEnsureTrackingHandlersInstalled();
77 wxDropSource
* wxDropSource::GetCurrentDropSource()
79 return gTrackingGlobals
.m_currentSource
;
82 wxDropSource::wxDropSource(wxDataObject
& data
,
84 const wxCursor
&cursorCopy
,
85 const wxCursor
&cursorMove
,
86 const wxCursor
&cursorStop
)
87 : wxDropSourceBase(cursorCopy
, cursorMove
, cursorStop
)
89 wxMacEnsureTrackingHandlersInstalled();
95 wxDragResult
wxDropSource::DoDragDrop(int flags
)
97 wxASSERT_MSG( m_data
, wxT("Drop source: no data") );
99 if ((m_data
== NULL
) || (m_data
->GetFormatCount() == 0))
100 return (wxDragResult
)wxDragNone
;
102 DragReference theDrag
;
103 RgnHandle dragRegion
;
104 OSStatus err
= noErr
;
105 PasteboardRef pasteboard
;
109 err
= PasteboardCreate( kPasteboardUniqueName
, &pasteboard
);
113 // we add a dummy promise keeper because of strange messages when linking against carbon debug
114 err
= PasteboardSetPromiseKeeper( pasteboard
, wxMacPromiseKeeper
, this );
117 CFRelease( pasteboard
);
121 err
= PasteboardClear( pasteboard
);
124 CFRelease( pasteboard
);
127 PasteboardSynchronize( pasteboard
);
129 m_data
->AddToPasteboard( pasteboard
, 1 );
131 if (NewDragWithPasteboard( pasteboard
, &theDrag
) != noErr
)
133 CFRelease( pasteboard
);
137 dragRegion
= NewRgn();
138 RgnHandle tempRgn
= NewRgn();
141 ConvertEventRefToEventRecord( (EventRef
) wxTheApp
->MacGetCurrentEvent(), &rec
);
143 const short dragRegionOuterBoundary
= 10;
144 const short dragRegionInnerBoundary
= 9;
148 rec
.where
.h
- dragRegionOuterBoundary
,
149 rec
.where
.v
- dragRegionOuterBoundary
,
150 rec
.where
.h
+ dragRegionOuterBoundary
,
151 rec
.where
.v
+ dragRegionOuterBoundary
);
155 rec
.where
.h
- dragRegionInnerBoundary
,
156 rec
.where
.v
- dragRegionInnerBoundary
,
157 rec
.where
.h
+ dragRegionInnerBoundary
,
158 rec
.where
.v
+ dragRegionInnerBoundary
);
160 DiffRgn( dragRegion
, tempRgn
, dragRegion
);
161 DisposeRgn( tempRgn
);
163 // TODO: work with promises in order to return data
164 // only when drag was successfully completed
166 gTrackingGlobals
.m_currentSource
= this;
167 gTrackingGlobals
.m_result
= wxDragNone
;
168 gTrackingGlobals
.m_flags
= flags
;
170 err
= TrackDrag( theDrag
, &rec
, dragRegion
);
172 DisposeRgn( dragRegion
);
173 DisposeDrag( theDrag
);
174 CFRelease( pasteboard
);
175 gTrackingGlobals
.m_currentSource
= NULL
;
177 return gTrackingGlobals
.m_result
;
180 bool gTrackingGlobalsInstalled
= false;
182 // passing the globals via refcon is not needed by the CFM and later architectures anymore
183 // but I'll leave it in there, just in case...
185 pascal OSErr
wxMacWindowDragTrackingHandler(
186 DragTrackingMessage theMessage
, WindowPtr theWindow
,
187 void *handlerRefCon
, DragReference theDrag
);
188 pascal OSErr
wxMacWindowDragReceiveHandler(
189 WindowPtr theWindow
, void *handlerRefCon
,
190 DragReference theDrag
);
192 void wxMacEnsureTrackingHandlersInstalled()
194 if ( !gTrackingGlobalsInstalled
)
198 err
= InstallTrackingHandler( NewDragTrackingHandlerUPP(wxMacWindowDragTrackingHandler
), 0L, &gTrackingGlobals
);
201 err
= InstallReceiveHandler( NewDragReceiveHandlerUPP(wxMacWindowDragReceiveHandler
), 0L, &gTrackingGlobals
);
204 gTrackingGlobalsInstalled
= true;
208 pascal OSErr
wxMacWindowDragTrackingHandler(
209 DragTrackingMessage theMessage
, WindowPtr theWindow
,
210 void *handlerRefCon
, DragReference theDrag
)
212 MacTrackingGlobals
* trackingGlobals
= (MacTrackingGlobals
*) handlerRefCon
;
214 Point mouse
, localMouse
;
215 DragAttributes attributes
;
217 GetDragAttributes( theDrag
, &attributes
);
218 PasteboardRef pasteboard
= 0;
219 GetDragPasteboard( theDrag
, &pasteboard
);
220 wxNonOwnedWindow
* toplevel
= wxNonOwnedWindow::GetFromWXWindow( (WXWindow
) theWindow
);
222 bool optionDown
= GetCurrentKeyModifiers() & optionKey
;
223 wxDragResult result
= optionDown
? wxDragCopy
: wxDragMove
;
227 case kDragTrackingEnterHandler
:
228 case kDragTrackingLeaveHandler
:
231 case kDragTrackingEnterWindow
:
232 if (trackingGlobals
!= NULL
)
234 trackingGlobals
->m_currentTargetWindow
= NULL
;
235 trackingGlobals
->m_currentTarget
= NULL
;
239 case kDragTrackingInWindow
:
240 if (trackingGlobals
== NULL
)
242 if (toplevel
== NULL
)
245 GetDragMouse( theDrag
, &mouse
, 0L );
249 toplevel
->GetNonOwnedPeer()->ScreenToWindow( &x
, &y
);
254 wxWindow
*win
= NULL
;
255 ControlPartCode controlPart
;
256 ControlRef control
= FindControlUnderMouse( localMouse
, theWindow
, &controlPart
);
258 win
= wxFindWindowFromWXWidget( (WXWidget
) control
);
263 localx
= localMouse
.h
;
264 localy
= localMouse
.v
;
267 win
->MacRootWindowToWindow( &localx
, &localy
);
268 if ( win
!= trackingGlobals
->m_currentTargetWindow
)
270 if ( trackingGlobals
->m_currentTargetWindow
)
272 // this window is left
273 if ( trackingGlobals
->m_currentTarget
)
275 HideDragHilite( theDrag
);
276 trackingGlobals
->m_currentTarget
->SetCurrentDragPasteboard( pasteboard
);
277 trackingGlobals
->m_currentTarget
->OnLeave();
278 trackingGlobals
->m_currentTarget
= NULL
;
279 trackingGlobals
->m_currentTargetWindow
= NULL
;
285 // this window is entered
286 trackingGlobals
->m_currentTargetWindow
= win
;
287 trackingGlobals
->m_currentTarget
= win
->GetDropTarget();
289 if ( trackingGlobals
->m_currentTarget
)
291 trackingGlobals
->m_currentTarget
->SetCurrentDragPasteboard( pasteboard
);
292 result
= trackingGlobals
->m_currentTarget
->OnEnter( localx
, localy
, result
);
295 if ( result
!= wxDragNone
)
300 win
->MacWindowToRootWindow( &x
, &y
);
301 RgnHandle hiliteRgn
= NewRgn();
302 Rect r
= { y
, x
, y
+ win
->GetSize().y
, x
+ win
->GetSize().x
};
303 RectRgn( hiliteRgn
, &r
);
304 ShowDragHilite( theDrag
, hiliteRgn
, true );
305 DisposeRgn( hiliteRgn
);
312 if ( trackingGlobals
->m_currentTarget
)
314 trackingGlobals
->m_currentTarget
->SetCurrentDragPasteboard( pasteboard
);
315 result
= trackingGlobals
->m_currentTarget
->OnDragOver( localx
, localy
, result
);
319 // set cursor for OnEnter and OnDragOver
320 if ( trackingGlobals
->m_currentSource
&& !trackingGlobals
->m_currentSource
->GiveFeedback( result
) )
322 if ( !trackingGlobals
->m_currentSource
->MacInstallDefaultCursor( result
) )
324 wxStockCursor cursorID
= wxCURSOR_NONE
;
329 cursorID
= wxCURSOR_COPY_ARROW
;
333 cursorID
= wxCURSOR_ARROW
;
337 cursorID
= wxCURSOR_NO_ENTRY
;
344 // put these here to make gcc happy
348 if (cursorID
!= wxCURSOR_NONE
)
350 wxCursor
cursor( cursorID
);
359 case kDragTrackingLeaveWindow
:
360 if (trackingGlobals
== NULL
)
363 if (trackingGlobals
->m_currentTarget
)
365 trackingGlobals
->m_currentTarget
->SetCurrentDragPasteboard( pasteboard
);
366 trackingGlobals
->m_currentTarget
->OnLeave();
367 HideDragHilite( theDrag
);
368 trackingGlobals
->m_currentTarget
= NULL
;
370 trackingGlobals
->m_currentTargetWindow
= NULL
;
380 pascal OSErr
wxMacWindowDragReceiveHandler(
383 DragReference theDrag
)
385 MacTrackingGlobals
* trackingGlobals
= (MacTrackingGlobals
*)handlerRefCon
;
386 if ( trackingGlobals
->m_currentTarget
)
388 Point mouse
, localMouse
;
391 PasteboardRef pasteboard
= 0;
392 GetDragPasteboard( theDrag
, &pasteboard
);
393 trackingGlobals
->m_currentTarget
->SetCurrentDragPasteboard( pasteboard
);
394 GetDragMouse( theDrag
, &mouse
, 0L );
396 localx
= localMouse
.h
;
397 localy
= localMouse
.v
;
398 wxNonOwnedWindow
* tlw
= wxNonOwnedWindow::GetFromWXWindow((WXWindow
) theWindow
);
400 tlw
->GetNonOwnedPeer()->ScreenToWindow( &localx
, &localy
);
402 // TODO : should we use client coordinates?
403 if ( trackingGlobals
->m_currentTargetWindow
)
404 trackingGlobals
->m_currentTargetWindow
->MacRootWindowToWindow( &localx
, &localy
);
405 if ( trackingGlobals
->m_currentTarget
->OnDrop( localx
, localy
) )
407 // the option key indicates copy in Mac UI, if it's not pressed do
408 // move by default if it's allowed at all
410 result
= !(trackingGlobals
->m_flags
& wxDrag_AllowMove
) ||
411 (GetCurrentKeyModifiers() & optionKey
)
414 trackingGlobals
->m_result
=
415 trackingGlobals
->m_currentTarget
->OnData( localx
, localy
, result
);
422 #endif // wxUSE_DRAG_AND_DROP