]> git.saurik.com Git - wxWidgets.git/blame - src/mac/carbon/dnd.cpp
cleanup mac
[wxWidgets.git] / src / mac / carbon / dnd.cpp
CommitLineData
e9576ca5 1///////////////////////////////////////////////////////////////////////////////
670f9935 2// Name: src/mac/carbon/dnd.cpp
6eae1f7d 3// Purpose: wxDropTarget, wxDropSource implementations
a31a5f85 4// Author: Stefan Csomor
e9576ca5 5// Modified by:
a31a5f85 6// Created: 1998-01-01
e9576ca5 7// RCS-ID: $Id$
a31a5f85 8// Copyright: (c) 1998 Stefan Csomor
65571936 9// Licence: wxWindows licence
e9576ca5
SC
10///////////////////////////////////////////////////////////////////////////////
11
3d1a4878 12#include "wx/wxprec.h"
ff143598
GD
13
14#if wxUSE_DRAG_AND_DROP
15
e9576ca5 16#include "wx/dnd.h"
670f9935
WS
17
18#ifndef WX_PRECOMP
19 #include "wx/app.h"
1832043f 20 #include "wx/toplevel.h"
dd05139a 21 #include "wx/gdicmn.h"
670f9935
WS
22#endif // WX_PRECOMP
23
76a5e5d2 24#include "wx/mac/private.h"
e9576ca5
SC
25
26// ----------------------------------------------------------------------------
6eae1f7d 27// globals
e9576ca5
SC
28// ----------------------------------------------------------------------------
29
6eae1f7d 30typedef struct
e9576ca5 31{
51d4293d
DS
32 wxWindow *m_currentTargetWindow;
33 wxDropTarget *m_currentTarget;
34 wxDropSource *m_currentSource;
56d152b2
VZ
35 wxDragResult m_result;
36 int m_flags;
716d0327 37} MacTrackingGlobals;
e9576ca5 38
e22ab33a 39MacTrackingGlobals gTrackingGlobals;
6eae1f7d 40
51d4293d 41void wxMacEnsureTrackingHandlersInstalled();
e9576ca5 42
a07c1212
SC
43//----------------------------------------------------------------------------
44// wxDropTarget
45//----------------------------------------------------------------------------
e9576ca5 46
a07c1212
SC
47wxDropTarget::wxDropTarget( wxDataObject *data )
48 : wxDropTargetBase( data )
e9576ca5 49{
51d4293d 50 wxMacEnsureTrackingHandlersInstalled();
e9576ca5
SC
51}
52
51d4293d
DS
53wxDragResult wxDropTarget::OnDragOver(
54 wxCoord WXUNUSED(x), wxCoord WXUNUSED(y),
55 wxDragResult def )
e9576ca5 56{
a07c1212
SC
57 return CurrentDragHasSupportedFormat() ? def : wxDragNone;
58}
e9576ca5 59
a07c1212 60bool wxDropTarget::OnDrop( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y) )
e9576ca5 61{
876b960a 62 if (m_dataObject == NULL)
6eae1f7d 63 return false;
a07c1212 64
51d4293d 65 return CurrentDragHasSupportedFormat();
e9576ca5
SC
66}
67
51d4293d
DS
68wxDragResult wxDropTarget::OnData(
69 wxCoord WXUNUSED(x), wxCoord WXUNUSED(y),
70 wxDragResult def )
e9576ca5 71{
876b960a 72 if (m_dataObject == NULL)
a07c1212
SC
73 return wxDragNone;
74
75 if (!CurrentDragHasSupportedFormat())
76 return wxDragNone;
77
78 return GetData() ? def : wxDragNone;
e9576ca5
SC
79}
80
6eae1f7d 81bool wxDropTarget::CurrentDragHasSupportedFormat()
e9576ca5 82{
51d4293d 83 bool supported = false;
6239ee05
SC
84 if (m_dataObject == NULL)
85 return false;
876b960a 86
a07c1212
SC
87 if ( gTrackingGlobals.m_currentSource != NULL )
88 {
51d4293d 89 wxDataObject* data = gTrackingGlobals.m_currentSource->GetDataObject();
6eae1f7d 90
e40298d5 91 if ( data )
a07c1212 92 {
51d4293d 93 size_t formatcount = data->GetFormatCount();
876b960a 94 wxDataFormat *array = new wxDataFormat[formatcount];
e40298d5 95 data->GetAllFormats( array );
51d4293d 96 for (size_t i = 0; !supported && i < formatcount; i++)
a07c1212 97 {
51d4293d 98 wxDataFormat format = array[i];
6eae1f7d 99 if ( m_dataObject->IsSupported( format ) )
e40298d5 100 {
51d4293d
DS
101 supported = true;
102 break;
e40298d5 103 }
a07c1212 104 }
6eae1f7d 105
51d4293d 106 delete [] array;
a07c1212 107 }
a07c1212 108 }
6eae1f7d 109
a07c1212
SC
110 if ( !supported )
111 {
6239ee05 112 PasteboardRef pasteboard;
6eae1f7d 113
6239ee05 114 if ( GetDragPasteboard( (DragReference)m_currentDrag, &pasteboard ) == noErr )
e40298d5 115 {
6239ee05 116 supported = m_dataObject->HasDataInPasteboard( pasteboard );
e40298d5 117 }
a07c1212 118 }
6eae1f7d 119
51d4293d 120 return supported;
e9576ca5
SC
121}
122
a07c1212 123bool wxDropTarget::GetData()
e9576ca5 124{
e22ab33a 125 if (m_dataObject == NULL)
6eae1f7d
DS
126 return false;
127
a07c1212 128 if ( !CurrentDragHasSupportedFormat() )
2e91d506 129 return false;
6eae1f7d 130
2e91d506 131 bool transferred = false;
a07c1212
SC
132 if ( gTrackingGlobals.m_currentSource != NULL )
133 {
2e91d506 134 wxDataObject* data = gTrackingGlobals.m_currentSource->GetDataObject();
6eae1f7d 135
2e91d506 136 if (data != NULL)
a07c1212 137 {
2e91d506 138 size_t formatcount = data->GetFormatCount();
6eae1f7d 139 wxDataFormat *array = new wxDataFormat[formatcount];
e40298d5 140 data->GetAllFormats( array );
2e91d506 141 for (size_t i = 0; !transferred && i < formatcount; i++)
a07c1212 142 {
2e91d506 143 wxDataFormat format = array[i];
6eae1f7d 144 if ( m_dataObject->IsSupported( format ) )
e40298d5
JS
145 {
146 int size = data->GetDataSize( format );
2e91d506 147 transferred = true;
6eae1f7d
DS
148
149 if (size == 0)
e40298d5 150 {
2e91d506 151 m_dataObject->SetData( format, 0, 0 );
e40298d5
JS
152 }
153 else
154 {
155 char *d = new char[size];
2e91d506
DS
156 data->GetDataHere( format, (void*)d );
157 m_dataObject->SetData( format, size, d );
158 delete [] d;
e40298d5
JS
159 }
160 }
a07c1212 161 }
6eae1f7d 162
2e91d506 163 delete [] array;
e40298d5 164 }
a07c1212 165 }
6eae1f7d 166
a07c1212
SC
167 if ( !transferred )
168 {
6239ee05 169 PasteboardRef pasteboard;
de5e599c 170
6239ee05 171 if ( GetDragPasteboard( (DragReference)m_currentDrag, &pasteboard ) == noErr )
55f5548f 172 {
6239ee05 173 transferred = m_dataObject->GetFromPasteboard( pasteboard );
55f5548f 174 }
a07c1212 175 }
6eae1f7d 176
6239ee05 177 return transferred;
e9576ca5
SC
178}
179
180//-------------------------------------------------------------------------
181// wxDropSource
182//-------------------------------------------------------------------------
183
184//-----------------------------------------------------------------------------
185// drag request
186
a07c1212 187wxDropSource::wxDropSource(wxWindow *win,
da804130
SC
188 const wxCursor &cursorCopy,
189 const wxCursor &cursorMove,
190 const wxCursor &cursorStop)
191 : wxDropSourceBase(cursorCopy, cursorMove, cursorStop)
e9576ca5 192{
51d4293d 193 wxMacEnsureTrackingHandlersInstalled();
e22ab33a 194
a07c1212
SC
195 m_window = win;
196}
e9576ca5 197
a07c1212
SC
198wxDropSource::wxDropSource(wxDataObject& data,
199 wxWindow *win,
da804130
SC
200 const wxCursor &cursorCopy,
201 const wxCursor &cursorMove,
202 const wxCursor &cursorStop)
203 : wxDropSourceBase(cursorCopy, cursorMove, cursorStop)
a07c1212 204{
51d4293d 205 wxMacEnsureTrackingHandlersInstalled();
e22ab33a 206
a07c1212
SC
207 SetData( data );
208 m_window = win;
209}
e9576ca5 210
a07c1212 211wxDropSource::~wxDropSource()
e9576ca5 212{
a07c1212 213}
e9576ca5 214
6239ee05
SC
215OSStatus wxMacPromiseKeeper( PasteboardRef inPasteboard, PasteboardItemID inItem, CFStringRef inFlavorType,
216 void *inContext )
217{
218 OSStatus err = noErr;
219
220 // we might add promises here later, inContext is the wxDropSource*
221
222 return err;
223}
224
525ae3fe 225wxDragResult wxDropSource::DoDragDrop(int flags)
e9576ca5 226{
a07c1212 227 wxASSERT_MSG( m_data, wxT("Drop source: no data") );
6eae1f7d 228
de5e599c
DS
229 if ((m_data == NULL) || (m_data->GetFormatCount() == 0))
230 return (wxDragResult)wxDragNone;
6eae1f7d 231
a07c1212
SC
232 DragReference theDrag;
233 RgnHandle dragRegion;
6239ee05
SC
234 OSStatus err = noErr;
235 PasteboardRef pasteboard;
236
a07c1212 237 // add data to drag
6239ee05
SC
238
239 err = PasteboardCreate( kPasteboardUniqueName, &pasteboard );
240 if ( err != noErr )
241 return wxDragNone;
242
243 // we add a dummy promise keeper because of strange messages when linking against carbon debug
244 err = PasteboardSetPromiseKeeper( pasteboard, wxMacPromiseKeeper, this );
245 if ( err != noErr )
a07c1212 246 {
6239ee05
SC
247 CFRelease( pasteboard );
248 return wxDragNone;
a07c1212 249 }
6239ee05
SC
250
251 err = PasteboardClear( pasteboard );
252 if ( err != noErr )
253 {
254 CFRelease( pasteboard );
255 return wxDragNone;
256 }
257 PasteboardSynchronize( pasteboard );
258
259 m_data->AddToPasteboard( pasteboard, 1 );
260
261 if (NewDragWithPasteboard( pasteboard , &theDrag) != noErr)
262 {
263 CFRelease( pasteboard );
264 return wxDragNone;
265 }
266
a07c1212 267 dragRegion = NewRgn();
51d4293d 268 RgnHandle tempRgn = NewRgn();
6eae1f7d 269
db28a493 270 EventRecord rec;
6239ee05 271 ConvertEventRefToEventRecord( (EventRef) wxTheApp->MacGetCurrentEvent(), &rec );
6eae1f7d 272
51d4293d
DS
273 const short dragRegionOuterBoundary = 10;
274 const short dragRegionInnerBoundary = 9;
6eae1f7d
DS
275
276 SetRectRgn(
51d4293d 277 dragRegion,
6239ee05
SC
278 rec.where.h - dragRegionOuterBoundary,
279 rec.where.v - dragRegionOuterBoundary,
280 rec.where.h + dragRegionOuterBoundary,
281 rec.where.v + dragRegionOuterBoundary );
6eae1f7d
DS
282
283 SetRectRgn(
51d4293d 284 tempRgn,
6239ee05
SC
285 rec.where.h - dragRegionInnerBoundary,
286 rec.where.v - dragRegionInnerBoundary,
287 rec.where.h + dragRegionInnerBoundary,
288 rec.where.v + dragRegionInnerBoundary );
6eae1f7d 289
51d4293d
DS
290 DiffRgn( dragRegion, tempRgn, dragRegion );
291 DisposeRgn( tempRgn );
6eae1f7d 292
e22ab33a
DS
293 // TODO: work with promises in order to return data
294 // only when drag was successfully completed
6eae1f7d 295
e22ab33a 296 gTrackingGlobals.m_currentSource = this;
56d152b2
VZ
297 gTrackingGlobals.m_result = wxDragNone;
298 gTrackingGlobals.m_flags = flags;
299
6239ee05
SC
300 err = TrackDrag( theDrag, &rec, dragRegion );
301
e22ab33a
DS
302 DisposeRgn( dragRegion );
303 DisposeDrag( theDrag );
6239ee05 304 CFRelease( pasteboard );
e22ab33a 305 gTrackingGlobals.m_currentSource = NULL;
6eae1f7d 306
56d152b2 307 return gTrackingGlobals.m_result;
a07c1212
SC
308}
309
da804130
SC
310bool wxDropSource::MacInstallDefaultCursor(wxDragResult effect)
311{
312 const wxCursor& cursor = GetCursor(effect);
6eae1f7d
DS
313 bool result = cursor.Ok();
314
315 if ( result )
e22ab33a 316 cursor.MacInstall();
da804130 317
6eae1f7d 318 return result;
da804130
SC
319}
320
51d4293d 321bool gTrackingGlobalsInstalled = false;
a07c1212
SC
322
323// passing the globals via refcon is not needed by the CFM and later architectures anymore
324// but I'll leave it in there, just in case...
325
6eae1f7d
DS
326pascal OSErr wxMacWindowDragTrackingHandler(
327 DragTrackingMessage theMessage, WindowPtr theWindow,
e22ab33a 328 void *handlerRefCon, DragReference theDrag );
6eae1f7d
DS
329pascal OSErr wxMacWindowDragReceiveHandler(
330 WindowPtr theWindow, void *handlerRefCon,
e22ab33a 331 DragReference theDrag );
a07c1212
SC
332
333void wxMacEnsureTrackingHandlersInstalled()
e9576ca5 334{
6eae1f7d 335 if ( !gTrackingGlobalsInstalled )
a07c1212 336 {
2e91d506 337 OSStatus err;
a07c1212 338
2e91d506
DS
339 err = InstallTrackingHandler( NewDragTrackingHandlerUPP(wxMacWindowDragTrackingHandler), 0L, &gTrackingGlobals );
340 verify_noerr( err );
6eae1f7d 341
2e91d506
DS
342 err = InstallReceiveHandler( NewDragReceiveHandlerUPP(wxMacWindowDragReceiveHandler), 0L, &gTrackingGlobals );
343 verify_noerr( err );
e9576ca5 344
e22ab33a 345 gTrackingGlobalsInstalled = true;
a07c1212
SC
346 }
347}
348
6eae1f7d
DS
349pascal OSErr wxMacWindowDragTrackingHandler(
350 DragTrackingMessage theMessage, WindowPtr theWindow,
e22ab33a 351 void *handlerRefCon, DragReference theDrag )
6eae1f7d 352{
a07c1212 353 MacTrackingGlobals* trackingGlobals = (MacTrackingGlobals*) handlerRefCon;
e22ab33a 354
a07c1212
SC
355 Point mouse, localMouse;
356 DragAttributes attributes;
e22ab33a
DS
357
358 GetDragAttributes( theDrag, &attributes );
359
51d4293d 360 wxTopLevelWindowMac* toplevel = wxFindWinFromMacWindow( theWindow );
f43084de 361
51d4293d 362 bool optionDown = GetCurrentKeyModifiers() & optionKey;
f43084de
JS
363 wxDragResult result = optionDown ? wxDragCopy : wxDragMove;
364
6eae1f7d 365 switch (theMessage)
a07c1212
SC
366 {
367 case kDragTrackingEnterHandler:
a07c1212
SC
368 case kDragTrackingLeaveHandler:
369 break;
6eae1f7d 370
a07c1212 371 case kDragTrackingEnterWindow:
e22ab33a
DS
372 if (trackingGlobals != NULL)
373 {
51d4293d
DS
374 trackingGlobals->m_currentTargetWindow = NULL;
375 trackingGlobals->m_currentTarget = NULL;
e22ab33a 376 }
a07c1212 377 break;
6eae1f7d 378
a07c1212 379 case kDragTrackingInWindow:
e22ab33a
DS
380 if (trackingGlobals == NULL)
381 break;
a07c1212
SC
382 if (toplevel == NULL)
383 break;
384
e22ab33a 385 GetDragMouse( theDrag, &mouse, 0L );
a07c1212 386 localMouse = mouse;
4913272f 387 wxMacGlobalToLocal( theWindow, &localMouse );
f43084de 388
a07c1212 389 {
51d4293d
DS
390 wxWindow *win = NULL;
391 ControlPartCode controlPart;
6eae1f7d 392 ControlRef control = wxMacFindControlUnderMouse(
51d4293d 393 toplevel, localMouse, theWindow, &controlPart );
2877659b 394 if ( control )
51d4293d 395 win = wxFindControlFromMacControl( control );
7adabb9a 396 else
51d4293d 397 win = toplevel;
6eae1f7d 398
51d4293d
DS
399 int localx, localy;
400 localx = localMouse.h;
401 localy = localMouse.v;
7adabb9a 402
a07c1212 403 if ( win )
51d4293d 404 win->MacRootWindowToWindow( &localx, &localy );
a07c1212
SC
405 if ( win != trackingGlobals->m_currentTargetWindow )
406 {
407 if ( trackingGlobals->m_currentTargetWindow )
408 {
409 // this window is left
410 if ( trackingGlobals->m_currentTarget )
411 {
4913272f 412#ifndef __LP64__
6eae1f7d 413 HideDragHilite( theDrag );
4913272f 414#endif
876b960a
DS
415 trackingGlobals->m_currentTarget->SetCurrentDrag( theDrag );
416 trackingGlobals->m_currentTarget->OnLeave();
a07c1212 417 trackingGlobals->m_currentTarget = NULL;
876b960a 418 trackingGlobals->m_currentTargetWindow = NULL;
a07c1212
SC
419 }
420 }
6eae1f7d 421
a07c1212
SC
422 if ( win )
423 {
424 // this window is entered
51d4293d
DS
425 trackingGlobals->m_currentTargetWindow = win;
426 trackingGlobals->m_currentTarget = win->GetDropTarget();
a07c1212 427 {
6eae1f7d
DS
428 if ( trackingGlobals->m_currentTarget )
429 {
51d4293d
DS
430 trackingGlobals->m_currentTarget->SetCurrentDrag( theDrag );
431 result = trackingGlobals->m_currentTarget->OnEnter( localx, localy, result );
da804130 432 }
6eae1f7d 433
da804130 434 if ( result != wxDragNone )
a07c1212 435 {
51d4293d 436 int x, y;
6eae1f7d 437
51d4293d
DS
438 x = y = 0;
439 win->MacWindowToRootWindow( &x, &y );
440 RgnHandle hiliteRgn = NewRgn();
441 Rect r = { y, x, y + win->GetSize().y, x + win->GetSize().x };
442 RectRgn( hiliteRgn, &r );
4913272f 443#ifndef __LP64__
876b960a 444 ShowDragHilite( theDrag, hiliteRgn, true );
4913272f 445#endif
51d4293d 446 DisposeRgn( hiliteRgn );
a07c1212
SC
447 }
448 }
449 }
450 }
451 else
452 {
6eae1f7d 453 if ( trackingGlobals->m_currentTarget )
a07c1212 454 {
51d4293d 455 trackingGlobals->m_currentTarget->SetCurrentDrag( theDrag );
6239ee05 456 result = trackingGlobals->m_currentTarget->OnDragOver( localx, localy, result );
f43084de
JS
457 }
458 }
459
460 // set cursor for OnEnter and OnDragOver
bf473da7 461 if ( trackingGlobals->m_currentSource && !trackingGlobals->m_currentSource->GiveFeedback( result ) )
f43084de 462 {
6eae1f7d 463 if ( !trackingGlobals->m_currentSource->MacInstallDefaultCursor( result ) )
f43084de 464 {
de5e599c
DS
465 int cursorID = wxCURSOR_NONE;
466
467 switch (result)
f43084de 468 {
2e91d506 469 case wxDragCopy:
de5e599c 470 cursorID = wxCURSOR_COPY_ARROW;
51d4293d 471 break;
6eae1f7d 472
2e91d506 473 case wxDragMove:
de5e599c 474 cursorID = wxCURSOR_ARROW;
51d4293d 475 break;
6eae1f7d 476
2e91d506 477 case wxDragNone:
de5e599c 478 cursorID = wxCURSOR_NO_ENTRY;
51d4293d 479 break;
eb7f8ac5
VZ
480
481 case wxDragError:
482 case wxDragLink:
483 case wxDragCancel:
6eae1f7d 484 default:
eb7f8ac5
VZ
485 // put these here to make gcc happy
486 ;
f43084de 487 }
de5e599c
DS
488
489 if (cursorID != wxCURSOR_NONE)
490 {
491 wxCursor cursor( cursorID );
492 cursor.MacInstall();
493 }
6eae1f7d 494 }
a07c1212 495 }
7adabb9a 496 }
a07c1212 497 break;
6eae1f7d 498
a07c1212 499 case kDragTrackingLeaveWindow:
e22ab33a
DS
500 if (trackingGlobals == NULL)
501 break;
502
6eae1f7d 503 if (trackingGlobals->m_currentTarget)
a07c1212 504 {
876b960a
DS
505 trackingGlobals->m_currentTarget->SetCurrentDrag( theDrag );
506 trackingGlobals->m_currentTarget->OnLeave();
4913272f 507#ifndef __LP64__
876b960a 508 HideDragHilite( theDrag );
4913272f 509#endif
876b960a 510 trackingGlobals->m_currentTarget = NULL;
a07c1212 511 }
876b960a 512 trackingGlobals->m_currentTargetWindow = NULL;
a07c1212 513 break;
6eae1f7d
DS
514
515 default:
516 break;
a07c1212 517 }
6eae1f7d
DS
518
519 return noErr;
a07c1212
SC
520}
521
6eae1f7d
DS
522pascal OSErr wxMacWindowDragReceiveHandler(
523 WindowPtr theWindow,
524 void *handlerRefCon,
525 DragReference theDrag)
526{
527 MacTrackingGlobals* trackingGlobals = (MacTrackingGlobals*)handlerRefCon;
a07c1212
SC
528 if ( trackingGlobals->m_currentTarget )
529 {
51d4293d
DS
530 Point mouse, localMouse;
531 int localx, localy;
6eae1f7d 532
51d4293d
DS
533 trackingGlobals->m_currentTarget->SetCurrentDrag( theDrag );
534 GetDragMouse( theDrag, &mouse, 0L );
a07c1212 535 localMouse = mouse;
4913272f 536 wxMacGlobalToLocal( theWindow, &localMouse );
51d4293d
DS
537 localx = localMouse.h;
538 localy = localMouse.v;
6eae1f7d
DS
539
540 // TODO : should we use client coordinates?
a07c1212 541 if ( trackingGlobals->m_currentTargetWindow )
51d4293d
DS
542 trackingGlobals->m_currentTargetWindow->MacRootWindowToWindow( &localx, &localy );
543 if ( trackingGlobals->m_currentTarget->OnDrop( localx, localy ) )
a07c1212 544 {
56d152b2
VZ
545 // the option key indicates copy in Mac UI, if it's not pressed do
546 // move by default if it's allowed at all
547 wxDragResult
548 result = !(trackingGlobals->m_flags & wxDrag_AllowMove) ||
549 (GetCurrentKeyModifiers() & optionKey)
550 ? wxDragCopy
551 : wxDragMove;
552 trackingGlobals->m_result =
553 trackingGlobals->m_currentTarget->OnData( localx, localy, result );
a07c1212
SC
554 }
555 }
6eae1f7d
DS
556
557 return noErr;
a07c1212 558}
6eae1f7d 559
56d152b2
VZ
560#endif // wxUSE_DRAG_AND_DROP
561