]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/dnd.cpp
New implementation for printing circles and epllipses.
[wxWidgets.git] / src / mac / carbon / dnd.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: dnd.cpp
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 #include "wx/window.h"
18 #include "wx/toplevel.h"
19 #include "wx/app.h"
20 #include "wx/gdicmn.h"
21 #include "wx/mac/private.h"
22
23 #ifndef __DARWIN__
24 #include <Scrap.h>
25 #endif
26
27
28 // ----------------------------------------------------------------------------
29 // globals
30 // ----------------------------------------------------------------------------
31
32 typedef struct
33 {
34 wxWindow* m_currentTargetWindow;
35 wxDropTarget* m_currentTarget;
36 wxDropSource* m_currentSource;
37 }
38 MacTrackingGlobals;
39
40 MacTrackingGlobals gTrackingGlobals;
41
42 void wxMacEnsureTrackingHandlersInstalled() ;
43
44 //----------------------------------------------------------------------------
45 // wxDropTarget
46 //----------------------------------------------------------------------------
47
48 wxDropTarget::wxDropTarget( wxDataObject *data )
49 : wxDropTargetBase( data )
50 {
51 wxMacEnsureTrackingHandlersInstalled() ;
52 }
53
54 wxDragResult wxDropTarget::OnDragOver( wxCoord WXUNUSED(x),
55 wxCoord WXUNUSED(y),
56 wxDragResult def )
57 {
58 return CurrentDragHasSupportedFormat() ? def : wxDragNone;
59 }
60
61 bool wxDropTarget::OnDrop( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y) )
62 {
63 if (m_dataObject == NULL)
64 return false;
65
66 return CurrentDragHasSupportedFormat() ;
67 }
68
69 wxDragResult wxDropTarget::OnData( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y),
70 wxDragResult def )
71 {
72 if (m_dataObject == NULL)
73 return wxDragNone;
74
75 if (!CurrentDragHasSupportedFormat())
76 return wxDragNone;
77
78 return GetData() ? def : wxDragNone;
79 }
80
81 bool wxDropTarget::CurrentDragHasSupportedFormat()
82 {
83 bool supported = false ;
84
85 if ( gTrackingGlobals.m_currentSource != NULL )
86 {
87 wxDataObject* data = gTrackingGlobals.m_currentSource->GetDataObject() ;
88
89 if ( data )
90 {
91 size_t formatcount = data->GetFormatCount() ;
92 wxDataFormat *array = new wxDataFormat[formatcount];
93 data->GetAllFormats( array );
94 for (size_t i = 0; !supported && i < formatcount ; i++)
95 {
96 wxDataFormat format = array[i] ;
97 if ( m_dataObject->IsSupported( format ) )
98 {
99 supported = true ;
100 break ;
101 }
102 }
103
104 delete [] array ;
105 }
106 }
107
108 if ( !supported )
109 {
110 UInt16 items ;
111 OSErr result;
112 ItemReference theItem;
113 FlavorType theType ;
114 UInt16 flavors = 0 ;
115
116 CountDragItems( (DragReference)m_currentDrag, &items );
117 for (UInt16 index = 1; index <= items && !supported; ++index)
118 {
119 flavors = 0 ;
120 GetDragItemReferenceNumber( (DragReference)m_currentDrag, index, &theItem );
121 CountDragItemFlavors( (DragReference)m_currentDrag, theItem, &flavors );
122
123 for ( UInt16 flavor = 1 ; flavor <= flavors ; ++flavor )
124 {
125 result = GetFlavorType( (DragReference)m_currentDrag, theItem, flavor, &theType );
126 if ( m_dataObject->IsSupportedFormat( wxDataFormat( theType ) ) )
127 {
128 supported = true ;
129 break ;
130 }
131 }
132 }
133 }
134
135 return supported ;
136 }
137
138 bool wxDropTarget::GetData()
139 {
140 if (m_dataObject == NULL)
141 return false;
142
143 if ( !CurrentDragHasSupportedFormat() )
144 return false ;
145
146 bool transferred = false ;
147 if ( gTrackingGlobals.m_currentSource != NULL )
148 {
149 wxDataObject* data = gTrackingGlobals.m_currentSource->GetDataObject() ;
150
151 if ( data )
152 {
153 size_t formatcount = data->GetFormatCount() ;
154 wxDataFormat *array = new wxDataFormat[formatcount];
155 data->GetAllFormats( array );
156 for (size_t i = 0; !transferred && i < formatcount ; i++)
157 {
158 wxDataFormat format = array[i] ;
159 if ( m_dataObject->IsSupported( format ) )
160 {
161 int size = data->GetDataSize( format );
162 transferred = true ;
163
164 if (size == 0)
165 {
166 m_dataObject->SetData( format , 0 , 0 );
167 }
168 else
169 {
170 char *d = new char[size];
171 data->GetDataHere( format , (void*) d );
172 m_dataObject->SetData( format , size , d ) ;
173 delete [] d ;
174 }
175 }
176 }
177
178 delete [] array ;
179 }
180 }
181
182 if ( !transferred )
183 {
184 UInt16 items ;
185 OSErr result;
186 ItemReference theItem;
187 FlavorType theType ;
188 FlavorFlags theFlags;
189 UInt16 flavors ;
190 bool firstFileAdded = false ;
191
192 CountDragItems( (DragReference)m_currentDrag, &items );
193 for (UInt16 index = 1; index <= items; ++index)
194 {
195 flavors = 0 ;
196 GetDragItemReferenceNumber( (DragReference)m_currentDrag, index, &theItem );
197 CountDragItemFlavors( (DragReference)m_currentDrag, theItem , &flavors );
198 wxDataFormat preferredFormat = m_dataObject->GetPreferredFormat( wxDataObject::Set );
199 bool hasPreferredFormat = false ;
200
201 for ( UInt16 flavor = 1 ; flavor <= flavors ; ++flavor )
202 {
203 result = GetFlavorType( (DragReference)m_currentDrag, theItem, flavor, &theType );
204 wxDataFormat format( theType );
205 if ( preferredFormat == format )
206 {
207 hasPreferredFormat = true ;
208 break ;
209 }
210 }
211
212 for ( UInt16 flavor = 1 ; flavor <= flavors ; ++flavor )
213 {
214 result = GetFlavorType( (DragReference)m_currentDrag, theItem, flavor, &theType );
215 wxDataFormat format( theType ) ;
216 if ( (hasPreferredFormat && format == preferredFormat)
217 || (!hasPreferredFormat && m_dataObject->IsSupportedFormat( format )))
218 {
219 result = GetFlavorFlags( (DragReference)m_currentDrag, theItem, theType, &theFlags );
220 if (result == noErr)
221 {
222 Size dataSize ;
223 Ptr theData ;
224
225 GetFlavorDataSize( (DragReference)m_currentDrag, theItem, theType, &dataSize );
226 if ( theType == kScrapFlavorTypeText )
227 {
228 // this increment is only valid for allocating:
229 // on the next GetFlavorData call it is reset again to the original value
230 dataSize++ ;
231 }
232 else if ( theType == kScrapFlavorTypeUnicode )
233 {
234 // this increment is only valid for allocating:
235 // on the next GetFlavorData call it is reset again to the original value
236 dataSize++ ;
237 dataSize++ ;
238 }
239
240 theData = new char[dataSize];
241
242 GetFlavorData( (DragReference)m_currentDrag, theItem, theType, (void*) theData, &dataSize, 0L );
243 if ( theType == kScrapFlavorTypeText )
244 {
245 theData[dataSize] = 0 ;
246 m_dataObject->SetData( wxDataFormat(wxDF_TEXT), dataSize , theData );
247 }
248 #if wxUSE_UNICODE
249 else if ( theType == kScrapFlavorTypeUnicode )
250 {
251 theData[dataSize + 0] =
252 theData[dataSize + 1] = 0 ;
253 m_dataObject->SetData( wxDataFormat(wxDF_UNICODETEXT), dataSize , theData );
254 }
255 #endif
256 else if ( theType == kDragFlavorTypeHFS )
257 {
258 wxFileDataObject *fdo = dynamic_cast<wxFileDataObject*>(m_dataObject);
259 wxASSERT( fdo != NULL );
260
261 if ((theData != NULL) && (fdo != NULL))
262 {
263 HFSFlavor* theFile = (HFSFlavor*) theData ;
264 wxString name = wxMacFSSpec2MacFilename( &theFile->fileSpec ) ;
265
266 if ( !firstFileAdded )
267 {
268 // reset file list
269 fdo->SetData( 0 , "" ) ;
270 firstFileAdded = true ;
271 }
272
273 if (!name.IsEmpty())
274 fdo->AddFile( name ) ;
275 }
276 }
277 else
278 {
279 m_dataObject->SetData( format, dataSize, theData );
280 }
281
282 delete [] theData;
283 }
284 break ;
285 }
286 }
287 }
288 }
289
290 return true ;
291 }
292
293 //-------------------------------------------------------------------------
294 // wxDropSource
295 //-------------------------------------------------------------------------
296
297 //-----------------------------------------------------------------------------
298 // drag request
299
300 wxDropSource::wxDropSource(wxWindow *win,
301 const wxCursor &cursorCopy,
302 const wxCursor &cursorMove,
303 const wxCursor &cursorStop)
304 : wxDropSourceBase(cursorCopy, cursorMove, cursorStop)
305 {
306 wxMacEnsureTrackingHandlersInstalled() ;
307
308 m_window = win;
309 }
310
311 wxDropSource::wxDropSource(wxDataObject& data,
312 wxWindow *win,
313 const wxCursor &cursorCopy,
314 const wxCursor &cursorMove,
315 const wxCursor &cursorStop)
316 : wxDropSourceBase(cursorCopy, cursorMove, cursorStop)
317 {
318 wxMacEnsureTrackingHandlersInstalled() ;
319
320 SetData( data );
321 m_window = win;
322 }
323
324 wxDropSource::~wxDropSource()
325 {
326 }
327
328 wxDragResult wxDropSource::DoDragDrop(int flags)
329 {
330 wxASSERT_MSG( m_data, wxT("Drop source: no data") );
331
332 if (!m_data)
333 return (wxDragResult) wxDragNone;
334 if (m_data->GetFormatCount() == 0)
335 return (wxDragResult) wxDragNone;
336
337 OSErr result;
338 DragReference theDrag;
339 RgnHandle dragRegion;
340 if ((result = NewDrag(&theDrag)) != noErr)
341 return wxDragNone ;
342
343 // add data to drag
344 size_t formatCount = m_data->GetFormatCount() ;
345 wxDataFormat *formats = new wxDataFormat[formatCount] ;
346 m_data->GetAllFormats( formats ) ;
347 ItemReference theItem = 1 ;
348
349 for ( size_t i = 0 ; i < formatCount ; ++i )
350 {
351 size_t dataSize = m_data->GetDataSize( formats[i] ) ;
352 Ptr dataPtr = new char[dataSize] ;
353 m_data->GetDataHere( formats[i] , dataPtr ) ;
354 OSType type = formats[i].GetFormatId() ;
355 if ( type == 'TEXT' || type == 'utxt' )
356 {
357 if ( dataSize > 0 )
358 dataSize-- ;
359 dataPtr[ dataSize ] = 0 ;
360 if ( type == 'utxt' )
361 {
362 if ( dataSize > 0 )
363 dataSize-- ;
364 dataPtr[ dataSize ] = 0 ;
365 }
366
367 AddDragItemFlavor( theDrag, theItem, type , dataPtr, dataSize, 0 );
368 }
369 else if (type == kDragFlavorTypeHFS )
370 {
371 HFSFlavor theFlavor ;
372 OSErr err = noErr;
373 CInfoPBRec cat;
374
375 wxMacFilename2FSSpec( wxString( dataPtr, *wxConvCurrent ), &theFlavor.fileSpec ) ;
376
377 memset( &cat, 0, sizeof(cat) );
378 cat.hFileInfo.ioNamePtr = theFlavor.fileSpec.name;
379 cat.hFileInfo.ioVRefNum = theFlavor.fileSpec.vRefNum;
380 cat.hFileInfo.ioDirID = theFlavor.fileSpec.parID;
381 cat.hFileInfo.ioFDirIndex = 0;
382 err = PBGetCatInfoSync( &cat );
383 if (err == noErr)
384 {
385 theFlavor.fdFlags = cat.hFileInfo.ioFlFndrInfo.fdFlags;
386 if (theFlavor.fileSpec.parID == fsRtParID)
387 {
388 theFlavor.fileCreator = 'MACS';
389 theFlavor.fileType = 'disk';
390 }
391 else if ((cat.hFileInfo.ioFlAttrib & ioDirMask) != 0)
392 {
393 theFlavor.fileCreator = 'MACS';
394 theFlavor.fileType = 'fold';
395 }
396 else
397 {
398 theFlavor.fileCreator = cat.hFileInfo.ioFlFndrInfo.fdCreator;
399 theFlavor.fileType = cat.hFileInfo.ioFlFndrInfo.fdType;
400 }
401
402 AddDragItemFlavor( theDrag, theItem, type , &theFlavor, sizeof(theFlavor), 0 );
403 }
404 }
405 else
406 {
407 AddDragItemFlavor( theDrag, theItem, type , dataPtr, dataSize, 0 );
408 }
409
410 delete [] dataPtr ;
411 }
412
413 delete [] formats ;
414
415 dragRegion = NewRgn();
416 RgnHandle tempRgn = NewRgn() ;
417
418 EventRecord* ev = NULL ;
419
420 #if !TARGET_CARBON // TODO
421 ev = (EventRecord*) wxTheApp->MacGetCurrentEvent() ;
422 #else
423 {
424 EventRecord rec ;
425 ev = &rec ;
426 wxMacConvertEventToRecord( (EventRef) wxTheApp->MacGetCurrentEvent() , &rec ) ;
427 }
428 #endif
429
430 const short dragRegionOuterBoundary = 10 ;
431 const short dragRegionInnerBoundary = 9 ;
432
433 SetRectRgn(
434 dragRegion , ev->where.h - dragRegionOuterBoundary ,
435 ev->where.v - dragRegionOuterBoundary ,
436 ev->where.h + dragRegionOuterBoundary ,
437 ev->where.v + dragRegionOuterBoundary ) ;
438
439 SetRectRgn(
440 tempRgn , ev->where.h - dragRegionInnerBoundary ,
441 ev->where.v - dragRegionInnerBoundary ,
442 ev->where.h + dragRegionInnerBoundary ,
443 ev->where.v + dragRegionInnerBoundary ) ;
444
445 DiffRgn( dragRegion , tempRgn , dragRegion ) ;
446 DisposeRgn( tempRgn ) ;
447
448 // TODO: work with promises in order to return data
449 // only when drag was successfully completed
450
451 gTrackingGlobals.m_currentSource = this;
452 result = TrackDrag( theDrag, ev, dragRegion );
453 DisposeRgn( dragRegion );
454 DisposeDrag( theDrag );
455 gTrackingGlobals.m_currentSource = NULL;
456
457 bool optionDown = GetCurrentKeyModifiers() & optionKey;
458 wxDragResult dndresult = wxDragCopy;
459 if ( flags != wxDrag_CopyOnly )
460 // on mac the option key is always the indication for copy
461 dndresult = optionDown ? wxDragCopy : wxDragMove;
462
463 return dndresult;
464 }
465
466 bool wxDropSource::MacInstallDefaultCursor(wxDragResult effect)
467 {
468 const wxCursor& cursor = GetCursor(effect);
469 bool result = cursor.Ok();
470
471 if ( result )
472 cursor.MacInstall();
473
474 return result;
475 }
476
477 bool gTrackingGlobalsInstalled = false ;
478
479 // passing the globals via refcon is not needed by the CFM and later architectures anymore
480 // but I'll leave it in there, just in case...
481
482 pascal OSErr wxMacWindowDragTrackingHandler(
483 DragTrackingMessage theMessage, WindowPtr theWindow,
484 void *handlerRefCon, DragReference theDrag );
485 pascal OSErr wxMacWindowDragReceiveHandler(
486 WindowPtr theWindow, void *handlerRefCon,
487 DragReference theDrag );
488
489 void wxMacEnsureTrackingHandlersInstalled()
490 {
491 if ( !gTrackingGlobalsInstalled )
492 {
493 OSErr result;
494
495 result = InstallTrackingHandler( NewDragTrackingHandlerUPP(wxMacWindowDragTrackingHandler), 0L, &gTrackingGlobals );
496 wxASSERT( result == noErr );
497
498 result = InstallReceiveHandler( NewDragReceiveHandlerUPP(wxMacWindowDragReceiveHandler), 0L, &gTrackingGlobals );
499 wxASSERT( result == noErr );
500
501 gTrackingGlobalsInstalled = true;
502 }
503 }
504
505 pascal OSErr wxMacWindowDragTrackingHandler(
506 DragTrackingMessage theMessage, WindowPtr theWindow,
507 void *handlerRefCon, DragReference theDrag )
508 {
509 MacTrackingGlobals* trackingGlobals = (MacTrackingGlobals*) handlerRefCon;
510
511 Point mouse, localMouse;
512 DragAttributes attributes;
513
514 GetDragAttributes( theDrag, &attributes );
515
516 wxTopLevelWindowMac* toplevel = wxFindWinFromMacWindow( theWindow ) ;
517
518 bool optionDown = GetCurrentKeyModifiers() & optionKey ;
519 wxDragResult result = optionDown ? wxDragCopy : wxDragMove;
520
521 switch (theMessage)
522 {
523 case kDragTrackingEnterHandler:
524 case kDragTrackingLeaveHandler:
525 break;
526
527 case kDragTrackingEnterWindow:
528 if (trackingGlobals != NULL)
529 {
530 trackingGlobals->m_currentTargetWindow = NULL ;
531 trackingGlobals->m_currentTarget = NULL ;
532 }
533 break;
534
535 case kDragTrackingInWindow:
536 if (trackingGlobals == NULL)
537 break;
538 if (toplevel == NULL)
539 break;
540
541 GetDragMouse( theDrag, &mouse, 0L );
542 localMouse = mouse;
543 GlobalToLocal( &localMouse );
544
545 {
546 wxWindow *win = NULL ;
547 ControlPartCode controlPart ;
548 ControlRef control = wxMacFindControlUnderMouse(
549 toplevel , localMouse , theWindow , &controlPart ) ;
550 if ( control )
551 win = wxFindControlFromMacControl( control ) ;
552 else
553 win = toplevel ;
554
555 int localx , localy ;
556 localx = localMouse.h ;
557 localy = localMouse.v ;
558
559 if ( win )
560 win->MacRootWindowToWindow( &localx , &localy ) ;
561 if ( win != trackingGlobals->m_currentTargetWindow )
562 {
563 if ( trackingGlobals->m_currentTargetWindow )
564 {
565 // this window is left
566 if ( trackingGlobals->m_currentTarget )
567 {
568 HideDragHilite( theDrag );
569 trackingGlobals->m_currentTarget->SetCurrentDrag( theDrag );
570 trackingGlobals->m_currentTarget->OnLeave();
571 trackingGlobals->m_currentTarget = NULL;
572 trackingGlobals->m_currentTargetWindow = NULL;
573 }
574 }
575
576 if ( win )
577 {
578 // this window is entered
579 trackingGlobals->m_currentTargetWindow = win ;
580 trackingGlobals->m_currentTarget = win->GetDropTarget() ;
581 {
582 if ( trackingGlobals->m_currentTarget )
583 {
584 trackingGlobals->m_currentTarget->SetCurrentDrag( theDrag ) ;
585 result = trackingGlobals->m_currentTarget->OnEnter( localx , localy , result ) ;
586 }
587
588 if ( result != wxDragNone )
589 {
590 int x , y ;
591
592 x = y = 0 ;
593 win->MacWindowToRootWindow( &x , &y ) ;
594 RgnHandle hiliteRgn = NewRgn() ;
595 Rect r = { y , x , y + win->GetSize().y , x + win->GetSize().x } ;
596 RectRgn( hiliteRgn , &r ) ;
597 ShowDragHilite( theDrag, hiliteRgn, true );
598 DisposeRgn( hiliteRgn ) ;
599 }
600 }
601 }
602 }
603 else
604 {
605 if ( trackingGlobals->m_currentTarget )
606 {
607 trackingGlobals->m_currentTarget->SetCurrentDrag( theDrag ) ;
608 trackingGlobals->m_currentTarget->OnDragOver( localx , localy , result ) ;
609 }
610 }
611
612 // set cursor for OnEnter and OnDragOver
613 if ( trackingGlobals->m_currentSource && !trackingGlobals->m_currentSource->GiveFeedback( result ) )
614 {
615 if ( !trackingGlobals->m_currentSource->MacInstallDefaultCursor( result ) )
616 {
617 switch ( result )
618 {
619 case wxDragCopy :
620 {
621 wxCursor cursor(wxCURSOR_COPY_ARROW) ;
622 cursor.MacInstall() ;
623 }
624 break ;
625
626 case wxDragMove :
627 {
628 wxCursor cursor(wxCURSOR_ARROW) ;
629 cursor.MacInstall() ;
630 }
631 break ;
632
633 case wxDragNone :
634 {
635 wxCursor cursor(wxCURSOR_NO_ENTRY) ;
636 cursor.MacInstall() ;
637 }
638 break ;
639
640 case wxDragError:
641 case wxDragLink:
642 case wxDragCancel:
643 default:
644 // put these here to make gcc happy
645 ;
646 }
647 }
648 }
649 }
650 break;
651
652 case kDragTrackingLeaveWindow:
653 if (trackingGlobals == NULL)
654 break;
655
656 if (trackingGlobals->m_currentTarget)
657 {
658 trackingGlobals->m_currentTarget->SetCurrentDrag( theDrag );
659 trackingGlobals->m_currentTarget->OnLeave();
660 HideDragHilite( theDrag );
661 trackingGlobals->m_currentTarget = NULL;
662 }
663 trackingGlobals->m_currentTargetWindow = NULL;
664 break;
665
666 default:
667 break;
668 }
669
670 return noErr;
671 }
672
673 pascal OSErr wxMacWindowDragReceiveHandler(
674 WindowPtr theWindow,
675 void *handlerRefCon,
676 DragReference theDrag)
677 {
678 MacTrackingGlobals* trackingGlobals = (MacTrackingGlobals*)handlerRefCon;
679 if ( trackingGlobals->m_currentTarget )
680 {
681 Point mouse, localMouse ;
682 int localx, localy ;
683
684 trackingGlobals->m_currentTarget->SetCurrentDrag( theDrag ) ;
685 GetDragMouse(theDrag, &mouse, 0L);
686 localMouse = mouse;
687 GlobalToLocal(&localMouse);
688 localx = localMouse.h ;
689 localy = localMouse.v ;
690
691 // TODO : should we use client coordinates?
692 if ( trackingGlobals->m_currentTargetWindow )
693 trackingGlobals->m_currentTargetWindow->MacRootWindowToWindow( &localx , &localy ) ;
694 if ( trackingGlobals->m_currentTarget->OnDrop( localx , localy ) )
695 {
696 bool optionDown = GetCurrentKeyModifiers() & optionKey ;
697 wxDragResult result = optionDown ? wxDragCopy : wxDragMove;
698 trackingGlobals->m_currentTarget->OnData( localx , localy , result ) ;
699 }
700 }
701
702 return noErr;
703 }
704
705 #endif