craigh022697
asked on
How do I get Finder to recognize new custom icon?
I've got an application that sets up the custom icon resources. It looks like the resources are getting put in the right places and other applications can see that they are there.
One problem: the Finder doesn't update the display of the file. I'm guessing that there is some kind of caching mechanism that is preventing the update. I tried twiddling the modification dates of the files and using ResEdit to flip some of the Finder flags, but nothing seems to work.
Anybody out there have any clues or code snippets?
Thanks in advance,
Craig Hockenberry
One problem: the Finder doesn't update the display of the file. I'm guessing that there is some kind of caching mechanism that is preventing the update. I tried twiddling the modification dates of the files and using ResEdit to flip some of the Finder flags, but nothing seems to work.
Anybody out there have any clues or code snippets?
Thanks in advance,
Craig Hockenberry
ASKER
No, this won't work (at least on my 7.5.5 system). I'm trying to add _custom_ icons (not standard icons .. there are no BNDL issues). I've found that I need to send the Finder some AppleEvents and let it set the custom icon through it's normal mechanism (via the cache). I'm not sure what the correct AppleEvents are though...
Hmmm. I was not talking about custom icons specifically. Any change you make to a folder usually needed to have the folder touched.
Perhaps what you are thinking of is the 'fupd' event. I am not sure whether the direct object needs to be the file or the enclosing folder.
Perhaps what you are thinking of is the 'fupd' event. I am not sure whether the direct object needs to be the file or the enclosing folder.
ASKER
ASKER
Hit the submit button on the previous one before I typed anything.
Here's what I'm doing...
The following code is distilled from Greg Anderson's article in Develop #10:
osErr = GetFinder (&finderPSN);
osErr = AECreateDesc(typeProcessSe rialNumber , &finderPSN, sizeof(ProcessSerialNumber ), &target);
osErr = AECreateAppleEvent(kAECore Suite, kAEGetData, &target, kAutoGenerateReturnID, kAnyTransactionID, &ae);
#ifdef IT_WORKS
osErr = AECreateDesc(typeType, &selectionProperty, sizeof(DescType), &specDesc);
osErr = CreateObjSpecifier(cProper ty, &nullDesc, formPropertyID, &specDesc, false, &specifier); // TEMPORARY - disposeInputs parameter should be true
osErr = AECreateDesc(typeType, &iconProperty, sizeof(DescType), &keyData);
osErr = CreateObjSpecifier(cProper ty, &specifier, formPropertyID, &keyData, false, &directSpecifier); // TEMPORARY - disposeInputs parameter should be true
osErr = AEPutParamDesc(&ae, keyDirectObject, &directSpecifier);
#else // IT DOESN'T WORK
osErr = AECreateDesc(typeFSS, file, sizeof(FSSpec), &specDesc);
osErr = CreateObjSpecifier(cItem, &nullDesc, formPropertyID, &specDesc, false, &specifier); // TEMPORARY - disposeInputs parameter should be true
osErr = AECreateDesc(typeType, &iconProperty, sizeof(DescType), &keyData);
osErr = CreateObjSpecifier(cProper ty, &specifier, formPropertyID, &keyData, false, &directSpecifier); // TEMPORARY - disposeInputs parameter should be true
osErr = AEPutParamDesc(&ae, keyDirectObject, &directSpecifier);
#endif
osErr = AESend(&ae, &aeReply, kAEWaitReply, kAENormalPriority, kAEDefaultTimeout, NULL, NULL); // TEMPORARY - (kAENoReply | kAENeverInteract)
osErr = AEGetParamDesc(&aeReply, keyAEResult, typeWildCard, &result);
The code from the article shows how to change the icon of the current Finder selection. I want to use a FSSpec instead of the object specifier (he says you can do that in the article). I haven't been able to get this to work (and I've tried _many_ different combinations).
I'm also aware of the 'fupd' event. I've not been successful with that either (from a folder or a file):
osErr = GetFinder (&finderPSN);
osErr = AECreateDesc(typeProcessSe rialNumber , &finderPSN, sizeof(ProcessSerialNumber ), &target);
osErr = AECreateAppleEvent(kAEFind erSuite, kAEUpdate, &target, kAutoGenerateReturnID, kAnyTransactionID, &ae);
osErr = AECreateDesc(typeFSS, file, sizeof(FSSpec), &specDesc);
osErr = AEPutParamDesc(&ae, keyDirectObject, &specDesc);
osErr = AESend(&ae, &aeReply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, NULL, NULL); // TEMPORARY - (kAENoReply | kAENeverInteract)
This Apple Events stuff is really hairy... I've read shitloads of documentation and I still don't have a solid grasp of the concepts. And I thought the ScriptEditor was a pain in the ass...
Here's what I'm doing...
The following code is distilled from Greg Anderson's article in Develop #10:
osErr = GetFinder (&finderPSN);
osErr = AECreateDesc(typeProcessSe
osErr = AECreateAppleEvent(kAECore
#ifdef IT_WORKS
osErr = AECreateDesc(typeType, &selectionProperty, sizeof(DescType), &specDesc);
osErr = CreateObjSpecifier(cProper
osErr = AECreateDesc(typeType, &iconProperty, sizeof(DescType), &keyData);
osErr = CreateObjSpecifier(cProper
osErr = AEPutParamDesc(&ae, keyDirectObject, &directSpecifier);
#else // IT DOESN'T WORK
osErr = AECreateDesc(typeFSS, file, sizeof(FSSpec), &specDesc);
osErr = CreateObjSpecifier(cItem, &nullDesc, formPropertyID, &specDesc, false, &specifier); // TEMPORARY - disposeInputs parameter should be true
osErr = AECreateDesc(typeType, &iconProperty, sizeof(DescType), &keyData);
osErr = CreateObjSpecifier(cProper
osErr = AEPutParamDesc(&ae, keyDirectObject, &directSpecifier);
#endif
osErr = AESend(&ae, &aeReply, kAEWaitReply, kAENormalPriority, kAEDefaultTimeout, NULL, NULL); // TEMPORARY - (kAENoReply | kAENeverInteract)
osErr = AEGetParamDesc(&aeReply, keyAEResult, typeWildCard, &result);
The code from the article shows how to change the icon of the current Finder selection. I want to use a FSSpec instead of the object specifier (he says you can do that in the article). I haven't been able to get this to work (and I've tried _many_ different combinations).
I'm also aware of the 'fupd' event. I've not been successful with that either (from a folder or a file):
osErr = GetFinder (&finderPSN);
osErr = AECreateDesc(typeProcessSe
osErr = AECreateAppleEvent(kAEFind
osErr = AECreateDesc(typeFSS, file, sizeof(FSSpec), &specDesc);
osErr = AEPutParamDesc(&ae, keyDirectObject, &specDesc);
osErr = AESend(&ae, &aeReply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, NULL, NULL); // TEMPORARY - (kAENoReply | kAENeverInteract)
This Apple Events stuff is really hairy... I've read shitloads of documentation and I still don't have a solid grasp of the concepts. And I thought the ScriptEditor was a pain in the ass...
Don't know if this will help but I found it while surfing around looking for applescript information. You could send similar events to the finder to get it to change the icon of said thing.
This is from:
http://devworld.apple.com/ngs/lpp/adrpub/docs/dev/techsupport/develop/issue20/20anderson.html
GETTING AND SETTING CUSTOM ICONS
The icon bitmap of a file is available through ordinary file system calls, but there are a couple of
different cases to contend with: the icon might be stored in the desktop database, or it could be a custom
icon stored in the resource fork of the file. Some files are "special," and only the Finder really knows what
their icon bitmap should be. The simplest way to get the exact icon bitmap for a file is to ask the Finder
what it is. Once again, Get Data and Set Data are the events to use.
The result of a Get Data event that specifies the icon property of some object is an AERecord that
contains the entire icon family for the item's icon. The record contains parameters whose key is the same
as the individual resources of an icon family (for example, 'ICN#' and 'icl8'); the data stored in these
parameters is identical to the data found in a resource of the same type. A Set Data event takes a record
in the same format, or an empty list if the intention is to remove the custom icon.
Listing 4 shows how to remove the custom icon from every item in the selection. Note that the specifier
"icon of selection" is equivalent to the more complex specifier "icon of every item of selection."
Listing 4 shows how to remove the custom icon from every item in the selection. Note that the specifier
"icon of selection" is equivalent to the more complex specifier "icon of every item of selection."
Listing 4. Removing custom icons from the selection
// tell application "Finder"
// set icon of selection to empty
// end tell
TAEvent ae;
TDescriptor target = GetAddressOfFinder();
ae.MakeAppleEvent(kAECoreS uite, kAESetData, target);
target.Dispose();
// Make an object specifier for "icon of selection" and put it into the
// direct object of the event.
TDescriptor directObjectSpecifier;
TDescriptor selectionSpecifier;
TDescriptor keyData;
TDescriptor nullDescriptor;
keyData.MakeDescType(pSele ction);
selectionSpecifier.MakeObj ectSpecifi er(cProper ty, nullDescriptor,
formPropertyID, keyData, true);
keyData.MakeDescType(pIcon Bitmap);
directObjectSpecifier.Make ObjectSpec ifier(cPro perty, selectionSpecifier,
formPropertyID, keyData, true);
ae.PutDescriptor(keyDirect Object, directObjectSpecifier);
directObjectSpecifier.Disp ose();
// Obviously, a Set Data event needs data. In the case of this sample,
// the data we want is "empty," which is represented by an empty list.
TDescriptor emptyList;
emptyList.MakeEmptyList();
ae.PutDescriptor(keyAEData , emptyList);
emptyList.Dispose();
// Send the event and dispose of it once it has been sent.
TAEvent reply;
ae.Send(&reply, kAENoReply);
ae.Dispose();
The sample application Finder Tricks on the CD has a feature that changes the icons of all the items in the
frontmost Finder window -- each item is given some other item's icon. Other than serving as a useful
example of how to send events to the Finder, this sample doesn't have much utility, although it does do an
admirable job at messing up the appearance of Finder windows.
An application can change an item's icon by writing the custom icon directly into the appropriate resources
in the file and then setting the "custom icon bit" using the file system, instead of sending an event to the
Finder -- but the change won't take effect right away. The reason for the delay is that the Finder isn't
notified when the contents of the disk change, so it must periodically poll the file system to find out
whether it needs to redraw any items in its open windows. Polling happens only every now and again, so that
the Finder doesn't eat up every spare CPU cycle on the machine when it's just sitting idle in the
background.
This is from:
http://devworld.apple.com/ngs/lpp/adrpub/docs/dev/techsupport/develop/issue20/20anderson.html
GETTING AND SETTING CUSTOM ICONS
The icon bitmap of a file is available through ordinary file system calls, but there are a couple of
different cases to contend with: the icon might be stored in the desktop database, or it could be a custom
icon stored in the resource fork of the file. Some files are "special," and only the Finder really knows what
their icon bitmap should be. The simplest way to get the exact icon bitmap for a file is to ask the Finder
what it is. Once again, Get Data and Set Data are the events to use.
The result of a Get Data event that specifies the icon property of some object is an AERecord that
contains the entire icon family for the item's icon. The record contains parameters whose key is the same
as the individual resources of an icon family (for example, 'ICN#' and 'icl8'); the data stored in these
parameters is identical to the data found in a resource of the same type. A Set Data event takes a record
in the same format, or an empty list if the intention is to remove the custom icon.
Listing 4 shows how to remove the custom icon from every item in the selection. Note that the specifier
"icon of selection" is equivalent to the more complex specifier "icon of every item of selection."
Listing 4 shows how to remove the custom icon from every item in the selection. Note that the specifier
"icon of selection" is equivalent to the more complex specifier "icon of every item of selection."
Listing 4. Removing custom icons from the selection
// tell application "Finder"
// set icon of selection to empty
// end tell
TAEvent ae;
TDescriptor target = GetAddressOfFinder();
ae.MakeAppleEvent(kAECoreS
target.Dispose();
// Make an object specifier for "icon of selection" and put it into the
// direct object of the event.
TDescriptor directObjectSpecifier;
TDescriptor selectionSpecifier;
TDescriptor keyData;
TDescriptor nullDescriptor;
keyData.MakeDescType(pSele
selectionSpecifier.MakeObj
formPropertyID, keyData, true);
keyData.MakeDescType(pIcon
directObjectSpecifier.Make
formPropertyID, keyData, true);
ae.PutDescriptor(keyDirect
directObjectSpecifier.Disp
// Obviously, a Set Data event needs data. In the case of this sample,
// the data we want is "empty," which is represented by an empty list.
TDescriptor emptyList;
emptyList.MakeEmptyList();
ae.PutDescriptor(keyAEData
emptyList.Dispose();
// Send the event and dispose of it once it has been sent.
TAEvent reply;
ae.Send(&reply, kAENoReply);
ae.Dispose();
The sample application Finder Tricks on the CD has a feature that changes the icons of all the items in the
frontmost Finder window -- each item is given some other item's icon. Other than serving as a useful
example of how to send events to the Finder, this sample doesn't have much utility, although it does do an
admirable job at messing up the appearance of Finder windows.
An application can change an item's icon by writing the custom icon directly into the appropriate resources
in the file and then setting the "custom icon bit" using the file system, instead of sending an event to the
Finder -- but the change won't take effect right away. The reason for the delay is that the Finder isn't
notified when the contents of the disk change, so it must periodically poll the file system to find out
whether it needs to redraw any items in its open windows. Polling happens only every now and again, so that
the Finder doesn't eat up every spare CPU cycle on the machine when it's just sitting idle in the
background.
ASKER
This code is the same as the code from the Develop article. I understand this code .. the problem is that I haven't been successful at changing the selection property (the currently selected item on the finder desktop) to a file specified by my application (a FSSpec).
I've gotten some hints from the author of the article and am trying them out now.
I've gotten some hints from the author of the article and am trying them out now.
This may sound basic, but are you restting the "inited" bit in the finder flags ?
localError := FSPGetFInfo(localSpec, localInfo);
if localError = noErr then
if BAND(localInfo.fdFlags,kHa sBeenInite d) <> 0 then
begin
localInfo.fdFlags := localInfo.fdFlags - kHasBeenInited;
localError := FSPSetFInfo(lcoalSpec,loca lInfo);
end;
and as correctly pointed out in the comments, you then need to change the modification date of the enclosing folder to force the finder to notice it.
end;
localError := FSPGetFInfo(localSpec, localInfo);
if localError = noErr then
if BAND(localInfo.fdFlags,kHa
begin
localInfo.fdFlags := localInfo.fdFlags - kHasBeenInited;
localError := FSPSetFInfo(lcoalSpec,loca
end;
and as correctly pointed out in the comments, you then need to change the modification date of the enclosing folder to force the finder to notice it.
end;
ASKER
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
This usually works, although if you are trying to change standard icons in an application, it usually takes a desktop rebuild.