home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 April: Mac OS SDK / Dev.CD Apr 99 SDK1.toast / Development Kits / ColorSync 2.5.1 SDK / Sample Code / CSDemo 2.5 / ShellSources / dragUtils.c < prev    next >
Encoding:
Text File  |  1998-09-09  |  29.2 KB  |  1,006 lines  |  [TEXT/CWIE]

  1. // Simple framework for Macintosh sample code
  2. //
  3. // David Hayward 
  4. // Developer Technical Support
  5. // AppleLink: DEVSUPPORT
  6. //
  7. // Copyrite 1995, Apple Computer,Inc
  8. //
  9. // This file contains the framework's AppleEvent handlers
  10. // 
  11. // 9/13/94    nick    first cut
  12. // 12/13/94    david    several modifications
  13.  
  14. #include <Types.h>
  15. #include <Memory.h>
  16. #include <Gestalt.h>
  17. #include <Errors.h>
  18. #include <CodeFragments.h>
  19. #include <Processes.h>
  20. #include <AppleEvents.h>
  21. #include <QuickDraw.h>
  22. #include <QDOffScreen.h>
  23. #include <Windows.h>
  24. #include <Folders.h>
  25. #include <Files.h>
  26. #include <Drag.h>
  27.  
  28. #include "aeUtils.h"
  29. #include "dragUtils.h"
  30.  
  31.  
  32. /**\
  33. |**| ==============================================================================
  34. |**| PRIVATE GLOBALS
  35. |**| ==============================================================================
  36. \**/
  37. static    Boolean         acceptableDrag ;
  38. static    long            hilitedContentIndex ;
  39.  
  40. /**\
  41. |**| ==============================================================================
  42. |**| PRIVATE FUNCTION PROTOTYPES
  43. |**| ==============================================================================
  44. \**/
  45. static    OSErr            InstallDragZonesHandlers    ( DragZonesHdl zones ) ;
  46. static    OSErr            RemoveDragZonesHandlers        ( DragZonesHdl zones ) ;
  47. static    pascal OSErr    DragZoneTrackingHandler        ( short theMessage, WindowRef theWindow, void *handlerRefCon, DragReference theDrag) ;
  48. static    pascal OSErr    DragZoneReceiveHandler        ( WindowRef theWindow, void *handlerRefCon, DragReference drag ) ;
  49.  
  50. /**\
  51. |**| ==============================================================================
  52. |**| PRIVATE TYPEDEFS
  53. |**| ==============================================================================
  54. \**/
  55. typedef struct DragZoneRecvData
  56. {
  57.     DragZoneHdl        zone ;
  58.     WindowRef        window ;
  59.     Point            location ;
  60.     DragZoneRecvUPP    callback ;
  61.     Size            dataSize ;
  62.     char            *dataPtr[] ;
  63. } DragZoneRecvDataRec, *DragZoneRecvDataPtr, **DragZoneRecvDataHdl ;
  64.  
  65. enum {
  66.     kDraggingClass             = 'drag',
  67.     kDragDrawID                = 'draw',
  68.     kDragSendID                = 'send',
  69.     kDragReceiveID            = 'recv',
  70.     kDragTrackID            = 'trak',
  71.     kDragDragID                = 'drag',
  72.     keyPrivateData            = 'priv'
  73. };
  74.  
  75.  
  76. /**\
  77. |**| ==============================================================================
  78. |**| PRIVATE GLOBALS
  79. |**| ==============================================================================
  80. \**/
  81. OSErr        gDrag_present_err = 1;
  82. OSErr        gDrag_available_err = 1 ;
  83. OSErr        gDrag_initialized_err = 1;
  84.  
  85.  
  86. /**\
  87. |**| ==============================================================================
  88. |**| PUBLIC FUNCTIONS
  89. |**| ==============================================================================
  90. \**/
  91.  
  92.  
  93. /*------------------------------------------------------------------------------*\
  94.     Drag_present
  95.  *------------------------------------------------------------------------------*
  96.         This function returns noErr if drag and drop support is present 
  97.         (i.e passes gestalt) and returns an error otherwise.
  98.         It also sets the private global gDrag_present_err based on the result.
  99. \*------------------------------------------------------------------------------*/
  100. OSErr Drag_present ( void )
  101. {
  102.     OSErr err;
  103.     long response;
  104.     
  105.     if ( !gDrag_present_err )
  106.         return noErr;
  107.  
  108.     err = Gestalt(gestaltDragMgrAttr,&response) ;
  109.     if (!err)
  110.         if ((response & (1<<gestaltDragMgrPresent)) == 0 )
  111.             err = 1 ;                     // should return something else
  112.     
  113. #ifdef powerc
  114.     // This is a sanity check to see if the PowerPC DragLib is installed
  115.     // just in case we are "weak" against DragLib
  116.     if (!err)
  117.         if ( kUnresolvedCFragSymbolAddress == (long)NewDrag) 
  118.             err = 1;                // QuickDraw GX is not available in Power Mac
  119. #endif
  120.  
  121.     gDrag_present_err = err;
  122.     return err;
  123. }
  124.  
  125.  
  126. /*------------------------------------------------------------------------------*\
  127.     Drag_available
  128.  *------------------------------------------------------------------------------*
  129.         This function returns noErr if drag and drop support is available
  130.         (i.e present and initialized) to the application and returns an error otherwise.
  131.         It also sets the global gDrag_available_err based on the result.
  132. \*------------------------------------------------------------------------------*/
  133. OSErr Drag_available ( void ) 
  134. {
  135.     OSErr err;
  136.  
  137.     if ( !gDrag_available_err )
  138.         return noErr;
  139.     
  140.     err = Drag_present();
  141.     if ( !err )
  142.         err = Drag_initialize();
  143.     
  144.     gDrag_available_err = err;
  145.      return err ;
  146. }
  147.  
  148. /*------------------------------------------------------------------------------*\
  149.     Drag_initialize
  150.  *------------------------------------------------------------------------------*
  151.         This function initializes all the drag stuff.
  152.         It should be called early in the application.
  153. \*------------------------------------------------------------------------------*/
  154. OSErr Drag_initialize ( void ) 
  155. {
  156.     OSErr err;
  157.  
  158.     if ( !gDrag_initialized_err )
  159.         return noErr;
  160.  
  161.     err = Drag_present();
  162.     if ( !err )
  163.     {
  164.         err = RegisterDragAppleEvents();
  165.     }
  166.         
  167.     gDrag_initialized_err = err;
  168.     return err;
  169. }
  170.  
  171.  
  172. //-----------------------------------------------------------------------
  173. // DragIsInRect returns true if the current mouse is in the content
  174. // area of the window (but not necessarily in the visible rgn)
  175.  
  176. Boolean DragIsInRect ( DragReference drag, WindowRef window, Rect *rect )
  177. {
  178.     Point        mousePt ;
  179.     GrafPtr        savePort ;
  180.     
  181.     (void) GetDragMouse( drag, &mousePt, nil ) ;
  182.     
  183.     GetPort( &savePort ) ;
  184.     SetPort( (GrafPtr)window ) ;
  185.     GlobalToLocal( &mousePt ) ;
  186.     SetPort( savePort ) ;
  187.     
  188.     return PtInRect( mousePt, rect ) ;
  189. }
  190.  
  191.  
  192. //-----------------------------------------------------------------------
  193. // DragIsInSourceWindow returns true if the drag in progress
  194. // is in the same window it originated in
  195. //
  196. // DragIsInSourceWindow is called by the tracking and receive handlers
  197. //
  198. // Note that, if this application allowed items to be dragged within its windows, 
  199. // this function would not be appropriate.  Instead, hilighting would probably occur
  200. // in the source window when the dragHasLeftSourceWindow flag is set, and the receive
  201. // handler wouldn't check this at all
  202.  
  203. Boolean DragIsInSourceWindow ( DragReference drag )
  204. {
  205.     DragAttributes currDragFlags;
  206.     (void) GetDragAttributes( drag, &currDragFlags ) ;
  207.     return ( (currDragFlags & kDragInsideSenderWindow) != 0) ;
  208. }
  209.  
  210.  
  211. //
  212. //    DropLocationIsFinderTrash
  213. //
  214. //    Returns true if the given dropLocation AEDesc is a descriptor of the Finder's Trash.
  215. //
  216.  
  217. Boolean DropLocationIsFinderTrash ( DragReference drag )
  218. {    
  219.     AEDesc            dropLocation ;
  220.     OSErr            result;
  221.     AEDesc            dropSpec;
  222.     FSSpec            *theSpec;
  223.     CInfoPBRec        thePB;
  224.     short            trashVRefNum;
  225.     long            trashDirID;
  226.  
  227.     GetDropLocation( drag, &dropLocation ) ;
  228.     
  229.     //    Coerce the dropLocation descriptor to an FSSpec. If there's no dropLocation or
  230.     //    it can't be coerced into an FSSpec, then it couldn't have been the Trash.
  231.  
  232.     if ((dropLocation.descriptorType != typeNull) &&
  233.         (AECoerceDesc(&dropLocation, typeFSS, &dropSpec) == noErr))
  234.     {
  235.         HLock(dropSpec.dataHandle) ;
  236.         theSpec = (FSSpec *) *dropSpec.dataHandle;
  237.  
  238.         //    Get the directory ID of the given dropLocation object.
  239.         thePB.dirInfo.ioCompletion = 0L;
  240.         thePB.dirInfo.ioNamePtr = (StringPtr) &theSpec->name;
  241.         thePB.dirInfo.ioVRefNum = theSpec->vRefNum;
  242.         thePB.dirInfo.ioFDirIndex = 0;
  243.         thePB.dirInfo.ioDrDirID = theSpec->parID;
  244.  
  245.         result = PBGetCatInfoSync(&thePB) ;
  246.  
  247.         HUnlock(dropSpec.dataHandle) ;
  248.         AEDisposeDesc(&dropSpec) ;
  249.  
  250.         if (result != noErr)
  251.             return false ;
  252.  
  253.         //    If the result is not a directory, it must not be the Trash.
  254.         if (!(thePB.dirInfo.ioFlAttrib & (1 << 4)))
  255.             return false ;
  256.  
  257.         //    Get information about the Trash folder.
  258.         FindFolder(theSpec->vRefNum, kTrashFolderType, kCreateFolder, &trashVRefNum, &trashDirID) ;
  259.  
  260.         //    If the directory ID of the dropLocation object is the same as the directory ID
  261.         //    returned by FindFolder, then the drop must have occurred into the Trash.
  262.         if (thePB.dirInfo.ioDrDirID == trashDirID)
  263.             return true ;
  264.     }
  265.  
  266.     return false ;
  267. }
  268.  
  269.  
  270. /*------------------------------------------------------------------------------*\
  271.     NewDragZonesHandle
  272.  *------------------------------------------------------------------------------*
  273. \*------------------------------------------------------------------------------*/
  274. DragZonesHdl NewDragZones ( WindowRef window )
  275. {
  276.     DragZonesHdl    zones ;
  277.     
  278.     zones = (DragZonesHdl) NewHandleClear( sizeof(DragZonesRec) ) ;
  279.     if (zones==nil) return nil ;
  280.     
  281.     (**zones).count = 0 ;
  282.     (**zones).window = window;
  283.     
  284.     if (InstallDragZonesHandlers(zones) != noErr)
  285.     {
  286.         DisposeHandle( (Handle)zones );
  287.         zones = nil;
  288.     }
  289.     
  290.     return zones ;
  291. }
  292.  
  293.  
  294. /*------------------------------------------------------------------------------*\
  295.     DisposeDragZonesHandle
  296.  *------------------------------------------------------------------------------*
  297. \*------------------------------------------------------------------------------*/
  298. void DisposeDragZonesHandle ( DragZonesHdl zones )
  299. {
  300.     DragZoneHdl        zone ;
  301.         
  302.     RemoveDragZonesHandlers( zones ) ;
  303.     
  304.     while ( (**zones).count )
  305.     {
  306.         (**zones).count--;
  307.         zone = (**zones).item[(**zones).count];
  308.         DisposeRoutineDescriptor( (**zone).dragRecvUPP ) ;
  309.         DisposeHandle( (Handle)zone );
  310.     }
  311.     
  312.     DisposeHandle( (Handle)zones );
  313.     
  314.     return ;
  315. }
  316.  
  317.  
  318. /*------------------------------------------------------------------------------*\
  319.     AddDragZone
  320.  *------------------------------------------------------------------------------*
  321. \*------------------------------------------------------------------------------*/
  322. OSErr AddDragZone ( DragZonesHdl zones, DragZonePtr zone )
  323. {
  324.     DragZoneHdl        newZone ;
  325.     long            newCount ;
  326.     Size            newHandleSize ;
  327.     OSErr            err ;
  328.     
  329.     newCount = (**zones).count + 1 ;
  330.     newHandleSize = sizeof(DragZonesRec) + newCount*sizeof(DragZoneHdl) ;
  331.     SetHandleSize ( (Handle)zones, newHandleSize ) ;
  332.     err = MemError() ;
  333.     if (err) return err ;
  334.  
  335.     newZone = (DragZoneHdl) NewHandleClear( sizeof(DragZoneRec) ) ;
  336.     if (newZone==nil) return MemError() ;
  337.     
  338.     **newZone = *zone ;
  339.     (**zones).item[newCount-1] = newZone ;
  340.     (**zones).count = newCount ;
  341.     
  342.     return err ;
  343. }
  344.  
  345.  
  346. /*------------------------------------------------------------------------------*\
  347.     DelDragZone
  348.  *------------------------------------------------------------------------------*
  349. \*------------------------------------------------------------------------------*/
  350. OSErr DelDragZone ( DragZonesHdl zones, DragZoneHdl zone )
  351. {
  352.     long            index, newIndex ;
  353.     long            oldCount, newCount ;
  354.     Size            newHandleSize ;
  355.     OSErr            err ;
  356.     
  357.     oldCount = (**zones).count ;
  358.     newCount = oldCount - 1 ;
  359.     
  360.     for ( index=newIndex=0; index<oldCount; index++ )
  361.         if ( (**zones).item[index] != zone )
  362.         {
  363.             (**zones).item[newIndex] = (**zones).item[index] ;
  364.             newIndex++ ;
  365.         }
  366.     
  367.     (**zones).count = newCount ;
  368.     
  369.     newHandleSize = sizeof(DragZonesRec) + newCount*sizeof(DragZoneHdl) ;
  370.     SetHandleSize ( (Handle)zones, newHandleSize ) ;
  371.     err = MemError() ;
  372.     
  373.     DisposeHandle( (Handle)zone ) ;
  374.     return err ;
  375. }
  376.  
  377.  
  378. /*------------------------------------------------------------------------------*\
  379.     FindDragZones
  380.  *------------------------------------------------------------------------------*
  381.         This routine searches through the DragZones data structure to locate those 
  382.         DragZones that have given flavor and/or fileType.  It can be used either 
  383.         to count the number of matches or to return the matches in the result buffer.
  384.         The logic is basically the following:
  385.           if result buffer is nil
  386.             return num of DragZones that match the flavor and/or fileType parameters
  387.             the index and count fields are ignored
  388.           else
  389.             copy into result buffer up to count DragZoneHdls that match the flavor
  390.             and/or fileType parameters starting with the index-th match
  391.             return the the number of DragZoneHdl copied into the buffer
  392. \*------------------------------------------------------------------------------*/
  393. short    FindDragZones ( DragZonesHdl zones,
  394.                         FlavorType flavor,
  395.                         OSType HFSfileType,
  396.                         short index,
  397.                         short count,
  398.                         DragZoneHdl *result )
  399. {
  400.     long            z ;
  401.     DragZoneHdl        zone ;
  402.     short            n = 0;
  403.     short            stopCount, foundCount;
  404.     Boolean            foundOne, sameFlavor, sameFileType;
  405.     
  406.     stopCount = count ;
  407.     foundCount = z = 0 ;
  408.  
  409.     if ((**zones).count==0) return 0 ;        // no zones are in the DragZonesHdl
  410.  
  411.     do {
  412.         zone = (**zones).item[z] ;
  413.         foundOne = false;        
  414.         if ( zone != nil )
  415.         {
  416.             if ( flavor==nil )
  417.                 foundOne = true;
  418.             else
  419.             {
  420.                 sameFlavor = ( flavor==(**zone).flavor ) ;
  421.                 sameFileType = ( HFSfileType==(**zone).HFSfileType ) ;
  422.     
  423.                 if ( sameFlavor )
  424.                 {
  425.                     if (flavor!=flavorTypeHFS) 
  426.                         foundOne = true;
  427.                     else if ( sameFileType )
  428.                         foundOne = true;
  429.                 }
  430.             }
  431.     
  432.             if (foundOne)
  433.             {
  434.                 if  ( result==nil )
  435.                     foundCount++ ;
  436.                 else
  437.                 {
  438.                     n++;
  439.                     if (n>=index)
  440.                     {
  441.                         foundCount++ ;
  442.                         result[foundCount-1] = zone;
  443.                     }
  444.                 }
  445.             }
  446.         }
  447.         z++ ;
  448.  
  449.     } while ( (z!=(**zones).count)  &&  ((foundCount<stopCount) || (result==nil)) ) ;
  450.     
  451.     return foundCount;
  452. }
  453.  
  454.  
  455. /**\
  456. |**| ==============================================================================
  457. |**| PRIVATE FUNCTIONS
  458. |**| ==============================================================================
  459. \**/
  460.  
  461.  
  462. /*------------------------------------------------------------------------------*\
  463.     InstallDragZonesHandlers
  464.  *------------------------------------------------------------------------------*
  465. \*------------------------------------------------------------------------------*/
  466. static OSErr InstallDragZonesHandlers ( DragZonesHdl zones )
  467. {
  468.     OSErr        errT, errR ;
  469.     WindowRef    window;
  470.     
  471.     window = (**zones).window;
  472.     (**zones).trackingHandler = NewDragTrackingHandlerProc(DragZoneTrackingHandler) ;
  473.     (**zones).receiveHandler  = NewDragReceiveHandlerProc(DragZoneReceiveHandler) ;
  474.     
  475.     errT = InstallTrackingHandler( (**zones).trackingHandler, (WindowPtr)window, (void *)zones ) ;
  476.     errR = InstallReceiveHandler( (**zones).receiveHandler, (WindowPtr)window, (void *)zones ) ;
  477.     
  478.     if (errT) DisposeRoutineDescriptor( (**zones).trackingHandler ) ;
  479.     if (errR) DisposeRoutineDescriptor( (**zones).receiveHandler ) ;
  480.     
  481.     if (errT) (**zones).trackingHandler = nil ;
  482.     if (errR) (**zones).receiveHandler  = nil ;
  483.     
  484.     return (errT) ? (errT) : (errR) ;        // return one of the errors
  485. }
  486.  
  487.  
  488. /*------------------------------------------------------------------------------*\
  489.     RemoveDragZonesHandlers
  490.  *------------------------------------------------------------------------------*
  491. \*------------------------------------------------------------------------------*/
  492. static OSErr RemoveDragZonesHandlers ( DragZonesHdl zones )
  493. {
  494.     OSErr        errT, errR ;
  495.     WindowRef    window;
  496.     
  497.     window = (**zones).window;
  498.     errT = RemoveTrackingHandler( (**zones).trackingHandler, (WindowPtr)window ) ;
  499.     errR = RemoveReceiveHandler( (**zones).receiveHandler, (WindowPtr)window ) ;
  500.  
  501.     if (!errT) DisposeRoutineDescriptor( (**zones).trackingHandler ) ;
  502.     if (!errR) DisposeRoutineDescriptor( (**zones).receiveHandler ) ;
  503.     
  504.     if (!errT) (**zones).trackingHandler = nil ;
  505.     if (!errR) (**zones).receiveHandler  = nil ;
  506.  
  507.     return (errT) ? (errT) : (errR) ;        // return one of the errors
  508. }
  509.  
  510.  
  511. /*------------------------------------------------------------------------------*\
  512.     DragZoneTrackingHandler
  513.  *------------------------------------------------------------------------------*
  514. \*------------------------------------------------------------------------------*/
  515. static pascal OSErr DragZoneTrackingHandler ( short theMessage, WindowRef theWindow,
  516.                                     void *handlerRefCon, DragReference drag )
  517. {
  518.     OSErr            err ;
  519.     RgnHandle        tempRgn;
  520.     Rect            rect;
  521.     long            mouseContentIndex = -1 ;
  522.     OSErr            retCode;
  523.     DragZonesHdl    zones = (DragZonesHdl)handlerRefCon;
  524.     
  525.     retCode = noErr ;
  526.     switch (theMessage)
  527.     {
  528.         case kDragTrackingEnterHandler:
  529.             break;
  530.             
  531.         case kDragTrackingEnterWindow: 
  532.             // determine if the items are acceptable and store that
  533.             // flag in the globals, plus reset the hilighted global flag
  534.             acceptableDrag = DragZoneItemsAcceptable(drag,zones) ;
  535.             hilitedContentIndex = -1 ;
  536.             break;
  537.         
  538.         case kDragTrackingInWindow:
  539.         case kDragTrackingLeaveWindow:
  540.  
  541.             // highlighting of the window during a drag is done here. 
  542.             // Do it only if we can accept these items and we're not in the source window...
  543.             if ( acceptableDrag && !DragIsInSourceWindow(drag) ) 
  544.             {    
  545.                 // unless the mouse is leaving the visible area of the
  546.                 // window, check if it's in the window's content region
  547.                 
  548.                 if (theMessage == kDragTrackingLeaveWindow)
  549.                     mouseContentIndex = -1L;
  550.                 else
  551.                     mouseContentIndex = DragZoneIsInWhichRect( drag, theWindow, zones ) ;
  552.                                 
  553.                 // if the mouse is not in the content region
  554.                 // and the window is hilighted, erase the hilight
  555.                 
  556.                 if ( mouseContentIndex!=hilitedContentIndex )
  557.                 {    
  558.                     // erase the hilight and restore the port
  559.                     err = HideDragHilite( drag ) ;
  560.                     if ( !err )
  561.                         hilitedContentIndex = -1;    // remember that nothing hilighted
  562.                 }
  563.  
  564.                 // if the mouse is in the content area and the window
  565.                 // is not yet hilighted, then do the hilighting
  566.                 
  567.                 if ( mouseContentIndex>=0 &&
  568.                      mouseContentIndex!=hilitedContentIndex  )
  569.                 {    
  570.                     // make a region bordering the window content
  571.                     tempRgn = NewRgn() ;
  572.                     rect = (**((**zones).item[mouseContentIndex])).rect ;
  573.                     RectRgn(tempRgn, &rect ) ;
  574.                     
  575.                     // draw the hilight
  576.                     err = ShowDragHilite( drag, tempRgn, true) ;
  577.                     if ( !err )
  578.                         hilitedContentIndex = mouseContentIndex ;        // remember which is hilited
  579.  
  580.                     // free up the region
  581.                     DisposeRgn(tempRgn) ;
  582.                 }
  583.             }
  584.             break;
  585.  
  586.         // do nothing for the leaveHandler message
  587.         case kDragTrackingLeaveHandler:
  588.             break;
  589.         
  590.         // let the drag manager know if we didn't recognize the message
  591.         default:
  592.             retCode = paramErr ;
  593.             break;
  594.     }
  595.     
  596.     return retCode;
  597. }
  598.  
  599.  
  600. /*------------------------------------------------------------------------------*\
  601.     DragZoneReceiveHandler
  602.  *------------------------------------------------------------------------------*
  603. \*------------------------------------------------------------------------------*/
  604. static pascal OSErr DragZoneReceiveHandler ( WindowRef theWindow, void *handlerRefCon, DragReference drag )
  605. {
  606.     OSErr            err ;
  607.     ItemReference    theItem ;
  608.     DragAttributes    attributes ;
  609.     Size            dataSize ;
  610.     short            mouseDownModifiers, mouseUpModifiers ;
  611.     Point            mouseLoc ;
  612.     Handle            dragData = nil ;
  613.     long            mouseContentIndex ;
  614.     DragZoneHdl        iZone ;
  615.     FlavorType        iFlavor ;
  616.     DragZonesHdl    zones = (DragZonesHdl)handlerRefCon;
  617.     
  618.     if (!DragZoneItemsAcceptable(drag,zones) ||
  619.         DragIsInSourceWindow(drag) ) 
  620.         return dragNotAcceptedErr ;
  621.                 
  622.     mouseContentIndex = DragZoneIsInWhichRect( drag, theWindow, zones ) ;
  623.     if ( mouseContentIndex <0 )
  624.         return dragNotAcceptedErr ;
  625.         
  626.     // We will only support one item, so get its reference number.
  627.     err = GetDragItemReferenceNumber( drag, 1, &theItem) ;
  628.     if ( err ) return err;
  629.  
  630.     GetDragAttributes( drag, &attributes) ;
  631.     GetDragModifiers( drag, 0L, &mouseDownModifiers, &mouseUpModifiers) ;
  632.     GetDragMouse( drag, &mouseLoc, nil ) ;
  633.     
  634.     iZone = (**zones).item[mouseContentIndex] ;
  635.     iFlavor = (**iZone).flavor ;
  636.  
  637.     //    Get the item's reference, so we can refer to it.
  638.     GetDragItemReferenceNumber( drag, 1, &theItem) ;
  639.     
  640.     err = GetFlavorDataSize( drag,theItem,iFlavor,&dataSize ) ;
  641.     if ( err ) return err;
  642.         
  643.     // so we either have nothing or something (in the form of prof or PICT data)
  644.     if ( !err )
  645.     {    
  646.         DragZoneRecvUPP theDragZoneRecvUPP;
  647.         
  648.         // create a handle large enough for the data
  649.         dragData = NewHandle( dataSize ) ;
  650.         if( dragData == nil )
  651.             return MemError() ;
  652.         
  653.         // Lock and load, I dunno if GetFlavorData moves memory, I'm just assuming it may...
  654.         //  passing (**dragData) in dereferenced - ASSUMES the handle is locked
  655.         HLock( (Handle)dragData ) ;
  656.         GetFlavorData( drag, theItem, iFlavor, *dragData, &dataSize, 0L) ;
  657.         HUnlock( (Handle)dragData ) ;
  658.  
  659.         theDragZoneRecvUPP = (**(**zones).item[mouseContentIndex]).dragRecvUPP ;
  660.         
  661. /*         err = CallDragZoneRecvProc(
  662.                         theDragZoneRecvUPP,
  663.                         iZone,
  664.                         theWindow,
  665.                         mouseLoc,
  666.                         dragData ) ;
  667. */
  668.         // send it to ourselves
  669.         err = SendDragRecv(
  670.                         iZone,
  671.                         theWindow,
  672.                         mouseLoc,
  673.                         dragData,
  674.                         theDragZoneRecvUPP ) ;
  675.         
  676.         // and dispose of the data and upp
  677.         DisposeHandle( dragData ) ;
  678.         DisposeRoutineDescriptor( theDragZoneRecvUPP ) ;
  679.  
  680.         if ( attributes & kDragHasLeftSenderWindow )
  681.             HideDragHilite( drag ) ;
  682.     }
  683.     
  684.     //DebugStr("\pleaving recv handlr") ;
  685.     return err ;
  686. }
  687.  
  688.  
  689.  
  690. /*------------------------------------------------------------------------------*\
  691.     DragZoneIsInWhichRect
  692.  *------------------------------------------------------------------------------*
  693. \*------------------------------------------------------------------------------*/
  694. long DragZoneIsInWhichRect ( DragReference drag, WindowRef theWindow, DragZonesHdl zones )
  695. {
  696.     OSErr            err ;
  697.     unsigned short    totalItems ;
  698.     long            count, i ;
  699.     long            result ;
  700.     ItemReference    itemRef;
  701.     Size            dataSize;
  702.     HFSFlavor         theHFSFlavor ;
  703.     FlavorFlags        theFlavorFlags;
  704.     DragZoneHdl        iZone ;
  705.     FlavorType        iFlavor ;
  706.     Rect            iRect ;
  707.     
  708.     result = -1;
  709.  
  710.     if ( !DragZoneItemsAcceptable(drag,zones) )
  711.         return 0 ;
  712.         
  713.     // for now, this app can only accept the drag of a single item
  714.     err = CountDragItems( drag, &totalItems ) ;
  715.     if ( err || totalItems != 1) return 0;
  716.         
  717.     // get the reference number of the dragged item
  718.     err = GetDragItemReferenceNumber( drag, 1, &itemRef ) ;
  719.     if ( err ) return 0;
  720.     
  721.     // use GetFlavorFlags to check on flavor existence of PICT data
  722.     // without forcing translation
  723.     
  724.     // for each item in the struct, check to see, if the drag has the flavor of data needed
  725.     // and if the drag is currently within the items bound rect.
  726.     // when we find the first items that passes this test, return its index
  727.     count = (**zones).count ;
  728.     for ( i=0; (result<0) && (i<count); i++ )
  729.     {
  730.         iZone = (**zones).item[i] ;
  731.         iFlavor = (**iZone).flavor ;
  732.         iRect = (**iZone).rect ;
  733.         
  734.         if ( DragIsInRect( drag, theWindow, &iRect ) )
  735.         {
  736.             err = GetFlavorFlags( drag, itemRef, iFlavor, &theFlavorFlags) ;
  737.             if ( !err )
  738.             {
  739.                 if ( iFlavor==flavorTypeHFS )
  740.                 {
  741.                     dataSize = sizeof(HFSFlavor) ;
  742.                     err = GetFlavorData( drag, itemRef, iFlavor, &theHFSFlavor, &dataSize, 0 ) ;
  743.                     if ( (!err) && (theHFSFlavor.fileType == (**iZone).HFSfileType ) ) 
  744.                         result = i;
  745.                 }
  746.                 else
  747.                     result = i;
  748.             }
  749.         }
  750.     }
  751.     return result;
  752. }
  753.  
  754.  
  755. /*------------------------------------------------------------------------------*\
  756.     DragZoneItemsAcceptable
  757.  *------------------------------------------------------------------------------*
  758. \*------------------------------------------------------------------------------*/
  759. Boolean DragZoneItemsAcceptable ( DragReference drag, DragZonesHdl zones )
  760. {
  761.     OSErr            err ;
  762.     unsigned short    totalItems;
  763.     long            count, i ;
  764.     ItemReference    itemRef;
  765.     Boolean            result ;
  766.     Size            dataSize;
  767.     HFSFlavor         theHFSFlavor ;
  768.     FlavorFlags        theFlavorFlags;
  769.     DragZoneHdl        iZone ;
  770.     FlavorType        iFlavor ;
  771.     
  772.     result = false;
  773.  
  774.     // for now, this app can only accept the drag of a single item
  775.     err = CountDragItems( drag, &totalItems) ;
  776.     if ( err || totalItems!=1) return false;
  777.         
  778.     // get the reference number of the dragged item
  779.     err = GetDragItemReferenceNumber( drag, 1, &itemRef ) ;
  780.     if ( err ) return false;
  781.     
  782.     // for each item in the struct, check to see, if the drag has the flavor of data needed
  783.     // if any of the items pass this test then return true
  784.  
  785.     count = (**zones).count ;
  786.     for ( i=0; (!result) && (i<count); i++ )
  787.     {
  788.         iZone = (**zones).item[i] ;
  789.         iFlavor = (**iZone).flavor ;
  790.         
  791.         err = GetFlavorFlags( drag, itemRef, iFlavor, &theFlavorFlags ) ;
  792.         if ( !err )
  793.         {
  794.             if ( iFlavor==flavorTypeHFS )
  795.             {
  796.                 dataSize = sizeof(HFSFlavor) ;
  797.                 err = GetFlavorData( drag, itemRef, iFlavor, &theHFSFlavor, &dataSize, 0 ) ;
  798.                 if ( (!err) && (theHFSFlavor.fileType == (**iZone).HFSfileType ) ) 
  799.                     result = true;
  800.             }
  801.             else
  802.                 result = true;
  803.         }
  804.     }
  805.  
  806.     return result;
  807. }
  808.  
  809.  
  810.  
  811. /*------------------------------------------------------------------------------*\
  812.     RegisterDragAppleEvents
  813.  *------------------------------------------------------------------------------*
  814.         called to register our drag apple event handler
  815. \*------------------------------------------------------------------------------*/
  816. OSErr RegisterDragAppleEvents ( void )
  817. {
  818.     OSErr err ;
  819.     
  820.     err = AEInstallEventHandler( kDraggingClass, kDragReceiveID,
  821.                                  NewAEEventHandlerProc(HandleDragRecv),
  822.                                  0L, false ) ;
  823.     return err ;
  824. }
  825.  
  826.  
  827. /*------------------------------------------------------------------------------*\
  828.     HandleDragRecv
  829.  *------------------------------------------------------------------------------*
  830.         This routine processes the Drag Receive AppleEvent
  831.         and passes it to the framework.
  832. \*------------------------------------------------------------------------------*/
  833. pascal OSErr HandleDragRecv ( AppleEvent *theAppleEvent, AppleEvent *reply, long refCon )
  834. {
  835.     AEDesc                myDesc ;
  836.     OSErr                err = noErr ;
  837.     OSErr                ignoreErr ;
  838.     Handle                dataHdl ;
  839.     DragZoneRecvDataHdl    thePackage = nil ;
  840.     Size                thePackageSize ;
  841.     DragZoneHdl            theZone ;
  842.     WindowRef            theWindow ;
  843.     Point                theLocation ;
  844.     DragZoneRecvUPP     theCallback ;
  845.     Size                dataHdlSize ;    
  846.     
  847.     err = AEGetParamDesc(theAppleEvent,keyPrivateData,typeChar,&myDesc) ;
  848.     if ( !err )
  849.     {
  850.         // try to load all of the items we stuffed into the apple event
  851.         
  852.         thePackage = (DragZoneRecvDataHdl)myDesc.dataHandle ;
  853.         thePackageSize = GetHandleSize( (Handle)thePackage) ;
  854.  
  855.         // get the fields from the packaged data
  856.         theZone            = (**thePackage).zone ;
  857.         theWindow        = (**thePackage).window ;
  858.         theLocation        = (**thePackage).location ;
  859.         theCallback        = (**thePackage).callback ;
  860.         dataHdlSize        = (**thePackage).dataSize ;
  861.         
  862.         // sanity check
  863.         if( thePackageSize != (dataHdlSize + sizeof(DragZoneRecvDataRec)) )
  864.         {
  865.             ignoreErr = AEDisposeDesc(&myDesc) ;
  866.             return paramErr ;
  867.         }
  868.         
  869.         // Lock them down
  870.         MoveHHi( (Handle)thePackage ) ;
  871.         HLock( (Handle)thePackage ) ;
  872.  
  873.         // copy the data from the descriptor to a new handle
  874.         err = PtrToHand( (**thePackage).dataPtr, &dataHdl, dataHdlSize) ;
  875.         DisposeHandle( (Handle)thePackage ) ;
  876.         if ( err )            // check we could create the data handle OK
  877.         {
  878.             ignoreErr = AEDisposeDesc(&myDesc) ;
  879.             return err ;
  880.         }
  881.  
  882.         // we need to get rid of the descriptor (and thePackage) to save on memory
  883.         err = AEDisposeDesc(&myDesc) ;
  884.  
  885.         // process the information from the drag
  886.         if (err == noErr)
  887.             CallDragZoneRecvProc(theCallback, theZone, theWindow, theLocation, dataHdl) ;        
  888.  
  889.         // we can free up the memory now...
  890.         DisposeHandle( dataHdl ) ;
  891.     }
  892.     return err ;
  893. }
  894.  
  895.  
  896. /*------------------------------------------------------------------------------*\
  897.     SendDragRecv
  898.  *------------------------------------------------------------------------------*
  899.         This routine sends a drag receive Apple Event to this application.
  900. \*------------------------------------------------------------------------------*/
  901. OSErr SendDragRecv ( DragZoneHdl theZone, WindowRef theWindow, Point theLocation,
  902.                       Handle dataHdl, DragZoneRecvUPP theDragZoneRecvUPP )
  903. {
  904.      AppleEvent            myAppleEvent;
  905.     AppleEvent            defReply;
  906.     OSErr                err ;
  907.     char                cMemTags ;
  908.     DragZoneRecvDataHdl    thePackage = nil ;
  909.     Size                thePackageSize ;    
  910.  
  911.  
  912.     cMemTags = HGetState( dataHdl ) ;    // save the state of the handle in case it
  913.                                         // was already locked before we were called
  914.     
  915.     myAppleEvent.dataHandle = nil;
  916.     defReply.dataHandle = nil;
  917.  
  918.     // the static pSelfAddress that we create an usually use will cause the 
  919.     // AE handler to be caused directly (less overhead).  We DON'T WANT THAT
  920.     // to happen here.  The reason being that the handler for this event needs
  921.     // to be called in our main event loop, not directly at the send.  Doing things
  922.     // this way lets us get out of the Drag Managers context, back into our own.
  923.     // that in turn lets us use a high level debugger.
  924.     
  925.     err = AECreateAppleEvent(    kDraggingClass,
  926.                                 kDragReceiveID,
  927.                                 &gSelfPSNAddress,
  928.                                 kAutoGenerateReturnID,
  929.                                 kAnyTransactionID,
  930.                                 &myAppleEvent ) ;
  931.     if ( err ) return err ;
  932.  
  933.     // create a new data handle to hold the data the user just dragged in
  934.     thePackage = (DragZoneRecvDataHdl) NewHandle( sizeof(DragZoneRecvDataRec) ) ;
  935.     if ( thePackage == nil ) return MemError() ;
  936.  
  937.     (**thePackage).zone     = theZone ;
  938.     (**thePackage).window   = theWindow ;
  939.     (**thePackage).location = theLocation ;
  940.     (**thePackage).callback = theDragZoneRecvUPP ;
  941.     (**thePackage).dataSize = GetHandleSize(dataHdl) ;
  942.  
  943.     // append the dataHdl to the end of thePackage handle
  944.     err = HandAndHand( dataHdl,(Handle)thePackage ) ;
  945.     if ( err ) return MemError() ;
  946.     thePackageSize = GetHandleSize( (Handle)thePackage ) ;
  947.  
  948.     // Lock it down
  949.     MoveHHi( (Handle)thePackage ) ;
  950.     HLock( (Handle)thePackage ) ;
  951.  
  952.     // Put Params into our event and send it
  953.     err =  AEPutParamPtr(    &myAppleEvent,
  954.                             keyPrivateData,
  955.                             typeChar,
  956.                             *thePackage,
  957.                             thePackageSize ) ;
  958.     if ( err ) return err ;
  959.  
  960.     // restore the state of the handle (effectively the same as HUnlock)
  961.     HSetState( dataHdl, cMemTags) ;
  962.  
  963.     err = AESend(    &myAppleEvent,
  964.             &defReply,
  965.             kAENoReply+kAENeverInteract,
  966.             kAENormalPriority,
  967.             kAEDefaultTimeout,
  968.             nil,
  969.             nil) ;
  970.     if ( err ) return err ;
  971.  
  972.     if ( myAppleEvent.dataHandle ) 
  973.         err = AEDisposeDesc( &myAppleEvent ) ;
  974.  
  975.     // we dont want to dispose of thePackage here because
  976.     // whe don't know if the AppleEvent has been handled yet
  977.  
  978.     return err ;
  979. }
  980.  
  981.  
  982. /*------------------------------------------------------------------------------*\
  983.     OutlineRegion
  984.  *------------------------------------------------------------------------------*
  985.         This routine modifies a rgn to be an outline of its former self.
  986. \*------------------------------------------------------------------------------*/
  987. OSErr OutlineRegion ( RgnHandle theRgn )
  988. {
  989.     RgnHandle tempRgn;
  990.     
  991.     // create a temp rgn that is a copy of the rgn passed in
  992.     tempRgn = NewRgn();
  993.     CopyRgn(theRgn, tempRgn);
  994.     
  995.     // inset the temp rgn
  996.     InsetRgn(tempRgn, 1, 1);
  997.     
  998.     // subtract the temp rgn from the rgn passed in
  999.     DiffRgn(theRgn, tempRgn, theRgn);
  1000.     DisposeRgn(tempRgn);
  1001.     
  1002.     return noErr ;
  1003. }
  1004.  
  1005.  
  1006.