DA Philosophy
Volume Number: 2
Issue Number: 6
Column Tag: Programmer's Forum
Philosophy of c Programming
By David Dunham, Maitreya Design
We are grateful to have this article from David Dunham, best known for his desk
accessory DiskInfo, now in version 1.41. In this article, he shares some of his
experiences in writing a first class DA. -Ed.
Introduction
Desk accessories (DAs) are in many ways one of the best design features of the
Macintosh. Not only did Apple provide a clean way to handle them (unlike
theincompatibilities between DAs under MSDOS), they’re currently the only way the
average user is going to multitask.
In my opinion, desk accessories are really no different from applications.
Examples of desk accessories which do the job of applications are MockWrite, ClickOn
Worksheet, and Acta. One developer wondered why everything on the Mac couldn’t be a
DA. There’s really no reason, except that the Mac architecture implements them as
drivers, and the unit table is limited to 32 entries. So we’re stuck.
Although in one sense writing a desk accessory should be no different than
writing an application (Acta started out life as an application, and was easy to convert),
there are some differences, mainly because desk accessories are the guests of an
application. I’ll discuss implementing DAs at a fairly abstract level. Plenty of detailed
articles on desk accessories have already been published. See the Oct 85, Nov 85, Jan
86, Feb 86, Mar 86, or Apr 86 issues of MacTutor or the Oct 85 issue of MacUser for
complete listings. I’ll talk about what I’ve learned writing the DAs DiskInfo, FileInfo,
and Acta.
Edit Menu
An accessory that manipulates data almost certainly needs to support the Edit
menu. But if you use the Edit menu, you’re confronted with the fact that many
applications don’t include the keyboard equivalents to the standard commands. In fact,
ThinkTank doesn’t even provide an Undo menu item at all! This means that you’ll have
to handle the standard equivalents (e.g. Command-Z for Undo).
EventRecord *ep;
/* This code is necessary because */
/* MenuKey() won't check for Edit menu */
case keyDown:
case autoKey:
c = (word)(ep->message & 255); /* Mask for low byte */
if (ep->modifiers & cmdKey) { /* Pretzel key , menu item*/
switch (c) {
case 'Z':
case 'z':
/* You may want to check for option-equivalents, too */
undo_cmd();
break;
case 'X':
case 'x':
cut_cmd();
break;
Note that this causes a localizing problem, since non-English systems may use
different keyboard equivalents (the leftmost four keys on the bottom row are still
used).
If at all appropriate, include Undo! I don’t consider anything a true Mac program
without it. And it impresses people. When Guy Kawasaki of Apple first saw Acta, he
exclaimed, “You have Undo in a desk accessory?!” Having Undo is impressive because
desk accessories are often considered poor cousins of applications. But ClickOn
Worksheet provides more features than Multiplan, and Acta’s application equivalent
lacks Undo.
Goodbye Kisses
Any intelligent application asks the user to save his work before quitting. Since
desk accessories don’t have access to the File menu, it isn’t quite as easy to implement
this feature. Luckily, Apple provided the goodbye kiss, a special call to your accessory
before the heap is reinitialized. This is your way of knowing that the user quit the
application, and is the time to remind him about unsaved changes. Users tend to get
unhappy if they lose data, even if it’s because they didn’t quit in the “proper” way.
When I was trying to implement this feature, I couldn’t find a single DA that had
it! (I’ve since learned that ClickOn Worksheet [which by now you can tell I admire
greatly] does field goodbye kisses.) In fact, since I couldn’t get it to work, and since I
couldn’t determine that it worked anywhere else, I was convinced that it didn’t work at
all. It does. You do need to return via JIODone, which may be difficult in a high-level
language. Mike Schuster’s article in the April MacTutor had some clever glue to handle
this. I did it with inline code:
/* Pbp is a global pointer to the parameter block */
/* restore() restores registers */
if (Pbp->u.cp.csCode < 0) { /* Goodbye kiss */
close_ window(); /* Close it NOW */
restore(); /* Since above affects A0/A1 */
close(); /* Exactly same as close box */
#asm
move.l Dp_,A1 ; restore DCE pointer
move.w #0,D0 ; Return code
movem.l (SP)+,.registers ; normally done in a return
unlk A6
move.l JIODone,-(SP) ; Goto IODone
rts
#endasm
}
I found that I had to close the DA window first, presumably since I was putting
up an SFPutFile() dialog and thus getting reentrant calls. However, at the time of a
goodbye kiss, your window may be gone already; programs like MacWrite close all
windows before quitting (but don’t close the desk accessory associated with a window).
Here’s a routine to close your window only if it’s still there; I found this attributed to
Mike Schuster:
/*************************************************** */
/* */
/* CLOSE_WINDOW - Close our window, if it's there. */
/* Note: Dp is the global DCE pointer */
/* */
/*************************************************** */
close_ window() {
WindowPeek w;
/* Make sure window's still there before getting rid of it. */
/* It may be gone, because applications like MacWrite */
/* close all open windows without regard to */
/* what they are. */
/* Start at beginning of window list */
w = FrontWindow();
/* Look for our window */
while (w && w != Dp->dCtlWindow)
w = w->nextWindow;
/* If we found it, get rid of it */
if (w)
CloseWindow(w);
Dp->dCtlWindow = 0;
}
Files
Your DA can create, delete, and rename files, even from the Finder. The newer
Finders handle these changes properly. All you have to do is call FlushVol() after
making any changes. This signals the Finder to update the desktop (and it’s something
you should do anyway after altering a disk).
There are a few things that you shouldn’t do from the Finder. These include
changing the FinderInfo of a file, including its type and creator. Apparently the Finder
keeps those in memory, and doesn’t update its copy if a DA changes them. If it then
writes desktop information before launching an application, it overwrites what the DA
did with its original copy.
If your DA uses a resource file to store information (like the Scrapbook File),
you should open it on bootDrive (the global at $210). Despite its name, this is the
vRefNum or WDRefNum where the Finder is located. In other words, the System Folder
(usually).
If you want your DA’s files to have distinctive icons, you’ll have to figure out a
way to get the bundle into the Desktop file. It’s best to put the bundle in a support
program, such as an installer or configurer. This should be less confusing than having
the user copy a special file to a disk, then delete it.
Menus
If you’re going to use more than one menu, they won’t fit. You’ll have to change
the entire menu bar in order to guarantee enough space.
In fact, the easiest way for the menu bar to run out of room is to use DAs that
consist of just a menu. Several of these can swamp an application with many menus. So
be sure the world needs another menu-only DA before you write one.
The big problem with menus is that your DA may have enough functions to
require more than one. At least the current System has scrolling menusbut if there
are more than 19 items, your user might not realize there are any down below (this is
where Apple really screwed upthere was another implementation of scrolling menus