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 //----------------------------------------------------------------------------
45 //----------------------------------------------------------------------------
47 wxDropTarget::wxDropTarget( wxDataObject
*data
)
48 : wxDropTargetBase( data
)
50 wxMacEnsureTrackingHandlersInstalled();
53 wxDragResult
wxDropTarget::OnDragOver(
54 wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
),
57 return CurrentDragHasSupportedFormat() ? def
: wxDragNone
;
60 wxDataFormat
wxDropTarget::GetMatchingPair()
62 wxFAIL_MSG("wxDropTarget::GetMatchingPair() not implemented in src/osx/carbon/dnd.cpp");
66 bool wxDropTarget::OnDrop( wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
) )
68 if (m_dataObject
== NULL
)
71 return CurrentDragHasSupportedFormat();
74 wxDragResult
wxDropTarget::OnData(
75 wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
),
78 if (m_dataObject
== NULL
)
81 if (!CurrentDragHasSupportedFormat())
84 return GetData() ? def
: wxDragNone
;
87 bool wxDropTarget::CurrentDragHasSupportedFormat()
89 bool supported
= false;
90 if (m_dataObject
== NULL
)
93 if ( gTrackingGlobals
.m_currentSource
!= NULL
)
95 wxDataObject
* data
= gTrackingGlobals
.m_currentSource
->GetDataObject();
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
++)
104 wxDataFormat format
= array
[i
];
105 if ( m_dataObject
->IsSupported( format
) )
118 supported
= m_dataObject
->HasDataInPasteboard( m_currentDragPasteboard
);
124 bool wxDropTarget::GetData()
126 if (m_dataObject
== NULL
)
129 if ( !CurrentDragHasSupportedFormat() )
132 bool transferred
= false;
133 if ( gTrackingGlobals
.m_currentSource
!= NULL
)
135 wxDataObject
* data
= gTrackingGlobals
.m_currentSource
->GetDataObject();
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
++)
144 wxDataFormat format
= array
[i
];
145 if ( m_dataObject
->IsSupported( format
) )
147 int size
= data
->GetDataSize( format
);
152 m_dataObject
->SetData( format
, 0, 0 );
156 char *d
= new char[size
];
157 data
->GetDataHere( format
, (void*)d
);
158 m_dataObject
->SetData( format
, size
, d
);
170 transferred
= m_dataObject
->GetFromPasteboard( m_currentDragPasteboard
);
176 //-------------------------------------------------------------------------
178 //-------------------------------------------------------------------------
180 //-----------------------------------------------------------------------------
183 wxDropSource::wxDropSource(wxWindow
*win
,
184 const wxCursor
&cursorCopy
,
185 const wxCursor
&cursorMove
,
186 const wxCursor
&cursorStop
)
187 : wxDropSourceBase(cursorCopy
, cursorMove
, cursorStop
)
189 wxMacEnsureTrackingHandlersInstalled();
194 wxDropSource::wxDropSource(wxDataObject
& data
,
196 const wxCursor
&cursorCopy
,
197 const wxCursor
&cursorMove
,
198 const wxCursor
&cursorStop
)
199 : wxDropSourceBase(cursorCopy
, cursorMove
, cursorStop
)
201 wxMacEnsureTrackingHandlersInstalled();
207 wxDropSource::~wxDropSource()
211 OSStatus
wxMacPromiseKeeper(PasteboardRef
WXUNUSED(inPasteboard
),
212 PasteboardItemID
WXUNUSED(inItem
),
213 CFStringRef
WXUNUSED(inFlavorType
),
214 void * WXUNUSED(inContext
))
216 OSStatus err
= noErr
;
218 // we might add promises here later, inContext is the wxDropSource*
223 wxDragResult
wxDropSource::DoDragDrop(int flags
)
225 wxASSERT_MSG( m_data
, wxT("Drop source: no data") );
227 if ((m_data
== NULL
) || (m_data
->GetFormatCount() == 0))
228 return (wxDragResult
)wxDragNone
;
231 DragReference theDrag
;
232 RgnHandle dragRegion
;
233 OSStatus err
= noErr
;
234 PasteboardRef pasteboard
;
238 err
= PasteboardCreate( kPasteboardUniqueName
, &pasteboard
);
242 // we add a dummy promise keeper because of strange messages when linking against carbon debug
243 err
= PasteboardSetPromiseKeeper( pasteboard
, wxMacPromiseKeeper
, this );
246 CFRelease( pasteboard
);
250 err
= PasteboardClear( pasteboard
);
253 CFRelease( pasteboard
);
256 PasteboardSynchronize( pasteboard
);
258 m_data
->AddToPasteboard( pasteboard
, 1 );
260 if (NewDragWithPasteboard( pasteboard
, &theDrag
) != noErr
)
262 CFRelease( pasteboard
);
266 dragRegion
= NewRgn();
267 RgnHandle tempRgn
= NewRgn();
270 ConvertEventRefToEventRecord( (EventRef
) wxTheApp
->MacGetCurrentEvent(), &rec
);
272 const short dragRegionOuterBoundary
= 10;
273 const short dragRegionInnerBoundary
= 9;
277 rec
.where
.h
- dragRegionOuterBoundary
,
278 rec
.where
.v
- dragRegionOuterBoundary
,
279 rec
.where
.h
+ dragRegionOuterBoundary
,
280 rec
.where
.v
+ dragRegionOuterBoundary
);
284 rec
.where
.h
- dragRegionInnerBoundary
,
285 rec
.where
.v
- dragRegionInnerBoundary
,
286 rec
.where
.h
+ dragRegionInnerBoundary
,
287 rec
.where
.v
+ dragRegionInnerBoundary
);
289 DiffRgn( dragRegion
, tempRgn
, dragRegion
);
290 DisposeRgn( tempRgn
);
292 // TODO: work with promises in order to return data
293 // only when drag was successfully completed
295 gTrackingGlobals
.m_currentSource
= this;
296 gTrackingGlobals
.m_result
= wxDragNone
;
297 gTrackingGlobals
.m_flags
= flags
;
299 err
= TrackDrag( theDrag
, &rec
, dragRegion
);
301 DisposeRgn( dragRegion
);
302 DisposeDrag( theDrag
);
303 CFRelease( pasteboard
);
304 gTrackingGlobals
.m_currentSource
= NULL
;
309 return gTrackingGlobals
.m_result
;
312 bool wxDropSource::MacInstallDefaultCursor(wxDragResult effect
)
314 const wxCursor
& cursor
= GetCursor(effect
);
315 bool result
= cursor
.Ok();
323 bool gTrackingGlobalsInstalled
= false;
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...
329 pascal OSErr
wxMacWindowDragTrackingHandler(
330 DragTrackingMessage theMessage
, WindowPtr theWindow
,
331 void *handlerRefCon
, DragReference theDrag
);
332 pascal OSErr
wxMacWindowDragReceiveHandler(
333 WindowPtr theWindow
, void *handlerRefCon
,
334 DragReference theDrag
);
337 void wxMacEnsureTrackingHandlersInstalled()
340 if ( !gTrackingGlobalsInstalled
)
344 err
= InstallTrackingHandler( NewDragTrackingHandlerUPP(wxMacWindowDragTrackingHandler
), 0L, &gTrackingGlobals
);
347 err
= InstallReceiveHandler( NewDragReceiveHandlerUPP(wxMacWindowDragReceiveHandler
), 0L, &gTrackingGlobals
);
350 gTrackingGlobalsInstalled
= true;
356 pascal OSErr
wxMacWindowDragTrackingHandler(
357 DragTrackingMessage theMessage
, WindowPtr theWindow
,
358 void *handlerRefCon
, DragReference theDrag
)
360 MacTrackingGlobals
* trackingGlobals
= (MacTrackingGlobals
*) handlerRefCon
;
362 Point mouse
, localMouse
;
363 DragAttributes attributes
;
365 GetDragAttributes( theDrag
, &attributes
);
366 PasteboardRef pasteboard
= 0;
367 GetDragPasteboard( theDrag
, &pasteboard
);
368 wxNonOwnedWindow
* toplevel
= wxNonOwnedWindow::GetFromWXWindow( (WXWindow
) theWindow
);
370 bool optionDown
= GetCurrentKeyModifiers() & optionKey
;
371 wxDragResult result
= optionDown
? wxDragCopy
: wxDragMove
;
375 case kDragTrackingEnterHandler
:
376 case kDragTrackingLeaveHandler
:
379 case kDragTrackingEnterWindow
:
380 if (trackingGlobals
!= NULL
)
382 trackingGlobals
->m_currentTargetWindow
= NULL
;
383 trackingGlobals
->m_currentTarget
= NULL
;
387 case kDragTrackingInWindow
:
388 if (trackingGlobals
== NULL
)
390 if (toplevel
== NULL
)
393 GetDragMouse( theDrag
, &mouse
, 0L );
396 toplevel
->GetNonOwnedPeer()->ScreenToWindow( &x
, &y
);
401 wxWindow
*win
= NULL
;
402 ControlPartCode controlPart
;
403 ControlRef control
= FindControlUnderMouse( localMouse
, theWindow
, &controlPart
);
405 win
= wxFindWindowFromWXWidget( (WXWidget
) control
);
410 localx
= localMouse
.h
;
411 localy
= localMouse
.v
;
414 win
->MacRootWindowToWindow( &localx
, &localy
);
415 if ( win
!= trackingGlobals
->m_currentTargetWindow
)
417 if ( trackingGlobals
->m_currentTargetWindow
)
419 // this window is left
420 if ( trackingGlobals
->m_currentTarget
)
423 HideDragHilite( theDrag
);
425 trackingGlobals
->m_currentTarget
->SetCurrentDragPasteboard( pasteboard
);
426 trackingGlobals
->m_currentTarget
->OnLeave();
427 trackingGlobals
->m_currentTarget
= NULL
;
428 trackingGlobals
->m_currentTargetWindow
= NULL
;
434 // this window is entered
435 trackingGlobals
->m_currentTargetWindow
= win
;
436 trackingGlobals
->m_currentTarget
= win
->GetDropTarget();
438 if ( trackingGlobals
->m_currentTarget
)
440 trackingGlobals
->m_currentTarget
->SetCurrentDragPasteboard( pasteboard
);
441 result
= trackingGlobals
->m_currentTarget
->OnEnter( localx
, localy
, result
);
444 if ( result
!= wxDragNone
)
449 win
->MacWindowToRootWindow( &x
, &y
);
450 RgnHandle hiliteRgn
= NewRgn();
451 Rect r
= { y
, x
, y
+ win
->GetSize().y
, x
+ win
->GetSize().x
};
452 RectRgn( hiliteRgn
, &r
);
454 ShowDragHilite( theDrag
, hiliteRgn
, true );
456 DisposeRgn( hiliteRgn
);
463 if ( trackingGlobals
->m_currentTarget
)
465 trackingGlobals
->m_currentTarget
->SetCurrentDragPasteboard( pasteboard
);
466 result
= trackingGlobals
->m_currentTarget
->OnDragOver( localx
, localy
, result
);
470 // set cursor for OnEnter and OnDragOver
471 if ( trackingGlobals
->m_currentSource
&& !trackingGlobals
->m_currentSource
->GiveFeedback( result
) )
473 if ( !trackingGlobals
->m_currentSource
->MacInstallDefaultCursor( result
) )
475 wxStockCursor cursorID
= wxCURSOR_NONE
;
480 cursorID
= wxCURSOR_COPY_ARROW
;
484 cursorID
= wxCURSOR_ARROW
;
488 cursorID
= wxCURSOR_NO_ENTRY
;
495 // put these here to make gcc happy
499 if (cursorID
!= wxCURSOR_NONE
)
501 wxCursor
cursor( cursorID
);
509 case kDragTrackingLeaveWindow
:
510 if (trackingGlobals
== NULL
)
513 if (trackingGlobals
->m_currentTarget
)
515 trackingGlobals
->m_currentTarget
->SetCurrentDragPasteboard( pasteboard
);
516 trackingGlobals
->m_currentTarget
->OnLeave();
518 HideDragHilite( theDrag
);
520 trackingGlobals
->m_currentTarget
= NULL
;
522 trackingGlobals
->m_currentTargetWindow
= NULL
;
532 pascal OSErr
wxMacWindowDragReceiveHandler(
535 DragReference theDrag
)
537 MacTrackingGlobals
* trackingGlobals
= (MacTrackingGlobals
*)handlerRefCon
;
538 if ( trackingGlobals
->m_currentTarget
)
540 Point mouse
, localMouse
;
543 PasteboardRef pasteboard
= 0;
544 GetDragPasteboard( theDrag
, &pasteboard
);
545 trackingGlobals
->m_currentTarget
->SetCurrentDragPasteboard( pasteboard
);
546 GetDragMouse( theDrag
, &mouse
, 0L );
548 localx
= localMouse
.h
;
549 localy
= localMouse
.v
;
550 wxNonOwnedWindow
* tlw
= wxNonOwnedWindow::GetFromWXWindow((WXWindow
) theWindow
);
552 tlw
->GetNonOwnedPeer()->ScreenToWindow( &localx
, &localy
);
554 // TODO : should we use client coordinates?
555 if ( trackingGlobals
->m_currentTargetWindow
)
556 trackingGlobals
->m_currentTargetWindow
->MacRootWindowToWindow( &localx
, &localy
);
557 if ( trackingGlobals
->m_currentTarget
->OnDrop( localx
, localy
) )
559 // the option key indicates copy in Mac UI, if it's not pressed do
560 // move by default if it's allowed at all
562 result
= !(trackingGlobals
->m_flags
& wxDrag_AllowMove
) ||
563 (GetCurrentKeyModifiers() & optionKey
)
566 trackingGlobals
->m_result
=
567 trackingGlobals
->m_currentTarget
->OnData( localx
, localy
, result
);
575 #endif // wxUSE_DRAG_AND_DROP