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