home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Snippets / GetFileIcon 1.1 / Universal Headers / GetFileIcon.c next >
Encoding:
C/C++ Source or Header  |  1995-03-15  |  15.2 KB  |  556 lines  |  [TEXT/MPCC]

  1. #include <Icons.h>
  2. #include <Finder.h>
  3. #include "GetFileIcon.h"
  4.  
  5. typedef struct getIconData { OSType        fileCreator;
  6.                              OSType        fileType;
  7.                              short        DTRefNum;
  8.                             } GetIconData;
  9.  
  10. extern Boolean IsVolEjected( short vRefNum );
  11. extern OSErr GetCustomFileIcon(FSSpec *filespec, IconSelectorValue iconSelector, Handle *theSuite);
  12. extern OSErr GetNormalFileIcon(CInfoPBRec *cpb, IconSelectorValue iconSelector, Handle *theSuite);
  13. extern void GetFinderFilename(StringPtr _finderFilename);
  14. extern pascal OSErr GetIconProc(ResType theType, Handle *theIcon, void *yourDataPtr);
  15. extern short FindDesktopDatabase(short firstVRefNum, OSType fileCreator); // returns a DT refnum or 0
  16. extern Boolean InOneDesktop(short vRefNum, OSType fileCreator, short *dtRefNum);
  17. extern pascal OSErr GetResourceIcons(Handle *theSuite, short theID, long theSelector);
  18. extern OSErr CopyEachIcon(Handle theSuite);
  19. extern pascal OSErr CopyOneIcon(ResType theType, Handle *theIcon, void *yourDataPtr);
  20. extern short FindGenericIconID(OSType theType, Boolean *inFinder);
  21. extern pascal OSErr Get1IconSuite(Handle *theSuite, short theID, long theSelector);
  22. extern pascal OSErr Get1Icon(ResType theType, Handle *theIcon, short *resID);
  23. extern pascal OSErr TestHandle(ResType theType, Handle *theIcon, void *yourDataPtr);
  24.  
  25.  
  26. /*    Custom icons numbered -16496 appear in aliases to volumes and
  27.     servers.  I don't know where this is documented.    */
  28. #define    kVolumeAliasIconResource    -16496
  29.  
  30.  
  31. /*    ------------------------------------------------------------------
  32.     GetFileIcon        Given a file specification for a file, folder, or
  33.                     volume, create an appropriate icon suite
  34.                     and find its label color.
  35.     ------------------------------------------------------------------ */
  36. pascal OSErr GetFileIcon(
  37. /* --> */    FSSpec                *thing,
  38. /* --> */    IconSelectorValue    iconSelector,
  39. /* <-- */    Handle                *theSuite)
  40. {
  41.     CInfoPBRec        cpb;
  42.     OSErr            err;
  43.  
  44.  
  45.     *theSuite = NULL;
  46.  
  47.     if( IsVolEjected(thing->vRefNum) )
  48.     {
  49.         err = volOffLinErr;
  50.     }
  51.     else
  52.     {
  53.         cpb.hFileInfo.ioVRefNum        = thing->vRefNum;
  54.         cpb.hFileInfo.ioDirID        = thing->parID;
  55.         cpb.hFileInfo.ioNamePtr        = thing->name;
  56.         cpb.hFileInfo.ioFDirIndex    = 0;
  57.         err = PBGetCatInfoSync( &cpb );
  58.  
  59.         if( !err )
  60.         {
  61.             if( (cpb.hFileInfo.ioFlAttrib & ioDirMask) == 0)    // file
  62.             {
  63.                 if(cpb.hFileInfo.ioFlFndrInfo.fdFlags & kHasCustomIcon)
  64.                 {
  65.                     err = GetCustomFileIcon(thing, iconSelector, theSuite );
  66.                 }
  67.                 else    // no custom icon
  68.                 {
  69.                     err = GetNormalFileIcon(&cpb, iconSelector, theSuite);
  70.                 }
  71.             }
  72.             // ----------- end of normal case --------------
  73.         }    
  74.     }
  75.  
  76.     // ------- error handler ---------
  77.     /*if(thing->parID == fsRtParID)    // a volume
  78.     {
  79.         if(err == volOffLinErr)
  80.         {
  81.             *labelColor = ttOffline;
  82.         }
  83.         err = GetVolumeIcon(thing->vRefNum, iconSelector, theSuite);
  84.     }*/
  85.  
  86.     return( err );
  87. }
  88.  
  89.  
  90. static Boolean    IsVolEjected( short vRefNum )
  91. {
  92.     OSErr            err;
  93.     HVolumeParam    vol_pb;
  94.     
  95.     vol_pb.ioNamePtr    = NULL;
  96.     vol_pb.ioVRefNum    = vRefNum;
  97.     vol_pb.ioVolIndex    = 0;
  98.     err = PBHGetVInfoSync( (HParmBlkPtr )&vol_pb );
  99.     
  100.     return( (err == noErr) && (vol_pb.ioVDRefNum > 0) );
  101. }
  102.  
  103.  
  104.  
  105. static OSErr    GetCustomFileIcon(
  106. /* --> */    FSSpec                *filespec,
  107. /* --> */    IconSelectorValue    iconSelector,
  108. /* <-- */    Handle                *theSuite)
  109. {
  110.     short    saveResFile, customResFile;
  111.     OSErr    err;
  112.     
  113.     saveResFile = CurResFile();
  114.     SetResLoad( false );
  115.     customResFile = FSpOpenResFile(filespec, fsRdPerm);
  116.  
  117.     SetResLoad( true );
  118.  
  119.     if(customResFile == -1)
  120.     {
  121.         err = ResError();
  122.     }
  123.     else
  124.     {
  125.         err = GetResourceIcons(theSuite, kCustomIconResource, iconSelector);
  126.         if( !err )
  127.         {
  128.             if( IsSuiteEmpty( *theSuite ) )
  129.             {
  130.                 err = GetResourceIcons(theSuite, kVolumeAliasIconResource, iconSelector);
  131.             }
  132.         }
  133.  
  134.         CloseResFile( customResFile );
  135.         UseResFile( saveResFile );
  136.     }
  137.     return( err );
  138. }
  139.  
  140.  
  141. static OSErr    GetNormalFileIcon(
  142. /* --> */    CInfoPBRec            *cpb,
  143. /* --> */    IconSelectorValue    iconSelector,
  144. /* <-- */    Handle                *theSuite)
  145. {
  146.     OSErr            err;
  147.     long            dataSize;
  148.     Handle            iconData;
  149.     Byte            iconType;
  150.     GetIconData        getData;
  151.     short            iconID;
  152.     Boolean            inFinder;
  153.     short            saveResFile, FinderResFile, sysVRefNum;
  154.     long            sysDirID;
  155.     Str255            finderName;
  156.     IconActionUPP    getIconProcPtr;
  157.  
  158.  
  159.     iconID = FindGenericIconID(cpb->hFileInfo.ioFlFndrInfo.fdType, &inFinder );
  160.     saveResFile = CurResFile();
  161.  
  162.     if( inFinder )
  163.     {
  164.         FindFolder(kOnSystemDisk, kSystemFolderType, kDontCreateFolder, &sysVRefNum, &sysDirID);
  165.  
  166.         SetResLoad( false );
  167.         GetFinderFilename( finderName );
  168.         FinderResFile = HOpenResFile(sysVRefNum, sysDirID, finderName, fsRdPerm);
  169.         SetResLoad( true );
  170.  
  171.         if(FinderResFile == -1)
  172.         {
  173.             err = ResError();
  174.         }
  175.         else
  176.         {
  177.             err = GetResourceIcons(theSuite, iconID, iconSelector);
  178.             CloseResFile( FinderResFile );
  179.         }
  180.     }
  181.     else    // icons in desktop DB or in System
  182.     {
  183.         getData.DTRefNum = FindDesktopDatabase(cpb->dirInfo.ioVRefNum,
  184.             cpb->hFileInfo.ioFlFndrInfo.fdCreator );
  185.  
  186.         if(getData.DTRefNum != 0)    // the right icons are in some desktop
  187.         {
  188.             err = NewIconSuite( theSuite );
  189.             if( !err )
  190.             {
  191.                 getData.fileCreator    = cpb->hFileInfo.ioFlFndrInfo.fdCreator;
  192.                 getData.fileType    = cpb->hFileInfo.ioFlFndrInfo.fdType;
  193.                 if(getData.fileType == kApplicationAliasType)
  194.                 {
  195.                     getData.fileType = 'APPL';
  196.                 }
  197.                 getIconProcPtr = NewIconActionProc( GetIconProc );
  198.                 err = ForEachIconDo(*theSuite, iconSelector, getIconProcPtr, &getData);
  199.                 DisposeRoutineDescriptor( getIconProcPtr );
  200.             }
  201.         }
  202.         if( (getData.DTRefNum == 0) || IsSuiteEmpty( *theSuite ) )
  203.         {
  204.             UseResFile( 0 );
  205.             err = GetResourceIcons(theSuite, iconID, iconSelector);
  206.         }
  207.     }
  208.  
  209.     UseResFile( saveResFile );
  210.  
  211.     return( err );
  212. }
  213.  
  214.  
  215. static void GetFinderFilename(
  216. /* <-- */    StringPtr       _finderFilename)
  217. {
  218.     Str255          _defaultFinderFilename="\pFinder";
  219.     StringPtr       _lowMemFinderName;
  220.  
  221.     _lowMemFinderName = LMGetFinderName();
  222.     if( (_lowMemFinderName != (StringPtr )nil) && (_lowMemFinderName[0] > 0))
  223.         BlockMove(_lowMemFinderName, _finderFilename, _lowMemFinderName[0]+1);
  224.     else
  225.         BlockMove(_defaultFinderFilename, _finderFilename, _defaultFinderFilename[0]+1);
  226. }
  227.  
  228.  
  229. /*    ------------------------------------------------------------------
  230.     GetIcon        This is an IconAction procedure to fill in one
  231.                     slot of an icon suite, given a file type, creator,
  232.                     and desktop database.
  233.     ------------------------------------------------------------------ */
  234. static    pascal OSErr GetIconProc(ResType theType, Handle *theIcon, void *yourDataPtr)
  235. {
  236.     OSErr            err;
  237.     GetIconData        *data;
  238.     DTPBRec            deskRec;
  239.  
  240.     err = noErr;
  241.     data = (GetIconData *)yourDataPtr;
  242.     *theIcon = NewHandle( kLarge8BitIconSize );
  243.  
  244.     if( !(*theIcon) )
  245.     {
  246.         err = memFullErr;
  247.     }
  248.     else
  249.     {
  250.         HLock( *theIcon );
  251.     
  252.         deskRec.ioDTRefNum        = data->DTRefNum;
  253.         deskRec.ioDTBuffer        = **theIcon;
  254.         deskRec.ioDTReqCount    = kLarge8BitIconSize;
  255.         deskRec.ioFileCreator    = data->fileCreator;
  256.         deskRec.ioFileType        = data->fileType;
  257.     
  258.         switch( theType )
  259.         {
  260.             case large1BitMask:
  261.                 deskRec.ioIconType = kLargeIcon;
  262.                 break;
  263.     
  264.             case large4BitData:
  265.                 deskRec.ioIconType = kLarge4BitIcon;
  266.                 break;
  267.     
  268.             case large8BitData:
  269.                 deskRec.ioIconType = kLarge8BitIcon;
  270.                 break;
  271.     
  272.             case small1BitMask:
  273.                 deskRec.ioIconType = kSmallIcon;
  274.                 break;
  275.     
  276.             case small4BitData:
  277.                 deskRec.ioIconType = kSmall4BitIcon;
  278.                 break;
  279.     
  280.             case small8BitData:
  281.                 deskRec.ioIconType = kSmall8BitIcon;
  282.                 break;
  283.             
  284.             default:
  285.                 // The desktop database does not have "mini" icons
  286.                 deskRec.ioIconType = 1000;
  287.                 break;
  288.         }
  289.  
  290.         err = PBDTGetIconSync( &deskRec );
  291.         if(err == noErr)
  292.         {
  293.             HUnlock( *theIcon );
  294.             SetHandleSize(*theIcon, deskRec.ioDTActCount);
  295.         }
  296.         else
  297.         {
  298.             DisposeHandle( *theIcon );
  299.             *theIcon = NULL;
  300.             err = noErr;
  301.         }
  302.     }
  303.     return( err );
  304. }
  305.  
  306.  
  307. /*    ------------------------------------------------------------------
  308.     Find_desktop_database            Find the reference number of a
  309.                                     desktop database containing icons
  310.                                     for a specified creator code.
  311.     The search begins on a specified volume, but covers all volumes.
  312.     ------------------------------------------------------------------ */
  313. static    short    FindDesktopDatabase(
  314. /* --> */    short    firstVRefNum,
  315. /* --> */    OSType    fileCreator)    // returns a DT refnum or 0
  316. {
  317.     OSErr            err;
  318.     VolumeParam        vpb;
  319.     short            DTRefNum = 0;
  320.  
  321.     if( !InOneDesktop(firstVRefNum, fileCreator, &DTRefNum) )
  322.     {
  323.         vpb.ioNamePtr = NULL;
  324.         for(vpb.ioVolIndex = 1; PBGetVInfoSync((ParmBlkPtr )&vpb) == noErr; ++vpb.ioVolIndex)
  325.         {
  326.             if(vpb.ioVRefNum == firstVRefNum)
  327.                 continue;
  328.             if( InOneDesktop(vpb.ioVRefNum, fileCreator, &DTRefNum) )
  329.                 break;
  330.         }
  331.     }
  332.     return( DTRefNum );
  333. }
  334.  
  335.  
  336.  
  337. /*    ------------------------------------------------------------------
  338.     InOneDesktop            Determine whether the desktop database for
  339.                             one particular volume contains icons for
  340.                             a given creator code, and if so, return its
  341.                             reference number.
  342.     ------------------------------------------------------------------
  343. */
  344. static    Boolean    InOneDesktop(
  345. /* --> */    short    vRefNum,
  346. /* --> */    OSType    fileCreator,
  347. /* <-- */    short    *dtRefNum)
  348. {
  349.     OSErr        err;
  350.     DTPBRec        deskRec;
  351.     Boolean        retVal;
  352.     
  353.     HParamBlockRec         _myHPB;
  354.     GetVolParmsInfoBuffer  _infoBuffer;
  355.     
  356.     retVal = false;    // default to failure
  357.     deskRec.ioNamePtr = NULL;
  358.     deskRec.ioVRefNum = vRefNum;
  359.     
  360.     // check to make sure we've got a database first:
  361.     _myHPB.ioParam.ioNamePtr  = (StringPtr)nil;
  362.     _myHPB.ioParam.ioVRefNum  = vRefNum;
  363.     _myHPB.ioParam.ioBuffer   = (Ptr)&_infoBuffer;
  364.     _myHPB.ioParam.ioReqCount = sizeof(_infoBuffer);
  365.     if ( ((err=PBHGetVolParms(&_myHPB,false/*async*/))!=noErr) ||
  366.     ((_infoBuffer.vMAttrib&(1L<<bHasDesktopMgr))==0) )
  367.         return( retVal );
  368.  
  369.     err = PBDTGetPath( &deskRec );
  370.     if( !err )
  371.     {
  372.         /*    We want to ignore any non-icon data, such as the 'paul'
  373.             item that is used for drag-and-drop. */
  374.         deskRec.ioFileCreator = fileCreator;
  375.         deskRec.ioIndex = 1;
  376.         do
  377.         {
  378.             deskRec.ioTagInfo = 0;
  379.             err = PBDTGetIconInfoSync( &deskRec );
  380.             deskRec.ioIndex += 1;
  381.         }while( (err == noErr) && (deskRec.ioIconType <= 0) );
  382.     
  383.         if(err == noErr)
  384.         {
  385.             retVal = true;
  386.             *dtRefNum = deskRec.ioDTRefNum;
  387.         }
  388.     }
  389.     return( retVal );
  390. }
  391.  
  392.  
  393. static pascal OSErr GetResourceIcons(
  394. /* <-- */    Handle    *theSuite,
  395. /* --> */    short    theID,
  396. /* --> */    long    theSelector)
  397. {
  398.     OSErr    err;
  399.     
  400.     err = Get1IconSuite(theSuite, theID, theSelector);
  401.     if(err == noErr)
  402.     {
  403.         err = CopyEachIcon( *theSuite );
  404.     }
  405.     return( err );
  406. }
  407.  
  408.  
  409. static pascal OSErr CopyOneIcon(
  410. /* --> */    ResType        theType,
  411. /* <-> */    Handle        *theIcon,
  412. /* --- */    void        *yourDataPtr)
  413. {
  414.     OSErr    err;
  415.     
  416.     if(*theIcon != NULL)
  417.     {
  418.         LoadResource( *theIcon );
  419.         err = HandToHand( theIcon );
  420.         if(err != noErr)
  421.             *theIcon = NULL;
  422.     }
  423.     return( noErr );
  424. }
  425.  
  426.  
  427. static OSErr CopyEachIcon(
  428. /* <-> */    Handle theSuite)
  429. {
  430.     IconActionUPP    copyOneIconProc;
  431.     OSErr            err;
  432.     copyOneIconProc = NewIconActionProc( CopyOneIcon );
  433.     err = ForEachIconDo(theSuite, svAllAvailableData, copyOneIconProc, NULL);
  434.     DisposeRoutineDescriptor( copyOneIconProc );
  435.     return( err );
  436. }
  437.  
  438.  
  439. typedef struct genericIconInfo { OSType type; short id; } GenericIconInfo;
  440. static GenericIconInfo gGenericFinderIcons[]={ {'ifil',12500},
  441.                                                {'ifil',12500},
  442.                                                {'sfil',14000},
  443.                                                {'ffil',14500},
  444.                                                {'tfil',14501},
  445.                                                {'kfil',14750},
  446.                                                {'FFIL',15500},
  447.                                                {'DFIL',15750}
  448.                                               };
  449. static GenericIconInfo gGenericSysIcons[]={ {kContainerFolderAliasType,genericFolderIconResource},
  450.                                             {kContainerTrashAliasType,trashIconResource},
  451.                                             {kSystemFolderAliasType,systemFolderIconResource},
  452.                                             {'INIT',genericExtensionIconResource},
  453.                                             {'APPL',genericApplicationIconResource},
  454.                                             {'dfil',genericDeskAccessoryIconResource},
  455.                                             {'pref',genericPreferencesIconResource},
  456.                                             {kAppleMenuFolderAliasType,appleMenuFolderIconResource},
  457.                                             {kControlPanelFolderAliasType,controlPanelFolderIconResource},
  458.                                             {kExtensionFolderAliasType,extensionsFolderIconResource},
  459.                                             {kPreferencesFolderAliasType,preferencesFolderIconResource},
  460.                                             {kStartupFolderAliasType,startupFolderIconResource},
  461.                                             {kApplicationAliasType,genericApplicationIconResource},
  462.                                             {kExportedFolderAliasType,ownedFolderIconResource},
  463.                                             {kDropFolderAliasType,dropFolderIconResource},
  464.                                             {kSharedFolderAliasType,sharedFolderIconResource},
  465.                                             {kMountedFolderAliasType,mountedFolderIconResource}
  466.                                            };
  467.  
  468.  
  469. static short    FindGenericIconID(
  470. /* --> */    OSType theType,
  471. /* <-- */    Boolean    *inFinder)
  472. {
  473.     
  474.    short id=genericDocumentIconResource; // default
  475.    GenericIconInfo *_icon, *_endIcon;
  476.    
  477.     for (_icon=gGenericFinderIcons,_endIcon=_icon+sizeof(gGenericFinderIcons)/sizeof(GenericIconInfo);
  478.          (_icon<_endIcon)&&(_icon->type!=theType); _icon++) ;
  479.     if (!(*inFinder=(_icon<_endIcon)))
  480.         for (_icon=gGenericSysIcons,_endIcon=_icon+sizeof(gGenericSysIcons)/sizeof(GenericIconInfo);
  481.              (_icon<_endIcon)&&(_icon->type!=theType); _icon++) ;
  482.     if (_icon<_endIcon)
  483.         id = _icon->id;
  484.  
  485.     return( id );
  486. }
  487.  
  488.  
  489. /*    --------------------------------------------------------------------
  490.     Get1IconSuite            Like GetIconSuite, but only looks in
  491.                             the current resource file.
  492.     
  493.     In case you're wondering why it would be necessary to ensure that
  494.     icons come from only one file, suppose you're looking at a
  495.     file that has its custom icon bit set, but for some reason does
  496.     not contain a custom icon, or at least not a full family.
  497.     Way down the resource chain, there may be another file, say a
  498.     font file, that does have a full family of custom icons. 
  499.     So you get an unexpected icon.
  500.     -------------------------------------------------------------------- */
  501.  
  502. static pascal OSErr Get1IconSuite(
  503. /* <-- */    Handle    *theSuite,
  504. /* --> */    short    theID,
  505. /* --> */    long    theSelector)
  506. {
  507.     OSErr        err;
  508.     IconActionUPP    get1IconProc;
  509.  
  510.     err = NewIconSuite( theSuite );
  511.     if( !err )
  512.     {
  513.         get1IconProc = NewIconActionProc( Get1Icon );
  514.         err = ForEachIconDo(*theSuite, theSelector, get1IconProc, &theID);
  515.         DisposeRoutineDescriptor( get1IconProc );
  516.     }
  517.     return( err );
  518. }
  519.  
  520.  
  521. static pascal OSErr Get1Icon(
  522. /* --> */    ResType    theType,
  523. /* <-> */    Handle    *theIcon,
  524. /* --> */    short    *resID)
  525. {
  526.     *theIcon = Get1Resource(theType, *resID);
  527.  
  528.     return( noErr );
  529. }
  530.  
  531.  
  532. static pascal OSErr TestHandle(ResType theType, Handle *theIcon, void *yourDataPtr)
  533. {
  534.     if(*theIcon != NULL)
  535.         *(Boolean *)yourDataPtr = false;    // not empty!
  536.  
  537.     return( noErr );
  538. }
  539.  
  540.  
  541. Boolean IsSuiteEmpty( Handle theSuite )
  542. {
  543.     Boolean            retVal;
  544.     IconActionUPP    testHandleProc;
  545.  
  546.     testHandleProc = NewIconActionProc( TestHandle );
  547.     
  548.     retVal = true;
  549.     ForEachIconDo(theSuite, svAllAvailableData, testHandleProc, &retVal);
  550.     DisposeRoutineDescriptor( testHandleProc );
  551.  
  552.     return( retVal );
  553. }
  554.  
  555.  
  556.