Macintosh programmers: have you ever wished you could pull down a menu, type in the name of a toolbox routine, and view its Inside Macintosh description on screen? Meet MacMan, the Macintosh manual-in-a-desk accessory.
January 01, 1988
URL:http://www.drdobbs.com/database/a-programmers-database-for-the-macintosh/184407892
Abdullah Al-Dhelaan and Ted Lewis work in the Computer Science Dept. Oregon State University, Corvallis, OR. 97331
One challenge to writing application software for Apple's Macintosh is the complex environment. Programming the Mac requires the use of an extensive set of ROM routines known as the Toolbox. These routines, although largely responsible for the machine's radical ease of use, add appreciably to the Mac programmer's work load. The Toolbox contains more than 600 routines, and many of them are required in writing even the smallest application. Most programmers find themselves continually referencing Apple's massive documentation, Inside Macintosh, for technical details on the numerous procedures, functions, and data structures of the Toolbox.
At first, using Inside Macintosh as a handy reference manual might seem a minor chore. It has a good index and is divided into five logical volumes. Unfortunately, information retrieval time becomes a dominant factor in the development process, and it quickly becomes obvious that an on-line, electronic means of retrieval is needed.
Our program, MacMan, is an online programmers database that contains much of the key information found in Inside Macintosh. Programmers can use MacMan to fetch the name, parameters, comments, and often-needed descriptions of the Toolbox routines. This information can be accessed from within an editor as an aid to documentation or can be used simply as a way to acquire a better understanding of the inner workings of the Mac. Currently, the database contains more than 500K of text describing the Toolbox routines as well as many other useful facts about the Macintosh.
The design goals for MacMan were simple: the program should be convenient to use, and it should contain useful information. Above all else, we knew that it had to be convenient to be compelling. Convenient meant both simple and fast. We knew that programmers wouldn't accept MacMan if they had to learn a new language or come to grips with a complex database system.
We also knew that the information contained had to be accurate and useful. We could have written the information in a more useful form than that of Inside Macintosh, and we could have selected information from various other sources. We rejected these alternatives, however, because we didn't want to risk introducing errors or to accidentally include ambiguous passages.
We therefore elected to copy carefully selected passages directly from Inside Macintosh. We worked hard to convince Apple Computer to let us use the copyrighted contents of Inside Macintosh specifically to avoid errors or misrepresentations of fact.
MacMan is not a generalized programmers' database program. We willingly sacrificed generality for user convenience. As a result, MacMan is both fast and extremely easy to use. The description of any Toolbox routine can be retrieved from the 500K database file and displayed in a window-all in less than a second.
There are a two ways to use the database: an abbreviated version of MacMan can be installed in the system file as a desk accessory (DA). or a full-fledged application version of the program can be launched from the desktop.
A DA is a special program that can run concurrently in memory with another application. Most DDJ readers are familiar with the concept of DAs from TSR (terminate-and-stay-resident) programs such a SideKick, but these products illustrate an ad hoc solution to the problem of writing a DA. In contrast to the PC, the Mac allows DAs to be integrated into the Macintosh operating environment. It's this integration that we'll be emphasizing in this article. We'll describe the MacMan desk accessory and then show how it was implemented using the Macintosh Toolbox functions.
Two simple access methods are provided through the menu: Find by Name and View by Category (see Figure 1, page 25). Find by Name, as you might expect, retrieves the desired Toolbox routine by its name. If you don't know the routine's name, you can select the View by Category menu item (see Figure 2, page 25). View by Category lets you select one of the 28 managers as a category and then browse through it. When you browse through a category, the Toolbox routine names are displayed in alphabetical order--selecting one of them results in a full display of the routine's description (see Figure 3, below). If MacMan is unable to find a Toolbox routine, it reports the error and asks if it should browse all the routines that begin with the same letter (see Figure 4, page 26).
MacMan Edit Find by name View by category Quit
Select any Category Please: All Macintosh Packages Resource Manager Memory Manager Quick Draw Segment Loader Font Manager O.S. Event Manager ToolBox Event Manager File Manager Window Manager Printing Manager Control Manager Device Manager Menu Manager Disk Driver TextEdit Sound Driver Dialog Manager Serial Drivers Desk Manager AppleTalk Manager Scrap Manager Vertical Retrace Manager ToolBox Utilities Operating System Utilities CANCEL
dragcontrol PROCEDURE DragControl (theControl: ControlHandle; startPt: Point; limitRect,slopRect: Rect; axis: INTEGER); Called with the mouse button down inside theControl, DragControl pulls a gray outline of the control around the screen, following the movements of the mouse until the button is released. When the mouse button is released, DragControl calls MoveControl to move the control to the location to which it was dragged. (note) Before beginning to follow the mouse, DragControl calls
Sorry, "setwtitlee" is not found Should I Give a list of all that start with "s" CANCEL OK
The subject of this article, DAMacMan, is a version of the database that runs as a desk accessory. Before delving into the inner structure of DAMacMan, however, we'll first review the structure of the typical Macintosh application and how it relates to calling DAs.
Every Macintosh application consists of at least one event loop that determines what operations the application's user is allowed to perform. The event loop must handle all user interactions such as mouse clicks, menu selections, and icon manipulations. The existence of an event loop makes Macintosh applications resemble realtime control programs more than traditional interactive sequential programs.
Every well-behaved application must include a Toolbox call to SystemTask so that periodic actions, such as updating the system clock, can be performed by the Macintosh operating system. In Example 1, page 26, we show only one SystemTask call for each pass through the main event loop, but in general SystemTask should be called at least once every 16 clock ticks (a tick is defined as a 60th of a second). If the application is doing a lot of work on each pass of the event loop, then the SystemTask call should be made more often.
PROCEDURE SimpleEventLoop ( Var Event: EventRecord ); Var UserAction : Boolean; {Has the user done something??} Finished : Boolean; {Exit When user Quits} Begin Repeat SystemTask; {To support periodic events} UserAction := GetNextEvent ( AllEvents, Event); {To invoke SystemEvent} If UserAction then {Handle the event...} Case Event.what Of mouseDown : DoMouseDown (Event, Finished ); KeyDown : DoKeyDown (Event, Finished ); ActivateEvt : DoActivate (Event, Finished ); UpDateEvt : DoUpdate (Event, Finished ); End; {case} Until Finished; {terminate the program?} End; {SimpleEventLoop}
The application calls GetNextEvent each time through the event loop in order to find out what events have taken place since the previous pass. GetNextEvent calls the SystemEvent routine, which simply intercepts the stream of events, and if an event belongs to the DA, that event is shuttled to the DA rather than to the application.
Suppose the user selects the DA menu and presses the mouse button; this will cause a mousedown event (mouseDown) to be generated by calling the DoMouseDown routine. The application programmer must write the DoMouseDown routine in such a way as to call the appropriate DA. The code necessary to do this is shown in Example 2, below.
PROCEDURE DoMouseDown ( Var Event : EventRecord; Var Finished: Boolean ); Var whichWindow : WindowPtr;{Window that mouse was pressed in} whereIs : INTEGER; {Part of screen where mouse was pressed} Begin {DoMouseDown} {Where on the screen was mouse pressed?} whereIs := Findwindow ( Event.where, whichWindow); Case whereIs Of InDesk: {In Empty Space...} {Do nothing}; InMenuBar: {Menu Selection...} DoMenuClick; InSysWindow: {Aha! In a DA...} SystemClick ( Event, whichWindow); InContent: {In Application's window...} DoContent (whichWindow); InDrag: {Drag Application's window...} DoDrag (whichWindow); InGrow: {Resize Application's window...} DoGrow (whichWindow); InGoAway: {Close Application's window...} DoGoAway (whichWindow) End--{case} End; {DoMouseDown}
The events that are diverted from the application to the DA are channeled into the DA processing code in two ways, as shown in the DoMouseDown procedure. The first way is through the System Click Toolbox routine, as shown in case InSysWindow of DoMouseDown, and the second way is through a menu selection.
When a mouse-down event occurs in a system window, the application code should call SystemClick. If the mouse-down event is in a DA window, Systemclick takes care of processing the event instead of the application. This case will be discussed later as it is what happens when the DA is already on the screen.
The mouse-down event could also occur in the DA menu (under the apple), which would mean that the DA is to be activated (this is called opening the DA). This is the case we are most interested in for the time being. If the user has selected the MacMan DA, for instance, then the application program must handle the opening of the DA from the DoMenuClick routine, shown in Example 3, page 30.
PROCEDURE DoMenuClick; { Handle mouse-down event in menu bar. } Var menuChoice : LONGINT; {Menu ID and item number} theMenu : INTEGER; {Menu ID of selected menu} theItem : INTEGER; {Item number of selected item} Begin {DoMenuClick} menuChoice := MenuSelect (TheEvent.where); if menuChoice <> 0 {Application, or DA?} Then begin {Application...} theMenu := HiWord (menuChoice);{Get menu ID} theItem := LoWord (menuChoice);{Get item number} Case theMenu of AppleID: {Make selection from Apple menu} DoAppleChoice (GetMenu ( AppleID ), theItem); FileID: {Make selection from File menu} DoFileChoice (GetMenu ( FileID ), theItem); EditID: {Make selection from Edit menu} DoEditChoice (GetMenu ( EditID ), theItem) End; {case} End; {if} End; {DoMenuClick}
As shown in DoMenuClick, when an application calls the MenuSelect (or MenuKey) Toolbox routine, a call is made to SystemMenu, which passes the event to the DA (if the event is a mouse-down in the DA menu). The DA must then handle the event and return a zero to the application. Otherwise, MenuSelect returns a long integer containing the menu number in its HiWord and the item number in its LoWord. In this case, when the user selects the Apple menu, and within this menu, the MacMan DA, the DoAppleChoice routine (see Example 4, page 30) is called to activate the DA.
PROCEDURE DoAppleChoice (Var AppleMenu: MenuHandle; theItem : INTEGER); Var accName : Str255; {Name of desk accessory} accNumber : INTEGER {Reference number of desk accessory} Begin {DoAppleChoice} Case theItem of AboutItem: {Application's About... Item} DoAbout; otherwise {Must be a DA...} Begin GetItem {AppleMenu, theItem, accName) {Get accessory name} accNumber := OpenDeskAcc (accName) {Open desk accessory} End {otherwise} End {case} End; {DoAppleChoice}
This sequence of actions opens the DA and prepares it for use alongside the currently running application. In summary, the sequence is:
A DA is a "mini-application" that can be run concurrently with a Macintosh application. A DA cannot exceed 32K of executable machine code and data and is installed in the start-up disk system file using a Macintosh utility program called the Font/DA Mover. Once a DA is installed, it no longer has a file or an icon visible from the desktop. Instead, the user opens a DA by selecting it from the standard Apple menu, which by convention is the first in the menu bar.
After a DA has been opened, its window, if any, is displayed on the desktop and it becomes the active window. To close a DA, the user can click the DA's close box (in its own title bar), or another program can call the function CloseDeskAcc to close it. The DA will then disappear and the frontmost window will become the active window.
A desk accessory may have a menu of its own, which will be added to the menu bar when it is active and deleted when it is not. The Cut, Copy, and Paste commands in a standard Edit menu can be used by an active DA. They are very useful for copying and pasting between the DA and the application or another DA.
Writing a DA is a lot more difficult than writing a "plain vanilla" application because a DA has no main procedure, no main event loop to obtain events, and no global variables.
Technically, a DA is known as a Macintosh device driver, and each DA is required to have three special procedures: Open, Close, and Ctl (for control). These procedures are called directly by the operating system through a special table called the DA Header.
Each of these procedures requires two formal parameters of type Device Control Record and Parameter Block Record. A Device Control Record is created when a DA is opened and destroyed when it is closed. A Parameter Block Record is created by the operating system each time any of the three routines is called. It is used to inform the DA about the purpose of the call.
The Macintosh operating system calls Open whenever a DA is selected from the Apple menu and calls Close whenever the close box on the title bar of the DA's window is clicked or CloseDeskAcc is called by some other program. Between these two calls, the system will call Ctl.
When the Open procedure is called to open the DA, it will:
Close is called to close the DA. It first disposes of its window and stores nil in the DctlWindow field of the Device Control Entry Record, then it disposes of any global data it might have allocated in the dctlstorage field of the Device Control Entry Record.
Ctl is called to enable the DA to handle the action indicated by the csCode field of the Parameter Block Record. There are nine such actions, as shown in Table 1.
1. AccEvent An event (update, activate, keyboard...) 2. AccRun Do a periodic action 3. AccCursor Change cursor shape 4. AccMenu Menu selection 5. AccUndo The Undo editing command 6. AccCut The Cut editing command 7. AccCopy The Copy editing command 8. AccPaste The Paste editing command 9. AccClear The Clear editing command
An application must have the standard Edit menu if it wits to support passing text to and from DAs. The order of items in this menu is important, but the menu can be made longer by adding items at the end.
The standard Edit menu contains Undo, Cut, Copy, Paste, and Clear. When a user chooses one of these commands, the application must call Toolbox routine SystemEdit from within DoEditChoice (see Example 5, page 30). The menu items are numbered 0 through 5 internally, which is why we subtract 1 from the item number (theItem-1) in the routine shown in Example 5. If the active window is a system window (that is, a DA window), then SystemEdit will return false and the application will process the command as usual. Otherwise, SystemEdit will shuttle the event on to the DA for command processing and return true.
ProcDoEditChoice (......, theitem : Integer); { Handle choice from Edit Menu } Begin {DoEditChoice} if Not SystemEdit (theItem-1) Then Case theItem of cutitem : DoCut; copyitem : DoCopy; Pasteitem: DoPaste; end; {Case} End; {DoEditChoice}
The code for the DA is not a CODE resource, as it is for applications, but is a DRVR because a DA is actually a device driver. The Macintosh resource compiler RMaker can be used to create a DRVR resource by reading the CODE resource created MAC DATA BASE by the linker with ID = 1 and converting it to a DRVR resource. This is done by including the following lines in the resource file prior to compiling it with RMaker:
Type DRVR = PROC Deskacc,16 DeskaccFile
The name DeskaccFile is the linker's output file for the DA file, and Deskacc will be used as the DA name to appear under the Apple menu once the DA is installed in the system file. The resource ID then becomes the DA's driver reference number and is used by the operating system to implement the DA and is also used for owned resources.
A range of 32 resource IDs has been reserved for each DA DRVR resource ID, so they are called owned resources. A special numbering convention is used to associate owned system resources with the resources they belong to. For any particular DA, this range is computed by adding $C000 and 32 times the driver reference number--for example, if the driver reference number is 16, then the range is -15,872 through -15,857.
When the DA is moved from its own file or a system file into a system file, all its resources for windows, menus, and so on must be transferred along with the code for the DA into the destination system file. If the destination system file already has a DA with the same DRVR resource ID, the Font/DA Mover will renumber it and all of its owned resources. Part of the DAMacMan resource file is shown in Listing One, beginning on page 48.
In summary, a DA program consists of at least three special procedures called Open, Close, and Ctl. The DA program may have other procedures as well, but it has no main body. You might think of the DA program as a module consisting of its own constants,g types, variables (Listing Two, page 48), and procedures (Listing Three, page 50).
Open is called by OpenDeskAcc (from the running application); Close is called by Ctl (when the DA terminates itself) or ExitToShell (when the application terminates); and Ctl is called each time the application calls SystemEvent.
Listing Three shows these three procedures for DAMacMan, but keep in mind that these procedures must always exist for every DA even if they are tailored for some other purpose. In addition, because DAs are limited to 32K in size, the sophistication of a DA is restricted to miniature utility functions such as displaying the keyboard and so on. Implementing the MacMan database retrieval code was quite a challenge because of this limitation.
When DAMacMan is opened from the Apple menu, it looks in the system disk to see if the files it requires are present. If a file named Manual and another file named MMIndex are not present, DAMacMan will display an error dialog.
DAMacMan's related files are Manual, text from Inside Macintosh (the database); MMIndex, the index into the database; MMSize.int, a temporary file used to generate a version of DAMacMan; MMConfig, a DAMacMan software tool for generating versions and MMLock, which locks and unlocks files.
Manual, the database, consists of two parts: the MacMan distribution text and the MacMan information that contains all the procedures and functions defined in Inside Macintosh, organized as follows:
\name category# body
where name is the name of the procedure or function, category is the section of Inside Macintosh in which it is defined, and body is the information about the procedure or function.
The index file, MMIndex, contains records sorted with respect to name, each record having the following form:
Record name : String[25]; start : longint; length : Integer; man : Integer; end;
where name is the name of the procedure or function, start is the starting position relative to the beginning of the manual, length is the length of the text that belongs to this procedure or function, and man is an integer representing the section or manager of Inside Macintosh where this function or procedure is defined.
The MMSize.int file contains the statement:
Const MaxRec = ;
The blank will be filled in by the MacMan tool MMConfig, prior to compiling MacMan. The value of MaxRec is equal to the number of entries in Manual. The DAMacman main program is shown in Example 6, page 41.
PROGRAM DAMacMan; {DAMacMan is an online inside macintosh, running as a desk accessory Pascal source: DAMacMan.pas Main Program Uses : MMSize.Int The Manual Size, Generated by MMConfig Tool DAMacMan.int The Interface include file DAOthers.imp Our own procedures and functions DAThree.mp The open, Ctl, Close procedures DAIndex Indes To Database Enntries Manual Database from Inside Macintosh Resources : DAMacMan.R Creation Date: July 1st, 1986 Author : Abdullah Al-Dhelaan (TGL Software Development Group) Oregon State University } { The next four include files below are Interface to Toolbox....} {$I MemTypes.ipas } {$I QuickDraw.ipas } {$I OSIntf.ipas } {$I ToolIntf.ipas } {$I MMSize,Int } {The Manual Size, Generated by MMConfig Tool} {$I CAMacMan.int } {The Interface include file } {$I DAOthers.imp } {Our own procedures and functions} {$I DAThree.imp } {The open, Ctl, Close procedures} {-----------------------Main Program--------------------------} BEGIN {Desk Accessory, There should be no main program} END.
DAMacMan is configured and maintained through the use of a set of tools that must be applied each time the database is changed. MMConfig is a tool for constructing the index file for the database and the Pascal compiler include file that contains the size of the database. In addition, the integrity of the database is maintained by locking the database files using the MMLock program, described later.
MMConfig reads the file Manual and writes the ordered file MMIndex with records of the form:
Record name : String [251; start : Longint; length : Integer; man : Integer; end;
MMConfig performs the following steps:
MMConfig is run to create MMIndex and MMSize.int after Manual has been edited the first time and whenever Manual is updated.
Finally, MMLock is a MacMan tool whose job is to lock and unlock the files that are generated by MMConfig.
As mentioned, after Manual has been constructed by entering all desired text into the database, MMConfig is run to generate the files MMIndex and MMSize.int. Then DAMacMan can be compiled and run. When DAMacMan is run, it loads the file MMIndex into a list of
type table: table : array [1. .MaxRec] of ptr1;
where ptr1 is a pointer to a record similar to those stored in MMIndex and MaxRec is the number of functions or procedures in Manual. MaxRec is set by including the file MMSize .int.
DAMacMan is compiled into the resource file MacManFile. The Font/ DA Mover utility tool is used to copy this file into a system file. After the DA has been installed in the system file of the start-up volume, it can be selected from the Apple menu.
Apple Computer Inc. Inside Macintosh. 4 vols. Reading, Mass.: Addison-Wesley, 1985-1986.
Chernicoff, Stephen. Macintosh Revealed, Volumes I and II. Hasbrouck Heights, NJ.: Hayden/Apple Press, 1985.
Reingold, E.; and Wilfred, H. Data Structures. Boston: Little, Brown, 1983.
Takatsuka, J.; Huxham, F; and Burnard, D. Using the Macintosh Toolbox with C. Berkley, Calif: Syvex, 1986
TML Systems. MacLanguage Series Pascal User's Guide and Reference Manual, Jacksonville, Fla. TML Systems, 1985
Wirth, Niklaus, Algorithms + Data Structures = Programs. Englewood Cliffs, N.J.: Prentice-Hall, 1976
Wootton, Alan. "Resource Utility DA with TML." MacTutor (November 1985).
[LISTING ONE]
* DAMacMan.r Resource
* July 3, 1986 Last modified
*
* Resource file for "DAMacMan.pas" for use with MacLanguage
* series Pascal Compiler (TML Pascal)
*
*
* all resources must be between -15872 and -15841 inclusive
* if they are to travel with DRVR number 16
MacManFile
DFILDMOV
TYPE DRVR = PROC
MacMan,16
DAMacMan
* this DLOG is the main window.
* the StatText items are used only for their rectangles.
Type WIND
,-15872
Untitled
50 40 300 510
InVisible GoAway
0
0
* menu used by the DA
type MENU
,-15872
Macman ;; menu title
about Macman
(-
Find By Name
View By Category
* This second dialog is for about menu item
* the button and icon do nothing. Just decoration
Type ALRT
,-15872
50 50 330 430
-15872
4444
,-15871
50 50 300 480
-15871
4444
,-15870
60 80 126 430
-15870
4444
--------------------------------------------------------------------------
[LISTING TWO]
PROGRAM DAMacMan;
{ DAMacMan is an online inside macintoch, running as a desk accessory
Pascal source: DAMacMan.pas Main Program
Uses :
MMSize.Int The Manual Size, Generated by MMConfig Tool
DAMacMan.int The Interface include file
DAOthers.imp Our own procedures and functions
DAThree.imp The open, Ctl, Close procedures
DAIndex Index To Database Entries
Manual Database from Inside Macintosh
Resources : DAMacMan.R
Creation Date: July 1St, 1986
Author : Abdullah Al-Dhelaan
(TGL Software Development Group)
Oregon State University
}
{ The next four include files below are Interface to Toolbox ...}
{$I MemTypes.ipas }
{$I QuickDraw.ipas }
{$I OSIntf.ipas }
{$I ToolIntf.ipas }
{$I MMSize.Int } { The Manual Size, Generated by MMConfig Tool }
{$I DAMacMan.int } { The Interface include file }
{$I DAOthers.imp } { Our own procedures and functions }
{$I DAThree.imp } { The open, Ctl, Close procedures }
{------------------------------Main Program----------------------------}
BEGIN
{ Desk Accessory, There should be no main program }
END.
The DAMacMan.int file in shown below :
{
DAMacMan.int Interface
July 3, 1986 Last modified
An interface file that Contains all the needed types and vars
}
Const
accEvent = 64;
accRun = 65;
accCursor = 66;
accMenu = 67;
accUndo = 68;
accCut = 70;
accCopy = 71;
accPaste = 72;
accClear = 73;
ManFile = 'Manual'; {Name of Database File}
Vnum = 0; {default drive}
Type
Str25 = String [25];
Lptr = ^LongInt;
Item = Record { An entity record}
name : Str25; { Proc/Func. Name }
start : LongInt; { Starting pos. on the Manual }
length : Integer; { Length of Proc./Func. Text }
man : Integer; { Category # }
END;
ptr1 = ^ Item;
myarray = ARRAY [1..MaxRec] of Ptr1; { The main array }
{This is the data. A handle to it will be stored in the dctl storage field
of the DCltEntry Record }
GlobalsH = ^GlobalsP;
GlobalsP = ^GlobalsRec;
GlobalsRec = Record { DAMacMan Database Info }
hScroll : ControlHandle;{Horizontal scroll for window.}
vScroll : ControlHandle;{Vertical scroll for window}
pRect : Rect; {Rectangle within window to see}
tRect : Rect;
hTE : TEHandle; {Text is here...}
table : myarray; {Index to entries}
noIndex : boolean; {Error if no Index on Disk}
noman : boolean; {Error if no Database on Disk}
END;
{ This is used to store system info about the state of the driver. It will
be passed to us on all calls from system. This Record is definded in the
interface (TML files) above (as DCtlEntry) . it is not strictly necessary
to redefine it here. But doing so, will enable me to use dctlStorage^^ to
refer to GlobalsRec without coercing Types }
MyDeviceEntry = Record
DctlDriver : HAndle; { Pointer to driver }
DctlFlags : Integer; { Flags }
DctlQueue : Integer; { Low-order byte, drivers version
number }
DctlQhead : Lptr; { Pointer to first entry in
drivers I/O queue }
DctlQTail : Lptr; { pointer to last entry in
drivers I/O queue }
DctlPosition : LongInt; { Byte position }
DctlStorage : GlobalsH; { Handle to RAM driver's private
storage }
DctlRefNum : Integer; { Driver's reference number }
DctlCurTicks : LongInt; { Used internally by Device
Manager }
DctlWindow : Grafptr; { Pointer to driver's window
Record }
DctlDelay : Integer; { number of ticks between
periodic actions }
DctlEmask : Integer; { Desk accessory event mask }
DctlMenu : Integer; { Menu ID of menu associated with
driver }
END;
{ No VARiables for main program are allowed }
The file DAThree.imp is shown below :
{
DAThree.imp Implementation
July 3, 1986 Last modified
[LISTING THREE]
THE FOLLOWING PROCEDURES SHOULD BE IN EVERY DESK ACCESSORY
AND THEY ARE CALLED BY THE SYSTEM
}
PROCEDURE open ( VAR Device : MyDeviceEntry;
VAR block : ParamblockRec);
{ Open Makes a window and sets-up our private storage.
we may get an open call even after we are already open }
CONST
InfoLength = 700; {The number of chars. fro the distribution text}
VAR
Wpk : WindowPeek;
Dtyp : Integer;
ID : Integer;
Dhan : Handle;
tmpPtr : ptr;
dummy : GlobalsRec;
Watch : CursHandle; {Handle to wristwatch cursor}
BEGIN
{Use ID for all Resource access}
ID := $C000 - 32 * (1 + Device.dctlRefNum);
Device.dctlMenu := ID;
With Device do
if DctlWindow = nil
THEN BEGIN
{ Create a hole in the heap. It is good practice to keep
Window records off of the bottom of the Application Heap. }
DctlStorage := pointer(NewHandle(SizeOf(dummy)));
TmpPtr := NewPtr($1000);
Hlock(Handle(DctlStorage));
With DctlStorage^^ do
BEGIN {initialize our storage }
noindex := false; {Index found}
noman := false; {Manual found}
Watch := GetCursor (WatchCursor);
SetCursor (Watch^^); {Indicate delay }
CreateWindow (Device,ID);
{ post information }
DoOpen (Device,'MacMan Distribution',0,InfoLength);
If not noman
Then LoadData(device); {Load the array}
initcursor;
END; { of with storage }
{Deallocate our temporary pointer }
Hunlock(Handle(DctlStorage));
DisposPtr(TmpPtr);
END; { of if }
END; { of open }
{---------------------------------------------------------------------}
PROCEDURE close ( VAR Device : MyDeviceEntry;
VAR block : paramBlockRec);
BEGIN
deactivate(Device); { remove menu }
with Device do
BEGIN
disposHandle(Handle(DctlStorage)); { kill data }
disposeWindow(DctlWindow); { erase window }
DctlWindow := nil;
END; {of with }
END; { of close }
{----------------------------------------------------------------------}
PROCEDURE ctl ( VAR Device : MyDeviceEntry;
VAR block : ParamBlockRec) ;
{ Here is the main entry point for system calls. The permanent bolck tell us
what the nature of the call is. }
VAR
mousept : point;
wpnt : Grafptr;
item : Integer;
ibeam : cursHandle;
ignore : Integer;
longignore : LongInt;
BEGIN
setport(Device.DctlWindow);
Hlock(Handle(Device.DctlStorage));
with Device, DctlStorage^^,block do
BEGIN
TEidle(hTE);
CASE csCode of
accevent : Event(Device, block);
accCursor :
BEGIN
ibeam := GetCursor(ibeamcursor);
GetMouse(mousePt);
If (PtInRect(mousePt,pRect))
THEN SetCursor(iBeam^^)
ELSE InitCursor;
END;
accmenu : { CASE out menu item number }
BEGIN
Initcursor;
CASE csParam[1] of
1 : Doabout (Device.dctlmenu); {about... }
3 : IF (not noindex) THEN DoFind (Device,'');
4 : IF (not noindex) THEN DoView (Device) ;
END; { of CASE menu }
HiliteMenu(0);
END; { of menu CASE }
accCopy :
BEGIN
longignore := ZeroScrap; {Init. Scrap}
TECopy(hTE); {Copy text from hte to TextEdit scrap}
ignore := TEToScrap; {Copy TextEdit scrap to desk scrap }
ignore := UnloadScrap; {Copy desk scrap to file scrap}
END;
Otherwise ;
END; { CASE of ... }
END; { of with block }
Hunlock(Handle(Device.DctlStorage));
END; { of control PROCEDURE }