MultiFinder Icon Fix
Volume Number: 6
Issue Number: 3
Column Tag: Programmer's Workshop
Æeshete--a fix for MultiFinder 
By David Dunham, Bellevue, WA
I’ve enjoyed multitasking on my Macintosh since I discovered in 1984 that the
Key Caps DA kept running in a background window. So I should be happy with
MultiFinder, right? Well, almost. Besides multitasking, I like my Macintosh because
it’s, well, pretty. From the cute startup icon to the zooming Open command in the
Finder, there’s an attention to artistic detail. Except in MultiFinder. I had to keep
staring at that ugly shrunken representation of an icon at the right of the menu bar.
It was pretty obvious why it was ugly -- QuickDraw was just scaling down a
32*32 icon to 16*16 pixels. Why couldn’t MultiFinder plot small icons (SICN
resources) instead of shrinking icons? (I don’t know -- I did suggest this in my bug
reports. Apparently, this will happen in System 7.0.)
Checking for Traps
Obviously I had to do something to make my Macintosh aesthetic again. But what?
Presumably MultiFinder was drawing the ugly menu bar icon, or at least patching the
Menu Manager to do its dirty work. But patching MultiFinder didn’t seem like a good
approach. First of all, it would be a lot of work -- I’d probably have to disassemble it,
and I neither own a disassembler nor enjoy reading undocumented code. Second, there
are several versions of MultiFinder. Each time a new one came out, I’d have to figure
out how to patch it. Perhaps the Menu Manager (as embodied in the MBDF and MDEF
defprocs) was responsible for the ugly icons, but these resources also get revised with
each System release, and weren’t good candidates for patching.
My next thought was to patch the _PlotIcon trap, which must be responsible for
drawing the shrunken icons. I used a low-level debugger to determine that _PlotIcon
was never in fact getting called. Oops. But that was OK, because _CopyBits was called.
This wasn’t a great surprise, since _PlotIcon would have called _CopyBits in any case.
Unfortunately, _CopyBits wasn’t a good trap to patch. It’s used all over the place to
blit (bit block transfer) to the screen, so any overhead I added to it would slow down
frequent operations such as drawing scroll bars and radio buttons. Further, its
argument is a bitmap, rather than a handle to an icon, which would make it difficult to
determine whether or not the bitmap was an application icon. Worse, there might be
legitimate cases for plotting ugly shrunken icons -- I wanted my patch to fix
MultiFinder, not break other programs.
Finally, it dawned on me. I could plot aesthetic icons by patching
_DetachResource. _DetachResource? Yes, because the application’s resource file may
not be accessible when the menu’s drawn. If you need resource data, but can’t
guarantee that the resource will be available, the simplest thing would be to do
/* 1 */
handle = GetResource(type, id);
DetachResource( handle);
and then use the handle some time later (of course, you’d have to make sure your
resource wasn’t purgeable, or call _HNoPurge on the handle). I hauled out the
debugger again, and sure enough, MultiFinder was calling _DetachResource on ICN#
resources.
This would be just the right trap to patch -- it’s not called too frequently, and
probably never in time-critical loops. And its argument is a handle, which I could
easily call _GetResInfo on to determine if it was an ICN#.
The Patch
So now that I knew how to identify where MultiFinder got the icons for the menu,
I had to replace them with SICNs. I could have replaced them with different ICN#s, but
ResEdit has a graphical SICN editor which I like using. And SICNs are just bitmap data,
the 16*16 equivalent of the 32*32 ICN#s.
The patch is simple (see listing 1): whenever someone calls _DetachResource on
an ICN#, replace the data with a doubled SICN; when it’s plotted, it’ll be shrunk down
to 50% and look like a SICN again. Just which SICN I determine by getting the current
application’s signature (I find its name with _PBGetFCBInfo, then the signature with
_PBHGetFInfo), then looking it up in a list (the CRE# resource, discussed below). If I
find the signature, and the ICN# is for the application, I replace the ICN# data. Note
that I replace only the icon data. I don’t touch the mask, because it’s not used in
drawing menu icons.
In an attempt to prevent replacing ICN#s which are being drawn by programs
other than their owner, the test in the beginning makes sure the ICN# belongs to the
current application. The ICN# used by Finder comes from the System file, so it
doesn’t belong to any application. It is, however, identifiable as ICN# 3.
In the original version of the patch, I got the SICN and doubled it by _CopyBitsing
it right into the ICN#.
/* 2 */
typedef struct {
OSType creator;
word rsrcID;
} SIGNATURE;
/*
AESTHETIZE -- Change an ICN# resource (so it’s aesthetic when
shrunken)
*/
void aesthetize( handle, sicn, creators)
Handle handle, sicn; SIGNATURE **creators;
{
word sicnNum = -1;
word id;
OSType type;
Str255 name;
FCBPBRec fcb;
HParamBlockRec pb;
OSErr error;
register word i;
GetResInfo( handle, &id, &type, &name);
if (type == ‘ICN#’) {
/* Be sure ICN# is owned by this application (or may be System)
*/
if (HomeResFile( handle) != CurApRefNum && id != 3) return;
/* Get application’s name and directory */
fcb.ioNamePtr = name;
fcb.ioRefNum = CurApRefNum;