1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/carbon/dnd.cpp
3 // Purpose: wxDropTarget, wxDropSource implementations
4 // Author: Stefan Csomor
7 // Copyright: (c) 1998 Stefan Csomor
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 #include "wx/wxprec.h"
13 #if wxUSE_DRAG_AND_DROP
19 #include "wx/toplevel.h"
20 #include "wx/gdicmn.h"
23 #include "wx/osx/private.h"
25 // ----------------------------------------------------------------------------
27 // ----------------------------------------------------------------------------
31 wxWindow
*m_currentTargetWindow
;
32 wxDropTarget
*m_currentTarget
;
33 wxDropSource
*m_currentSource
;
34 wxDragResult m_result
;
38 MacTrackingGlobals gTrackingGlobals
;
40 void wxMacEnsureTrackingHandlersInstalled();
42 OSStatus
wxMacPromiseKeeper(PasteboardRef
WXUNUSED(inPasteboard
),
43 PasteboardItemID
WXUNUSED(inItem
),
44 CFStringRef
WXUNUSED(inFlavorType
),
45 void * WXUNUSED(inContext
))
49 // we might add promises here later, inContext is the wxDropSource*
54 wxDropTarget::wxDropTarget( wxDataObject
*data
)
55 : wxDropTargetBase( data
)
57 wxMacEnsureTrackingHandlersInstalled();
61 //-------------------------------------------------------------------------
63 //-------------------------------------------------------------------------
65 wxDropSource::wxDropSource(wxWindow
*win
,
66 const wxCursor
&cursorCopy
,
67 const wxCursor
&cursorMove
,
68 const wxCursor
&cursorStop
)
69 : wxDropSourceBase(cursorCopy
, cursorMove
, cursorStop
)
71 wxMacEnsureTrackingHandlersInstalled();
76 wxDropSource
* wxDropSource::GetCurrentDropSource()
78 return gTrackingGlobals
.m_currentSource
;
81 wxDropSource::wxDropSource(wxDataObject
& data
,
83 const wxCursor
&cursorCopy
,
84 const wxCursor
&cursorMove
,
85 const wxCursor
&cursorStop
)
86 : wxDropSourceBase(cursorCopy
, cursorMove
, cursorStop
)
88 wxMacEnsureTrackingHandlersInstalled();
94 wxDragResult
wxDropSource::DoDragDrop(int flags
)
96 wxASSERT_MSG( m_data
, wxT("Drop source: no data") );
98 if ((m_data
== NULL
) || (m_data
->GetFormatCount() == 0))
99 return (wxDragResult
)wxDragNone
;
101 DragReference theDrag
;
102 RgnHandle dragRegion
;
103 OSStatus err
= noErr
;
104 PasteboardRef pasteboard
;
108 err
= PasteboardCreate( kPasteboardUniqueName
, &pasteboard
);
112 // we add a dummy promise keeper because of strange messages when linking against carbon debug
113 err
= PasteboardSetPromiseKeeper( pasteboard
, wxMacPromiseKeeper
, this );
116 CFRelease( pasteboard
);
120 err
= PasteboardClear( pasteboard
);
123 CFRelease( pasteboard
);
126 PasteboardSynchronize( pasteboard
);
128 m_data
->AddToPasteboard( pasteboard
, 1 );
130 if (NewDragWithPasteboard( pasteboard
, &theDrag
) != noErr
)
132 CFRelease( pasteboard
);
136 dragRegion
= NewRgn();
137 RgnHandle tempRgn
= NewRgn();
140 ConvertEventRefToEventRecord( (EventRef
) wxTheApp
->MacGetCurrentEvent(), &rec
);
142 const short dragRegionOuterBoundary
= 10;
143 const short dragRegionInnerBoundary
= 9;
147 rec
.where
.h
- dragRegionOuterBoundary
,
148 rec
.where
.v
- dragRegionOuterBoundary
,
149 rec
.where
.h
+ dragRegionOuterBoundary
,
150 rec
.where
.v
+ dragRegionOuterBoundary
);
154 rec
.where
.h
- dragRegionInnerBoundary
,
155 rec
.where
.v
- dragRegionInnerBoundary
,
156 rec
.where
.h
+ dragRegionInnerBoundary
,
157 rec
.where
.v
+ dragRegionInnerBoundary
);
159 DiffRgn( dragRegion
, tempRgn
, dragRegion
);
160 DisposeRgn( tempRgn
);
162 // TODO: work with promises in order to return data
163 // only when drag was successfully completed
165 gTrackingGlobals
.m_currentSource
= this;
166 gTrackingGlobals
.m_result
= wxDragNone
;
167 gTrackingGlobals
.m_flags
= flags
;
169 err
= TrackDrag( theDrag
, &rec
, dragRegion
);
171 DisposeRgn( dragRegion
);
172 DisposeDrag( theDrag
);
173 CFRelease( pasteboard
);
174 gTrackingGlobals
.m_currentSource
= NULL
;
176 return gTrackingGlobals
.m_result
;
179 bool gTrackingGlobalsInstalled
= false;
181 // passing the globals via refcon is not needed by the CFM and later architectures anymore
182 // but I'll leave it in there, just in case...
184 pascal OSErr
wxMacWindowDragTrackingHandler(
185 DragTrackingMessage theMessage
, WindowPtr theWindow
,
186 void *handlerRefCon
, DragReference theDrag
);
187 pascal OSErr
wxMacWindowDragReceiveHandler(
188 WindowPtr theWindow
, void *handlerRefCon
,
189 DragReference theDrag
);
191 void wxMacEnsureTrackingHandlersInstalled()
193 if ( !gTrackingGlobalsInstalled
)
197 err
= InstallTrackingHandler( NewDragTrackingHandlerUPP(wxMacWindowDragTrackingHandler
), 0L, &gTrackingGlobals
);
200 err
= InstallReceiveHandler( NewDragReceiveHandlerUPP(wxMacWindowDragReceiveHandler
), 0L, &gTrackingGlobals
);
203 gTrackingGlobalsInstalled
= true;
207 pascal OSErr
wxMacWindowDragTrackingHandler(
208 DragTrackingMessage theMessage
, WindowPtr theWindow
,
209 void *handlerRefCon
, DragReference theDrag
)
211 MacTrackingGlobals
* trackingGlobals
= (MacTrackingGlobals
*) handlerRefCon
;
213 Point mouse
, localMouse
;
214 DragAttributes attributes
;
216 GetDragAttributes( theDrag
, &attributes
);
217 PasteboardRef pasteboard
= 0;
218 GetDragPasteboard( theDrag
, &pasteboard
);
219 wxNonOwnedWindow
* toplevel
= wxNonOwnedWindow::GetFromWXWindow( (WXWindow
) theWindow
);
221 bool optionDown
= GetCurrentKeyModifiers() & optionKey
;
222 wxDragResult result
= optionDown
? wxDragCopy
: wxDragMove
;
226 case kDragTrackingEnterHandler
:
227 case kDragTrackingLeaveHandler
:
230 case kDragTrackingEnterWindow
:
231 if (trackingGlobals
!= NULL
)
233 trackingGlobals
->m_currentTargetWindow
= NULL
;
234 trackingGlobals
->m_currentTarget
= NULL
;
238 case kDragTrackingInWindow
:
239 if (trackingGlobals
== NULL
)
241 if (toplevel
== NULL
)
244 GetDragMouse( theDrag
, &mouse
, 0L );
248 toplevel
->GetNonOwnedPeer()->ScreenToWindow( &x
, &y
);
253 wxWindow
*win
= NULL
;
254 ControlPartCode controlPart
;
255 ControlRef control
= FindControlUnderMouse( localMouse
, theWindow
, &controlPart
);
257 win
= wxFindWindowFromWXWidget( (WXWidget
) control
);
262 localx
= localMouse
.h
;
263 localy
= localMouse
.v
;
266 win
->MacRootWindowToWindow( &localx
, &localy
);
267 if ( win
!= trackingGlobals
->m_currentTargetWindow
)
269 if ( trackingGlobals
->m_currentTargetWindow
)
271 // this window is left
272 if ( trackingGlobals
->m_currentTarget
)
274 HideDragHilite( theDrag
);
275 trackingGlobals
->m_currentTarget
->SetCurrentDragPasteboard( pasteboard
);
276 trackingGlobals
->m_currentTarget
->OnLeave();
277 trackingGlobals
->m_currentTarget
= NULL
;
278 trackingGlobals
->m_currentTargetWindow
= NULL
;
284 // this window is entered
285 trackingGlobals
->m_currentTargetWindow
= win
;
286 trackingGlobals
->m_currentTarget
= win
->GetDropTarget();
288 if ( trackingGlobals
->m_currentTarget
)
290 trackingGlobals
->m_currentTarget
->SetCurrentDragPasteboard( pasteboard
);
291 result
= trackingGlobals
->m_currentTarget
->OnEnter( localx
, localy
, result
);
294 if ( result
!= wxDragNone
)
299 win
->MacWindowToRootWindow( &x
, &y
);
300 RgnHandle hiliteRgn
= NewRgn();
301 Rect r
= { y
, x
, y
+ win
->GetSize().y
, x
+ win
->GetSize().x
};
302 RectRgn( hiliteRgn
, &r
);
303 ShowDragHilite( theDrag
, hiliteRgn
, true );
304 DisposeRgn( hiliteRgn
);
311 if ( trackingGlobals
->m_currentTarget
)
313 trackingGlobals
->m_currentTarget
->SetCurrentDragPasteboard( pasteboard
);
314 result
= trackingGlobals
->m_currentTarget
->OnDragOver( localx
, localy
, result
);
318 // set cursor for OnEnter and OnDragOver
319 if ( trackingGlobals
->m_currentSource
&& !trackingGlobals
->m_currentSource
->GiveFeedback( result
) )
321 if ( !trackingGlobals
->m_currentSource
->MacInstallDefaultCursor( result
) )
323 wxStockCursor cursorID
= wxCURSOR_NONE
;
328 cursorID
= wxCURSOR_COPY_ARROW
;
332 cursorID
= wxCURSOR_ARROW
;
336 cursorID
= wxCURSOR_NO_ENTRY
;
343 // put these here to make gcc happy
347 if (cursorID
!= wxCURSOR_NONE
)
349 wxCursor
cursor( cursorID
);
358 case kDragTrackingLeaveWindow
:
359 if (trackingGlobals
== NULL
)
362 if (trackingGlobals
->m_currentTarget
)
364 trackingGlobals
->m_currentTarget
->SetCurrentDragPasteboard( pasteboard
);
365 trackingGlobals
->m_currentTarget
->OnLeave();
366 HideDragHilite( theDrag
);
367 trackingGlobals
->m_currentTarget
= NULL
;
369 trackingGlobals
->m_currentTargetWindow
= NULL
;
379 pascal OSErr
wxMacWindowDragReceiveHandler(
382 DragReference theDrag
)
384 MacTrackingGlobals
* trackingGlobals
= (MacTrackingGlobals
*)handlerRefCon
;
385 if ( trackingGlobals
->m_currentTarget
)
387 Point mouse
, localMouse
;
390 PasteboardRef pasteboard
= 0;
391 GetDragPasteboard( theDrag
, &pasteboard
);
392 trackingGlobals
->m_currentTarget
->SetCurrentDragPasteboard( pasteboard
);
393 GetDragMouse( theDrag
, &mouse
, 0L );
395 localx
= localMouse
.h
;
396 localy
= localMouse
.v
;
397 wxNonOwnedWindow
* tlw
= wxNonOwnedWindow::GetFromWXWindow((WXWindow
) theWindow
);
399 tlw
->GetNonOwnedPeer()->ScreenToWindow( &localx
, &localy
);
401 // TODO : should we use client coordinates?
402 if ( trackingGlobals
->m_currentTargetWindow
)
403 trackingGlobals
->m_currentTargetWindow
->MacRootWindowToWindow( &localx
, &localy
);
404 if ( trackingGlobals
->m_currentTarget
->OnDrop( localx
, localy
) )
406 // the option key indicates copy in Mac UI, if it's not pressed do
407 // move by default if it's allowed at all
409 result
= !(trackingGlobals
->m_flags
& wxDrag_AllowMove
) ||
410 (GetCurrentKeyModifiers() & optionKey
)
413 trackingGlobals
->m_result
=
414 trackingGlobals
->m_currentTarget
->OnData( localx
, localy
, result
);
421 #endif // wxUSE_DRAG_AND_DROP