]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/dnd.cpp
a2059478e08f06f57bc1af75e5715b340e9c46f7
[wxWidgets.git] / src / mac / carbon / dnd.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: dnd.cpp
3 // Purpose: wxDropTarget, wxDropSource, wxDataObject implementation
4 // Author: AUTHOR
5 // Modified by:
6 // Created: ??/??/98
7 // RCS-ID: $Id$
8 // Copyright: (c) 1998 AUTHOR
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "dnd.h"
14 #endif
15
16 #include "wx/dnd.h"
17 #include "wx/window.h"
18 #include "wx/app.h"
19 #include "wx/gdicmn.h"
20
21 #if wxUSE_DRAG_AND_DROP
22
23 // ----------------------------------------------------------------------------
24 // global
25 // ----------------------------------------------------------------------------
26
27 void wxMacEnsureTrackingHandlersInstalled() ;
28
29 typedef struct
30 {
31 wxWindow* m_currentTargetWindow ;
32 wxDropTarget* m_currentTarget ;
33 wxDropSource* m_currentSource ;
34 } MacTrackingGlobals ;
35
36 MacTrackingGlobals gTrackingGlobals ;
37
38 //----------------------------------------------------------------------------
39 // wxDropTarget
40 //----------------------------------------------------------------------------
41
42 wxDropTarget::wxDropTarget( wxDataObject *data )
43 : wxDropTargetBase( data )
44 {
45 wxMacEnsureTrackingHandlersInstalled() ;
46 }
47
48 wxDragResult wxDropTarget::OnDragOver( wxCoord WXUNUSED(x),
49 wxCoord WXUNUSED(y),
50 wxDragResult def )
51 {
52
53 return CurrentDragHasSupportedFormat() ? def : wxDragNone;
54 }
55
56 bool wxDropTarget::OnDrop( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y) )
57 {
58 if (!m_dataObject)
59 return FALSE;
60
61 return CurrentDragHasSupportedFormat() ;
62 }
63
64 wxDragResult wxDropTarget::OnData( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y),
65 wxDragResult def )
66 {
67 if (!m_dataObject)
68 return wxDragNone;
69
70 if (!CurrentDragHasSupportedFormat())
71 return wxDragNone;
72
73 return GetData() ? def : wxDragNone;
74 }
75
76 bool wxDropTarget::CurrentDragHasSupportedFormat()
77 {
78 bool supported = false ;
79 if ( gTrackingGlobals.m_currentSource != NULL )
80 {
81 wxDataObject* data = gTrackingGlobals.m_currentSource->GetDataObject() ;
82
83 if ( data )
84 {
85 int formatcount = data->GetFormatCount() ;
86 wxDataFormat *array = new wxDataFormat[ formatcount ];
87 data->GetAllFormats( array );
88 for (size_t i = 0; !supported && i < formatcount ; i++)
89 {
90 wxDataFormat format = array[i] ;
91 if ( m_dataObject->IsSupported( format ) )
92 {
93 supported = true ;
94 break ;
95 }
96 }
97 delete[] array ;
98 }
99 }
100 if ( !supported )
101 {
102 UInt16 items ;
103 OSErr result;
104 CountDragItems(m_currentDrag, &items);
105 for (UInt16 index = 1; index <= items && supported == false ; ++index)
106 {
107 ItemReference theItem;
108 FlavorType theType ;
109 UInt16 flavors = 0 ;
110 GetDragItemReferenceNumber(m_currentDrag, index, &theItem);
111 CountDragItemFlavors( m_currentDrag, theItem , &flavors ) ;
112 for ( UInt16 flavor = 1 ; flavor <= flavors ; ++flavor )
113 {
114 result = GetFlavorType(m_currentDrag, theItem, flavor , &theType);
115 if ( m_dataObject->IsSupportedFormat( wxDataFormat( theType ) ) )
116 {
117 supported = true ;
118 break ;
119 }
120 }
121 }
122 }
123 return supported ;
124 }
125
126 bool wxDropTarget::GetData()
127 {
128 if (!m_dataObject)
129 return FALSE;
130
131 if ( !CurrentDragHasSupportedFormat() )
132 return FALSE ;
133
134 bool transferred = false ;
135 if ( gTrackingGlobals.m_currentSource != NULL )
136 {
137 wxDataObject* data = gTrackingGlobals.m_currentSource->GetDataObject() ;
138
139 if ( data )
140 {
141 int formatcount = data->GetFormatCount() ;
142 wxDataFormat *array = new wxDataFormat[ formatcount ];
143 data->GetAllFormats( array );
144 for (size_t i = 0; !transferred && i < formatcount ; i++)
145 {
146 wxDataFormat format = array[i] ;
147 if ( m_dataObject->IsSupported( format ) )
148 {
149 int size = data->GetDataSize( format );
150 transferred = true ;
151
152 if (size == 0)
153 {
154 m_dataObject->SetData(format , 0 , 0 ) ;
155 }
156 else
157 {
158 char *d = new char[size];
159 data->GetDataHere( format , (void*) d );
160 m_dataObject->SetData( format , size , d ) ;
161 delete[] d ;
162 }
163 }
164 }
165 delete[] array ;
166 }
167 }
168 if ( !transferred )
169 {
170 UInt16 items ;
171 OSErr result;
172 CountDragItems(m_currentDrag, &items);
173 for (UInt16 index = 1; index <= items; ++index)
174 {
175 ItemReference theItem;
176 FlavorType theType ;
177 UInt16 flavors = 0 ;
178 GetDragItemReferenceNumber(m_currentDrag, index, &theItem);
179 CountDragItemFlavors( m_currentDrag, theItem , &flavors ) ;
180 for ( UInt16 flavor = 1 ; flavor <= flavors ; ++flavor )
181 {
182 result = GetFlavorType(m_currentDrag, theItem, flavor , &theType);
183 wxDataFormat format(theType) ;
184 if ( m_dataObject->IsSupportedFormat( format ) )
185 {
186 FlavorFlags theFlags;
187 result = GetFlavorFlags(m_currentDrag, theItem, theType, &theFlags);
188 if (result == noErr)
189 {
190 Size dataSize ;
191 Ptr theData ;
192 GetFlavorDataSize(m_currentDrag, theItem, theType, &dataSize);
193 if ( theType == 'TEXT' )
194 dataSize++ ;
195 theData = new char[dataSize];
196 GetFlavorData(m_currentDrag, theItem, theType, (void*) theData, &dataSize, 0L);
197 if( theType == 'TEXT' )
198 {
199 theData[dataSize]=0 ;
200 if ( wxApp::s_macDefaultEncodingIsPC )
201 {
202 wxMacConvertToPC((char*)theData) ;
203 }
204 m_dataObject->SetData( format, dataSize, theData );
205 }
206 else if ( theType == kDragFlavorTypeHFS )
207 {
208 HFSFlavor* theFile = (HFSFlavor*) theData ;
209 wxString name = wxMacFSSpec2MacFilename( &theFile->fileSpec ) ;
210 m_dataObject->SetData( format , name.Length() + 1, name ) ;
211 }
212 else
213 {
214 m_dataObject->SetData( format, dataSize, theData );
215 }
216 delete[] theData;
217 }
218 break ;
219 }
220 }
221 }
222 }
223 return TRUE ;
224 }
225
226 //-------------------------------------------------------------------------
227 // wxDropSource
228 //-------------------------------------------------------------------------
229
230 //-----------------------------------------------------------------------------
231 // drag request
232
233 wxDropSource::wxDropSource(wxWindow *win,
234 const wxIcon &iconCopy,
235 const wxIcon &iconMove,
236 const wxIcon &iconNone)
237 {
238 wxMacEnsureTrackingHandlersInstalled() ;
239 m_window = win;
240 }
241
242 wxDropSource::wxDropSource(wxDataObject& data,
243 wxWindow *win,
244 const wxIcon &iconCopy,
245 const wxIcon &iconMove,
246 const wxIcon &iconNone)
247 {
248 wxMacEnsureTrackingHandlersInstalled() ;
249 SetData( data );
250 m_window = win;
251 }
252
253 wxDropSource::~wxDropSource()
254 {
255 }
256
257
258 wxDragResult wxDropSource::DoDragDrop( bool allowMove )
259 {
260 wxASSERT_MSG( m_data, wxT("Drop source: no data") );
261
262 if (!m_data)
263 return (wxDragResult) wxDragNone;
264
265 if (m_data->GetFormatCount() == 0)
266 return (wxDragResult) wxDragNone;
267
268 OSErr result;
269 DragReference theDrag;
270 RgnHandle dragRegion;
271 if (result = NewDrag(&theDrag))
272 {
273 return wxDragNone ;
274 }
275 // add data to drag
276 size_t formatCount = m_data->GetFormatCount() ;
277 wxDataFormat *formats = new wxDataFormat[formatCount] ;
278 m_data->GetAllFormats( formats ) ;
279 ItemReference theItem = 1 ;
280 for ( int i = 0 ; i < formatCount ; ++i )
281 {
282 size_t dataSize = m_data->GetDataSize( formats[i] ) ;
283 Ptr dataPtr = new char[dataSize] ;
284 m_data->GetDataHere( formats[i] , dataPtr ) ;
285 OSType type = formats[i].GetFormatId() ;
286 if ( type == 'TEXT' )
287 {
288 dataSize-- ;
289 if ( wxApp::s_macDefaultEncodingIsPC )
290 {
291 wxMacConvertFromPC((char*)dataPtr) ;
292 }
293 AddDragItemFlavor(theDrag, theItem, type , dataPtr, dataSize, 0);
294 }
295 else if (type == kDragFlavorTypeHFS )
296 {
297 HFSFlavor theFlavor ;
298 OSErr err = noErr;
299 CInfoPBRec cat;
300
301 wxMacFilename2FSSpec( dataPtr , &theFlavor.fileSpec ) ;
302
303 cat.hFileInfo.ioNamePtr = theFlavor.fileSpec.name;
304 cat.hFileInfo.ioVRefNum = theFlavor.fileSpec.vRefNum;
305 cat.hFileInfo.ioDirID = theFlavor.fileSpec.parID;
306 cat.hFileInfo.ioFDirIndex = 0;
307 err = PBGetCatInfoSync(&cat);
308 if (err == noErr )
309 {
310 theFlavor.fdFlags = cat.hFileInfo.ioFlFndrInfo.fdFlags;
311 if (theFlavor.fileSpec.parID == fsRtParID) {
312 theFlavor.fileCreator = 'MACS';
313 theFlavor.fileType = 'disk';
314 } else if ((cat.hFileInfo.ioFlAttrib & ioDirMask) != 0) {
315 theFlavor.fileCreator = 'MACS';
316 theFlavor.fileType = 'fold';
317 } else {
318 theFlavor.fileCreator = cat.hFileInfo.ioFlFndrInfo.fdCreator;
319 theFlavor.fileType = cat.hFileInfo.ioFlFndrInfo.fdType;
320 }
321 AddDragItemFlavor(theDrag, theItem, type , &theFlavor, sizeof(theFlavor), 0);
322 }
323 }
324 else
325 {
326 AddDragItemFlavor(theDrag, theItem, type , dataPtr, dataSize, 0);
327 }
328 delete[] dataPtr ;
329 }
330 delete[] formats ;
331
332 dragRegion = NewRgn();
333 RgnHandle tempRgn = NewRgn() ;
334
335 EventRecord* ev = wxTheApp->MacGetCurrentEvent() ;
336 const short dragRegionOuterBoundary = 10 ;
337 const short dragRegionInnerBoundary = 9 ;
338
339 SetRectRgn( dragRegion , ev->where.h - dragRegionOuterBoundary ,
340 ev->where.v - dragRegionOuterBoundary ,
341 ev->where.h + dragRegionOuterBoundary ,
342 ev->where.v + dragRegionOuterBoundary ) ;
343
344 SetRectRgn( tempRgn , ev->where.h - dragRegionInnerBoundary ,
345 ev->where.v - dragRegionInnerBoundary ,
346 ev->where.h + dragRegionInnerBoundary ,
347 ev->where.v + dragRegionInnerBoundary ) ;
348
349 DiffRgn( dragRegion , tempRgn , dragRegion ) ;
350 DisposeRgn( tempRgn ) ;
351
352 // TODO:work with promises in order to return data only when drag
353 // was successfully completed
354
355 gTrackingGlobals.m_currentSource = this ;
356 result = TrackDrag(theDrag, ev , dragRegion);
357 DisposeRgn(dragRegion);
358 DisposeDrag(theDrag);
359 gTrackingGlobals.m_currentSource = NULL ;
360
361 return wxDragCopy ;
362 }
363
364 bool gTrackingGlobalsInstalled = false ;
365
366 // passing the globals via refcon is not needed by the CFM and later architectures anymore
367 // but I'll leave it in there, just in case...
368
369 pascal OSErr wxMacWindowDragTrackingHandler(DragTrackingMessage theMessage, WindowPtr theWindow,
370 void *handlerRefCon, DragReference theDrag) ;
371 pascal OSErr wxMacWindowDragReceiveHandler(WindowPtr theWindow, void *handlerRefCon,
372 DragReference theDrag) ;
373
374 void wxMacEnsureTrackingHandlersInstalled()
375 {
376 if( !gTrackingGlobalsInstalled )
377 {
378 OSErr result;
379
380 result = InstallTrackingHandler(NewDragTrackingHandlerUPP(wxMacWindowDragTrackingHandler), 0L,&gTrackingGlobals);
381 wxASSERT( result == noErr ) ;
382 result = InstallReceiveHandler(NewDragReceiveHandlerUPP(wxMacWindowDragReceiveHandler), 0L, &gTrackingGlobals);
383 wxASSERT( result == noErr ) ;
384
385 gTrackingGlobalsInstalled = true ;
386 }
387 }
388
389 pascal OSErr wxMacWindowDragTrackingHandler(DragTrackingMessage theMessage, WindowPtr theWindow,
390 void *handlerRefCon, DragReference theDrag)
391 {
392 MacTrackingGlobals* trackingGlobals = (MacTrackingGlobals*) handlerRefCon;
393 Point mouse, localMouse;
394 DragAttributes attributes;
395 RgnHandle hiliteRgn;
396 GetDragAttributes(theDrag, &attributes);
397 wxTopLevelWindowMac* toplevel = wxFindWinFromMacWindow( theWindow ) ;
398 switch(theMessage)
399 {
400 case kDragTrackingEnterHandler:
401 break;
402 case kDragTrackingLeaveHandler:
403 break;
404 case kDragTrackingEnterWindow:
405 trackingGlobals->m_currentTargetWindow = NULL ;
406 trackingGlobals->m_currentTarget = NULL ;
407 break;
408 case kDragTrackingInWindow:
409 if (toplevel == NULL)
410 break;
411
412 GetDragMouse(theDrag, &mouse, 0L);
413 localMouse = mouse;
414 GlobalToLocal(&localMouse);
415
416 // if (attributes & kDragHasLeftSenderWindow)
417 {
418 wxPoint point(localMouse.h , localMouse.v) ;
419 wxWindow *win = NULL ;
420 toplevel->MacGetWindowFromPointSub( point , &win ) ;
421 int localx , localy ;
422 localx = localMouse.h ;
423 localy = localMouse.v ;
424 //TODO : should we use client coordinates
425 if ( win )
426 win->MacRootWindowToWindow( &localx , &localy ) ;
427 if ( win != trackingGlobals->m_currentTargetWindow )
428 {
429 if ( trackingGlobals->m_currentTargetWindow )
430 {
431 // this window is left
432 if ( trackingGlobals->m_currentTarget )
433 {
434 HideDragHilite(theDrag);
435 trackingGlobals->m_currentTarget->SetCurrentDrag( theDrag ) ;
436 trackingGlobals->m_currentTarget->OnLeave() ;
437 trackingGlobals->m_currentTarget = NULL;
438 trackingGlobals->m_currentTargetWindow = NULL ;
439 }
440 }
441 if ( win )
442 {
443 // this window is entered
444 trackingGlobals->m_currentTargetWindow = win ;
445 trackingGlobals->m_currentTarget = win->GetDropTarget() ;
446 if ( trackingGlobals->m_currentTarget )
447 {
448 trackingGlobals->m_currentTarget->SetCurrentDrag( theDrag ) ;
449 if ( trackingGlobals->m_currentTarget->OnEnter(
450 localx , localy , wxDragCopy ) != wxDragNone )
451 {
452 int x , y ;
453 x = y = 0 ;
454 win->MacWindowToRootWindow( &x , &y ) ;
455 RgnHandle hiliteRgn = NewRgn() ;
456 SetRectRgn( hiliteRgn , x , y , x+win->GetSize().x ,y+win->GetSize().y) ;
457 ShowDragHilite(theDrag, hiliteRgn, true);
458 DisposeRgn( hiliteRgn ) ;
459 }
460 }
461 }
462 }
463 else
464 {
465 if( trackingGlobals->m_currentTarget )
466 {
467 trackingGlobals->m_currentTarget->SetCurrentDrag( theDrag ) ;
468 trackingGlobals->m_currentTarget->OnDragOver(
469 localx , localy , wxDragCopy ) ;
470 }
471 }
472
473 }
474 // MyTrackItemUnderMouse(localMouse, theWindow);
475 break;
476 case kDragTrackingLeaveWindow:
477 if (trackingGlobals->m_currentTarget)
478 {
479 trackingGlobals->m_currentTarget->SetCurrentDrag( theDrag ) ;
480 trackingGlobals->m_currentTarget->OnLeave() ;
481 HideDragHilite(theDrag);
482 trackingGlobals->m_currentTarget = NULL ;
483 }
484 trackingGlobals->m_currentTargetWindow = NULL ;
485 break;
486 }
487 return(noErr);
488 }
489
490 pascal OSErr wxMacWindowDragReceiveHandler(WindowPtr theWindow, void *handlerRefCon,
491 DragReference theDrag)
492 {
493 MacTrackingGlobals* trackingGlobals = (MacTrackingGlobals*) handlerRefCon;
494 if ( trackingGlobals->m_currentTarget )
495 {
496 Point mouse,localMouse ;
497 int localx,localy ;
498
499 trackingGlobals->m_currentTarget->SetCurrentDrag( theDrag ) ;
500 GetDragMouse(theDrag, &mouse, 0L);
501 localMouse = mouse;
502 GlobalToLocal(&localMouse);
503 localx = localMouse.h ;
504 localy = localMouse.v ;
505 //TODO : should we use client coordinates
506 if ( trackingGlobals->m_currentTargetWindow )
507 trackingGlobals->m_currentTargetWindow->MacRootWindowToWindow( &localx , &localy ) ;
508 if ( trackingGlobals->m_currentTarget->OnDrop( localx , localy ) )
509 {
510 trackingGlobals->m_currentTarget->OnData( localx , localy , wxDragCopy ) ;
511 }
512 }
513 return(noErr);
514 }
515 #endif