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