home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 October: Mac OS SDK / Dev.CD Oct 97 SDK1.toast / Development Kits (Disc 1) / Color Picker SDK / Sample Code / Picker Demo Sample / GetMonitorProfile.c next >
Encoding:
Text File  |  1997-06-13  |  11.4 KB  |  429 lines  |  [TEXT/CWIE]

  1.  
  2. //===============================================================================
  3. //
  4. //                               GetMonitorProfile.c
  5. //
  6. //===============================================================================
  7.  
  8.  
  9. #include <CMApplication.h>
  10. #include <StandardFile.h>
  11. #include <LowMem.h>
  12. #include "GetMonitorProfile.h"
  13.  
  14.  
  15. #define kProfileType                'prof'
  16. #define kXYZProfileID                -16011
  17. #define custGFDialogID                -4048
  18. #define itemSFProfileName            11
  19.  
  20.  
  21. typedef struct
  22. {
  23.     OSType                dataType;    
  24.     FSSpec                lastSpec;    // last file spec that we used to display profile name
  25.     StandardFileReply    reply;        // current reply for CustomGetFile
  26. } FilterDataStructure;
  27.  
  28.  
  29. static pascal Boolean TheFileFilter (CInfoPBPtr, FilterDataStructure *);
  30. static pascal short TheDialogHook (short item, DialogRef, FilterDataStructure *);
  31. static void CSProfileInfoString (FSSpec *, Str255);
  32. static void SetSFDefaults (short, long);
  33. static void GetSFDefaults (short *, long *);
  34. static OSErr ReadProfileCM2Header(FSSpec *, CM2Header *);
  35. static OSErr ResolveFSSpec (FSSpec *, FSSpec *);
  36. static OSErr IsAliasFile (const FSSpec *, Boolean *, Boolean *);
  37. static OSErr ResolveAliasFileMountOption (FSSpec *, Boolean, Boolean *, Boolean *, Boolean);
  38.  
  39.  
  40. //===================================================================== Functions
  41. //--------------------------------------------------------------------- StandardGetProfile
  42.  
  43. OSErr StandardGetProfile ( CMProfileLocation *profLoc, Boolean *sfGood, 
  44.         OSType inputDataType)
  45. {
  46.     FilterDataStructure    fds;
  47.     Point                position;
  48.     OSType                profileType;
  49.     CMError                err;
  50.     FileFilterYDUPP        fileUPP;
  51.     DlgHookYDUPP        hookUPP;
  52.     long                oldDirID;
  53.     short                oldVRefNum;
  54.     
  55.     profileType = kProfileType;
  56.     err = noErr;
  57.     *sfGood = false;
  58.     
  59.                 // Set Standard File directory to be ColorSync profiles folder.
  60.     GetSFDefaults( &oldVRefNum, &oldDirID );
  61.     
  62.     fds.lastSpec.name[0] = 0;
  63.     fds.dataType = nil;    
  64.     position.h = position.v = -1;
  65.     
  66.     fileUPP = NewFileFilterYDProc(TheFileFilter);
  67.     hookUPP = NewDlgHookYDProc(TheDialogHook);
  68.     
  69.                 // Do standard file, with our filters causing only valid system 
  70.                 // profiles to be displayed.
  71.     CustomGetFile(fileUPP, 1, &profileType, &fds.reply, custGFDialogID, position, hookUPP, 
  72.             0L, 0, 0L, &fds);
  73.     
  74.     DisposeRoutineDescriptor(fileUPP);
  75.     DisposeRoutineDescriptor(hookUPP);
  76.     
  77.                 // Restore Standard File default directory.
  78.     SetSFDefaults(oldVRefNum,oldDirID);
  79.     
  80.     if (fds.reply.sfGood)
  81.     {
  82.         *sfGood = true;
  83.         profLoc->locType = cmFileBasedProfile;
  84.         profLoc->u.fileLoc.spec = fds.reply.sfFile;
  85.         
  86.     }
  87.     
  88.     return err;
  89. }
  90.  
  91. #pragma mark -------------------- Private Functions
  92. //===================================================================== Private Functions
  93. //--------------------------------------------------------------------- TheFileFilter
  94. // Our file filter for allowing only valid system profiles to be displayed
  95. // in the Standard File dialog.
  96.  
  97. static pascal Boolean TheFileFilter (CInfoPBPtr pb, FilterDataStructure *fds)
  98. {
  99.     Boolean            goodFile;
  100.     OSErr            err;
  101.     FSSpec            spec,fromSpec;
  102.     CM2Header        hdr2;
  103.     
  104.     goodFile = false;
  105.     err = noErr;
  106.     
  107.     if ( (*pb).hFileInfo.ioFlFndrInfo.fdType != kProfileType)
  108.         err = 1;  // this should never happen
  109.     
  110.     if (!err)
  111.         err = FSMakeFSSpec( (*pb).hFileInfo.ioVRefNum,
  112.                             (*pb).dirInfo.ioDrParID,
  113.                             (*pb).hFileInfo.ioNamePtr, &fromSpec);
  114.     
  115.     if (!err)
  116.         err = ResolveFSSpec( &fromSpec, &spec );
  117.     
  118.     if (!err)
  119.         err = ReadProfileCM2Header( &spec, &hdr2 );
  120.     
  121.     if (!err)
  122.         if ((hdr2.CS2profileSignature == cmMagicNumber) &&
  123.             (hdr2.profileVersion == cmCS2ProfileVersion) &&
  124.             (fds->dataType == nil || fds->dataType==hdr2.dataColorSpace) )
  125.             goodFile = true;
  126.     
  127.     return !goodFile;
  128. }
  129.  
  130. //--------------------------------------------------------------------- TheDialogHook
  131. // During standard file null events, check to see if the user has changed
  132. // the current selection.  If so, we need to update the profile name
  133. // string in the window.  If nothing is selected, the string will end
  134. // up blank.
  135.  
  136. static pascal short TheDialogHook (short item, DialogRef theDialogRef, 
  137.         FilterDataStructure *fds )
  138. {
  139.     if (item == sfHookFirstCall)
  140.     {
  141.         UInt32        refcon;
  142.         SInt32        csDirID;
  143.         SInt16        csVRefNum;
  144.         
  145.         refcon = GetWRefCon((WindowRef)theDialogRef);
  146.         if ( refcon == sfMainDialogRefCon )
  147.         {
  148.             if ( CMGetColorSyncFolderSpec(kOnSystemDisk, false, &csVRefNum, &csDirID) == noErr )
  149.             {
  150.                 fds->reply.sfFile.vRefNum = csVRefNum;
  151.                 fds->reply.sfFile.parID = csDirID;
  152.                 fds->reply.sfFile.name[0] = 0;
  153.                 return sfHookChangeSelection;
  154.             }
  155.         }
  156.         if ( refcon == sfLockWarnDialogRefCon )
  157.             return 1;    // simulate hit of OK button
  158.     }
  159.     
  160.     if (item == sfHookNullEvent)
  161.     {
  162.         OSErr        err;
  163.         Str255        profName;
  164.         FSSpec        *old = &fds->lastSpec;
  165.         FSSpec        *new = &fds->reply.sfFile;
  166.         FInfo        fndrInfo;
  167.         
  168.                 // First compare the new spec with the last one we looked at.
  169.         if ( (new->vRefNum != old->vRefNum) ||
  170.              (new->parID != old->parID) ||
  171.              !EqualString(new->name,old->name,true,true) )
  172.         {
  173.                 // OK, they are different.  Save the new one.
  174.             
  175.             *old =*new;
  176.             
  177.                 //    Get the Info string.  Note that if new is not a valid
  178.                 //  filespec (as will be the case when nothing is selected),
  179.                 //    we end up with an empty string.
  180.             err = FSpGetFInfo(old,&fndrInfo);
  181.             if (!err && (fndrInfo.fdType == kProfileType) )
  182.                 CSProfileInfoString(old,profName);
  183.             else
  184.                 profName[0] = 0;
  185.             
  186.               // Save old again in case above changed it
  187.             *old =*new;
  188.             
  189.             {
  190.                 Rect        r;
  191.                 Handle        textHdl;
  192.                 SInt16        itemType;
  193.                 
  194.                 GetDialogItem (theDialogRef, itemSFProfileName, &itemType, &textHdl, &r);
  195.                 SetDialogItemText (textHdl, profName);
  196.             }
  197.         }
  198.     }
  199.     
  200.     return item;
  201. }
  202.  
  203. //--------------------------------------------------------------------- CSProfileInfoString
  204.  
  205. static void CSProfileInfoString ( FSSpec *spec, Str255 info )
  206. {
  207.     CMProfileRef    prof;
  208.     CMError            err;
  209.     
  210.                 // Clear string first just to be safe.
  211.     info[0] = 0;
  212.     
  213.     if (spec)
  214.     {
  215.         CMProfileLocation location;
  216.         location.locType = cmFileBasedProfile;
  217.         location.u.fileLoc.spec = *spec;
  218.         err = CMOpenProfile(&prof,&location);
  219.     }
  220.     else
  221.         err = CMGetSystemProfile(&prof);
  222.     
  223.     if (!err)
  224.     {
  225.         ScriptCode script;
  226.         err = CMGetScriptProfileDescription(prof, info, &script);    // in ProfileConvert.c
  227.         CMCloseProfile(prof);
  228.     }
  229. }
  230.  
  231. //--------------------------------------------------------------------- SetSFDefaults
  232. // Jam the low-mem globals for StandardFile such that the dialog comes up
  233. // in the specified directory.
  234.    
  235. static void SetSFDefaults ( short vRefNum, long dirID )
  236. {
  237.     LMSetSFSaveDisk(-1 * vRefNum);
  238.     LMSetCurDirStore(dirID);
  239. }
  240.  
  241.  
  242. //--------------------------------------------------------------------- GetSFDefaults
  243. // Get the low-mem globals for the directory that the StandardFile dialog 
  244. // comes up in.
  245.    
  246. static void GetSFDefaults ( short *vRefNum, long *dirID )
  247. {
  248.     *vRefNum = -1 * LMGetSFSaveDisk();
  249.     *dirID = LMGetCurDirStore();
  250. }
  251.  
  252. //--------------------------------------------------------------------- ReadProfileCM2Header
  253.  
  254. static OSErr ReadProfileCM2Header ( FSSpec *spec, CM2Header *hdr)
  255. {
  256.     OSErr            err=noErr;
  257.     short            refNum;
  258.     long            readSize;
  259.     
  260.     refNum = 0;
  261.     readSize = sizeof(CM2Header);
  262.     
  263.     if (!spec || !hdr)
  264.         err = paramErr;
  265.  
  266.     if (!err)
  267.         err = FSpOpenDF( spec, fsRdPerm, &refNum);
  268.  
  269.     if (!err)
  270.         err = FSRead( refNum, &readSize, (Ptr)hdr);
  271.     
  272.     if (refNum)
  273.         (void) FSClose(refNum);
  274.     
  275.     return err;
  276. }
  277. //--------------------------------------------------------------------- ResolveFSSpec
  278.  
  279. static OSErr ResolveFSSpec (FSSpec *fromSpec, FSSpec *toSpec)
  280. {
  281.     OSErr        err = noErr;
  282.     Boolean        isFolder;
  283.     Boolean        wasAlias;
  284.     
  285.     err = FSMakeFSSpec(fromSpec->vRefNum,fromSpec->parID, (StringPtr) 
  286.             &fromSpec->name,toSpec);
  287.     
  288.     if (!err)
  289.         err = ResolveAliasFileMountOption( toSpec, true, &isFolder, &wasAlias, false);
  290.     else
  291.         err = noErr;
  292.     
  293.     return err;
  294. }
  295.  
  296. //--------------------------------------------------------------------- IsAliasFile
  297.  
  298. static OSErr IsAliasFile (const FSSpec *fileFSSpec, Boolean *aliasFileFlag, 
  299.         Boolean *folderFlag)
  300. {
  301.     CInfoPBRec    myCInfoPBRec;
  302.     OSErr        retCode;
  303.     
  304.     if (fileFSSpec == nil || aliasFileFlag == nil || folderFlag == nil)
  305.         return paramErr;
  306.     
  307.     *aliasFileFlag = *folderFlag = false;
  308.     
  309.                 // Get the item's catalog information.
  310.     myCInfoPBRec.hFileInfo.ioCompletion = nil;
  311.     myCInfoPBRec.hFileInfo.ioNamePtr = (StringPtr) &fileFSSpec->name;
  312.     myCInfoPBRec.hFileInfo.ioVRefNum = fileFSSpec->vRefNum;
  313.     myCInfoPBRec.hFileInfo.ioDirID = fileFSSpec->parID;
  314.     myCInfoPBRec.hFileInfo.ioFVersNum = 0;
  315.     myCInfoPBRec.hFileInfo.ioFDirIndex = 0;
  316.     
  317.     retCode = PBGetCatInfoSync(&myCInfoPBRec);
  318.     
  319.                 // Set aliasFileFlag if the item is not a directory and the...
  320.                 // aliasFile bit is set.
  321.     if (retCode == noErr)
  322.     {            // Check directory bit else check isAlias bit.
  323.         if ((myCInfoPBRec.hFileInfo.ioFlAttrib & ioDirMask) != 0)
  324.             *folderFlag = true;
  325.         else if ((myCInfoPBRec.hFileInfo.ioFlFndrInfo.fdFlags & 0x8000) != 0)
  326.             *aliasFileFlag = true;
  327.     }
  328.     
  329.     return retCode;
  330. }
  331.  
  332. //--------------------------------------------------------------------- ResolveAliasFileMountOption
  333.  
  334. static OSErr ResolveAliasFileMountOption (FSSpec *fileFSSpec, Boolean resolveAliasChains,
  335.         Boolean *targetIsFolder, Boolean *wasAliased, Boolean mountRemoteVols)
  336. {
  337.                 // Maximum number of aliases to resolve before giving up.
  338.     #define        MAXCHAINS        10
  339.     FSSpec        initFSSpec;
  340.     Handle        alisHandle;
  341.     OSErr        retCode;
  342.     SInt16        myResRefNum, chainCount;
  343.     Boolean        updateFlag, foundFlag;
  344.     Boolean        wasAliasedTemp, specChangedFlag;
  345.     
  346.     if (fileFSSpec == nil || targetIsFolder == nil || wasAliased == nil)
  347.         return paramErr;
  348.     
  349.                 // So FSSpec can be restored in case of error.
  350.     initFSSpec = *fileFSSpec;
  351.                 // Circular alias chain protection.
  352.     chainCount = MAXCHAINS;
  353.                 // Resource file not open.
  354.     myResRefNum = -1;
  355.     
  356.     *targetIsFolder = foundFlag = specChangedFlag = false;
  357.     
  358.                 // Loop through chain of alias files.
  359.     do
  360.     {
  361.         chainCount--;
  362.         
  363.                 // Check if FSSpec is an alias file or a directory.
  364.                 // Note: targetIsFolder => NOT wasAliased.
  365.         retCode = IsAliasFile(fileFSSpec, wasAliased, targetIsFolder);
  366.         if (retCode != noErr || !(*wasAliased))
  367.             break;
  368.         
  369.                 // Get the resource file reference number.
  370.         myResRefNum = FSpOpenResFile(fileFSSpec, fsCurPerm);
  371.         retCode = ResError();
  372.         if (myResRefNum == -1)
  373.             break;
  374.         
  375.                 // The first 'alis' resource in the file is the appropriate alias.
  376.         alisHandle = Get1IndResource(rAliasType, 1);
  377.         retCode = ResError();
  378.         if (alisHandle == nil)
  379.             break;
  380.         
  381.                 // Load the resource explicitly in case SetResLoad(FALSE).
  382.         LoadResource(alisHandle);
  383.         retCode = ResError();
  384.         if (retCode != noErr)
  385.             break;
  386.         
  387.         retCode = FollowFinderAlias(fileFSSpec, (AliasHandle) alisHandle, 
  388.         mountRemoteVols, fileFSSpec, &updateFlag);
  389.         
  390.                 // FollowFinderAlias returns nsvErr if volume not mounted.
  391.         if (retCode == noErr)
  392.         {
  393.             if (updateFlag)
  394.             {
  395.                 // The resource in the alias file needs updating.
  396.                 ChangedResource(alisHandle);
  397.                 WriteResource(alisHandle);
  398.             }
  399.             
  400.             specChangedFlag = true;
  401.             
  402.                 // In case of error, restore file spec.
  403.             retCode = IsAliasFile(fileFSSpec, &wasAliasedTemp, targetIsFolder);
  404.             if (retCode == noErr) 
  405.                 // We're done unless it was an alias file and we're following a chain.
  406.                 foundFlag = !(wasAliasedTemp && resolveAliasChains);
  407.             
  408.         }
  409.         
  410.         CloseResFile(myResRefNum);
  411.         myResRefNum = -1;
  412.         
  413.     } while (retCode == noErr && chainCount > 0 && !foundFlag);
  414.     
  415.                 // Return file not found error for circular alias chains.
  416.     if (chainCount == 0 && !foundFlag)
  417.         retCode = fnfErr;
  418.     
  419.                 // If error, close resource file and restore original FSSpec.
  420.     if (myResRefNum != -1)
  421.         CloseResFile(myResRefNum);
  422.         
  423.     if (retCode != noErr && specChangedFlag)
  424.         *fileFSSpec = initFSSpec;
  425.     
  426.     return retCode;
  427. }
  428.  
  429.