home *** CD-ROM | disk | FTP | other *** search
/ ftp.mactech.com 2010 / ftp.mactech.com.tar / ftp.mactech.com / machack / Hacks95 / TrashAddition.sit / TrashAddition / TrashAddition.c < prev    next >
C/C++ Source or Header  |  1995-09-10  |  11KB  |  453 lines

  1. // This is a sample drag strip addition. The purpose is to correct the behavior
  2. // that DS has when an alias of the trash is placed on it.
  3.  
  4.  
  5. // This demonstrates sending an apple event, looping through mounted volumes,
  6. // plotting an icon family, ejecting/unmounting volumes, moving items to the
  7. // trash, and other DragStrip™ addition API features.
  8.  
  9. //    Revisions
  10.  
  11. //    Author            Date            Comment
  12. //    ------------    -------------    ------------------------------------------
  13. //    JGB                MacHack '95        First revision
  14.  
  15. #include <Palettes.h>
  16. #include <GestaltEqu.h>
  17. #include <Icons.h>
  18. #include <AppleEvents.h>
  19. #include <A4Stuff.h>
  20. #include <Files.h>
  21. #include <Strings.h>
  22. #include "DS Additions.h"
  23. #include "Drag.h"
  24.  
  25. #define ScreenDepth(gdh) ((*((*gdh)->gdPMap))->pixelSize)
  26.  
  27. pascal long main( DSAdditionParamBlockPtr params)
  28. {
  29.     long         result = 0;
  30.     Rect        localRect;
  31.     Point        mousePoint;
  32.     OSErr        theErr, iErr;
  33.     long        iconID ;
  34.     long        oldA4 = SetCurrentA4();
  35.     AppleEvent    theAppleEvent ;
  36.     
  37.     switch(params->dsMessage) 
  38.     {
  39.     
  40.         //    -------------------------------------------------------
  41.         //    Given an Init or Close message, do what we need to
  42.         //    -------------------------------------------------------
  43.  
  44.         case kMsgInitAddition:
  45.             params->dsRefCon = (long)NewHandle(10);    //Allocate some memory for some reason
  46.             result = MemError();
  47.             InitAppleEvents();
  48.             break;
  49.  
  50.         case kMsgCloseAddition:
  51.             if(params->dsRefCon != nil) 
  52.             {
  53.                 DisposeHandle((Handle)params->dsRefCon);
  54.             }
  55.             break;
  56.  
  57.  
  58.         //    -------------------------------------------------------
  59.         //    Given a draw or hilite message, draw what we need into 
  60.         //    the provided rectangle
  61.         //    -------------------------------------------------------
  62.         
  63.         case kMsgDraw:
  64.         case kMsgDrawHilite:
  65.         
  66.             localRect = params->dsIconRect;
  67.             iconID = GetTrashIcon() ;
  68.             PlotIconID( &localRect ,
  69.                         atBottom + atVerticalCenter ,
  70.                         ttNone ,
  71.                         iconID    );
  72.  
  73.             params->dsNextDrawTime = TickCount() + (60 * 3);    //Draw again in 3 seconds
  74.             
  75.             break;
  76.  
  77.             
  78.         //    -------------------------------------------------------
  79.         //    Given a hit message, do whatever we do when we are hit
  80.         //    -------------------------------------------------------
  81.         
  82.         case kMsgHit:
  83.         
  84.             localRect = params->dsLocalRect;
  85.             GetMouse( &mousePoint );
  86.  
  87.             // Make sure that the user actually let go inside the rect
  88.             // before doing our thing.
  89.             
  90.             while(StillDown() && PtInRect(mousePoint, &localRect)) {
  91.                 GetMouse(&mousePoint);
  92.             }
  93.  
  94.             if( ! StillDown() ) 
  95.             {
  96.                 OSType    fndrSig = 'MACS';
  97.                 AEAddressDesc target ;
  98.                 
  99.                 AECreateDesc(                 typeApplSignature , 
  100.                                             &fndrSig , 
  101.                                             sizeof( fndrSig ) , 
  102.                                             &target             );
  103.                 
  104.                 iErr = AECreateAppleEvent(    kAEFinderEvents,
  105.                                             'empt',
  106.                                             &target,
  107.                                             kAutoGenerateReturnID,
  108.                                             kAnyTransactionID,
  109.                                             &theAppleEvent        );
  110.                                             
  111.                 iErr = AESend(                &theAppleEvent,
  112.                                             nil,
  113.                                             kAENoReply + kAECanInteract,
  114.                                             kAENormalPriority,
  115.                                             3600,
  116.                                             nil,
  117.                                             nil            );
  118.                                             
  119.                 AEDisposeDesc( &target );
  120.                 AEDisposeDesc( &theAppleEvent );                            
  121.             }
  122.             
  123.             break;
  124.             
  125.  
  126.         //    -------------------------------------------------------
  127.         //    Given a drop message, pull the files out of the 
  128.         //    DragReference then do what you want with them.
  129.         //    -------------------------------------------------------
  130.  
  131.         case kMsgDropOccurred:
  132.         {
  133.             unsigned short    items, index, flavors, j ;
  134.             ItemReference    theItemRef ;
  135.             FlavorType        theType ;
  136.             HFSFlavor        flavorData ;
  137.             Size            dataSize ;
  138.             unsigned long    dataOffset = 0;
  139.  
  140.             CountDragItems( params->dsDragReference, &items );
  141.             
  142.             for (index = 1; index <= items; index++) 
  143.             {
  144.                 iErr = GetDragItemReferenceNumber(    params->dsDragReference,
  145.                                                     index,
  146.                                                     &theItemRef                );
  147.                 iErr = CountDragItemFlavors(        params->dsDragReference,
  148.                                                     theItemRef,
  149.                                                     &flavors                );
  150.                 for( j = 1 ; j <= flavors ; j++)
  151.                 {
  152.                     iErr = GetFlavorType(            params->dsDragReference,
  153.                                                     theItemRef,
  154.                                                     j,
  155.                                                     &theType                );
  156.                                                                         
  157.                     switch( theType )
  158.                     {
  159.                         case 'hfs ':                // We an HFS Flavor was dropped on us
  160.                             // Move this puppy to the trash
  161.                             
  162.                             iErr = GetFlavorDataSize(        params->dsDragReference,
  163.                                                             theItemRef,
  164.                                                             theType,
  165.                                                             &dataSize);
  166.                                                                                         
  167.                             iErr = GetFlavorData(            params->dsDragReference,
  168.                                                             theItemRef,
  169.                                                             theType,
  170.                                                             &flavorData,
  171.                                                             &dataSize,
  172.                                                             dataOffset                );
  173.                                                             
  174.                             TrashItem( flavorData );
  175.                             
  176.                             break;
  177.                                                     
  178.                     }
  179.                     
  180.                 }
  181.  
  182.             }
  183.             break;
  184.         }
  185.  
  186.     }
  187.     
  188.     SetA4(oldA4);
  189.     return result;
  190. }
  191.  
  192.  
  193.  
  194.  
  195. //    ------------------------------------------------------------------
  196. //    GetTrashIcon
  197. //
  198. //    Based on the current state of the trash on all volumes, return the
  199. //    resource ID of the icon to plot.
  200. //    ------------------------------------------------------------------
  201.  
  202. long GetTrashIcon ( void ) 
  203. {
  204.     VolumeParam    paramBlock ;
  205.     CInfoPBRec    pb ;
  206.     Str255        volName , dirName ;
  207.     OSErr        checkErr , theErr ;
  208.     long        trashFiles ;
  209.     short        i = 1 ;
  210.     short        volRefNo , trashVRefNo ;
  211.     long        trashDirID ;
  212.     long        iconID = -3993 ;
  213.     
  214.     theErr = noErr ;
  215.     
  216.     // Walk through all mounted volumes
  217.     for( i = 1 ; theErr == noErr ; i++)
  218.     {
  219.         paramBlock.ioVolIndex = i ;
  220.         paramBlock.ioNamePtr = volName ;
  221.         paramBlock.ioVRefNum = volRefNo ;
  222.         
  223.         theErr = PBGetVInfo( (ParmBlkPtr) ¶mBlock , FALSE ) ;
  224.         
  225.         volRefNo = paramBlock.ioVRefNum ;
  226.         
  227.         if( theErr == noErr )
  228.         {    
  229.             checkErr = FindFolder(     volRefNo , 
  230.                                     kTrashFolderType , 
  231.                                     kDontCreateFolder , 
  232.                                     &trashVRefNo , 
  233.                                     &trashDirID        );
  234.                                     
  235.             pb.dirInfo.ioVRefNum = volRefNo ;
  236.             pb.dirInfo.ioFDirIndex = -1 ;
  237.             pb.dirInfo.ioNamePtr = dirName ;
  238.             pb.dirInfo.ioDrDirID = trashDirID ;
  239.             
  240.             checkErr = PBGetCatInfo( &pb , FALSE );
  241.             
  242.             trashFiles = pb.dirInfo.ioDrNmFls ;
  243.             
  244.             // If the trash folder has any items, return # and break
  245.             
  246.             if( trashFiles > 0 ) 
  247.             {
  248.                 iconID = -3984 ;
  249.                 theErr = nsvErr ;
  250.             }
  251.             
  252.         }
  253.         
  254.     }
  255.         
  256.     return iconID ;
  257. }
  258.  
  259.  
  260.  
  261. //    ------------------------------------------------------------------
  262. //    InitAppleEvents
  263. //
  264. //    Initialize AppleEvent sender. Beep and return 1 if not supported.
  265. //    ------------------------------------------------------------------
  266.  
  267. long InitAppleEvents( void )
  268. {
  269.     long    feature, result = 0 ;
  270.     OSErr    err ;
  271.     
  272.     err = Gestalt( gestaltAppleEventsAttr, &feature );
  273.     
  274.     if( err != noErr )
  275.     {
  276.         SysBeep( 10 );
  277.         result = 1 ;
  278.     }
  279.     
  280.     return result;
  281. }
  282.  
  283.  
  284.  
  285. //    ------------------------------------------------------------------
  286. //    TrashItem
  287. //
  288. //    Send this "thing" to hell!
  289. //    ------------------------------------------------------------------
  290.  
  291. void TrashItem( HFSFlavor hfsFlavor )
  292. {
  293.     OSErr            result = noErr;
  294.     ParamBlockRec    paramBlock ;
  295.     Str255            pathName ;
  296.     
  297.     if((hfsFlavor.fileType == 'disk') && (hfsFlavor.fileCreator == 'MACS')) //Don't unmount the startup volume
  298.     {        
  299.     
  300.         if (hfsFlavor.fileSpec.vRefNum != -1) // This is a drive 
  301.         {
  302.             short    driveNumber;
  303.             
  304.             driveNumber = GetDriveNumber(hfsFlavor.fileSpec.vRefNum);
  305.  
  306.             result = UnmountVol(nil, hfsFlavor.fileSpec.vRefNum);
  307.             
  308.             if(result == noErr) 
  309.             {
  310.                 result = Eject(nil, driveNumber);
  311.             }
  312.         }            
  313.         else {
  314.             result = -50;
  315.         }
  316.     }
  317.     else // We are trashing an actual file or folder
  318.     {
  319.         FSSpec    trashFolder;
  320.         FInfo    fndrInfo;
  321.         Str63    newName = "\p" ;
  322.         char    addName ;
  323.         short    strLen , copyIDPos ;
  324.         
  325.         if(result == noErr && MakeSpecialFolderFSSpec(hfsFlavor.fileSpec.vRefNum, &trashFolder, kTrashFolderType)) 
  326.         {
  327.             result = FSpCatMove( &hfsFlavor.fileSpec , &trashFolder);
  328.             if( result == dupFNErr )
  329.             {
  330.                 // there is already an item named this in the trash - how often does this happen anyway?
  331.                 short    i;
  332.  
  333.                 strLen = hfsFlavor.fileSpec.name[0] ;
  334.  
  335.                 copyIDPos = strLen + 1 ;
  336.                 if( copyIDPos > 62 ) copyIDPos = 62 ;
  337.                                                 
  338.                 for (i = 1 ; result == dupFNErr ; i++ )
  339.                 {
  340.                     addName = (char)(i+(short)'a') ;
  341.                     BlockMove( &hfsFlavor.fileSpec.name[1] , &newName[1] , strLen );
  342.                     BlockMove( &addName , &newName[copyIDPos] , 1 );
  343.                     newName[0] = copyIDPos;
  344.                     
  345.                     result = FSpRename( &hfsFlavor.fileSpec , newName );    
  346.                     
  347.                     BlockMove( newName , &hfsFlavor.fileSpec.name , copyIDPos + 1 );        
  348.                     
  349.                     result = FSpCatMove( &hfsFlavor.fileSpec , &trashFolder);
  350.                 }
  351.             }
  352.             UpdateParentFolderModDate( &hfsFlavor.fileSpec );
  353.         }
  354.     }
  355. }
  356.  
  357.  
  358.  
  359.  
  360. //    ------------------------------------------------------------------
  361. //    MakeSpecialFolderFSSpec
  362. //  
  363. //    Courtesy of Chris Evans
  364. //    Return a finder folder's FSSpec
  365. //    ------------------------------------------------------------------
  366.  
  367. Boolean    MakeSpecialFolderFSSpec(short    vRefNum, FSSpec *folderSpec, OSType folder)
  368. {
  369.     short            folderVRefNum;
  370.     long            folderDirID;
  371.     OSErr            theErr;
  372.     Boolean            result = false;
  373.  
  374.     if(FindFolder(vRefNum, folder, kCreateFolder, &folderVRefNum, &folderDirID) == noErr) 
  375.     {
  376.         CInfoPBRec        thePB;
  377.         folderSpec->name[0] = 0;
  378.         
  379.         thePB.dirInfo.ioCompletion = 0L;
  380.         thePB.dirInfo.ioNamePtr = (StringPtr) &folderSpec->name;
  381.         thePB.dirInfo.ioVRefNum = folderVRefNum;
  382.         thePB.dirInfo.ioFDirIndex = -1;
  383.         thePB.dirInfo.ioDrDirID = folderDirID;
  384.  
  385.         theErr = PBGetCatInfo(&thePB, false);
  386.         if(theErr == noErr ) 
  387.         {
  388.             folderSpec->parID = thePB.dirInfo.ioDrParID;
  389.             folderSpec->vRefNum = folderVRefNum;
  390.             result = true;
  391.         }
  392.     }
  393.  
  394.     return result;
  395. }
  396.  
  397.  
  398.  
  399. //    ------------------------------------------------------------------
  400. //    GetDriveNumber
  401. //  
  402. //    Courtesy of Chris Evans
  403. //    Return a finder folder's FSSpec
  404. //    ------------------------------------------------------------------
  405.  
  406. short    GetDriveNumber( short vRefNum )
  407. {
  408.     QHdrPtr        qhp;
  409.     VCB            *vcbp;
  410.     
  411.     qhp = GetVCBQHdr();        // Address of queue header
  412.     
  413.     vcbp = ( VCB *) qhp->qHead;
  414.     
  415.     while( vcbp )
  416.     {
  417.         if( vcbp->vcbVRefNum == vRefNum )
  418.         {
  419.             return vcbp->vcbDrvNum;
  420.         }
  421.         vcbp = (VCB *)vcbp->qLink;
  422.     }
  423.     return -1;
  424.     
  425. }
  426.  
  427.  
  428.  
  429. //    ------------------------------------------------------------------
  430. //    UpdateFolderModDate
  431. //  
  432. //    Update a folder so the finder redraws it.
  433. //    ------------------------------------------------------------------
  434.  
  435. void UpdateParentFolderModDate( FSSpec *theSpec )
  436. {
  437.     CInfoPBRec    pb;
  438.     OSErr        theErr;
  439.  
  440.     pb.dirInfo.ioCompletion = nil;
  441.     pb.dirInfo.ioNamePtr = nil;
  442.     pb.dirInfo.ioVRefNum = theSpec->vRefNum;
  443.     pb.dirInfo.ioFDirIndex = -1;
  444.     pb.dirInfo.ioDrDirID = theSpec->parID;
  445.     
  446.     theErr = PBGetCatInfo(&pb, false);
  447.     if(theErr == noErr) 
  448.     {
  449.         pb.dirInfo.ioDrMdDat = LMGetTime();
  450.         pb.dirInfo.ioDrDirID = theSpec->parID;
  451.         PBSetCatInfo(&pb, false);
  452.     }
  453. }