![]() |
PATH![]() |
![]() ![]() |
Starting with version 2.5,
ColorSync provides a profile cache and a new routine,
CMIterateColorSyncFolder
, for optimized profile searching. The sample code shown in
Listing 3-13
through
Listing 3-15
takes advantage of optimized searching if ColorSync version 2.5 is available; if not, it performs a search that is compatible with earlier versions of ColorSync. The compatible search may take some advantage of the profile cache, but cannot provide fully optimized results.
As background for the code samples in Listing 3-13 to Listing 3-15 , you should be familiar with the topics described in the following sections:
IMPORTANT
You cannot use the ColorSync Manager search functions to search for ColorSync 1.0 profiles.
The
CMIterateColorSyncFolder
function uses ColorSync's profile cache to supply your application with information about the profiles currently available in the ColorSync Profiles folder. The function calls your callback routine once for each available profile, supplying your routine with the profile header, script code, name, and location, stored in a structure of type
CMProfileIterateData
.
Even though there may be many profiles available, CMIterateColorSyncFolder can take advantage of ColorSync's profile cache to return profile information quickly, and (if the cache is valid) without having to open any profiles. As a result, your routine may be able to perform its function, such as building a list of profiles to display in a pop-up menu, quickly and without having to open each file-based profile.
The CMIterateColorSyncFolderCompat function, shown in
Listing 3-15
, performs an optimized search using the
CMIterateColorSyncFolder
function if ColorSync version 2.5 is available. Otherwise, it calls the
CMNewProfileSearch
function, which is available in earlier versions of ColorSync.
When you call the CMIterateColorSyncFolderCompat function, you pass a universal procedure pointer to a filter procedure in the proc parameter. CMIterateColorSyncFolderCompat uses that filter procedure when it performs an optimized search with CMIterateColorSyncFolder . Listing 3-13 provides a sample filter procedure called MyIterateProc .
The MyIterateProc function is called once for each available profile and merely stores the names of all non-display profiles (such as printer and scanner profiles) at an arbitrary position in a list. You would do something similar, for example, to display a list of profiles in a dialog.
Note that the CMIterateColorSyncFolderCompat function works in a similar way for ColorSync 2.5 and for earlier versions, although the search is much more efficient with version 2.5. CMIterateColorSyncFolderCompat either calls the
CMIterateColorSyncFolder
function, which calls the MyIterateProc function once for each available profile, or it calls the
CMNewProfileSearch
function, which calls the ProfileSearchFilter function (
Listing 3-14
) once for each available profile. The ProfileSearchFilter function in turn calls MyIterateProc, so similar processing occurs.
Listing 3-13 An iteration function for profile searching with ColorSync 2.5
Pascal OSErr MyIterateProc(CMProfileIterateData* data, void* refcon)
{
Cell theCell;
// Assume we can cast refCon to a ListHandle.
ListHandle list = (ListHandle)refcon;
/* Assume we're interested only in non-display profiles, such as printer
and scanner profiles. */
if (data->header.profileClass != cmDisplayClass)
{
/* This code adds the profile name at an arbitrary position
in a list. You could do something similar to display a
list of all available profiles. */
cell.v = LAddRow(1,999,list);
cell.h = 0;
// The name data in the iterate data structure is in Pascal format,
so we use the length byte to determine how many bytes to copy. */
LSetCell((Ptr)data->name+1, name[0], cell, list);
cell.h = 1;
// Store the profile's location information with the cell.
LSetCell((Ptr)data->location, sizeof(cmProfileLocation), cell, list);
}
// A more complicated function might need to return an error here.
return noErr;
};
To search for profiles prior to version 2.5 of the ColorSync Manager, you use the
CMNewProfileSearch
function. You supply
CMNewProfileSearch
with a search record of type
CMSearchRecord
that identifies the search criteria. If you also provide a pointer to a filter function,
CMNewProfileSearch
uses the function to eliminate profiles from the search based on additional criteria not defined by the search record. The
ProfileSearchFilter
function shown in
Listing 3-14
provides an example of a filter routine for searching with the
CMNewProfileSearch
function.
Listing 3-14 defines the IterateCompatPtr data type, a pointer to a structure that stores search information. When you call the CMIterateColorSyncFolderCompat function shown in Listing 3-15 , you pass a reference to the MyIterateProc function ( Listing 3-13 ) in the proc parameter. If ColorSync 2.5 is not available, the CMIterateColorSyncFolderCompat function calls the CMNewProfileSearch function. It passes the ProfileSearchFilter function ( Listing 3-13 ) as the search filter and it passes an IterateCompatPtr pointer as the refCon parameter. It sets the proc field of the IterateCompatPtr pointer to the MyIterateProc function that you passed in the proc parameter.
The CMNewProfileSearch function calls the ProfileSearchFilter function ( Listing 3-13 ) once for each profile. The ProfileSearchFilter function simply casts the passed refCon pointer to an IterateCompatPtr, then calls the function specified by the pointer's proc field. As a result, the MyIterateProc function is called once for each profile, just as it is when CMIterateColorSyncFolderCompat calls CMIterateColorSyncFolder under ColorSync 2.5.
Note that ProfileSearchFilter always returns true, indicating the profile should be filtered out of the search result returned by CMNewProfileSearch , because we've already gotten all the information we need from it. Note also that ProfileSearchFilter uses the require macro, which is defined in Poor Man's Exception Handling .
Listing 3-14 A filter function for profile searching prior to ColorSync 2.5
// Declare a structure to use for searching with ColorSync versions prior to 2.5.
typedef struct IterateCompat
{
CMProfileIterateUPP proc;
OSErr osErr;
void* refCon;
} IterateCompatRec, *IterateCompatPtr;
static pascal Boolean ProfileSearchFilter (CMProfileRef prof, void *refCon)
{
OSErr theErr = noErr;
IterateCompatPtr refConCompatPtr;
CMProfileIterateData iterData;
// Cast refcon to our type.
refConCompatPtr = (IterateCompatPtr)refCon;
// If we had an error from an earlier profile, give up
// by branching to cleanup location.
theErr = refConCompatPtr->osErr;
require(theErr == noErr, cleanup); // require is defined in Listing 3-3 on page -xcviii.
// Try to get the profile's location.
theErr = CMGetProfileLocation(prof, &iterData.location);
require(theErr == noErr, cleanup);
// Try to get the profile's header.
theErr = CMGetProfileHeader(prof, (CMAppleProfileHeader*)&iterData.header);
require(theErr == noErr, cleanup);
// Try to get the profile's name.
theErr = CMGetScriptProfileDescription(prof, iterData.name, &iterData.code);
require(theErr == noErr, cleanup);
iterData.dataVersion = cmProfileIterateDataVersion1;
// Call the iterate callback routine.
theErr = CallCMProfileIterateProc(refConCompatPtr->proc,
&iterData, refConCompatPtr->refCon);
require(theErr == noErr, cleanup);
cleanup:
if (theErr)
refConCompatPtr->osErr = theErr;
return true; // exclude the profile;
}
Listing 3-15 provides sample code that performs an optimized profile search if ColorSync 2.5 is available, but provides a search that is compatible with previous versions if ColorSync 2.5 is not available.
When ColorSync 2.5 is available, CMIterateColorSyncFolderCompat simply calls the function
CMIterateColorSyncFolder
, passing on the information it received through its parameters. As a result,
CMIterateColorSyncFolder
calls the MyIterateProc function, shown in
Listing 3-13
, once for each available profile. Your version of MyIterateProc can examine the passed information for each profile and perform any required operation on the profiles it is interested in.
When ColorSync 2.5 is not available, CMIterateColorSyncFolderCompat sets up a search with the function
CMNewProfileSearch
. As part of this setup, it initializes a structure of type IterateCompatRec, defined in
Listing 3-14
, which it passes to
CMNewProfileSearch
for the
refCon
parameter. The
CMNewProfileSearch
function in turn passes a pointer to the IterateCompatRec structure as the
refCon
parameter to ProfileSearchFilter, which it calls once for each available profile.
ProfileSearchFilter calls the MyIterateProc function, which gets a chance to handle each profile, just as it does in the case where ColorSync 2.5 is available. The main drawback is that without the availability of the profile cache and the CMIterateColorSyncFolder function, searching through the profiles is likely to be a much more time-consuming task.
Note that CMIterateColorSyncFolderCompat uses the require macro, which is defined in Poor Man's Exception Handling .
Listing 3-15 Optimized profile searching compatible with previous versions of ColorSync
CMError CMIterateColorSyncFolderCompat (CMProfileIterateUPP proc,
unsigned long *seed,
unsigned long *count,
void *refCon)
{
CMError theErr = noErr ;
/* Presume the caller passed a pointer to MyIterateProc to this
function in the proc parameter. */
if ( ColorSync25Available() ) // This routine is shown in Listing 3-1 on page -xcii.
return CMIterateColorSyncFolder(proc, seed, count, refCon);
else
{
CMProfileSearchRef searchResult;
CMSearchRecord searchSpec;
unsigned long count;
IterateCompatRec refConCompat;
/* Set up a search record to pass to CMNewProfileSearch. Include
procedure pointer to search filter from Listing 3-14 on page -cxxxi. */
searchSpec.filter = NewCMProfileFilterProc(ProfileSearchFilter);
searchSpec.searchMask = cmMatchAnyProfile;
/* Set up our private data structure for compatible (pre-ColorSync 2.5)
profile searching.
Pass the pointer to the MyIterateProc function, which was
presumably passed to this function in the proc parameter,
on to our filter routine, ProfileSearchFilter,
in the refCon parameter, using an IterateCompatRec structure. */
refConCompat.proc = proc;
refConCompat.osErr = noErr;
refConCompat.refCon = refCon;
// Start traditional search.
theErr = CMNewProfileSearch(&searchSpec,
(void*)&refConCompat, &count, &searchResult);
if (theErr == noErr)
{
// We don't use the result, but still must dispose of it.
CMDisposeProfileSearch(searchResult);
theErr = refConCompat.osErr;
}
DisposeRoutineDescriptor(searchSpec.filter);
}
return theErr;
}