 Writing DAs, Inits, and CDevs
 
 David A. Lyons, Apple II Developer Technical Support
 Matt Deatherage, Apple II Developer Technical Support
 Don Brady, Green System Software
 (all of Apple Computer)
 July 18, 1990
 
 
 There are two kinds of desk accessories on the Apple IIgs:  Classic
 Desk Accessories (which show up when you hit Apple-Ctrl-ESC) and New
 Desk Accessories (which you select from the Apple menu in a desktop
 program).
 
 
 Classic Desk Accessories (CDAs)
 
 Reference material:  the Desk Manager chapters of Apple IIgs Toolbox
 Reference volumes 1 and 3, Apple IIgs Technical Note #71.
 
 CDAs are executed in the text environment, and the stack is in page
 1 of bank 0 ($00/01xx).  This means you only have 256 bytes of stack
 space to work with, which isn't very much if you're making toolbox
 calls or writing in a high-level language like C or Pascal.  Apple
 IIgs Technical Note #71 shows you how to attempt to get more memory
 for a stack, but the memory is not always available (under ProDOS 8,
 all the bank 0 memory is already allocated for use by the application,
 so you're stuck with just one page).
 
 Reading the keyboard is tricky, becuase keyboard interrupts may or may
 not be started up (the Event Manager is one thing that uses keyboard
 interrupts to read the keyboard).  You can use IntSource in the
 miscellaneous tools to temporarily disable keyboard interrupts, so the
 Event Manager won't steal keystrokes away from you, or you can call
 GetNextEvent to read keys if EMStatus indicates the Event Manager is
 active.
 
 CDAs get a chance to do special things when the system is booted,
 and other times when applications call DeskShutDown.  Every CDA's
 "shutdown" entry point gets called whenever DeskShutDown is called.
 CDAs are not notified when DeskStartUp is called.
 
 If you make GS/OS calls, be sure to check the OS_KIND byte at
 $E1/00BC.  You'll find $00 in the 8-bit world and $01 in the 16-bit
 world.  The user can enter your CDA under ProDOS 8.  With a
 third-party product, a user can even load your CDA without booting
 GS/OS at all--it's polite not to crash in these circumstances, so
 check OS_KIND even when your "shutdown" routine is called for the
 first time.
 
 (There is no completely reliable way to make ProDOS 8 calls from a
 CDA.)
 
 There's a RemoveCDA toolbox call in the Desk Manager in System
 Software 5.0 and later.  This removes a CDA from the list, but it
 doesn't dispose of the CDA's memory, because there's no way to be
 sure that the CDA hasn't installed hooks into the system (heatbeat
 tasks, interrupt handlers, etc).  If you write an application that
 calls RemoveCDA and then disposes of the CDA's memory, the
 responsibility is yours to determine that it's safe.
 
 CDAs can use the Message Center to communicate information to other
 pieces of code that know how to look for specific messages you create.
 See MessageCenter in the Tool Locator chapter of Apple IIgs Toolbox
 Reference volume 1, and MessageByName in volume 3.
 
 When you try to debug a CDA with GSBug, you crash in short order
 because GSBug is not designed to trace code while the stack is in
 page 1.  To trace your CDA code, locate its entry point, break into
 GSBug from a convenient place in an application, set the Direct page
 register to 0, and start Stepping from your CDA's entry point.
 You'll probably have to reboot rather than resume the application,
 but at least you have a way to step through the CDA code.
 
 
 
 New Desk Accessories (NDAs)
 
 References:  Desk Manager chapter of Apple IIgs Toolbox Reference
 volume 1, Apple IIgs Technical Notes #12, 53, 71, 76, 83, and probably
 others.  (Don't wait!  Memorize all the Technical Notes today.)
 
 Notes on GS Technical Note #71:  ResourceShutDown does not have any
 parameters, in spite of the note's instruction to "Call
 ResourceShutDown with your NDA's user ID."  Oops.  Also, it is
 advisable to call GetSysPrefs and SetSysPrefs (GS/OS calls) around
 OpenResourceFile to ensure that the user gets prompted to insert the
 correct disk if it happens to be offline (be sure to put the
 preferences back how they were!).  It's also a good idea to call
 GetLevel and SetLevel around the OpenResourceFile to minimize the
 chance of an application accidentally closing your NDA's resource
 fork (get the level, set it to 0, open your file, and put the level
 back how it was).
 
 Using tool sets that are not already started up is a complicated
 issue.  See Apple IIgs Technical Note #53 for lots of information.
 This note will be revised further in the future.
 
 See Apple IIgs Technical Note #84 for information on using the System
 Software 5.0 TaskMasterDA call to greatly simplify event handling for
 your NDA.
 
 NDAs have four entry points:  Init, Open, Close, and Action.
 
 The Open routine creates a window, calls SetSysWindow on it, and
 returns the pointer.  Starting with System Software 4.0, the Open
 routine is allowed to return 0 if it doesn't want to open a window
 or for some reason fails to open its window (out of memory, for
 example). 
 
 The Init entry point is notified at DeskShutDown and DeskStartUp so
 that the DA can take any special actions needed at boot time or when
 switching between applications.  (DeskShutDown happens once at boot
 time before any application is executed.)
 
 Note that you may get more than one consecutive DeskShutDown call
 while switching between applications.  (For most NDAs this is no
 problem.)
 
 Use your NDA's existing memory ID, which you can get by calling
 MMStartUp.  There is rarely a need to get another one with GetNewID.
 
 NDAs should not call TLStartUp or TLShutDown!  (Those are for
 applications.)
 
 Where should an NDA put configuration files on disk?  Hard-coding the
 pathname */System/Desk.Accs/my.settings is not a very great idea.
 It's better to call LGetPathname or LGetPathname2 (in the System
 Loader tool set, documented with GS/OS) to find your NDA's actual
 pathname.  Then you can put your files in the same directory as your
 NDA.  (Utilities exist that load NDAs from directories other than
 */System/Desk.Accs!)
 
 NDAs that want to be friendly to users who boot their Apple IIgs's
 over a network from an AppleShare file server have a little more
 work cut out for them.  You can do a GetFileInfo GS/OS call on the
 pathname "*/" and examine the fileSysID result field to determine
 whether the user booted from an AppleShare volume.  If so, you can
 make the AppleShare FST-specific call GetUserPath to find the pathname
 of the user's private folder on the server.
 
 NDAs can communicate with other pieces of code by using MessageByName.
 See Apple IIgs Toolbox Reference volume 3.
 
 Apple does not currently guarantee that future system software will
 allow NDAs to receive keypresses with the Apple key down.
 In current system software, NDAs do receive Apple keys, but there are
 advantages to having those keys always handled by the current
 application.  If you have an opinion on this, let's hear it!  It's
 not too late.  [Opinion at the session was pretty clearly "don't
 change it--my NDAs want Apple keys.  Discussion of alternatives is
 still needed. --DAL]
 
 RemoveNDA was added to the Desk Manager new for System Software 5.0.
 (Be careful removing DAs, though.  If you actually UserShutDown them
 and they're still trapping vectors or toolbox calls or have heartbeat
 or run-queue tasks installed, etc, you'll crash the machine.)
 
 Writing a NDA to call install another NDA is tricky--you need to use
 SchAddTask to make it happen after your DA code exits back to the Desk
 Manager.  See Apple IIgs Technical Note #71.
 
 Debugging NDAs with GSBug used to be nearly impossible if the NDA
 accepted keyDown events.  With GSBug 1.5, you can put the CapsLock
 key down to cause GSBug to receive keystrokes instead of letting 
 the NDA munch them.
 
 Here are a few of things applications should do for maximum
 compatibility with NDAs:
 
 --Call DeskStartUp after all the other toolbox startups, and call
 DeskShutDown first, before shutting down other tools.
 
 --Enable the Undo/Cut/Copy/Paste/Clear items in the Edit menu when
 an NDA is the front window (see GetSysWFlag or GetWKind in the Window
 Manager chapter of volume 2).
 
 --Support the Scrap Manager, and have the application's main loop
 watch for GetScrapCount to change.  This way an NDA can change the
 contents of the clipboard and the application can invalidate its Show
 Clipboard window.  (A CDA could change the scrap, too, so don't avoid
 keeping a "private scrap" and converting it to the public formats
 only when an NDA comes to the front or goes away!)
 
 
 Control Panel Devices (CDevs)
 
 The only place CDevs are documented is File Type note $C7.  DTS Sample
 code available in several languages.
 
 Be sure to read Apple IIgs Toolbox Reference volume 3 for information
 about extended controls and resources.  These make CDevs pretty easy
 to write.  Apple IIgs Technical Note #81 contains more information on
 extended controls.
 
 It's difficult to have any of your CDev's code stay resident in
 memory while your CDev is not the one currently selected in the
 control panel.  If you need to keep code around all the time,
 consider writing an Initialization file or an NDA instead, or having
 an init file communicate with your CDev through the Message Center.
 
 
 Initialization Files (Inits)
 
 Inits are executed by the system at boot time, after the OS is
 present but before the first application is launched.
 
 There are two kinds of Initializaton files, Permanent Init Files
 (PIFs, with file type $B6) and Temporary Init Files (TIFs, with file
 type $B7).  Watch for File Type Notes to be released for these soon.
 [This probably means the mid-September batch.]
 
 Inits are documented poorly (apparently not at all, except for page
 266 of Programmer's Introduction to the Apple IIgs.
 
 Permanent inits generally stay in memory until the system is shut
 down, but temporary inits execute and are then immediately removed
 from memory.
 
 The environment when an Init gets control is this:
 --Processor is in 16-bit native mode.
 --There is a 4K stack/direct-page space.  D points to the bottom,
 and S points near the top.
 --The A register contains the init's memory ID
 --The Bank register is not defined.  If you use absolute addressing,
 start with PHB PHK PLB and end with PLB.
 --You can't use the desktop tools.  User interaction is not generally
 a good idea at boot time (because the desktop environment may or may
 not be there--we don't guarantee it one way or the other; and because
 users with long boot times, for whatever reason, want to be able to
 turn on the machine and go get a cool drink while it boots, without
 finding the thing only part-way booted when they come back, waiting
 for them to hit OK).  If you need user interaction, consider using a
 CDev or an NDA and, if necessary, having it communicate with your init
 through the Message Center (MessageByName, volume 3).
 
 The init must execute an RTL when it's finished.  A permanent init
 can store a $0001 in the word just above the RTL address (LDA #1,
 STA 4,S) to ask the system to unload it (as if it were a temporary
 init instead).  A PIF that is useless without certain nonstandard
 hardware might want to do this, for example.
 
 PIFs may want to install HeartBeat tasks (using SetHeartBeat and
 IntSource in the Miscellaneous tools), or they may wanto to install
 RunQueue tasks (AddToRunQ in the Desk Manager).
