Inside

Macintosh,"

Promotional Edition

A Letter from the Macintosh Developers Group
Dear Reader:

15 March 1985

After many months of work the Macintosh Division's User Education Group (responsible for all the Macintosh documentation) has completed the manuscript for Inside Macintosh. We've finalized production arrangements with a major publisher and you can expect to see the final edition at better bookstores everywhere by late summer '85. However, we can't wait that long and don't expect you to either. We've therefore produced this special Promotional Edition to handle the demand for Inside Macintosh until the final edition becomes available. The contents of this edition are still preliminary and subject to change; the final edition will include many updates and corrections. The production quality of the final edition will be significantly improved from this inexpensive edition. Now, here are answers to some questions we anticipate:

Q. I purchased the three-ring binder version of Inside Macintosh from your mail-house for
$100 and also bought the Software Supplement for $100. Is this Promotional Edition the final copy I'm supposed to receive for purchasing the Software Supplement?

A. No. As promised, Supplement owners will receive a copy of the final version when it's available.
Q. How can I get Macintosh developer utilities, example programs, example source code, the libraries I need to do Lisa Pascal/Macintosh cross-development work, and additional copies of this manual?
A.The Software Supplement consists of: 1) useful Macintosh utilities, example programs, and example source code, 2) the interface files, equate files, and trap definitions in both Macintosh and Lisa readable format, 3) all of the libraries required for Lisa Pascal/Macintosh cross-development, 4) a new Lisa Pascal Compiler, which supports SANE numerics, and 5) a copy of the final published edition of Inside Macintosh (this will be sent to you when available). The price for the Software Supplement is $100. As of April '85 the Software Supplement has been frozen to correspond to Inside Macintosh and automatic updates will no longer be included in the Software Supplement price. We will, however, inform Supplement owners of other products and utilities as they become available. You may also order additional copies of this special Promotional Edition of Inside Macintosh for $25 per copy. You can order the Software Supplement and/or copies of this Promotional Edition of Inside Macintosh by writing to (California residents please add 6.5% sales tax) : Apple Computer, Inc. 467 Saratoga Avenue Suite 621 San Jose, CA 95129 (408) 988-6009

Q. Is there a good way to keep up-to-date with new utilities and technical notes and at the same time stay in touch with other developers?
A. We've found that electronic distribution is a very cost-effective, timely way to keep the developer world
up-to-date. At least two major on-line services, Delphi and Compuserve, host the MicroNetworked Apple Users' Group (MAUG)--an electronic service open to all people who are interested in or have information to share about Apple products. MAUG is an independently run service and is not affiliated with Apple Computer, Inc. If you have a modem and communication software you can sign-on and download the latest developer utilities from the Macintosh Software Supplement, example programs, technical notes, and documentation. You can also carryon electronic conversations with hundreds of other Macintosh developers. For more information on these services please write to either: Delphi Compuserve 3 Blackstone Street 5000 Arlington Centre Boulevard Cambridge, MA 02139 Columbus, OH 43220 (617) 491-3393 (614) 457-8600 (800) 544-4005 (toll-free outside of Massachusetts) All of us in the Macintosh Division would like to thank you for your support of Macintosh development. We'll continue to provide the programs, tools, and documentation to assist your efforts. We'd love to hear from you on any topic related to Macintosh Development. Send your letters to Apple Computer, Macintosh Developers Group, Mail Stop 4T, 20525 Mariani Avenue, Cupertino CA 95014.

Limitation on Warranty and Liabilities Inside Macintosh is a working document used by Apple's own programmers and developers which describes the hardware and software associated with the Macintosh computer. This is a preliminary edition that is incomplete and may contain errors. Apple itself does not rely solely on this document, but rather subjects all of its products to extensive testing prior to introduction. Further, Apple is continuing to improve its products and the contents of this manual may ,be obsoleted as a result of changes to Apple products. Accordingly, Apple makes no warranty that this manual is accurate or complete and notifies all readers that the specifications of its products are subject to change without notice.
APPLE MAKES NO WARRANTY OR REPRESENT ATION, EITHER EXPRESS OR IMPLIED, WITH RESPECT TO THIS MANUAL, ITS ACCURACY, CONTENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. AS A RESULT, THIS MANUAL IS SOLD" AS IS" AND YOU, THE PURCHASER, ARE ASSUMING THE ENTIRE RISK AS TO THE USE OF AND RELIANCE ON THIS MANUAL. IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT, INDIRECT, SPECIAL, INCIDENT AL, OR CONSEQUENTIAL DAMAGES RESULTING FROM,ANY DEFECT OR OMISSION IN THIS MANUAL, even if advised of th,e possibility of possible damages resulting therefrom. No Apple dealer, agent, or employee is authorized to make any modification, extension, or addition to this warranty. Some states do not allow the exclusion or limitation of implied warranties or liability for incidental or consequential damages, so the above limitation may not apply to you. This warranty gives you specific legal rights, and you may also have other rights which vary from state to state.

This manual introduces you to the Macintosh technical documentation and the "inside" of Macintosh: the Operating System and other routines that your application program will call. It will help you figure out which software you need to learn more about and how to proceed with the rest of the documentation. It also presents a simple example program. Since the last draft, changes and additions have been made to the " overviews, a~ example program has been added, and the structure of a typical Inside Macintosh manual is discussed.

2

Inside Macintosh Road Map

TABLE OF CONTENTS 3 3 4 4 5 6 6 10 11 18 19 About This Manual About Inside" Macintosh Everything You Know Is Wrong Conventions The Structure of a Typical Manual Overview of the Software The Toolbox and Other High-Level Software The Operating System and Other Low-Level Software A Simple Example Program Where to Go From Here Appendix: Resource Compiler Input for Exa~ple Program Glossary

20

/

Copyright (c) 1984 Apple Computer, Inc.

All rights reserved.

ABOUT THIS MANUAL

3

ABOUT THIS "MANUAL This manual introduces you to the Macintosh technical documentation and the "inside" of Macintosh: the Operating System and User Interface Toolbox routines that your application program will call. It will help you figure out which software you need to learn more about and how to proceed with the rest of the documentation. To orient you to the software, it presents a simple example program. *** Eventually it will become the preface"and introductory chapter in the comprehensive Inside Macintosh manual. ***

ABOUT INSIDE MACINTOSH Inside Macintosh *** (currently a set of separate manuals) *** tells you what you need to know to write software for the Macintosh. Although directed mainly toward programmers writing standard Macintosh applications, it also contains the information necessary for writing simple utility .programs, desk accessories, device drivers, or any other Macintosh software. It includes: - the user interface guidelines for applications on the Macintosh - a complete description of the routines available for your program to call-(both those built into the Macintosh and others on disk), along with related concepts and background information - a description of the Macintosh hardware It does not include: - information about getting started as a developer (for that, see the Apple ~ Developer's Handbook, available from Apple Computer's Software Industry Relations) - any information that's specific to the development system being used, except where indicated *** (The manual Putting Together a Macintosh Application will not be part of the fina~ Inside Macintosh.) *** The routines you'll need to call are written in assembly language, but they're also accessible from high-level languages. The development system currently available from Apple supports Lisa Pascal and includes Pascal interfaces to all the routines (except for a few that are called only from assembly language). Inside Macintosh documents these Pascal interfaces; if you're using a development system that supports a different high-level language, its documentation should tell ,you how to apply the information 'presented "here to that system. Inside Macintosh is intended to serve the needs of both Pascal and assembly-language programmers. Every routine is shown in its Pascal form (if it has one), but assembly-language programmers are told how to 9/10/84 Rose /ROAD.MAP/ROAD.2

***

(forthcoming)

***

4

Inside Macintosh Road Map
r

translate this to assembly code. Info~mation of interest only to assembly-language programmers is isolated and labeled so that Pascal programmerS can conveniently skip it. Familiarity with Lisa Pascal is recommended for all readers, since it's used for most examples. Lisa Pascal is described in the Pascal Reference Manual for the Lisa. You should also be familiar with the basic information that's in Macintosh, the owner's guide, and have some experience usihg a standard Macintosh application (such as MacWrite). Everything You Know Is Wrong

On an innovative system like the Macintosh, programs don't look quite the way they do on other systems. For example, instead of carrying out a sequence of steps in a predetermined order, your program is driven primarily by user actions (such as clicking and typing) whose- order cannot be predicted. You'll probably find that many of your preconceptions about how to write application~ don't apply h~re. Because of this, and because of the sheer volume of information in Inside Macintosh, it's essential that you read the Road Map *** (the rest of this man~al) .~**. It will h~lp you get oriented and figure-out where to go next.
Conventions The following notations are used in Inside Macintosh to draw your attention to p~rticular items of information: (note) A note that may be interesting or useful (warning) A point you need to be cautious about

Assembly-language note: A note of interest to assembly-language programmers only *** (in final manual, may instead be a shaded note or warning) ***

[No trap macro] This notation is of interest only to assembly-language programmers *** (may be shaded in final manual) ***; it's explained along with other general information on using assembly language in the manual Programming Macintosh Applications in Assembly Language.

9/10/84 Rose

/ROAD.MAP/ROAD.2

ABOUT INSIDE MACINTOSH

5

The Structure of a TyRical Manual This section refers to "manuals" for the time being; when the individual manuals become chapters of Inside Macintosh, this will be changed to "chapters". *** Most manuals of Inside Macintosh have the same structure~ as described below. Reading through this now will s~ve you a lot of time. and effort later on. It contains important hints on how to find what you're looking for within this vast amount of technical documentation. Every manual begins with a very brief description of its subject and a list of what you should already know before reading that manual. Then . there's a section called, for example, "About the Window Manager", which gives you more information about the subject, telling you what you can do with it in general, elaborating on ~elated user interface guidelines, and introducing terminology that will be used in the manual. This is followed by a series of sections describing important related concepts and background information; unless they're noted to be for advanced programmers only, you'll have to read them in order to understand how to use the r'outines described la'ter. Before the routine descriptions themselves, there's a section called, for example, "Using the Window Manager". It introduces you to the routines, telling you how they fit into the general flow of an application program and, most important, giving you an idea of which ones you'll need to use. Often you'll need only a few routines out of many to do basic o~erations; by reading this section, you can save yourself the trouble of learning routines you'll never use. Then, for the details about the routines, read on to the next section. It gives the calling sequence for each routine and describes all the parameters, effects, side effects, and so on. Following the routine descriptions, there may be some sections that won't be of interest to all readers. Usually these contain information about advanced techniques, or behind-the-scenes details for the curious. For review and quick reference, each manual ends with a summary of the subject matter, including the entire Pascal interface and a subsection for assembly-language programmers. *** For now, this is f9llowed by a glossary of terms used in the manual. Eventually, all the individual glossaries will be combined into one. ***

***

9/10/84 Rose

/ROAD.MAP/ROAD.2

6

Inside Macintosh Road Map

OVERVIEW OF THE SOFTWARE
The routines available for use in Macintosh programs are divided according to function t into what are in most cases called "managers" of the application feature that they support. As shown in Figure 1 on the following page, most are part of either the Operating System or the User Interface Toolbox and are in the Macintosh ROM. The Operating System is at the lowest level; it does bas.ic tasks such as input and output t memory management t and interrupt handling. The User Interface Toolbox is a level above the Operating System; it helps, you implement the standard Macintosh user interface in your application. The Toolbox calls the Operating System to do low-level operations, and you'll also call the Operating System directly yourself. RAM-based software is available as well. In most cases this software performs specialized operations that aren't integral to the user interface but may be useful to some applications (such as printing and floating-point arithmetic). The Toolbox and Other High-Level Software The Macintosh User Interface Toolbox provides a simple means of constructing application programs that conform to the standard Macintosh user interface. By offering a common set of routines that every application calls to implement the user int~rfacet the Toolbox not, only ensures familiarity and consistency for the user but also helps reduce the application's code size and development time. At the same timet it allows a great deal of flexibility: an application can use its own code ins tead of a Toolbox call wherever app'ropriate t" and can define its own types of windows t menus t controls t and desk accessories. Figure 2 shows the various parts of the Toolbox in rough order of their relative level. There are many interconnections between these parts; the higher ones often call those at the lower levels. A brief description of each part is given below t to help you figure out which ones you'll need to learn more about. Details are given in the Inside Macintosh documentation on that part of the Toolbox. The basic Macintosh terms used below are explained in the Macintosh owner's guide.

To keep the data of an application separat,e' from its code, making· the data easier to modify and easier to share among applications, the Toolbox includes the Resource Manager. The Resource Manager lets you, for example, store menus separately from your code so that they can'be edited or translated without requiring recompilation of the code. It also allows you to get standard data, such as the I-beam pointer for inserting text, from a shared system file. When you call other parts of the Toolbox that need access to the data, they call the Resource Manager. Although most applications never need to call the Resource Manager directly, an understanding of the concepts' behind it is essential because they're basic to so many other Toolbox operations. Graphics are an important part of every Macintosh application. All graphic operations on the Macintosh are performed by QuickDraw. To draw something on the screen, you'll often call one of the other parts of the Toolbox, but it will in turn call QuickDraw. You'll also call QuickDraw directly, usually to draw inside a window, or just to set up constructs like rectangles that you'll need when making other Toolbox calls. QuickDraw's underlying concepts, like those of the Resource Manager, are important for you to understand. Graphics include text as well as pictures. To draw text, QuickDraw calls the Font Manager, which does the background work necessary to make a variety of character fonts available in various sizes and styles. Unless your,application includes a font menu, you need to know only a minimal amount about the Font Manager.
An application decides what to do from moment to moment by examining

input from the user in the form of mouse and keyboard actions. It learns of such actions by repeatedly calling the Toolbox Event Manager (which in turn calls another, lower-level Event Manager in the Operating System). The Toolbox Event Manager also reports occurrences within the application that may require a response, such as when a 9/10/84 Rose /ROAD.MAP/ROAD.2

OVERVIEW OF THE SOFTWARE
window that was overlapped becomes exposed and needs to be redrawn. All information preseqted by a standard Macintosh application appears in windows. To create windows. activate them. move them. resize them, or close them. you 'Ii call the Window Manager. It keeps track of overlapping windows. so you can manipulate windows without concern for how they overlap. For example. the Window Manager tells the Toolbox Event Manager when to oinform your application that a window ,has to be redrawn. Also, when the user presses the mouse button. you call the Window Manager to learn which part of which window it was pressed in. or whether it was pressed in the menu bar or a desk accessory. Any window may contain controls. such as buttons. check boxes. and scroll bars. You create and manipulate controls with the Control Manager. When you learn from the Window Manager that the user pressed the mouse button inside a window containing controls. you call the Control Manager to find out which control it was pressed in, if any.

9

A common place for the user to press the mouse button is, of course. in the menu bar. You set up menus in the menu bar by calling the Menu Manager. When the user gives a command. either from a menu with the mouse or from the keyboard with the Command key. you call the Menu Manager to f,ind out which command was given. To accept text typed by th~ user and allow the standard editing capabilities. including cutting and pasting text within a document via the Clipboard, your application can call TextEdit. TextEdit also handles basic formatting such as word wraparound and justification. You can use it just to display text if you like. When an application needs more informatoion from the user about a command, it presents a dialog box. In case of errors or potentially dangerous situations. it alerts the user with a box containing a message or with sound from the Macintosh's speaker (or both). To create and present dialogs and alerts. and find out the user's responses to them. you call the Dialog Manager. Every Macintosh application should support the use of desk accessories. The user opens desk accessories 'through the Apple menu. which you set up by calling the Menu Manager. When you learn that the user has pressed the mouse button in a desk accessory. you pass that information on to the accessory by calling the Desk Manager. The Desk Manager also includes routines that you must call to ensure that desk,accessories' work properly.

As mentioned above, you can use TextEdit to implement the standard text editing capability of cutting and pasting via the Clipboard in your application. To allow the use of the Clipboard for cutting and pasting text,or graphics between your application and another application or a desk accessory, you need to call the Scrap Manager.
Some generally useful operations such as fixed-point arithmetic, string manipulation. and logical operations on bits may be performed with the Toolbox Utilities. 9/10/84 Rose

/ROAD.MAP/ROAD.2

10

Inside Macintosh Road Map

The final part of the Toolbox, the Package Manager, lets you use RAMbased sofrware called-packages. The Standard File Package will be called by every application whose File menu includes the standard commands for saving and opening documents; it presents the standard user interface for specifying the document. Some of the Macintosh packages can be seen as extensions to the Toolbox Utilities: the Binary-Decimal Conversion Package converts integers to decimal strings and vice versa, and'the International Utilities Package gives you access to country-dependent information such as the formats for numbers, currency, dates, and times. The Operating System and Other Low-Level Software The Macintosh Operating System provides the low-level support that applications need in order to use the Macintosh hardware. As the Toolbox is your program's interface to the user, the Operating System is its interface to the Macintosh. ' The Memory Manager dynamically allocates and releases memory for use by applications and by the other parts of the Operating System. Most of the memory that you·r pT:ogram uses is in an area called .the heap;' tne code of the program itself occupies space in the heap. Memory space in the heap must be obtained from the Memory Manager. The Segment Loader is the part of the Operating System that loads program code into memory to be executed. Your program can be loaded all at once, or you can divide it up into dynamically loaded segments to economize on memory usage. The Segment Loader also serves as a bridge between the Finder and your application, letting you know whether the application has to open or print a document on the desktop when it starts up. Low-level, hardware-related events such as mouse-button presses and keystrokes are reported by the Operating System Event Manager. (The Toolbox Event Manager then passes them to the application, along with higher-levei, software-generated events added at the Toolbox level.) Your program will ordinarily deal only with the Toolbox Event Manager and rarely call the Operating System Event ~nager directly. File I/O is supported by the File Manager, and device I/O by the Device Manager. The task of making the various types of devices present the same interface to the application is performed by specialized device drivers. The Operating System includes three built-in drivers: - The Disk Driver controls data storage and retrieval on 3 1/2-inch diskS:-- The Spund Driver controls sound generation, including music composed of up to four simultaneous tones. - The Serial Driver reads and writes asynchronous data through the two serial ports, providing communication between applications and serial peripheral,devices such as a modem or printer. 9/10/84 Rose /ROAD.MAP/ROAD.2

OVERVIEW OF TIlE SOFTWARE

11

The above drivers are all in ROM; other drivers are RAM-based. There's a Serial Driver in RAM as well as the one in ROM, and there's a Printer Driver in aAM that enables applications to print information on any variety of p'rinter via the same interface (called the Printing Manager). The AppleBus Manager is an interface to a pair of RAM drivers that enable programs to send and receive information via an AppleBus network. More RAM drivers can be added independently or built on the existing drivers. For example, the Printer Driver was built on the Serial Driver, and a music driver could be built on the Sound Driver. The Macintosh video circuitry generates a vertical retrace interrupt 60 times a second. An application can schedule routines to be executed at regular intervals based on this "heartbeat" of the system. The Vertical Retrace Manager handles the scheduling and execution of tasks during the vertical retrace interrupt.
'>

If a fatal error occurs while your application is running (for example, if it runs out of memory), the System Er.ror lfandler assumes control. The System Error Handler displays a box containing an error message and provides a mechanism for the user to start up the system again or resume execution of the application. The Operating System Utilities perform miscellaneous operations such as getting the date and time, finding out the user's preferred speaker volume and other preferences~ and doing simple string comparison. (More sophisticated string comparison routines are available in the International Utilities Package.) , Finally, there are three Macintosh packages that perform low-level operations: the Disk Initialization Package, which the Standard File Package calls to initialize and name disks; the Floating-Point Arithmetic Package; and the Transcendental Functions Package.

A SIMPLE EXAMPLE PROGRAM To illustrate various commonly used parts of the software, this section presents an extremely simple example of a Macintosh application program. Though too simple to be practical, this example shows the overall structure that every application program will have, and it does many of the basic things every application will do. By looking it over, you can become more familiar with the software and see how your own program code will be structured. The example program's source code is shown in Figure 4, which begins on page 15. A lot of comments are included so that you can see which part of the- Toolbox or Operating System is being called and what operation is being performed. These comments, and those that follow below, may contain terms that are unfamiliar to you, but for now just read along to get the ge~eral idea. All the terms are explained at length within Inside Macintosh. If yo~ want more information right away, you can look up the terms in the Glossary or the Index *** (currently the
9/ 10/84 Ros~

/ROAD.MAP/ROAD.3

12

Inside Macintosh Road Map

individual glossaries in the various manuals, and the manual Index to Technical Documentation) *** The application, called Samp, displays a single, fixed-size window in which the user can enter and edit text (see Figure 3). It has three menus: the standard Apple menu, from which desk accessories can be chosen; a File menu, containing only a Quit command; and an Edit menu, containing the standard editing commands Undo, Cut, Copy, Paste, and Clear. The Backspace key may be used tq delete, and Shift-clicking will extend or -shorten a selection. The user can move the document window around the desktop by dragging it by its title bar.

Cut

Copy
Paste Clear ,

Figure 3.

The Samp Application

The Undo command doesn't work in the application's document window, but it and all the other editing commands do work in any desk accessories that allow them (Note Pad, for example). Some standard features this simple example doesn't support are as follows: - Text cannot be cut (or copied) and pasted between the document and a desk accessory. - The pointer remains an arrow rather than changing to an 'I-beam within the document. - The standard keyboard equiva1ents--Command-Z, X, C, and V for Undo, Cut, Copy, and Paste--a-ren't in the Edit menu. They won't work in the document window (but they will work in desk accessories that allow those commands). Because the File menu contains only a Quit command, the document can't be saved or printed. Also, the application doesn't have an "About 9/10/84 Rose /ROAD.MAP/ROAD.3

A SIMPLE EXAMPLE PROGRAM

13

Samp" command as the first item in its Apple menu, nor does it present any dialog'Doxes or al~rts. All of the'se features and more are illustrated in programs in the Sample Macintosh Programs manual *** (forthcoming) ***. In addition to the code shown in Figure 4, the Samp application has a resource file that includes the data listed below. The program uses the numbers in the second column to identify the resources; for example, it makes a Menu Manager call td get menu number 128 from the resource file. Resource Menu Menu Menu Resource 'ID 128 129 130 Description Menu with the apple symbol as its title and no commands in it File menu with one command, Quit Edit menu with the commands Undo (dimmed), Cut, Copy, Paste, and Clear, in that order, with a dividing line between Undo and Cut Document window without a size box; top left corn~r of (50,40) on QuickDraw's coordinate 'plane, bottom right corner of (300,450); title "A Sample"; no close box

Window template

128

Each menu resource also contains a "menu iD" that's used to identify the menu when the user chooses a command from it; for all three menus, this ID is the same as the resource ID. (note) To create a resource file with the above contents, you can use the Resource Editor *** (for now, the Resource Compiler) *** or any similar program that may be available on the development system you're using; for more information, see the documentation for that program. *** The Resource Compiler is documented in Putting Together ~ Macintosh application. The Resource Compiler input file for the Samp application is shown in the appendix of this manual. All these ftles will eventually be provided to'developers by Macintosh Technical Support.

***
The program-starts with a USES clause that specifies all the necessary Pascal interface files. (The names shown are for the Lisa Workshop development system, and may be different for other systems.) This is followed by declarations of some useful constants, to make the source code more readable. Then there are a number of variable declarations, some having simple Pascal data types and others with data types defined in the Pascal interface files '(like Rect and WindowPtr). Variables used in the program that aren't declared here are global variables defined in the interface to QuickDraw. The variable declarations are followed by two procedure declarations: _SetUpMenus and DoCommand. You can understand them better after looking 9/10/84 Rose /ROAD.MAP/ROAD.3

14

Inside Macintosh Road Map

at the main program and seeing where they're called. The program begins with a standard initialization sequence. Every application will need to do this same initialization (in the order shown), or something close to it. Additional initialization needed by the program follows. This includes setting up the menus and the menu bar (by calling SetUpMenus) and ~reating the application's document window (reading its description from the resource file and displaying it on the screen). The heart of every application program is .its maIn event loop, which repeatedly calls the Toolbox Event Manager to get events and then responds to them as appropriate. The most common event is a press of the mouse button; depending on where it was pressed, as reported by the Window Manager, the sample program may execute a command, move the document window, make the window active, or pass the event on to a desk accessory. The DoCommand procedure takes care of executing a command; it looks at information received by the Menu Manager to determine which command to execute. Besides events reSUlting dire~tly from'user actions such as pressing the mouse button or a key on the keyboard, events are detected by the Window Manager as a side effect of those actions. For example, when a window changes from active to inactive or vice versa, the Window Manager tells the Toolbox Event Manager to report it to the application program. A similar process happens when all or part of a window needs to be updated (redrawn). The internal mechanism in each case is invisible to the program, which simply responds to the event when notified. The main event loop terminates when the user takes some action to leave the program--in this case, when the Quit command is chosen. That ,Is it! Of course, the program structure and level of detail will get more complicated as the application becomes more complex, and every actual application will be more complex than this one. But each will be based on the structure illustrated here.

9/10/84 Rose

/ROAD.MAP/ROAD.3

A SIMPLE EXAMPLE PROGRAM

15

PROGrulK SCIl'lp; { SaMP -- A snaIl sanple application written in Pascal by Macintosh User Education} { I t displays a single, f~xed-size window in which the user can enter and edi t text. } USES

{case on nenu ID in high-order word} call Menu Manager to get desk accessory } nane, and call Desk Manager to open } accessory (OpenDeskRcc;: result not used)} call OuickDraw to restore application } 'window as grafPort to draw in (nay have } been changed during OpenDeskRcc)}

This section refers to "manuals" for t-he time being; when the individual manuals b'ecome chapters of Inside M~iclntosh, this will be changed to "chapters". It also refers to the "order" of the manuals; this means the order of the documentation when it's combined into a single manual. For a list of what's been distributed so far and how it will be ordered, see the cover page of this manual. Anything not listed there'hasn't been distributed yet by Macintosh User Education, but programmer's notes or other preliminary documentation may be available. *** This section contains important directions for every reader of Inside Macintosh. It will help you figure out which manuals to read next. The Inside Macintosh documentation is ordered in such a way that you can follow it if you read through it sequentially. Forward references are given wherever necessary to any additional information that you'll need in order to understand what's being discussed. Special-purpose Information that can possibly be skipped is indicated as such. Most likely you won't need to read everything in each manual and can even skip entire manuals. You should begin by reading the following:
1.

***

Macintosh User Interface Guidelines. All Macintosh applications should follow these guidelines to ensure that the end user is presented w~th a consistent, familiar interface. Macintosh Memory Management:

2.

An Introduction.

3.

Programming Macintosh Applications in Assembly Language, if you're using assembly language. Depending on the debugging tools available on the development system you're using, it may also be helpful or necessary for Pascal programmers to read this manual. You'll also have to read it if you're creating your own development system and want to know how to write interfaces to the routines. The documentation of the parts of the Toolbox that deal with the fundamental aspects of the user interface: the Resource Manager, QuickDraw, the Toolbox Event Manager, the Window Manager, and the Menu Manager.

4.

Read the other manuals if you're interested in what they discuss, which you should be able to tell from the overviews in this "road map" and from the introductions to the manuals themselves. Each manual's introduction will also tell you what you should already know before reading that manual. When you're ready to try something out, refer to the appropriate documentation for the development system you'll be using. *** (Lisa Workshop users, see Putting Together ~ Macintosh Application.) *** 9/10/84 Rose /ROAD.MAP/ROAD.3

APPENDIX:

RESOURCE COMPILER INPUT FOR EXAMPLE PROGRAM

19

APPENDIX:

RESOURCE COMPILER INPUT FOR EXAMPLE PROGRAM

For Lisa Workshop users, this appendix shows the Resource Compiler input file used with the example program presented earlier. For more information on the format of the file, see Putting Together ~ Macintosh Application. (note) This entire appendix is temporary; it will not be part of the final Inside Macintosh manual, because all the information in that manual will be independent of the development system being used. Authors of the documentation for a particular development system may choose to show how the resource file for Samp would be created on that system~

GLOSSARY AppleBus Manager: An interface to a pair of RAM drivers that enable programs to send and receive information via an AppleBus network. Binary-Decimal Conversion Package: A Macintosh package for converting integers to decimal strings and vice versa. Control Manager: The part of the Toolbox that provides routines for creating and manipulating controls (such as buttons, check boxes, and scroll bars). Desk Manager: The part of the Toolbox that supports the use of desk accessories from an application. device driver: A piece of software that controls a peripheral device and makes it present a standard interface to the application. Device Manager: I/O. The part of the Operating System that supports device

Dialog Manager: The part of the Toolbox that provides routines for implementing dialogs and alerts. Disk Driver: The device driver that controls data storage and retrieval on 3 l/2-inch disks. Disk Inityalization Package: A Macintosh package for initializing and naming new disks; called by the Standard File Package. Event Manager: Manager. File Manager: See Toolbox Event Manager or Operating System Event The part of the Operating System that supports file I/O.

Font Manager: The part of the Toolbox that supports the use of various character fonts for QuickDraw when it draws text. heap: An area of memory. in which space can be allocated and released on demand, using the Memory Manager •.
In~ernational Utilities Package: A Macintosh package that gives you access to country-dependent information such as the formats for numbers, currency, dates, and times.

main event loop: In a standard Macintosh application program, a loop that repeatedly calls the Toolbox Event Manager to get events and then responds to them as appropriate. Memory Manager: The part of the Operating System that dynamically allocates and releases memory space in the heap.

9/10/84 Rose

IROAD.MAP/R9AD.G

GLOSSARY

21

Menu Manager: The part of the Toolbox that deals with setting up menus and lettiPg the user_choose from them. Operating System: The lowest-level software in the Macintosh. It does basic tasks such as I/O, memory management, and interrupt handling. Operating System Event Manager: The part of the Operating System that reports hardware-related events such as mouse-button presses and keystrokes. Operating System Utilities: Operating System routines that perform miscellaneous tasks such as getting the date and time, finding out the _ user's preferred speaker volume and other preferences, and doing simple string comparison. package: A set of routines and data types that's stored as a resource and brought into memory only when needed. Package Manager: The part of the Toolbox that lets you access Macintosh RAM-based packages. Printer Driver: The device driver for the currently installed printer.

Printing Manager: The routines and data types that enable applications to communicate with the Printer Driver to print on any variety of printer via the same interface. QuickDraw: The part of the Toolbox that performs all graphic operations on the Macintosh screen. resource: Data used by an application (such as menus, ,fonts, and icons), and also the application code itself. Resource Manager: resources. The part of the Toolbox that reads and writes

Scrap Manager: The part of the Toolbox that enables cutting and pasting between applications, desk accessories, or an application and a desk accessory. Segment Loader: The part of the Operating System that loads the code of/an application into memory, either as a single unit or divided into dynamically loaded segments. Serial Driver: The device driver that controls communication, via serial ports, between applications and serial peripheral devices. Sound Driver: application. The device driver that controls sound generation in an

Standard File Package: A Macintosh package for presenting the standard user interface when a file is to be saved or opened.

9/10/84 Rose

/ROAD.MAP/ROAD.G

22

Inside Macintosh Road Map

System Error Handler: The part of the Operating System that assumes control when a fatal error (such as running out of ~emory) occurs. TextEdit: The part of the Toolbox that support~ the basic text entry and editing capabilities of a standard Macintosh application. Toolbox: Same as User Interface Toolbox.

Toolbox Event Manager: The part of the Toolbox that allows your application program to monitor the us~r's ~ctions with the mouse, keyboard, and keyp~d. Toolbox Utilities: The part of the Toolbox that performs generally useful operations such as fixed-point arithmetic, string manipulation, and logical operations on bits. User Interface Toolbox: The software in the Macintosh ROM that helps you implement the standard Macintosh user interface in your application. vertical retrace interrupt: An interrupt generated 60 times a second by the Macintosh video circuitry while the beam of the display tube returns from the bottom of. the screen to the top. Vertical Retrace Manager: The part of the Operating System that , schedules and executes tasks during the vertical retrace interrupt.
\

~

Window Manager: The part of the Toolbox that provides routines for creating and manipulating windows.

The User Interface Guidelines describe the most basic common features of Macintosh applications. Unlike the rest of Inside Macintosh, t.hese guidelines describe these features as seen by the user~ Since the last draft, this manual has been reorganized and mostly rewritten. Some new recommendations have been added, and some previous recommendations have been clarified or amplified. '

ABOUT THI S MANUAL This manual describes the Macintosh user interface, for the benefit of people who want to develop Macintosh applications. *** Eventually it will become part of the comprehensive Inside Macintosh manual. *** More details about many of these features can be found in the "About" sections of the other chapters of Inside Macintosh. Unlike the rest of Inside Macintosh, this manual describes applications from the outside, not the inside. The terminology used is the terminology users are familiar with, which is not necessarily the same as that used elsewhere in Inside Macintosh. The Macintosh user interface consists of those features that are generally applicable to a variety of applications. Not all of the features are -found in every application. In fact, some features are hypothetical, and may not be found in any current applications. The best time to familiarize yourself with the user interface is before beginning to design an application. Good application design on the Macintosh hap'pens when a developer has absorbed the spirit as w~ll as the details of the user inte'rface. Before reading this manual, you should have read Inside Macintosh: A Road Map and have som~ experience using one or more applications, preferably one each ofa word processor, spreadsheet or data base, and graphics application. You should also have read Macintosh; the owner·s guide, or at least be familiar with the terminology used in that manual.
\,)

INTRODUCTION The Macintosh is designed to appeal to an audience of nonprogrammers, including people who have previously feared and distrusted computers. To achieve this goal, Macintosh applications should be easy to learn and to use. To help people feel more comfortable with the applications, the applic-ations should build on skills that people already have, not force them to learn new ones. The user should feel in control of the computer, not the other way around. This is achieved in applications that embody three qualities: ~esponsiveness, permissiveness, and consistency. Responsiveness means that the user's actions tend to have direct results. The user should be able to accomplish what needs to be done spontaneously and intuitively, rather than having to think: "Let's see; to do C, first I have to do A and B and then ••• ". For example, with pull-down menus, the user can choose the desired command directly and instantaneously. This is a typical Macintosh operation: The user moves the pointer to a location on the screen and presses the mouse button.

11/30/84 Averill
\

/INTF/INTRO

INTRODUCTION

5

Permissiveness means that the application tends to allow the user to do anything reasonable. The user, not the system, decides what to do next. Also, error messages tend to come up infrequently. If the user is constantly subjected to a barrage of error messages, something is wrong somewhere. The most important way in which an application is permissive is ,in avoiding modes., This idea is so important that it's 'dealt wi,th in a separate, section, "Avoiding Modes", below. The third and most important principle is consistency. Since Ma'cintosh users usually divide their time among several applications, they would be confused and irritated if they had to learn a completely new , interface for each application. The main purpose of this manual is to describe the shared interface ideas of Macintosh applications, so that developers of new applications can gain leverage from the time spent developing and testing existing applications. Fortunately, consistency is easier to achieve on the Macintosh than on many other computers. This is because many of the routines used to implement the user interface are supplied in the Macintosh Operating System and User Interface Toolbox. However, you should be aware that impiementing the use.r interface guidelines in their full glory often requires writing additional code that isn't supplied.
(

Of course, you shouldn't feel that· you're restricted to, using existing features. The Macintosh is a growing system, and new ideas are essential. But the bread-and-butter features, the kind that every application has, should certainly work the same way so that the user can move easily back and forth between applications. The best rule to follow is that if your application has a feature that's described in these guidelines, you should' implement the feature 'exactly as the guidelines describe it. It's better to do something completely different than to half-agre~ with the guidelines. Illustrations of most of the features described in this manual can be found in various already-released applications. However, there is probably no one application that illustrates' these guidelines in every particular. Although it's useful and important for you to get the feeling of the Macintosh user interface by looking at existing applications, the guidelines in this manual are the ultimate authority. Wherever an existing application disagrees with the guidelines, follow the guidelines. Avoiding Modes "But, gentlemen, you overdo the mode." -- John Dryden, The Assignation, or Love in Nunnery, 1672

~

11/30/84 Averill

/INTF/INTRO

6

User Interface Guidelines

A mode is a part of an application that the user has to formally enter and leave, and that restricts the operations that can be performed while it's in effect. Since people don't usually operate modally in real life, having to deal with modes in computer software reinforces the idea that computers are unnatural and unfriendly. Modes are most confusing when you're in the wrong one. Unfortunately, this is the most common case. Being in a mode is confusing because it makes future actions contingent upon past ones; it changes the behavior of familiar objects and commands; and it makes habitual actions .cause unexpected results. It's tempting to use modes in a Macintosh existing software leans on them heavily. temptation too frequently, however, users. with your application a chore rather than application" since most If you yield to the will consider spending time a satisfying experience.

This is not to say that modes are never used in Macintosh applications. Sometimes a mode is the best way out of a particular problem. Most of these modes fall into one of the following categories: - Long-term modes with. a procedural basis,. such as doing word processing as opposed to graphics editing. Each application program is a mode in this sense. - Short-term "spring-loaded" modes, in which the user is constantly doing something to perpetuate the mode. Holding down the mouse button or a key is the most common example of this kind of mode. - Alert modes; where the user must rectify an unusual situation before proceeding. These modes should be kept to a minimum. Other modes are acceptable if they meet one of the following requirements: - They emulate a familiar real-life model that is itself modal, like picking up different-sized paintbrushes in a graphics editor. MacPaint and other palette-based applications are examples of this use of modes. - They change only the attributes of something, and not its behavior, like the boldface and underline modes of text entry. - They block most other normal operations of the ~ystem to emphasize the modality, as in error conditions incurable through software ("There's no disk in the disk drive", for example). If an appl~cation uses modes, there must be a clear visual indication of the current mode, and the indication should be. near the object being most affected by the mode. It should also be very easy to get into or out of the mode (such as by clicking on a palette symbol).

11/30/84 Averill

/INTF/INTRO

TYPES OF APPLICATIONS

7

TYPES OF APPLICATIONS Everything on a Macintosh screen is displayed graphically; the Macintosh has no text mode. Nevertheless, it's useful to make a distinction among three types of 'objects that an application deals with: text, graphics, and arrays. Examples of each of these are shown in Figure 1.

The rest to some fei nt meani ng make pretence But Shedvell never deviates into sense. Some beams ,of 'w'it on other soul,- me", fall, Stri ke throuoh end make a 1ucid interval; But Shactw'ell"s genui ne n19ht admits no ray, His risl ng fogs prevail upon the de",.

Text

Advertising

132.9 121.3 18.7

Manufacturi flCJ R&D Intere,t Total

12.2
285.1

Figure 1.

Ways of Structuring Information

11/30/84 Averill

/INTF/APPS

8

User Interface Guidelines

Text can be arranged in a variety of ways on the screen. Some applications, ~uch as word processors, might consist of nothing but text, while others, such as graphics-oriented applications, use text almost incidentally. It's useful to consider all the text appearing together in a particular context as a block of text. The size of the block can range from a single field, as in a dialog box, to the whole document, as in a word processor. Regardless of its size or arrangement, the application sees each block as a one-dimensional string of characters. Text is edited the same way regardless of where it appears. Graphics are pictures, drawn either by the user or by the application. Graphics in a document tend to consist of discrete objects, which can be selected individually. Graphics are discussed further below, under "Using Graphics". Arrays are one- or two-dimensional arrangements of fields. If the array is one-dimensional, it's called a form; if it's two-dimensional it's called a table. Each field, in turn, contains a collection of information, usually text, but conceivably graphics. A table can be readily identified on the screen, since it consists of rows and columns of fields (ofteri·called cells), separated by. horizontal and vertical lines. . A form is sO'mething you fill out, like a credi i-card ' application. A form may not be as obvious to the user as a table, since the fields can be arranged in any appropriate way. Nevertheless, the application regards the fields as in a definite iinear order. Each of these three ways of presenting information retains its integrity, regardless of the context in which it appears. For example, a field in'an array can contain text. When the user is manipulating the field as a whole, the field is treated as part 'of the array. When the user wants to change the contents of the field, the contents are edited in the same way as any other text. Another case is text that appears in a graphics application. Depending on the circumstances, the text can be treated as text or as graphics. In MacDraw, for example, the way text is treated depends on which palette symbol is in effect. If the text symbol is in effect, text can be edited in the usual way, but cannot be moved around on the screen. If the selecting arrow is in effect, a block of text can be moved around, or even stretched or shrunk, but cannot be edited •

.USING GRAPHICS A key feature of the Macintosh is its high-resolution graphics screen. To use this screen to its best advantage, Macintosh applications use graphics copiously, even in places where other applications use text. As much as possible, all commands, features, and parameters of an application, and all the user's data, appear as graphic objects on the screen. Figure 2 shows some of the ways in which applications can use graphics to communicate with the user.

11/30/84 Averill

/INTF/GRAPHICS

USING GRAPHICS

9

'?

r-,

• . -~•

0 A
&
::·m

~ LJ D ~ ~ (!g] rum
.1.

" D

17

Palette, with paintbrush symbol selected

II 0 III 0
e:?

Icons
Figure 2.

a

III

Objects on the Screen

Objects, whenever applicable, resemble the familiar material objects ., they resemble. Objects that act like pushbuttons "light up" when pressed; the Trash icon looks like a trash can. Objects are designed to look good on the screen. Predefined graphics patterns can give objects a shape and texture beyond simple line graphics. Placing a drop-shadow slightly below and to the right of an object can give it a three-dimensional appearance. Generally, when the user clicks on an object, it's highlighted to distinguish it from its peers. The most common way to show this highlighting is by inverting. the object: reversing its black and white pixels.' In some situations, other forms of highlighting, such as the knobs used in MacDraw, may be more appropriate. The important thing is that there should always be some sort of feedback, so that the user knows that the click had an effect. One special aspect of the appearance of a document on the screen is visual fidelity. This principle is also known as "what you see is what 'you get". It primarily refers to printing: The version of a, document shown on the screen should be ~s close as possible to its printed version, taking into account inevitable differences due to different media.

11/30/84 Averill

/INTF/GRAPHICS

10

User Interface Guidelines

Icons A fundamental object in Macintosh software is the icon, a small graphic object that is usually symbolic of an operation or of a larger entity such as a document. Icons should be sprinkled liberally over the screen. Wherever an or label is needed, first consider using an icon instead of using text as the label or explanation. Icons not only contribute to the clarity and attractiveness of the system, they don't need to be translated into foreign languages.
e~planation

Palettes Some applications use palettes as a quick way for the user to change from one operation to another. A palette is a collection of small squares, each containing a symbol. A symbol can be an icon, a pattern, a character, or just a drawing, that stands for an operation. When the user clicks on one of the symbols, it's distinguished from the other 'Symbols, such as by highlighting, and-the previous symbol goes back to its normal state. Typically, the symbol that's selected dete'rmines what operations the user can perform.~ Selecting a palette symbol puts the user into a mode. This use of modes can be justified because changing from one mode to another is almost instantaneous, and the use can always see at a glance which mode is in effect. Like all modal features, palettes should be used only when they're the most natural way to structure an application. A palette can either be part of a window (as in MacDraw), or a s~parate window (as in MacPaint). ' Each system has its disadvantages. If the palette is part of the window, then parts of the palette might be c'oncealed if the user makes the window smalle'r. On the other hand t if it's not part 'of the window, then it takes up extra space on the desktop. If an application supports multiple documents open at the same time, it might be better to put a separate palette in each window, so that a different palette symbol can be in effect in each document.

COMPONENTS OF THE MACINTOSH SYSTEM This section explains the relationship among the principal large-scale components of the Macintosh system (from an external point of view). The main vehicle for ~he interaction of the user and the system is the application. Only one application is active at a time. When an application is active, ,it's in control of all communications between the user and the system. The application's menus are in the menu bar, and the application is in charge of all windows as well as the desktop.

11/30/84 Averill

/INTF/STRUC

COMPONENTS OF THE MACINTOSH SYSTEM

11

To the user, the main unit of information is the document. Each document is a unified collection of information--a single business letter or spreadsheet or chart. A complex application, such as a data base, might require several related documents. Some documents can be processed by more than one application, but each document has a principal application, which is usually the one that created it. The other applicat~ons that process the document are called secondary applications. The only way the user can actually see the document (except by printing it) is through a window. The application puts one or more windows on the screen; each window shows a view of a document or of auxiliary information used in processing the document. The part of the screen underlying all the windows is called the desktop. The user returns to the Finder to change applications. When the Finder is active, if the user double-clicks on either the application's icon or the icon of a document belonging to that application (or ,opens the document or application by choosing Open from the File menu), the application becomes active and displays the document window. Internally, applications and documents are both kept in files. However, the user never sees files as such, so they dofi't really enter into the user interface.

THE KEYBOARD
,I

The Macintosh keyboard is used primarily for entering text. Since commands are chosen from menus or by clicking somewhere on the screen, the keyboard is not needed for this function, although it can be used for alternative ways to enter commands. The keys on the keyboard are arranged in familiar typewriter fashion. The U.S. keyboard is shown in Figure 3.

Figure 3.

The Macintosh U.S. Keyboard

11/30/84 Averill

/INTF/KEY

12

User Interface Guidelines

There are two kinds of keys: character keys and modifier keys. A character key sends characters to the computer; a modifier key alters the meaning of a character key if it's held down while the character key is pressed.
-\

Character Keys Character keys include keys for letters, numbers, and symbols, as well as the space bar. ,If the user presses one of these keys while entering text, the corresponding character is added to the text. Other keys, such as the Enter, _Tab, Return, Backspace, and Clear keys, are also considered character keys. However, the result of pressing one of these keys depends on the application and the context. The Enter key tells the application that the user is through entering information in a particular area of the document, such as a field in an array. Most applications add information to a document as soon as the user types or draws it. However, the application may need to wait until a whole collection of information is available before processing it. In this cas~, the user presses the Enter key to signal that the information is complete. The Tab key is a signal to proceed: It signals movement tq the next item in a sequence. Tab often implies an Enter operation before the Tab motion is performed. The Return key is another signal to proceed, but it defines a different type of motion than Tab. A press of the Return key signals movement to the leftmost field one step ~own (just like a carriage return on a typewriter). Return can also imply an Enter operation before the Return operation. (note) Return and Enter also dismiss dialog and alert boxes (see "Dialogs and Alerts"). Backspace is used to delete text or graphics. The exact use of Backspace in text is described in the section on text editing. The Clear key on the keypad has the same effect as the Clear command in the Edit menu; that is, it removes the selection from the document without putting it on the Clipboard. This is also explained in the section on text editing. Because the keypad is optional equipment, no application should ever require use of the Clear key or any other key on the pad. Modifier Keys: Shift, Caps Lock, Option, and Command

There are six keys on the keyboard that change the interpretation of keystrokes: two labeled Shift, two labeled Option, one labeled Caps Lock, and one labeled with the "freeway interchange" symbol, which is usually called the Command key. These keys change the 11/30/84 Averill /INTF/KEY

THE KEYBOARD

13

interpretation of keys_trokes, and sometimes mouse actions. When one of these keys is held down, the effect of the other keys (or the mouse button) may change. The Shift and Option keys choose among the characters on each character key. Shift gives the upper character on two-character keys, or the uppercase letter on alphabetic keys. The Shift key is also used in conjunction with the mouse for extending a selection; see "Selecting". Option gives ~n alternate character set interpretation, including international characters, special symbols, and so on. Shift and Option can be used in combination. Caps Lock latches in the down position when pressed, and releases when pressed again. When down it gives the uppercase letter on alphabetic keys. The operation of Caps Lock on alphabetic keys is parallel to that of the Shift key, but the Caps Lock key has no effect whatsoever on any of the other keys. Caps Lock and Option can be used in combination on alphabetic keys. Pressing a character key while holding down the Command key usually tells the application to interpret the key as a command, not as a character (see "Commands"). Typeahead and Auto-Repeat If the user types when the Macintosh is unable to process the keystrokes immediately, or types more quickly than the Macintosh can handle, the extra keystrokes are queued, to be processed later. This queuing is called typeahead. There's a limit to the number of keystrokes that can be queued, but the limit is usually not a problem unless the user types while the application is performing a lengthy operation. When the user holds down a character key for a certain amount of time, it starts repeating automatically. The delays and the rates of repetition are global preferences that the user can set through the Control Panel desk accessory. An application can tell whether a series of n keystrokes wa.s generated by auto-repeat or by pressing the same key n times. It can choose to disregard keystrokes generated by auto-repeat; this is usually a good idea for menu commands chosen with the Command key. Holding down a modifier -key has the same effect as pressing it once. However, if the user holds down a modifier key and a charac ter key- at the same time, the effect is the same as if the user held down the modifier key while pressing the character key repeatedly. Auto-repeat does not function during typeahead; it operates only when the application is ready to accept keyboard input.

11/30/84 Averill

/INTF/KEY

14

User Interface Guidelines

Versions of the Keyboard \ There are two physical versions of the keyboard: U.s. and European. The European version has one more key than the U.s. version. The standard layout on the European version is designed to conform to the ISO (Internation Standards-Organization) standard; the U.S. key layout mimics that of common American office typewriters. European keyboards have different labels on the keys in different countries, but the overall layout is the same. The Numeric Keypad
An

optional numeric keypad can be hooked up between the main unit and the standard keyboard; see Figure 4.

Figure 4.

Numeric Keypad

The keypad contains 18 keys, some of which duplicate keys on the main keyboard, and some of which are unique to the keypad. The application-can tell whether the keystrokes have come from the main keyboard or the numeric keypad. The character keys on the keypad are labeled with the digits 0 through 9, a decimal point, the four standard arithmetic operators for addition, subtraction, multiplication, and division, and a comma. The keypad also contains the Enter and Clear keys; it has no modifier keys. The keys on the numeric keypad follow the same rules for typeahead and auto-repeat as the main keyboard. Four keys on the numeric keypad are labeled with "field-motion" symbols: small rectangles with arrows pointing in various directions. 11/30/84 Averill /INTF/KEY

THE KEYBOARD

15

Some applications may use these keys to select objects in the direction indicated by the key; the most likely use for this feature is in tables. When a key is used this way, the user must use the Shift key to obtain the four characters (+ * / ,) normally available on those keys. Since the numeric keypad is optional equipment, no application should require it or any keys available on it in order to perform standard functions. Specifically, since the Clear key is not available on the main keyboard, a Clear function may be implemented with this key only as the equivalent of the Clear command in the Edit menu.

THE MOUSE The mouse is a small device the size of a deck of playing cards, connected to the computer by a long, flexible cable. There's a button on the top of the mouse. The user holds the mouse and rolls it on a flat, smooth surface. A pointer on the ,screen follows the motion of the mouse. Simply moving the mouse results only in a correspo~ding movement of the pointer and no other action. Most actions take place when the user positions the "hot spot" of the pointer over an object on the screen and presses and releases the mouse button. The hot spot should be intuitive, like the point of an arrow or the center of a crossbar. Mouse Actions The three basic mouse actions are: - clicking: positioning the pointer with the mouse, and briefly pressing and releasing the mouse button without moving the mouse - pressing: positioning the pointer with the mouse, and holding down the mouse button without moving the mouse - dragging: positioning the pointer with the mouse, holding down the mouse button, moving the mouse to a new position, and releasing the button The system provides "mouse-ahead"; that is, any mouse actions the user performs when the application isn't ready to process them are saved in a buffer and can be processed at the application's convenience. Alternatively, the application can choose to ignore saved-up mouse actions, but should do so only to protect the user from possibly damaging consequences. Clicking something with the mouse performs an instantaneous action, such as selecting a location within the user's document or activating an object.

11/30/84 Averill

/INTF/MOUSE

16

User Interface Guidelines

For certain kinds of objects, pressing on the object has the same effect as clicking it repeatedly. For example, clicking a scroll arrow causes a document to scroll one line; pressing on a scroll arrow causes the document to scroll repeatedly until the mouse button is released or the end of the document is reached. Dragging can have different effects, depending on what's under the pointer when the mouse button is pressed. The uses of dragging include choosing a menu item, selecting a range of objects, moving an object from one place to another, and shrinking or expanding an object. Some objects, especially graphic objects, can be moved by dragging. In this case, the application attaches a dotted outline of the object to the pointer and redraws the outline continually as the user moves the pointer. When the user releases the mouse button, the application redraws the complete object at the new location.

An object being moved can be restricted to certain boundaries, such as the edges of a window frame. If the user moves the pointer outside of the boundaries, the 'application stops drawing the dotted outline of the object. If the user releases ~he mouse button while the pointer is outside of the boundaries, the object isn't moved. If, on the pther hand, the user moves the pointer back within the boundaries again before releasing the mouse bu~ton, the outline is drawn again.
In general, moving the mouse changes nothing except the location, and possibly the shape, of the pointer. Pressing the mouse button indicates the intention to do something, and releasing the button completes the action. Pressing by itself should have no effect except in well-defined areas, such.as scroll arrows, where it has the same effect as repeated clicking. Multiple-Clicking
A variant of clicking involves performing a second click shortly after

the end of an initial click. If the downstroke of the second click follows the upstroke of the first by a short amount of time (as set by the user in the Control Panel), and if the locations of the two clicks are reasonably close together, the two clicks constitute a double-click. Its most common use is as a faster or easier way to perform an action that can also be performed in another way. For example, clicking twice on an icon is a faster way 'to open it than choosing Open; clicking twice on a word to select it is faster than dragging through it. To allow the software to distinguish efficiently between single clicks and double-clicks on objects that respond to both, an operation invoked by double-clicking an object must be an enhancement, superset, or extension of the feature invoked by single-clicking that object. Triple-clicking is also possible; it should similarly represent an extension of a dQuble-click. _

11/30/84 Averill

/INTF/MOUSE

THE MOUSE

17

Changing Pointer Shapes The pointer may change shape to give feedback on the range of activities that make sense in a particular area of the screen, in a . current mode, or both. - The result of any mouse action depends on the item under the pointer when the mouse button is pressed. To emphasize the differences among mouse actions, the pointer may assume different appearances in different areas to indicate the actions possible in each area. - Where an application uses modes for different functions, the pointer .can be a different shape in each mode. For example, in MacPaint, the pointer shape always reflects the 'active palette symbol. Figure 5 shows some examples of pointers and their effect. An application can design additional pointers for other contexts.

Pointer

Used for Scroll ber and"other controls~ size box tit leber, menu ber, desktop} and so on

SELECTING The user selects an object to distinguish it from other objects, just be'fore performing an operation on it. Selecting the object of an operation before identifying the operation is a fundamental characteristic of the Macintosh system. Selecting an object has no effect on the contents of a document. Making a selection shouldn't commit the user to anything; the user is 11/30/84 Averill /INTF/SELECT

18

User Interface Guidelines

never penalized for making an fncorrect selection. The user fixes an incorrect selection by making the' correct selection. Although there is a variety of ways to select objects. they fall into easily recognizable groups. Users get used to doing specific things to seiect objects. and applications that use these methods are therefore easier to learn. Some of, these methods apply to every type of application. and some only to particular types of applications. This section discusses first the general methods, and then the specific methods that apply to text applications, graRhicsapplications, and arrays. Figure 6 shows a comparison of some of the general methods.

Selection by Clicking The most straightforward method of selecting an object is by clicking on it once. Most things that can be selected ,in Macintosh applications can be selected this way. Some applications support selection by double-clicking and tripleclicking. As always with multiple clicks, the second click extends the effect of the first click, and the third click extends the effect of the second click. In the case of selection, this means that the second click selects the same sort of thing as the first click, only more of them. The same holds true for the third click. For example, in text, the first click selects an insertion point, ' whereas the second click selects a whole word. The third click might select a whole block or paragraph of text. In graphics, the first click selects a single object, and double- and triple-clicks might select increasingly larger groups of objects.

11/30/84 Averill -

/INTF/SELECT

SELECTING

19

Range Selection The user selects a range of objects by dragging through them. Although the exact meaning of the selection depends on the type of application, the procedure i~ always the same: 1. The user positions the pointer at one corner of the range and presses the mouse button. This position is called the anchor point of the range. The user moves the pointer in any direction. As the pointer is moved" visual feedback keeps the user informed of the objects that would be selected if the mouse button were released. For text and arrays, the selected area is continually h~ghlighted. For graphics, a dotted rectangle expands or contracts to show the range that will be selected. When the feedback shows the desired range, the user releases themouse button. The point at which the button is released is called the endpoint of the range.

2.

3.

Extending a Selection A user can change the extent of an existing selection by holding down the Shift key and clicking the mouse button. 'Exactly what happens next depends on the context. In text or an array, the result of a Shift-click is always a range. The position where the button is clicked becomes the new endpoint or anchor point of the range; the selection can be extended in any direction. If the user clicks within the current range, the new range will be smaller than the old range. In graphics, a selection is extended by adding objects to it; the added objects do not have to be adjacent to the objects already selected. The user can add either an individual object or a range of objects to the selection by holding down the Shift key before making the" additional selection. If the user holds down the Shift key and selects one or more objects that are already highlighted, the objects are deselected. Extended selections can be made across the panes of a split window. (See "Splitting Windows".)

11/30/84 Averill

/INTF/SELECT

~

20

User Interface Guidelines

Making a Discontinuous Selection
I, In graphics applications, objects aren't usually considered to be in I any particular sequence. T~erefore, the user can use Shift-click to I extend a selection ~y a single object, even if that object is nowhere i near the current selection. When this happens, the objects between the current selection and the new object are not automatically included in t~e selection. This kind of selection is called a discontinuous selection. In the case of graphics, all selections are discontinuous selections.
1

This is not the case with arrays and text, however. In these two kinds \ of applications, an extended selection made by a Shift-click-'always includes everything betw~en the old selection and the new endpoint. To \ provide the possibility of a.discontinuous selection in these applications, Command-click is included in the user interface. To make a discontinuous selection in a text or array application, the user selects the first piece in the normal way, then holds doWn the Command key before selecting the remaining pieces. Each piece is sel~~ted in the ,same way as. if it were the whole selection, but be(::ause the Command key is held doWn, the new pieces are added to the existing selection instead of supplanting it. If one' of the pieces selected is already within an existing part of the selection, then instead of being added to the selection it's removed from the selection. Figure 7 shows a sequence in which several pieces are selected and deselected.

11/30/84 Averill

/INTF/SELECT

SELECTING

21

A
Cell s 82, 83" are selected

B

c

o

e2, and C3

1
2 3

..

S
A

B

C

o

The user hords down the Commend key end cl icks in

OS

1 2 3

..

S
A The user holds down the· Commend key end cl icts in
1

B

c

o

C3

2 3

..

S
Figure 7. Discontinuous Selection

Not all applications support discontinuous selections, and those that do might restrict the operations that a user can perform on them. For example, a word processor might allow the user to choose a font after making a discontinuous selection, but not to choose Cut or Paste. Selecting Text Text"is used in most applications; it's selected and edited in a consis'tent way, regardless of where it appears. A block of text is a string of characters. A text selection is a substring of this string, which can have any length from zero characters to the whole block. Each of the text selection methods selects a different kind of substring. Figure 8 shows different kinds of text selections.

Insertion Point The insertion point. is a zero-length text selection. The user establishes the location of the insert"ion point by clicking between two characters. The insertion PQint then appears at the nearest character boundary. If the user clicks to the right of the last character on a line. the insertion point appears immediately after the last character. The converse is true if the user clicks to the left of the first character in the line. The insertion point shows where text will be inserted when the user begins typing, or where the contents of. the Clipboard will be pasted. After each character is typed, the insertion point is relocated to the right of the insertion. If, between the mouse-down and the mouse-up, the user moves the pointer more than about half the width of a character, the selection is a range selection rather than an insertion point. Selecting Words The user selects a whole word by double-clicking somewhere within that word., If the use~ begins a double-click sequence, but then drags the mouse between the mouse-down and the mouse-up of the second click, the selection becomes a range of words rather than a single word. As the pointer moves, the application highlights or unhighlights a whole word at a time. A word, or range of words, can also be selected in the same way as any other range; whether this type of selection is treated as a range of characters or as a range of words depends on the operation. For example. in MacWrite, a range of individual characters that happens to coincide with a range ~f wor~s is treated like characters for purposes

11/30/84 Averill

/INTF/SELECT

SELECTING of extending a selection, but is treated like words for purposes of intelligent cut and paste. A'word is defined as any continuous substring that contains only the following characters: - a letter (including letters with diacritical marks) - a digit - a nonbreaking space (Option-space) - a dollar sign, cent sign, English pound symbol, or yen symbol - a percent sign - a comma be'tween. digi ts - a period before a digit - an apostrophe between letters or digits - a hyphen, but not a minus sign (Option-hyphen) or a dash (Option-Shift-hyphen) This is the definition in the United States and Canada; in other count-ries, it would have to be changed to reflect local formats for numbers, dates, and currency. If the user double-clicks over any character not on the list above, only that character is selected. Examples of words: $123,456.78 shouldn't 3 1/2 [with a nonbreaking space] .5% Examples of nonwords:

23

7/10/6 blue cheese [with i breaking space] "Yoicks!" [the quotation marks and ,exclamation point aren't part of the word] Selecting a Range of Text The user selects a range of text by dragging through the range. A range is either a range of words or a range of individual characters, as described under "Selecting Words", above.

11/30/84 Averill

/ INTF I. SELECT,

24

User Interface Guidelines

If the user extends the range, the way the range is extended depends on what kind of range it is. If it's a range of individual characters, it can be extended one character at a time. If it's a range of words (including a single word), it's extended only by whole words.
j~'

.Graphics Selections There are several different ways to select graphic objects and to show selection feedback in existing Macintosh applications. MacDraw, MacPaint, and t~e Finder all illustrate different possibili~ies. This section describes the MacDraw paradigm, which is the most extensible to other kinds of applications. A MacDraw document is a collection of individual graphic objects. To select one of these objects, the user clicks once on the object, which is then shown with knobs. (The knobs are used to stretch or shrink the object, and won't be discussed in this manual.) Figure 9 shows some examples of selection in MacDraw.

•

•

• •ThlS

1S

D

• block o~ •

•

text 1n MDcOrew.

•

Figure 9.

Graphics Selections in MacDraw

To select more than one object, the user can select either a range or a multiple selection. A range selection includes every object completely contained within the dotted rectangle that encloses the range, while an extended selection includes only those objects explicitly selected. Selections in Arrays As described above, under "Types of Applications", an array is a oneor two-dimensional arrangement of fields. If the array is one-dimensional, it's called a form; if it's two-dimensional, it's called a table. The user can select one or more fields, or part of the contents of a field. To select a single field, the user clicks in the field. The user can also implicitly select a field by moving into it with the Tab or Return key. 11/30/84 Averill /INTF/SELECT

SELECTING

25

The Tab key cycles through the fields in an order determined by the application. From each field, the Tab' key selects the "next" field. Typically, the sequence of .fields is first from left to right, and then from top to bottom. When the last field in a form is selected, pressing the Tab key selects the first field in the form. In a form, an application might prefer to select the fields in logical, rather than physical, order.
T~e

Return key selects the first field in the next row. If the idea of rows doesn't make sense in a particular context, then the Return key should have the same effect as the Tab key.

Tables are more likely than forms to support range selections and extended selections. A table can also support selection of rows and columns. The most convenient way for the user to select a column is to click in the column header. To select more than one column, the user drags through several column headers. The same applies to rows. To select part of the contents of a field, the user must first select the field. The user then clicks 'again to select the desired part of the field. Since the contents of a field are either text or graphics, this. type of selection follows the rules outlined above. Figure 1~ shows some selections in an array.
Column

Range

-+----.....-Per1 of e field

_ _ _ _ __+0_

Discontinuous Selection

Figure

10. Array Selections

WINDOWS Windows are the rectangles on the desktop that 'display information. The most commmon types of windows are document windows, desk accessories, dialog boxes, and alert boxes. (Dialog and alert boxes 11/30/84 Averill /INTF/WINDOW

26

User Interface Guidelines

are discussed under "Dialogs and Alerts".) Some of the features described in this section are applicable only to document windows. Figure 11 shows a typical active window and some of' its components.
- - --- Title ---- -- - ~---~-:::

Close box

Title bar

Scroll bar

lilllMiilillil.....~. .

- Size box

Scroll bar
Figure 11. An Active Wtndow

Multiple Windows Some applications may be able to keep several windows on the desktop at the same time. Each window is in a different plane. Windows can be moved around on the Macintosh's desktop much like pieces of paper can be moved around on a real desktop. Each window can overlap those behind it, and can be overlapped by those in front of it. Even when windows don't overlap, they retain their front-to-back ordering. Different windows can represent: - different parts of the same document, such as the beginning and eud of a long report - different interpretations of the same document, such as the tabular and chart forms of a set of numerical data - related 'parts of a logical whole, like the listing, ~xecution, and debugging of a program - separate
do~uments

being viewed or edited simultaneously

Each application may deal with the meaning and creation of mUltiple windows in its own way. The advantage of multiple windows is that the user can isolate unrelated chunks of information from each other. The disadvantage is that the desktop can becpme cluttered, especially if some of the

11/30/84 Averill

/INTF/WINDOW

WINDOWS windows can't be moved. Figure 12 shows multiple windows.

27

Inactive windows

Figure 12. Multiple Windows

The
active

""indOw

Opening and Closing Windows Windows come up onto the screen in different ways as appropriate to the purpose of the window. The application controls' at least the initial size and placement of its windows. Most windows have a close box that, when clicked, makes the window go away. The application in control of the window determines what's done with the window visually and logically when the close box is clicked. Visually, the windo~ can either shrink to' a smaller object such as an icon ,. or leave no trace behind when it closes. Logically, the information in the window is either retained and then restored when the window is reopened (which is the usual case), or else the window is reinitialized each time it's opened. When a document is closed, the user is given the choice whether to save any changes made to the document since the last time it was saved. If an application doesn't support closing a window with a close box, it should not include a close box on the window.

11/30/84 Averill

/INTF/WINDOW

28

User Interface Guidelines

The Active Window Of all the windows that are open on the desktop, the user can work in only one window at a time. This window is called the active window. All other open windows are inactive. To make a window active, the user clicks in it. Making a w~ndow active has two immediate consequences: - The window's title bar is highlighted, the scroll bars and size box are shown, and any controls inside the window become active. If the window is being reactivated, the selection that was in effect when it was deactivated is rehighlighted. - The window is moved to the frontmost plane, so that it's shown in front of any windows that it overlaps. Clicking in a window does nothing except activate it. To make a selection in the window, the user must click again. When the user clicks in a window that has been deactivated, the window should be reinstated just the way it was when it was deactivated, with the same position of the scroll box, and the same selection highlighted. When a w'indow becomes inactive, all the visual changes that took place when it was activated are reversed. ' The title bar becomes unhigh1ighted, the scroll bars and size box aren't shown, any controls inside the window are dimmed, and no selection is shown in the window. Moving a Window Each application initially places windows on the screen wherever it wants them. The user can move a window--to make more room on the desktop or to uncover a window it's over1apping--by dragging it by its title bar. As soon as the user presses in the title bar, that window becomes the active window. A dotted outline of the window follows the pointer until the user releases the mouse button. At the release of the but'ton the full window is drawn in its new location. Moving a window doesn't affect the appearance of the document within the window. If the user holds down the Command key while moving the window, the window isn't made active; it moves in the same plane.
i

The application should ensure that a window can never be moved completely off the screen. Changing the Size of a Window If a window has a size box in its bottom right corner, where the scroll bars come together, the user can change the size of the window-enlarging or reducing it to the desired size. Dragging the size box attaches a dotted' outline, of the window to the pointer. The outline's top left corner stays fixed, while the bottom
,

11/30/84 Averill

/INTF/WINDOW

WINDOWS right corner follows the pointer. When the mouse button is released, the entire window is redrawn in the shape of the dotted outline.

29

Moving windows and sizing them go hand in hand. If a window can be moved, but not sized, then the user ends up constantly moving windows on and off the screen. The reason for this is that if the user moves the window off the right or bottom edge of the screen, the scroll bars are the first thing to disappear. To scroll the window, the user must move the window back onto the screen again. If, on the other hand" the window can be resized, then the user can change its size instead of moving it off the screen, and will still be able to scroll. Sizing a window doesn't change the position of the top left corner of the window over the document or the appearance of the part of the view that's still showing; it changes only how much of the view is visible inside the window •. One 'exception to this rule is a command such as Reduce to Fit in MacDraw, which changes the scaling of the view to fit the size of the window. If, after choosing this command, the user resizes the window, the application changes the scaling of the view. The application can define a minimum window size. shrink the window below this size is ignored. Scroll Bars Scroll bars are used to change which part of a document view is shown in a window. Only the active window can be scrolled. A scroll bar (see Figure 11 above) is a light gray shaft, capped on each end with square boxes labeled with arrows; inside the shaft is a white rectangle. The shaft represents one dimension of the entire document; the white rectangle (called the scroll box) represents the location of the portion of the document currently visible inside the window. As the user moves the document under the window, the position of the rectangle in the scroll bar moves correspondingly. If the document is no larger than the window, the scroll bars are inactive (the scrolling apparatus isn't shown in them). If the document wipdow is inactive, the scroll bars aren't shown at all. There are three ways to move the document under the window: by sequential scrolling, by "paging" windowful by windowful through t,he document, and by directly positioning the scroll box. Clicking a scroll arrow moves the document in the opposite direction from the scroll arrow. For example, when the user clicks the top scroll arrow, the document moves down, bringing the view closer to the top of the document. The scroll box moves towards the arrow being clicked. Each click in a scroll arrow causes movement a distgnce of one unit in the chosen direction, with the unit of distance being appropriate to the application: one lin~ for a word processor, one row or column ~or , a spreadsheet, and so on. Within a document, units should always be 11/30/84 Averill /INTF/WINDOW Any attempt to

30

User Interface Guidelines

the same size, for.smooth scrolling. Pressing the scroll arrow causes continuous movement in its direction. Clicking the mouse anywhere in the gray area of the scroll bar advances the document by windowfu1s. The scroll box, and the document view, move toward the place where the user clicked. C1ickipg below the scroll box. for example, brings the user the next windowfu1 towards the bottom of the document. Pressing in the gray area keeps windowfu1s flipping by until the user releases the button, or until the location of the scroll box catches up to the location of the pointer. Each windowfu1 is the height or width of the window, min~s one unit overlap (where a unit is the distance the view scrolls when the scroll arrow is clicked once). In both the above schemes the user moves the document incrementally until it's in the proper position under the window; as the document moves, the scroll box moves accordingly. The user can also move the document directly to any position simply by ~oving the scroll box to the corresponding position in the. scroll bar. To move the scroll box, the user drags it along the scroll bar; an outline of the scroll box follows the pointer. When the mouse button is released, the scroll box jumps to the position last held by the outline, and the document jumps to the position corresponding to the new position of tQe scroll box. If the user starts dragging the scroll box, and then moves the pointer a certain distance outside the scroll bar, the scroll box detaches itself from the pointer and stops following it; if the user releases the mouse button, the scroll box returns to its original position and the document remains unmoved. But if the user still holds the mouse button and drags the pointer back into the scroll bar, the scroll box reattaches itself to the pointer and can be dragged as usual. If a document has a fixed size, and the user scrolls to the right or bottom edge of the document, the application displays a small amount of gray background (the same pattern as the desktop) between the edge of the document and the window frame. Automatic Scrolling There are several instances when the application, rather than the user, scrolls the document. These instances involve some potentially sticky problems about how to position the document within the window after scrolling. The first case is when the user moves the pointer out of the window while selecting by dragging. The window keeps up with the selection by scrolling automatically in the direction the pointer has been moved. The rate of scrolling is the same as if the user were pressing on the corresponding scroll arrow or arrows. The second case is when the selection isn't currently showing in the window, and the user performs an operation on it. When this happens, it's usually because the user has scrolled the document after making a

11/30/84 Averill

/INTF/WINDOW

WINDOWS selection. In this case, the application scrolls the window so that the selection is showing before performing the operation.

31

The third case is when the application performs an operation whose side effect is to make a new selection. An example is a search operation, after which the object of the search is selected. If this object isn't showing in the window, the application must scroll the window so as to show it. The second and t6ird cases present the same problem: Where should the selection be positioned within the window after scrolling? The primary rule is that the application should avoid unnecessary scrolling; users prefer to retain control over the ,positioning of a document. The following guidelines should be helpful: ~f part of the new selection is already showing in the window, don ',t scroll at all. An exception to this rule is when the part of the selection that isn't showing is more important 'than the part that's showing.

- If scrolling in one orientation (horizontal or vertical) is sufficient to reveal the selection, don't scroll in both orientations. - If the selection is smaller than the window, position the selection so that some of its context is showing on each side. It's better to put the selection somewhere' near the middle of the window than right up against the corner. - Even if the selection is too large to show in the window, it might be preferable to show some context rather than to try to 'fit as much as possible of the selection in'the,window. Splitting a Window Sometimes it's desirable to be able to see disjoint parts of a document simultaneously. Applications that accommodate such a capability allow the window to be split into independently scrollable panes. Applications that support splitting a window into panes place split bars at the top of the vertical, scroll bar and to the left of the horizontal one. Pressing a split bar attaches it to the pointer. Dragging the split bar positions it anywhere along the scroll bar; releasing the mouse button moves the split bar to a new position, splits the window at'that location, and divides the appropriate scroll bar (horizontal or vertical) into separate scroll bars for each pane. Figure 13 shows the ways a window can be split. .

11/30/84 Averill

/INTF/WINDOW

32

User Interface Guidelines

Horizontal Split
Figure 13.

Vertical Spl it
Types of Split" Windows

80th Splits

After a split, the document appears the same"except for the split line lying across it. But there are now separate scroll bars for each pane. The panes are still scrolled together in the orientation of the split, but can be~crolled independently in the other orientation. For example, if the split is horizontal, then horizontal scrolling (using the scroll bar along the bottom of the window), is still synchronous. Vertical scrolling is controlled separately for each pane, using the two scroll bars along the right of the window. This is shown in Figure 14.

C=Rl =)

(=81 =)

C=A2=) C=A3=)

(=82=)
C=83=)

C=M2~)

C- N2 - ) i:i!ii

C-M3-)

---

C~-N3~)
---

ii!1

C~N4~) j:!i!

The pene~ ~cro II together in the vertical orientation

, The panes scroll independently in the horizontal orientation

Figure 14.

Scrolling a Split Window

To remove a split, the user drags the split bar to the bottom or the right of the window. The number of views in a document doesn't alter the number of selections per document: that is, one. The active selection appears highlighted in all views that show it. If the application has to 11/30/84 Averill /INTF/WINDOW

WINDOWS

33

scroll automatically to show the selection, the pane that should be scrolled is the last one that the user clicked in. If the selection is already showing in one of the panes, no automatic scrolling takes place. Panels If a document window is more or less permanently divided into different regions, each of which has different content, these regions are called panels. Unlike panes, which show different parts of the same document but are functionally identical, panels are' functionally different from each other but might show different interpretations of the same part of the document. For example, one panel might show a graphic version of the document while another panel shows a textual version. Panels can behave much like subwindows; they can have scroll bars, and can even be split into more than one pane. An example of a panel with scroll bars is the list of files in the Open dialog box. Whether to use panels instead of separate windows is up to the application. Multiple panels in the same window are more compact than separate windows, but they have to be moved, opened, and closed as a unit.

COMMANDS Once the information to be operated on has been selected, a command to operate on that information can be chosen from lists of "commands called menus. Macintosh's pull-down menus have the "advantage that they're not visible until the user wants to see them; at the same time they're easy for the user to see and choose items from. Most commands either do something, in which case they're verbs or verb phrases, or else they specify an attribute of an object, in which case they're adjectives. They usually apply to the current selection, although some commands ~pply to the whole document or window. When you're designing your application, don't assume that everything has to be done through menu commands. Sometimes it's more appropriate for an operation to take place as a result of direct user manipulation of a graphic object on the screen, such as a control or icon. Alternatively, a single command can execute complicated instructions if it brings up a dialog box for the user to fill in.

11/30/84 Averill

/INTF/COMMANDS

34

User Interface Guidelines

The Menu Bar The menu bar is displayed at the top of the .screen. It contains a number of words and phrases: These are the titles of the menus associated with the current application. Each application has its own menu bar. The names of the menus do not change, except when the user calls for a desk accessory that uses different menus. Only menu menu menu menu titles appear in the menu bar. If all of the commands in a are currently disabled (that is, the user can't choose them), the title should be dimmed (in gray type). The user can pull down the to see the commands, but can't choose any of them.

Choosing a Menu Command To'choose a command, the user positions the pointer over the menu title and presses the mouse button. The application highlights the title and displays the menu, as shown in Figure 15.

While holding down the mouse button, the user moves the pointer down the menu. As the pointer moves to each command, the command is highlighted. The command that's highlighted when the user releases the mouse button is chosen. As soon as the mouse button is released, the command blinks briefly, the menu disappears, and the command is executed. (The user can set the number of times the command blinks' in the Control Panel ·desk accessory.) The menu title in the menu bar 11/30/84 Averill /INTF/COMMANDS

COMMANDS remains highlighted until the command has completed execution. Nothing actually happens until the user chooses the command; the user can look at any of the menus without making a commitment to do anything.

35

The most frequently used commands should be at the top of a menu; research shows that the easiest item for the user to choose is the s~cond item from the top. The most dangerous commands should be at the bottom of the menu, preferably isolated from the frequently used, commands. Appearance of Menu Commands The commands in a particular menu should be logically related to the title of the menu. In addition to command names, three features of menus help the user understand what each command does: command groups, toggles, and special visual features. Command Groups ,As mentioned above, menu commands can be divided into two kinds: verbs and adjectives, or actions and attributes. An important difference between the two kinds of commands is that an attribute' stays in effect until it's cancelled, while an action ceases to be relevant after it has been performed. Each of these two kinds can be grouped within a menu. Groups are separated by gray lines, which are implemented as disabled commands. The most basic reason to group commands is to break up a menu so it's easier to read. Commands grouped for this reason are logically related, but independent. Commands that are actions are usually grouped this way, such as Cut, Copy, Paste, and Clear in the Edit menu. Attribute commands that are interdependent are grouped to show this interdependence. Two kinds of attribute command groups are mutually exclusive groups and accumulating groups • . In a mutually exclusive attribute group, only one command in the group is in effect at the same time. The command that's in effect is preceded by a check mark. If the user chooses a different command in the group, the check mark is moved to the new command. Ari example is the Font menu in MacWrite; no more than one font can be in effect at a time. In an accumulating attribute group, any number of attributes can be in effect at the same time. One special command in the group cancels all the other commands. An example is the Style menu in MacWrite: the user can choose any combination of Bold, Italic, Underline, Outline, or Shadow, but Plain Text cancels all the other commands.

11/30/84 Averill

/INTF/COMMANDS

36

User Interface Guidelines

Toggles Another way to show the presence or absence of an attribute is by a toggled command. In this case, the attribute has two states, and a single command allows the user to toggle between the states. For example, when rulers are showing in MacWrite, a command in the Format menu reads "Hide Rulers". If the user chooses this command, the rulers are hidden, and the command is changed to read "Show Rulers". This kind of, group should be used only when the wording of the commands makes it obvious that they're opposites.
~pecial Visual Features

,In addition to the command names and how they're grouped, several other features of commands communicate information to the user: - A check mark indicates whether an' attribute command is currently in effect. An ellipsis ( ••• ) after a command name means that choosing that command. brings up a dialog box·. "The command isn't actually executed until the user has finished filling in the dialog box and has clicked the OK button or its equivalent. - The application dims a command when the user can't choose the user moves the pointer over a dimmed item, it isn't highlighted.
i~.

If

- If a command can be chosen from the ~eyboard, it's followed by the Command key symbol and the character used to choose it. To choose a command this way, the user holds down the Command key and then presses the character key. Some characters are reserved for special purposes, but there are different degrees of stringency. Since almost every application has a ·File menu and an Edit menu, the keyboard equivalents in those menus are strongly reserved, and should never be used for any other purpose: Character
C
Q

The keyboard equivalents in the Style menu are conditionally reserved. If an application has this menu, it shouldn't use ~hese characters for any other purpose, but if it doesn't, it can use them however it likes:

11/30/84 Averill

/INTF/COMMANDS

CO~u\NDS

37

Character B I
0
I

Command Bold Italic Outline Plain text Shadow Underline

P S U

One keyboard command doesn't have a menu equivalent: Character Command Stop current .operation Several other menu features are also supported: - A command can be shown in Bold, Italic, Outline, Underline, or Shadow type style. - A command can be preceded by an icon. - The application can draw its own type of menu. is the Fill menu in MacDraw. ) An example of this

STANDARD MENUS

One of the strongest ways in which Macintosh applications can take ( advantage of the consistency of the user interface is by using standard menus. The operations controlled by these menus occur so frequently that it saves considerable time for users if they always match exactly. Three of these menus, the Apple, File, and Edit menus, appear in almost every application. The Font, FontSize, and Style menus affect the appearance of text, and appear only in applications where they're relevant. The Apple Menu Macintosh doesn't allow two applications to be running at once. Desk accessories, however, are mini-applications that are available while using any application. At any time the user can issue a command to call up one of several desk accessories; the available accessories are listed in the Apple menu, as shown in Figure 16.

Accessories are disk-based: Only those accessories on an available disk can be.u~ed. The list of accessories is expanded or reduced according to what's available. More than one accessory can be on the desktop at a time. For a description of these desk accessories, see Macintosh, the owner's guide. An application can also pr.ovide its own desk accessories. The Apple menu also contains the "About xxx" menu item, where "xxx" is the· name of the application. Choosing this item brings up a dialog box with the name and copyright information for the application, as well as any other information the application wants to display. The File Menu The File menu allows the user to perform certain simple filing operations without" leaving the application and returning to the Finder. It also contains the commands for printing and for leaving the application. The standard File menu includes the commands shown in Figure 17..

Other frequently used commands are Print Draft, Print Final, and Print One. All of these commands are described below. New New opens a new, untitled document. The user names the document the first time it's saved. This command is disabled when the maximum number of documents allowed by the application is already open.

Open opens an existing document. To select the document" the user is presented with a dialog box (Figure 18). This dialog box shows' a list of all the documents on the disk whose name is displayed that can be handled by the current application. The user can scroll this list forward and backward. The dialog box also gives the user the chance to look at the documents on the disk in the other disk drive that belong to the current application, or to eject either disk.

\, ..

11/30/84 Averill

/INTF/SMENUS

40

User Interface Guidelines

Letter Marth figures Marketing Memo

,
iiiiii ~ihh :1:;:1
~i:i:i

(

(lJ)(~n

) (

Current

II!*

Eject'
Drlue

)

Messages
New Totels Old Totels

lilili ( Cencel

5
Figure 18.
Op~n

1

(

)

Dialog Box

Using the Open command, the user can only open a document that can be processed by the current application. Opening a document that can only be processed by a different application requires leaving the application and returning to the Finder. This command ·is disabled when the maximum Inumber of documents allowed by the application is already open. Close Close closes the active document or desk accessory. If the user has changed the document since the last time it was saved, the command pre~ents an alert box giving the user the choice of whether or not to save the changes. Clicking in the close box of a window is the same as choosing Close. Save Save makes permanent any changes to the active document since the last time it was saved. It leaves the document open. If the user chooses Save for a new document that hasn't been named yet, the application presents the Save As dialog (see below) to name the document, and then continues with the save. The active document remains active. If there's not enough room on the disk to save the document, the application asks if the' user wants to save the document on another disk. If the answer is yes, the application goes through the Save As dialog to find out" which disk.

11/30/84 Averill

/INTF/SMENUS

STANDARD MENUS

41

Save As Save As saves a copy of the active document under a file name provided by the user. If the document already has a name, Save As closes the old version of the document, creates a copy, and displays the copy in the window. If the document is untitled, Save As saves the original document under the specified name. The active document remains activ.e. Revert to Saved Revert to Saved returns the document to the state it was in the last time it was saved. Before doing so, it puts up an alert box to confirm that this is what the user wants. Page Setup Page Setup lets the user specify printing parameters such as what its paper size and printing orientation are. These parameters remain with the document. Print Print lets the user specify various parameters such as print quality and number of copies, and then prints the document. The parameters apply only to the current printing operation.

Quit leaves the application and returns to the Finder. If ~ny open documents have been changed since the last time they were saved, the application presents the same alert box as for Close, once for each document. Other Commands Other commands that are in the File menu in some applications include: - Print Draft. This command prints one copy of a rough version of a document more' quickly than Prin-t. It I S useful in applications where ordinary printing is slow. If an application has this command, it should change the pame of the Print command to Print Final. - Print One. This command saves time by printing one copy using default parameters without bringing up the Print dialog box. 11/30/84 Averill /INTF/SMENUS

42

User Interface Guidelines

The Edit Menu The Edit menu contains the commands that delete, move, and copy objects, as well as commands such as Undo, Show Clipboard, and Select All. This section also discusses the Clipboard, which is controlled by the Edit menu commands. Text editing methods that don't use menu commands are discussed under "Text Editing". If the. application supports desk access~ries, the order of commands in the Edit menu shoul,d be exactly as sl:t0wn here. This is because, by default, the application passes the numbers, not the names, of the menu commands to the desk accessories. (For more details, see the Desk Manager manual.) In particular, your application must provide an Undo command for the benefit of the desk accessories, even if it doesn't support the command (in which case it can disable the command until a desk accessory is opened). The standard order of commands in the Edit menu is shown in Figure 19.

The Clipboard The Clipboard is a special kind of window with a well-defined function: it holds whatever is cut or copied from a document. Its contents stay intact when the user change's documents, opens a desk accessory, or . leaves the application. An application can choose whether to have the Clipboard open or closed when the application starts up. The Clipboard looks like a document window, with a close box but with no scroll bars. Its contents cannot be edited. Every time the user performs a Cut or Copy on the current selection, a copy of the selection replaces the previous contents of the Clipboard. The previous contents are kept around in case the user chooses Undo.

11/30/84 Averill

/INTF/SMENUS

STANDARD MENU S The user can see the contents of the Clipboard but can't edit them. most 'other ways the Clipboard behaves just like any other window.

43 In

There is only one Clipboard, which is present for all applications that support Cut, Copy, and Paste. The user can see the Clipboard window by choosing Show Clipboard from the Edit menu. If the window is already showing, it's hidden by choOSing Hide Clipboard. (Show Clipboard and Hide Clipboard are a single toggled command.) Because the contents of the' Clipboard remain unchanged when applications begin and end, or when the user opens a desk accessory, the Clipboard can be used for transferring data among mutually compatible applications and desk accessories. Undo Undo reverses the effect of the previous operation. Not all operations can be undone; the definition of an undoable operation is somewhat application-dependent. The general rule is that operations that change the contents of the document are undoable, and operations that don't are not. MbS~ menu items ar~ undoable, and so are typing sequences. A typing sequence is any sequence of characters typed from the keyboard or numeric keypad, including Backspace, Return, and Tab, but not including keyboard equivalents of commands. Operations that aren't undoable include selecting, scrolling, and splitting the window or changing its size or location. None of these operations interrupts a typing sequence. That is, if the user types a few characters and then scrolls the document, the Undo command still undoes the typing. Whenever the location affected by the Undo operation isn't currently showing on the screen, the application should scroll the document so the user can see the effect of the Undo. An application should also allow the user to undo any operations that are initiated directly on the screen, without a menu command. This includes operations controlled by setting dials, clicking check boxes, and so on, as well as drawing graphic objects with .the mouse. The actual wording of the Undo command as it appears in the Edit menu is "Undo xxx", where xxx is the name of the last operation. If the last operation isn't a menu command, use some suitable term after the word Undo. If the last operation can't be undone, the command reads "Undo", but is disabled. If the last operation was Undo, the menu command says "Redo xxx", where xxx is the operation that was undone. If this command is chosen, the Undo is undone.

11/30/84 Averill

/INTF/SMENUS

44

User Interface Gu!delines

Cut The user chooses Cut either to delete the current selection or to move it. If it's a move, it's eventually completed by choosing Paste. When the user chooses Cut, the application removes the current selection from the document and puts it in the Clipboard, replacing the Clipboard's previous contents. The place where the selection used to be becomes the new selection; the visual implications of this vary among applications. For example, in text, the new selection is an insertion point, while in an array, it's an empty but highlighted cell. If the user chooses Paste immediately after choosing Cut, the document should be just as it was ,before the cut; the Clipboard is unchanged. When the user chooses Cut, the application doesn't know if it's a deletion or the first step of a move. Therefore, it must be prepared for either possibility.

Copy is the first st"age of a copy operation. Copy puts a copy of the selection in the Clipboard, but the selection also remains in the document. Paste Paste is the last stage of a copy or move operation. It pastes the contents of the Clipboard to the document, replacing the current selection. The user can choose Paste several times in a row to paste multiple copies. After a paste, the new selection is the object that was pasted, except i~ text, where it's an insertion point immediately after the pasted text. The Clipboard remains unchanged. Clear When the user chooses Clear, or presses the Clear key on the numeric keypad, the application removes the selection, but doesn't put it on the Clipboard. The new selection is the same as it would be after a Cut • . Show Clipboard Show Clipboard is a toggled command. Initially, the Clipboard isn't displayed, and the command is "Show Clipboard". If the user chooses the command, the Clipboard is displayed and the command changes to "Hide Clipboard".

11/30/84 Averill

/INTF/SMENUS

STANDARD MENUS

45

Select All Select All selects every object in the document. Font-Related Menus Three standard menus affect the appearance of text: Font, which determines the font of a text selection; FontSize, which determines the ,size of the characters; and Style, which determines aspects of its appearance s~ch 'as boldface, italics, and so on. Font Menu A font is a set of typographical characters created-with a consistent design. Things that relate characters in a font include the thickness of vertical and horizontal lines, the degree and position of curves and swirls, and the use of serifs. A font has the same general appearance, regardless of the size of the characters. The Font menu always lists the fonts that are cur'ren~ly available. Figure 20 shows ,a Font, menu with some of the most. common fonts.

Chicago &eneua ~New York Monaco Uenice london Rthens
Figure

20.

FQnt Menu

FontSize Menu Font sizes are measured in points; a point is about 1/72 of an inch. Each font is available in predefined sizes. The numbers of these sizes for each font are shown outlined in the FontSize menu. The font can also be scaled to other sizes, but it may not look as good. Figure 21 shows a FontSize menu with the standard font sizes.

11/30/84 Averill

/INTF/SMENUS

46

User Interface Guidelines
J

ont\llP

9 point 10
~UI

14 18

24 56

48 12
Figure 21. FontSize Menu

If there's insufficient room.in the menu bar for the word FontSize, it can be abbreviated to Size. 1£ there's insufficient toom for both a Font menu and a Size menu, the sizes can be put at the end of the Font or Style menu. Style Menu The commands in the Style menu are Plain Text, Bold, Italic, Underline, Outline, and Shadow. All the commands except Plain Text are accumulating attributes; the user can choose any combination. They are also toggled commands; a command that's in effect for the current selection is preceded by a check mark. Plain Text cancels all the other choices. Figure 22 shows these styles.

~PI.ln

TeHt

.P
XI

•• I~

1,.,1(:

.a
.U .0 .5

Underline

0l0J0IDDD

DIbCDdIaIlU
Figure 22.

Style Menu

11/30/84 Averill

/I~TF/sMENUS

TEXT EDITING

47

TEXT EDITING In addition to the operations described under "The Edit Menu" above, there are other ways to edit text that don't use menu items~ Inserting Text To insert text, the user selects an insertion point by clicking where the text is to go, and then starts typing it. As the user types, the application continually moves the insertion point to the right of each new character. Applications with multiline text blocks should support word wraparound, according to the definition of a word given above. The intent is that no word be broken between lines.
\

Backspace When 'the user presses the Backspace key, one, of two things happens: If the current selection is one
o~

more characters, it's deleted.

- If the current selection is an insertion point, the previous character is deleted. In both cases, the deleted'characters don't go into the Clipboard, and the insertion point replaces the d~leted characters in the document. Replacing Text If the user starts typing when the selection is one or more characters, the characters that are typed replace the selection. The deleted characters don't go into the Clipboard, but the replacement can be undone by immediately 'choosing Undo. Intelligent Cut and Paste An application that lets the user select a word by double-clicking should also see t~ it that the user doesn't regret using this feature. The only way to do this is by providing "intelligent" cut and paste. To understand why this feature is necessary, consider the following sequence of events in an application that doesn't provide it:
'I.

A sentence in the user's document reads: "Returns' are only accepted if the merchandise is damaged." The user wants to change this to: "Returns are accepted only if the merchandise is damaged."

11/30/84 Averill

/INTF/EDIT

48 2. 3. 4.

User Interface Guidelines The user selects the word "only" by double-clicking. The letters are highlighted, but not eit~er of the adjacent spaces. The user chooses Cut, -clicks just before the word "if", and chooses Paste. The sentence now reads: "Returns are accepted onlyif the merchandise is damaged." To correct the sentence, the user has to remove a space between "are" and "accepted", and add one between "only'" and "if". At this point he or she may be wondering why the Macintosh is supposed to be easier to use than other computers.

If an application supports intelligent cut and paste, the rules to follow are: - If the user selects a word or a range of words, highlight the selection, but not any adjacent spaces. - When the user chooses Cut, if the character to the left of the selection is a space, discard it. - When the. user chooses Paste, if the character to the left ~f the current selection isn't a space, add a space. If the character to the right of the current selection isn't a punctuation mark or a space, add a space. Punctuation marks in~lude the period, comma, exclamation point, question mark, apostrophe, colon, semicolon,r and quotation mark. This feature makes more sense if the application supports the full definition of a word (as detailed above under "Selecting a Word"), rather than the definition of a word as anything between two spaces. These rules apply to any selection that's one or more whole words, whether it was chosen with a double-click or as a range selection. Figure 23 shows some examples of intelligent cut and paste.

11/30/84 Averill

/INTF/EDIT

TEXT EDITING
Example 1:

49

1. Select

a word.

Drink to me _

with thine eyes.

2. Choose Cut.
3. Selec1 an insertion point.
4. Choose Paste.

Drink to mel wi th thine eyes Drink to me
Wl th

~hlne eyes.

Drink to me wi th only Ithlne eyes.

Example 2: 1. Select
8

word.

How) _

brown

CO'tV

2. Choose Cut.
3. Select en insertion point 4. Choose Paste.

How)1 brown cow
How~ brown cow

How now~ brown cow
Intelligent Cut and Paste

Figure 23.

Editing Fields If an application isn't primarily a text application, but does use text in fields (such as in a dialog box), it may not be able to provide the full text editing capabilities described so far. It's important, however, that whatever editing capabilities the application provides under these circumstances be upward-compatible with the fulI" text editing capability. The following list shows the capabilities that can be provided, going from the minimal to the most sophisticated: - The user can select the whole field and type in a new value. - The user can backspace. - The user can select a substring of the field and replace it. - The user can select a word by
double-clicki~g.

- The user can choose Undo, Cut, Copy, Paste, and Clear, as described above under "The Edit Menu". In the most sophisticated version, the application implements intelligent cut and paste. An application should also perform appropriate edit checks. For example, if the only legitimate value for a field is a string of digits, the application might issue an alert if the user typed any nondigits. Alternatively, the application could wait until the user is through typing before checking the validity of the contents of the 11/30/84 Averill /INTF/EDIT

50

User Interface Guidelines

field. In this case, the appropriate time to check the field is when the user clicks anywhere other than within the fie+d.

DIALOGS AND ALERTS
The paradigm is sufficient whenever operations are and act on only one object. But occasionally a command will require more than one object, or will need additional parameters before it can be executed. And sometimes a command won't be able to carry out its normal function, or will be unsure of the user's real intent. For these special circumstances the Macintosh user interface includes two additional features:
s~mple

"se1ect-then~choose"

- dialogs, to allow the user to provide additional information before a command is executed - alerts, to notify the user whenever an unusual situation occurs Since both of these features lean heavily on controls, controls are described in this section, even though controls are also used in ~ther places. Controls Friendly systems act by direct cause-and-effect; they do what they're told. Performing actions on a system in an indirect fashion reduces the sense of direct manipulation. To give Macintosh users the feeling that they're in control of their machines, many of an application's features are implemented with controls: graphic objects that, when directly manipulated by the mouse, cause instant action with visible results. ' ' There are four main types of controls: buttons, check boxes, radio buttons, and dials. These four kinds are ,shown in Figure 24.

11/30/84 Averill

/INTF/BOX

DIALOGS AND ALERTS

51

( Button 1 ) ( Button 2 )

cgJ Check

BOH BOH BOH

1 2

Diels

o Check

~

Check

:5

o Radio Button 1
@ Radio Button 2

o Radio Button 3
Figure 24. Controls

Buttons Buttons are small objects, usually- inside a window, labeled with text. Clicking or pressing a button performs the action described by the button's label. Buttons perform instantaneous actions, such as completing operations defined by a dialog box or acknowledging error messages. Conceivably they could perform continuous actions, in which case the effect of pressing on the button would be the same as the effect of clicking it repeatedly. Two parti~ular buttons, OK and Cancel, are especially important in dialogs and alerts; they're discussed under those headings below. Check Boxes and Radio Buttons Whereas buttons perform instantaneous or continuous actions, check boxes and radio buttons let the user choose among alternative values for a parameter. Check boxes act like toggle switches; they're used to indicate the state of a parameter that must be either off or on. The parameter is on if the box is checked, otherwise it's off. The check boxes appearing together in a given context are independent of each other; any number of them can be pff or on. Radio buttons typically occur in groups; they're round and are filled in with a black circle when on. They're called radio buttons because 11/30/84 Averill /INTF/BOX

/

52

User Interface Guidelines

they act like the buttons on a car radio. At any given time, exactly one button in the group is· on. Clicking one button in a group turns off the current button. Both check boxes and radio buttons are accompanied by text that identifies what each button does. Dials Dials display the value, magnitud.e, or position of something in the application or system, and optionally allow the user to alter that value. Dials are predominantly analog devices, displaying their values graphically and allowing the user to change the value by dragging an indicator; dials may also have a digital display. The most common example of a dial is the scroll bar. The indicator of the scroll bar is the scroll box; it represents the position of the window over the length of the document. The user can drag the scroll box-to change that position. Dialogs Commands in menus normally act on only one object. If a command needs more information before it can be performed, it presents a dialog box to gather the additional information from the user. The user can tell which commands bring up dialog boxes because they're followed by an ellipsis ( ••• ) in the menu. A dialog box is a rectangle that may contain text, controls, and icons. There should be some text in the box that indicates which command brought up the dialog box. Other than explanatory text, the contents of a diaIog box are all objects that the user sets to provide the needed information. These objects include controls and text fields. .When the application puts up the dialog box, it should set the controls to some default setting and fill in the text fields with default values, if possible. One of the text fields (the "first" field) should be highlighted, so that the user can change its value just by typing in the new value. If all the text fields are blank, there should be an insertion point in the first field. Editing text fields in a dialog box should conform to the guidelines detailed above, under "Text Editing". When the user is through editing an item: - Pressing Tab accepts the changes made to the item, and selects the next item in sequence. - Clicking in another item accepts the changes made to the previous item and selects the newly clicked item. 11/30/84 Averill /INTF/BOX

DIALOGS AND ALERTS Dialog boxes are either modal or modeless. as described below. Modal Dialog Boxes

'53

A modal dialog box is one that the user must explicitly dismiss before doing anything else. such as making a selection outside the dialog box or choosing a command. Figure 25 shows a modal dialog box.

Print the document @8 1/2" H II" paper o 8 1/2" H 14" paper
~

( CanCel)

(

OK

)

Stop printing after each page

Title: Rnnual Reportl

I

Figure 25.

A Modal Di'alog Box

Because it restricts the user's freedom of action, this type of dialog box should be used sparingly. In particular, the user can't choose a menu item while a modal dialog box is uP. and therefore can only do the simplest kinds of text editing. For these reasons, the main use of a modal dialog box is when it's important for the user to complete an operation before doing anything else. A modal dialog box usually has at least two buttons: OK and Cancel. OK ,dismisses the dialog box and performs the original command according to the information provided; it can be given a more descriptive name than "OK". Cancel dismisses the dialog box and cancels the original command; it must always be called "Cancel". A dialog box can have other kinds of buttons as well; these mayor may not dismiss the dialog box. One of the buttons in the dialog box may be outlined boldly. The outlined button is the default button; if no button is outlined, then the OK 'button is the default button. The default button should be the safest button in the current situation. Pressing the Return or Enter key has the same effect as clicking' the default button. If there is no default button, then Return 'and Enter have no effect. A special type of modal dialog box is one with no buttons. This type of box is just to inform the user of a situation without eliciting any response. Usually. it would describe the progress of an ongoing operation. S~nce it has no buttons, the user has no way to dismiss it. Therefore, the application must leave it up long enough for the user toread it before taking it down again. 11/30/84 Averill /INTF/BOX

.A mode1ess dialog box is dismissed by clicking in the close box or by choosing Close when the dialog is active. The dialog box is also dismissed implicitly when the user chooses Quit. It's usually a good idea for the application to remember the contents of the dialog box after it's dismissed, so that when it's opened again, it can be restored exactly as it was. Controls work the same way in modeless '. dialog boxes as in modal dialog boxes, exc~pt that buttons never dismiss the dialog box. In this context, the OK button means "go ahead and perform the operation, but leave the dialog box up", while Cancel usually terminates an ongoing operation. A modeless dialog box can also have text fields; since the user can choose menu commands, the full range of editing capabilities can be made available. Alerts Every user of every application is liable to do something that the application won't understand. From simple typographical errors to slips of the mouse to trying to write on a protected disk, users will do things an application can't cope with in a normal manner. Alerts give applications a way to respond to errors not only in a consistent manner, but in stages according to the severity of the error, the user's level of expertise, and the particular history of the error. 11/30/84 Averill /INTF/BOX

DIALOGS AND ALERTS The two kinds of alerts are beeps and alert boxes.

55

Beeps are used for errors that are both minor and immediately obvious. For example, if the user tries to backspace past the left boundary of a text field, the application could choose to beep instead of putting up an alert box. A beep can also be ~art of a staged alert, as described below. An alert box looks like a modal dialog box, except that it's somewhat narrower and appears lower on the screen. An alert box is primarily a one-way communication from the system to the user; the only way the user can respond is by clicking buttons. Therefore alert boxes might contain dials and buttons, but usually not text fields, radio buttons, or check boxes. Figure 27 shows a typical alert box.

CAUTION

( Cancel)
OK )

Rre you sure ( you want to erase all changes to your document?

Figure 27.

An Alert Box

There are three types of alert boxes: - Note: A minor mistake that wouldn't have any disastrous consequences if left as is. - Caution: An operation that mayor may not have undesirable results if it is allowed to continue. The user is given the choice whether or not to continue. - Stop: A situation that requires remedial action by the user. situation could be either a serious problem, or something as simple a's a request by the application to the us'er to change diskettes. The

An application can define several stages for an alert, so that if the user persists in the same mistake, the application can issue increasingly more helpful (or sterner) messages. A typical sequence is for the first two occurrences of the mistake to result in a beep, and for subsequent occurrences to result in an alert box. This type of sequence is especially appropriate when the mistake is one that has a high probability of being accidental. An example is when the user chooses Cut when the selection is an insertion point.

11/30/84 Averill

/INTF/BOX

56

User Interface Guidelines

How the buttons in an alert box are labeled depends on the nature of. the box. If the. box presents the user with a situation in which no alternative actions are available, the box has a single button that says OK. Clicking this button means "I have read the alert." If the user is given alternatives, then typically the alert is phrased as a question that can be answered "yes" or "no". In this case, buttons labeled Yes and No are appropriate, although some variation such as Save and Don't Save is also acceptable. OK and Cancel can be used, as long as their meaning isn't ambiguous. The preferred (safest) button to use in the current situation· is boldly outlined. This is the alert's default button; its effect occurs if the user presses Return or Enter. It's important to phrase messages in alert boxes so that users aren't left guessing the real meaning. Avoid computer jargon. Use icons whenever possible. Graphics can better describe some error situations than words, and familiar icons help users distinguish their alternatives better. Icons should be internationally comprehensible; they should not contain any words, or any symbols that are unique to a particular country. Generally, i~'s better to be polite-than abrupt, even if it means lengthening the message. The role of the alert box is to be helpful and make constructive suggestions, not to give out orders. But its focus is to help the user solve the problem, not to give an interesting but academic description ~f the problem itself. ,Under no circumstances should an alert message refer the user to external documentation for further clarification. It should provide an adequate description of the information needed by the user to take appropriate action. The best way to make an alert message understandable is to think carefully through·the error condition itself. Can the application handle this without an error? Is the error specific enough so that the user can fix the situation? What are the recommended solutions? Can the exact item causing the error be displayed in the alert message?

DO'S AND DON'TS OF A FRIENDLY USER INTERFACE Do: - Let the user have as much control as possible over the-appearance of objects on the screen--their arrangement, size, and visibility. - Use verbs as menu commands. - Make alert messages self-explanatory.

11/30/84 Averill

/INTF/THOUS

DO'S AND DON'TS ,OF A FRIENDLY USER INTERFACE
- Use controls and other graphics instead of just menu commands. - Take the time to use good graphic design; it really helps. Don't: - Overuse modes, including modal dialog boxes. - Require using the keyboard for an operation that would be easier with the mouse, or require using the mouse for an operation that would be easier with ·the keyboard. - Change the way the screen looks unexpectedly, especially by scrolling automatically more than necessary. - Make up your own menus and then give them the same names as standard menus. - Take an old-fashioned prompt-based application originally developed for another machine and pass it off as a Macintosh application.

ABOUT THIS MANUAL This manual contains the minimum information needed about memory management on the Macintosh. *** Eventually it will form an early chapter in the comprehensive Inside Macintosh manual. *** Memory management is covered in greater detail in the Memory Manager manual. This manual assumes you're familiar with Lisa Pascal and the information in Inside Macintosh: A Road Map.

THE STACK AND THE HEAP A running program can dynamically allocate and release memory in two different ways: from the stack or the heap. The stack is an area of memory that can grow or shrink at one end while the other end remains fixed, as shown in Figure 1. This means that space on the stack is always allocated and released in LIFO (last-in-first-out) order: the last item allocated is always the first to be released. It also means . that the allocated area of the stack is always contiguous. Space is released only at the top of the' stack, never in the middle, so there can never be any unallocated "holes" in the stack.

low memory

low memory

low memory

high memory

high memory
stack

high memory
free space
\

m w

--·0
The Stack

Figure 1.

By convention, the stack grows from high toward low memory addresses. The end of the stack that grows and shrinks is usually referred to as the "top" of the stack, even though it's actually at the lower end of the stack in memory. The other method of dynamic memory allocation is from the heap. Unlike stack space, which is implicitly tied to a program's subroutine structure, heap. space is allocated and released only at the program'R explicit request. In Pascal, objects on the heap are referred to by 8/20/84 Chernicoff-Hacker /MEM/INTRO.2

4

Memory Management Introduction

means of pointers instead of by name. Space on the heap is allocated in blocks, which may be of any size needed for a particular object. The Macintosh Operating System's Memory Manager does all the necessary "housekeeping" to keep track of the blocks as they're allocated and released. Because these operations can occur in any order, the heap doesn't grow and shrink in an orderly way like the stack. After a program has been running for a while, the heap tends to become fragmented into a patchwork of allocated and free blocks, as sho~n in Figure 2.

low memory

ra
:-: -: ~:-: . »: .:-:-: .:-:-:-:-:.: .:-:-:.:.: -:<

allocated blocks free blocks

D

high memory
Figure 2. A Fragmented Heap

As a result of heap fragmentation, when the program a!:;ks to· allocate a new block of a certain size, it may be impossible to satisfy the request even though there's enough free space available, because the space is broken up into blocks smaller than the requested size. When this happens, the Memory Manager will try to create the needed space by compacting the heap: moving already allocated blocks together in order to collect the free space into a single larger block (see Figure 3).

THE STACK AND THE HEAP There are always two independent heap areas in memory: the system heap, which is used by the Toolbox and Operating System, and the application heap, which is used by the application program.

5

POINTERS AND HANDLES The Memory Manager contains a few fundamental routines for allocating and releasing heap space. The NewPtr function allocates a block on the heap of a requested size and returns a pointer to the block. The DisposPtr procedure releases the block the variable points to and sets the variable to NIL. For example, after the declarations TYPE ThingPtr Thing

= AThing; = RECORD
END;

VAR aThingPtr: ThingPtr; the statement aThingPtr := NewPtr(SIZEOF(Thing» will allocate heap space for a new variable of type Thing and set aThingPtr to po!nt to it. The amount of space to be allocated is determined by the size of Thing. To allocate a 2K-byte memory block, you can use: aThingPtr := NewPtr($2000) Once you've used NewPtr to allocate a block and obtain a pointer to it, you can make as many copies of the pointer' as you need and use them in any way your program requires. When you're finished with the block, you can release the memory it occupies (returning it to available free space) with the statement DisposPtr(aThingPtr) Any pointers you may have to the block are now invalid, since the block they're supposed to point to no longer exists. You have to be careful not to use such "dangling" pointers. This type of bug can be very difficult to diagnose and correct, since its effects typically aren't discovered until long after the pointer is left dangling. Another way ,a pointer can be left dangling is for its underlying block to be ,moved to a different location within the heap. To avoid the problem, blocks that are referred to through simple pointers, as in Figure 4, are nonrelocatable. The Memory Manager will never move a nonrelocatable block, so you can rely on all pointers to it to remain correct for as long as the block remains allocated. 8/20/84 Chernicoff-Hacker /MEM/INTRO.2

q

Memory Management Introduction

heap
pointer ,.---nonre Ioceteb Ie
block

...............................................

Figure 4.

A Pointer to a Nonrelocatable Block

If all blocks on the heap were nonrelocatable, there would be no way to prevent the heap's free,space from becoming fragmented. Since the Memory Manager needs to be able to move blocks around in order to compact the heap, it also uses relocatable blocks. (All the allocated blocks shown earlier in Figure 3, the illustration of heap compaction, are relocatable.) To keep from creating dangling pointers, the Memory Manager maintains a single master pointer to each relocatable "block. Whenever a relocatable block is created, a master pointer is allocated from the heap at the same time and set to point to the block. All references to the block are then made by double indirection, through a pointer to the master pointer, called a handle to the block (see Figure 5). If the Memory Manager needs to move the block during compaction, it has only to update the master pointer to point to the block's new location; the master pointer itself is never moved. Since all copies of the handle point to this same master pointer, they can be relied on not to dangle, even after the block has been moved.

heap
handle

~

__________

~)~-------------4

master pointer re Iocetab Ie
block

Figure 5.

A Handle to a Relocatable Block

Given a handle to an object on the heap, you can access the object itself by double indirection. For example, after the following additional declarations 8/20/84 Chernicoff-Hacker /MEM/INTRO.2

POINTERS AND HANDLES TYPE ThingHandle

7

=

AThingPtr;

VAR aThingHandle: ThingHandle; you can access the Thing referred to by the handle aThingHandle with the expression aThingHandle AA Once you've allocated a block and obtained a handle to it, you can ma1ke as many copies of the handle as you need and use them in any way your program requires. When you're finished with the block, you can free the space it occupies with the statement DisposHandle(aThingHandle) (note) Toolbox routines that create new objects of various kinds, such as NewWindow and NewControl, implicitly call the NewPtr and NewHandle routines to allocate the space they need. There are also analogous routines for releasing these objects, such as DisposeWindow and -DisposeControl. If the Memory Manager can't allocate a block of a requested size even after compacting the entire heap, it can try to free some space by purging blocks from the heap. Purging a block removes it from the heap and frees the space it occupies. The block's master pointer is set to . NIL, but the space occupied by the master pointer itself remains allocated. Any handles to the block now point to a NIL master pointer, and are said to be empty. If your program later needs to refer to the purged block, it can detect that the handle has become empty and ask the Memory Manager to reallocate the block. This operation updates the original mas ter pointer, so that all handles to the .block are left referring correctly to its new location (see Figure 6 on the following page) • (warning) Reallocating a block recovers only the space it occupies, not its contents. Any information the block contains is lost when the block is purged. It's up to your program to reconstitute the block's contents after reallocating it. Relocatable and nonrelocat·able are permanent properties of a block that can never be changed once the block is allocated. A relocatable block can also be locked or unlocked, purgeable or unpurgeable; your program can set and change these attributes as necessary. Locking a block temporarily prevents it from being moved, even if the heap is compacted. The block can later be unlocked, again allowing the Memory Manager to move it during compaction. A block can be purged only if it's relocatable, unlocked, and purgeable. A newly allocated relocatable block is initially unlocked and unpurgeable.

GENERAL-PURPOSE DATA TYPES The Memory Manager includes a number of type definitions for generalpurpose use. For working with pointers and handles, there are the following definitions: TYPE Signed Byte Byte Ptr Handle -128 •• 127;

0 •• 255;
ASignedByte; APtr; ,

SignedByte stands for an arbitrary byte in memory, just to give Ptr and Handle something to point to. You can define a buffer of, say, bufSize untyped memory bytes as a PACKED ARRAY [l •• bufSize] OF SignedByte. Byte is an alternative definition that treats byte-length data as unsigned rather that signed quantities. Because of Pascal's strong typing rules, you can't directly assign a value of type Ptr to a variable of some other pointer type. Instead, you have to convert the pointer from one type to another. For example, after the declarations TYPE Thing

= RECORD
E~;

ThingPtr = AThing; VAR aPtr: Ptr; aThingPtr: ThingPtr; Lisa Pascal allows you to make aThingPtr point to the same object as aPtr with the assignment aThingPtr := ThingPtr(aPtr) or, you can refer! to a field of a record of type Thing with the expression ThingPtr(aPtr)A.field In fact, you can use this same syntax to equate any two variables of the same length. For example: VAR aChar: CHAR; aByte: Byte; aByte := Byte(?Char); You can also use the Lisa Pascal functions ORD, ORD4, and POINTER, to convert variables of different length from one type to another. For example: 8/20/84 Chernicoff-Hacker /MEM/INTRO.2

END;
you can make aProcPtr point to MyProc by using Lisa Pascal's @ operator, as follows: ( aProcPtr := @MyProc With the @ operator, you can assign procedures and functions to variables of type ProcPtr, embed them in data structures, and pass them as arguments to other routines. Notice, however, that the data type ProcPtr technically points to an arbitrary byte (SignedByte), not an actual routine. As a result, there's noway in Pascal to access the underlying routine l vi~ this pointer in order to call it. Only routines written in assembly language (such as those in the Operating System and the Toolbox) can actually call the routine designated by a pointer of type ProcPtr. 8/20/84 Chernicoff-Hacker /MEM/INTRO.2

GENERAL-PURPOSE DATA TYPES (warning) Procedures and functions that are nested within other routines can't be passed with the @ operator.

11

Finally, for treating long integers as fixed-point numbers, there's· the following data type: TYPE Fixed

= LONGINT;

As illustrated in Figure 7, a fixed-point number is a 32-bit quantity

containing an integer part in the high-order word and a fractional part in the low-order word. Negative numbers are the two's 'complement (formed by inverting each bit and adding 1).

15
4
integer (high-order)
2

o
1

15 1 2

o
1 4

I

1 8
fraction (low-order)
Figure 7. Fixed-Point Numbers

***

(The discussion of Fixed will be removed from the next draft of the Toolbox Utilities manual.) ***

application heap: The portion of the heap available to the running application program for its own memory allocation. block:
~~

area of contiguous memory on the heap.

compaction: The process of moving allocated blocks within the heap in order to collect the free space into a single block. empty handle: A handle that points to a NIL master pointer, signifying that the underlying relocatable block has been purged. fixed-point number: A,32-bit quantity containing an integer part in the high-order word and a fractional part\in the low-order word.
i

handle: A pointer to a master pointer, which designates a relocatable block on the heap by double indirection.' heap: The area of memory in which space is dynamically allocated and released on demand, u~ing the Memory Manager. lock: To temporarily prevent a relocatable block from being moved during heap compaction. . master pointer: A single pointer to a relocatable block, maintained by the Memory Manager and updated whenever the block is moved, purged, or reallocated. All handles to a relocatable block refer to it by double indirection through the master pointer. nonrelocatable block:- A block whose location in the 'heap is fixed and can't be moved during heap compaction. purge: To remove a relocatable block from the heap, leaving its master pointer allocated but set to NIL. purgeable block: A relocatable block that can be purged from the heap.

reallocate: To allocate new space on the heap for a purged block, updating its master pointer to point to its new location. release: reuse. To free an allocated area of memory, making it available for A block that can be moved within the heap during

relocatable block: compaction.

stack: The area of memory in which space is allocated and released in , LIFO (last-in-first-out) order.

8/20/84

Chernicoff-Hacker

/MEM/INTRO.G

14

Memory Management Introduction

system heap: The portion of the heap reserved for use by the Toolbox and Operating System. unlock: To allow a relocatable block to be moved during heap compaction. unpurgeable block: heap. A relocatable block that can't be purged from the

ABSTRACT This manual gives you general information that you'll need to write all or part of your Macintosh application program in assembly language. Summary of significant changes and additions since last draft: - Some additional generally useful global variables are documented (page 4). - Additions, corrections, and clarifications have been made to the sections "Pascal Data Types" (page 4) and "Calling Conventions" (page 9). - All illustrations of the stack now place high memory at the top.

ABOUT THIS MANUAL This manual gives you general information that you'll need to write all or part of your Macintosh application program in assembly language. *** Eventually it will become part of the comprehensive Inside Macintosh man~al. *** It assumes you already know how to write assembly-language programs for the' Motorola MC68000, the microprocessor in the Macintosh. You should also be familiar with the information in the manuals Inside Macintosh: A Road Map and Macintosh Memory Management: An Introduction.

***

Lisa running MacWorks is· called "Macintosh XL" in this manual.

***

DEFINITION FILES
., The primary aids to assembly-language programmers'are a set of defini tion files for symbolic names used in assembly-language pr'ograms. The definition files include equate files, which equate symbolic names with values, and macro files, which define the macros used to call Toolbox and Operating System routines from assembly language. The equate files define a variety of symbolic names for various purposes, such as:

useful numeric quantities - masks and bit numbers - offsets into data structures addresses of global variables (which often in turn contain addresses) It's a good idea to always use the symbolic names defined in an equate file in place of the corresponding numeric values (even if you know them), since some of these values may change. Note that the names of the offsets for a data structure don't always match the field names in the corresponding Pascal definition. In the documentation, the definitions are normally shown in their Pascal form; the corresponding offset constants for assembly-language use are listed in the summary at the end of each manual.

1/22/85

Hacker-Rose

/INTRO/ASSEM.2

'4

Programming in Assembly Language

Some generally useful global variables are defined in the equate files as follows: Name One One MinusOne Lo3Bytes Scratch20 Scratch8 ToolScratch ApplScratch Contents $00010001 $FFFFFFFF S00FFFFFF 20~byte scratch area 8-byte scratch area 8-byte scratch area 12-byte scratch area reserved for use by applications

Scratch20, Scratch8, and ToolScratch will not be preserved across calls to the routines in the Macintosh ROM. ApplScratch will be preserved; it ·should be used only by application programs and not by desk accessories or other drivers.
I

PASCAL DATA TYPES Pascal's strong typing ability lets Pascal programmers write programs without really considering the size of variables. But assemblylanguage programmers must keep track of the size of every variable. The sizes of the stanqard Pascal data types, and some of the basic types defined in the Hemory Manager, are listed below. {See the Apple Numerics Manual (Apple Product #nnn) *** fill in the number *** for more information about REAL, DOUBLE, EXTENDED, and COMP.)
~

Other data types are constructed from these. For some commonly used data types, the size in bytes is available as a predefined constant. Before allocating space for any variable whose size is greater than one byte, Pascal adds "padding" to the next word boundary, if it isn't 1/22/85 Hacker-Rose /INTRO/ASSEM.2

PASCAL DATA TYPES already at a word boundary. It does this not only variables declared successively in VAR statements, arrays and records. As you would expect, the size record is the sum of the sizes of all its elements stored with the first one at the lowest address). size of the data type TYPE TestRecord RECORD testHandle: testBoolA: testBoolB: testChar: END; Handle; BOOLEAN; BOOLEAN; CHAR

5

when allocating but also within of a Pascal array or or fields (which are For example, the

is eight bytes: four for the handle, one each for the Booleans, and two for the character. If the testBoolB field weren't there, the size would be the same, because of the byte of padding Pascal would add to make the character begin on a word boundary. In a packed record or array, type BOOLEAN is stored as a bit, and types CHAR and. Byte ~re stored as bytes. The padding rule described above still applies. For example, if the TestRecord data type shown above were declared as PACKED RECORD, it would occupy only six bytes: four for the handle, one for the Booleans (each stored in a bit), and one for the character. If the last field were INTEGER rather than CHAR, padding before the 2-byte integer field would cause the ·size to be eight bytes. (note) The packing algorithm may not be what you expect. If you need to exactly how data is packed, or if you have \ questions about the size of a particular data type, the best thing to do is write a test program in Pascal and look at the results. (You can use the SIZEOF function to get the size.) '.

THE TRAP DISPATCH TABLE The Toolbox and Operating System reside in ROM. However, to allow flexibility for future development, application code/must be kept free of any specific ROM addresses. So all references to Toolbox and Operating System routines are made indirectly through the trap dispatch table in RAM, which contains the addresses of the routines. As long as the location of the trap dispatch table is known, the routines themselves can be moved to different locations in ROM without disturbing the· operation of programs that depend on them. Information about the locations of the· various Toolbox and Operating System routines is encoded in -compressed form in the ROM itself. When the system is started up, this encoded information is expanded to form the trap dispatch table. Because the trap dispatch table resides in· RAM, individual entries can be "patched" to point to addresses other 1/22/85 Hacker-Rose /INTRO/ASSEM.2

6

Programming in Assembly Language

than the original ROM address. This allows changes to be made in the ROM code by loading corrected versions of individual routines into RAM at system startup and patching the trap dispatch table to point to them. It1also allows an application program to replace specific Toolbox and Operating System routines with its own "custom" versions. A pair of utility routines for manipulating the trap dispatch table, GetTrapAddress and SetTrapAddress, are described in the Operating System Utilities manual. f . For compactness, entries in the trap dispatch table are encoded into one word each, instead of a full long-word address. Since the trap dispatch table is 1024 bytes long, it has room for 512 word-length entries. The high-order bit of each entry tells whether the routine resides in ROM (0) or RAM (1). The remaining 15 bits give the offset of the routine relative to a base address. For routines in ROM, this base address is the beginning of the'ROM; for routines in RAM, it's the beginning of the system heap. The two base addre~ses are' kept in a pair of global variables named ROMBase and RAMBase. The offset in a trap dispatch of bytes, taking advantage of fallon word boundaries (even Figure 1, the system does the the routine: 1. 2. 3. table entry is expressed in words instead the fact that instructions must always byte addresses). As illustrated in following t~ find the absolute address of

checks the high-order bit of the trap dispatch table entry to find out which base address to use doubles the offset to convert it from words to bytes (by leftshifting one bit) adds the result to the designated base address

I I

trap dispatch table entry 15 14 0

I
10 I
address of

15

1 0

,
0: (~OM8eSe)}-1: (AAMBase)
Figure 1.

I
+
=

routine

Trap Dispatch Table Entry

1/22/85

Hacker-Rose

/INTRO/ASSEM.2

THE TRAP DISPATCH TABLE

7

Using IS-bit word offsets, the trap dispatch table can address locations within' a range of 32K words, or 64K bytes, from the base address. Starting from ROMBase, this range is big enough to cover the entire ROM; but only slightly more than half of the 128K RAM lies within range of RAMBase. Since all RAM-based code resides in the heap, RAMBase'is set to the beginning of the system heap to maximize the amount of useful space within range. Locations below the start of the heap are used to hold global system data (including the trap dispatch table itself), and can never contain executable code; but if the heap . is big enough, it's possible for some of the application's code to lie beyond the upper end of the trap dispatch table's range. Any such code is inaccessible through the trap dispatch table. (note) This problem is particularly acute on the Macintosh 512K and Macintosh XL. To make sure they lie within range of RAMBase, patches to Toolbox and Operating System routines are typically placed in the system heap rather than the application heap.

THE TRAP MECHANISM Calls to the Toolbox and Operating System via the trap dispatch table are implemented by means of the MC68000's "1010 emulator" trap. To issue such a call in assembly language, you use one of the trap macros defined in the macro files. When you assemble your program, the macro generates a trap word in the machine-language code. A trap word always begins with the hexadecimal digit $A (binary 1010); the rest of the word identifies the routine you're calling,along with some additional information pertaining to the call. ' (note) A list of all Macintosh trap words is given in the appendix of the Operating System Utilities manual. Instruction words beginning with $A or $F ("A-line" or "F-Ifne" instructions) don't correspond to any valid machine-language instruction, and are known as unimplemented instructions. They're used to augment the p'rocessor's native instruction set with additional operations that are "emulated" in software instead of being executed directly by the hardware. A-line instructions are reserved for use by Apple; on a Macintosh, they provide access to the Toolbox and Operating System routines. Attempting to execute such an instruction causes °a trap to the trap dispatcher, which examines the bit pattern of the trap word, to determine what operation it stands for, looks up the address of the corresponding routine in the trap dispatch table, and jumps to the routine. (note) F-line instructions are reserved by Motorola for use in future processors.

1/22/85

Hacker-Rose

/INTR9/ASSEM.2

8

Programming in Assembly Language

Format of Trap Words As noted above, a trap word always contains $A in bits 12-15. Bit Ii determines ,how the remainder of the word will be interpreted; usually it's 0 for Operating System calls and 1 for'Toolbox calls, though there are some exceptions. Figure 2 shows the Toolbox trap word format. Bits 0-8 form the trap number (an index into the trap dispatch table), identifying the particular routine being called. Bit 9 isn't used. Bit 10 is the "auto-pop" bit; this bit is used by language systems that, rather than directly invoke the trap like Lisa Pascal, do a JSR to the trap word followed immediately by a return to t~e calling routine. In this case, the return addresses for the both the JSR and the trap get pushed onto the stack, in that order. The auto-pop bit causes the trap dispatcher to pop the trap's return address from the stack and return directly to the calling program.
15 14 13 12 11 10 9 8 trap number

a
not used .

I I
Figure 2.

~ auto-pop bit

Toolbox Trap Word (Bit 11=1)

For Operating System calls, only the low-order eight bits (bits 0-7) are used for the trap number (see Figure 3). Thus of the 512 entries in the trap dispatch table, only the first 256 can be used for Operating System traps. Bit 8 of an Operating System trap has to do with register usage and is discussed below under "Register-Saving \ Conventions". Bits 9 and 10 have specialized meanings depending on which routine you're calling, and are covered where relevant in other manuals.
1

Trap Macros The names of all trap macros begin with the underscore character ( ), followed by the name of the corresponding routine. As a rule, themacro name is the same as the name used to call the routine from Pascal, as giv~n in the Toolbox and Operating System documentation. For example, to call the Window Manager routine NewWindow, you would use an instruction with the macro name _NewWindow in the opcode field. There are some exceptions, however; in which the spelling of the macro name differs from the name of the Pascal routine itself; these are noted in the documentation for the individual routines. (note) The reason for the exceptions is that assembler names must be unique to eight characters. Since one character is taken up by the underscore, special macro names must be used for Pascal routines ,whose names aren't unique to seven characters. Trap macros for Toolbox calls take no arguments; those for Operating System calls may have as many as three optional arguments. The first argument, if present, is used to load a register with a parameter value for the routine you're, calling, and is discussed below under "RegisterBased Routines". The remaining arguments control the settings of the various flag bits in the trap word. The, form of these arguments varies ,with the meanings of the flag bits, and is described in the manuals on the relevant parts of the Operating Sy~tem.

CALLING CONVENTIONS The calling conventions for Toolbox and Operating System routines fall into two categories: stack-based and register-based. As the terms imply, stack-based routines communicate via the stack, following the same conventions used by the Pascal Compiler for routines ,written in Lisa P~~cal, while register-based routines receive their parameters and return'their results in registers. Before calling any Toolbox or Operaiing System routine, you have to set up the parameters in the way the routine expects. (riote) ,As a general rule, Toolbox routines are stack-based and Operating System routines register-based, but there are exceptions on both sides. Throughout the technical documentation, register-based calling conventions are given for all routines that have them; if none is shown, then the routine is stack-based.

1/22/85

Hacker-Rose

/INTRO/ASSEM.3

10

Programming in Assembly Language

Stack-Based Routines To call a stack-based routine from assembly language, you have to set up the parameters on the stack in the same way the compiled object code would if your program were written in Pascal. If the routine you're calling is a function, its result is returned on the stack. The number and types of' parameters, and the type of result returned by a function, depend on the routine being called. The number of bytes each parameter or result occupies on the stack depends on its type:
T~pe of parameier or function result INTEGER LONGINT BOOLEAN

The steps to take to call the routine are as follows: 1. 2. 3. If i~'s a function, reserve space on the stack for the result. Push the parameters onto the stack in the order they occur in the routine's Pascal definition. Call the routine by executing the corresponding trap macro.

The trap pushes the return address onto the stack, along with an extra word of processor status information. The trap dispatcher removes this extra status word, leaving the stack in the state shown in Figure 4 on entry to the routine. The routine itself is responsible for removing its own parameters from the stack before returning. If it's a function, it leaves its result on top of the stack in the space reserved for it; if it's a procedure, it restores the stack to the same state it was in before tJhe call.

;make room for LONGINT result ;push window pointer ;a Point is a 4-byte record, ; so push actual contents ;a Rect is an 8-byte record, ; so push a pointer to it ;trap to routine ;pop result from stack

Although the MC68000 hardware provides for separate user and supervisor stacks, each with its own stack pointer, the Macintosh maintains only one stack. All application programs run in supervisor mode and share the same stack with the system; the user stack pointer isn't used. 1/22/85 Hacker-Rose

/INTRO/ASSEM.3

12

Programming in Assembly Language

Remember that the stack pointer must always be aligned on a word boundary. This is whYt for example t a Boolean parameter occupies two bytes; it's actually the Boolean value followed by a byte of padding. Because all Macintosh application code runs in the MC68000's supervisor mode t an odd stack pointer will cause a "double bus fault": a catastrophic system failure that causes the system to restart. To keep the stack pointer properly aligned t the MC68000 automatically adjusts the pointer by 2 instead of 1 when you move a byte-length value to or from the stack. This happens only when all of the following three conditions are met: - A 1-byte value is being transferred. - Either the source or the destination is specified by predecrement or postincrement addressing. - The register being decremented or incremented is the stack pointer

(A7).
An extra t unused byte will automatically be added in the low-order byte to keep the stack pointer even. (Note that if you need to move a character to br from the stack, you must explicitly use a full word of data, with the character in the low-order byte.) (warning) If you use any other method to manipulate the stack pointer t it's your responsibility to make sure the pointer stays properly aligned. (note) Some Toolbox and Operating Systeln routines accept the address of"one of your own routines as a parameter, and call that routine under certain circumstances. In these cases, you must set up your routine to be stack-based. Register-Based Routines By convention, register-based routines normally use register A0 for passing addresses (such as pointers to data objects) and D0 for other data val~es (such as integers). Depending on the routine, these registers may be used to pass parameters to the routine, result values back to the calling program, or both. 'For routines that take more than two parameters (one address and one data value), ~he'parameters are normally collected in a parameter block in memory and a pointer to the parameter block is passed in A0. However, not all routines obey these conventions; for example t some expect' parameters in other registers, such as Al. See the documentation on each individual routine for details. Whatever the conventions may be for a particular routine, it's up to you to set up the parameters in the appropriate registers before calling the routine. For instance t the Memory Manager procedure 1/22/85 Hacker-Rose /INTRO/ASSEM.3

CALLING CONVENTIONS

13

BlockMove, which ~opies a block of consecutive bytes from one place to another in memory, expects to find the address of the first source byte in· register A0, the address of the first destination location in AI, and the number of bytes to be copied in D0. So you might write something like LEA src(A5),A0 LEA dest(A5),Al MOVEQ #20,D0 BlockMove ;source address in A0 ;destination address in Al ;byte count in D0 ;trap to routine

Macro Arguments The following information applies to the Lisa Assembler. If you're using some other assembler, you should check its documentation to find out whether this information applies. Many register-based routines expect to find an address of some sort in register A0. You can specify the contents of that register as an argument to the macro instead of explicitly setting up the register yourself. The first argument you supply to the macro, if any, represents an address to be passed in A0. The macro will load the register with an LEA (Load Effective Address) instruction before trapping to the routine. So, for instance, to perform a Rea~ operation on a file, you could set up the parameter block for the operation and then use the instruction Read paramBlock ;trap to routine with pointer to· ; parameter block in A0

This feature is purely a convenience, and is optional: If you don't supply· any arguments to a trap macro, or if the first argument is null, the LEA to A0 will be omitted from the macro expansion. Notice that A0 is loaded with the address denoted by the argument, not the contents of that address. (note) You can use any of the MC68000's addressing modes to specify this addr~ss, with one exception: You can't use the two-register indexing mode ("address register indirect with index and displacement"). An instruction such as Read offset(A3,D5)

won't work properly, because the comma separating the two registers will be taken as a delimiter marking the end of the macro argument.

1/22/85

Hacker-Rose

/INTRO/ASSEM.3

14

Programming in Assembly Language

Result Codes Many regisier-based routines return a result code in the low-order word of registerD0 to report successful completion or failure due to some error condition. A result code of 0 always indicates that the routine was completed successfully. Just before returning from a registerbased call, the trap dispatcher tests the low-order word of D0 with a TST.W instruction to set the processor's condition codes. You can then check for an error by branching directly on the condition codes, without any explicit test of your own. For example: _PurgeMem BEQ NoError ;trap to routine ;branch if no error ;handle error

(warning) Not all register-based routines return a result code. Some leave the contents of D0 unchanged; others use the full 32 bits of the register to return a long-word result. See the documentation of individual routines for details. Register-Saving Conventions All Toolbox and Operating System routines preserve the contents of all registers except A0, AI, and D0-D2 (and of course A7, which is the stack pointer). In addition, for register-based routines, the trap dispatcher saves registers AI, Dl, and D2 before dispatching to the routine and restores the~ before returning to the calling program. A7 and D0 are never restored; whatever the routine leaves in these registers is passed back unchanged to the calling program, allowing the routine to manipulate the stack pointer as appropriate and to return a result co~e. Whether the trap dispatcher preserves register A0 for a register-basedtrap depends on the setting of bit 8 of the trap word: If this bit is 0, the trap dispatcher saves and restores A0; if it's 1, the routine passes back A0 unchanged. Thus bit 8 of the trap word should be set to 1 only for those routines that return a result 'in A0, and to 0 for all other routines. The trap macros automatically set this bit correctly for eac~ routine, so you never have to worry about it yourself.
Stack-b~sed traps preserve only registers A2-A6 and D3-D7. If you want to preserve any of the other registers, you have to save them yourself before trapping to the routine--typically on the stack with a MOVEM (Move Multiple) instruction--and restore them afterward.

(note) Any routine in your application that may be called as the result of a. Toolbox or Operating System call shouldn't rely on the value of any register except AS, which shouldn't change. 1/22/85 Hacker-Rose
/INT~O/ASSEM.3

CALLING CONVENTIONS

15

Pascal Interface to the Toolbox and Operating System When you call a register-based Toolbox or Operating System routine from Pascal, you're actually calling an interface routine that fetches the parameters from the stack where the Pascal-calling p~ogram left them, puts them in the registers where the routine expects them, and then traps to the routine. On return, it moves the routine's result, if any, from a register to the stack and then returns to the calling program. (For routines that return a result code, the interface routine may also move the result code to a global variable, where it can later be accessed.) For stack-based calls, there's no interface routine; the trap word is inserted directly into the compiled code.

MIXING PASCAL AND ASSEMBLY LANGUAGE You can mix Pascal and assembly language freely in your own programs, calling routines written in either language from the other. The Pascal and assembly-language portions of the program have to be compiled and assembled separately, then combined with a program such as the Linker. For convenience in this discussion, such separately compiled or assembled portions of a program will be called "modules". You c'an divide a program into any number of modules, each of which may be written in either Pascal or assembly language. References in one module to routines defined in another are called external references, and must be resolved by a program such as the Linker that resolves external references by matching them up with their definitions in other modules. You have to identify all the external references in each module so they can be resolved properly. For more information, and for details about the actual process of linking the modules together, see the documentation for the development system you're using. In addition to being able to call your own Pascal routines from assembly language, you can call certain routines in the Toolbox and Operating System that were created expressly for Lisa Pascal programmers and aren't part of the Macintosh.ROM. (These routines may also be available to users of other development systems, depending on how the interfaces have been set up on those s~stems.) They're marked with the notation [Not in ROM]

*** previously [Pascal only] or [No trap macro] *** in the documentation. There are no trap macros for these routines (though they may call other routines for which there are trap macros). Some of them were created just to allow Pascal programmers access to assemblylanguage information, and so won't be useful to assembly-language programmers. Others, however, contain code that's executed before a
1/22/85 Hacker-Rose /INTRO/ASSEM.3 ,

16

Programming in Assembly Language

trap macro is invoked, and you may want to perform the operations they provide. All calls from one language to the other, in either direction, must obey Pascal's stack-based calling conventions (see "Stack-Based Routines", above). To call your own Pascal routine from assembly language, or one of'the Toolbox or Operating System routines that aren't in ROM, you push the parameters onto the stack before the call and (if the routine is a function) look for the result on the stack on return. In an assembly-language routine to be called from Pascal, you look for the parameters on the stack on entry and leave the result (if any) on the stack before returning. Under stack-based calling conventions, a convenient way to access a routine's parameters on the stack is with a frame pOinter, using the MC68000's LINK and UNLK (Unlink) instructions. You can use any address register for the frame pointer (except A7, which is reserved for the stack'p01nter), but on the Macintosh register A6 is conventionally used for this purpose. The instruction LINK A6,#-12

at the beginning of a rpu~ine saves the previous contents of A6 on the stack and sets A6 to point to it. The second operand specifies the number of bytes of stack space to be reserved for the routine's local variables: in this case, 12 bytes. The LINK instruction offsets the stack pointer by this amount after copying it into A6. (warning) The offset is added to the stack pointer, not subtracted from it. So to allocate stack space for local variables, you have to give a negative offset; the instruction won't work properly if the offset is positive. Also, to keep the stack pointer correctly aligned, be sure the offset is even. For a routine with no local variables on the stack, use an offset of #0.
~egister

A6 now points to the routine's stack frame; the routine can locate its parameters and local variables by indexing with respect to this register (see Figure 5). The register itself points to its own saved contents, which are often (but needn't necessarily be) the frame pointer of the calling routine. The parameters and return address are found at positive offsets from the frame pointer.

Since the saved contents of the frame pointer register occupy a long word (four bytes) on the stack, the return address is located at 4(A6) and the last parameter at 8(A6). This ts followed by the rest of the parameters in reverse order, and finally by the space reserved for the function result, if any. The proper offsets for these remaining parameters and for the function result depend on the number and types of the parameters, according to the table above under "Stack-Based Routines". If the LINK instruction allocated stack space for any local variables, they can be accessed at negative offsets from the frame pointer, again depending on their number and types. At the end of the routine, the instruction UNLK A6

reverses the process: First it releases the local variables by setting the stack pointer equal to the frame pointer (A6), then it pops ihe saved contents back into register A6. This restores the register to its original state and leaves the stack pointer pointing to the routine's return address. A routine with no parameters can now just return to the caller with an RTS instruction. But if there are any parameters, it's the routine's 1/22/85 Hacker-Rose , / INTRO / ASSEM. 3

19

Programming in Assembly Language

responsibility to pop them from the stack before returning. The usual way of doing this is to pop the return address into an address register, increment the stack pointer to remove the parameters, and then exit with an indirect jump through the register. Remember that any routine called from Pascal must observe Pascal register conventions and preserve registers A2-A6 and D3-D7. This is usually done by saving the registers that the routine will be using on the stack with a MOVEM instruction, and then restoring them before returning. Any routine you write that will be accessed via the trap mechanism--for instance, your own version of a Toolbox or Operating System routine that you've patched into the trap dispatch table--should observe the same conventions. Putting all this together, the routine should begin with a sequence like MyRoutine LINK A6,iI-dd ;set up frame pointer-, dd = number of bytes ; of local variables ; ••• or whatever subset of ; these registers you use

Notice that A6 doesn't have to be included in the MOVEM instructions, since it's saved and restored by the LINK and UNLK. (warning) Whe.n the Segment Loader starts up an application, it sets register AS to point to the boundary between the application's globals and parameters. Certain parts of the system (notably QuickDraw and the File Manager) rely on· finding AS set up properly--so you have to be a bit more careful about preserving this register. The safest policy is never to touch AS at all. If you must use it for your own purposes, just saving its contents at the beginning of a routine and restoring them before returning isn't enough: You have to be sure to restore it before any call t~at might depend on it. The correct setting of AS is always available in the global variable CurrentAS.

'1/22/85

Hacker-Rose

/INTRO/ASSEM.3

SUMMARY

19

SUMMARY

Variables One One MinusOne Lo3Bytes Scratch20 Scratch8 ToolScratch ApplScratch CurrentAS $00010001 $FFFFFFFF $00FFFFFF 20-byte scratch area 8-byte scratch area 8-byte scratch area 12-byte scratch area reserved for use by applications Correct value of AS (long)

1/22/85

Hacker-Rose

/INTRO/ASSEM.S

20

Programming in Assembly Language

GLOSSARY external reference: A reference to a routine or variable defined in a' separate compilation or assembly. frame pointer: A pointer to a routine's stack frame, held in an address register and manipulated with the LINK and UNLK instructions. interface routine: A routine called from Pascal whose purpose is to trap to a certain Toolbox or Operating System routine. parameter block: Memory space used to transfer information between applications and- certain Ope~ating System routines. register-based routine: A Toolbox or Operating System routine that receives its parameters and returns its results, if any, in registers. stack-based routine: A Toolbox or Operating System routine that receives its parameters and returns its results, if any, on the stack. stack frame: The area of the stack used by a routine for i~s parameters, return address, local variables, and temporary storage. trap dispatch table: A table in RAM containing the addresses of al} Toolbox and Operating System routines in encoded form. trap dispatcher: The part of the Operating System that examines a trap word to determine what operation it stands for, looks up the address of the corresponding routine in the ,trap dispatch table, and jumps to the routine. trap macro: A macro that assembles into a trap word, used for calling a Toolbox or Operating System routine from assembly language. trap number: The identifying number of a Toolbox or Operating System routine; an index into the trap dispatch table. trap word: An unimplemented instruction representing a call to a Toolbox or Operating System routine. unimplemented instruction: An instruction word that doesn't correspond to any valid machine-language instruction but instead causes a trap.

Macintosh applications make ,use of many resources, such as menus, fonts, and icons. These resources are stored in resource files separately from the application code, for flexibility and ease of maintenance. This manual describes resource files and the Resource Manager routines. Summary of significant changes and additions since the last draft: - A detailed discussion of the specification of resource ID numbers has been added (page 9). - The concept of "system references" has been moved from the discussion of resource references (page 11) to a separate section (page 37). Since the Finder does not recognize these references to system resources, they aren't particularly useful and have been moved to a section which is essentially "of historical interest only". For this reason, "local references" are now simply called "resource references". - SizeResource returns a long integer rather than an integer (page 25) •

ABOUT THIS MANUAL This manual describes the Resource Manager, the part of the Macintosh User Interface Toolbox through which an application accesses various resources that it uses, such as menus, fonts, and icons. *** Eventually it will become part of the comprehen.sive Inside Macintosh manual. *** It discusses resource files, where resources are-stored. Resources form the foundation of every Macintosh application; even the application's code is a resource. In a resource file, the resources used by the application are stored separately from the code for flexibility and ease of maintenance. - You can use an existing program for creating and editing resource files, or write one of your own. These programs will call Resource Manager routines. - Usually you'll access resources indirectly through other parts of the Toolbox, such as the Menu Manager and the Font Manager, which in turn call the Resource Manager to do the low-level resource operations. In some cases, you may need to call a Resource Manager routine directly. Like all Toolbox documentation, this manual assumes you're familiar with Lisa Pascal and the information in the following manuals: - Inside Macintosh:

- Programming Macintosh Applications in Assembly Language, if you're using assembly language Familiarity with Macintosh files, as described in the File Manager manual, is optional. It's useful if you want a complet'e unders tanding of the internal structure of a resource file, but you d~n't have to know it to be, able to use the Resource Manager. If you're going to write your" own program to create and edit resource files, you also need to know the exact format of eacp type of resource. The documentation for the part of the Toolbox that deals w~th a particular type of resource will tell you what you need to know for that resource.

ABOUT 'THE RESOURCE MANAGER Macintosh applications make use of many resources, such as menus, fonts, and icons, which are stored in resource files. For example, an icon resides in a resource file as a 32-by-32 bit image, and a font as a large bit image containing the characters of the font. In some cases 11/28/84 Rose-Anders /RMGR/RESOURCE.2

4

Resource Man&ger Programmer's Guide

the resource consists of descriptive information ,( such as, for a menu, .the menu title, the text of each command in the menu, whether the command is checked with a check mark, and so on). The Resource Manager keeps track of resources in resource files and provides routines that allow applications and other parts of the Toolbox to access them. There's a resource file associated with each application, containing the resources specific to that application; these resources include the application code itself. There's also a system resource file, which contains standard resources shared by all applications (also called system resources). The resources used by an application are created and changed separately from the application's code. This separation is the main advantage to having resource files. A change in the title of a menu, for example, won't require any recompilation of code, nor will translation to a foreign language. The Resource Manager is initialized by the system when it starts up, and the system resource file is opened as part of the initialization. Your application's resource file is opened when the application starts up. When instructed to get a certain resource, the Resource Manager normally looks first tn the application's resource file and then, if the search isn't successful, in the system resource file. This makes it easy to share resources among applications and also to override a system resource with one of you"[' own Cif you want to use something other than a standard icon in an alert box, for example). Resources are grouped logically by function into resource types. You refer toa resource by passing the Resource Manager a resource specification, which c'onsists of the resource type and either an ID nu~ber or a name. Any resource type is valid, whether one of those recognized by the Toolbox as referring to standard Macintosh resources (such as menus and fonts), or a type created for use by your application. Given resource specification, the Resource Manager will read the 'resource into memory and return a handle to it.

a

(note) The Resource Manager knows nothing about the formats of the individual types of resources. Only the routines in the other parts of the Toolbox that call the Resource Manager have this knowledge. While most access to resources is read-only, certain applications may want to modify resources,. You can change the content of a resource or its ID number, name, or other attributes--everything except its type. For example, you can designate whether the resource should be kept in memory or whether, as is normal for large resources, it can be removed from memory and read in again when needed. You can change existing resources, remove resources from the resource file altogether, or add new resources to the file. Resource files are not limited to applfcations; anything stored in a file can have its own resources. For instance, an unusual font used in 11/28/84 Rose-Anders /RMGR/RESOURCE.2

ABOUT THE RESOURCE MANAGER only one document can be included in the,resource file for that document rather than in the system resource file. (note) Although shared resources are usually stored in the system resource file, you can have other resource files that contain resources shared by two or more applications (or documents, or whatever).

5

A number of resource files may be open at one time; the Resource Manager by default searches the files in the reverse of the order that they were opened. Since the system resource file is opened when the Resource Manager is initialized, it's always searched last. The search starts with the most recently opened resource file, but you can change it to start with a file that was opened earlier. (See Figure 1.)
Order of opening: Opened last Document's resource f i Ie

:;;

Usual search

You can change

it to this:

Opened

second

Appl ication's resource 1i Ie

Opened first

System resource tile

Figure 1.

Resource File Searching

OVERVIEW OF RESOURCE FILES Resources may be put in a resource file with the aid of the Resource Editor, which is documented *** nowhere right now, because it isn't' yet available. Meanwhile, you can use the Resource Compiler. You describe the resources in a text file that the Resource Compiler uses to generate the resource file. The exact format of the input file to the Resource Compiler is given in the manual Putting Together ~ Macintosh Application. *** A resource file is not a file in the strictest sense. Although it's functionally like a file in many ways, it's actually just one of two parts, or forks, of a file. (See Figure 2.) Every file has a resource fork and a data fork (either of which may be empty). The resource fork of an application file contains not only the resources used by the 11/28/84 Rose-Anders /RMGR/RESOURCE.2

6

Resource Manager Programmer's

Gu~de

application but also the"application code itself. The code may be divided into different segments, each of which is 'a. resource; this allows various parts of the program.to be loaded and purged dynamically. Information is stored in the resource fork vi~ the Resource Manager. The data fork of an application file can contain anything an application wants to store there. Information is stored in the data fork via the File Manager.

As shown in Figure 3, the system resource file has this same structure. The resource fork contains the system resources and the data fork contains "patches" to the routines in the Macintosh ROM. Figure 3 also shows the structure of a file containing a document; the resource fork contains the document's resources and the data fork contains the data that comprises the document.
r--------~----~----~--------, ~---J-----~----~---------------

OVERVIEW OF RESOURCE FILES To open a resource file, File Manager routine and File Manager. This is a to the file when calling (note) This'reference number is actually the path reference number, as described in the File Manager manual. the Resource Manager calls the appropriate returns the reference number it gets from the number greater than 0 by which you can refer other Resource Manager routines.

7

Most of the Resource Manager routines don't require the resource file's reference riumber a~ a parameter. Rather, they assume that the current resource file is where they should perform their operation (or begin it, in the case of a search for a resource). The current resource file is the last one that was opened unless you specify otherwise. A resource file consists primarily of resource data and a resource map. The resource data consists of the resources themselves (for example, the bit image for an icon or the descriptive information for a 'menu). The resource map contains an entry for each resource that provides the location of its resource data. Each entry in the map either give~ the offset of the resource data in the file or contains a handle to the data if it's in memory. The resource map is like the index of a book; the Resource Manager looks in it for th~ resource you specify and determines where its resource data is located. The resource map is read into memory when the file is remains there until, the file is closed. Although for that the Resource Manager searches resource files t it the resource maps that were read into memory, and not files on the disk. opened and simplicity we say actually searches the resource

Reso~rce data is normally read into memory when needed, though you can specify that it be read in as soon as the' resource file is opened. ' When re~d in, resource data is stoied in a relocatable block in the heap. Resources are designated in the resource map as being either purgeable or unpurgeable; if, purgeable, they may be removed from the heap when space is required by the Memory Manager. Resources consisting of a relatively large amount of data are usually designated as purgeable. Before accessing such a resource through its handle, you ask the Resource Manager to read the resource into memory again if it has been purged.

(note) Programmers concerned about the amount of available memory should be aware that there's a 12-byte overhead in the resource map for every resource and an additional 12-byte overhead fqr memory management if the resource is read into memory. To modify a resource, you change the resource data or resource map in memory. The change becomes permanent only at your explicit request, and then only when the application terminates or when you' call a routine specifically for updating or closing the resource file.

11/28/84 Rose-Anders

/RMGR/RESOURCE.2

8

Resource Manager

Programmer'~

Guide

Each resource file also may contain a partial copy of its entry in the file directory, writtell and used 'by the Finder, and up to 128 bytes of any data the application wants to store there.

RESOURCE SPECIFICATION In a resource file, every resource is assigned a type, an ID number, and optionally a name. When calling a Resource Manager routine to access a resource, you specify the resource by passing its type and either its ID number or its name. This section gives some general information about resource specification. Resource Types The resource ~ is a sequence of four characters. type is: TYPE ResType Its Pascal data

(warning) Uppercase and lowercase letters are distinguished in resource types. For example, 'Menu' will not be recognized as the resource type for menus. Notice that some of the resources listed above are "templates". A template is a list of parameters used to build a Toolbox object; it is not the object- itself. For example, a window template contains information specifying the size and location of the window, its title, whether it's visible, and so on. The Window Manager uses this information to build the window in memory and then never accesses the template again. You can use any four-character sequence (except those listed above) for resource types specific to your application. Resource ID Numbers Every resource has an ID number, or resource ID. The resource ID must be unique within each resource type, but resources of different types may have the same ID. If you assign the same resource ID to two resources of the same type, the second assignment of the ID will override the first, thereby making the first resource inaccessible. (warning) Certain resources contain the resource IDs of other resources; for instance, a dialog template contains the resource ID of its item list. In order not to duplicate an existing resource ID, a program that copies resources may need to change the resource ID of a resource; such a program may not, however, change the ID where it occur,s in other resources. For instance~ an item list's resource ID contained in a dialog template may not be changed, even though the actual resource ID of the item list was changed to avoid duplication; this would make it impossible for the template to access the item list. Be sure to verify, and if necessary, correct, the IDs contained within such resources. (For related information, see the section "Resource IDs of Owned Resources" below.) By convention, the ID numbers are divided into ,the following ranges:

11/28/84 Rose-Anders

/RMGR/RESOURCE.2

10

Resource Manager Programmer's Guide Range -32768 through -16385 -16384 through -1 Description Reserved; do not use Used for system resources owned by other system resources (explained below) Used for other system resources Available for your use in whatever way you wish

o through
128

thro~gh

127 32767

(note) The manuals that describe the different types of resources in detail give information about resource types that may be more restrictive about the allowable range for their resource IDs. A device driver, for instance, can't have a resource ID greater than 31. Resource IDs of Owned Resources This section is intended for advanced programmers who are involved in writing their own desk accessories (or other drivers), or special types of windows, controls, and menus. It's also useful in understanding the way that resource-copying programs recognize resources that are associated with each other. Certain types of system resources may have resources of their own in the system resource file; the "owning" resource consists of code that reads the "owned" resource into memory. For exampie, a desk accessory might have its own pattern and string resources. A special numbering convention is used to associate owned system resources with the resources they belong to. This enables resource-copying programs to recognize which additional resources need to be copied along with an owning resource. An owned system resource has the ID illustrated in Figure 4.

Bits 5 through 10 contain the resource ID of the owning resource (limited to 0 through 63). Bits 0 through 4 contain any desired value (0 through 31). Certain types of resources can't be owned, because their IDs don't conform to the special numbering convention described above. For instance, the resource ID for a resource of type 'WDEF can't be more than 12 bits long (as described in the Window Manager manual). Fonts are also an exception because their IDs include the font size. The manuals describing the different types of resources provide detailed information about such restrictions.

An owned resource may itself contain the ID of a resource associated with it. For instance, a dialog template owned by a desk accessory contains the resource ID of its item list. Though the item list is associated with the dialog template, it's actually owned (indirectly) by the desk accessory. The resource ID of the item list should conform to the same special convention as the ID of the template. For example, if the resource 10 of the desk accessory is 17, the IDs of both the template and the item list should contain the value 17 in bits 5 through 10.
As mentioned above"a program that copies resources may need to- change the resource 10 of a resource in order not to duplicate an existing resource ID. Bits 5 through 10 of resources owned, directly or indirectly, by the copied resource will also be changed when those resources are copied. For instance, in the above example, if the desk accessory must be given a new ID, bits 5 through 10 of both the template and the item list will also be changed. (warning) Remember that while the ID of an owned' resource may be changed by a resource-copying program, the 10 may not be changed where it appears in other resources (such as an item list's ID contained in a dialog template). Resource Names A resource may optionally have a resource name. Like the resource 10, the resource name must be unique within each type. When comparing resource names, the Resource Manager ignores case (but does not ignore diacritical marks in foreign names).

RESOURCE REFERENCES The entries in the resource map that identify and locate the resources in a resource file, are known as resource references. Using the analogy of an index of a book, resource references are like the individual entries in the index.
I

11/28/84 Rose-Anders

/RMGR/RESOURCE.2

12

Resource Manager Programmer's Gu.ide

re,ource specification

... ,

re,ource reference

J resource

'I

dete

I

resource map
Figure 5. Resource References in Resource Maps

Every resource reference includes the type, ID number, and optional name of the resource. Suppose you're accessing a resource for the first time. You pass a resource specification to the Resource Manager, which looks for a match among all the references in the resource map of the current resource file. If none is found, it looks at the references in the resource map of the next resource file to be searched. (Remember, it looks in the resource map in memory, not in the file.) Eventually it finds a reference matching the specification, which tells it,where the resource data is in the file. After reading the resource data into memory, the Resource Manager stores a handle to that data in the reference (again, in the resource map in memory) and returns the handle so you can use it to refer to the resource in subsequent routine calls. Every resource reference also contains certain resource attributes that determine how the resource should be dealt with. In the routine calls for'setting or reading them, each attribute is specified by a bit in the low-order byte of a word, as illustrated in Figure 6.

11/28/84 Rose-Anders

/RMGR/RESOURCE.2

RESOURCE REFERENCES

13

7

low-order byte 6 S .. 3 2

,

(high-order byte is ignored) 0

10 I I I I
I

IL

reserved for use by the Resource Manager , if to be written to resource fi Ie.. 0 if not

1 if to be prelo8ded, 0 if not . --------1 if protected, 0 if not 1 if loclced.. 0 if not

- - - 1 if purgeeble, 0 if not
~----1 if re80 into system he8p,

0 if application heap

Figure 6.

Resource Attribuies

The Resource Manager provides a predefined constant for each attribute, in which the bit corresponding to that attribute is set. CONST resSysHeap resPurgeable resLocked resProtected resPreload res Changed

= 64; = 32; = 8', = 4-, , 2'
16;

{set {set {set {set {set {set

if if if if if if

read into system heap} purgeable} locked} protected} to be preloaded} to be written to resource file}

(warning) Your application should not change the setting of bit 0 or 7, nor should it set the resChanged attribute directly. (ResChanged is set as a side effect of the procedure you call to tell the Resource Manager that you've changed a resource.) Normally the resSysHeap attribute is set for all system resources; it should not be set for your ~pplication's resources. If a system resource is too large for the system heap, this attribute will be 0, and the resource will be read into the application heap. Since a locked resource is neither relocatable nor purgeable, the resLocked attribute overrides the resPurgeable attribute; when resLocked is set, the resource will not be purgeable regardless of whether resPurgeable is set. If the resProtected attribute is set, the application can't use Resource Manager routines to change the ID number or name of the resource, modify its contents, or remove the resource from the resource file. The routine that sets the resource attributes may be called, however, to remove the protection or just change some of the other attributes. 11/28/84 Rose-Anders /RMGR/RESOURCE.2

14

Resource Manager Programmer's Guide

The resPreload attribute tells the Resource Manager to read this resource into memory immediately after opening ,the resource file. This is useful, for example, if you immediately want to draw ten icons stored in the file; rather than read and draw each one individually in turn, you can have all of them read in when the file is opened and just draw all ten. The res Changed attribute is used orily while the resource map is in memory; it must be 0 in the resource file. It tells the Resource Manager whether this resource has been changed.

USING THE RESOURCE MANAGER The Resource Manager is initialized automatically when the system starts up: the -system resource file is opened and its resource map is read into memory. Your application's resource file is opened when the application starts up; you can call CurResFile to get its reference number. You can also call OpenResFile to open any resource file that you specify by name, and CloseResFile to close any resource file. A function named ResError lets ,you check for errors that may occur during ex~cution of Resource Manager routines. (note) These are the only routines you need to know about to use the Resource Manager indirectly through other parts of the Toolbox; you can skip to their descriptions in the next section. Normally when you want to access a resource for the first time, you'll specify it by type and ID number (or type and name) in a call to GetResource (or GetNamedResource). In special situations, you may want to get every resource of each type. There are two routines which, used together, will tell you all the resource types that are in all open resource files: CountTypes and GetIndType. Similarly, CountResources and GetIndResource may be used to get all resources of a particular type. If you don't specify otherwise, GetResource, GetNamedResource, and GetIndResource read the resource data into memory and return a handle to it. Sometimes, however, you may not need the data to be in memory. You can use a procedure named SetResLoad to tell the Resource Manager not to read the resource data into memory when you get a, resource; in this case, the handle returned for the resource will be an empty handle (a-pointer to a NIL master pointer). You can pass the empty ,handle to routines that operate only on the resource map (such as the routine that sets resource attributes), since the handle is enough for the Resource Manager to tell "what resource you're referring to. Should you later want to access the resource data, you can read it into memory with the LoadResource procedure. Before calling any of the above routines that read the resource data rnto memory, it's a good idea to call SizeResource to see how much space is needed.

11/28/84 Rose-Anders

/RMGR/RESOURCE.2

USING THE RESOURCE MANAGER

15

Normally the Resource Manager starts looking for a resource in the most recently opened resource file, and searches other open resource files in the reverse of the order that they were opened. In some situations, you may want to change which file is searched first. You ,can do this with the UseResFile procedure. One such situation might be when you want a resource to be read from the same file as another resource; in this case, you can find out which resource file the other resource was read from by calling the HomeResFile function. Once you have a handle to a resource, you can call GetResInfo or GetResAttrs to get the information that's stored for that resource in the resource map, or you can access the resource data through the handle. (If the resource was designated as purgeable, first call LoadResource to ensure that the data is in memory.) Usually you'll just read resources from previously created resource files with the routines described above. You may, however, want to modify existing resources or even create your 'own resource file. To create your own resource file, call CreateResFile (followed by OpenResFile to open it). The AddResource procedure lets you add resources to a resource file; to be sure a new resource won't override an existing one, 'you can call the UniqueIO function to get an 10 number ,for it. To make a copy of an existing resource, call OetachResource followed by AddResource (with a new resource 10). There are a number of procedures for modifying existing resources: - To remove a resource, call RmveResource. - If you've changed the resource data for a resource and want the changed data to be written to the resource file, call ChangedResource; it signals the Resource Manager to write the data out when the resource file is later updated. - To change the information stored for ·a resource in the resource map, call SetResInfo or SetResAttrs. If you want the change to be written to the resource file, call ChangedResource. (Remember that ChangedResource will also cause the resource data itself to be written out.) These procedures for adding and modifying resources change only the resource map in memory. The changes are written to the resource file when the application terminates (at which time all resource files other than the system resource file are updated and closed) or when one of the following routines is called:' - CloseResFile, which updates the resource file before closing it. UpdateResF~le,

which simply updates the resource file.

- WriteResource, which writes the resource data for a specified resource to th~ resource file.

Initialization Although you don't call these initialization routines (because they're executed automatically for.you), it's a good idea to familiarize yourself with what they do. FUNCTION InitResources : INTEGER; InitResources is be called by the opens the system into memory, and called by the system when it starts up, and should not application. It initializes the Resource Manager, resource file, reads the resource map from the file returns a refeEence number for the file.

Assembly-language note: The name of the system resource file is stored in the global variable SysResName; the reference number for the file is stored in the global variable SysMap. ,A handle to the resource map of the system resource file is stored in the variable SysMapHndl.

(note) The application doesn't need the reference number for the system resource file, because every Resource Manager routine that has a reference number as a parameter interprets 0 to mean the system resource file. PROCEDURE RsrcZoneInit; RsrcZoneInit is called automatically when your application starts up, to initialize the resource map read from the system resource file; normally you'll have no need to call it directly. It "cl'eans up" after any resource access that may have been done by a previous application~ First it closes all open resource files except the system resource file. Then, for every system resource that was read into the application heap (that is, whose resSysHeap attribute is 0), it replaces the handle to that resource in the resource map with NIL. 11/28/84 Rose-Anders /RMGR/RESOURCE.R

RESOURCE MANAGER ROUTINES This lets the Resource Manager know that the resource will have to be read in again (since the previous application heap is no longer around). Opening and Closing Resource Files

17

When calling the CreateResFile or OpenResFile routines, described below, you specify a resource file by its file name; the routines assume that the file has a version number of 0 and is on the default volume. (Version numbers and volumes are described in the File Manager manual.) PROCEDURE CreateResFile (fileName: Str255); CreateResFile creates a resource file containing no resource data or copy of the file's directory entry. If there's no file at all with the given name, it also creates an empty data fork for the file. If there's already a resource file with the given name (that is, a resource fork that isn '.t empty), CreateResFile will do nothing and the ResError function will retur~ an appropriate Operating System result code. (note) Before you can work with the resource file, you need to open it with OpenResFile. FUNCTION OpenResFile (fileName: Str255) : INTEGER; OpenResFile opens the resource file having the given name and makes it the current resource file. It reads the resource map from the file into memory and returns a reference number for the file. It also reads in every resource whose resPreload attribute is set. If the resource file is already open, it doesn't make it the current resource file; it simply returns the reference number. (note) You don't have to call OpenResFile to open the system resource file or the application's resource file, because they're opened when the system and the application start up, respectively. To get the reference number of the application's resource file, you can call CurResFile after the application starts up (before you open any other resource file). If the file can't be opened, OpenResFile will return -1 and the ResError function will return an appropriate Operating System result code. For example, an error occurs if there's no resource file with the given name.

11/28/84 Rose-Anders

/RMGR/RESOURCE.R

18

Resource Manager Programmer's Guide

Assembly-language~: A handle to the resource map of the most recently opened resource file is stored in the global variable TopMapHndl.

PROCEDURE CloseResFile (refNum: INTEGER); Given the reference number of a resource file, CloseResFile does the foll?wing: - updates the resource file by calling the UpdateResFile procedure - for each resource in the resource. file, releases the memory it occupies by calling the ReleaseResource procedure - releases the memory occupied by the resource map - closes the resource file If there's no resource file open with the given reference number; CloseResFile will do nothing and the ResError function will return the result code resFNotFound. A refNum of 0 represents the system resource file, but if you ask to close this file, CloseResFile first closes all other open resource files. A CloseRes~ile of ~very open resource file except the syste~ resource file is done automatically when the application terminates. So you only need to call CloseResFile if you want to close the system resource file, or if jou want to close any resource file before 'the application terminates. Checking for Errors

FUNCTION ResError : ,INTEGER; Called after one of the various Resource Manager routines that may result in an error condition, ResError returns a resul.t code identifying the error, if any. If no error occurred, it returns the result code ' CONST noErr

= 0;

{no error}

If an error occurred at the Operating System level, it returns an Operating System result code, such as the File Manager "disk I/O u error or the Memory Manager "out of memoryU error. (See the File Manager and Memory Manager manuals for a list of the result codes.) If an error haEpened at ~he Resource Manager level, ResError returns one of the 11/28/84 Rose-Anders /RMGR/RESOURCE.R

Each routine description tells which errors may occur for that routine. You can also check for an error after system startup, which calls InitResources, and application startup, which opens the application's resource file.

Assembly-language note: The current value of ResError is stored in the global variable ResErr. In addition, you can specify a procedure to be called whenever there's an error by storing a pointer to the procedure in the global variable ResErrProc (which is normally NIL). Before returning a result code other than noErr, the ResError function places that result code in register D0 and calls your procedure.

Setting the Current Resource File

FUNCTION CurResFile : INTEGER; CurResFile returns the reference number of the current resource file. You can call it when the application starts up to get the reference number of its resource file. (note) If the system resource file is the current resource file, CurResFile returns the actual reference number of the system reference file (found in the global variable SysMap). You needn't worry about this number being used (instead of 0) in the routines that require a reference number; these routines recognize both 0 and the actual reference nu~ber as referring to the system resource file.

Assembly-language note: The reference number of the current resource file is stored in the global variable CurMap.

11/28/84 Rose-Anders

/RMGR/RESOURCE.R

20

Resource Manager Programmer's Guide

FUNCTION HomeResFile (theResource: Handle) : INTEGER; Given a handle to a resource, HomeResFile returns the reference number of the resource file containing that resource. If the given handle isn't a handle to a resource, HomeResFile will re.turn -1 and the ResError function will return the result code resNotFound. PROCEDURE UseResFile (refNum: INTEGER); Given the reference number of a resource file, UseResFile sets the current r~source file to that file. If there's no resource file open with the given reference number, UseResFile will do nothing and the ResError function will return the result code resFNotFound. A ref~um of 0 represents the system resource file. Open resource files are arranged, as a linked list; the most recently opened file is at the end of the list and is the first one to be searched. UseResFile lets you start the search with a file opened earlier; the file(s) following it on the list are then left out of the search process. This is best understood with an example. Assume there are four open resource files (R0 through R3); the search'order is R3, R2, R1, R0. If you,call UseResFile(R2), the search order becomes R2, R1, R0; R3 is no longer searched. If you then open a fifth resource file (R4), it's added to the end of the list and the search order becomes R4, R3, R2, R1, R0. This procedure is useful if you no longer want to override a system resource with one by the same name in your application's resource file. You can call UseResFile(0) to leave the application resource file out of the search, causing only the system resource file to be searched. (warning) Early versions of some desk accessories may, upon closing, always set the current resource file to the one opened just prior to the accessory, ignoring any additional resource files that may have been opened while the accessory was in use. To be safe, whenever desk accessories may have been in use, call UseResFile to ensure access to resource files opened after accessories. Getting Resource Types

FUNCTION CountTypes : INTEGER; , CountTypes returns the number of resource types in all open resource files.

Given an index ranging from 1 to CountTypes (above), GetlndType returns a resource type in theType. Called repeatedly over the entire range for the index, it returns all the resource types in all open resource files. If the given index isn't in the range from 1 to CountTypes, GetIndType returns four NUL characters (ASCII code 0). Getting and Disposing of Resources

PROCEDURE SetResLoad (load: BOOLEAN); Normally, the routines that return handles to resources read the resource data into memory if it's not already in memory. SetResLoad(FALSE) affect's all those routines so that they will not read the resource data into memory and will return an empty handle. Resources whose resPreload attribute is set will still be read in, however, when a resource file is opened. SetResLoad (TRUE) res tores t'he normal state. (warning) If you call SetResLoad(FALSE), be sure to restore the normal state as soon as possible, because other parts of the Toolbox that call the Resource Manager 'rely on it.

Assembly-language note: The current SetResLoad state is stored in the global variable ResLoad.

FUNCTION CountResources (theType:. ResType) : INTEGER; CountResources returns the total number of resources of the given type in all open resource files. FUNCTION GetlndResource (theType: ResType; index: INTEGER) Handle;

Given an index ranging from 1 to CountResources(theType), GetlndResource returns a handle to a resource of the given type (see CountResources, above). ' Called repeatedly over the entire range for the index, it ~eturns handles to all resources of the given type in all open resource files. GetlndResource reads the resource data into memory if it's not already in memory, unless you've called SetResLoad(FALSE).

11/28/84 Rose-Anders

/RMGR/RESOURCE.R

22

Resource Manager Programmer's Guide

(warning) The handle returned wi~l be an empty handle if you've called SetResLoad(FALSE) (and the data isn't already in memory). The handle will become empty if the resource data for a purgeable resource is read in but later purged. (You can test for an empty handle with, for example, myHndl = NIL.) To read in the data and make the handle no lo'nger be empty, you can call LoadResource.
A

GetIndResource returns handles for all resources in the most recently opened resource file first, and then for those in the resource files opened before it, in the reverse of the order that they were opened. If you want to find out how many resources of a given type are in-a particular resource file, you can do so as follows: Call GetIndResource repeatedly with the index ranging from 1 to the number of resources of that type. Pass each handle returned by GetIndResource to HomeResFile and count all occurrences where the reference number returned is that of the desired file. Be sure to start the index fr6m 1, and to call SetResLoad(FALSE) so the resources won't be read in. (note) The UseR~sFile procedure affects which file the Resource Manager searches first when looking for a particular resource but not when getting indexed resources with GetIndResource. If the given index isn't in the range from 1 to CountResources(theType), GetIndResource returns NIL and the ResError function will return the result code resNotFound. GetIndResource also returns NIL if the resource is to be read· into memory but won't fit; in this case, ResError will return an appropriate Operating Sy~tem result code. FUNCTION GetResource (theType: ResType; theID: INTEGER) Handle;

GetResource returns a handle to the resource having the given type and ID number, reading the resource data into memory if it's not already in memory and if you haven't called SetResLoad(FALSE) (see the warning above for GetIndResource). GetResource looks in the current resource file and all resource files opened before it, 'in the ~everse of the order that they were opened; the system resource file is searched last. If it doesn't find the resource, GetResource returns NIL and the ResError function will return the result code resNotFound. GetResource also returns NIL if"the resource is to be read into memory but won't fit; in this case, ResError will return an appropri.ate Operating System result code. FUNCTION GetNamedResource (theType: ResType; name: Str255) : Handle;
GetNamedR~source is the same as GetResource (above) except that you pass a reso'urce name instead of an ID number.

Given a handle to a resource (returned by GetIndResource, GetResource, or GetNamedResourc'e), LoadResource reads that resource into memory. It does nothing if the resource is already in memory or if the given handle isn't a handle to a resource; in the latter case, the ResError function will return the result code resNotFound. Call this procedure if you want to access the data for a resource through its handle and either you've called SetResLoad(FALSE) or if the resource is purgeable. If you've changed the resource data for a purgeable resource and the resource is purged before being written to, the resource file, the changes will be lost; LoadResource will reread the original resource from the resource file. See the descriptions of ChangedResource and SetResPurge for information about how to ensure that changes made to purgeable resources will be written to the resource file.

Assembly-language note:

LoadResource preserves all registers.

PROCEDURE ReleaseResource (theResource: Handle); Given a handle to a resource, ReleaseResource releases the memory occupied by the resource data,'if any, and replaces the handle to that resource in the resource map with NIL. (See Figure 7.) The given handle will no longer be recognized as a handle to a resource; ~f the Resource Manager is subsequently called to get the released resource, a new handle will be allocated. Use this procedure only after you're completely through with a·resource.

11/28/84 Rose-Anders

/RMGR/RESOURCE.R

24

Resource Manager Programmer's Guide
resource map resource deta handle

TYPE myHndl: Hendlej
myHndl := GetResource(type" 10);

myHndl

After Rei eeseResource(myHnd I)j
resource map

After _ oetachAesource(myHnd I) j
resource map resource dete

NIL

NIL

myHndl

~yHndl

Figure 7.

ReleaseResource and DetachResource

If the given handle isn't a handle to a resource, ReleaseResource will do nothing and the ResError function will return the result code resNotFound. PROCEDURE DetachResource (theResource: Handle); Given a handle to a resource, OetachResource replaces the handle to that resource in the resource map with NIL. (See Figure 7 above.) The given handle will no longer be recognized as a handle to a resource; if the Resqurce Manager is subsequently called to get the detached resource, a new handle will'be allocated. OetachResource is useful if you, want the resource data to be accessed only by yourself through the given handle and not by the Resource Manager. OetachResource is also useful in the unusual ·case that you don't want a resource to be released when a resource file is closed. To copy a resource, you can call OetachResource followed by AddResource (with a new resource 10). If the given handle isn't a handle to a resource, OetachResource will do nothing and the ResError function will return the result code resNotFound.

11/28/84 Rose-Anders

/RMGR/RESOURCE.R

RESOURCE MANAGER ROUTINES

25

Getting Resource Information

FUNCTION UniqueID (theType: ResType) : INTEGER; UniqueID returns an ID number greater than 0 that isn't currently assigned to any resource of the given type in any open resource file. Using this number when you add a new resource to a resource file ensures that you won't duplicate a resource ID and override an existing resource. (warning) It's possible that UniqueID will return an ID in the range reserved for system resources (0 to 127). You should check that the ID returned is greater than 127; if' it isn't, call UniqueID again. PROCEDURE GetResInfo (theResource: Handle; VAR theID: INTEGER; VAR theType: ResType; VAR name: Str255); Given a handle to a resource, GetResInfo returns the ID number, type, and name of the resource. If the given handle isn't a handle to a resource, GetResInfo will do nothing and the ResError function will return the result code resNotFound. FUNCTION GetResAttrs (theResource: Handle) : INTEGER; Given a handle to a resource, GetResAttrs returns the resource attributes for the resource" (Resource attributes are described above under "Resource References".) If the given handle isn't a handle to a resource, GetResAttrs will do nothing and the ResError function will return the result code resNotFound. FUNCTION SizeResource (the Resource: Handle) : LONGINT; Given a handle to a resource, SizeResource returns the size in bytes of the resource in the resource file. If the given handle. isn't a ha~dle to a resource, SizeResource will return -1 and the ResError function will return the result code resNotFound. It's a good idea to call SizeResource and ensure that sufficient space is' available before reading a resource into memory.

Assembly-language note: The macro you invoke to call SizeResource from assembly language is named SizeRsrc.

11/28/84 Rose-Anders

/RMGR/RESOURCE.R

26

Resource Manager Programmer's Guide

Modifying Resources Except for UpdateResFile and WriteResource, all the routines described below change the resource map in memory, and not the resource file . itself. PROCEDURE SetResInfo (theResource: Handle; theID: INTEGER; name: Str25S); Given a,handle to a resource, SetResInfo changes the ID number and name of the resource to the given ID number and name.

Assembly-language note: If you pass NIL for the name parameter, the name will not be changed.

(warning) It's a dangerous practice to change the 10 number and name of a system resource, because other applications may already access the resource and may no longer work properly. The change will be written to the resource file when the file is updated if you follow SetResInfo with a call to ChangedResource. (warning) Even if you don't call ChangedResource for this resource, the change may be written to the resource file when the file is updated. If you've ever called ChangedResource for any resource in the file, or if you've added or removed a resource, the Resource Manager will write out the entire resource map when it updates the file, so all changes made to resource information in the map will become permanent. If you want any of the changes to be temporary, you'll have to restore the original information before the file is updated. SetResInfo does nothing in the following cases: - The resProtected attribute for the resource is set. - The given handle isn't a handle to a resource. The ResError function will return the result code resNotFound. - The resource map becomes too large to fit in memory (which can happen if a name is passed) or sufficient space for the modified resource file can't be reserved on the disk. ResError will return an appropriate Operating System result .code.

Given a handle to a resource, SetResAttrs sets the resource attributes for the resource to attrs. (Resource attributes are described above under "Resource References".) The resProt~cted attribute takes effect immediately; the others take effect the next time the resource is read in. (warning) Do not use SetResAttrs to set the resChanged attribute; you must call ChangedResource instead. Be sure that the attrs parameter passed to SetResAttrs doesn't change the current setting of this attribute. The attributes set with SetResAttrs will be written to the resource file when the f~le is updated if you follow SetResAttrs with a call to ChangedResource. However, even if 'you don't call ChangedResource for this resource, the change may be written to the resource file when the file is updat~d. See the last warning for SetResInfo (above). If the given handle isn't a handle to a resource, SetResAttrs will do nothing and the ResError function will return the result code resNotFound. PROCEDURE ChangedResource '( theResource: Handle); Call ChangedResource after changing .either the information about a resource in the resource map (as described above under SetResInfo and SetResAttrs) or the resource data for a resource, if you want the change to be permanent. Given a handle to a resource, ChangedResource sets the resChanged attribute for the resource. This attribute tells the Resource Manager to do both of the following: - write the resource data for the resource to the resource file when the file is updated or when WriteResource is called - write the entire resource map to the resource file when the file is updated (warning) If you change SetResInfo or remember that I1esource data is updated. information in the resource map with SetResAttrs and then call ChangedResource, not only the resource map but also the will be written out when the resource file

To change the resource data for a purgeable resource and make the change permanent, you have to take special precautions to ensure that the resource won't be purged while you're changing it. You can make the resource temporarily unpurgeable and then write it out with WriteResource before making it purgeable again. You have to use the Memory Manager procedures HNoPurge and HPurge to make the resource unpurgeable and purgeable; SetResAttrs can't be used because it won't 11/28/84 Rose-Anders /RMGR/RESOURCE.R

Or, instead of calling WriteResource to write the data out immediately, you can call SetResPurge(TRUE) before making any changes to purgeable resource data. ChangedResource does nothing in the following cases: - The given handle isn't a handle to a resource. The ResError function will return the result code resNotFound. - Sufficient space for the modified resource file can't be reserved on the disk. ResError will return an appropriate Operating System result code. (warning) Be aware that ChangedResource (and not WriteResource) checks to see if there's sufficient disk space to write out the modified file; if there isn't enough space, the resChanged attribute won't be set. This means that when WriteResource is called,it won't know that the resource file has been changed; it won't write out the modified file and no error will be returned. For this reason, always check to see that ChangedResource returns noErr. PROCEDURE AddResource (theData: Handle; theType: ResType; theID: INTEGER; name: Str255); Given a handle to data in memory (not a handle to an existing resource)~ AddResource adds to the current resource file a resource reference that points to the data. It sets the resChanged attribute for the resource, so the data will be written to the resource file when the file is updated or when WriteResource is called. If the given handle is empty, zero-length resource data will be written. AddResource does nothing in the following cases:
I

- The given handle is NIL or is already a handle to an existing resource. The ResError function will return the result code addResFailed. - The resource map becomes too large to fit in memory or sufficient space for the modified resource file can't be reserved on the disk. ResError will return an appropriate Operating System result code.

11/28/84 Rose-Anders

/RMGR/RESOURCE.R

RESOURCE MANAGER ROUTINES (warning) AddResource doesn't verify whether the resour'ce ID you've: passed is already assigned to another resource of the same type; be sure to call UniqueID before adding a resource. PROCEDURE RmveResource (theResource: Handle);

29

Given a handle to a resource in the current resource file, RmveResource removes the resource reference to the resource. The resource data will be removed from the resource file when the file is updated. (note) RmveResource doesn't release the memory occupied by the resource data; to do that, call the Memory Manager procedure DisposHandle after calling RmveResource. If the resProtected attribute for the resource is set or if the given handle isn't a handle to a resource in the current resource'file, /RmveResource will do nothing and the ResError function will return the result code rmvResFailed. PROCEDURE UpdateResFile (refNum: INTEGER); Given the reference number of a resource file, UpdateResFile does the following: - Changes, adds, or removes resource data in the file as appropriate to' match the map. Remember that changed resource data is written out only if you called ChangedResource (and the call was ,successful); if you did, the resource data will be written out with WriteResource. - Compacts the resource file, closing up any' empty space created when a resource was removed or made larger. (If the size of a changed resource is greater than its original size in the resource file, it's written at the end of the file rather than at its original location; the space occupied by the original is then compacted.) UpdateResFile doesn't close up any empty space created when a resource is made smaller. - Writes out the resource map of the resource file, if you ever called ChangedResource for any' resource in the file or if you added or removed a resource. All changes to resource information in the map will become permanent as a result of this, so if you want any such changes to be temporary, you must restore the original information before calling UpdateResFile. If there's no open resource file with the given reference number, _ UpdateResFile wil~ do nothing and the ResError function will return the result code resFNotFound. A refNum of 0 represents the system resource file. 11/28/84 Rose-Anders /RMGR/RESQURCE.R

,30

Resource Manager Programmer's Guide

The CloseResFile procedure calls UpdateResFile before it closes the resource file, so you only need to call UpdateResFile'yourself if you want to update the file without closing it. PROCEDURE WriteResource (theResource: Handle); Given a handle to a resource, WriteResource checks the resChanged attribute for that resource and, if it's set (which it will be if you called ChangedResource or AddResource successfully), writes its resource data to the resource file and clears its resChanged attribute. (warning) Be aware that ChangedResource (and not WriteResource) determines if sufficient disk space is available to write out the modified file; if there isn't it will clear the resChanged attribute and WriteResource will be unaware of the modifications. For this reason, always verify that ChangedResource returns noErr. If the resource is purgeable and has been purged, zero-length resource data will be written. WriteResource does nothing if the resProtected attribute for the resource is set or if the given handle isn't a handle to a resource; in the latter case, the ResError function will ,return the result code resNotFound. Since the resource file is updated when the application terminates or when you call UpdateResFile (or CloseResFile, which calls UpdateResFile), you only need to call WriteResource if you want to write out just one or a few resources immediately. (warning) The maximum size for resources to be written to a resource file is 32K bytes •. PROCEDURE SetResPurge (install: BOOLEAN); SetResPurge(TRUE) sets a "hook" in the Memory Manager such that before purging data specified by a handle, the Memory Manager will first pass the handle to the Resource Manager. The Resource Manager will determine whether the handle is that of a resource in the application heap and, if so, will call WriteResource to write the resource data for that resource to the resource file if its resChanged attribute is set (see ChangedResource and WriteResource above). SetResPurge(FALSE) restores the normal state, clearing the hook so that the Memory Manager will once again purge_without checking with the Resource Manager. ,SetResPurge(TRUE) is useful in applications that modify purgeable resources. You still have to make the resources temporarily unpurgeable while making the changes, as shown in the description of ChangedResource, but you can set the purge hook inst~ad of writing the data out immediately with WriteResource. Notice that you won't know exactly when the resource~ are being written out; most applications 11/28/84 Rose-Anders /RMGR/RESOURCE.R

RESOURCE MANAGER ROUTINES will want more control than this. If you wish, you can set your own such hook; for details, refer to the section "Memory Manager Data Structures" in the Memory Manager manual. ' Advanced Routines

31

The routines described below allow advanced programmers to have even greater control over resource file operations. Just as individual resources have attributes, an entire resource file also has attributes, which these routines manipul~te. Like the attributes of individual resources, resource file attributes are specified by bits in the lowerder byte of a word. The Resource Manager provides a predefined constant for each attribute, in which the bit corresponding to that attribute is set. CONST mapReadOnly = 128; mapCompact 64; mapChanged = 32; {set if resource file is read-only} {set to compact file on update} {set to write map on update}

When the mapReadOnly attribute is set, the Resource Manager will neither write anything to the resource file nor check whether there's sufficient space for the file on the disk when the resource map ·is modified •. (warning) If you set mapReadOnly but then later clear it, the resource file will be written even if ther~'s no room for it on the disk. This would destroy the file.

Assembly-language note: The current value of the read-only attribute is stored in the global variable ResReadOnly.
\

The mapCompact attribute causes resource file compaction to occur when the file is updated. It's set by the Resource Manager when a resource is removed, or when a resource is made larger and thus has to be written at the end of the resource file. You may want to set mapCompact to force compac~ion when you've only made resources smaller. The mapChanged attribute causes the resource map to be written to the resource file when the file is updated. It's set by the Resource Manager when you call ChangedResource or when you 'add or remove a resource. You can set mapCnanged if, for example, you've changed resource attributes only and d9n't want to tall ChangedResource because you don't want the resource data to be written out.

11/28/84 Rose-Anders

/RMGR/RESQURCE.X

32

Resource Manager Programmer's Guide

FUNCTION'GetResFileAttrs (refNum: INTEGER) : INTEGER; Given the reference number of a re'source file, GetResFileAttrs returns the resource file attributes for the file. If there's no resource file with the given reference number, GetResFileAttrs will do nothing and the Res"Error function will return. the result code resFNotFound. A refNum of 0 represents the system resource file. PROCEDURE SetResFileAttrs (refNum: INTEGER; attrs: INTEGER); Given the ,.. reference number of a resource file, SetResFileAttrs sets the resource file attributes of the file to attrs. If there's no resource file with the given reference number, SetResFileAttrs will do nothing and the ResError function will return the result code resFNotFound. A refNum of 0 represents the system resource file, but you shouldn't change its resource file attributes.

RESOURCES WITHIN RESOURCES Resources may point to other resources; this section discusses how this is normally done, for programmers who are interested in background information about resources or who are defining their own resource types. In a resource file, one resource points to another with the ID number of the other resource. For example, the resource data for a menu includes the ID number of the menu's definition procedure (a separate resource that determines how the menu looks and behaves). To work with the resource data in memory, however, it's faster and more convenient to have a handle to the other resource rather than its ID number. Since a handle occ~pies two words, the ID number in the resource file is followed by a word containing 0; these two words together serve as a placeholder for the handle. Once the other resource has been read into memory, these two words can be replaced by a handle to it. (See .Figure 8.)

11/28/84 Rose-Anders

/RMGR/RESOURCE.F

RESOURCES WITHIN RESOURCES

33

placeholder { for handle

10

_

.... ,

0

.l
menu

· ·

·

.. ,

Appl i cat ion's resource

f; Ie

menu definition procedure

Memory handle
. . master

,

pointe~

.... ,

~~

· · ·

l

menu menu definition
procedure

Figure 8. (note)

How Resources Point to Resources

The practice of using th~ ID number followed by 0 as a placeholder is simply a convention. If you like, you can set up your own resources to have the In number followed by a dummy word, or even a word of useful information, or you can put the In in the second rather than the first word of the placeholder. In the case of menus, the Menu Manager function GetMenu calls the Resource Manager to read the menu ~nd the menu definition procedure into memory, and then replaces the placeholder in the menu with th~ handle to the procedure. There may be other cases where you call the Resource Manager directly and store the handle in the placeholder yourself. It might be useful in these cases to call HomeResFile to learn which resource file the original resource is located in, and. then, before getting the resource it points to, 'call UseResFile to set the current resource file to that file. This will ensure that the resource pointed to is read from that same file (rather than one that was opened after it).
(war~ing)

If you modify a resource that points to another resource and you make the change permanent by calling ChangedResource, be sure you reverse the process described here, restoring the other resource's ID number in the placeholder.

11/28/84 Rose-Anders

/RMGR/RESOURCE.F

34

Resource Manager Programmer's Guide

FORMAT OF A RESOURCE FILE You need to know the exact format of a resource file, described below, only if you're writing a program that will create or modify resource files directly; you don't have to know it to be able to use the Resource Manager routines.

As illustrated in Figure 9, every resource file begins with a resource header. The resource header gives the offsets to and lengths of the resource data and resource map parts of the file, as follows: Number of bytes 4 bytes 4 bytes 4 bytes 4 bytes (note) All offsets and lengths in the resource file are given in bytes. This is what immediately follows the resource header: Number of bytes 112 bytes 128 bytes Contents Partial copy of'directory entry for this file Available for application data The application data may be Contents Offset from beginning of resource file to resource data Offset from beginning of resource file to resource map Length of resource data Length of resource map

The directory copy is used by the Finder. whatever you want.

11/28/84 Rose-Anders

/RMGR/RESOURCE.F

FORMAT OF A RESOURCE FILE The resource data follows the application data. following for each resource in the file: Number of bytes For each resource: 4 bytes n bytes Contents Length of foilowing resource data Resource data for this resource .

35

It consists of the

To learn exactly what the resource data is for a standard type of resource, see the documentation on the part of the Toolbox that deals with that resource type. After the resource data, the resource map begins as follows: Number of bytes 16 bytes 4 bytes
2 bytes 2 bytes 2 bytes 2 bytes

Contents (reserved for copy of resource header) (reserved for handle to next resource map to be searched) (reserved for file reference number) Resource file attributes Offset from beginning of resource map to type list (see below) Offset from beginning of resource map to resource name list (see below)

o o o

After reading the resource map into memory, the Resource Manager stores the indicated information in the reserved areas at the beginning of the map. The resource map continues with a type list, 'reference lists, and a resource name list. The type list contains the following: Number of bytes 2 bytes For each type: 4 bytes 2 bytes
2 bytes

Contents Number of resource types in the map minus 1 Resource type Number of resources of this type in the map minus 1 Offset from beginning of type list to reference list for resources of this type

This is followed by the reference list for each type of resource, which contains the resource references for all resources of that type. The reference lists are contiguous and in the same order as the types in the type list. The format of a reference list is as follows:

11/28/84 Rose-Anders

/RMGR/RESOURCE.F

36

Resource Manager Programmer's Guide Number of bytes For each reference of this type: 2 bytes 2 bytes 1 byte 3 bytes 4 bytes Contents Resource ID Offs~t from beginning of resource name list to length of resource name, or -1 if none Resource attributes Offset from beginning of resouce data to length of data for this resource (reserved for handle to resource)

o

The resource name list. follows the reference list and has this format:_ Number of bytes For each name: 1 byte n bytes Contents Length of following resource name Characters of resource name

Figure 10 shows where the various offsets lead to in a resource file, in general and also specifically for a resource reference.

11/28/84 Rose-Anders

/RMGR/RESOURCE.F

FORMAT OF A RESOURCE FILE
resource header and other data . resource dete
.. i

SYSTEM REFERENCES
This section gives information of historical interest only. It explains another kind of resource reference besides the one explained in the "Resource References", section above. This additional kind of reference t called a system reference t was intended to be used by the Finder t as described below. In fact t the Finder doesn't use system references, so they're not particularly useful. There are. actually two.different kinds of resource references t as illustrated in Figure 11: - Local reference. The term "resource reference"t as used earlier in this manual t refers to this type of reference. A local 11/28/84 Rose-Anders

/RMGR/RESOURCE.F

38

Resource Manager Programmer's Guide reference is an entry in the resource map that locates the resource data of a resource. If the resource data is already in memory, the local reference provides a handle to the data; otherwis~ it gives an offset to the resource data in the file. - System reference. This is also an entry in the resource map but it's a reference to a system resource. It provides a resource specification for the resource in the system resource file, which in turn leads to a local reference to the resource in that file.

resource map
Local and System References optional name are on the other those of the

Every resource reference has its own type, ID" number, and name. In the case of local references, the ID number and simply those of the resource itself. A system reference, hand, may have its own ID number and name, different from actual resource it refers to in the system resource file.

System references need not be included in an application's resource file in order for the system resources to be found, because the system resource file will be searched anyway as part of the normal search process. The major reason for having system references was to tell the Finder what system resources an application or document was using. This would ensure that those resources would accompany the applicat'ion or document should it be copied to a disk having a different system resource file on it. The Finder, however, doesn't recognize system refere~ces, which renders them i'argely ineffectual. (One remaining use for such a reference could be to provide an "alias" for a system resource.) The remainder of this section explains the use and format of system references, and discusses several routines that work with such references. 11/28/84
Ros~-Anders

/RMGR/RESOURCE.F

SYSTEM REFERENCES

39

Resource Attributes of System References As stated in the section on resource references» each reference has a set of resource attributes associated with it» and each attribute is specified by a bit in the low-order byte of a word in the resource map. In Figure 6 in that section, bit 7 of the low-order byte is shown as 0. This bit actually specifies whether or not the reference is a system reference. If you have a system reference in your resource file, this bit should be set. A predefined constant for this attribute is also provided: CONST resSysRef = 128; {set if system reference}

System

Reference~

in Resource Manager Routines

Some of the previously described Resource Manager routines take special action if the current resource file contains a system reference to the given resource: - GetResInfo will return the ID number» type» and name of the system reference'. The ID number and name may be different from those of the resource itself in the system resource file. - GetResAttrs will return the attributes of the system reference» which may be different from those of the resource itself .in the system resource file. - SetResInfo will change only the ID number and name of the system reference. - SetResAttrs will set only the attributes of the system reference. The following additional procedures can be used to add or remove a system reference. (note) If you've added or removed a system reference» the Resource Manager will write out the entire resource map when it updates the resource file. Also, file compaction will occur during the update if a system reference has been removed. PROCEDURE AddReference (theResource: Handle; theID: INTEGER; name:
~tr255);

Given a handle to a system resource, AddReference adds to the current resource file a system reference to the resource, giving it the ID number and name specified by the parameters. It sets the resChanged attribute for the resource, so the reference will be written to the resource file when the file is updated~ AddReference does nothing in 11/28/84 Rose-Anders /RMGR/RESQURCE.F

40

Resource Manager Programmer's Guide

the following cases: - The current resource file is the system resource file or already contains a system reference to the specified resource, or the given handle isn't a handle to a system resource. The ResError function will return the result code CONST addRefFailed

= -195;

{AddReference failed}

- The resource map becomes too large to fit in memory or sufficient space for the modified resource file can't be reserved on the disk. ResError will return,an appropriate Operating System result code. PROCEDURE RmveReference (theResource: Handle); Given a handle to a system resource, RmveReference removes the system reference to the resource from the current resource file. (The reference will be removed from the resource file when the file is updated.) RmveReference will do nothing and the ResError function will return the result code CONST rmvRefFailed

= -197;

{RmveReference failed}

if any of the following are true: - The resProtected attribute for the resource is set. - There's no system reference to the resource in the current resource file. - The given handle isn't a handle to a Format of System References In the section "Format of a Resource-File", the format of a resource list' actually covered only the case of a local reference; the format of a reference list containing either local ,or system references is outlined below:
syst~m

resource.

11/28/84 Rose-Anders

/RMGR/RESOURCE.F

SYSTEM REFERENCES Number of bytes For each reference of this type: 2 bytes 2 bytes 1 byte 3 bytes Contents

41

4 bytes

Resource ID Offset from beginning of resource name list to length of resource name, or -1 if none Resource attributes If local reference, offset from beginning of resource data to length of data for this resource If system reference, 0 (ignored) If local reference, 0 (reserved for handle to resource) If system reference, resource specification for system resource: in high-order word, resource ID; in low-order word, offset from beginning of resource name list to length of resource name, or -1 if none

Reference number of system resource file Reference number of current resource file Current value of mapReadOnly attribute Current value of SetResLoad Current value of ResError Pointer to resource error procedure Name of system resource file (beginning with one-byte. length)

Special Macro Name Routine name Size-aesource Macro name SizeRsrc

11/28/84

~ose-Anders

/RMGR/RESOURCE.S

46

Resource Manager Programmer's Guide

SUMMARY OF THE RESOURCE FILE FORMAT
(note) All offsets and lengths are given in bytes. Resource Header and other data
4 bytes

Length of following resource data Resource data for this resource Reserved for copy of resource header Reserved for handle to next resource map to be searched Reserved for file reference number R~source file attributes Offset to type list Offset to resource name list Number of resource types minus 1 Resource type Number of resources of this type minus 1 Offset to reference list for this type

Resource Map

Type list For

ea~h

2 bytes type: 4 bytes 2 bytes 2 bytes

Reference lists (one per type, contiguous, same order as in type list) Resource name list

Resource ID Offset to length of resource name or -1 if none Resource attributes Offset to length of resource data Reserved for handle to resource Length of following resource name Characters of resource name

data fork: The part of the file that contains data accessed via the File Manager. empty handle: fork: A pointer to a NIL master
poi~ter.

One of two parts of a file; see data fork and resource fork.

reference number: A number greater than 0, returned when a file is opened, by which you can refer to that file. In Resource Manager routines that expect a reference number, 0 represents the system resource file. resource: Data or code stored in a resource file and managed by the Resource Manager. resource attribute: One of several characteristics, specified by bits in a resource reference, that determine how the resource should be dealt with. resource data: In a resource file, the data that comprises a resource.

resource file: The resource fork of a file, which contains data used by the application (such as menus, fonts, and icons) and also the app1icat,ion code it~e1f. resource fork: The part of the file"that contains the resources used by an application (such as menus, fonts, and icons) and also the application code itself; usually accessed via the Resource Manager. resource header: At the beginning of a resource file, data that gives the offsets to and lengths of the resource data and resource map. resource ID: A number that, together with the resource type, identifies a resource in a resource file. Every resource has an ID number. resource map: In a resource file, data that is read into memory when the file is opened and that, given a resource specification, leads to the corresponding resource data. resource name: A string that, together with the resource type, identifies a resource in a resource file. A resource mayor may not have a name. resource reference: In a resource map, an entry that identifies a resource and contains either an offset to its resource data in the resource file or a handle to the data if it's already been read into memory.

11/28/84 Rose-Anders

/RMGR/RESOURCE.G

48

Resource Manager Programmer's Guide

resource specification: res,ource name.

A resource type and either a resource ID or a

resource type:. The type of a resource in a resource file, designated by a sequence of four characters (such as 'MENU' for a menu). system resource:

A resource in the system resource file.

system resource file: A resource file containing standard resources, accessed if a requested resQurce wasn't found in any of the other resource fIles that were searched.

11/28/84 Rose-Anders

/RMGR/RESOURCE.G

MACINTOSH PUBLICATIONS QuickOraw: See Also: A Programmer's Guide Macintosh User Interface Guidelines Macintosh Operating System Reference Manual The Window Manager: A Programmer's Guide First Draft Revised and Edited Revised and Edited Errata Added Revised Revised for ROM 2.1 C. C. C. C. C. C. Espinosa Espinosa Rose Rose Rose Rose 11/27/81 2/15/82 8/16/82 8/19/82 11/15/82 3/2/83 ABSTRACT This document describes the QuickDraw graphics package, heart of-the Macintosh User Interface Toolbox routines. It describes the conceptual and physical data types used by QuickDraw and gives details of the procedures and functions available in QuickDraw. Summary of significant changes and additions since last version: - "Font" no longer includes type size. There is a new grafPort field (txSize) and a procedure (TextSize) for specifying the size (pages 25, 43). Some other grafPort fields were reordered and some global variables were moved to the grafPort (page 18). - The character style data type was renamed Style and now includes two new variations, condense and extend (page 23). - You can set up your application now to produce color output when devices supporting it are available in the future (pages 30, 45). - The Polygon data type was changed (page 33), and the PolyNext procedure was removed. - There are two new grafPort routines, InitPort and ClosePort (pages 35, 36), and three new calculation routines, EqualRect and EmptyRect (page 48) and EqualPt (page 65). - XferRgn and XferRect were removed; use CopyBits, PaintRgn, FillRgn, PaintRect, or FillRect. CursorVis was also removed; use HideCursor or ShowCursor. - A section on customizing QuickDra\\T operations was added (page 7(/1). /QUICK/QUIKDRAW

This manual describes QuickDraw, a set of graphics procedures, functions, and data types that allow a Pascal or\ assembly-language programmer of Macintosh to perform highly complex graphic operations very easily and very quickly. It covers the graphic concepts behind QuickDraw, as well as the technical details of the data types, procedures, and functions you will use in your programs. ' ( hand) This manual describes version 2.1 of the ROM. In earlier versions, QuickDraw may not work as discussed here. We assume that you are familiar with the Macintosh User Interface Guidelines, Lisa Pascal, and the Macintosh Operating System's memory management. This graphics package is for programmers, not end users. Although QuickDraw may be used from either Pascal or assembly language, this manual gives all examples in their Pascal form, to be clear, concise, and more intuitive; a section near the end describes the details of the assemb"ly-language interface to QuickDraw. The manual begins with an introduction to QuickDraw and what you can do with it. It then steps back a little and looks at the mathematical concepts that form the foundation for QuickDraw: coordinate planes, points, and rectangles. Once you understand these concepts, read on about the gr,aphic entities based on those concepts -- how the mathematical world of planes and rectangles is translated into the physical phenomena of light and shadow. Then comes some discussion of how to use several graphics ports, a summary of the basic drawing process, and a discussion of two more parts of QuickDraw, pictures and polygons. Next, there's the detailed description of all QuickDraw procedures and functions, their parameters, calling protocol, effects, side effects, and so on -- all the technical information you'll need each time you write a program for Macintosh. Following these descriptions are sections that will not be of interest to all readers. Special information is given for programmers who want to customize QuickDraw operations by overriding the standard drawing procedures, and for those Who will be using QuickDraw from assembly language. Finally, the~e's a summary of the QuickDraw data structures and routine calls, for quick reference'l and a glossary that' explains terms that may be unfamiliar to you.

3/2/83 Espinosa-Rose

/QUICK/QUIKDRAW.2

4

QuickDraw Programmer's Guide

ABOUT QUICKDRAW

------------------------

QuickDraw allows you to divide the Macintosh screen Into a number of individual areas. Within each area you can draw many things, as illustrated in Figure 1 •

Text.
Bold /f8//C. UnderlIne
@!ffilfiH~

._ Lines

(P.eetangles

I

~~~ DOICJO
I

~
k...1 F~ ellI·l(lF·~ pc-t,::,
",_'.. ',. 1._' __

:~::\~::~ ~)~~i· :~::~)
/~·I
Samples of QuickDraw's Abilities

(-'~JO
....---~

DtP! CzuCz

Figure 1. You can draw:

Text characters in a number of proportionally-spaced fonts, with variations that include boldfacing, italicizing, underlining, and outlining. - Straight lines of any length and width. - A variety of shapes, either solid or hollow, including: rectangles, with or without rounded corners; full circles and ovals or wedge-shaped sections; and polygons. - Any other arbitrary shape or collection of shapes, again either solid or hollow. - A picture consisting of any combination of the above items, with just a single procedure call. In addition, QuickDraw has some other abilities that you won't find in many other graphics packages. These abilities take care of most of the "housekeeping" -- the trivial but time-consuming and bothersome overhead that's necessary to keep thlngs in order. - The ability to define many distinct "ports" on the screen, each with its own complete drawing environment -- its own coordinate system, drawing location, character set, location on the screen, and so on. You can easily switch from one such port to another. 3/2/83 Espinosa-Rose /QUICK/QUIKDRAW.2

ABOUT QUICKDRAW - Full and complete "clipping" to arbi trary areas·, so that drawing will occur only where you want. It's like a super-duper coloring book that won't let you color outside the lines. You don't have to worry about accidentally drawing over something else on the screen, or drawing off the screen and destroying memory.

5

- Off-screen drawing. Anything you can draw on the screen, you can draw into an off-screen buffer, so you can prepare an image for an output device without disturbing the screen, or you can prepare a picture and move it onto the screen very quickly. And QuickDraw lives up to its name! It's very fast. The speed and responsiveness of the Macintosh user interface is due primarily to the speed of the QuickDraw package. You can do good-quality animation, fast interactive graphics, and complex yet speedy text displays using the full features of QuickDraw. This means you don't have to bypass the general-purpose QuickDraw routines by writing a lot of special routines to improve speed. How To Use QuickDraw QuickDraw can be used from either Pascal or MC68~~~ machine language. It has no user interface of its own; you must write and 'compile (or assemble) a Pascal (or assembly-language) program ·that includes the proper QuickDraw calls, link the resulting object code with the QuickDraw code, and execute the linked o1?je.ct file. Some programming models are available t~rough your Macintosh software coordinator; they show the structure of a properly organized QuickDraw program. What's best for beginners is to obtain a machine-readable version of the text of one of these programs, read through the text, and, using the superstructure of the program as a "shell", modify it to suit your own purposes. Once you get the hang of writing programs inside the presupplied shell, you can work on changing the shell itself. QuickDraw is stored permanently in the ROM memory. All access is made through an indirection table in low RAM. '~en you write a program that uses QuickDraw, you link it with this indirection table. Each time you call a QuickDraw procedure or function, or load a predefined constant, the request goes through the table into QuickDraw. You'll never access any QuickDraw address directly, nor will you have to code constant addresses into your program. The linker will make sure all address references get straightened out. QuickDraw is an independent unit; it doesn't use any other units, not even HeapZone (the Pascal interf~ce to the Operating System's memory management routines). This means it cannot use the data types Ptr and Handle, because they are defined in HeapZone. Instead, QuickDraw defines two data types that are equivalent to Ptr· and Handle, QDPtr and QDHandle.

3/2/83 Espinosa-Rose

/QUICK/QUIKDRAW.2

6

QuickDraw Programmer's Guide TYPE QDByte QDPtr QDHandle

= -128 .. 127;

= . . QDByte;
. . QDPtr;

QuickDraw includes only the graphics and utility procedures and functions you'll need to create graphics on the screen. Keyboard input, mouse input, and larger user-interface constructs such as windows and menus are implemented in separate packages that use QuickDraw but are linked in as separate units. You don't need these units in order to use QuickDraw; however, you'll probably want to read the documentation for windows and menus and learn how to use them with your Macintosh programs.

THE MATHEMATICAL FOUNDATION OF QUICKDRAW To create graphics that are both precise and pretty requires not supercharged'features but a firm mathematical foundation for the features you have. If the mathematics that underlie a graphics package are imprecise or fuzzy, the graphics will be, too. QuickDraw defines some clear mathematical constructs that are widely used in its procedures, functions, and data types: the coordinate plane, the point, the rectangle, and the region. The Coordinate Plane All information about location, placement, or movement that you give to QuickDraw is in terms of coordinates on a plane. The coordinate plane is a two-dimensional grid, as illustrated in Figure 2.

t

Figure 2.

The Coordinate Plane

There are two distinctive features of the QuickDraw coordinate plane:

3/2/83 Espinosa-Rose

/QUICK/QUIKDRAW.2

THE MATHEMATICAL FOUNDATION OF QUICKDRAW - All grid coordinates are integers. - All grid lines are infinitely thin. These concepts are important! First, they mean that the QuickDraw plane is finite, not infinite (although it's very large). Horizontal coordinates range from -32768 to +32767, and vertical coordinates have the same range. (An auxiliary package is available that maps real Cartesian space., with X, Y, and Z coordinates, onto QuickDraw's two~dimensional integer coordinate system.)

7

Second, they mean that all elements represented on the coordinate plane are mathematically pure. Mathematical calculations using integer arithmetic will produce intuitively correct results. If you keep in mind that grid lines are infinitely thin, you'll never have "endpoint paranoia" -- the confusion thaf results from not knowing whether that last dot is included in the line. Points On the coordinate plane are 4,294,967,296 unique points. Each point is at the intersection of a horizontal grid line and a vertical grid line. As the grid lines are infinitely thin, a point is infinitely small. Of course there are more points on this grid than there are dots on the Macintosh screen: when using QuickDraw you associate small parts of the grid with areas on the screen, so that you aren't bound into an arbitrary, limited coordinate system. The coordinate origin (0,0) is in the middle of the grid. Horizontal coordinates increase as you move from left to right, and vertical coordinates increase as you.move from top to bottom. This is the way both a TV screen and a page of English text are scanned: from the top left to the bottom right. You can store the coordinates of a point into a Pascal variable whose type is defined by QuickDraw. The type Point is a record of two integers, and has this structure: TYPE VHSelect = (V,H); = RECORD CASE INTEGER OF Point
~:

(v: h: (vh:

INTEGER; INTEGER); ARRAY [VHSelect] OF INTEGER)

1: END;

The variant part allows you to access the vertical and horizontal components of a point either individually or as an array. For example, if the variable goodPt were declared to be of type ?oint, the following would all refer to the coordinate parts of the point:

Rectangles Any two points can define the top left and bottom right corners of a rectangle. As these points are infinitely small, the borders of the rectangle are infinitely thin (see Figure 3).

left.

Top

_JIL

Bon:orn.
~~t~3hf

Figure 3.

A Rectangle

Rectangles are used to define active areas .on the screen, to assign coordinate systems to graphic entities, and to specify the locations and sizes for various drawing cOlllmands. QuickDraw also allows you to perform many mathematical calculations on rectangles -- changing their sizes, shifting them around, and so on. ( hand) Remember that rectangles, like points, are mathematical concepts that have no direct representation on the screen. The association between these conceptual elements and their physical representations is made by.a bitMap, described below. The data type for rectangles is called Rect, and consists of four integers or two points:

3/2/83 Espinosa-Rose

/QUICK/QUIKDRAW.2

THE MATHEMATICAL FOUNDATION OF QUICKDRAW TYPE Rect = RECORD CASE INTEGER OF
~:

9

(top: left: bottom: right: (topLeft: botRight:

INTEGER; INTEGER; INTEGER; INTEGER); Point; Point)

1:

END; Again, the record variant allows you to access a .variable of type Rect either as four boundary coordinates or as two diagonally opposing corner points. Combined with the record variant for points, all of the following references to the rectangle named bRect are legal: bRect bRect.topLeft bRect.top bRect.topLeft.v bRect.topLeft.vh[V] bRect.bottom bRect.botRight.v bRect.botRight.vh[V] ( eye) If the bottom coordinate of a rectangle is equal to or less than the top, or the right coordinate is equal to or less th~n the left, the rectangle is an empty rectangle (i.e., one that contains no bits). Regions Unlike most graphics packages that can manipulate only simple geometric structures (usually rectilinear, at that), QuickDraw has the unique and amazing ability to gather an arbitrary set of spatially cohere'nt points into a structure called a region, and perform complex yet rapid manipulations and calculations on such structures. This remarkable feature not only will make your standard programs simpler and faster, but will let you perform operations that would otherwise be nearly impossible; it is fundamental to the Macintosh user interface. You define a region by drawing lines, shapes such as rectangles and ovals, or even other regions. The outline of a region should be one or more closed loops. A region can be concave or convex, can consist of one area or many disjoint arefls, and can even have "holes" in the middle. In Figure 4, th~ region on the left has a hole in. the middle, and the region on the right consists of two disjoint areas. bRect.botRight bRect.left bRect.topLeft.h bRect.topLeft.vh[HJ bRect.right bRect.botRight.h bRect.botRight.vh[H] {type Rect} {type Point} {type INTEGER} {type INTEGER} {type INTEGER} {type INTEGER} {type INTEGER} {type INTEGER}

3/2/83 Espinosa-Rose

/QUICK/QUIKDRAW.2

10

QuickDraw Programmer's Guide

Figure 4.

Regions

Because a region can be any arbitrary area or set of areas on the coordinate plane, it takes a variable amount 'of information to store the outline of a region. The data structure for a region, therefore, is a variable-length entity with two fixed fields at the beginning, followed by a variable-length data field: TYPE Region

The rgnSize field contains the size, in bytes, of the region variable. The rgnBBox field is a rectangle Which completely encloses the region. The simplest region is a rectangle. In this case, the rgnBBox field defines .the entire region, and there is no optional region data. For "rectangular regions (or empty regions), the rgnSize field contains 10. The region definition data for nonrectangu1ar regions is stored in a compact way which allows for highly efficient access by QuickDraw procedures. As regions are of variable size, they are stored dynamically on the heap, 'and the Operating System's memory management moves them around as their sizes change. Being dynamic, a region can be accessed only through a pointe~; but When a region is movad, all pointers referring to it must be updated. For this reason, all regions are accessed through handles, which point to one master pointer which in turn points to the region. TYPE RgnPtr RgnHand1e 3/2/83 Espinosa-Rose

=

= ""Region;
""RgnPtr; /QUICK/QUIKDRAW.2

THE MATHEMATICAL FOUNDATION OF QUICKDRAW

11

When the memory management relocates a region's data in memory, it updates only the RgnPtr master pointer to that region. The references through the master pointer can find the region's new home, but any references pointing directly to the region's previous position in memory would now,point at dead bits. To acc~ss individual fields of a region, use the region handle and double indirection: myRgn ....... rgnSize myRgn ....... rgnBBox myRgn ....... rgnBBox.top myRgn .... rgnBBox {size of region whose handle is myRgn} {rectangle enclosing the same region} {minimum vertical coordinate of all points in the region} {syntactic'ally incorrect; will not compile if myRgn is a rgnHandle}

Regions are created by a QuickDraw function which allocates space for the region, creates a master pointer, and returns a rgnHandle. When you're done with a region, you dispose of it with another QuickDraw routine which frees up the space used by the region. Only these calls allocate or deallocate regions; do 'NOT use the Pascal procedure NEW to create a new region! You specify the outline of a region with procedures that draw lines and shapes, as described in the section "QuickDraw Routines". An example is given in the discussion of CloseRgn under "Calculations with Regions" in that section. Many calculations can be performed on regions. A region can be "expanded" or "shrunk" and, given any two regions, QuickDraw can find their union, intersection, difference, and exclusive-OR; it can also determine whether a given point or rectangle intersects a given region, and so on. There is of course a set of graphic operations on regions to draw them on the screen.

GRAPHIC ENTITIES Coordinate planes, points, rectangles, and regions are all go04 mathematical models, but they aren't really graphic elements -- they don't have a direct physical appearance. Some graphic entities that do have a direct graphic interpretation are the bit image, bitMap, pattern, and cursor. This section describes the data structure of these graphic entities and how they 'relate to the mathematical constructs described above.

3/2/83 Espinosa-Rose

/QUICK/QUIKDRAW.2

12

QuickDraw Programmer's Guide

The Bit Image A bit image is a collection of bits in memory which have a rectilinear representation. Take a collection of words in memory and lay them end to end so that bit 15 of the lowest-numbered word is on the left and bit 0 of the highest-numbered word is on the far right. Then take this array of bits and divide it, on word boundaries, 'into a number of equal-size rows. Stack these rows vertically so that the first row is on the top and the last row is on the bottom. The result is a matrix like the one shown in Figure 5 -- rows and columns of bits, with each row containing the same number of bytes. The number of bytes in each row of the bit image is called the row width of that ima'ge.

firSt:

Ro~p

V'/hith, is
8 tJ1JI)JS

Lo..st.
81=~t~~:

Figure 5.
A

A Bit Image

bit image can be stored in any static or dynamic variable, and can be of any length that is a multiple of the row width.

The Macintosh screen itself is one large visible bi t image. The upper 21,888 bytes of memory are displayed as a matrix of 175,104 pixels on the screen', each bi t corresponding to one pixel. If a bi t' s yalue is 0, its pixel is white; if the bit's value is 1, the pixel is black. The screen is 342 pixels tall and 512 pixels wide, and the .row width of its bit image is 64 bytes. Each pixel on the screen is'squar~; there are 72 pixels per inch in each direction. ( hand) Since each pixel on the screen represents one bit in a bit image, wherever this document says "bit", you can substitute "pixel" if the bit image is the Macintosh _ screen. Likewise, this document often refers to pixels on the screen where the discussion applies equally to bits in an off-screen bit image.

3/2/83 Espinosa-Rose

/QUICK/QUIKDRAW.2

GRAPHIC ENTITIES

13

The BitMap When you combine the physical entity of a bit image with the conceptual entities of the coordinate plane and rectangle, you get a bitMap. A bitMap has three parts: a pointer to a bit image, the. row width (in bytes) of that image, and a boundary rectangle which gives' the bitMap both its dimensions and a coordinate system. Notice that a bitMap does not actually include the bits themselves: it points to them. There can be several bi tMaps pointing to the same bi t image, each imposing a different coordinate system on it. This important feature is explained more fully in "Coordinates in GrafPorts", below. As shown in Figure 6, the data structure of a bitMap is as follows: TYPE BitMap

= RECORD
baseAddr: rowBytes: bounds: END; QDPtr; INTEGER; Rect

Base:

;a,

1~I(jlt.reSS

rcn·VB1..JH::S

bouruis

Figure 6.

A BitMap

The baseAddr field is a pointer to the beginning of the hit image in memory, and the rowBytes field is the number of bytes in each row of the image. Both of these should always be even: a bitMap should always begin on a word boundary and contain an integral number of words in each row. The bounds' field is a boundary rectangle that both encloses the active area of the bit image and imposes a coordinate system on it. The relationship between the boundary rectangle ann the bit image in a bitMap is simple yet very important. First, a few general rules:

3/2/83 Espinosa-Rose

/QUICK/QUIKDRAW.2

14

QuickDraw Programmer's Guide

- Bits in a bit image fall between points on the coordinate plane. - A rectangle . divides a bit image into two sets of bits: inside the rectangle and those outside the rectangle. those bits

- A rectangle that is H points wide and V points tall encloses exactly (H-1)*(V-1) bits. The top left corner of the boundary rectangle is aligned around the first bit in the bit image. The width of the rectangle determines how many bits of one row are logically owned by the hitMap; the relationship 8*map.rowBytes
)=

map. bounds. right-map. bounds. left

must always be true. The height of the rectangle determines how many rows of the image are logically owned by the bitMap; the relationship SIZEOF(map.baseAddr
A )

)=

(map.bounds.bottom-map.bounds.top) * map.rowBytes

must always be true/to ensure that the number of bits in the logical bitMap area is not larger than the number of bits in the bit image. Normally, the boundary rectangle completely encloses the bit image: .the wi?th of the boundary rectangle is equal to the number of bi ts in one row of the image, and the height of the rectangle is equal to the number of rows in the image. If the rectangle is smaller than the dimensions of the image, the least significant bits in each row, as well as the last rows in the image, are not affected by any operations on the bitMap. The bi tMap -also imposes a coordinate system on the image. Because bi ts fall between coordinate points, the coordinate system assigns integer values to the lines that border and separate bits, not to the bit positions themselves. For example, if a bitMap is assigned the boundary rectangle with corners (10,-8) and (34,8), the bottom right bit in the image will be between horizontal coordinates 33 and 34, and between vertical coordinates 7 and 8 (see Figure 7).

3/2/83 Espinosa-Rose

/QUICK/QUIKDRAW.2

GRAPHIC ENTITIES

15

\

•
Figure 7. Coordinates and BitMaps

Patterns A pattern is a 64-bit image, organized as an 8-by-8-bit 'sqlmre, which is used to define a repeating oesign (such as stripes) or tone (~uch as gray). Patterns can be used to draw lines and shapes or to fill areas on the screen.
~Vhen

a pattern is drawn, it is ,aligned such that adjacent areas of the same pattern in the same graphics port will blend with it into a continuous, coordinated pattern. QuickDraw provides the predefined patterns white, black, gray, ItGray, and dkGray. Any other 64-bit variable or constant can be used as a pattern, too. The data ~ype definition for a pattern is as fo~lows: TYPE Pattern The row width of _a Cursors

=

PACKED ARRAY

[0 •• 7] OF 0•• 255;

patter~

is 1 byte.

A cursor is a small image that appears on the screen and is controlled by the mouse. (It appears only on the screen,- and never in an off-screen bit image.) ( hand) Other Macintosh documentation "pointer", since it points to To avoid confusion with other this manual and other Toolbox alternate term "cursor". 3/2/83 Espinosa-Rose calls this image a a location on the screen. meanings of "pointer" in documentation, we use the

/QUICK/QUIKDRAW.2

16

QuickDraw Programmer's Guide

A cursor is defined as a 256-bit image, a 16-by-16-bit square. The row - width of a cursor is 2 bytes. Figure 8 illustrates four cursors.

- I lJ--

o

9

,-.

(.I

Figure 8.

Cursors

A cursor has three fields: a 16-word data field that contains the image itself, a 16-word mask field that contains information about the screen appearance of each bit of the cursor, and a hotSpot point that aligns the cursor with the position of the mouse. TYPE Curso'r = RECORD data: mask: \ hotSpot: END; ARRAY [0 •• 15] OF INTEGER; ARRAY [0 •• 15] .OF INTEGER; Point

The data for the cursor must begin on a word boundary. The cursor appears on the screen as a 16-by-16-bit square. The appearance of each bit of the square is determined by the corresponding bits in the data and mask and, if the mask bit is ~, by the pixel "under" the cursor (the one already on the screen in the same position as this bit of the cursor):

-01 1

Data

Mask -11
~ ~

0

Resulting pixel on screen White Black Same as pixel under cursor Inverse of pixel under cursor

Notice that if all mask bits are ~, the cursor is completely transparent, in that the image under the cursor can still be viewed: pixels under the white part of the cursor appear unchanged, while under the black part of the cursor, black pixels show through as white.

3/2/83 Espinosa-Rose

/QUICK/QUIKDRAW.2

GRAPHIC ENTITIES

17

-The hotSpot aligns a point in the image (not a bit, a point!) with the mouse position. Imagine the rectangle with 'c'orners (9},9}) and (16,16) framing the image, as in each of the examples in Figure 8; the hotSpot is defined in this coordinate system. A hotSpot of (9},9}) is at the top left of the image. For the arrow in Figure 8 to point to the mouse position, (9},9}) would be its hotSpot. A hotSpot of (8,8) is in the exact center of the image; the center of the plus sign or circle in Figure 8 would coincide with the mouse position if (8,8) were the hotSpot for that cursor. Similarly, the hotSpot for the pointing hand would be (16,9). Whenever you move the mouse, the low-level interrupt-driven mouse routines move the cursor's hotSpot to be aligned with the new mouse position. ( hand) The mouse position is always linked to the cursor position. You can't reposition the cursor through software; the only control you have is whether it's visible or not, and what shape it will assume. Think of it as being hard-wired: if the cursor is visible, it always folJows the mouse over the full size of the screen. QuickDraw supplies a predefined arrow cursor, an arrow pointing north-northwest.

THE DRAWING ENVIRONMENT:
J

GRAFPORT
~----------------------------------------------

A grafPort is a complete drawing environment that defines how and where graphic operations will have their effect. It contains all the information about one instance of graphic output that is kept separate from all other instances. You can have many grafPorts open at once, and each one will have its own coordinate system, drawing pattern, background pattern, pen size and location, character font and style, and .bitMap in which drawing takes place. You can instantly switch from one port to another. GrafPorts are the structures on which a program builds windows, which are fundamental to the Macintosh "overlapping windows" user interface.

All QuickDraw operations refer to grafPorts via grafPtrs. You create a grafPort with the Pascal procedure NEW and use the resulting pointer in calls to QuickDraw. You could, of course, declare a static VAR of type grafPort, and obtain a pointer to that static structure (with the @ operator), but as most grafPorts will be used dynamically, their data structures should. be dynamic also. ( hand) You can access all fields and subfields of a grafPort normally, but you should not store new values directly into them. QuickDraw has procedures for altering all fields of a grafPort, and using these procedure~ ensures that changing a grafPort produces no unusual side effects. The device'field of a grafPort is the number of the logical output device that the grafPort will be using. The Font Manager uses this information, since there are physical differences in the same logical font for different output devices. The default device number is ~, for the Macintosh screen. For more information about device numbers, see the *** not yet existing *** Font Manager documentation.

The portBits field is the bitMap that points to the bit image to be used by the grafPort. All drawing that is done in this grafPort will take place in this bit image. The default bitMap uses the entire Macintosh screen as its bit image t with rowBytes of 64 and a boundary rectangle of (0 t 0 t 5l2 t 342). The bitMap may be changed to indicate a different structure in memory: all graphics procedures work in exactly the same way regardless of whether their effects are visible on the screen. A program cant for example t prepare an image to be printed on , a printer without ever displaying the image on the screen t or develop a picture in an off-screen bitMap before transferring it to the screen. By altering the coordinates of the portBits.bounds rectangle, you can change the coordinate system of the grafPort; with a QulckDraw procedure call t you can set an arbitrary'coordinate system for each grafPort t even if the different grafPorts all use the same bit image (e.g.'t the full screen). The portRect field is a rectangle that defines a subset of the bitMap for use by the grafPort. Its coordinates are in the system defined by the portBits.bounds rectangle. All drawing done by the application occurs inside this rectangle. The portRect usually defines the "writable" interior area of a window t document, or other object on the screen. The visRgn field is manipulated by the t·1indow Manager; users and programmers will normally never change a grafPort's visRgn. It indicates that region (remember t an arbitrary area or set _of areas) which is actually visible on the screen. For example, if you move one window in front of another, the Window Manager logically removes the area of overlap from the visRgn of the window in the back. ~~en you draw into the back window, whatever's being drawn is clipped to the visRgn so that it doesn't run over onto the front window. The default visRgn is set to the portRect. The visRgn has no effect on images that are not displayed on the screen. The clipRgn is an arbitrary region that the application can use to limit drawing to any region within the portRect. If, for example, you want to draw a half circle on the screen, you can set the clipRgn to half the square that would enclose the whole circle, and go ahead and draw the whole circle. Only the half within the clipRgn will actually be drawn in the grafPort. The de'fault clipRgI! is set arbi trarily large, and you have~full control over its setting. Notice that unlike the visRgn, the clipRgn affects the image even if it is not displayed on the screen. Figure 9 illustrates a typical bitMap' (as defined by portBfts), portRect, visRgnt and clipRgn.

3/2/83 Espinosa-Rose

/QUICK/QUIKDRAW.3

I~

Chapter 1

Introduction

190 I

Part III: The 68000 Assembly-Language SANE Engine

\

The purpose of the software package described in Part III of this manual is. to provide the features of the Standard Apple Numeric Environment (SANE) to assembly-language programmers using Apple's 68000-based systems. SANE -described in detail in Part I-fully supports the IEEE Standard (754) for Binary Floating-Point Arithmetic, and augments the Standard to provide greater utility for applications in accounting, finance, science, and' engineering. The IEEE Standard and SANE offer a combination of quality, predictability, and portability heretofore unknown for numerical software. A functionally equivalent 6502 assembly-language SANE engine is available for Apple's 6502-based systems. Thus numerical algorithms coded in assembly language for an Apple 68000-based system can be readily recoded for an Apple 6502-based system. We have chosen macros for accessing the 6502 and 68000 engines to make it easier to port algorithms from one system to the other. Part III of this manual describes the use of the 68000 assembly-language SANE engine, but does not describe SANE itself. For example, Part III explains how to call the SANE .remainder function from 68000 assembly language, but does not discuss what this function does. See Part I for information about the semantics of SANE. See Appendix A for information about accessing the 68000 SANE engine from the Apple 68000-based systems.

FSU8S is an assembly-language macro taken from the file listed in Appendix 8. The form of the operation in the example (8 - 8 - A, where A is a numeric type and 8 is extended) is similar to the forms Jor most FP68K operations. Also, this example is typical of SANE engine calls because operands are passed to FP68K by pushing the addresses of the operands onto the stack prior to the call. Details of SANE engine access are given later in this chapter. The SANE elementary functions are provided in Elems68K. Access to Elems68K is similar to access to FP86K; details are given in Chapter 9.

Chapter 2: Basics
)

•

Operation Forms
The example above illustrates the form of an FP68K binary operation. Forms for other FP68K operations are described in this section. Examples and furthe~ details are given in subsequent chapters.

The operation <op> is applied to (or operates on) the operand DST and the result is returned to DST, overwriting the previous value. DST is called the destination operand. FP68K provides binary operations in a two-address form: DST DST < op > SRC ... for example, B B/A

The operation < op > is applied to the operands DST and SRC and the result is returned to DST, overwriting the previous value. SRC is called the source operand. In order to store the result of an operation (unary or binary), the location of the operand DST must be known to FP68K, so DST is passed by address to FP68K. In general all operands, source and destination, are passed by address to FP68K. For most operations the storage format for a source operand (SRC) can be one of the SANE numeric formats (single, double, extended, or comp). To support the extended-based SANE arithmetic, a destination operand (DST) must be in the extended format. The forms for the copysign next-after functions are unusual and are discussed in Chapter 4.

1941

Part III: The 68000 Assembly-Language SANE Engine

Conversions
FP68K provides conversions between the extended format and other SANE formats, between extended and 16- or 32-bit integers, and between extended and decimal records. Conversions between binary formats (single, double, extended, comp, and integer) and conversions from decimal to binary have the form DST SRC

Conversions from binary to decimal have the form DST SRC according to SRC2

where SRC2 is a DecForm record specifying the decimal format for the conversion of SRC to DST.

Comparisons
Comparisons have the form

< relation> -

SRC, DST

where DST is extended and SRC is single, double, camp, or extended, and where < relation> is less, equal, greater ~ or unordered according as DST < relation> SRC Here the result < relation> is indicated by setting the 68000 CCR flags.

Other Operations
FP68K provides inquiries for determining the class and sign of an operand and operations for accessing the floating-point environment word and the halt address. Forms for these operations vary and are given as the operations are introduced.

Chapter 2: Basics

•

External Access
The SANE engine, FP68K, is reentrant, position-independent code, which may be shared in multiprocess environments. It is accessed through one entry point, labeled FP68K. Each user process has a . static state area consisting of one word of mode bits and error flags, and a two-word halt vector. The package allows for different access to the state word in single and multiprocess environments.
I

The package preserves all 68000 registers across invocations, except that REMAINDER modifies DO. The package modifies the 68000 CCR flags. Except for binary-decimal conversions, it uses little more stack area than is required to save the sixteen 32~bit 68000 registers. Because the binary-decimal conversions themselves call the package (to perform multiplies and divides), they use about twice the stack space of the regular operations. The access constraints described in this section ' Elems68K.
~Iso

The macro JSRFP in turn generates a call to FP68K; for MacintoshT~ it expands to an A-line trap, whereas for Lisae it expands to an intrinsic unit subroutine call
JSR FP68K.

1961

Part III: The 68000 Assembly-Language SANE Engine

The Opword
The opword is the logical OR of an operand format code and an operation code. The operand format code specifies the format (extended, double, single, integer, or comp) of one of the operands. The operand format code typically gives the format for the source operand (SRC). At most one operand format need be specified, because other operands' formats are implied. The operation code specifies the operation to be performed by FP68K. (Opwords are listed in Appendix C; operand format codes and operation codes are listed in Appendix B.)

Example
The format code for single is 1000 (hex). The operation code for divide is 0006 (hex). Hence the opword 1b06 (hex) indicates divide by a value of type single. .

Arithmetic Abuse
FP68K is designed to be as robust as possible, but it is not bullet-proof. Passing the wrong number of operands to the engine damages the stack. Using UNDEFINED opword parameters or passing incorrect addresses produces undefined results .

.Chapter 2: Basics

20

QuickDraw Programmer's Guide

Figure 9.

GrafPort Regions

The bkPat and fillPat fields of a grafPort contain patterns used by certain QuickDraw routines. BkPat is the "background" pattern that is used when an area is erased or when bi ts are scrolled out of it. ,.]hen asked to fill an area with a specified pattern, QuickDraw stores the given pattern in the fillPat field and then calls a low-level drawing routine which gets the pattern from that field. The various graphic operations are discussed in detail later in the descriptions of individual QuickDraw routines. Of the next ten fields, the first five determine characteristics of the graphics pen and the last five.determine characteristics of any text that may be drawn; these are described in subsections below. The fgColor, bkColor ,'and colrBi t fields contain values related to . drawing in color, a capability that will be available in the future when Apple supports color output devices for the Macintosh. FgColor is the grafPort's foreground color and bkColor is its background color. ColrBit tells the color imaging software which plane of the color picture to draw into. For nire information, see "Drawing in Color" in the general discussion of drawing. The patStretch field is used during output to a printer to expand patterns if necessary. The application should not change its value. The picSave, rgnSave, and polySave fields reflect the state of picture, region, and polygon defintion, respectively. To define a region, for example, you "open" it, call routines that draw it, and then "close" it. If no region is open, rgnSave contains NIL; otherwise, it contains a handle to information related to the region definition. The application should not be concerned about exactly what information the handle leads to; you may, however, save the current value of rgnSave, set the field to NIL to disable the region definition, and later restore it to the saved value to resume the region definition. The 3/2/83 .Espinosa-Rose /QUICK/QUIKDRAW.3

The 68000 engine uses the convention that least-significant bytes are stored in high memory. For example, let us take a variable of type single with bits

s
eO ... e7

fO ... f22

sign exponent (msb .. .Isb) significand fraction (msb .. .Isb)

. Chapter 3: Data Types

The logical structure of this four-byte variable is shown below.

Order
msb lsb msb lsb

Hilllill fie! IIIIIIIIIIIIIIIIIIIII~
1000 1001

1002

1003

Memory Location
If this variable is assigned the address 1000, then its bits are distributed to the locations 1000 to 1003 as shown. The other SANE formats (see Chapter 2 in Part I)' are represented in memory in similar fashion.

The destination operand (DST) for these operations is passed by address and is generally in the extended format. The source operand (SRC) is also passed by address and may be single, double, comp, or extended. Some operations are distinguished by requiring some specific type for SRC, by using a nonextended destination, or by returning auxiliary information in the DO register and in the processor CCR status bits. In this section, operations so distinguished are noted. The examples employ the macros in Appendix B.

Chapter 4: Arithmetic Operations and Auxiliary Routines

1205 '

•

Add, Subtract, Multiply, and Divide
These are binary operations and follow the two-address form.

Example
8 - B / A , where A is double and 8 is extended.
PEA PEA FDIVD
push address of A push address of B divide with source operand of type double

•

Square Root
This is. a unary operation and follows the one-address form.

Example
8 - sqrt(8) , where B is extended.
PEA
FSQRTX

push address of B ; square root (operand is always extended)

•

Round-to'-Integer, Truncate-to-Integer
These are unary operations and follow the one-address form. Round-to-integer rounds (according to the current rounding direction) to an integral value in the extended format. Truncate-to-integer rounds toward zero (regardless of the current rounding direction) to an integral value in the extended format. The calling sequence is the usual one for unary operators, illustrated above for square root.

2061

Part III: The 68000 Assembly-Language SANE Engine

•

Remainder
This is a binary operation and follows the two-address form. Remainder returns auxiliary information: the low-order integer quotient (between -127 and + 127) in DO.W. The high half of DO.L is undefined. This intrusion into the register file is extremely valuable in argument reduction-the principal use of the remainder function. The state of DO after an invalid remainder is undefined.

Example
B - 8 rem A , where A is single and B is extended.
PEA PEA FREMS
push address of A push address of B remainder with source operand of type single

•

Logb, Scalb
Logb is a unary operation and follows the one-address form. Scalb is a binary operation and follows the two-address form. Its source operand is a 1S-bit integer. -

to copy the sign of DST onto the sign of SRC. Note that copy-sign differs from most two-address operations in that it changes the SRC value rather than the DST value. The formats of the operands of FCPYSGNX can be single, double, or extended. (For efficiency, the 68000 assembly-language programmer should copy signs directly rather than calling FP68K.)

Example
Copy the sign of B (single, double, or extended) into the sign of A (single, double, or extended).
PEA A_ADR PEA B_ADR FCPYSGNX ; push address of A ; push address of B ; cOPy-sign

2081

Part III: The 68000 Assembly-Language SANE Engine

•

Next-After
Both source and destination operands must be of the same floating-point type (single, double, or extended). The next-after operations use the calling sequence
PEA <SRC address> PEA <DST address> <next-after macro>

to effect SRC - next value, in the format indicated by the macro, after SRC in the direction of DST. Note that next-after operations differ from most two-address operations in that they change SRC values rather than DST values.

Example
A - next-after(A) in the direction of B, where A and B are double (so next-after means next-double-after).
PEA PEA FNEXTD A_ADR B_ADR push address of A push address of B next-after in double format

Chapter 4: Arithmetic Operations and Auxiliary Routines

1209

THE DRAWING ENVIRONMENT:

GRAFPORT

21

picSave and polySave fields work similarly for pictures and polygons. Finally, the grafProcs field may point to a special data structure that the application stores into if it wants to customize QuickDraw drawing procedures or use QuickDraw in other advanced, highly specialized ways. ("For more information, see "Customizing QuickDraw Operations".) If grafProcs is NIL, QuickDraw responds in the standard ways described in this manual. Pen Characteristics The pnLoc, pnSize, pnMode, pnPat, and pnVis fields of a grafPort deal with the graphics pen. Each grafPort has one and only one graphics pen, t~hich is used for drawing lines, shapes, and text. As illustrated in Figure 10, the pen has four characteristics: a location, a size, a drawing mode, and a drawing pattern.

Figure 10.

A Graphics Pen

The pen location is a point in the coordinate system of the grafPort, and is where QuickDraw will begin drawing the next line, shape, or character. It can be "anywhere on the coordinate plane: there are no restrictions on the movement or placement of the pen. Remember that the pen location is a point on the coordinate plane, not a pixel in a bit image! The pen is rectangular in shape, and has a user-definable width and height. The default size is a 1-by-1-bit square; the "width and height can range from (0,O) to (32767,32767). If either the pen width or the pen height is less than 1, the pen will not draw on the screen. - The pen appears as a rectangle wi th its top left corner at the pen location; it hangs below and to the right of the pen locat~on.

~

3/2/83 Espinosa-Rose

/QUICK/QUIKDRAW.3

Chapter 5

Conversions .

210 I

Part III: The 68000

Assembl~:-Language SANE Engine \
)

This chapter discusses conversions between binary formats and conversions between binary and decimal formats .

•

Conversions Between Binary Formats
FP68K provides conversions between the extended type and the SANE types single, double, and comp, as ~ell as the 16- and 32-bit integer types.

Conversions to Extended
FP68K provides conversions of a source, of type single, double, -comp, extended, or integer, to an extended destination.

extended

-

single double comp extended integer

All operands, even integer ones, are passed by address. The following example illustrates the calling sequence.

Example
Convert A to B, where A is of type comp and B is extended.
PEA PEA

FC2X
/

push address of A push address of B convert comp to extended

Chapter 5: Conversions

Conversions From Extended
FP68K provides conversions of an extended source to a destination of type single, double, comp, extended, or integer. single double comp extended
i~teger

-

extended

(Note that conversion to a narrower format may alter values.) Contrary to the usual scheme, the destination for these conversions need not be of type extended. All operands are passed by address. The following example illustrates the calling sequence.

Example
Convert A to B where A is extended and B is double.
PEA PEA FX2D

push address of A push address of 8 convert extended to double

•

Binary-Decimal Conversions
FP68K provides conversions between the binary types (single, double, comp, extended, and integer) and the decimal record type. Decimal records and decform records (used to specify the form of decimal representations) are described in Chapter 4 of Part I. For FP68K, the maximum length of the sig digits field of a decimal record is 20. (The value 20 is specific to this implementation: algorithms intended to port to other SANE implementations should use no more than 18 digits in sig.)

Binary ·to Decimal
The calling sequence for a conversion from a· binary format to a decimal record passes the address of a decform record, the address of a binary source operand, and the address of a decimal-record destination. The maximum number of significant digits that will be returned is 19..

2121

Part III: The .68000 Assembly-Language SANE 'Engine

Example
Convert a comp-format value A to a decimal record D according to the decform record F.
PEA PEA PEA FC20EC F_ADR A_ADR D_AOR push address push address push address convert comp of of of to F A 0 decimal

Fixed-Format "Overflow"
If a number is too large for a chosen fixed style, then FP68K returns the string I?' in the sig field of the decimal record.

Decimal to Binary
The calling sequence for a conversion from decimal to binary passes the address of a decimal-record source operand and the address of a binary destination operand. The maximum number of digits in sig is 19. If the length of sig is 20, then sig represents its first 19 digits plus one or more additional nonzero digits after the 19th. The exponent corresponds to the 19-digit integer represented by the first 19 digits of sig.

Techniques for Maximum Accuracy
The following techniques apply to FP68K; other SANE implementations require other techniques. For maximum accuracy, insert or delete trailing zeros for the sig field of a decimal record in order to minimize the magnitude of the exp field. For example, for 1.0E60 set sig to '1000000000000000000000000000' (17 zeros) and exp to 43, and for 300E-43 set sig to '3' and exp to -41.

Chapter 5: Conversions

If you are writing a parser and must handle a number with more than 19 significant digits, follow these rules: • Place the implicit decimal point to the right of the 19 most . significant digits. • If any of the discarded digits to the right of the implicit decimal point are nonzero, then concatenate the digit '1' to sig.

2141

Part III: The 68000 Assembly-Language SANE Engine

Chapter 6

Comparisons and Inquiries .

2161

Part III: The 68000 Assembly-Language SANE Engine

•

Comparisons
FP68K offers two comparison operations: FCPX (which signals invalid if its operands compare unordered) and FCMP (which does not). Each compares a source operand (which may be single, double, extended, or comp) with a destination operand (which must be extended). The result of a comparison is the relation (less, greater, equal, or unordered) for which DST < relation> SRC ;

is true. The result is delivered in the X, N, Z, V, and C status bits:

Result
greater less equal unordered

Status Bits
XNZVC o 0 000 1 1 0 0 1 od1 0 0 00010

These status bit encodings reflect that floating-point comparisons have four possible results, unlike the more familiar integer comparisons with three possible results. You need not learn these encodings, however; simply use the FBxxx series of macros for branching after FCMP and FCPX. FCMP and FCPX are both provided to facilitate implementation of relational operators defined by higher level languages that do not contemplate unordered comparisons. The IEEE standard specifies that the invalid exception shall be signaled whenever necessary to alert users of such languages that an unordered- comparison may have adversely affected their program's logic.

Chapter 6: Comparisons and Inquiries

Example",
Test B < = A, where B is extended and A is single; if TRUE branch to LOC; signal if unordered.
PEA PEA FCPXS FBLE A_ADR B_AOR
push address of A puSh address of B compare using source of type single. signal invalid if unordered branch if B <= A

LaC

Example 2
Test B not-equal A, where B is extended and A is double; if TRUE branch to LOC. (Note that not-equal is equivalent to less, greater, or unordered, so invalid should not be signaled on unordered.)
PEA PEA' FCMPD FBNE A_ADR B_ADR
push address of A pUSh address of B compare using source of type double, do not signal invalid if unordered b~anch if B not-equal A

LaC

•

Inq~iries
The classify operation provides both class and sign inquiries. This operation takes one source operand (single, double, or extended), which is passed by address, and places the result in a 16-bit integer destination. The sign of the result is the sign of the source; the magnitude of the result is 1 2 3 4 5 6 signaling NaN quiet NaN infinite zero normal denormal

2181

Part III: The 68000 Assembly-Language SANE Engine

Example
Set C· to sign and class of A.
PEA A_ADR PEA C_ADR FCLASSS
push address of A push address of result classify single

Chapter 6: Comparisons and Inquiries

22

QuickDraw Programmer's Guide

The pnMode and pnPat fields' of a grafPort determine how the bits under the pen are affected when lines or shapes are drawn. The pnPat is a' pattern that is used like the "ink" in the pen. This pattern, like all other patterns drawn in the grafPort, is always aligned with the port's coordinate system: the top left. corner of the pattern is aligned with the top left corner of the portRect, so that adjacent areas of the same pattern will blend into a continuous, coordinated pattern. Five patterns are predefined (white, black, and three shades of gray); you can also create your own pattern and use it as the pnPat. (A utility procedure, called StuffHex, allows you ·to fill patterns easily.) The pnMode field determines Lhow the pen pattern is to affect what's already on the bitMap when lines or shapes are drawn. When the pen draws, QuickDraw first determines what bits of the bitMap will be affected and finds their corresponding bits in the pattern. It then does a bit-by-bit evaluation based on ~he pen mode, which specifies one of eight boolean operations to perform. The resulting bit is placed into its proper place in the bitMap. The pen modes are described under "Transfer Modes" in the general discussion of) drawing ,below. The pnVis field determines. the pen's visibility, that is, whether it draws on the screen. For more information, see the descriptions of HidePen and ShowPen under "Pen and Line-Drawing Routines" in the "QuickDraw Routines" section. Text Characteristics The txFont, txFace, txMode, txSize, andspExtra fields of a grafPort determine how text will be drawn -- the font, style, and size of characters and how they will be placed on the bi tMap. ( hand) In the Macintosh User Interface Toolbox, character style means stylistic variations such as bold, italic, and underline; font means the complete set of characters of one typeface:-;Uch as Helvetica, and does not include the character style or size. QuickDraw can draw characters as quickly and easily as it draws lines and shapes, and in many 'prepared fonts. Figure 11 shows two QuickDraw characters and some terms you should become familiar with.

3/2/83

Espinosa-~ose

/QUICK/QUIKDRAW.3

Chapter 7

Environmental Control

Part III: The 68000 Assembly-Language SANE Engine

•

The Environment Word
The floating-point environment is encoded in the 1S-bit integer format as shown below in hexadecimal:

Note that the default environment is represented by the integer value zero.

Example
With rounding toward-zero, inexact and underflow exception flags raised, extended rounding precision, and halt on invalid, overflow, and division-by-zero, the most significant byte of the environment is 72 and the least significant byte is 00. Access to the environment is via the operations get-environment, set-environment, test-exception, set-exception, procedure-entry, and procedure-exit.

2221

Part III: The 68000 Assembly-Language SANE Engine

•

Get-Environment and Set-Environment
Get-environment take.s one input operand: the address of a '16-bit integer destination. The environment word is returned in the destination. . Set-environment has one input operand: the address of a 16-bit integer, which is to be interpreted as an environment word.

Set- exception takes one source operand, the address of a16- bit integer which encodes an exception in the manner described above for test- exception. Set- exception stimulates the indicated exception.

2241

Part III: The 68000 Assembly-Language SANE Engine

•

Procedure-Entry and Procedure-Exit
Procedure-entry saves the current floating-point environment (16-bit integer) at the address passed as the sole operand, and sets the operative environment to the default state.
Procedure-exi~ saves (temporarily) the exception. flags, sets the environment passed as the sole operand, and then stimulates the saved exceptions.

Example
Here is a procedure that appears to its callers as an atomic operation.
ATOMICPRO,C PEA FPROCENTRY ; push address to store environment ; procedure entry

FP68K lets you transfer program control when selected floating-point exceptions occur. Because this facility will be used to implement halts in high-level languages, we refer to it as a halt mechanism. The assembly-language programmer can write a halt handler routine to cause special actions for floating-point exceptions. The FP68K halting mechanism differs from the traps that are an optional part of the IEEE Standard .

•

Conditions for a Halt
Any floating-point exception can, under the appropriate conditions, trigger a halt. The halt for a particular exception is enabled when the user has set the halt-enable bit corresponding to that . exception.

Chapter 8: Halts

\

•

The Halt Mechanism
If the halt for a given exception is enabled, FP68K does these things when that exception occurs: 1. FP68K delivers the same result to the destination address that it would return if the halt were not enabled.

The first word of the record MISC contains in its five low-order bits the AND of the halt-enable bits with the exceptions that occurred in the operation just completing. If halts were not enabled, then (upon return from FP68K) CCR and DO would . . have the values given in MISC. 3. It passes control by JSR through the halt vector previously set by FSETHV, pushing another long word containing a return address in FP68K. If execution is to continue, the halt procedure must clear 18 bytes from the stack to remove the opword and the DST, SRC, SRC2, and MISC addresses.

2281

Part III: The 68000 Assembly-Language SANE Engine

Set-halt-vector has one input· operand: the address of a 32-bit integer, which is interpreted as the halt vector (that is, the address to jump to in case a halt occurs). Get-halt-vector has. o~e input operand: the address of a 32-bit integer, which receives the halt vector .

•

Using the Halt Mechanism
This example illustrates the use of the halrmechanism. The user must set the halt vector to the starting address of a halt handler routine. This particular halt handler returns control to FP68K, which will continue as if no halt had occurred, returning to the next instruction in the user's program. LEA MOVE.L PEA. FSETHV HROUTINE,AO AO,H_ADR H_ADR AO gets address of halt routine H_ADR gets same
set halt vector to HRDUTINE floating-point operand here a floating-point call here called by FP68K AO saves return address in FP68K increment stack past arguments return to FP68K

PEA <FOPMACRO> ·HROUTINE MOVE.L ADD.L JMP (SP)+.AO H18,SP
(AO)

Chapter 8: Halts

THE DRAWING ENVIRONMENT:

G~AFPORT

23

--.---r.-----.,-------

oscent. line

-X.._ _ _ _ _........_ _ _

(jescent. line

Figure 11.

QuickDraw Characters

QuckDraw can display characters in any size, as well as boldfaced, italicized, outlined, or shadowed, all without changing fonts. It can also underline the characters, or draw them closer together or farther apat:t. ThetxFont field is a font number that identifies the character font to be used in the grafPort. The font number ~ represents the system font. For more information about the sys tern font, the other font numbers recognized by the Font Manager, and the construction, layout, and loading of fonts, see the *** not yet existing *** Font Manager documentation. A character font is defined as a collection of bit images: these images make up the individual characters of the font. The characters can be of unequal widths, and they . . re not restricted to their "cells": the lower curl of a lowercase j, for example, can stretch back under the previous character (typographers call this kerning). A font can consist of up to 256 distinct characters, yet not all characters need be defined in a single font. Each font contains a missing symbol to be drawn in case of a request to draw a character that is missing from the font. The txFace field controls the appearance of. the font wi th values from the set def.ined by the Style data type: TYPE StyleItem Style

You can apply these either alone or in combination (see Figure 12). Most combinations usually look good only for large fonts.

3/2/83 Espinosa-Rose

/QUICK/QUIKDRAW.3

The FP68K halt machanism is designed so that a halt procedure may be written in Lisa Pascal. This is the form of a Pascal equivalent to HROUTINE:
type
mise~ee

= ~eeo~d
halte~~o~s
ee~pending

intege~

"

1ntege~,;

end
p~oeedu~e

{~eeo~d}

DOpending : longint ; ;

halt~outine va~

mise :
s~e.

mise~ee

dst : longint opeode : intege~ ) ;
s~e2.

begin {halt~outine} end {halt~outine} ;

Like HROUTINE, haltroutine merely continues execution as if no , halt had occurred.

Part 1\1: The 68000 Assembly-Language SANE Engine

Chapter 9

Elementary Functions

2321

Part III: The 68000 Assembly-Language SANE Engine

The elementary functions that are specified by the Standard Apple Numeric Environment are made available to the 68000 assembly-language programmer in ELEMS68K. Also included are two functions that compute logd1 + x) and 2X - 1 accurately. ELEMS68K calls the SANE engine (FP68K) for its basic arithmetic. The access schemes for FP68K (described in Chapter 2) and ELEMS68K are similar. Opwords and sample macros are included at the end of the file listed in Appendix B. (These macros are used· freely in the examples below.)

<EOPMACRO> is one of the macros in Appendix B that generate code to push an opword and invoke ELEMS68K.. This calling sequence follows the FP68K access scheme for unary operations, such as square root and negate.

Two-Argument Functions
General exponentiation (xY) has two extended arguments, both passed by address. The result is returned in x. Integer exponentiation (Xi) also has two arguments. The extended argument x, passed by address, receives the result. The 16-bit integer argument i is also passed by address. 80th exponentiation functions use the calling sequence for binary operations
SRC address PEA DST address PEA <EOPMACRO> push exponent address first push base address second

to effect DST DS,-sRC

Example
B B~ where the type of 8 is extended.

PEA PEA FXPWRI

push address of K push address of B i~teger exponentiation

2341

Part III: The 68000 Assembly-Language SANE Engine

•

Three-Argument Functions
Oompound and annuity use the calling sequence
push addr-ess of r-ate first push addr-ess of number- of periods second push address of destination thir-d

In your assemblies include the file TLASM/SANEMACS. TEXT, which contains the macros mentioned in this manual. The standard version is for Macintosh. For programs that will run on Lisa, redefine the symbol FPBYTRAP as follows:
FPBYTRAP .EQU 0

On Macintosh, the object code for FP68K and ELEMS68K is automatically loaded as needed by the Package Manager. On Lisa, it suffices to link your assembled code with the intrinsic unit file 10SFPLlB.OBJ. -

H~~ ,. ,. . and in other tl)tlts, too(
Figure 12. Character Styles If you specify bold, each character is repeatedly drawn one bit to the right ?n appropriate number of times for extra thickness. Italic adds an italic ,slant to the characters. Character bi ts above the base line are skewed right; bits below the base line are skewed left. Underline draws a line below the base line of the characters~ If part of a character descends below the base line (as "y" in Figure 12), the underline is not drawn through the pixel on either side of the descending part. You may specify either outline or shadow. Outline makes a hollow, outlined character rather than a solid one. '-lith shadow, not only is the character hollow and outlined, but the outline is thickened below and to the right of the character to achieve the effect of a shadow. If you .specify bold along with outline or shadow, th~ hollow part of the character is widened. Condense and extend affect the horizontal distance between all characters, including spaces. Condense decreases the distance between char~cters and extend increases it, by an amount Which the Font Manager determines is appropriate. The txMode field controls the way characters are placed on a bit image. It functions much like a pnMode: when a character is drawn, QuickDraw determines which bi ts of the bi t 'image will be af fected, does a bit-by-bit comparison based on the mode, and stores the resulting bits into the bit image. These modes are described under "Transfer Modes" in the general discussion of drawing below. Only three of them srcOr, srcXor, and srcBic -~ should be used for drawing text.

The txSize field specifies the type size for the font, in points (where "point" here is a printing term meaning 1/72 inch). Any size may be specified. If the Font Manager does not have the font in a specified size, it will scale a size it does have as necessary to produce the size desired. A value of ~ in thi~ field directs the Font Manager to choose the size from among those it has for the font; it will choose whichever size is closest to the system font size. Finally, the spExtra field is useful when a line of characters is to be drawn justified such that it is aligned wi th both a left and a right margin (sometimes called "full justification"). SpExtra is the number of pixels by which each space character should be widened to fill out the line.

COORDINATES IN GRAFPORTS Each grafPort has its own local 'coordinate system. All fields in the grafPort are expressed in these coordinates, and all calculations and actions performed in QuickDraw use the local coordinate system of the currently selected port. Two things are important to remember: - Each grafPort maps a portion of the coordinate plane into a similarly-sized portion of a bit image. - The portBits.bounds rectangle defines the local coordinates for a grafPort. The top left corner of portBits.bounds is always aligned around the firs t bi t in the hi t image; the coordinates of that corner "anchor" a' point on the grid to that hi t in the bi t image •. This forms a common reference point 'for mult iple grafPorts using the same bi t image (such as the screen) • Given a portBi ts. bounds rectangle for each port, you know that their top left corners coincide. The interrelationship between the portBits. bounds and portRect rectangles is very important. As the portBits.bounds rectangle establishes a coordinate sys tern for the port" the portRect rectangle indicates the section of the coordinate plane (and thus the bit image) that will be used for drawing. The portRect usually falls inside the portBits.bounds rectangle, but it's not required to do so. When a new grafPort is created, its bitMap is set to point to the entire Macintosh screen, and both the portBits.bounds and the portRect rectangles are set to 512-by-342-bit rectangles, with the point (0,~) at the top left corner of the screen. You can redefine the local coordinates of the top left corner of the grafPort's portRect, using the SetOrigin procedure. This changes the local coordinate system of the grafPort, recalculating the coordinates of ,all points in the grafPort to be relative to the new corner 3/2/83 Espinosa-Rose /QUICK/QUIKDRAW.3

SetPort(gamePort); SetOrigin(40,80); The call to SetPort sets the current grafPort to gamePort; the .call to SetOrigin changes ·the local coordinates of the top left corner of that port's portRect to (40,80) (see Figure 13).

Before

S"~~r Oliqin

Figure 13.

Changing Local Coordinates

This recalculates the coordinate components of the following elements: gamePortA.portBits.bounds gamePortA.visRgn These elements are always kept "in sync", so that all calculations, comparisons, or operations that seem right, work right. - Notice that when the local coordinates of a grafPort are offset, ,the visRgn of that port is offset also, but the clipRgn is not. A good way to think of it is that if a document ·is being, shown inside a grafPort, the document "sticks" to the coordinate system, and the port~s structure "sticks" to the screen. Suppose·, for example, that the visRgn and clipRgn in Figure 13 before SetOrigin are the same as the portRect, and a document is being shown. After the SetOrigin call, the top left corner of the clipRgn is still (95,120), but this location has moved down and to the right, and the location of the pen within the document has similarly moved. The locations of portBits.bounds, portRect, and visRgn did not change; their coordinates were offset. As always, the top left ·cornerof portRits.bounds remains aligned around the first bit in the bit image (the first pixel on the screen). If you are moving, comparing, or otherwise dealing with mathematical items in different grafPorts (for example, finding the intersection of 3/2/83 Espinosa-Rose /QUICK/QUIKDRAW.3 gamePortA.portRect

This guide contains diagrams of the SANE data formats and the . 68K SANE, operations and environment word.

•

Formats of SANE Types
Each of the diagrams below is followed by the rules for evaluating the number v. In each field of each diagram, the leftmost bit is the msb and the rightmost is the Isb.
Table C-1. Format Diagram Symbols
V

Operations
In the operations below, the operation's mnemonic is followed by the opword in parentheses: the first byte is the operation code; the second is the operand format code. For some operations, the first byte of the opword (xx) is ignored.

Abbreviations and Symbols
The symbols and abbreviations in this section closely parallel those in the text, although some are shortened. In some cases, the same symbol has various meanings, depending on context. Operands .cST SRC SRC2 destination operand (passed by address) source operand (passed by address), pushed before DST second source operand (passed by address), pushed before SRC

two regions in two different grafPorts) , you must adju~t to a common coordinate system before you perform the operation. A Quickpr~w procedure, LocalToGlobal, lets you convert a point's local coordinates to a global system where the top left corner of the bi t image is (0,0); by converting the various local coordinates to global coordinates, you can compare and mix them wi th confidence. For more informatio.n, see the description of this,procedure under "Calculations with Points" in the section "QuickDraw Routines".

GENERAL DISCUSSION OF DRAWING Drawing occurs: - Always inside a grafPort, in the bit image and coordinate system defined by the grafPort's bitMap.
I

- Always within the intersection of the grafPort's portBits.bounds and portRect, and clipped to its visRgn and clipRgn. - Always at the grafPort's pen location. - Usually with the grafPort's pen size, pattern, and mode. With QuickDraw procedures, you can draw lines, shapes, and text. Shapes include rectangles, ovals, rounded-corner rectangles, wedge-shaped sections of ovals, regions, and polygons •. Lines are defined by two points: the current pen location and a destination location. Hhen drawing a line, QuickDraw moves the top left corner of the pen along the mathematical trajectory from the current location to the destinatio~. The pen hangs below and to the right of the trajectory (see Figure 14). .

No mathematical element (such as the pen location) is ever affected by clipping; clipping only determines what appears where in the bit image. If you draw a line to a location outside your grafPort, the pen 'Iocation will move there, but only the 'portion of the line that is inside the port will actually be drawn. This is true for all drawing procedures. Rectangles, ovals, and rounded-corner rectangles are defined by two corner points. The shapes always appear inside the mathematical rectangle defined by the two points. A region is defined in a more complex manner, but also appears only within the rectangle enclosing it. Remember, these enclosing rectangles have infinitely thin borders and are'not visible on the screen.
I

I

As illustrated in Figure 15, shapes may be drawn either solid (filled in with a pattern) or framed (outlined and hollow).

lIen 1teig1\t.

...
f

-+1 ft- pen . wid!.i{

Figure 15.

Solid Shapes and Framed Shapes

In the case of framed shapes, the.outlineappears completely within the enclosing rectangle -- with one exception ~- and the vertical and horizontal thickness of the outline is determined by the pen size. The exception is polygons , as discussed in "Pictures and Polygons" below. The pen pattern is used to fill in the bits that are affected by the drawing operation. The pen mode defines how those bits are to be affected by directing QuickDraw to apply one of eight boolean operations to the bits in the shape and the corresponding pixels on the screen. Text drawing does not use the pnSize, pnPat, or pnMode, but it does use the pnLoc. Each character is placed to the right of the current pen location, with the left end of its base line at the pen's location. The pen is moved to the right to the location where it will draw the 3/2/83 Espinosa-Rose ·/QUICK/QUIKDRAW.3.

GENERAL DISCUSSION OF DRAWING next character.

29

No wrap or carriage return is performed automatically.

The method QuickDraw uses in, placing text is controlled by a mode similar to the pen mode. This is explained in "Transfer Modes", below. Clipping of text is performed in exactly the same manner as all other clipping in QuickDraw. Transfer Modes When lines or 'shapes are drawn, the pnMode field of the grafPort determines how the drawing is to appear in the port's bit image; similarly, the txMode field determines how text is to appear. There is also a QuickDraw procedure that transfers a bit image from one bitMap to another, and this procedure has a mode parameter that det~rmines the appearance of the result. In all these cases, the mode, called a transfer mode, specifies one of eight boolean operations: for each bit in the item to be drawn, QuickDraw finds the corresponding bit in the des tination bi t image, performs the boolean operation on the pair of bits, and stores the resulting bit into the bit image. There are two types of transfer mode: - Pattern transfer modes, for drawing lines or shapes with a pattern. - Source transfer modes, for drawing text or transferring any bit image between two bitMaps. For each type of mode, there are four basic operations -- Copy, Or, Xor, and Bic. The Copy operation simply replaces the pixels in the destination with the pixels in the pattern or source, "painting" over the destination without regard for ,what is already there. The Or, Xor, and Bic operations leave the destination pixels under,the white part of the pattern or source unchanged, and differ in how they affect the pixels under the black part: Or replaces those pixels. with black pixels, thus "overlaying" the destination wi th the black part of the pattern or source; XOr inverts the pixels under the black part; and Bic erases them to white. Each of the basic operations has a variant in which every pixel in the pattern or source is inverted before the operation is performed, giving eight operations in all. Each mode is defined by name as a constant in QuickDraw (see Figure 16).

Currently you can only look at QuickDraw output on a black-and-white screen or printer •. Eventually, however, Apple will support color output devices.' If you want to set up your application now to produce color output in the future, you can do so by using QuickDraw procedures to set the foreground color and tpe background color. Eight standard colors may be specified with the following predefined constants: b1ackCo1or, whiteColor, redCo10r, greenCo10r, b1ueCo1or, cyanCo1or, magentaCo1or, and yel10wColor. Initially, the foreground color is b1ackCo1or and the background color is ymiteColor. If 'you specify a color other than whiteCo10r '. it will appear as black on a black-and-white output device. To apply the table in the "Transfer Modes" section above to drawing in color, make the following translation: where the table shows "Force black", read "Force foreground color", and where 'it shows "Force white", read "Force background color". When you ~ventua11y receive the 3/2/83 Espinosa-Rose /QUIGK/QUIKDRAW.3

GENERAL DISCUSSION OF DRAWING

31

color output device, you'll find out the effect of inverting a color on it. ( hand) QuickDraw can support output devices that have up to 32 bits of color information per pixel. A color picture may be thought of, then, as having up to 32 planes. At any one time, QuickDraw draws into only'one of these planes. A QuickDraw routine c~lled by the color-imaging software specifies which plane.

PICTURES AND POLYGONS QuickDraw lets you save a sequence of drawing commands and "play them back" later with a single procedure call. There are two such mechanisms: one for d.rawing any picture to scale in a des tination rectangle that you specify, and another for drawing polygons in all the ways you can draw other shapes in QuickDraw. Pictures A picture in QuickDraw is a transcript of calls to routines which draw something -- anything -- on a bitMap. Pictures make it easy for one program to draw something defined in another program, wi th great flexib~,lity and without knowing the details about what's being drawn. For each picture you define, you specify a rectangle that surrounds the picture; this rectangle is called the picture frame. Hhen you later call the procedure that draws the saved picture, you supply a destination rectangle, and QuickDraw scales the picture so that its frame is completely aligned with the destination rectangle. Thus, the picture may be expanded or shrunk to fit its destination rectangle. For example, if the picture is a circle inside a square picture frame, and the destination rectangle is not square, the picture is drawn as an oval. Since a picture may include any sequence of drawing· commands, its data structure is a variable-length entity. It consists of two fixed fields followed by a variable-length data field: TYPE Picture

The picSize field contains the size, in bytes, of the picture variable. The picFrame fie~d is the picture frame which surrounds the picture and gives a frame of reference for scaling when the picture is drawn. The rest of the structure contains a compact representation of the drawing 3/2/83 Rose /QUICK/QUIKDRAW.P

32

QuickDraw Programmer's Guide

commands that define the picture. All pictures are accessed through handles, which point to one master pointer which in turn points to the picture • TYPE .PicPtr PicHandle ....Picture; . . PicPtr;

To define a picture, you call a QuickDraw function that returns a ' picHandle and then call the routines that draw the picture. There is a procedure to call when you've finished defining the picture, and another for when you're done with the picture altogether. QuickDraw also allows you to intersperse picture comments in with the definition of a picture. These comments, which do not affect the picture's appearance, may be used to provide additional information about the picture when it's played back. 'This is especially valuable when pictures are transmitted from one application to another. There are two standard types of comment which, like parentheses, serve to group drawing commands together (such as all the commands that draw a particular part of a picture): CONST picLParen picRParen
<6;
1;

The application defining the picture can use these standard comments as well as comments of its own design. To include a comment in the definition of a picture, the application calls a QuickDraw procedure that specifies the comment with three parameters: the comment kind, which identifies .the type of comment; a handle to additional 'data if desired; and the size of the additional data, if any. When playing back a picture, Qu~ckDraw passes any comments in the picture's definition to a low-level procedure accessed indirectly through'the grafProcs field of the grafPort (see "Customizing QuickDraw Operations" for more information). To process comments, the application must include a procedure to do the processing and store a pointer to it in the data structure pointed. to by the grafProcs field. ( hand) The standard low-level procedure for processing picture comments simply ignores all comments. 'Polygons Polygons are similar to pictures in that you define them by a sequence of calls to QuickDraw routines. They are also similar to other shapes that QuickDraw knows about, since there is a set of procedures for performing graphic operations and calculations on them. A polygon is simply any sequence of connected lines (s'ee 'Figure 17). You define a polygon by moving to the starting point of the polygon and 3/2/83 Rose /QUICK/QUIKDRAW.P

PICTURES AND POLYGONS

33

drawing lines from there to the next point, from that point to the next, and so on.

l/
......

l

/

/

l

..............,

Figure 17.

Polygons

The data structure for a polygon is a variable-length entity. It consists of two fixed fields followed by a variable-length array: TYPE Polygon

= RECORD
polySize: polyBBox: polyPoints:
END;

INTEGER; Rect; ARRAY [0 •• 0] OF Point

The polySize field contains the size, in bytes, of the polygon variable. The polyBBox field is a rectangle which just encloses the entire polygon. The polyPoints array expands as necessary to contain the points of the polygon -- the starting point followed by 'each succesive point to which a line is drawn. Like pictures and regions, polygons are accessed through handles. TYPE PolyPtr PolyHandle

=

= "'Polygon;
"'PolyPtr;

To define a polygon, you call a QuickDraw function that returns a polyHandle and then form the polygon by calling procedures that draw lines. You call a procedure when you've finished defining the polygon, and another when you're done with the polygon altogether. Just as for other shapes that QuickDraw knows about, there is a set of graphic operations on polygons to draw them on the screen. QuickDraw draws a polygon by moving to the starting point and then drawing lines to the remaining points in succession, just as when the ,routines were called to define the polygon. In this sense it "plays back" those routine calls. As a result, polygons are not treated exactly the same 3/2/83 Rose /QUICK/QUIKDRAW.P

34

_QuickDraw Programmer's Guide

as other QuickDraw shapes. For example, the procedure that frames a' polygon draws outside the actual boundary of the polygon, because QuickDraw line-drawing routines draw below and to the right of the pen location. The procedures that fill a polygon with a pattern, however, stay within the boundary. of the polygon; they also add an additional line between the ending point and the starting point ff those points are not the same, to complete the shape. There is also a difference in the way QuickDraw scales a polygon and a similarly-shaped region if it's being drawn as part of a picture: when stretched, a slanted line is drawn more smoothly-if it's part of a polygon rather than a region. You may find it helpful.to keep in mind the conceptual di fference between polygons and regions: a polygon is treated more as a continuous shape, a region more as a set of bits.

QUICKDRAW ROUTINES This section describes all the procedures and functions in QuickDraw, their parameters, and their operation. They are presented in their Pascal form; for information on using them from assembly language, see "Using QuickDraw from Assembly Language". GrafPort Routines

The globalPtr parameter tells QuickDraw where to store its global variables, beginning with thePort. From Pascal programs, this parameter should always be set to @thePort; assembly-language programmers may choose any location, as long as it can accommodate the number of bytes specified by GRAFSIZE in GRAFTYPES.TEXT (see "Using QuickDrawfrom.Assembly Language").

OpenPort allocates space for the given grafPort's visRgn and clipRgn, initializes the fields of the grafPort as indicated below, and makes the grafPort the current port (see SetPort). You must call OpenPort before using any grafPort; first perform a NEW to create a grafPtr and then use that grafPtr in the OpenPort call. Field device portBits portRect visRgn clipRgn Type INTEGER BitMap Rect RgnHandle RgnHandle Pattern Pattern Point Point INTEGER Pattern INTEGER INTEGER Style INTEGER INTEGER INTEGER Longlnt Longlnt INTEGER INTEGER QDHandle QDHandle QDHandle QDProcsPtr Initial setting
~ (Macintosh screen)

PROCEDURE InitPort (gp: GrafPtr); Given a pointer to a grafPort that has been opened with OpenPort, InitPort reinitializes 'the fields of the grafPort and makes it the current port (if it's not already). ( hand) InitPort does everything OpenPort does except allocate space for the visRgn and clipRgn.

3/2/83 Espinosa-Rose

/QUICK/QUIKDRAW.4

36

QuickDraw Programmer's Guide

PROCEDURE ClosePort (gp: GrafPtr); ClosePort deallocates the space occupied by the given grafPort's visRgn and clipRgn. l~en you' are completely through with a grafPort, call ,this procedure and then dispose of the grafPort (with a DISPOSE of the grafPtr). " ( eye) If you do not call ClosePort before disposing of the grafPort, the memory used by the visRgn and clipRgn will be,unrecoverable. ( eye) After calling ClosePort, be sure not to use any copies of the visRgn or clipRgn handles that 'you may have made. PROCEDURE SetPort (gp: GrafPtr); SetPort sets the grafPort indicated· by gp to be the current port. The global pointer thePort always points to the current port. All QuickDraw drawing routines affect the bitMap thePortA.portBits and use the local coordinate system of thePort A• Note that OpenPort and InitPort do a SetPort to the given port. ( eye) Never do a SetPort to a port that has not been opened with OpenPort. Each port possesses its own pen and text characteristics which remain unchanged when the port is not selected as the current' port. PROCEDURE GetPort (VAR gp: GrafPtr); GetPort returns a pointer to the current grafPort. If you have a program that draws into more than one grafPort, it's extremely useful to have each procedure save the current grafPort (with GetPort), set its own grafPort, do drawing or calculations, and then restore the previous grafPort (with SetPort). The pointer to the current grafPort is also available through the global pointer thePort, but you may prefer to use GetPort for better readabili ty of your program text. For example, a procedure could do a GetPort(savePort) before setting its own grafPort and a SetPort(savePort) afterwards to restore the previous port. PROCEDURE GrafDevice (device: INTEGER); GrafDevice sets thePortA.device to the given number, which identifies the logical output device for this grafPort. The Font Manager uses this information. The initial device number is ~, which represents the Macintosh screen.

3/2/83 Espinosa-Rose

/QUICK/QUIKDRAW.4

QUICKDRAW ROUTINES PROCEDURE SetPortBits (bm: BitMap); SetPortBits sets thePort ...... portBits to any previously defined bi tMap. This allows you to perform all normal drawing and calculations on a buffer other than the Macintosh screen -- for example, a 64~-by-7 output buffer for a C. Itoh printer, or a small off-screen image for later "stamping" onto the screen. Remember to prepare all fields of the bitMap before you call , SetPortBits.
\

37

PROCEDURE PortSize (width,height: INTEGER); PortSize changes the size of the current grafPort's po'rtRect. THIS DOES NOT AFFECT THE SCREEN; it merely changes the size of the "active area" of the grafPort. ( hand)
T~is procedure is normally called only by the '·1indow Manager.

The top left corner of the portRect remains at its same location; the width and height of the portRect are set to the given width and height. In other words, PortSize moves the bottom right corner of the portRect to a position relative to the top left corner. Port Size does not change the clipRgn or the visRgn, nor does it affect the local coordinate system of the grafPort: it changes only the portRect's width and height. Remember that all drawing occurs only in the intersection of the portBits.bounds and the portRect, clipped to the visRgn and the clipRgn. PROCEDURE MovePortTo (leftGlobal,topGlobal: INTEGER); MovePortTo changes the position of the current grafPort's portRect. THIS DOES NOT AFFECT THE SCREEN; it merely changes the location at which subsequent drawing inside the port will appear. ( hand) This procedure is normally called only by the l·lindow Manager. The leftGlobal and topGlobal parameters set the distance between the top left corner of portBits.bounds and the top left corner of the new portRect. For example, MovePortTo(256,171); will move the top left corner of the portRect to the center of the screen (if portBits is the Macintosh screen) regardless of the local coordinate system.

3/2/83 Espinosa-Rose

/QUICK/QUIKDRAW.4

38

QuickDraw Programmer's Guide

Like PortSize, MovePortTo does not change the clipRgn or the visRgn, nor does it affect the local coordinate system of the grafPort. PROCEDURE SetOrigin (h,v: INTEGER); SetOrigin changes the local coordinate system of the current grafPort. THIS DOES NOT AFFECT THE SCREEN; it does, however, affect where subsequent drawing and calculation will appear in the grafPort. SetOrigin updates the coordinates'of the portBits.bounds, the portRect, and the visRgn. All subseq,uent drawing and calculation routines will use the new coordinate system. The h and v parameters set the coordinates of the top left corner of the portRect. All other coordinates are calculated from this point. All relative distances among any el,ements in the port will remain the same; only their absolute local coordinates will change. ( hand) SetOrigin does not update the coordinates of the clipRgn or the ~n; these items stick to the coordinate system (unlike the port's ,structure, which sticks to the screen). SetOrigin is useful for adjusting the coordinate system after a scrolling operation. (See ScrollRect tinder ~'Bit Transfer Operations" below. ) PROCEDURE SetClip (rgn: RgnHandle); SetClip changes the clipping region of the current grafPort to a region equivalent to the given region. Note that this does not change the region handle, but affects the clipping region itself. Since SetClip makes a copy of the given region, any. subsequent changes you make to· that region will not affect the clipping region of the port. You can set the clipping region to any arbitrary region, to aid you in drawing inside the grafPort. The initial clipRgn is an arbitrarily large rectangle. PROCEDURE GetClip (rgn: RgnHandle);
G~tClip changes the given region to a region equivalent to the clipping region of the current grafPort. This is the reverse 'of What SetClip does. Like SetClip, it does not change the region handle.

PROCEDURE ClipRect (r: Rect); ClipRect changes the clipping region of the current grafPort to a rectangle equivalent to given rectangle. Note that this does not change the region handle, but affects the region itself. 3/2/83 Espinosa-Rose /QUICK/QUIKDRAW.4

QUICKDRAW ROUTINES PROCEDURE BackPat (pat: Pattern);

39

BackPat sets the background pattern of the·current grafPo~t to the given pattern.. The background pattern is used in ScrollRect and in all QuickDraw routines that perform an "erase" operation. Cursor-Handling Routines

PROCEDURE InitCursor; InitCursor sets the current cursor to the predefined arrow cursor, an arrow pointing north-northwest, and sets the ~ursor level to ~, making the cursor visible. The cursor 'level, which is initialized to ~ when . the system is booted, keeps track of the number of times the cursor has been hidden to compensate for nested calls to HideCursor and ShowCursor (below). Before you call InitCursor, the cursor is undefined (or, if set by a previous process, it's whatever that process set it to). PROCEDURE SetCursor (crsr: Cursor); SetCursor sets the current cursor to the 16-by-16-bit image in crsr. If the cursor is hidden, it remains hidden and -will attain the new appearance when it's uncovered; if the cursor is already visible, it .changes to the new appearance i~mediately. The cursor image is initi~lized by InitCursor to a north-northwest arrow, visible on the screen. There is no way to retrieve the current cursor image. PROCEDURE HideCursor; HideCursor removes the cursor from the screen, restoring the bits under it, and decrements the cursor level (which InitCursor initialized to 0). Every call to HideCursor should be balanced by a subsequent call to ShowCursor. PROCEDURE
ShowCur~or;

ShowCursor increments the cursor level, which may have been decremented by HideCursor, and displays the cursor on the screen if the level becomes 0. A call to ShowCursor should balance each previous call to lIideCursor. The level is not incremented/ beyond ~,\ so extra calls to ShowCursor don't hurt. QuickDraw low-level interrupt-driven routines 'link the cursor with the mouse position, so that if the cursor level is ~ (visible), the cursor 3/2/83 Espinosa-Rose /QUICK/QUIKDRAW.4

40

QuickDraw Programmer's Guide

automatically follows the mouse. You don't need todd anything but a ShowCursor to have a cursor track the ~use'. There is no way to "disconnect".. the cursor from the mouse; you can't force' the cursor to a certain position, nor can you easily prevent the cursor from entering a certain area of the screen. If the cursor has been changed (with SetCursor) while hidden, ShowCursor presents the new cursor. The cursor is initialized by InitCursor to a north-northwest arrow, not hidden. PROCEDURE ObscureCursor;

I

ObscureCursor hides the cursor until the. next time the mouse is roved. Unlike HideCursor, it has no effect on the cursor level and must not be balanced by a call to ShowCursor. Pen and Line-Drawing Routines The pen and line-drawing routines all depend on the coordinate system of the current grafPort. Remember that ~ach grafPort has its own pen; if you draw in one grafPort, change to another, and return to the first, the pen will have remained in the same location. PROCEDURE HidePen; HidePen decrements the current grafPort's pnVis field, which is initialized to (J by OpenPort; ~~henever pnVis is negative, the pen does not draw on the screen. PnVis keeps track of the number of times the pen has been hidden to compensate for nested calls to HidePen and ShowPen (below). HidePen is called by OpenRgn, OpenPicture, and OpenPoly so that you can define regions, pictures, and polygons wi thout drawing on the screen. PROCEDURE ShowPen; ShowPen increments the current grafPort's pnVis field, Which may have been decremented by HidePen; if pnVis becomes (J, QuickDraw resumes drawing on the screen. Extra calls to ShowPenwill increment pnVis beyond (J, so every call to ShowPen should be balanced, by a subsequent call to HidePen. ShowPen is called by CloseRgn, ClosePicture,_and ClosePoly. PROCEDURE GetPen (VAR pt: Point); GetPen returns the current pen location, in the local coordinates of the current grafPort.

3/2/83 Espinosa-Rose

/QUICK/QUIKDRAW.4

QUICKDRAW ROUTINES PROCEDURE GetPenState (VAR pnState: PenState);

.41

GetPenState saves the pen location, size, pattern, and mode into a storage variable, to be res tored later' wi th SetPenSta te (below). This is useful when calling short subroutines that operate in the current port but must change the graphics pen: each such procedure can save the pen's state when it's called, do whatever it needs to do, and restore the previous pen state immediately before returning. The PenState data type is not useful for anything except saving the pen's state. PROCEDURE SetPenState (pnState: PenState); SetPenState sets the pen location, size, pattern, and mode in the current grafPort to the values stored in pnState. This is usually called at the end of a procedure that has altered the pen parameters and wants to restore them to their state at the beginning of the procedure. (See GetPenState, above.) PROCEDURE PenSize (width,height: INTEGER); PenSize sets the dimensions of the graphics pen in the current grafPort. All subsequent calls to Line, LineTo, and the procedures that draw framed shapes in the current grafPort will use the .new pen dimensions. The pen dimension~ can be accessed in the variable thePortA.pnSize, which is of type Point. If either of the pen dimensions is set to a negative value, the pen assumes the dimensions (0,O) and no drawing is performed. For a discussion of how the pen draws, see the "General Discussion of Drawing" earlier in this manual. . PROCEQURE PenMode (mode: INTEGER); PenMode sets the transfer mode through which the pnPat is transferred onto the bitMap when lines or shapes are drawn. The mode may be any one of the pattern transfer modes: patCopy patOr patXor patBic notPatCopy notPatOr notPatXor notPatBic
"-

If the mode is one of the source transfer modes (or negative), no drawing is performed. The current pen mode can be obtained in the variable thePortA.pnMode. The initial pen mode is patCopy, in Which the pen pattern is copied directly to the bitMap.

3/2/83 Espinosa-Rose

/QUICK/QUIKDRAW.4

42

QuickDraw Programmer's Guide

PROCEDURE PenPat (pat: Pattern); PenPat sets the pattern that is used by the pen in the current grafPort. The standard patterns white, black, gray, ItGray,and dkGray are predefined; the initial pnPat is'black. The current pen pattern can be obtained in the variable thePortA.pnPat, and this value can be assigned (but not compared!) to any other variable of type Pattern. PROCEDURE PenNormal"; PenNormal resets the initial state of the pen in the current ,grafPort, as follows: Field pnSize pnMode pnPat Setting
(1,1)

patCopy black

The pen location is not changed. PROCEDURE MoveTo (h,v: INTEGER); MoveTo moves the pen to location (h,v) in the local coordinates of the current grafPort. No drawing is performed. PROCEDURE Move (dh,dv: INTEGER); This procedure moves the pen a distance of dh horizontally and dv vertically from its current location; it calls MoveTo(h+dh,v+dv), where (h, v) is -the current location. The positive directions are to the right and down. No drawing is performed. PROCEDURE LineTo (h,v: INTEGER); LineTo draws a line from the current pen location to the location specified (in local coordinates) by hand v. The new pen location is (h,v) after the line is drawn. See the general discussion of drawing. If a region or polygon is open and being formed, its outline is infinitely thin and is not affected by the pnSize, pnMode, or pnPat. (See OpenRgn and OpenPoly.) " PROCEDURE Line (dh,dv: INTEGER); This procedure draws a line to the location that is a distance of dh horizontally and dv vertically from the current pen location; it calls LineTo(h+dh,v+dv), where (h,v) is the current location. The positive directions are to the right and down. The pen location becomes the coordinates of the end of the line after the line is drawn. See the

3/2/83 Espinosa-Rose

/QUICK/QUIKDRAW.4

QUICKDRAW ROUTINES general discussion of drawing. If a region or polygon is open and being formed, its outline is infinitely thin and is not affected by the pnSize, pnMode, or pnP~t. (See OpenRgn and OpenPoly.) Text-Drawing Routines Each grafPort has its own text characteristics, and all these procedures deal with those of the current port. PROCEDURE TextFont (font: INTEGER);

43

TextFont sets the current grafPort's font (thePortA.txFont) to the given font number. The initial font number is ~, which represents the system font. ' PROCEDURE TextFace (face: Style); TextFace sets the current grafPort's character style (thePortA.txFace). The Style data type allows you to specify a set of one or more of the following predefined constants: bold, italic, underline, outline, shadow, c~ndense, and extend. For example: TextFace([bold]); TextFace([bold,italic]); , TextFace(thePortA.txFace+[bold]); TextFace(thePortA.txFace-[bold]); TextFace([]); PROCEDURE TextMode (mode: INTEGER); TextMode sets the current grafPort's transfer- mode for drawing text (thePortA.txMode). The mode should be srcOr, srcXor, or srcBic. The initial transfer mode for drawing text is srcOr. PROCEDURE TextSize (size: INTEGER); TextSize sets the current grafPort's type size (thePortA.txSize) to the given number of points. Any size may be specified, but the result will look best if the Font Manager has the font in that size (otherwise it will scale a size it does have). The next best result will occur if the given size is 'an even multiple of a size available for the font. If 0 is specified, the Font Manager will choose one of the available sizes -- whichever is closest to the syste~ font size. The initial txSize setting is ~. {bold} {bold and italic} {whatever it was plus bold} {whatever it was but not bold} {normal}

3/2/83 Espinosa-Rose

/QUICK/QUIKDRAW.4

44

QuickDraw Programmer's Guide

PROCEDURE SpaceExtra (extra: INTEGER); SpaceExtra sets the current grafPort's spExtra field, Which specifies the. number of pixels by which to widen each, space in a line of text. This is useful when text is being fully justified (that is, aligned with both a left and a right margin). Consider, for example, a line that contains three spaces; if there would normally be six pixels between the end of the line and the right margin, you would call SpaceExtra(2) to print the line with full justification.. The initial spExt~a setting ~s ~. ( hand) SpaceExtra will also take a negative argument, but be careful not to n~rrow spaces so much that the text is unreadable. PROCEDURE DrawChar (ch: CHAR); DrawChar places the given character to the right of the pen location, with the left end of its base line at the pen's location, and advances the pen accordingly. If the character is not in the font, the font's missing symbol is drawn. PROCEDURE DrawString (s: 'Str255);
,/

DrawString performs consecutive calls to DrawChar for each character in the supplied string; the string is placed beginning at the current pen location and extending right. No formatting (carriage returns, line feeds, etc.) is performed by QuickDraw. The pen location ends up to the 'right of the last character in the string. PROCEDURE DrawText (textBuf: QDPtr; firstByte,byteCount: INTEGER); DrawText draws text from an arbitrary structure in memory- specified by textBuf, starting firstByte bytes into the structure and continuing fo'r byteCount bytes. The string of text is placed beginning at the current pen location and extending right. No formatting (carriage returns, line feeds, etc.) is performed by QuickDraw. The pen location ,ends up to the right of the last character in the string. FUNCTION CharWidth (ch: CHAR) : INTEGER; CharWidth returns the value that will be added to the pen horizontal coordinate if the specified character is drawn. CharWidth includes the effects of the stylistic variations set with TextFace; if you change these af·ter determining the character width but before actually drawing the character, 'the predetermined width may not be correct. If the character is a space, CharWidth also includes the effect of SpaceExtra.

3/2/83 Espinosa-Rose

/QUICK/QUIKDRAW.4

QUICKDRAW ROUTINES FUNCTION StringWidth (s: Str255) : INTEGER;

45

StringWidth returns the width of the given text string, which it calculates by adding the CharWidths of all the characters in the string (see above). This value will be added to the'pen horizontal coordinate if the specified string is drawn. FUNCTION TextWidth (textBuf: QDPtr; firstByte,byteCount: INTEGER) INTEGER; TextWidth returns the width of the text stored in the arbitrary structure in memory specified by textBuf, starting firstByte bytes into the structure and continuing for byteCount bytes. It calculates the width by adding the Char~vidths of all the characters in the text. (See CharWidth, above.) PROCEDURE GetFontInfo (VAR info: FontInfo); GetFontInfo returns the following information about the current grafPort . . scharacter font, taking .into consideration the style and size in which the characters will be drawn: the ascent, descent, maximum character width (the greates t distance the pen will move when a character is drawn), and leading (the vertical distance between the descent line and the ascent line below it), all in pixels. The FontInfo data structure is defined as: TYPE FontInfo

Drawing in Color These routines will enable applications to do color drawing in the future when Apple supports color output devices for the Macintosh. All nonwhite colors will appear as black on black-and-white output devices. PROCEDURE ForeColor (color: LongInt); ForeColor sets the foreground color for all drawing in the current grafPort (AthePort.fgColor) to the' given color. The following standard colors are predefined: blackColor, whiteColor, redColor, greenColor, blueColor, cyanColor, magentaColor, and yellowColor. The initial foreground color is blackColor.

3/2/83 Espinosa-Rose

/QUICK/QU,IKDRAW • 4

46

QuickDraw Programmer"'s Guide

PROCEDURE BackColor (color: LongInt); BackColor sets the background color for all drawing in the current grafPort (AthePort.bkColor) to the given color. Eight standard colors are predefined (see ForeColor above). The initial background color is whiteColor. PROCEDURE ColorBit (whichBit: INTEGER); ColorBit is called by printing software for a color printer, or other color-imaging software, to set the current grafPort .... s colrBit field to whichBit; this tells QuickDraw which plane of the color picture to draw into. QuickDraw will draw into the plane corresponding to bit number whichBit. Since QuickDraw can support output devices that have up to 32 bits of color information per pixel, the possible range of values , for whichBit is 0 through 31. The initial value of the colrBit field is 0. Calculations with Rectangles Calculation routines are independent of the current 'coordinate system; a calculation will operate the same regardless of which grafPort is active'. ( hand) Remember that if the parameters to one of the calculation routines were defined in different grafPorts, you must first adjust them to be in the'same coordinate system. If you do not "adjust them, the result returned by the - routine may be different from what you see on the screen. To adjust to a common coordinate system, see LocalToGlobal and GlobalToLocal under "Calculations with Points" below • . PROCEDURE SetRect (VAR r: Rect; left, top, right, bottom: INTEGER);' SetRect assigns the four boundary coordinates to the rectangle. result is a rectangle with coordinates (l,eft, top, right, bottom). The

This procedure is supplied as a utility to help you shorten your program text. If yo~ want a more readable text at the expense of length, you can assign integers (or points) directly into the rectangle"'s fields~ There is no significant code size or execution speed advantage to either method; one"'s just easier to write, and the other"'s easier to read. PROCEDURE OffsetRect (VAR r: Rect; dh,dv: INTEGER); OffsetRect moves the rectangle by'. adding dh to each horizontal coordinate and dv to each vertical coordinate. If dh and dv are 3/2/83 Espinosa-Rose /QUICK.2/QUIKDRAW.5

QUICKDRAW ROUTINES

47

positive, the movement is to the right and down; if either is negative, the corresponding movement is in the opposite direction. The rectangle retains its shape and size; it's merely moved on the coordinate plane. This does not affect the screen unless you subsequently call a routine to draw within the rectangle. PROCEDURE InsetRect (VAR r: Rect; dh,dv: INTEGER); InsetRect shr~nks or expands the rectangle. The left and right sides are moved in by the amount specified by dh; the top and bottom are . moved towards the center by the amount specified by dv. If dh or dv is negative, the appropriate pair of sides is moved outwards instead of inwards. The effect is to alter the size by 2*dh horizontally and 2*dv vertically, with the rectangle remaining centered in the same place on the coordinate plane. If the resulting width or height becomes less than 1, the rectangle is set to the empty rectangle (0,0,0,0). / FUNCTION
SectRect'(srcRectA,srcR~ctB:

Rect; VAR dstRect: Rect)

BOOLEAN; SectRect calculates the rectangle that is the intersection of the tWo input rectangles, and returns TRUE if they indeed intersect or FALSE if they do not. Rectangles that "touch" at. a line or a point are not considered intersecting, because their intersection rectangle (really, in this case, an intersection line or point) does not enclose any bits on the bi tMap • If the rectangles do not intersect, the destination rectangle is set to (0,0,0,0). SectRect works correctly even if one of the source rectangles is also the destination. PROCEDURE UnionRect (srcRectA,srcRectB: Rect; VAR dstRect: Rect); UnionRect calculates the smallest rectangle which encloses both input rectangles. It works correctly even if one of the source rectangles is also the destination. / FUNCTION PtInRect (pt: Point; r: Rect) : BOOLEAN; PtInRect determines whether the pixel below and to the right of the given coordinate point is enclosed in the specified rectangle, and returns TRUE if so or FALSE if not. PROCEDURE Pt2Rect (ptA,ptB: Point; VAR: dstRect: Rect); Pt2Rect returns the smallest rectangle which encloses the ·two input points. 3/2/83 Espinosa-Rose /QUICK.2/QUIKDRAW.5

48

QuickDraw Programmer's Guide
VA~

PROCEDURE PtToAngle (r: Rect; pt: Point;

angle: INTEGER);

PtToAngle calculates an integer angle between a line from the center of the rectangle to the given point and a line from the center of the rectangle pointing straight up ,(12 o'clock high). The angle is in degrees from ~ to 359, measured clockwise from 12 o'clock, with 9~ degrees at 3 o'clock, 18~ at 6 o'clock, ·and.27~ at 9 o'clock. Other angles are measured relative to the rectangle: If the line to the given point goes through the top right corner of the rectangle, the angle returned is 45 degrees, even if the rectangle is nQt square; if it goes through the bottom right corner, the angle is 135 degrees, and so on (see Figure 18).

-----.....

~-~

....

pt.

~·-··-·-·1·-·-·
1 ....f _ _ _ _

_ ___,'

Figure 18.

PtToAngle

The angle returned' might be used as input to one of the proc'edures that manipulate arcs and wedges, as described 'below under "Graphic Operations on Arcs and Wedges". ,FUNCTION EqualRect (rectA,rectB: Rect) : 'BOOLEAN; EqualRect compares the two rectangles and returns' TRUE if they are equal or FALSE if not. The two rectangles must have identical boundary coordinates to be considered equal. FUNCTION EmptyRect (r: Rect) : BOOLEAN; EmptyRect returns TRUE if the given rectangle is an empty rectangle or FALSE if not. A rectangle is considered empty if the bottom coordinate 'is equal to or less than the top or the right coordinate is equal to or less than the left.

3/2/83 Espinosa-Rose

/QUICK.2/QUIKDRAW.5

QUICKDRAW ROUTINES

49

Graphic Operations on Rectangles These procedures perform graphic operations on rectangles. ScrollRect under "Bit Transfer Operations". PROCEDURE FrameRect (r: Rect); FrameRect draws a- hollow.outline just inside the specified rectangle, using the current grafPort's pen pattern, mode, and size. The outline is as wide as the pen width and as tall as the pen height. It ~s drawn with the pnPat, according to the pattern transfer mode specified by pnMode. The pen location is not changed by this procedure. If a region is open and being formed, the outside outline of the new rectangle is mathematically added to the region's boundary. PROCEDURE PaintRect (r: Rect); PaintRect paints the specified rectangle with the current grafPort's pen pattern and mode. The r'ectangle on the bitMap is filled with the pnPat, according to' the pattern transfer mode specified by pnMode. The pen location is not changed by this procedure. PROCEDURE EraseRect (r: Rect); EraseRect paints the specified rectangle with the current grafPort's background pattern bkPat (in patCopy mode). The grafPort's pnPat and pnMode are ignored; the pen location is not changed. PROCEDURE InvertRect (r:Rect); InvertRect inverts the pixels enclosed by the specified rectangle: every white pixel becomes black and every black pixel becomes white. The grafPort's pnPat, pnMode, and bkPat are all ignored; the pen location is not changed. - PROCEDURE FillRect (r: Rect; pat: Pattern); FillRect fills the specified rectangle with the given pattern (in patCopy mode). The grafPort's pnPat, pnMode, -and bkPat are all ignored; the pen location is not changed. See also

3/2/83 Espinosa-Rose

/QUICK.2-!QUIKDRAW • 5

50

QuickDraw Programmer's Guide

Graphic Operations on Ovals Ovals are drawn inside rectangles that you specify. you specify is square, QuickDraw draws a circle. PROCEDURE FrameOval (r: Rect); FrameOval draws a hollow outline just inside the oval that fits inside the specified rectangle, using the current grafPort's pen pattern, mode, and size. The outline is as wide as the pen width and as tall as the pen height. It is drawn with the pnPat, according to the pattern transfer mode specified by pnMode. The pen location is not changed by this procedure. If a region is open and being formed, the outside outline of the new oval is mathematically added to the region's boundary. PROCEDURE PaintOval (r: Rect); PaintOval paints an oval just inside the specified rectangle with the current grafPort's pen pattern and mode. The oval on the bi tMap is filled with the pnPat, according to the pattern ,transfer mode specified by pnMode. The pen location is not changed by this procedure. PROCEDURE EraseOval (r: Rect); EraseOval paints an oval just inside the specified rectangle wi th the current grafPort's background pattern bkPat (in patCopy mode). The grafPort's pnPat and pnMode are ignored; the pen location is not changed.
I

If the rectangle

PROCEDURE InvertOval (r: Rect); InvertOval inverts the pixels enclosed by an oval just inside the specified rectangle: every white pixel becomes black and every black pixel becomes white. The grafPort's pnPat, pnMode, and bkPat are all ignored; the pen location is not changed. PROCEDURE FillOval (r: Rect; pat: Pattern); Fil10val fills an oval just inside the specified rectangle with the given pattern ,(in patCopy mode). . The grafPort's pnPat, pnMode, and bkPat are all ignored; the pen location is not changed.

3/2/83 Espinosa-Rose

/QUICK.2/QUIKDRAW.5

QUICKDRAl~

ROUTINES

51

Graphic Operations on Rounded-Corner Rectangles

PROCEDURE

Frame~oundRect

'(r: Rect; ovaIWidth,ovaIHeight: INTEGER);

FrameRoundRect draws a hollow outline just inside the specified rounded-corner rectangle, using the current grafPort's pen pattern, mode, and size. Ovallvidth and ovalHeight specify the diameters of curvature for the corners (see Figure 19). The outline is as wide as the pen width and as tall as the pen height. It is drawn with the pnPat, according to the pattern transfer mode specified by pnMode. The pen location is not change? by this procedure.

OY31 V.f irl th
~.....---~
;
",\

oY;jlHeight

I,.,

......

_---_......

,."

(I) _- -_ \
.......
',,'

......

I/-~-~··)
1'0, ..-

(1. .··...----....-····. .
'.

.._---

<~

....

.\. ===..._--_. . ....l

Figure 19.

Rounded-Corner Rectangle

If a region is open and being formed, the outside outline of the new rounded~corner rectangle is mathematically added to the region's boundary. PROCEDURE PaintRoundRect (r: Rect; ovaIWidth,ovaIHeight: INTEGER); PaintRoundRect paints the specified rounded-corner rectangle with the current grafPort's pen pattern and mode. Ovallvidth and ovalHeight specify the diameters of curvature for the corners. The rounded-corner rectangle on the bitMap is filled with the pnPat, according to the pattern transfer mode specified by pnMode. The pen location is not changed by this procedure. PROCEDURE EraseRoundRect (r: Rect; ovallvidth,ovaIHeight:
INT~GER);

OvalWidth and ova1Heig\:tt specify the diameters of curvature for the corners. The grafPort's pnPat and pnMode are ignored; the pen location is not changed. PROCEDURE InvertRoundRect (r: Rect; ovalWidth,ovalHeight: INTEGER); InvertRoundRect inverts the pixels enclosed by the specified rounded-corner rectangle: every White pixel becomes black and every black pixel becomes White. OvalWidth and ovalHeight specify the diameters of curvature for the corners. The grafPort's pnPat, pnMode, and bkPat are all ignored; the pen location is not changed. PROCEDURE FillRoundRect (r: Rect; ovalWidth,ovalHeight: INTEGER; pat: Pattern); FillRoundRect fills the specified rounded-corner rectangle with the given pattern (in p'atCopy mode). OvalWidth and ovalHeight specffy the diameters of curvature for the corners. The grafPort's pnPat, pnMode, and bkPat are all ignored; the pen location is not changed. Graphic Operations on Arcs and Wedges These procedures perform graphic operations on arcs and wedge-shaped sections of ovals. See also PtToAngle under "Calculations with Rectangles". PROCEDURE FrameArc (r: Rect; startAngle,arcAngle: INTEGER); FrameArc draws an arc of the oval' that fits inside the, specified rectangle, using the current grafPort's pen pattern, mode, and size. StartAngle indicates Where the arc begins and is treated mod 36~. ArcAngle defines the extent of the arc. The angles are given in positive or negative degrees; a positive angle goes clockwise, While a negative angle goes counterclockwise. Zero degrees is at 12 o'clock high, 90 (or -270) is at 3 o"clock, 180 (or -18~) is at6 o'clock, and 270 (or -90) is at 9 o'clock. Other angles are measured relative to the enclosing rectangle: a line from the center of the rectangle through its top right 'corner is at 4S degrees, even if the rectangle is not square; a line through the bottom right corner is at 13S degrees, and so on (see Figure 20).

3/2/83 Espinosa-Rose

/QUICK.2/QUIKDRAW.S

QUICKDRAW ROUTINES

53

3t8ft.Afl~le

= (I .
l

~ ·f\1'r.A·p,jl~ -= 4 f··' '\::. " ..'

s!.;:lftAng,le =(I

st ijf1.Angle =

n
FraffLeArG
2It:~1't.Angle

·-1!,'Arl 1.::. - -4l"t\.:
,j
I• •"

:j''''';

({m I
••

':''''''Ar'1' :. i:1.... I.. L~ 1;= 4l" .J

.

I
,I

-= I)

L!____J

r FrijffteArc

!~
\r

-:1
~

}i;fcAngle :: .4S

P8,int.Arc
Figure 20. Operations on Arcs and Wedges It

The arc is as wide as the pen width and as tall as the pen height. is drawn with the pnPat, according to the pattern transfer mode specified by pnMode. The pen location is not changed by this procedure. ( eye) FrameArc differs from other QuickDraw procedures that frame shapes in that the arc is not mathematically added to the boundary of a region that is open and being formed. PROCEDURE PaintArc (r: Rect; startAngle,arcAngle: INTEGER);

PaintArc paints a wedge of the oval just inside the specified rect"angle with the current grafPort's pen pattern and mode. StartAngle and arcAngle define the arc of the wedge as in FrameArc. The wedge on the bitMap is filled with the pnPat, according. to the pattern transfer mode specified by pnMode. The pen location is not changed by this procedure • .PROCEDURE EraseArc (r: Rect; startAngle,arcAngle: INTEGER); EraseArc paints a wedge of the oval just inside the specified rectangle with the current grafPort's background pattern bkPat '(in patCopy mode). StartAngle and arcAngle define the arc of the wedge as in FrameArc. The grafPort's pnPat and pnMode are ignored; the pen location is not changed •

. 3/2/83 Espinosa-Rose

IQUICK. 2/QUIKDRAW.5

54

QuickDraw Programmer's Guide

PROCEDURE InvertArc (r: Rect; startAngle,arcAngle: INTEGER); InvertArc inverts the pixels enclosed by a wedge of the oval just inside the specified rectangle: every white pixel becomes black and every black pixel becomes white. StartAngle and arcAngle define the arc of the wedge as in FrameArc. The grafPort's pnPat, pnMode, and bkPat are all ignored; the pen location is not changed. PROCEDURE FillArc (r: Rect; startAngle,arcAngle: INTEGER; pat: Pattern); FillArc fills a wedge of the oval just inside the specified rectangle with the given pattern (in patCopy mode). StartAngle and arcAngle define the arc of the wedge as in FrameArc. The grafPort's pnPat, pnMode, and bkPat are all ignored; the pen location is not changed. Calculations with Regions ( hand) Remember that if the parameters to one of the calculation routines were defined in different grafPorts, you must first adjust them to be in the same coordinate system. If you do not adjust them, the result returned by the routine may be different from what I.you see on the screen. To adjust to a common coordinate system, see LocaltoGlobal and GlobalToLocal under "Calculations with Points" below. FUNCTION NewRgn : RgnHandle; NewRgn allocates space for a new, dynamic ,. variable-size region, initializes it to the empty region (0,0,0,0), and returns a handle to the new region. Only this function creates new regions; all other procedures just alter the size and shape of regions you create. OpenPort calls NewRgn to allpcate space for the port's visRgn and cl:i:pRgn. ( eye) Except When using visRgn or clipRgn, you MUST call NewRgn before specifying a region's handle in any drawing or calculation procedure. ( eye) Never refer to a region without using its handle. PROCEDURE DisposeRgn (rgn: RgnHandle); DisposeRgn deallocates space for the region whose handle is supplied, and returns the memory used by the region to the free memory pool. Use 3/2/83 Espinosa-Rose /QUICK. 2/QUIKDRAW. 5 .

QUICKDRAW ROUTINES this only after you are completely through with a temporary region. ( eye) Never use a region once you have deallocated it, or you will risk being hung by dangling pointers! PROCEDURE CopyRgn (srcRgn,dstRgn: RgnHandle);

55

CopyRgn copies~the mathematical structure of srcRgn into dstRgn; that is, it makes a duplicate copy of srcRgn. Once this is done, srcRgn may be altered (or even disposed of) without affecting dstRgn: COPYRGN DOES NOT CREATE THE DESTINATION REGION: you must use NewRgn to create the dstRgn before you call CopyRgn. PROCEDURE SetEmptyRgn (rgn: RgnHandle); SetEmptyRgn destroys the previous structure of the given region, then sets the new structure to the empty region (0,0,0,0). PROCEDURE SetRectRgn (rgn: RgnHandle; left,top,right,bottom: INTEGER); SetRectRgn destroys the previous structure of the given region, then sets the new structure to the rectangle specified by left, top, right, and bottom. If the specified rectangle is empty (i.e., left>=right or top>=bottom), the region is set to the empty'region (0,0,0,0). PROCEDURE RectRgn (rgn: RgnHandle; r: Rect); .RectRgn destroys the previous structure of the given region, then sets the new structure to the rectangle specified by r. This is operationally synonymous with SetRectRgn, except the input rectangle is defined by a rectangle rather than by four boundary coordinates. PROCEDURE OpenRgn; OpenRgn tells QuickDraw to allocate temporary space and start saving lines and framed shapes for later processing as a region definition. While a region is open, all calls to Line, LineTo, and the procedures that draw framed shapes (except arcs) affect the outline of the region. Only the line endpoints and shape boundaries affect the region definition; 'the pen mode, pattern, and size do not affect it. In fact, OpenRgn calls HidePen, so no drawing occurs on the screen While the region is open (unless you called ShowPen just after OpenRgn, or you called ShowPen previously without balancing it by a call to HidePen). Since the pen hangs below and to the right of the pen location, drawing lines with even the smallest pen will change bits that lie outside the region you define. 3/2/83 Espinosa-Rose /QUICK.2/QUIKDRAW.5

56

QuickDraw Programmer's Guide

The outline of a region is mathematically defined and infinitely thin, and separates the bitMap into two groups of bits: those within the region and those outside it. A region should consist of one or oore closed loops. Each framed shape itself constitutes a loop. Any lines drawn with Line or LineTo should connect with each other or with a framed shape. Even ~hough the on-scre~n presentation of a region is clipped, the definition of a region is not; you can define a region anywhere on the coordinate plane-with complete disregard for the location of various grafPort entities on that plane. l-1hen a region. is open, the current grafPort's rgnSave field contains a handle to information related to the region definition. If you want to temporarily disable the collection of lines and shapes, you can save the current value of this field, set the field to NIL, and la ter restore the saved value to resume the region definition. ( eye) Do not call OpenRgn while another region is already open. All open regions but the most recent Will behave strangely. PROCEDURE CloseRgn (dstRgn: RgnHandle); CloseRgn stops the collection of lines and framed shapes, organizes them into a region definition, and saves the resulting region into the region indicated by dstRgn. You should perform one and only one CloseRgn for every OpenRgn. CloseRgn calls ShowPen, balancing the HidePen call made by OpenRgn.
H~re's

an example of how to create and open a region, define a barbell shape, close the region; and draw it: barbell := NewRgn; OpenRgn; SetRect(tempRect,20,20,30,50); FrameOval(tempRect);
SetRect(tempRect,30,30,8~,40);

{make a new region} {begin collecting stuff} {form the left weight} {form the bar} {form the right weight} {we're done; save in barbell} {draw it on the screen} {we don't need you anymore ••• }

PROCEDURE OffsetRgn (rgn: RgnHandle; dh,dv: INTEGER); OffsetRgn moves the region on the coordinate plane, a distance of dh horizontally and dv vertically. This does not affect the screen unless you subsequently call a routine to draw the region. If dh and dv are positive, the movement is to the right and down; if either is negative, the corresponding movement is in the opposite direction. The region retains its size and shape. 3/2/83 Espinosa-Rose /QUICK. 2/QUIKDRAW.5
)

QUICKDRAW ROUTINES ( hand) OffsetRgn is an especially efficient operation, because most of the data defining a region is stored relative to rgnBBox and so isn't actually changed by OffsetRgn. PROCEDURE InsetRgn (rgn: RgnHandle; dh,dv: INTEGER);

57

InsetRgn shrinks or expands the region. All points on the region boundary are moved inwards a distance of dv vertically and dh . horizontally; if dh or dv is negative, the points are roved outwards in that direction. InsetRgn leaves the region "centered" at the same position, but moves the outline in (for positive values of dh and dv) or out (for negative values of dh and dv). InsetRgn of a rectangular region works just like InsetRect.
\

PROCEDURE SectRgn (srcRgnA,srcRgnB,dstRgn: RgnHandle); SectRgn calculates the intersection of two regions, and places the intersection in a third region. THIS DOES NOT CREATE THE DESTINATION REGION: you must use NewRgn to create the dstRgn before you call SectRgn. The dstRgn can be one of the source regions, if desired. If the regions do not intersect, or one of the regions is empty, the destination is set to the empty region (0,0,0,0). PROCEDURE UnionRgn (srcRgnA,srcRgnB,dstRgn: RgnHandle); UnionRgn calculates the union of two regions and places the union in a third region. THIS DOES NOT CREATE THE DESTINATION REGION: you must use NewRgn to create the dstRgn befo·re you call UnionRgn. The dstRgn can be one of the source regions, if desired. If both regions are empty, the destination is set to the empty region

(0,O,O,O).
PROCEDURE DiffRgn (srcRgnA,srcRgnB,dstRgn: RgnHandle); DiffRgn subtracts srcRgnB from srcRgnA and places the difference in a third region. THIS DOES NOT CREATE THE DESTINATION REGION: you must use NewRgn to create the dstRgn before you call DiffRgn. The dstRgn can be one of the source regions, if desired. If the first source region is empty, the destination is set to the empty region (0,0,0,0). PROCEDURE XorRgn (srcRgnA,srcRgnB,dstRgn: RgnHandle);
J

XorRgn calculates the difference between the union and the intersection' of two regions and places the result in a third region. THIS DOES NOT 3/2/83 Espinosa-Rose /QUICK.2/QUIKDRAW.5

58

QuickDraw Programmer's Guide you must use NewRgn to create the The dstRgn can be one of the source

CREATE THE DESTINATION REGION: dstRgn before you call' XorRgn. regions, if desired.

If the regions are coincident, the destination is set to the empty region (0,0,0,0). FUNCTION PtlnRgn (pt: Point; rgn: RgnHandle) : 'BOOLEAN; PtlnRgn checks whether the pixel below and to the right of the given coordinate point is within the specified region, and returns TRUE if so or FALSE if not. FUNCTION RectlnRgn (r: Reci; rgn: RgnHandle) : BOOLEAN; RectInRgn checks whether the given rectangle intersects the specified region, and returns TRUE if the intersection encloses at least one bit or FALSE if not. FUNCTION EqualRgn (rgnA,rgnB: RgnHandle) : BOOLEAN; EqualRgn compares the two regions and returns TRUE if they are equal or FALSE if not. The two regions must have identical sizes, shapes, and locations to be considered equal. Any two empty regions are always equal. FUNCTION EmptyRgn (rgn: RgnHandle) : BOOLEAN; EmptyRgn returns TRUE if the region is an empty region ,or FALSE if not. Some of the circumstances in which an empty region can be created are: a NewRgn call; a CopyRgn of an empty region; a SetRectRgn or RectRgn with an empty rectangle as an argument; CloseRgn without a previous OpenRgn or with no drawing after an OpenRgn; OffsetRgn of an empty region; InsetRgn with an empty region or too large an inset; SectRgn of nonintersecting regions; UnionRgn of two empty regions; and DiffRgn or XorRgn of two identical or nonintersecting regions. Graphic Operations on Regions These routines all depend on the coordinate system of the current grafPort. If a region is drawn in a different grafPort than the one in which it was defined, it may not appear in the proper position inside the port. PROCEDURE FrameRgn (rgn: RgnHandle); FrameRgn draws a hollow outline just inside the specified region', using the current grafPort's pen pattern, mode, and size. The outline is as 3/2/83 Espinosa-Rose /QUICK.2/QUIKDRAW.6

QUICKDRAW ROUTINES wide as the pen width and as tall as the pen height; under no circumstances will the frame go outside the region boundary. The pen location is not changed by this procedure.

59

If a region is open and being formed, the outside outline of the region being framed is mathematically added to that region's boundary. PROCEDURE PaintRgn (rgn: RgnHandle); PaintRgn paints the specified region with the current grafPort'spen pattern and pen mode. The region on the bitMap is filled with the pnPat, according to the pattern transfer mode specified by pnMode. The pen location is not changed by this procedure. , PROCEDURE EraseRgn (rgn: RgnHandle); EraseRgn paints the specified region with the current grafPort's background pattern bkPat (in patCopy mode). The grafPort's pnPat and pnMode are ignored; the pen location is not changed. PROCEDURE InvertRgn (rgn: RgnHandle); InvertRgn inverts the pixels enclosed by the specified ~egion: every white pixel becomes black and every black pixel becomes white. The grafPort's pnPat, pnMode, and bkPat are all ignored; the pen location is not changed. PROCEDURE FillRgn (rgn: RgnHandle; pat: Pattern); FillRgn fills the specified region with the given pattern (in patCopy mode).· The grafPort's pnPat, pnMode, and 'bkPat are all ignored; the pen location is pot changed. Bit Transfer Operations

PROCEDURE ScrollRect (r: Rect; dh,dv: INTEGER; updateRgn: RgnHandle); ScrollRect shifts ("scrolls") those bits inside the intersection of the specified rectangle, visRgn, clipRgn, portRect, and portBits.bounds. rhe bits are shifted a distance of dh horizontally and dv vertically. The positive directions are to the right and down. No other bits' are affected. Bits that are shifted out of the scroll area are lost; they are neither placed outside the area nor saved. The grafPort's background pattern bkPat fills the space created by the scroll. In addition,updateRgn is changed to the area filled with bkPat (see Figure 21).

3/2/83 Espinosa-Rose

IQUICK.2/QUIKDRAW.6

60

QuickDraw Programmer's Guide

·~t·lll··' _ ~;:. BI~;:.

l··-111lLr).~ .)1•.' _ r'i.~;:·I.-[ •.·.

1""'1

"t"-r"l" L.I:;.·
._1 ••.\.••

f··-l"ltn.'.--r(-/.~ .)1..' 'oJ ·['iX·!.,·l· •. I.-1;:arf'i.~;.·f..·

n ..,.-[., -f 0,._1 - C •••..'1

c

J

Figure 21.

Scrolling

Figure 21 shows that the pen location after a ScrollRect is in a different position relative to what was scrolled in the rectangle. The entire scrolled item has been moved to different coordinates. To restore it to its coordinates before the ScrollRect, you can use the SetOrigin procedure. For example, suppose the dstRect here is the portRect of the grafPort and its top left corner is at (95,120). SetOrigin(105,115) will offset the coordinate system to compensate for the scroll. Since the clipRgn and pen location are not offset, they move down and to the left. PROCEDURE CopyBits (srcBits,dstBits: BitMap; srcRect,dstRect: Rect; mode: INTEGER; maskRgn: RgnHandle); CopyBits transfers a bit image between any two bitMaps and clips the result to the area'specified by the maskRgn parameter. The transfer may be performed in any of the eight source transfer modes. The result is always clipped to the maskRgn and the boundary rectangle of the destination bitMap; if the destination bitMap is the current grafPort's portBits, it is also clipped to the intersection of the grafPort's clipRgn and v~sRgn. If you do not want to clip to a maskRgn, just pass NIL for the maskRgn parameter. The dstRect and maskRgn coordinates are in terms of the dstBits.bounds coordinate system, and the srcRect coordinates are in terms of the srcBits.bounds coordinates. The bits enclosed by the source rectangle are transferred into the destination rectangle according to the rules of the chosen mode. The source transfer modes are as follows: srcCopy srcOr 3/2/83 Espinosa-Rose srcXor srcBic notSrcCopy 'notSrcOr notSrcXor notSrcBic /QUICK.2/QUIKDRAW.6

QUICKDRAW

ROUTINE~

61

The source rectangle is completely aligned with the destination rectangle; if the rectangles are of different sizes, the bit image is expanded or shrunk as necessary to fit the destination rectangle. For example, if the bit image is a circle in a square source rectangle, and the des tination rectangle is not square, the bi t image appears as an oval in the destination (see Figure 22).

Source
Tr;jJLSfer
M\){le.

ma.stR:;1l

=NIl.
Source
Tf;;ft~lfef

l'.'lo(le
Figure 22.
Ope~ation

of CopyBits

Pictures

FUNCTION OpenPicture (picFrame: Rect) : PicHandle; OpenPicture returns a handle to a new picture Which has the given rectangle as its picture frame, and tells QuickDraw to start saving as the picture definition all calls to drawing routines and all picture comments (if any). OpenPicture calls HidePen, so no drawing occurs on the screen While the picture is open (unless you call ShowPen just after OpenPicture, or you called ShowPen previously without balancing it by a call to HidePen). When a picture is open, the current grafPort's picSave field contains a handle to information related to the picture definition. If you want to temporarily disable the collection of routine calls and picture comments, you can save the current value of this field, set the field to NIL, and later restore the saved value to resume the picture definition. ( eye) Do not call OpenPicture while another picture is already open. 3/2/83 Espinosa-Rose /QUICK.2/QUIKDRAW.6

62

QuickDraw Programmer's Guide

PROCEDURE ClosePicture; ClosePicture tells QuickDraw to stop saving routine calls and picture comments as the definition of the currently· open picture. You should perform one and only one ClosePicture for every OpenPicture. ClosePicture calls ShowPen, balancing the HidePen call made by ,OpenPicture. PROCEDURE PicComment (kind,dataSize: INTEGER; dataHandle: QDHandle); PicComment inserts the specified comment into the definition of the currently open picture. Kind identifies the type of comment. DataHandle is a handle to additional data if desired, and dataSize is the size of that data in bytes. If there is no additional data for the comment, dataHandle should be NIL and dataSize should be~. The application that processes the comment must include a procedure to do the processing and store a pointer to the procedure in the data structure pointed to by the grafProcs field of the grafPort (see "Customizing QuickDraw Operations"). PROCEDURE DrawPicture (myPicture: PicHandle; dstRect: Rect); DrawPicture draws the given picture .to scale ·in dstRect, expanding or shrinking it as necessary to align the borders of the picture frame with dstRect. DrawPicture passes any picture comments to the procedure accessed indirectly through the grafProcs field·of the grafPort (see PicComment above). PROCEDURE K111Picture (myPicture: PicHandle); KillPicture deallocates space for the picture whose handle is supplied, and returns the memory used by the picture to the free memory pool. Use this only when you are completely through with a picture. Calculations with Polygons

'FUNCTION OpenPoly : PolyHandle; OpenPoly returns a handle to a new polygon and tells QuickDraw to start saving the polygon definition as specified by calls to line-drawing routines. l~ile a polygon is open, all calls to Line and LineTo affect the outline of the polygon. Only the line endpoints affect the polygon definition; the pen mode, pattern, and size do not affect it. In fact, OpenPoly calls HidePen, so no drawing occurs on the screen while the polygon is open (unless you call ShowPen just after OpenPoly, or you called ShowPen previously without balancing it by a call to HidePen)./

3/2/83 Espinosa-Rose

/QUICK.2/QUIKDRAW.6

QUICKDRAW ROUTINES

63

A polygon should consist of a sequence of connected lines. Even though the on-screen presentation of a polygon is clipped, the definition of a polygon is not; you can define a polygon anywhere on the coordinate plane with complete disregard for the location of various grafPort entities on that plane. When a polygon is open, the current grafPort's a handle to information related to the polygon to temporarily disable the polygon definition, value of this field, set the field to NIL, and value to resume the polygon definition. ( eye) Do not call OpenPoly while another polygon is already open. PROCEDURE ClosePoly; ClosePoly tells QuickDraw to stop saving the definition of the currently open polygon and computes the polyBBox rectangle. You should perform one and only one ClosePoly for every OpenPoly. ClosePoly calls ShowPen, balancing the HidePen call made by OpenPoly. Here's an example of ,how to open a polygon, define it as a triangle, close it, and draw it: triPoly := OpenPoly; MoveTo(300,100); LineTo(400,200); , LineTo(200,200); LineTo(300, 100); ClosePoly; FillPoly(triPoly,gray); KillPoly(triPoly); {save hand Ie and begin collecting stuff} { move to first point and'} { } form } { the } { triangle {stop collecting stuff} {draw it on the screen} {we're all done} polySave field contains definition. If you want you can save the current later restore the saved

PROCEDURE KillPoly (poly: PolyHandle); KillPoly deallocates space for the polygon whose handle is supplied, and returns the memory used by the polygon to the free memory pool. Use this only after you are completely through with a polygon. PROCEDURE OffsetPoly (poly: PolyHandle;
dh~dv:

INTEGER);

OffsetPoly moves the polygon on the coordinate plane, a distance of dh horizontally and dv vertically. This' does not affect the screen Unless you subsequently call a routine to draw the polygon. If dh and dv are positive, the movement is to the right and down; if either is negative, the corresponding movement is in the opposite direction. The polygon retains its shape and size.

3/2/83 Espinosa-Rose

/QUICK.2/QUIKDRAW.6

64

QuickDraw Programmer's Guide

( hand) OffsetPoly is an especially efficient operation, because the data defining a polygon is stored relative to polyStart and so isn't actually changed by OffsetPoly. Graphic
Oper~tions

on Polygons

PROCEDURE FramePoly (poly: PolyHandle); FramePoly plays back.the line-drawing routine calls that define the given polygon, using the current grafPort's pen pattern, mode, and, size. The pen will hang below and to the right of each point on theboundary of the polygon; thus, the polygon drawn will extend beyond the right and bottom edges of poly~~.polyBBox by the pen width and pen height, respectively. All other graphic operations occur strictly within the boundary of the polygon, as for other shapes. You can see this difference in Figure 23, where each of the polygons is shown with its polyBBox.

FrarneF'oly
Figure 23.

F'ajntPoiy
Drawing Polygons

If a polygon is open and being formed, FramePoly affe.cts the outline of the polygon just as if the line-drawing routines themselves had been called. If a region is open and being formed, the outside outline of the polygon being framed is mathematically added to the region's boundary. . PROCEDURE PaintPoly (poly:PolyHandle); PaintPoly paints the specified polygon with the current grafPort's pen pattern and pen mode. The polygon on the bitMap is filled with the pnPat, according to the pattern transfer mode specified by pnMode. The 3/2/83 Espinosa-Rose /QUICK.2/QUIKDRAW.6

QUICKDRAW ROUTINES pen location is not changed by this procedure. PROCEDURE ErasePoly (poly: PolyHandle); ErasePoly paints the specified polygon with the current grafPort's background pattern bkPat (in patCopy mode). The pnPat and pnMode are ignored; the pen location is not changed. PROCEDURE InvertPoly (poly: PolyHandle);

65

InvertPoly inverts the pixels enclosed by the specified polygon: every white pixel becomes black and every black pixel becomes white. The grafPort's pnPat, pnMode, and hkPat are all ignored; the pen location is not changed. PROCEDURE FillPoly (poly: PolyHandle; pat: Pattern); FillPoly fills ,the specified polygon with the given pattern (in patCopy mode). The grafPort's pnPat, pnMode, and bkPat are all ignored; the pen location is not changed. Calculations with Points

PROCEDURE AddPt (srcPt: Point; VAR dstPt: Point); AddPt adds the coordinates of srcPt to the coordinates of dstPt, and returns the result in dstPt. PROCEDURE SubPt (srcPt: Point; VAR dstPt: Point); SubPt subtracts the coordinates of srcPt from the coordinates of dstPt, and returns the result in dstPt. PROCEDURE SetPt (VAR pt: Point; h,v: INTEGER); SetPt assigns two integer coordinates to a variable of type Point. FUNCTION EqualPt (ptA,ptB: Point) : BOOLEAN; EqualPt compares the two points and returns true if they are equal or FALSE if not.

3/2/83 Espinosa-Rose

/QUICK.2/QUIKDRAW.6

66

QuickDraw Programmer's Guide

. PROCEDURE LocalToGlobal (VAR pt: Point); LocalToGlobal converts the given point from the current grafPort's local coordinate system into a global coordinate system with the origin (0,O) at the top left corner of the port's bit image (such as 'the screen). This global point can then be compared to other global points, or be changed into the local coordinates of another grafPort. Since a rectangle is defined by two points, you can convert a rectangle into global coordinates by.performing two LocalToGlobal calls. You can also convert a rectangle, region, or polygon into global coordinates by calling OffsetRect, OffsetRg~, or OffsetPoly. For examples, see Globa1ToLocal below. . . PROCEDURE Globa1ToLoca1 (VAR pt: Point); G10ba1ToLoca1 takes a point expressed in global coordinates (with the top left corner of the bitMap as coordinate (0,O») and converts it into the local coordinates of the current grafPort. The global point can be obtained with the Loca1ToG10ba1 call (see above). For example, suppose a game draws a "ball" within a rectangle named ba1lRect, defined in the grafPort named gamePort (as illustrated below in Figure 24). If you want to draw that ball in the grafPort named selectPort, you can calculate the ball's selectPort coordinates like this: SetPort(gamePort); selectBa11 := ba11Rect; Loca1ToGloba1(se1ectBa1l.topLeft); LocalToG1obal(se1ectBal1.botRight); SetPort(se1ectPort); Globa1ToLoca1(se1ectBall.topLeft); Globa1ToLoca1( se1ectBall. botRight); FillOval(se1ectBa1l,ba11Color); {start in origin po.rt} {make a copy to be moved} {put both corners into} { global coordinates } {switch to destination port} {put both corners into } '{ these .loca1 coordinates,} {now you have the ba1~!}

You can see from Figure 24 that LocalToGlobal and GlobalToLocal simply offset the coordinates of the rectangle by the coordinates of the top left corner of the local grafPort's boundary rectangle. You could also do this with OffsetRect. In fact, the way to convert regions and polygons from one coordinate system to another is with OffsetRgn or OffsetPoly rather than Local~oGlobal and GlobalTqLocal. For example, if myRgn were a region enclosed by a rectangle having the same coordinates as ballRect in gamePort, you could convert the region to global coordinates with OffsetRgn(myRgn, -20, -40); and then convert it to the coordinates of the selectPort grafPort with OffsetRgn(myRgn, 15, -30);

Miscellaneous Utilities

FUNCTION Random : INTEGER; This function returns an integer, uniformly distributed pseudo-random, in the range from -32768 through 32767. The value returned depends on the global variable randSeed, which InitGraf initializes to 1; you can start the sequence over again from where it began by resetting randSeed to 1.

3/2/83 Espinosa-Rose

/QUICK.2/QUIKDRAW.6

68

QuickDraw Programmer's Guide

FUNCTION GetPixel (h,v: INTEGER) : BOOLEAN; GetPixel looks at the pixel associated with the given coordinate point and returns TRUE if it is black or FALSE if it is White. The selected pixel is immediately below and to the right of the point Whose coordinates are given in h and v, in the local coordinates of the current grafPort. There is no guarantee that the specified pixel actually belongs to the port, however; it may have been drawn by a port overlapping the current one. To see if the point indeed belongs to the current port, perform a PtInRgn(pt,thePortA.visRgn). PROCEDURE StuffHex (thingPtr: QDPtr; s: Str255); StuffHex pokes bits (expressed as a string of hexadecimal digits) into any data structure. This is a good way to create cursors, patterns, or bit images to be "stamped" onto the screen W;th CopyBits. For example,
r

StuffHex(@stripes,'0l02040810204080') places a striped pattern into the pattern variable stripes. ( eye) There is no range checking on the size of the destination variable. It's easy to overrun the variable and destroy something if you don't know what you're doing. PROCEDURE ScalePt (VAR pt: Point; srcRect,dstRect: Rect); A width and height are passed in pt; the horizontal component of pt is the width, and the vertical component of pt is the height. ScalePt scales these measurements as follows and returns the result in pt: it multiplies the given width by the ratio'of dstRect's width to srcRect's width, and multiplies the given height by the ratio of dstRect's height to srcRect's height. In Figure 25, Where dstRect's width is twice srcRect's width and its height is three times srcRect's height, the pen width is scaled from 3 to 6 and the pen height is scaled from 2 to 6.

3/2/83 Espinosa-Rose

/QUICK. 2/QUIKDRAW., 6

QUICKDRAW ROUTINES

69

\)
i

:)
t

16 1i
r

Figure 25.

ScalePt and MapPt

PROCEDURE MapPt (VAR pt: Point; srcRect,dstRect: Rect); Given a point within srcRect, MapPt maps it to a similarly located point within dstRect (that is, to where it would fall if it were part of a drawing being expanded or shrunk to fit dstRect). The result is returned in pt. A corner point of srcRect would be mapped to the corresponding corner point of dstRect, and the center of srcRect to the center of dstRect. In Figure 25 above, the point (3,2) in srcRect is mapped to (18,7) in dstRect. FromRect and dstRect may overlap, and pt need not actually be within srcRect. ( eye) Remember, if you are going to draw inside the rectangle in dstRect, you will probably also want to scale the pen size accordingly with ScalePt. PROCEDURE MapRect (VAR r: Rect; srcRect,dstRect: Rect); Given a rectangle within srcRect, MapRect maps it to a similarly located rectangle within dstRect by calling MapPt to map the top left and bottom right corners of the rectangle. The result is returned in

r.
PROCEDURE MapRgn (rgn: RgnHandle; srcRect,dstRect: Rect)"; Given a region within srcRect, MapRgn maps it to a similarly located region within dstRect by calling MapPt to map all the points in the region.

3/2/83 Espinosa-Rose

IQUICK.2/QuIKDRAW.6

70

QuickDraw Programmer's Guide

PROCEDURE MapPoly (poly: PolyHandle; srcRect,dstRect: Rect); Given a polygon within srcRect, MapPoly maps it to a similarly located polygon witQin dstRect by calling MapPt to map all the points that define the polygon.

CUSTOMIZING QUICKDRAW OPERATIONS For each shape that QuickDraw knows how to draw, there are procedures that perform these basic graphic operations on the shape: frame, paint, erase, invert, and fill. Those procedures in turn call a low-level drawing routine for the shape. For example, the FrameOval, PaintOval, EraseOval, InvertOval, and FillOval procedures all call a low-level routine that draws the oval. For each type of object QuickDraw can draw, including text and lines, there is a pointer to such a routine. By changing these pointers,. you can install your' own routines, and either completely override the standard ones or call them after your routines have ,modified parameters as necessary. Other low-level routines that you can install in this way are: - The procedure that does bit transfer and is called by CopyBits. - The function that measures the width of text and is called by CharWidth, String'-lidth, and TextWidth. - The procedure that processes picture comments and is called by DrawPicture. The standard such procedure ignores picture comments. - The procedure that saves drawing commands as the definition of a picture, and the one that retrieves them. This enables the application to. draw on remote devices, print to the disk, get picture input from the disk, and support large pictures. The grafProcs field of a grafPort determines which low-level routines are called; if it contains NIL, the standard routines are called, so that all operations in that grafPort are done in the standard ways described in this manual. You can set the grafProcs field to point to a record of pointers to routines. The data type of grafProcs is QDProcsPtr:

To assist you in setting up a QDProcs record, QuickDraw provides the following procedure: PROCEDURE SetStdProcs (VAR procs: QDProcs); This procedure sets all the fields of the given QDProcs record to point to the standard low-level routines. You can then change the ones you wish to point to your own routines. For example, if your procedure that processes picture comments is named MyComments, you will store @MyComments in the commentProc field of the QDProcs record. The routines you install must of course have the same calling sequences as the standard routines, which are described below. The stanQard drawing routines tell which graphic operation to perform from a parameter of type GrafVerb. TYPE GrafVerb

=

(frame, paint, erase, invert, fill);

When the grafVerb is fill, the pattern to use when filling is passed in the fillPat field of the grafPort. PROCEDURE StdText (byteCount: INTEGER; textBuf: QDPtr; numer,denom: INTEGER); StdText is the standard low-level routine for drawing text. It draws text from the arbitrary structure in memory specified by textBuf, starting from the first byte and continuing for byteCount bytes. Numer and denom specify the scaling, if any: numer.v over cienom.v gives the vertical scaling, and numer.h over denom.h gives the horizontal scaling. PROCEDURE-StdLine (newPt: Point); StdLine is the standard low-level routine for drawing a line. It draws a line from the current pen location to the location-specified (in 3/2/83 Rose /QUICK.2/QUIKDRAW.7

72

QuickDraw Programmer's Guide

local coordinates) by newPt. PROCEDURE StdRect (verb: GrafVerb; r: Rect);
StdR~ct is the standard low-level routine for drawing a rectangle. draws the given rectangle according to the specified grafVerb.

It·

PROCEDURE StdRRect (verb: GrafVerb; r: Rect; ovalwidth,ovaIHeight: INTEGER) ; StdRRect is the standard low-level routine for drawing a rounded-corner rectangle. It draws the given rounded~corner rectangle according to the specified grafVerb. Ovalt-lidth and ovalHeight specify the diameters of curvature for the corners. PROCEDURE StdOval (verb: GrafVerb; r: Rect); StdOval is the standard low-level routine for drawing an oval. It draws an oval inside the given rectangle according to the specified grafVerb. PROCEDURE StdArc (verb: GrafVerb; r: Rect; startAngle,arcAngle: INTEGER); StdArc is the standard low-level routine for drawing' an arc or a wedge. It draws an arc or wedge of the oval that fits inside the given rectangle. The grafVerb specifies the graphic 'operation; if it's the frame operation, an arc is drawn; otherwise, a wedge is drawn. PROCEDURE StdPoly (verb: GrafVerb; poly: PolyHandle);' StdPoly is the standard low-level routine for drawing a polygon. draws the given polygon according to 'the specified grafVerb. PROCEDURE StdRgn (verb: GrafVerb; rgn: RgnHandle); StdRgn is the standard low-level routine for drawing a region. drayws the given region according to the specified grafVerb'. It It

PROCEDURE StdBits (VAR, srcBits: BitMap; VAR srcRect,dstRect: Rect; ,,_ mode: INTEGER; maskRgn: RgnHandle); StdBits is the standard low-level routine for doing bit transfer. It transfers a bit image between the given bitMap and thePort .... portBits, just as if CopyBits were called with the same parameters and with a destination bitMap equal to thePort .... portBits.

StdComment is the standard low-level routine for processing a picture comment. Kind identifies the type of comment. DataHandle is a handle to additional data, and dataSize is the size of that data in bytes. If there is no additio~al data for the command, dataHandle will be NIL and dataSize will be~. StdComment simply ignores the comment. FUNCTION StdTxMeas (byteCount: INTEGER; textBuf: QDPtr; VAR numer,denom: Point; VAR info: FontInfo) : INTEGER; StdTxMeas is the standard low-level routine for measuring text width. It returns the width of the text stored in the arbitrary structure in memory specified by textBuf, starting with the first byte and continuing for byteCount bytes. ~umer and denom specify the scaling as in the StdText procedure; note that StdTxMeas may change them. PROCEDURE StdGetPic (dataPtr: QDPtr; byteCount: INTEGER); StdGetPic is the standard low-level routine for retrieving information from the definition of a picture., It retrieves the next byteCount bytes from the definition of the currently open picture and s,tores them in the data structure pointed to by dataPtr. PROCEDURE StdPutPic (dataPtr: QDPtr; byteCount: INTEGER); StdPutPic is the standard low-level routine for saving information as the definition of a picture. It saves as the definition of the currently open picture the drawing commands stored in the data structure pointed to by dataPtr, starting with the first byte and continuing for the next byteCount bytes.

USING QUICKDRAW FROM ASSEMBLY LANGUAGE All Macintosh User Interface Toolbox routines can be called from assembly-Iangu~ge programs as well as from Pascal. When you write an assembly-language program to use these routines, though, you must emulate Pascal's parameter passing and variable transfer protocols. This section discusses how to use the QuickDraw constants, global' variables, data types, procedures, and functions from assembly language. The primary aid to assembly-language programmers is a file named GRAFTYPES.TEXT. If you use .INCLUDE to include this fi~e when you assemble your program, all the QuickDraw constants, offsets to locations of global variables, and offsets into the fields of structured types will be available in symbolic form.

3/2/83 Espinosa-Rose

/QUICK.2/QUIKDRAW.A

74

QuickDraw Programmer's Guide

Constants QuickDraw constants are stored in the GRAFTYPES.TEXT file, and you can use the constant values symbolically. For example, if you've loaded the effective address of the thePortA.txMode field into address register A2, you can set that field to the srcXor mode with this statement: MOVE. W flSRCXOR, (A2) To refer to the number of bytes occupied by the QuickDraw global variables, you can use the constant GRAFSIZE. When you call the InitGraf procedure, you must pass a pointer to an area at least that large. Data Types Pascal's strong' typing ability lets you write Pascal programs without really considering the size of a variable. But in assembly language, you must keep track of the size of every variable. The sizes of the standard Pascal data types are as follows: Type INTEGER LongInt BOOLEAN CHAR REAL Size Word Long Word Word Long (2 bytes)

(4 bytes)
(2 bytes) (2 bytes) (4 bytes)

INTEGERs and LongInts are in tWo's complement form; BOOLEANs have their boolean value in bit 8 of the word (the low-order bit of the byte at the same location); CHARs are stored in the high-order byte of the word; and REALs are in the KCS standard format~ The QuickDraw simple data types listed below are constructed out of these fundamental types. Type QDPtr QDHandle Word Str255 Pattern 'Bits16 Size Long (4 bytes) Long (4 bytes) Long (4 bytes) Page (256 bytes) 8 bytes 32 bytes

Other data types are constructed as records of variables of the above types. The size of such a type is the sum of the sizes of all the fields .in the record; the fields appear in the variable with the first field in the lowest address. For example, consider the data type BitMap, which is defined like this:

This data type would be arranged in memory as seven words: a long for the baseAddr, a word for the rowBytes, and four words for the top, left, right, and bottom parts of the bounds rectangle. To assist you in referring to the fields inside a variable' that has a structure like this, the GRAFTYPES.TEXT file defines constants that /you can use as offsets into the fields of a structured variable. For example, to move a bitMap's rowBytes value into D3, you would execute the following instruction: MOVE.W MYBITMAP+ROWBYTES,D3

Displacements are given in the GRAFTYPES.TEXT file for all fields of all data types defined by QuickDraw. To do double indirection, you perform an LEA indirectly to obtain the effective address from the handle. For example, to get at the top coordinate of a region's enclosin~ rectangle: MOVE.L MOVE.L MOVE.W ( eye) For regions (and all other variable-length structures with handles), you must not move the pointer into a register once and just continue'to use that pointer; you must do the double indirection each time. Every QuickDraw, Toolbox, or memory management call you make can possibly trigger a heap' compaction that renders all pointers to movable heap items (like regions) invalid. The handles will remain valid, but pointers you've obtained through handles can be rendered invalid at any subroutine call or trap in your program. Global Variables Global variables are stored in a special section of Macintosh low memory; register AS always points to this section of memory. The GRAFTYPES.TEXT file defines a constant GRAFGLOB that points to the begin'ning of the QuickDraw variables in this space, and other cons tants that point to' the individual variables. To access one of the variables, put GRAFGLOB in an address register, sum the constants, and index off of that register. For example, if you want to know the horizontal coordinate of the pen location for the current grafPort, which the global variable thePort points to, you, can give the following instructions: ' MYHANDLE,AI (AI) ,AI RGNBBOX+TOP(AI),D3 Load handle into Al Use handle to get pointer Load value using pointer

Procedures and Functions To call a QuickDraw procedure ot function, you must push all parameters to it on the stack, then JSR to the function or procedure. When you link your program wi th QuickDraw," these JSRs are adjusted to refer to the jump table in low RAM, so that a JSR into the table redirects you to the actual location of the procedure or function. The only difficu~t part about calling QuickDraw procedures and functions is stacking the parameters. You must follow some strict rules: - Save all registers you wish to preserve BEFORE you begin pushing parameters. Any QuickDraw procedure or function can destroy the contents of the registers A0, AI, n0, DI, and D2, but the others are never altered. - Push the parameters in the order 'that they appear in the Pascal procedural interface. - For booleans, push a byte; for integers and characters, push a word; for pointers, handles, long integers, and reals, push a long. - For any structured variable longer than four (4) bytes, push a pointer to the variable. - For all VAR parameters, regardless of size, push a pointer to the variable. - When calling a function, FIRST push a null entry equal to the size of the function result, THEN push all other parameters. The result will be left on the stack after the function returns to you. This maKes for a lengthy interface, but it also guarantees that you can mock up a Pascal version of your program, and later translate it into assembly code that works the same. For example, the Pascal statement blackness :=
GetPixel(5~,mousePos.v);

To call the TextFace prbcedure, push a word in Which each of seven bits represents a stylistic variation: set bit ~ for bold, bit 1 for italic, bit 2 for underline, bit 3 for outline, bit 4 for shadow, bit 5 for condense, and bit 6 for extend.

GLOSSARY bit image: A collection of bits in memory which have a rectilinear representation. The Macintosh screen is a visible bit image. bitMap: A pointer to a bit image., the row width of that image, and its boundary rectangle. boundary rectangle: A rectangle defined ,as part of a bitMap, which encloses the active area of the bit image and imposes a coordinate system on it. Its top left corner is always aligned around the first bit in the bit image. , character style: A set of stylistic variations, such as bold, italic, and underline. The empty set indicates normal text (no stylistic , variations). clipping: Limiting drawing to within the bounds of a particular area. Same as clipRgn.
'\

clipping region:

clipRgn: The region to which an application limits drawing in a grafPort. coordinate plane: A two-dimensional grid. In QuickDraw, the grid coordinates are integers ranging from -32768 to +32767, and all grid lines are infinitely thin. cursor: A l6-by-16-bit image that appears on the screen and is controlled by the mouse; called the "pointer" in other Macintosh documentation. cursor level: A value, initialized to ~ when the system is booted, that keeps track of the number of times the cursor has been hidden. empty: Containing no 'bits, as a shape defined by only one point.

font: The complete set of characters of one typeface, such as Helvetica. frame: To draw a shape by drawing, an outline of it.

global coordinate system: The coordinate system based on the top left corner of the bit image being at (0,O). grafPort: A complete drawing environment, including such elements as a bitMap, a subset of it in which to draw, a character font, patterns for drawing and erasing, and other pen characteristics. grafPtr: A pointer to a grafPort.

handle: A pointer to one master pointer to a dynamic, relocatable data structure (such as a region). 3/2/83 Rose /QUICK.2/QUIKDRAW.G

88

QuickDraw Programmer's Guide

hotSpot: The point in a cursor that is aligned with the mouse' position. kern: To stretch part of a character back under the previous character. local coordinate system: coordinate system local to a grafPort, imposed by the boundary rectangle defined in its bitMap. missing symbol: A character to be drawn in case of a request to draw a character that is missing from a particular font. pattern: An 8-by-8-bit image, used to define a repeating design (such as stripes) or tone (such as gray). pattern transfer mode: One of eight transfer mo4es for drawing lines or shapes with a patt~rn. picture: A saved sequence of QuickDraw drawing commands (and, optionally, picture comments) that you can play ,back later wi th a single procedure call; also, the image resulting from these commands. picture comments:' Data stored in the definition of a picture which does not affect the picture's appearance but may be used to provide additional information about the picture when it's played back. picture frame: A rectangle, defined as part of a picture, which surrounds the picture and gives a frame of reference for scaling when the picture is drawn. , pixel: bit is The visual representation of a bit on the screen (white if the

The

0, black if it's 1).

point: The intersection of a horizontal grid line and a vertical grid line on the coordinate plane, defined by a horizontal and a vertical coordinate. polygon: A sequence of connected lines, defined by QuickDraw line-drawing commands. port: Same as grafPort. The bitMap of a grafPort. The boundary rectangle of a'grafPort's bitMap.

portBits:

portBits.bounds:

portRect: A rectangle, defined as part of a grafPort, which encloses a subset of the bi tMap for use by the -grafPort. region: An ,arbitrary area or set of areas on the coordinate plane. The outline of a region should be one or more closed loops. row width: The number of bytes in each row of a bit image.

3/2/83 Rose

/QUICK.2/QUIKDRAW.G

GLOSSARY solid: Filled in with any pattern.

89

source transfer mode: One of eight transfer modes for drawing text or transferring any bit image between two bitMaps. style: thePort: See character style. A global variable that points to the current grafPort.

transfer mode: A specification of which boolean operation QuickDraw should perform when drawing or when transferring a bit image from one bitMap to another. visRgn:. The region of a grafPort, manipulated by the which is actually visible on the screen.'
~vindow

The Font Manager is the part of the Macintosh User Interface Toolbox that supports the use of various character fonts when you draw text" with QuickDraw. This manual introduces you to the Font Manager and describes the routines your application can call to get font information • . It also describes the data structures of fonts and discusses how the F9nt Manager communicates with QuickDraw. Summary of significant changes and additions since last draft: - The default application font has changed from New York to Geneva. - Details are now given on the font characterization table (page 13) • - Programmers defining their own fonts must include the characters with ASCII codes $~~, $~9, and $~D (page 18). - The sample location table and offset/width table have been corrected, as has the calculation of the offset in the font record's owTLoc field (page 21). - Some assembly-language information has been changed and added.

ABOUT THIS MANUAL The Font Manager is the part of the Macintosh User Interface Toolbox that 'supports the use of various character fonts when you draw text with QuickDraw. This manual intr09uces you to the Font Manager and describes the routines your application can call to get font information. It also describes the data structures of fonts and discusses how the Font Manager communicates with QuickDraw. *** Eventually this will become part of the comprehensive Inside Macintosh manual. *** Like all documentation about Toolbox units, this manual assumes you're familiar with the Macintosh User Interface Guidelines, Lisa Pascal, and the Macintosh Operating System's Memory Manager. You should also be familiar with: - resources, as described
i~

the Resource Manager manual

- the basic concepts and structures behind QuickDraw, particularly bit images and how to draw text This manual is intended to serve the needs of both Pascal and assemblylanguage programmers. Information of interest to assembly-language programmers only is isolated and labeled so that Pascal programmers can conveniently skip it. The manual begins with an overview of the Font Manager and what you can do with it. It then discusses the font numbers by which fonts are identified, the characters in a font, and the scaling of fonts to different sizes. Next, a section on using the Font Manager introduces its routines and tells how they fit into the flow of your application. Thi~ is followed by detailed descriptions of Font Manager procedures and functions, their parameters, calling protocol, effects, side effects, and so on. Following these descriptions are sections that will not interest all readers. There's a discussion of how QuickDraw and the Font Manager communicate, followed by a section that describes the format of the data structures used to define fonts, and how QuickDraw uses the data to draw characters. Next is a section that gives the exact format of fonts in a resource file. Finally, there's a summary of the Font Manager, for quick reference, followed by a glossary of terms used in this manual.

ABOUT THE FONT MANAGER The main function of the Font Manager is to provide font support for QuickDraw. To the Macintosh user, font means the complete set of characters of. one typeface; it does~include the size of the characters, ~nd usually doesn't include any stylistic variations (such 6/11/84 Rose-Hacker /FMGR/FONT.2

4

Font Manager Programmer's Guide

as bold and italic). (note) Usually fonts are defined in the normal style and stylistic variations are applied to them; for example, the italic style simply slants the normal characters. However, fonts may be designed to include stylistic variations in the first place. The way you identify a font to QuickDraw or the Font Manager is with a font number. Every font also has a name (such as "New York") that's appropriate to include in a menu of available fonts. The size of the characters, called the font size, is given in points. Here this term doesn't have the same meaning as the "point" that's an intersection of lines on the QuickDraw coordinate plane, but instead is 'a typographical term that stands for approximately 1/72 inch. The font size measures the distance between the ascent line of one line of text and the ascent line of the next line of single-spaced text (see Figure 1). It assumes 80 pixels per inch, the approximate resolution of the Macintosh screen. For example, since an Imagewriter printer has twice the resolution of the screen, high-resolution 9-point output to the printer is actually accomplished with an 18-point font.

ascent line
font size

J

"...

base line
} descent line

--t-,.--.--(. ,)
Figure 1. (note)

L'eading

Font Size

Because measurements cannot be exact on a bit-mapped output device, the actual font size may be slightly different from what it would be in normal typography. Whenever you call a QuickDraw routine that does anything with text, QuickDraw passes the following information to the Font Manager:

6/11/84 Rose-Hacker

/FMGR/FONT.2

ABOUT THE FONT MANAGER - The font number. - The character style, which is a set of stylistic variations. The empty set indicates normal text. (See the'QuickDraw manual for details.)

5

- The font size. The size may range from 1 point to 127 points, but for readability should be at least 6 points. - The horizontal and vertical scaling factors, each of which is ' represented by a numerator and a denominator (for example, a numerator of 2 and a denominator ·of 1 indicates.2-to-l scaling in that direction). - A Boolean value indicating whether the characters will actually be drawn or not. 'They will not be drawn, for example, when the QuickDraw function CharWidth is called (since it only measures charact&rs) or when text is drawn after the pen has been hidden (such as by the HidePen procedure or the OpenPicture function, which calls HidePen). - A number specifying the device on which the characters will be drawn or printed. The number ~ represents the Macintosh screen. The Font Manager can adapt fonts to other devices. Given this information, the Font Manager provides QuickDraw with information describing the font and--if the characters will actually be drawn--the bits comprising the characters. Fonts are stored as resources in resource files; the Font Manager calls the Resource Manager to read them into memory. System-defined fonts are stored in the system resource file. You may define your own fonts with the aid of the Resource Editor and include them in the system resource file-so they can be shared among applications. *** (The Resource Editor doesn't yet exist, but an interim Font Editor is available from Macintosh Technical Support.) *** In special cases, you may want to store a font in an application's resource file or even in the resource file for a document. It's also possible to store only the character widths and general font information, and not the bits comprising the characters, for those cases where the characters won't actually be drawn. A font may be stored in any number of sizes in a resource file. If a size is needed that's not available as a resource, the Font Manager scales an available size. Fonts occupy a large amount of storage: a 12-point font typically occupies about 3K bytes, and a 24-point font, about l~K bytes; fonts for use on a high-resolution output device can take up four times as much space as that (up to a maximum of 32K bytes). Fonts normally are purgeable, which means they may be removed from the heap when space is required by the Memory Manager. If you wish, you can call a Font Manager routine to make a'font temporarily unpurgeable.

6/11/84 Rose-Hacker

/FMGR/FONT.2

6

Font Manager Programmer's Guide

There are also routines that provide information about a font. You can find out the name of a font having a particular font number, or the font number for a font having a particular name. You can also learn whether a font is available in a certain size or will have to be scaled to that size.

The system font is so called because it's the font used by the system (for drawing menu titles and commands in menus, for example). The name of the system font is Chicago. The size of text drawn by the system in this' font: is fixed at 12 points (called the system font size). The application font is the font your application will use unless you specify otherwise. Unlike the system fpnt, the application font isn't a separate font with its own typeface, but is essentially a reference to another font--Geneva, by default. *** In the future, there may be a way f'or the user to change the application font, perhaps through the Control Panel desk accessory. ***

Assembly-language note: The font number of the application font is stored in the global variable apFontID.

6/11/84 Rose-Hacker

/FMGR/FONT.2

CHARACTERS IN A FONT

7

CHARACTERS IN A FONT A font can consist of up to 255 distinct characters; not all characters need be defined in a single font. Figure 2 on the following page shows the standard printing characters on the Macintosh and their ASCII codes (for example, the ASCII code for "A" is 41 hexadecimal, or 65 decimal). In addition to its maximum of 255 characters, every font contains a missing symbol that's drawn in case of a request to draw a character that's missing from the font.

FONT SCALING The information QuickDraw passes to the Font Manager includes the font size and the scaling factors QuickDraw wants to use. The Font Manager determines the font information to return to QuickDraw' by looking for the exact size needed among the sizes stored for the font. If the exact size requested isn't available, it then looks for a nearby size that it can scale. 1. 2. 3. It looks first for a font that's twice the size, and scales down that size if there is one.
\

If there's no font that's twice the size, it looks "for a font that's half the size, and scales up that size if there is one. If there's no font that's half the size, it looks for a larger size of the font, and scales do~n the next larger size if there is one. If there's no larger size, it looks for a smaller size of the font, and scales up the closest smaller size if there is one. If the font isn't available in any size at all, it uses the application font instead, scaling the font to the proper size. If the application font isn't available in any size at all, it uses the system font instead, scaling the font to the proper si~e.

4. 5. 6.

Scaling looks best when the scaled size is an even multiple of an available size.

Assembly-language note: You can use the global variable fScaleDisable to defeat scaling, if desired. Normally, fScaleDisable is 0. If you set it to a nonzero value,. the Font Manager will look for the size as described above but will return the font unsealed.

SP stands for a space. ...., stands for ~ nonbreak i ng space) same width as numbers. The first four characters are only in the system font (Chicago). The shaded characters are only in the Geneva, Monaco and system fonts. ASCII codes $9D 1hrough $FF are reserved for future expansion.

Figure 2.

Font Characters

6/11/84 Rose-Hacker

/FMGR/FONT.2

USING THE FONT MANAGER

9

USING THE FONT MANAGER This section introduces you to the Font Manager routines and how they fit into the general flow of an application pro~ram. the routines themselves are described in detail in the next section. The InitFonts procedure initializes the Font Manager; you should call it after initializing 'QuickDraw but before initializing the Window Manager. You can set up a menu of fonts in your application by using the Menu Manager procedure AddResMenu (see the .Menu Manager manual for details). When the user chooses a menu item from the font menu, call the Menu Manager procedure GetItem to get the name of the corresponding font, and then the Font Manager function GetFNum to get the font number. The GetFontName function does the reverse of GetFNum: given a font ID, it returns the font name. In a menu of font sizes in your application, you may want to let the user know which sizes the current font is available in and therefore will not require scaling. You can call the RealFont function to find out whether a font is available in a given size. If you know you'll be using a font a lot and don't want it to be purged, you can use the SetFontLock procedure to make the font unpurgeable during that time. Advanced programmers who want to write their own font editors or otherwise manipulate fonts ~an access fonts directly with the SwapFont function.

FONT MANAGER ROUTINES This section describes all the Font Manager procedures and functions. The routines are presented in their Pascal form; for information on using them from assembly language, see the manual Programming Macintosh Applications in Assembly Language. Initializing the Font Manager

PROCEDURE InitFonts; InitFonts initializes the Font Manager. If the system font isn't already in memory, InitFonts reads it into memory. Call this procedure once before ~ll other Font Manager routines or any Toolbox routine that will call the Font Manager.

6/11/84 Rose-Hacker

/FMGR/FONT.R

10

Font Manager Programmer's Guide

Getting Font Information

PROCEDURE GetFontName (fontNum: INTEGER; VAR theName: Str255); GetFontName returns in theNa~e the name of the font having the font number fontNum. If there's no such font, GetFontName returns the empty string.

Assembly-language note: The macro you invoke to call GetFontName from assembly language is named GetFName.

PROCEDURE GetFNum (fontName: Str255; VAR theNum: INTEGER); GetFNum returns in theNum the font number for the font having the given fontName. If there's no such font, GetFNum returns 0. FUNCTION RealFont (fontNum: INTEGER; size: INTEGER) : BOOLEAN; RealFont returns TRUE if the font having the font number fontNum is available in the given size in ~ resource file, or FALSE if the font has to be scaled to that size. Keeping Fonts in Memory

PROCEDURE SetFontLock (lockFlag: BOOLEAN); SetFontLock applies to the font in which text was most recently drawn; it makes the font unpurgeable if 10ckFIag is TRUE or purgeable if lockFlag is 'FALSE. Since fonts are normally purgeable, this procedure is useful for making a font temporarily unpurgeable. Advanced Routine The following low-level routine will not normally be used by an appl~cation directly, but may be of interest to advanced programmers who want to bypass the QuickDraw routines that deal with text.

6/11/84 Rose-Hacker

/FMGR/FONT.R

FONT MANAGER ROUTINES FUNCTION SwapFont (inRec: ,FMInput) : FMOutPtr; SwapFont returns a pointer to an FMOutput record containing the size, style, and other information about an adapted version of the font requested in the given FMInput record. (FMInput and FMOutput records ,are explained in the following section.) SwapFont is called by QuickDraw every time a QuickDraw routine that does anything with text is used. If you want to call SwapFont yourself, you must build an FMInput record and then use the returned pointer to access the resulting FMOutpu't record.

11

Assembly-language note: The macro you invoke to call SwapFont from assembly language is named _FMSwapFont.

COMMUNICATION BETWEEN QUICKDRAW AND THE FONT MANAGER This section describes the data structures that allow QuickDraw and the Font Manager to exchange information. lt also discusses the communication that may occur between the Font Manager and the driver of the device on which the characters are being drawn or printed. You can skip this section if you want to change fonts, character style, and font sizes by calling QuickDraw and aren't interested in the lowerlevel data structures and routines of the Font Manager. To understand this section fully, you'll have to be familiar with device drivers and the Device Manager. *** (Device Manager manual doesn't yet' exist.)

***
Whenever you call a QuickDraw routine that does anything with text, QuickDraw requests information from the Font Manager about the characters. The Font Manager performs any necessary calculations and returns the requested information to QuickDraw. As illustrated in Figure 3, this information exchange occurs via two data structures, a font input record (type FMInput) and a font output record (type FMOutput).

The first three fields contain the font number, size, and character style that QuickDraw wants to use. The needBits field· indicates whether the characters actually will be drawn or not. If the characters are being drawn, all of the information describing the font, including the bit image comprising,the characters, will be read into memory. If the characters aren't being drawn·and there's a resource consisting of only the character widths and general font information, that resource will be read instead. The high-order byte of the device field contains a device driver reference number. From the driver reference number, the Font Manager can determine the optimum styli'stic variations on the font to produce the highest quality printing or drawing available on a device (as explained below). The low-order byte of the device field is ignored by the Font Manager but may contain information used by the device driver. The numer and denom fields contain the scaling factors to be used; numer.v divided by denom.v gives the vertical scaling, and numer.h 6/11/84 Rose-Hacker /FMGR/FONT.n

COMMUNICATION BETWEEN QUICKDRAW AND THE FONT MANAGER
I

13

divided by denom.h gives the horizontal scaling. The Font Manager takes the FMInput record and asks the Resource Manager for the font. If the requested size isn't available~ the Font Manager scales another size to match (as described previously). Then the Font Manager gets the font characterization table via the device field. If the high-order byte of the device field is 0, the Font Manager gets the font characterization table for the screen (which is stored in the Font Manager). If the high-order byte of the device field is rionzero, the Font Manager calls the status routine of the device driver having that. reference number, and the status routine returns a font characterization table. The status routine may use the value of the low-order byte of the device field to determine the font characterization table it returns. ( note) If you want to make / your own calls to the device driver's . status routine, the refNum parameter of the Status function must contain tHe driver reference number from the font input record's device field, the csCode parameter must be 8, and the csParam parameter must contain a pointer to the following: a pointer to where the device driver shouid put the font characterization table followed by 'an integer containing the value of the font input record's device field. Figure 4 shows the structure of a font characterization table and, on the right, the values it contains for the Macintosh screen and Imagewriter printer driver.

6/11/84 Rose-Hacker

/FMGR/FONT.D

14

Font Manager Programmer's Guide

::;creen dots per vert i cal i nct-. on dev i ce dots per horizontal i ncrl on dev i ce

Imagewr iter

80

80

ao
0.. 1.• 1
1J 8., 1

80

4

bo Id character i ::;t i C3 ital ic characteristics

0..
1,

'-

?

..

..,
~

7 10
13

c· .-, .!.
L'}

not used
out line characte'r i 31 i cs shado\,ll ct-.aracter i s1 i cs , condensed character i st iC:?,
extended character i 31 j cs

0.,
~I••

OJ 0

0.. 0,

I)

1, 1

5, 1, 5,
"'"I

.-,
r!..

16
19

5.1 2, 2

'-,

4

OJ OJ -1

OJ OJ -2
0.• 0..
r!..

22

0..

OJ 1

--,

under line character ist i cs

1, 1.1 1 .

1J "". "::'.1

,-,
r!..

Figure 4.

Font Characterization Table

The first two words of the font characterization table contain the number of dots per inch on the- device. The remainder of the table consists of 3-byte triplets providing information about the different stylistic variations. For all but the triplet defining the underline characteristics: - The first byte in the triplet indicates which byte beyond the bold field of the FMOutput record (see below) is affected by the triplet. The second byte contains the amount to be stored in the affected field. - The third byte indicates the amount by which the extra field of the FMOutput record is to be incremented (starting from 0). The triplet defining the underline characteristics indicates the amount by which the FMOutput record's ulOffset, ulShadow, and ulThick fields (respectively) should be incremented. Based on the'information in the font characterization table, the Font Manager determines the optimum ascent, descent, and leading, so that the highest quality printing rir drawing available will be produced. It then stores this information in a font output record:

ErrNum is reserved for future use, and is set to 0. FontHandle is a handle to the font record of the font, as described in the next section. Bold, -italic, ulOffset, ulShadow, ulThick, and shadow are all fields that modify the way stylistic variations are done; .their values are taken from the font characterization table, and are used by QuickDraw. (You'll need to experiment with these values if you want to determine exactly how they're used.) Extra indicates the number of pixels that each ·character has been widened by stylistic variation. For example, using the ~alues shown in the rightmost column of Figure 4, the extra field for bold italic characters would be 4. Ascent, descent, widMax, and leading are the same as the fields of the FontInfo record returned by the QuickDraw procedure GetFontInfo. Numer and denom contain the scaling factors. Just before returning this record to QuickDraw, the Font Manager calls the device driver's control routine to allow the driver to make any final modifications to the record. Finally, the font information is returned to QuickDraw via a pointer to the record, defined 'as follows: TYPE FMOutPtr (note) If you want to make your own calls to the ,device driver's control routine, the refNum parameter of the Control function must contain the driver reference number from the font input record's device field, ~he csCode parameter must be 8, and the csParam parameter must contain a pointer to the following: a pointer to the font output record followed by an integer containing the value of the font input record's device field.

= -FMOutput;

6/11/84 Rose-Hacker

/FMGR/FONT.D

16

Font Manager Programmer's Guide

FORMAT OF A FONT This section describes the data structure that defines a font; you need to read it only if you're going to define your own fonts with the Resource Editor *** doesn't yet exist *** or write your own font editor. Each character in a font is defined by pixels arranged in rows and columns. This pixel arrangement is called a character image; it's the image inside each of the character rectangles shown in Figure S.
1-

Character Images bottom of each is a point on the character. on when it the point where

The base line is a horizontal line coincident with the character, excluding descenders. The character origin the base line used as a reference location for drawing Conceptually the base line is the line that the pen is starts drawing a character, and the characer origin is the pen 'starts drawing.

The character, rectangle is a rectangle enclosing the character image; its sides are defined by the image width and the character height:

6/11/84 Rose-Hacker

/FMGR/FONT.D

FORMAT OF A FONT

17

- The image width is simply the horizontal extent of the character image, which varies among characters in-the font. It mayor may not include space on either side of the character; to minimize the amount of memory required to store the font, it should not include space. - The character height is the number of pixels from the ascent line to the descent line (which is the same for all characters in the font). -\ The image width is different from the character width, which is the distance to move the pen from this character's origin to the next while drawing--in other words, the image width plus the amount of blank space to leave before the next character. The character width may be ~, in which case the character that follows will be s~perimposed on this character (useful for accents, underscores, and so on). Characters whose image width is 0 (such as a space) can have a nonzero character width. Characters in a proportional font all have character widths proportional to their image width, whereas characters in a fixed-width font all have the same character width. Characters can kern; that is, they can overlap adjacent characters. The first character in Figure 5 above doesn't kern, but the second one kerns left. In addition to the terms used to describe individual characters, there are terms describing .features of the font as a whole (see Figure 6).,
(:lscent I; ne

The font rectangle is somewhat analogous to a character rectangle. Imagine that all the character images in the font are superimposed with their origins coinciding. The smallest rectangle enclosing all the superimposed images is the font rectangle. The ascent is the distance from-the base line to the top of the font rectangle, and the descent is the distance from' the base line to the bottom of the font rectangle.

6/11/84 Rose-Hacker

/FMGR/FONT.n

18

Font Manager Programmer's Guide

The character height is the vertical extent of the font rectangle. The maximum character height is 127 pixels. The maximum width of the font rectangle is 254 pixels. The leading is the amount of blank space to draw between lines of single-spaced text--the number of pixels between the descent line of one line of text and the ascent line of the next line of text. Finally, for each character in a font there's a character offset. As illustrated in Figure 7, the character offset is simply the difference in position of' the character rectangle for a given character and the font rectangle.

character --f--:H rectangle
font

rectangle

character

origin

L.t'

character
offset

Figure 7.

Character Offset

Every font has a bit image that contains a complete sequence of all its character images (see Figure 8 on the following page). The number of rows in the bit image is equivalent to the character height. The character images in the font are stored in the bit image as though the characters were laid out horizontally (in ASCII order, by convention) along a common base line. The bit image doesn't have to contain a character image for every character in the font. Instead, any characters marked as being missing from the font are omitted from the bit image. When QuickDraw tries to draw such 'characters, a missing symbol is drawn instead. The missing symbol is stored in the bit image after all the other character images. (warning) Every font must have a missing symbol. The characters with ASCII codes ~ (NUL), $~9 (horizontal tab), and $~D (return) must not be missing from the font; usually they'll be zero-length, but you may want to store a space for the tab character.

Font Records The information describing a font is contained in a data structure called a font record, which contains the following: - the font type (fixed-width or proportional) the ASCII code of the first character and the last character in the font the maximum character width and maximum amount any character kerns - the character height, ascent, descent, and leading - the bit image of the font - a location table, whi~h is an array of words specifying the location of each character image within the bit image - an offset/width table, which is an array of words specifying the character offset and character width for each character in the font. For every character, the location table contains a word that specifies the bit offset to the location of that character's image in the bit image. The entry for a character missing from the font contains the same value as the entry for the next character. The last word of the table contains the offset to one bit beyond the end of the bit image (that is, beyond the character image for the missing symbol). The image width of each character is determined from the location table by subtracting the bit offset to that character from the bit offset to the next character in the table. There's also one word in the offset/width table for every character: th~ high-order byte specifies the character offset and the low-order byte specifies the character width. Missing characters are flagged in this table by a word value of -1. The last word is also -1, indicating the end of the table. Figure 9 illustrates a sample location 'table and offset/width table corresponding to the bit image in Figure 6.

6/11/84 Rose-Hacker

/FMGR/FONT.O

FORMAT OF A FONT

21

word 0
.t."7

0 0
~.

20

II~."

15
/T .:

IIBII
IIY"

~

320

0
(I

336
:351 351

16 15
-1
. -1 -1 -1 -1 -1

IIZft

" 351 351 351

:351

ro i :~s ing character::;

:351
L

,.

364
~.
~

,.

0 0 0 0
(I

1'j

.:
/T

...1

Uall

16
14 11 16
-1

Ub

ll

650

664
67~,

dummy image

Be9
location

offset I

\I.ti dth

I

table Figure 9.

table

Sample Location Table and Offset/Width Table

A font record is referred to by a handle that you can get by calling the SwapFont function or the Resource Manager function GetResource. The data type for a font record is as follows:

(note) The variable-length arrays appear as comments because they're not valid Pascal syntax; they're used only as conceptual ai~. '. The fontType field must contain one of the following predefined constants: CONST propFont fixedFont

= $9000;
$B000;

{proportional font} {fixed-width font}

The values in the widMax, kernMax, nDescent, fRectWid, chHeight, ascent, descent, and leading fields all specify a number of pixels. KernMax indicates the largest number of pixels any character kerns, and should always be negative or 0, becau~e kerning is specified by negative bumbers (the kerned pi~els-are to the left of the character origin). NDescent must be set to the negative o~ the descent. The owTLoc field contains a word offset from itself to the offset/width table; it's equivalent to 4 + (rowWords

*

chHeight) + (lastChar - firstChar + 3) + 1

(warning) Remember, the offset and row width in a font record are given in words, not bytes. Normally, the Resource Editor will change the fields in a font record for you. You shouldn't have to change any fields unless you edit the font without the aid of the Resource Editor.

6/11/84

Ros~-Hacker

/FMGR/FONT.D

FORMAT OF A FONT

23

Assembly-language note: The global variable romFont~ contains a handle to the font record for the system font.

Font Widths A resource can be defined that consists of only the character widths and general font information--everything but the font's bit image and location table. If there is such a resource, it will be read in whenever QuickDraw doesn't need to draw the text, such as when you call one of the routines CharWidth, HidePen, or OpenPicture (which calls HidePen). The FontRec data type described above, minus the rowWords, bitlmage, and locTable fields, reflects the structure of,this type of resource. The owTLoc field will contain 4, and the fontType field will contain the following predefined constant: CONST fontWid =
$ACB~;

{font width data}

How QuickDraw Draws Text . This section provides a conceptual discussion of the steps QuickDraw takes to draw characters (without scaling or stylistic variations such as bold and outline). Basically, QuickDraw simply copies the character image onto the drawing area at a" specific location. 1. 2. Take the initial pen location as the character origin for the first character. Check the word in the offset/width table for the character to see, if it's -1. The word to check is entry (charCode - firstChar), where charCode is the ASCII code of the character to be drawn. 2a. The character exists if the entry in the offset/width table isn't -1. Determine the character offset and character width from the bytes of this same word. Find the character image at the location in the bit image specified by the location table. Calculate the image width by subtracting this word from the succeeding word in the location table. Determine the number of pixels the character kerns by subtracting kernMax from the character offset. The character is missing if the entry in the offset/width table is -1; information about the missing symbol is needed. ,Determine the missing symbol's character offset and character width from the next-to-Iast word in the offset/width table. Find the missing symbol at the location in the bit image specified by the next~to-last word in the location table (lastChar - firstChar + 1). Calculate the image width by /FMGR/FONT.n

'2b.

6/11/84 Rose-Hacker

24

Font Manager Programmer's Guide subtracting the next-to-Iast word in the location table from the last word (lastChar - firstChar + 2). Determine'the number of pixels the missing symbol kerns by subtracting kernMax from the character offset.

3.

1

Move the pen to the left the number of pixels that the character kerns. Move the pen up the number of pixels specified by the ascent. If the fontType field is fontWid, skip to step 5; otherwise, copy each row of the character image onto the screen or paper~ one row at 'a time. The number of bits to copy from each word is given by the image width, and the number of words is given by the chHeight field. If the fontType field is fontWid, move the pen to the right the number of pixels specified by the character width. If fontType is fixedFont, move the pen to the right the number of pixels specified by the widMax field. Return to step 2.

4.

5.

6.

FONTS IN A RESOURCE FILE This section contains details about fonts in resource files that most programmers need not be concerned about, since they can use the Resource Editor *** eventually *** to define fonts. It's included here to give background information to those who are interested. Every size of a font is stored as a separate resource. The resource type for a font is 'FONT'. The resource data for a font is simply a font record:

6/11/84 Rose-Hacker

/FMGR/FONT.D

FONTS IN A RESOURCE FILE Number of bytes 2 bytes 2 bytes 2 bytes 2 bytes 2 bytes 2 bytes 2 bytes 2 bytes 2 bytes 2 bytes 2 bytes 2 bytes 2 bytes n bytes m bytes m bytes Contents FontType field of font record FirstChar field of font record LastChar field of font record WidMax field of font record KernMax field of font record NDescent field of font record FRectWid field of font record ChHeight field of font record OWTLoc field of font record Ascent field of font record Descent field of font record Leading field of font record RowWords field of font record Bit image of font n = 2 * rowWords * chHeight Location table of font m = 2 * (lastChar - firstChar + 3) Offset/width table of font m = 2 * (lastChar - firstChar +·3)

25

The resource type 'FWID' is used to store only the character widths and general information for a font; its resource data is a font record without the rowWords field, bit image, and location table. As shown in Figure 10, the resource ID of a font is composed of two parts: bits 7 to 15 are the font number, and bits 0 to 6 are the font size. Thus the resource ID corresponding to a given font number and size is (128

*

font number) + font size

I

15
font number

7 6
font size

0

Figure 10.

Resource ID for a Font

Since 0 is not a valid font size, the resource ID having 0 in the size field is used to.provide only the name of the font: the name of the resource is the font name. For example, for a font named Griffin and numbered' 400, the resource naming the font would have a resource ID of 51200 and the resource name 'Griffin'. Size 10 of that font would be stored in a resource numbered 51210. Font numbers 0 through 127 are reserved for fonts provided by Apple, and font numbers 128 through 383 are reserved for assignment, by Apple, to software vendors. Each font will be assigned a unique number, and that font number should be used to identify only that font (for example, font number 9 will always be Toronto). Font numbers 384 through 511 are available for your use in whatever way you wish.

GLOSSARY
application font: The font your application will use unless you specify otherwise--Geneva, by default. ascent: line. The vertical distance from a font's base line to its ascent

base line: A horizontal line coincident with the bottom of each character in a font, excluding descenders. character height: its descent line. character image: The vertical distance from a font's ascent line to· The bit image that defines a chqracter.

character offset: The horizontal separation between a character rectangle and a font·rectangle. character orLg1n: The point on a base line used as a reference location for drawing a character. character rectangle: A rectangle enclosing an entire character image. Its sides are defined by the image width and the character height. character width: The distance to move the pen from one character's origin to the next; equivalent to the image width plus the amount of blank space to leave before the next character. descent: The vertical distance from a font's base line to its descent line. fixed-width font: A font whose characters all have the same width. font: The complete set of characters of one typeface.

font characterization table: A table of parameters in a device driver that specifies how best to adapt fonts to that device. font number: The number by which you identify a font to QuickDraw or the Font Manager. font record: A data structure that contains all the information describing a font. font rectangle: The smallest .rectangle enclosing all the character images in a font, if the images were all superimposed over the same character origin. font size: The size of a font in points; equivalent to the distance between the ascent line of one line of text and the ascent line of the next of line of single-spaced text.

6/11/84 Rose-Hacker

/FMGR/FONT.G

32

Font Manager Programmer's Guide The horizontal extent of a character image.

image width:

kern: To draw part of a character so that it overlaps an adjacent character. leading: The amount of blank vertical space between the descent line of one line of 'text and the ascent line of the next line of single-spaced text. location table: An array of words' (one for each character in a font) that specifies the location of each character's image in the font's bit image. missing symbol: A character to be drawn in case of a request to draw a character that's missing from a particular font. offset/width table: An array of words that specifies the character offsets and character widths of all characters in a font. point: The intersection of a horizontal grid line and a verti~al grid line on the coordinate plane, defined by a horizontal and a vertical coordinate; also, a typographical term meaning approximately 1/72 inch. proportional font: A font whose characters all have character widths that are proportional to their image width. scaling factor: A value, given as a fraction, that specifies the amount a character should be 'stretched or shrunk before it's· drawn. style: Same as character style.

system font: The font that the system uses (in menus, for example). Its name is Chicago. system font size: font; 12 points. The size of text drawn by the system in the system

This manual describes the Event Manager, the part of the Macintosh User Interface Toolbox that allows your application to monitor the user's actions·, such as those involving the mouse, keyboard, and keypad. The Event Manager is also used by other parts of the Toolbox; for instance, the Window Manager uses events to coordinate the ordering and display of windows on the screen. Summary of significant changes and additions since last draft: - PostEvent, FlushEvents, and SetEventMask have been moved to the Operating System Event Manager manual. The section on defining a nonstandard keyboard configuration was incorrect and has been removed; an accurate version of it will be included in the next draft of the Operating System Event Manager manual. - The changeFlag bit of the modifiers field of an event record is no longer documented; it's unreliable and should not be used. - Functions GetDblTime and GetCaretTime have been added (page 24). - Details have been added to GetNextEvent (page 21), GetKeys (page 24) and the sections on keyboard events (page 7), event records (page 10), using the Event Manager (page 15), and journaling (page 24) •

ABOUT THIS MANUAL This manual describes the Event Manager, the part of the Macintosh User Interface Toolbox that allows your application to monitor the user's actions, such as those involving the mouse, keyboard, and keypad. *** Eventually it will become part of the comprehensive Inside Macintosh manual. *** The Event Manager is also used by other parts of the Toolbox; for instance, the Window Manager uses events to coordinate the ordering and display of windows on the screen. , There are actually two Event Managers: one in the Operating System and one in the Toolbox. The Toolbox Event Manager calls the Operating System Event Manager and serves as an interface between it and your application; it also adds some features that aren't present at the Operating System level, such as,the window management facilities mentioned above.' This manual describes the Toolbox Event Manager, which is the one your application will ordinarily deal with. All references to "the Event Manager" should be understood to refer to the Toolbox Event Manager. For information on the Operating System's Event Manager, see the Operating System Event Manager manual. (note) Most of the constants and data types presented in this manual are actually defined in the Operating System Event Manager; they're explained here because they're essential to understanding the Toolbox Event Manager. Like all Toolbox documentation, this manual assumes you're familiar· with Lisa Pascal and the information in the following manuals: - Inside Macintosh:

!

Road Map

- Macintosh User Interface Guidelines - Macintosh Memory Management:

An Introduction

- Programming Macintosh Applications in Assembly Language, if you're using assembly language You should also be familiar with: - resources, as documented in the Resource Manager manual - the basic concepts and data structures behind QuickDraw

ABOUT THE TOOLBOX EVENT MANAGER The Toolbox Ev~nt Manager is your application's link to its user. Whenever the user presses the mouse button, types on the keyboard or keypad, or inserts a disk in a disk drive, your application is notified by means of an event. A typical Macintosh application program is event11/19/84 Rose-Davis /EMGR/EVENTS.2

4

Toolbox Event Manager Programmer's Guide

driven: It decides what to do from moment to moment by asking the Event Manager for events and responding to them one by one in whatever way is appropriate. Although the Event Manager's primary purpose is to monitor the user's actions and pass them to your application in an orderly way, it also serves as a convenient mechanism for sending signals from one part of your application to another. For instance, the Window Manager uses events to coordinate the ordering and display of windows as the user activates and deactivates them and moves them around on the screen. You can also define your own types of events and use them in any way you wish. Most events waiting to be processed are kept in the event queue, where they were stored (posted) by the Operating System Event Manager. The Toolbox Event Manager retrieves events from this queue jor your application and also reports other events that aren't kept in the queue, such as those related to windows. In general, events are collected from a variety of sources and .reported to your application on demand, one at a time. Events aren't necessarily reported in the order they occurred; some have a higher priority than others. There are several different types of ev~nts. You can restrict some Event Manager routines to apply only to certain event types, in effect disabling the other types. Other operations your application can perform with Event Manager routines include: - directly reading the current state of the keyboard, keypad, and .mouse button - monitoring the location of the mouse - finding out how much time has elapsed since the system was last started up The Event Manager also provides a journaling mechanism, which enables events to be fed to the Event Manager from a source other than the user.

EVENT TYPES Events are of various types, depending on their origin and meaning. Some report actions by the user; others are generated by the Window Manager, by device drivers, or by your application itself for its own purposes. Some events are handled by the system before your application ever sees them; others are left for your application to . handle in its own way. The most important event types are those that record actions by the user: ,11/19/84 Rose-Davis /EMGR/EVENTS.2

- Key-down and key-~ events occur when the user presses or releases a key on the keyboard or keypad. Auto-key events are generated when the us~r holds down a repeating' key. Together, these three event types are called keyboard events. - Disk-inserted events occur when the user inserts a disk into a disk drive or takes any other action that requires a volume to be mounted (as described in the File Manager manual). For example, a hard disk that contains several volumes may' also post a diskinserted event. (note) Mere movements of the mouse are not reported as events. If necessary, your application can keep track of them by periodically asking the Event Manager for the current location of the mouse. The following event types are generated by the Window Manager to coordinate the display of windows on the screen: - Activate events are generated whenever an inactive window becomes active or vice versa. They generally occur in pairs (that is, one window is deactivated and another activated at the same time). - Update events occur when all or part of a window's contents need to be drawn or redrawn, usually as a result of the user's opening, closing, activating, or moving a window. Another event type (device driver event) may be generated by device drivers in certain situations; for example, a driver might be set up to report an event when its transmission of data is interrupted. The documentation for the individual drivers will tell you about any specific device driver events that may occur. A network event may be generated by the. AppleBus Manager; for details, see the AppleBus Manager manual *** (doesn't yet exist) ***. In addition, your application can define as many as four event types of its own and use them for any desired purpose. (note) You place application-defined events in the event queue with the Operating System Event Manager procedure PostEvent. See the Operating System Event Manager manual for details. One final type of event is the null event, which is what the Event Manager returns if it has no other events to report.

11/19/84

Rose-Davis

/EMGR/EVENTS.2

6

Toolbox Event Manager Programmer's Guide

PRIORITY OF, EVENTS The event queue is a FIFO (first-in-first-out) list--that is, events are retrieved from the queue in the order they were originally posted. However, the way th~t various types of events are generated and detected causes some events to have higher priority than others. (Remember, not all events are kept in the event queue.) Furthermore, when you ask the Event Manager for an event, you can specify particular types that are of interest; doing so can cause some events to be passed over in favor of others that were actually posted later. The following discussion is limited to the event types you've specifically 'requested in your Event Manager call. The Event Manager always returns the highest-priority event available of the requested types. The priority ranking is as follows: 1. 2. 3. 4. 5. activate (window becoming inactive before window becoming active) mouse-down, mouse-up, key-down, key-up, disk-inserted, network, device driver, application-defined (all in FIFO order) auto-key update (in front-to-back order of windows) null

Activate events take priority over all others; they're detected in a special way, and are never actually placed in the event queue. The Event Manager checks for pending activate events before looking in the event queue, so it will always return such an event if one is available. Because of the special way activate even~s are detected, there can never be more than two such events pending at the same time; at most there will be one for a window becoming inactive followed by another for a window becoming active. Category 2 includes most of the event types. Within this category, events are retrieved from the queue in the order they were posted. If no event is available in categories 1 and 2, the Event Manager reports an auto-key event if the appropriate conditions hold for one. (These conditions are described in detail in the next section.) Next in priority are update events. Like activate events, these are not placed in the event queue, but are detected in another way. ~f no higher-priority event is available, the Event Manager checks for windows whose conte?ts need to be drawn. If it finds one, it generates and returns an update event for that window. Windows are checked in the order in which they're displayed on the screen, from front to back, so if two or more windows need to be updated, an update event will be generated for the frontmost such window.

11/19/84

Rose-Davis

/EMGR/EVENTS.2

PRIORITY OF EVENTS Finally, if no other event is available, the Event Manager returns a null event. (note) The event queue'has a capacity of 20 events. If the queue should become full, the Operating System Event Manager will begin discarding old events to make room for ' new ones as they're posted. The events di~carded are always the oldest ones in the queue. Advanced programmers can configure the capacity of the event queue in the system startup information stored on a volume; for more information, see 'the section "Data Organization on 'Volumes" in the File Manager manual. *** No more information is given there yet, but it will be included in the next draft of that manual.***

7

KEYBOARD EVENTS The character keys on the Macintosh keyboard and optional keypad generate key-down and key-up events when pressed and released; this includes all keys except Shift, Caps Lock, Command, and Option, which are called modifier keys. (Modifier keys are treated specially, as described below, and generate no keyboard events of their own.) In addition, an auto-key event is posted whenever all of the following conditions apply: - Auto-key events haven't been disabled. under "Event Masks" below.) - No higher-priority event is available. - The user is currently holding down a character key. - The appropriate time interval (see below) has. elapsed since the last key-down or auto-key event. Two different time intervals are associated with auto-key events. The first auto-key event is generated after a certain initial gelay has elapsed since the original key-down event (that is, since the key was originally pressed); this is called the auto-key threshold. Subsequent auto-key events are then generated each time a cereain repeat interval has elapsed since the last such event; this is called the auto-key . rate. The default values are 16 ticks (sixtieths of a second) for the auto-key threshold and four ticks for the auto-key rate. The user can change these values with the Control Panel desk accessory, by adjusting the keyboard touch and the rate of repeating keys. (This is discussed further

11/19/84

Rose-Davis

/EMGR/EVENTS.2

8

Toolbox Event Manager Programmer's Guide

Assembly-Ianguage~:

The current values for the auto-key threshold and rate are stored in the global variables KeyThresh and KeyRepThresh, respectively.

When the user presses, holds down, or releases a character key, the character generated by that key is identified internally with a character code. Character codes are given in the extended version of ASCII (the-x;erican Standard Code for Information Interchange) used by the Macintosh. A table 'showing the character codes for the standard Macintosh character set appears in Figure 1 on the following page. All character codes are given in hexadecimal in this table. The first digit of a character's hexadecimal value is shown at the top of the table, the second down the left side. For example, character code $47 stands for "G", which appears in the table at the intersection of column 4 and row 7. Macintosh, the owner's guide, describes the method of generating the printing characters (codes $20 through $D8) shown in Figure 1. Notice that in addition to the regular space character ($20) there's a nonbreaking space ($CA), which is generated by pressing the space bar with the Option key down. Nonprinting or "control" characters ($00 through $IF, as well as $7F) are identified in the table by their traditional ASCII abbreviations; those that are shaded have no special meaning on the Macintosh and cannot normally be generated from the Macintosh keyboard or keypad. Those that can be generated are listed below along with the method of generating them: Code $03 $08 $09 $0D $lB $IC $1D $1E $1F Abbreviation ETX BS HT CR ESC FS GS RS US Key Enter key on keyboard or keypad Backspace key on keyboard Tab key on keyboard Return key on keyboard Clear key on keypad Left arrow key on keypad Right arrow key on keypad Up arrow key on keypad Down arrow key on keypad

..... stands for a nonbreaking space, the same width as a digit. The shaded characters cannot normally be generated from the Macintosh keyboard or keypad,

Figure 1.

Macintosh Character Set

The association between characters and keys on the keyboard or the . keypad is defined by a keyboard configuration, which is a resource stored in a resource file. The particular character that's generated by a character key depends on three things:

11/19/84

Rose-Davis

/EMGR/EVENTS.2

10

Toolbox Event Manager Programmer's Guide - the character key being pressed - which. if any. of the modifier keys were held down when the character key was pressed - the keyboard configuration currently in effect

The modifier keys, instead of generating keyboard events themselves, modify the meaning of t~e character keys by changing the character codes that those keys generate. For example, under the standard u.s. keyboard configuration, the "c" key "generates any of the following, depending on which modifier keys are held down: Key(s) pressed "c" by itself "c" with Shift or Caps Lock down "c" with Option down Character generated Lowercase c Capital C Lowercase c with a cedilla (~), used in foreig'n languages Capital C with a cedilla (~)

"c" with Option and Shift down, or
with Option and Caps Lock down

The state of each of the modifier keys is also reported in a field of the event record (see next section), where you~ applica~ion can examine it directly. (note) As described in the owner's guide, some accented characters are generated by pressing Option along with another key for the accent, and then typing the character to be accented. In these cases, a single key-down event occurs for the accented character; there's no event corresponding to the typing of the accent. Under the standard keyboard configuration only the Shift, Caps Lock, and Option keys actually modify the character .code generated by a character key on the keyboard; the Command key has no effect on the character code generated. Similarly, character codes for the keypad are affected only by the Shift key. To find out whether the Command key was down at the time of an event (or Caps Lock or Option in the case of one generated from the keypad), you have to examine the event record field containing the state of the modifier keys. Normally you'll just want to use the standard keyboard configuration, which is read from the system resource file every time the system is started up. Other keyboard configurations can be used for nonstandard layouts. In rare cases, you may want to define your own keyboard configuration to suit your application's special needs. You can make the Command key affect the character code generated (or, when a key is pressed on the keypad, the Caps Lock or Option key). For ·information on how to install an alternate keyboard configuration or define one of your own, see the Operating System Event Manager manual *** (the information isn't yet in that m~nual; it will be in the next draft)

***.

11/19/84

Rose-Davis

, /EMGR/EVENTS.2

EVENT RECORDS

11

EVENT RECORDS Every event is represented internally by an event record containing all pertinent information about that event. The event record includes the following information: - the type of event - the time the event was posted (in ticks since system startup) - the location of the mouse at the time the event was posted (in global coordinates) - the state of the mouse button and modifier keys at the time the event was posted - any additional information required for a particular type of event, such as which key the user pressed or which window is being activated Every event has an event record containing this information--even null events. Event records are defined as follows: TYPE EventRecord

The when field contains the number of ticks since the system was last started up, and the where field gives the location of the mouse, in global coordinates, at the time. the event was posted. The other three fields are described below. Event Code The what field of an event record contains an event code identifying the type of the event. The event codes are available-aB predefined constants:

Event Message The message field of an event record contains the event message, which conveys additional important information about. the event. The nature of this information depends on the event type, as summarized in the following table and described below. Event type Keyboard Activate, update. Disk-inserted Mouse-down, mouse-up, null Network Device driver Applicationdefined Event message Character code and key code in low-order word Pointer to window Drive number in low-order word, File Manager result code in high-order word Meaningless See AppleBus Manager manual See driver documentation Whatever you wish

For keyboard events, only the low-order word of the event message is used, as shown in Figure 2. The low-order byte of this word contains the ASCII character code generated by the key or combination of keys that was pressed or released; usually this is all you'll need.
31

16 15
not used

'8 7

o

L cherecter code
' - - - - - - - - key code

Figure 2.

Event Message for Keyboard Events

The key code in the event message for a.keyboard event is an integer representing the character key that was pressed or released; this value is always the same for any given character key, regardless of the 11/19/84 Rose-Davis /EMGR/EVENTS.3

EVENT RECORDS

13

modifier keys pressed along with it. Key codes are useful in special cases--in a music generator, for example--where you want to treat the .keyboard as a set of keys unrelated to characters. Figure 3 gives the key codes for all the keys on the keyboard and keypad. (Key codes are shown for modifier keys here because they're meaningful in other contexts, as explained later.) Both the u.S. and foreign keyboards are shown; in some cases the codes are quite different (for example, space and Enter are reversed).

U. S. keyboard

Foreign keyboard (U.K. key cap~' ~ho\lln)
r

t:lpor

78 8 91
5'

+

..
66
l

I

71
7

70
9

89
4

92
6

77
I

86 1 83

87
2

88
3

72
Ent~r

84
0 82

85 65 76

Keypad (both U.S. and foreign)

Figure 3. 11/19/84 Rose-Davis

Key Codes

/EMGR/EVENTS.3

14

Toolbox Event Manager Programmer's Guide

The following predefined constants are available to help you access the character ,code and key code: CONST charCodeMask = $000000FF; keyCodeMask = $0000FF00; (note) You can use the Toolbox Utility function BitAnd with these constants;' for instance, to ~ccess the character code, use charCode := BitAnd(myEvent.message,charCodeMask) For activate and update events, the event message is a pointer to the window affected. (If the event is an activate event, additional important information about the event can be found in the modifiers field of the event record, as described below.) For disk-inserted events, the low-order word of the event message contains the drive number of the disk drive into which the disk was inserted: 1 for the Macintosh's built-in drive, and 2 for the external drive, if any. Numbers greater than 2 denote additional disk drives connected through one of the two serial ports. By the time your application receives a disk-inserted event, the system will already have attempted to mount the volume on the disk by calling the File Manager function MountVol; the high-order word of the event message will contain the result code returned by MountVol. For mouse-down, mouse-up, and null events, the event message is meaningless and should be ignored. For network and device driver events, the contents of the event message depend on the situation' under which the event was generated; the documentation describing those situations will give the details. Finally, you can use the event message however you wish for application-defined event types. Modifier Flags
I

{character code} {key code}

As stated above, the modifiers field of an event record contains further information about activate events and the state of the modifier keys and mouse button at the time the event was posted (see Figure 4). You might look at this field to find out, for instance, whether the Command key was down when a mouse-down event was posted (which in many applications affects the way objects are selected) or when a key-down eve~t was posted (which could 'mean ~he user i~ choosing a menu item by typing its keyboard equivalent).

The activeFlag bit gives further information about activate events; it's set if the window pointed to by the event message is being activated, or 0 if the window is being deactivated. The remaining bits indicate the state of the mouse button -and modifier keys. Notice that the btnState bit is set if the mouse button is up, whereas the bits for the four modifier keys are set if their corresponding keys are down.

EVENT MASKS Some of the Event Manager routines can be restricted to operate on a specific event type or group of types; in other words, the specified event types are enabled while all others are disabled. For instance, instead of just requesting the next available event, you can specifically ask for the next keyboard event. You specify which event types a particular Event Manager call applies to by supplying an event mask as a parameter. This is'an integer in which there's one bit position for each event type, as shown in Figure 5. The bit position representing a given type corresponds to the event code for that type--for example, update events (event code 6) are specified by bit 6 of the mask. A 1 in bit 6 means that this Event Manager call applies to update events; a 0 means that it doesn't.

Null events can't be disabled; a null event will always be ,reported when none of the enabled types of events are available. The following predefined mask designates all event types: CONST everyEvent

= -1;

{all event types}

11/19/84

Rose-Davis

/EMGR/EVENTS. 3·

EVENT MASKS You can form any mask you need by adding or subtracting these mask constants. For example, to specify every keyboard event, use keyDownMask + keyUpMask + autoKeyMask For every event except an update, use everyEvent - updateMask (note) It's recommended that you always use the event mask everyEvent unless there's a specific reason not to.

17

There's also a global system event mask that controls which event types get posted into the event queue. Only event types corresponding to bits set in the system event mask are posted; all others are ignored. When the system is started up, the system event mask is initially set to post all except key-up events--that is, it's initialized to everyEvent - keyUpMask (note) Key-up events are meani~gless fOT most applications. Your application will usually want to ignore them; if not, it can set the system event mask with the Operating System Event Manager procedure SetEventMask.

USING THE TOOLBOX EVENT MANAGER Betore using the Event Manager, you .should initialize the Window Manager by calling its procedure InitWindows; parts of the Event Manager rely on the Window Manager's data structures and will not work properly unless those structures have been properly initialized. Initializing the Window Manager requires you to have initialized QuickDraw and the Font Manager.

Assembly-Ianguage~:

If you want to use events but not windows, set the global variable WindowList to 0 instead of calling InitWindows.

It's also usually a good idea to issue the Operating System Event Manager call FlushEvents(everyEvent,0) to empty the event queue of any stray events left over from· before your application was started up (such as keystrokes typed to the Finder). See the Operating System Event Manager manual for a description of FlushEvents. Most Macintosh application programs are event-driven. Such programs have a main loop that repeatedly calls GetNextEvent to retrieve the next available event, and then uses a CASE statement to take whatever 11/19/84 Rose-Davis /EMGR/EVENTS.3

18

Toolbox Event Manager Programmer's Guide

action is appropriate for each type of event; some typical ~esponses to commonly occurring events are described below. Your program is expected to respond only to those events that are directly related to its own operations. After calling GetNextEvent, you should test its Boolean result to find out whether your application needs to 'respond to the event: TRUE means the event may be of int~rest to your application; FALSE usually means it will not be of interest. In some cases, you may simply want to look at a pending event while leaving it available for subsequent retrieval by GetNextEvent. You can do this with the EventAvail function. Responding to Mouse Events On receiving a mouse-down event, your application should first call the Window Manager function FindWindow to find out where on the screen the mouse button was pressed, and then respond in whatever way is ,appropriate. Depending on the part of the screen in which the button was pressed, this may involve calls to Toolbox routines such as the Menu Manager function MenuSelect, the Desk Manager procedure SystemClick, the Window Manager routines SelectWindow, DragWindow, GrowWindow, and TrackGoAway, and the Control Manager rputines FindControl, TrackControl, and DragControl. S~e the relevant manuals for details. If your application attaches some modifier key along with the mouse ,that modifier key while the mouse appropriate flag in the modifiers special significance to pressing a button, you can discover the state of button is down by examining the field.

If you're using the TextEdit part of the Toolbox to handle text editing, mouse double-clicks will work automatically as a means of selecting a word; to respond to double-clicks in any other context, \ however, you'll have to detect them yourself. You can do so by comparing the time and location of a mouse-up event with those of the immediately following mouse-down event. You should assume a 'doubleclick has occurred if both of the following are t~ue: - The times of the mouse-up event and the mouse-down event differ by a number of ticks less than or equal to the value returned by the Event Manager function GetDblTime. - The locations of the two mouse-down events separated by the mouseup event are sufficiently· close to each other. Exactly what this means depends on the particular application. For instance, in a word-processing application, you might consider the two locations essentially the same if they fallon the same character, whereas in a graphics application you might consider them essentially the same if the' sum of the horizontal and vertical changes in position is no more than five pixels. Mouse-up events may be significant in other ways; for example , they. might signal the end of dragging in a graphics or spreadsheet 11/19/84 Rose-Davis /EMGR/EVENTS.3

USING THE TOOLBOX EVENT MANAGER application. events.

19

Many simple applications, however, will ignore mouse-up

Responding to Keyboard Events For' a key-down event, you should first check the modifiers field to see whether the character was typed with the Command key held down; if so, the user may have been choosing a menu item by typing its keyboard equivalent. To find out, pass the character that was typed to the Menu Manager function MenuKey. (See the Menu Manager manual for details.) If the key-down event was not a.menu command, you should then respond to the event in whatever way is appropriate for your application. For example, if one of your windows is active, you might want to insert the typed character into the active document; if none of your windows is active, you might want to ignore the event. Usually your application can handle auto-key events the same as keydown events. You may, however, want to ignore auto-key events that invoke commands that shouldn't be continually repeated. (note) Remember that most applications will want to ignore keyup events; with the standard system event mask you won't get any. If you wish to periodically inspect the state of the keyboard or keypad --say, while the mouse button is being held down--use the procedure GetKeys; this procedure is also the only way to tell wheth~r a modifier key is being pressed alone. Responding to Activate and Update Events When your application receives an activate event for one of its own windows, the Window Manager will already have done 'all of the normal "housekeeping" associated with the event, such as highlighting or unhighlighting the window. You can then take any further action that your application may require, such as showing or hiding a scroll bar or highlighting or unhighlighting a selection. On receiving an update event for one of its own windows, your application should usually call the Window Manager procedure BeginUpdate, draw the window's contents, and then call EndUpdate. the Window Manager manual for important additional information on activate and update events.

See

11/19/84

Rose-Davis

/EMGR/EVENTS.3

20

Toolbox Event Manager Programmer's Guide

Responding to Disk-Inserted Events Most applications will use the Standard File Package, which responds to disk-inserted events for you during standard file saving and opening; you'll usually want to ignore any other disk-inserted events, su~h as the user's inserting a disk when not expected. If, however, you do. want to respond to other 'disk-inserted events, or if you plan not to use the Standard File Package, then you'll have to handle such events yourself. When you receive a disk-inserted event, the system will already have attempted to mount the volume on the .di~k by calling the File Manager function MountVol. You should examine the result code returned by the File Manager in the message field of the event record. If the result code indicates that the attempt to mount the volume was unsuccessful, you might want to take some special action, such as calling the Disk Initialization Package function DIBadMount. See the File Manager and Macintosh Packages manuals for further details. Other Operations In addition to receiving the user's mouse and keyboard ~ctions in the form of events, you can directly read the keyboard (and keypad), mouse location, and state of the mouse button by calling GetKeys, GetMouse, and Button, respectively. To follow the mouse when the user moves it with the button down, use StillDown or WaitMouseUp. The function TickCount returns the number of ticks since the last system startup; you might, for example, compare this value to the when field of an event record to discover the delay since that event was posted. Finally, the function GetCaretTime returns the number of ticks between blinks of the "caret" (usually a vertical bar) marking the insertion point in editable t~xt. You should call GetCaretTime if you aren't using TextEdit and therefore need to cause the caret to blink yourself. You would check this value each time through 'your program's .main event loop, to ensure a constant frequency of blinking.

11/19/84

Rose-Davis

/EMGR/EVENTS.3

TOOLBOX EVENT MANAGER ROUTINES

21

TOOLBOX EVENT MANAGER ROUTINES

Accessing Events

FUNCTION GetNextEvent (eventMask: INTEGER; VAR theEvent: EventRecord) BOOLEAN; GetNextEvent returns the next available event of a specified type or types and, if the event is in the event queue, removes it from the queue. The event is returned ~s the value of the parameter theEvent. The eventMask parameter specifies which event types are of interest. GetNextEvent returns the next available event of any type designated by the mask, subject to the priority rules discussed above under "Priority of Events". If no event of any of the designated types is available, GetNextEvent returns a null event. (note) Events in the que~e that aren't designated in the mask are kept in the queue; if you want to remove them, you can do so by calling the Operating System Event Manager procedure FlushEvents. Before reporting an event to your application, GetNextEvent first calls the Desk Manager function SystemEvent to see whether the system wants to intercept and respond to the event. If so, or if the event being reported is a null event, GetNextEvent returns a function result of FALSE; a function result of TRUE means that your application should handle the event itself. The Desk Manager intercepts the following events: - activate and update events directed to a desk accessory - keyboard events if the currently active window belongs to a desk accessory (note) In each case, the event is intercepted by the Desk Manager only if the desk' accessory can handle that type of event; however, as a rule all desk accessories should be set up to handle activate, update, and keyboard events. The Desk Manager also intercepts disk-inserted events: It attempts to mount the volume on the disk by calling the File Manager function MountVol. GetNextEvent will always return TRUE in this case, though, so that your application can take any further appropriate action after examining the result code returned by MountVol in the event message. (See the Desk Manager and File Manager manuals for further details.) GetNextEvent returns TRUE for all other non-null events '(including all 11/19/84 Rose-Davis /EMGR/EVENTS.R

22

Toolbox Event Manager Programmer's Guide

mouse-down events, regardless of which window is active), leaving them for your application to handle.

Assembly-language~: If for some reason you don't want GetNextEvent to call SystemEvent, set the global variable SEvtEnb' to 0.

GetNextEvent also makes the following processing happen, invisible to your program: - If the "alarm" is set and the current time is the alarm time, the alarm goes off (a beep followed by blinking the title of the Apple menu). The user can set the alarm with the Alarm Clock desk accessory. - If the user holds down the Command and Shift keys while pressing a numeric key that has a special effect, that effect occurs. The standard such keys are 1 and 2 for ejecting the disk in the _internal or external drive, and 3 and 4 for writing a snapshot of the screen to a MacPaint document or to the printei. (note) Advanced programmers can implement their own code to be executed in response to Command-Shift-number combinations (except for Command-Shift-l and 2, which can't be changed). The code corresponding to a particular number must be a routine having no parameters, stored in a resource whose type is 'FKEY' and whose ID is the number. The system resource file contains code for the numbers 3 and 4.

Assembly-language note: You can disable GetNextEvent's processing of Command-Shift-number combinations by setting the global variable ScrDmpEnb to 0.

FUNCTION EventAvail (eventMask: INTEGER; VAR theEvent: EventRecord) r BOOLEAN; EventAvail works exactly the same as GetNextEvent except that if the event is in the event queue, it's left there. (note) An event returned by EventA¥ail will not be accessible later if in the meantime the queu~ becomes full and the event is discarded from it; since the events discarded

11/19/84

Rose-Davis

/EMGR/EVENTS.R

TOOLBOX EVENT MANAGER ROUTINES are always the oldest ones in the queue, however, this will happen only in an unusually busy environment. Reading the Mouse

23

PROCEDURE GetMouse (VAR mouseLoc: Point); GetMouse returns the current mouse location in the mouseLoc parameter. The location is given in the local coordinate system of the current grafPort (which might be, for example, the currently active window). No"tice that this differs from the mouse location stored in the where field of an event record; that location is always in global coordinates. FUNCTION Button : BOOLEAN; The Button function returns TRUE if the mouse button is currently down, and FALSE if it isn't. FU.NCTION StillDown : BOOLEAN; Usually called after a mouse-down event, StillDown tests whether the mouse button is still down. It returns .TRUE if the button is currently down and there are no more mouse events pending in the event queue. This is a true test of whether the button is still down from the original.press--unlike Button (above), which retur~s TRUE whenever the button is currently down, even if it has been released ~nd pressed again since the original mouse-down event. FUNCTION WaitMouseUp : BOOLEAN; WaitMouseUp works exactly the same as StillDown (above), except that if -the button is not still down from the original press, WaitMouseUp removes the preceding mouse-up event before returning FALSE. If, for instance, your application attaches some special significance both to mouse double-clicks and to mouse-up events, this function would allow your application to recognize a double-click without being confused by the inter~ening mouse-up.

11/19/84

Rose-Davis

/EMGR/EVENTS.R

24

Toolbox Event Manager Programmer's Guide

Reading the Keyboard and Keypad

PROCEDURE GetKeys (VAR theKeys: KeyMap);. GetKeys reads the current state of the keyboard (and keypad, i-f any) and returns it in the form of a keyMap: ' TYPE KeyMap = PACKED ARRAY [0 •• 127] OF BOOLEAN; Each key on the keyboard or keypad corresponds to an element in the keyMap. The index into the keyMap for a particular key is the same as the key code ~or that k~y. (The key codes are shown in Figure 3 above.) The keyMap element is TRUE if the corresponding key is down and FALSE if it 'isn't. The maximum number of keys that. can be down simultaneously is two character keys plus any combination of the four modifier keys. Miscellaneous Routines

FUNCTION TickCount : LONGINT; TickCount returns the current number of ticks (sixtieths of a second) since the system was last started up.

Assembly-language note: The value returned by this function is . contained in the global variable Ticks.

FUNCTION

GetD~ITime

: LONGINT;

[No-trap macro]

GetDblTime returns the suggested maximum difference (in ticks) that should exist between the .times of a mouse-up event and a mouse-down event for those two mouse clicks to be considered a double-click. The user can adjust this value by means of the Control Panel desk accessory.

Assembly-language note: This value is available ,to assemblylanguage programmers in the global variable DoubleTime.

GetCaretTime returns the time (in ticks) between blinks of the "caret" (usually a vertical bar) marking an insertion point in editable text. If you aren't using TextEdit, you'll need to cause the caret to blink yourself; on every pass through your program's main event loop, you should check this value against the elapsed time since the last blink of the caret. ~ The user can adjust this value by means of the Control Panel desk accessory.

Assembly-language note: This value is available to assemblylanguage programmers in the global variable CaretTime.

THE JOURNALING MECHANISM So far, this manual has talked about the Event Manager as responding to events generated by users--keypresses, mouse clicks, disk insertions, and so on. By using the Event Manager's journaling mechanism, though, you can "decouple" the Event Manager from the user and feed it events from some other source. Such a source might be a file into which have been recorded all the events that occurred during some portion of a user's session with the Macintosh. This section describes the journaling mechanism briefly and gives some examples of its use; then, if you wish, you can read on to learn the technical information necessary to use it yourself. (note)
i

The journaling mechanism can be accessed only through assembly language; Pascal programmers may want to skip this discussion. In the usual sense, "journaling" means the recording of a sequence of user-generated events into a file; specifically, this file is a recording of all calls to the Event Manager routines GetNextEvent, EventAvail, GetMouse, Button, GetKeys, and TickCount. When a journal is being recorded, every call to any of these routines is sent to a journaling device driver, which records the call (and the results of the call) in a file. When the journal is played back, these recorded Event Manager calls are taken from the journal file and sent directly to the Event Manager. The result is that the recorded sequence of usergenerated events:'is reproduced when the journal is played back. The Macintosh Guided Tour is an example of such a journal. It was recorded using the Journal desk accessory, a special device driver that's available to users who want to record standard journal files for the purpose of, say', making their own Guided Tours. For more information about the Journal 'desk accessory, see A Guide ~ Making Guided Tours *** (forthcoming from Macintosh User Education) *** 11/19/84 Rose-Davis /EMGR/EVENTS.J

26

Toolbox Event Manager Programmer's Guide

Using the journaling mec~anism need not involve a file. 'Before Macintosh was introduced, Macintosh Software Engineering created a special desk accessory of its own for testing Macintosh software. This desk accessory, which was based on the journaling mechanism, didn't use a file--it generated events randomly, putting Macintosh "through its paces" for long periods of time without requiring a user's attention. So, the Event Manager's journaling mechanism has a much broader utility than a mechanism simply for "journali;ng" as it's normally defined. With the journaling mechanism, you can decouple the Event Manager from the user and feed it events from a journaling device driver of your own design. Figure 6 illustrates what happens when the journaling mechanism is off, in recording mode, and in playback mode.
user mouse, keyboard, and di SK Event Manager your appl ication Journa J ; ng off mouse, keyboard, and disk your j ourne ling dr i ver your app I i cat i on

I

your journal ing driver'

user

Event Manager Record i ng mode

mouse, keyboard, and disk

Event Manager

yciur journal i ng dr i ver your app I i cat ion

Figure 6.

Playback mode The Journaling Mechanism

Writing Your Own Journaling Device Driver If you want to implement journaling in a new way, you'll need to write your own journaling device driver •. Details about how to do this are given below; however, you must already have read about writing your own device driver in the Device Manager manual. Furthermore, if you ·want to implement your journaling device driver as a desk accessory, you'll have to be familiar with details given in the Desk Manager manual. Whenever a call is made to any of the Event Manager routines GetNextEvent, EventAvail, GetMouse, Button, GetKeys, and TickCount, the information returned by the routine is passed to the journaling device driver by means of a Control call. The routine makes the Control call to the journaling device driver with the reference number stored in the global variable JournalRef, so be sure anead of time that JournalRef contains the reference number of your own journaling device driver • . 11/.19/84 Rose-Davis /EMGR/EVENTS.J

THE JOURNALING MECHANISM (note) The reference number of the standard journaling device" driver is -2 and is available as the global constant jRefNum.

27

You control whether the journaling mechanism is playing or recording by setting the global variable JournalFlag to a negative or positive value. Before the Event Manager routine makes the Control call, it copies one of the following global constants into the csCode parameter of the Control call, depending on the value o~ JournalFlag: JournalFlag' Negative Positive Value of csCode jPlayCtl .EQU 16 jRecordCtl .EQU 17 Meaning Journal in playback mode Journal in recording mode

If you set the value of JournalFlag to made at all.

0, the Control call won't be

Before the Event Manager routine makes the Control call, it copies into csParam a pointer to the actual data being polled by the routine (for example, a pointer to a keyMap for GetKeys, or a pointer to an event record for GetNextEvent). It also copies, into csParam+4, a journal code designating which routine is making the call: Control call made during: TickCount GetMouse Button GetKeys GetNextEvent EventAvail CsParam contains pointer to: long integer 'point Boolean keyMap event record event record Journal code at csParam+4: jcTickCount .EQU j cGetMouse .EQU j cButton ' .EQU .EQU jcGetKeys j cEvent .EQU jcEvent .EQU

GLOSSARY activate event: An event generated by the Window Manager when a window changes from active to inactive or vice versa. auto-key event: An event' generated repeatedly when the user presses and holds down a character key on the keyboard or keypad. auto-key rate: The rate at which a character key repeats after it's begun to do so. auto-key threshold: The length of time a character key must be held down before it begins to repeat. character code: An integer representing the character that a key or combination of keys on the keyboard or keypad stands for. character key: Any key except Shift, Caps Lock, Command, or Option. An event generated by one of the Macintosh's

device driver event: device drivers.

disk-inserted event: An event generated when the user inserts a disk in a disk drive or takes any other action that requires a volume to be mounted. event: A notification to an application of some occurrence that the application may want to respond to. event code: An integer representing a particular type of event.

event mask: A parameter passed to a Toolbox or Operating System Event Manager routine to specify which types of events the routine should apply' to. event message: A field of an event record containing information specific to the particular type of event. event queue: events. The Operating System Event Manager's list of pending

event record: The internal representation of an event, through which your program learns all pertinent information about that event.' journal code: A code passed by a Toolbox Event Manager routine in its Control call to the journaling device driver, to designate which routine is making the Control call. journaling mechanism: A mechanism that allows you to feed the Toolbox Event Manager events from some source other than the user. key code: An integer representing a key on the keyboard or keypad, without reference -to the character that the key stands for. 11/19/84 Rose-Davis /ENGR/EVENTS.G

GLOSSARY key-down event: An event generated when the user presses a character key on the keyboard or keypad. key-up event: An event generated when the user releases a character key on the keyboard or keypad.

33

keyboard configuration: A resource that defines a particular keyboard layout by associating a.character code with each key or combination of keys on the keyboard or keypad. keyboard event: An event generated when the user presses, releases, or holds down a character key on the keyboard or keypad; any key-down, keyup, or auto-key event. modifier key: A key (Shift, Caps Lock, Option, or Command) that generates no keyboard events of its own, but changes the meaning of other keys or mouse actions. mouse-down event: button. mouse-up event: button. network event: null event: report. post: An event generated when the user presses the mouse' An event generated when the user releases the mouse An event generated by the AppleBus Manager.

An event reported when there are no other events to

To place an event in the event queue for later processing.

system event mask: A global event mask that controls which types of event get posted into the event queue. tick: A sixtieth of a second.

update event: An event generated by the Window -Manager when a window's contents need to be redrawn.

ABSTRACT Windows'play an important part in Macintosh applications, since all information presented by an application appears in windows. The Window Manager provides routines for creating and manipula,ting windows. This manual describes those routines along with related concepts and data types. Summary of significant changes and additions since last draft: - New window definition IDs have been added (page 8) and the diameters of curvature for an rDocProc type of window can now be varied (page_9). The discussion of how a window is drawn has been corrected and refined (page 15). - Assembly-language notes were added where appropriate, and the summary was updated to include all assembly-language information.

ABOUT THIS MANUAL This manual describes the Window Manager, a major component of the Macintosh User Interface Toolbox. *** Eventually it will become part of the comprehensive Inside Macintosh manual. *** The Window Manager allows you to create, manipulate, and dispose of windows in a way that's consistent with the Macintosh User Interface Guidelines. Like all Toolbox documentation, this manual assumes you're familiar with the Macintosh User Interface nuidelines, Lisa Pascal, and the Macintosh Operating System's Memory Manager. You should also be familiar with the following: Resources, as discussed in the Resource Manager manual. - The basic concepts and structures behind QuickDraw, particularly points, rectangles, regions, g~afPorts, and picture~. You don't have to know the QuickDraw routines in order to use the Windo~ Manager, though you'll be using QuickDraw to draw 'inside a window. - The Toolbox Event Manager. Some Window Manager routines are called only ~n response to certain events. This manual is intended to serve the needs of both Pascal and assemblylanguage programmers. Information of interest to assembly-language programmers only is isolated and labeled so that Pascal programmers can conveniently skip it. The manual begins with an introduction to the Window Manager and what you can do with it. It then discusses some basic concepts about windows: the relationship between windows and grafPorts; the various regions of a window; and the relationship between windows and resources. Following this is a discussion of window records, where the Window Manager keeps all the information it needs about a window. There are also sections on what happens when a window is drawn and when a window becomes active or inactive. Next, a section on using the Window Manager introduces its routines and tells how they fit into the flow of your application program. This is followed by detailed descriptions of all Window Manager procedures and functions, their parameters, calling protocol, effects, side effects, and so on. Following these descriptions are sections that will not interest all readers: special information is provided for programmers who want to define their own windows, and the exact formats of the resources related to windows are described. Finally, there's a summary of the Window Manager for quick reference, followed by a glossary of terms used in this manual.

5/30/84 Rose-Davis

/WMGR/WINDOW.2

4

Window Manager Programmer's Guide

ABOUT THE WINDOW MANAGER The Window Manager is a tool for dealing with windows on the Macintosh screen. The screen represents a working surface or desktop; graphic objects appear on the desktop and can be manipulated with the mouse. A window is an object on the desktop that presents information, such as a document or a message. Windows can be any size or shape, and there can be one or many of them, depending on the application. Some types of windows are predefined. One of these is the standard document window, as "illustrated in Figure 1. Every document window has a title bar containing a title that's centered and. in the system font and system font size. In addition, a particular document window mayor may not have a close box or a size box; you'll learn in this manual how to i~p1ement them. There may also be scroll bars along the bottom and/or right edge of a document window. Scroll 9ars are controls, and are supported by the Control Manager.

Close box

Scroll bar

Scroll bar
Figure 1. An Active Document Window

Your application can easily create standard types of windows such as document windows, and can also define its own types of windows. Some windows may be created indirectly for you when you use other parts of. the Toolbox; an example is the'window the Dialog Manager creates to display an alert box. Windows created either directly or indirectly by an application are collectively called application windqws. There's also a class of windows called system windows;, .these are the windows in which desk accessories are displayed. The document window shown in Figure 1 above is the frontmost (active) window, the one that will be acted on when the user types, gives commands, or whatever is appropriate to the application being used. Its title bar is high1ighted--displayed in a distinctive visual way--so that the window will stand out from other, inactive windows that may be on the screen. Since a close box, size box, and scroll bars will have 5/30/84 Rose-Davis /WMGR/WINDOW.2

ABOUT THE WINDOW MANAGER an effect only in an active window, none of them appear in an inactive window (see Figure 2).
M8IIID

5

dobTitl81 Charg81
Inactive windows

The
active

window

Figure 2. (note)

Overlapping Document Windows

If a document window has neither a size box nor scroll bars, the lines delimiting those areas aren't drawn, as in the Hemo window in Figure 2. An important function of the Window Manager is to keep track of overlapping windows. You can draw in any window without running over onto windows in front of it. You can move windows to different places on the screen, change their plane (their front-to-back ordering), or change their size, all without concern for how the various windows overlap. The Window Manager keeps track of any newly exposed areas and provides a convenient mechanism for you to ensure that they're properly redrawn. Finally, you can easily set up your application so that mouse actions cause these standard responses inside a document window, or similar responses inside other wiridows: - Clicking anywhere in an inactive window makes it the active window by bringing it to the front and highlighting its title bar. - Clicking inside the close box of the active window closes the window" Depending on the application, this may mean that the window disappears altogether, or a representation of the window (such as an icon) may be left on the desktop. - Dragging anywhere inside the title bar of a window (except in the close box, if any) pulls an outline of the window across the 5/30/84 Rose-Davis /WHGR/WINDOW.2

6

Window Manager Programmer's Guide screen, and releasing the mouse button moves the window to the new location. If the window isn't the active window, it becomes the active window unless the Comma~d key was also held down. A window can never be moved completely off the screen; by convention, it can't be moved such that the visible area of the title bar is less than four pixels square. Dragging inside·the size box of the active window changes the size of the window.

WINDOWS AND GRAFPORTS \ It's easy for applications 'to use windows: to the application, a window is a grafPort that it can draw into like any other with QuickDraw routines. When you create a window, you specify a rectangle that becomes the portRect of the grafPort in which the window contents will be drawn. The bitMap for this grafPort, its pen pattern, and other characteristics are the same as the default values set by QuickDraw, except for the character font, which is set to the application font. These characteristics will apply whenever the application draws in the window, and they can easily be changed with QuickDraw routines (SetPort ·to make the grafPort the current port, and other routines as appropriate). There is, however, more to a window than just the grafPort that the application draws in. In a standard document window, for example, the title bar and outline of the w~ndow are drawn by the Window Manager, not by the application. The part of a window that the Window Manager draws is called the window frame, since it usually surrounds the rest of the window. For drawing window frames, the Window Manager creates a grafPort that has the entire screen as its portRect; this grafPort is· called the Window Manager port.

WINDOW REGIONS Every window has the following two regions: - the content region: the area that your application draws in

- the structure region: the entire window; its complete "structure" (the content region plus the window frame) The content region is bounded by the rectangle you specify when you create the window (that is, the portRect of the window's grafPort); for a document window, it's the entire portRect. This is where your application presents information and where the size box and scroll bars of document window are located'- By convention, clicking in the content region of an inactive window makes it the active window.

a

5/30/84 Rose-Davis

/WMGR/WINDOW.2

WINDOW REGIONS (note) The results of clicking and dragging that are discussed here don't happen automatically; you have to make the right Window Manager calls to cause them to happen. A window may also have any of the regions listed below. Clicking or, dragging in one of these regions causes the indicated action. A go-away region within the window frame. of the active window closes the window.

7

Clicking in this region

A drag region within the window frame. Dragging in this region pulls an outline of the window across the screen, moves the window to a new location, and makes it the active window unless the Command key was held down. A grow region, usually within the content region. Dragging in this region of the active window changes the size of the window. In a document window, the grow region is in the content region, but in windows of your own design it may be in either the content region or the window frame. Figure 3 illustrates the various regions of a standard document window and its window frame. • Go-away region

An example of a window that has no drag region is the window that displays an alert box. On the other hand, you ~ould design a window whose drag region is the entire structure region and whose content region is empty; such a window might present a fixed picture rather than information that's to. be manipulated. Another important window region is the update region. Unlike the regions described above, the update region is dynamic rather than fixed: the Window Manager keeps track- of all areas of the content 5/30/84 Rose-Davis /WMGR/WINDOW.2

8

Window Manager Programmer's Guide

region that have to be redrawn and accumulates them into the update region. For example, if you bring to the front a window that was overlapped by another window, the Window" Manager adds "the formerly overlapped (now exposed) area of the front window's content region to its update region. You'll also accumulate areas into the update region yourself; the Window Manager provides update region maintenance routines for this purpose.

WINDOWS AND RESOURCES The general appearance and behavior of a window is determined by a routine called its window definition function, which is stored as a resource in a resource file. The window definition function performs all actions that differ from one window type to another, such as drawing the window frame. The Window Manager calls the window definition function whenever it needs to perform one of these typedependent actions (passing it a message that tells which "action to perform). " The system resource file includes window definition functions for the standard document window and other' predefined types of windows. If you want to define your own, nons tandard window ty"pes, you'l1. have to wri te your own window definition functions for them, as described later in the section "Defining Your Own Windows". When you create a window, you specify its type with a window definition ID, which tells the Window Manager the resource ID of the definition function for that type of window. You can use one of the following constants as a window definition ID to refer to a predefined type of window (see Figure 4): CONST documentProc = 0; dBoxProc = 1; plainDBox = 2; altDBoxProc = 3; noGrowDocProc = 4; rDocProc = 16; {standard document window} {alert box or modal dialog box} {plain box} , {plain box with shadow} {document window without size box} {rounded-corner window}

5/30/84 Rose-Davis

/WMGR/WINDOW.2

WINDOWS AND RESOURCES

9

50==: litle====:

so==: Title ======

o

,Tith:~

documentProc

noGrowDocProc

rDocProc

dBoxProc

pfainDBox

altDBoxProc

Figure 4.

Predefined Types of Windows

DocumentProc represents a standard document window that mayor may not contain a size box; noGrowDocProc is exactly the same except that the window must not contain a size box. If you're working with a number- of document windows that need to be treated similarly, but some will have size boxes and some won't, you can use documentProc for all of them. If none of the windows will have size boxes, however, it's more convenient to use noGrowDocProc. The dBoxProc type of window resembles an alert box or a "modal" dialog box (~he kind that requires the user to respond before doing any other work on the desktop). It's a rectangular window with no go-away region, drag region, or grow region and with a two-pixel-thick border two pixels in from the edge. It has no special highlighted state because alerts and modal dialogs are always displayed in the frontmost window. PlainDBox and altDBoxProc are variations of dBoxProc: plainDBox is just a plain box with no inner border, and altDBoxProc has a two-pixel-thick shadow instead of a border. The rDocProc type of window is like a document window with no grow region, with rounded corners, and with a method of highlighting that inverts the entire title bar (that is, changes white to black and vice versa). It's sometimes used for desk accessories. Rounded-corner windows are drawn by the QuickDraw procedure FrameRoundRect, which requires that the diameters of curvature be passed as parameters. For an rDocProc type of window, the diameters of curvature are both 16. You can. add a number from 1 to 7 to rDocProc to get different diameters:

To create a window, the-Window Manager needs to know not only the window definitio~ ID but also other information specific to this window, such as its title (if any), its location, and its plane. You can supply all the needed information in individual parameters to a Window Manager routine or, better yet, you can store it as a single resource in a resource file and just pass the resource ID. This type of resource is called a window template. U~ing window templates simplifies the process of creating a number of windows of the same type. More important, it allows you to isolate specific window descriptions from your application's code. Translation of window titles into a foreign language, for example, would require only a change to the resource file. (note) You can create window templates and store them in resource files with the aid of the Resource Editor *** eventually (for now, the Resource Compiler) ***. The Resource Editor relieves you of having to know the exact format of a window template, but for interested programmers 'this information is given in the section "Formats of Resources for Windows".

) WINDOW RECORDS The Window Manager keeps all the information it requires for its operations on a particular window in a window record. The window record contains the following: The grafPort for the window. - A handle to the window definition function. - A handle to the window's title, if any. The window class, which tells whether the window is a system window, a dialog or alert window, or a window created directly by the application. - A handle to the window's control list, which is a list of all the controls, if any, in the window. The Control Manager maintains this list.

5/30/84 Rose-Davis

/WMGR/WINDOW.3

WINDOW RECORDS

11

- A pointer to the next window in the window list, which is a list. of all windows ordered according to their front-to-back positions on the desktop.

***

The handle to the window's title has a data type that you may want to use yourself elsewhere; it's defined in the Memory Manager as follows: TYPE Str255 STRING[255]; . . Str255; StringPtr StringHandle = .....StringPtr; Forthcoming Memory Manager documentation will include this.

***

The window record also contains an indication of whether the window is currently visible or invisible. These terms refer only to whether the window is drawn in its plane, not necessarily whether you can see it on the screen. If, for example, it's completely overlapped by another window, it's still "visible" even though it can't be seen in its current location. The 32-bit reference value field of the window record is reserved for use by your application. You specify an initial reference value when you create a window, and can the~ read or change the reference value whenever you wish. For example, it might be a handle to data associated with the window, such as a TextEdit edit record. Finally, a window record may contain a handle to a QuickDraw picture of the window contents. The application can swap out the code and data that draw the window contents if desired, and instead use this picture. For more information, see "How a Window is Drawn". ' The data type for a window record is called WindowRecord. A window record is referred' to by a pointer, as discussed further under "Window Pointers" below. You can store into and access most of the fields of a window record with Window Manager routines, so normally you don't have to know the exact field names. Occasionally--particularly if you define your own type of wind'ow--you may need to know the exact structure; it's given below under "The WindowRecord Data Type". Window Pointers There are two types of pointer through which you can access windows: WindowPtr and WindowPeek. Most programmers will only need to use WindowPtr. The Window Manager defines the following type of window pointer: TYPE WindowPtr

= GrafPtr;

It can do this because the first thing stored in a window record is the window's grafPort. This.type of pointer can be used to access fields of the grafPort or can be passed to QuickDraw routines that expect 5/30/84 Rose-Davis /WMGR/WINDOW.3

12

Window Manager Programmer's Guide

pointers to grafPorts as parameters. The application might call such routines to draw into the window, and the Window Manager itself calls them to perform many of its operations. The Window Manager gets the additional information it needs from the rest of the window record beyond the grafPort. In some cases, however, a more direct way of ~ccessing the window record 'may be necessary or desirable. For this reason, the Window Manager also defines the following type of window pointer: TYPE WindowPeek

= AWindowRecord;

Programmers who want to access WindowRecord fields directly must use this type of pointer (which derives its name from the fact that it lets you "peek" at the additional information about the ~indow). A WindowPeek pointer is also used wherever the Window Manager will not be calling QuickDraw routines and will benefit from a more direct means of getting to the data stored in the window record.

Assembly-language note: From assembly language, of course, there's no type checking on pointers, and the two types of pointer are equal.

The WindowRecord Data Type For those who want to know more about the data structure of a window record or who will be defining their own types of windows, the exact data structure ,is given here. TYPE WindowRecord RECORD port: windowKind: visible: hilited: goAwayFlag: spareFlag: strucRgn: contRgn: updateRgn: windowDefProc: dataHandle: titleHandle: titleWidth: controlList: nextWindow: windowPic: ref Con: END; 5/30/84 Rose-Davis

WindowKind identifies the window class. If negative, it means the window is a system window (it's the desk accessory's reference number, as described in the Desk Manager manual). It may also be one of the following predefined constants: CONST dialogKind userKind 2; 8; {dialog or alert window} {window creat~d directly by the application}

WindowKind values 1 through 7 are reserved for system use. U~erKind is stored in this field when a window is created directly by application calls to the Window Manager (rather than indirectly through the Dialog Manager, as for dialogKind); for such windows the application can in fact set the window class to any value greater than 8 if desired. When visible is TRUE, the window is currently visible. Hilited and goAwayFlag are checked by the window definition function when it draws the window frame, to determine whether the window should be highlighted and whether it should have a go-away region. For a document window, this means that if hilited is TRUE, the title bar of the'window is highlighted, and if goAwayFlag is also TRUE, a close box appears in the highlighted title bat. (note) The Window Manager sets the visible and hilited flags to TRUE by storing 255 in them rather than 1. This may cause problems in Lisa Pascal; to be safe, you should check for the truth or falsity of these flags by comparing ORD of the flag to~. For example, you would check to see if the flag is TRUE with ORD(myWindow.visibl'e) <> ~.• StrucRgn, contRgn, and updateRgn are region handles, as defined in QuickDraw, to the structure region, content region, and update region of the window. These regions are all in global coordinates. WindowDefProc is a handle to the window definition function for this type of window. When you create a window, you identify its type with a window definition ID, which is converted into a handle and stored in the windowDefProc field. Thereafter, the Window Manager uses this. handle to access the definition function; you should never need to access this field directly. (note) The high-order byte of the windowDefProc field contains some additional information that the Window Manager gets from the window definition ID; for details, see the section "Defining Your Own Windows". Also note that if you write your own window definition function, you can include it as part of your application's code and just store a handle to it in the windowDefProc field.

5/30/84 Rose-Davis

/WMGR/WINDOW.3

14

Window Manager Programmer's Guide

DataHandle is reserved for use by the window definition function. If the window is one of your own definition, your window definition function may use this field to store and access any desired information. If no mo~e than four bytes of information are needed, the definition function can store the information directly in the dataHandle field rath~r than use a handle. For example, the definition function for rounded-corner windows uses this field to store the diameters of curvature. TitleHandle is a stringHandle to the window's title, if any. TitleWidth is the width, in pixels, of the window's title in the system font and system font size. This width is determined by the Window Manager and is normally of no concern to the application. ControlList is a handle to the window's control list. NextWindow is a pointer to the next window in the window list, that is, the window behind this window. If this window is the farthest back (with no windows between it and the desktop), nextWindow is NIL.

Assembly-language note: The global variable windowList contains a pointer to the first window in the window list. Remember that any window in the list may be invisible.

WindowPic is a handle to a QuickDraw picture of the window contents, or NIL if the application will draw the window contents in response to an update event, as described under "How a Window is Drawn", below. Ref Con is the window's reference value field, which the application may store into and access for any purpose. (note) ,'Notice that the go-away, drag, and grow regions are not included in the window record. Although these are conceptually regions, they don't necessarily have the formal data structure for regions as defined in QuickDraw. The window definition function determines where these regions are, and it can do so with great flexibility.

HOW A WINDOW IS DRAWN When a window is drawn or redrawn, the following two-step process usually takes place: 'the Window Manager draws the window frame and the application draws the window contents. To perform the first step of this process, the'Window Manager calls the window definition function with a request that the window frame be drawn. It manipulates regions of the Window Manager port as necessary before calling the window definition function, to ensure that only what should and must be drawn is actually drawn on the screen. Depending on a parameter passed to the routine that created the window, the window definition function mayor may not draw a go-away region in the window frame (a close box in the title bar, for a document window). Usually the second step is that the Window Manager generates an update event to get the application to draw the window contents. It does this by accumulating in the update region the areas of the window's content region that need updating. The Toolbox Event Manager periodically checks to see if there's any window whose update region is not empty; if it finds one, it reports (via the GetNextEvent function) that an update event has occurred, and passes along the window pointer in the event message. (If it finds more than one such window, it issues an update event for the frontmost one, so that update events are reported in front-to-back order.) The application should respond as follows: . 1. Call BeginUpdate. This procedure temporarily replaces the visRgn of the window's grafPort with the intersection of the visRgn and the update region. It then sets the update region to the empty region; this "clears," the update event so it won't be reported again. Draw the window contents, entirely or in part. Normally it's more convenient to draw the entire content region, but it suffices to draw only the visRgn. In either case, since the visRgn is limited to where it intersects the old update region, only the parts of the window that require updating will actually be drawn on the screen. Call EndUpdate, which restores the normal visRgn.

2.

3.

Figure 5 illustrates the effect of BeginUpdate and EndUpdate on the visRgn and update region of a window that's redrawn after being brought to the front.

5/30/84 Rose-Davis

/WMGR/WINDOW.3

16

Window Manager Programmer's Guide

When

L5J

changes to

cQ
After EndUpdate

Before BeginUpdate

After BeginUpdate

visRgn

visRgn

~

visRgn

~

update region

(update region is empty)

(update region is empty)

Figure 5.

Updating Window Contents

If you choose to draw only the visRgn in step 2 above, there are various ways you can check to see-whether what you need to draw falls in that region. With the QuickDraw functions PtInRgn and RectInRgn, you can check whether a point or rectangle lies in the visRgn. Or it m~y be more convenient to look at the visRgn's enclosing rectangle, which is stored in its bBox field. The QuickDraw functions PtInRect and SectRect let you check for intersection with a rectangle. To be able to respond to update events for one of its windows, the application has to keep track of the window's contents, usually in a data structure. In most case's, it's best never to draw immediately into a'window; when you need to draw something, just keep track ~f it and add the area where it should be drawn to the window's update region (by calling one of the Window Manager's update region maintenance routines, InvalRect and InvalRgn). Do the actual drawing only in response to an update event. Usually this will simplify the structure of your application considerably, but be aware of the following possible problems: - This method isn't convenient to apply to areas that aren't easily defined by a rectangle or a region; in those cases, you would just draw directly into the window. - If you find that sometimes there's too long a delay before the update event happens, you can "force" update events where necessary by calling GetNextEvent with a mask that accepts only that type of event. The Window Manager allows an alternative to the update event mechanism that may be useful for some windows: a handle to a QuickDraw picture may be stored in the window record. If this is done, the Window Manager doesn't generate an update event to get the application to draw the window contents; instead, it calls the QuickDraw procedure
~

5/30/84 Rose-Davis

/WMGR/WINDOW.3

HOW A WINDOW IS DRAWN

17

DrawPicture to draw the picture whose handle is stored in the window record (and it does all the necessary region manipulation). If the amount of storage occupied by the picture is less than the size of the code and data necessary to draw the window contents, and the application can swap out that code and data, this drawing method is more economical (and probably faster) than the usual updating process.

Assembly-language note: The global variables saveUpdate and paintWhite are flags that determine whether the Window Manager will generate any update events and whether it will paint the update region of a window white before generating an update event, respectively. Normally they're both set, but you can clear them to prevent the behavior that they control; for example, clearing paintWhite is useful if the background of the window isn't white. The Window Manager sets both flags periodically, so you should clear the appropriate flag just before each situation you wish it to apply to.

MAKING A WINDOW ACTIVE:

ACTIVATE EVENTS

A number of Window Manager routines change the state of a window from inactive to active or from active to inactive. For each such change, the Window Manager generates an activate event, passing along the window pointer in the event message.and, in the modifiers field of the event record, bits that indicate the following: - Whether this window has become active or inactive. the activeFlag bit is set; if inactive, it's 0.) (If active,

- Whether the active window is changing from an application w~ndow to a system window or vice versa. (If so, the changeFlag bit is set; qtherwise, it's 0.) When the Toolbox Event Manager finds out from the Window Manager that an activate event has been generated, it passes the event oi to the application (via the GetNextEvent function). Activate events have the highest priority of any type of event. Usually when one window becomes active another becomes inactive, and vice versa, so activate events are most commonly generated in pairs. When this happens, the Window Manager generates first the event for the window becoming inactive, and then the event for the window becoming active. Sometimes only a single activate event is generated, such as when there's only one window in the window list, or when the active window is permanently disposed of (since it no longer exists). Activate events for dialog and alert windows are handled by the Dialog Manager. In response to activate events for windows created directly 5/30/84 Rose-Davis /WMGR/WINDOW.3·

18

Window Manager Programmer's Guide

by your application. you might take actions such as the following: - In a document window containing a size. box or scroll bars. erase the size box icon or scroll bars when the window becomes inactive and'redraw them when it becomes active. / In a window that contains text being edited. remove the highlighting or blinking vertical bar from the text when the window becomes inactive and restore it when the window becomes active. - Enable or disable a menu or certain menu items as appropriate to match what the user can do when the window becomes active or inactive.

Assembly-language note: The global variable curActivate contains a pointer to a window for which an activate event has been generated; the event. however. may not yet have been reported to the application via GetNextEvent. so you may be able to keep the event from happening by clearing curActivate. Similarly. you may be able tO,keep a deactivate event from happening by clearing the global variable curDeactive.

USING THE WINDOW MANAGER This section discusses how the Window Manager routines fit into the general flow of an application program and gives you an idea of which , routines you'll need to use. The routines themselves' are described in detail in the next section. To use the Window Manager. you must have previously called InitGraf to initialize QuickDraw and InitFonts to initialize the Font Manager. The first Window Manager routine to call is the initialization routine InitWindows. which draws the'desktop and the (empty) menu ,bar. Where appropriate in your program. use NewWindow or GetNewWindow to create any windows you need; these functions return a window pointer. which you can then use to refer to the window. NewWindow takes descriptive information about the window from its parameters. whereas GetNewWindow gets the information from window templates in a resource file. You can supply a pointer to the storage for the window record or let it be allocated by the routine creating the window; when you 'no longer need a window. call CloseWindow if you supplied the storage. or DisposeWindow if not. When the Toolbox Event Manager function GetNextEvent reports that an update event has occurred. call BeginUpdate, draw the visRgn or the entire content region. and call EndUpdate (see "How a Window is Drawn", 5/30/84 Rose-Davis /WMGR/WINDOW.3

USING THE WINDOW MANAGER

19

above). You can also use InvalRect or InvalRgn to prepare a window for updating, and ValidRect or ValidRg~ to temporarily protect portions of the window from updating. When drawing the contents of a window that contains a size box in its content region, you'll draw the size box if the window is active or just the lines delimiting the size box and scroll bar areas if it's inactive. The FrontWindow function tells you which is the'active window; the DrawGrowIcon procedure helps you draw the size box or delimiting lines. You'll also call the latter procedure when an activate event occurs that makes the window active or inactive. (note) Although unlikely, it's possible that a desk accessory may not be set up to handle update or activate events, so GetNextEvent may return TRUE for a system window's update or activate ,~vent. For this reason, it's a good idea to check whether such an event applies to one of your own \ windows rather than a system window, and ignore it if it. When GetNextEvent reports a mouse-down event, call the FindWindow function to find out which part of which window the mouse button was pressed in. If it was pressed in the content region of an inactive window, make that window the active window by calling SelectWindow. - If it was pressed in the grow region of the active window, call GrowWindow to pull around an image that shows the window's size will change, and then SizeWindow to actually change the size. - If .it pressed in the drag region of any window, call DragWindow, which will pull an outline of the window across the screen, move the window to a new location, and, if the window is inactive, make it the active window (unless the Command key was held down). - If it was pressed in the go-away region of the active window, call TrackGoAway to handle the highlighting of the go-away region and to determine whether the mouse is inside the region when the button is released. Then do whatever is app~opriate as a response to this mouse action in the particular application. For example, call Close Window or DisposeWindow if you want the window to go away permanently, or HideWindow if you want it to disappear temporarily.
(no~e)

If the mouse button was pressed in the content region of an active window (but not in the grow region), call the Control Manager function FindControl if the window contains controls. If it was pressed in a system window, call the Desk Manager procedure SystemClick. See the Control Manager and Desk Manager manuals for details.

5/30/84 Rose-Davis

/WMGR/WINDOW.3

20

Window Manager Programmer's Guide

The procedure that simply moves a window without pulling around an outline of it, MoveWindow, can be called at any time, as can SizeWindow --though the application should not surprise the user by taking these actions unexpectedly. There are also routines fo~ changing the title of a window, placing a window behind another window, and making a window visible or invisible. Call these Window Manager routines wherever needed in your program.

WINDOW MANAGER ROUTINES This section describes first the Window Manager procedures and functions that are used in most applications, and then the low-level routines for use by programmers who have their own ideas about what to do with windows. All routines are presented in their Pascal form; for information on using them from assembly language, see Programming Macintosh Applications in Assembly Language. . Initialization and Allocation

PROCEDURE InitWindows; InitWindows initializes the Window Manager. It creates the Window Manager port; you can get a pointer to this port with the GetWMgrPort procedure. InitWindows draws the desktop and the (empty) menu bar. Call this procedure once before all other Window Manager routines. (note) InitWindows creates the Window Manager port as a nonrelocatable block in the application heap. For information on how this may affect your application's use of memory, see the Memory Manager manual. *** (A section on how to survive with limited memory will be added to that manual.) ***

Assembly-language note: InitWindows draws as the desktop the region whose handle is in the global variable grayRgn (normally a rounded-corner rectangle occupying the entire screen, minus the menu bar). It paints this region with the pattern in the global variable deskPattern (normally gray). Any subsequent time that the desktop needs to be drawn, such as when a new area of it is exposed after a window is closed or moved, the Window Manager calls the procedure whose pointer is stored in tpe global variable deskHook, if any (normally deskHook is 0). The deskHook procedure is called with 0 in D~ to distinguish this use of it from its use in responding to clicks on the desktop (as discussed in the description of FindWindow); it should respond by painting thePortA;clipRgn with deskPattern and then 5/30/84 Rose-Davis /WMGR/WINDOW.R

NewWindow creates a window as specified by its parameters, adds it to the window list, and returns a windowPtr to the new window. It allocates space for the structure and content regions of the window and asks the window definition .function to calculate those regions. WStorage is a pointer to where to store the window record. For example, if you've declared the variable wRecord of type WindowRecord, you can pass @wRecord as the first parameter to NewWindow. If you pass NIL for wStorage, the window record will be allocated on the heap; in that case, though, the record will be nonrelocatable, and so you risk ending up with a fragmented heap. You should therefore not pass NIL for wStorage unless your program has an unusually large amount 'of memory available or has been set up to dispose of windows dynamically. Even then, you should avoid passing NIL for wStorage if there's no limit to the number of windows that your application can open. *** (Some of this may be moved to the Memory Manager ~anual when that manual is updated to have a section on how to survive with limited memory.) *** BoundsRect, a rectangle given in global coordinates, determines the window's size and location. It becomes the portRect of the window's grafPort; note, however, that the portRect is in local coordinates. NewWindow makes the QuickDraw call SetOrigin(0,0), so that the top left corner of the portRect will be (0,0). (note) The bitMap, pen pattern, and other characteristics of the' window's grafPort are the same as the default values set by the OpenPort procedure in QuickDraw, except for the character font, which is set to the application font rather than the system font. Note, however, that the SetOrigin(0,0) call changes the coordinates of the grafPort's portBits.bounds and visRgn as well as its 5/30/84 Rose-Davis /WMGR/WINDOW.R

22

Window Manager Programmer's Guide portRect.

Title is the window's title. If the title of a document windo\~ is longer than will fit in the title bar, only as much of the beginning of the title as will fit is displayed. If the visible parameter is TRUE, NewWindow draws the window. First it calls the window definition function to draw the window frame; if goAwayFlag is also TRUE and the window is frontmost (as specified by the behind parameter, below), it draws a go-away region in the frame. Then it generates an update event for the entire window contents. ProcID is the window definition ID, which leads to the window definition function for this type of window. The window definition IDs for the predefined types of windows are listed above under "Windows and Resources". Window definition IDs for windows of your own design are discussed later under "Defining Your Own Windows". The behind parameter determines the window's plane. The new window is inserted in back of the window pointed to by this parameter~ To put the new window behind all other windows, use behind=NIL. To place it in front of all other windows, use behind=POINTER(-l); in this case, NewWindow will unhighlight the previously active window, highlight the window being created, and generate appropriate activate events. Ref Con is. the window's reference value, set and used only by your application. NewWindow also sets the window class in the win40w record to indicate that the window was created directly by the application. FUNCTION GetNewWindow (windowID: INTEGER; wStorage: Ptr; behind: WindowPtr) : WindowPtr; Like NewWindow (above), GetNewWindow cre'ates a window as specified by its parameters, adds it to the window ·list, and returns a windowPtr to the new window. The only difference between the two functions is that instead of having the parameters QoundsRect" title, visible, procID, goAwayFlag, and ref Con, GetNewWindow has a single windowID parameter, where windowID is the resource ID of a window template that supplies the same information as those parameters. The wStorage and behind parameters of GetNewWindow have the same meaning as in NewWindow. PROCEDURE CloseWindow (theWindow: WindowPtr); CloseWindow removes the given window from the screen and deletes it from the window list. It releases the memory occ~pied by all data structures associated with the window, but not the memory taken up by the window record itself. Call this procedure when you're done with a window if you supplied NewWindow or GetNewWindow a,pointer to the window storage (in the wStorage parameter) when you created the window.

5/30/84 Rose-Davis

/WMGR/WINDOW.R

WINDOW MANAGER ROUTINES

23

Any update events for the window are discarded. If the window was the frontmost window and there was another window behind it, the latter window is highlighted and an appropriate activate event is generated. PROCEDURE DisposeWindow (theWindow: WindowPtr); DisposeWindow calls CloseWindow (above) and then releases the memory occupied by the window record. ~all this procedure,when you're done with a window if you let the window record be allocated on the heap when you created the window (by passing NIL as the wStorage parameter to NewWindow or GetNewWindow).

Assembly-language note: The macro you invoke to call DisposeWindow from assembly language is named _DisposWindow.

Window Display These procedures affect the appearance or plane of a window but not its size or location. PROCEDQRE SetWTitle (theWindow: WindowPtr; title: Str255); SetWTitle sets theWindow's title to the given string, performing any necessary redrawing of the window frame. PROCEDURE GetWTitle (theWindow: WindowPtr; VAR title: Str255); GetWTitle returns theWindow's title as the value of the title parameter. PROCEDURE SelectWindow (theWindow: WindowPtr); SelectWindow makes theWindow the active window as follows: it unhighlights the previously active window, brings theWindow in front of all 'other windows, highlights theWindow, and generates the appropriate activate events. Call this procedure if there's a mouse~down event in the content region of an inactive window. PROCEDURE HideWindow (theWindow: WindowPtr); HideWindow makes theWindow invisible. If theWindow is the frontmost window and there's a window behind it, HideWindow also unhigh1ights theWindow, brings the window behind it to the front, highlights that window, and generates appropriate activate events (see Figure 6). If 5/30/84 Rose-Davis /WMGR/WINDm-l. R

24

Window Manager

Programme~'s

Guide

theWindow is already invisible, HideWindow has no effect.

I

I

Cha...._

I
I

Cbarge.

iCiM.....

=
~

sCEMemo=

wPtr poi nts to the frontmost window
Figure 6.

After HideWindow{wPtr)

After StlowWindow(wPtr)

Hiding and Showing Document Windows

PROCEDURE ShowWindow (theWindow: WindowPtr); ShowWindow makes theWindow visible. It does not change the front-toback ordering of the windows. Remember that if you previously hid the frontmost window with HideWindow, HideWindow will have brought the window behind it to the front; so if you then do a ShowWindow of the window you hid, it will no longer be frontmost (see Figure 6 above'). If theWindow is already visible, ShowWindow has no "effect. (note) Although it's inadvisable, you can create a situation where the frontmost window is invisible. If you do a ShowWindow of such a window, it will highlight the window if it's not already highlighted and will generate an activate event to force this window from inactive to active. PROCEDURE ShowHide (theWindow: WindowPtr; showFlag: BOOLEAN); If showFlag is FALSE, ShowHide makes theWindow invisible if it's not already invisible and has no effect if it is already invisible. If showFlag is TRUE, ShowHide makes theWindow visible if it's not already visible and has no effect if it is already visible. Unlike HideWindow and ShowWindow, ShowHide never changes the highlighting or front-tobacK ordering of windows or generates activate events. (warnin'g) . Use this procedure carefully, and only in special circumstances where you need more control than allowed by 5/30/84 Rose-Davis /WMGR/WINDOW.R

If fHilite is TRUE, this procedure highlights theWindow if it's not already highlighted and has no effect if it is highlighted. If fHili~e is FALSE, HiliteWindow unhighlights theWindow if it is highlighted and has no effect if it's not highlighted. The exact way a window is highlighted depends on its window definition functipn. Normally you won't have to call this procedure, since you should call SelectWindow to make a window active, and SelectWindow takes care of the necessary highlighting changes. Highlighting a window that isn't the active window is contrary to the Macintosh User Interface Guidelines. PROCEDURE BringToFront (theWindow: Wind~wPtr); BringToFront brings theWindow to the front of all other windows and redraws the window as necessary. Normally you won't have to call this procedure, since you should call SelectWindow to make a window active, and SelectWindow takes care of bringing the window to the front.' If you do call BringToFront, however, remember to call HiliteWindow to make the' necessary highlighting c~anges. PROCEDURE SendBehind (theWindow: WindowPtr; behindWindow: WindowPtr); SendBehind sends theWindow behind behindWindow, redrawing any exposed windows. If behindWindow is NIL, it sends theWindow behind all other windows. If theWindow is the active window, it unhighlights theWindow, highlights the new active window, and generates the appropriate activate events. (warning) Do not use SendBehind to deactivate a previously' active window. Calling SelectWindow to make a window active takes care of deactivating the previously active window. (note) If you're moving theWindow closer to the front (that is, if it's initially even farther behind behindWindow), you must make the following calls after calling SendBehind: wPeek := POINTER(theWindow); PaintOne(wPeek, wPeekA.strucRgn); CalcVis(wPeek, wPeekA.strucRgn) PaintOne and Cal,cVis are described below under "Low-Level Rou'tines" •

5/30/84 Rose-Davis

/WMGR/WINDOW.R

26

Window Manager Programmer's Guide

FUNCTION FrontWindow : WindowPtr; FrontWindow returns a pointer to the first visible window in the window list (that is, the active window). If there are no visible windows, it returns NIL.

Assembly-language note: In the global variable ghostWindow, you can store a pointer to a window that's not to be considered, frontmost even if it is (for example, if you want to have a special editing window always present and floating above all the others). If the window pointed to by ghostWindow is the first window in the window list, FrontWindow will return a pointer to the next visible window.

PROCEDURE DrawGrowlcon (theWindow: WindowPtr); Call DrawGrowIcon in response to an update or activate event involving a wind9w that contains a size box in its content region. If theWindow is active (highlighted), DrawGrowIcon draws the size box; otherwise, it draws whatever is appropriate to show that the window\temporarily cannot be sized. The exact appearance and location of what's drawn depend on the window definition function. For an active document window, DrawGrowIcon draws the size box icon in the bottom right corner of the portRect of the window's grafPort, along with the'lines . delimiting the size box and scroll bar areas (15 pixels in from the right edge and bottom of the portRect). It doesn't erase the scroll bar areas, so if the window doesn't contain scroll bars you should erase those areas yourself after the window's size changes. For an inactive document window, DrawGrowlcon draws only the delimiting lines (again, without erasing anything). Mouse Location

FUNCTION FindWindow (thePt: Point; VAR'whichWindow: WindowPtr) INTEGER; When a mouse-down event occurs, the application should call FindWindow with thePt equal to the point where the mOQse button was pressed (in global coordinates, as stored in the where field of the event record). FindWindow tells wh~ch part of which window, if any, the mouse button was pressed in. If it was pressed in a window, the whichWindow parameter is set· to the window pointer; otherwise, it's set to NIL. The integer returned by FindWindow is one of the following predefined constants:

InDesk usually means that the mouse button was pressed on the desktop, outside the menu bar or any windows; however, it may also mean that the mouse button was pressed inside a window frame but not in the drag region or go-away region of the window. Usually one of the last four values is returned for windows created by the application.

If you store a pointer to a procedure in the global variable deskHook, it will be called when the mouse button is pressed on the desktop. The deskHook procedure will be called with -1 in D~ to distinguish this use of it from its use in drawing the desktop (discussed in the description of InitWindows). A~ will contain a pointer to the event record for the mouse-down event. When you use deskHook in this way, FindWindow does not return inDesk when the mouse button is pressed on the desktop; it returns inSysWindow, and the Desk Manager procedure SystemClick calls the deskHook procedure.
Assembly-Ianguage~:

If the window is a documentProc type of window that doesn't contain a size box, the application should treat inGrow the same as inContent; if it's a noGrowDocProc type of window, FindWindow will never return inGrow for that window. If the window is a documentProc, noGrowDocProc, or rDocProc type of window with no close box, FindWindow will never return inGoAway for that window. FUNCTION TrackGoAway (theWindow: WindowPtr; thePt: Point) : BOOLEAN; When there's a mouse-down event in the. go-away region of theWindow, the application should call TrackGoAway with thePt equal to the point where the mouse button was pressed (in global coordinates, as stored in the where field of the event record). TrackGoAway keeps control until the mouse button is released, highlighting the go-away region as long as the mouse position remains inside it, and unhighlighting it when the mouse moves outside it. The exact way a window's go-away region is highlighted depends on its window definition function; the highlighting of a document window's close box is illustrated in Figure 7. When the mouse button is released, TrackGoAway unhighlights the go-away region and returns TRUE if the mouse is inside the go-away region or FALSE if it's outside the region (in which case the application should do nothing).

PROCEDURE MoveWindow (theWindow: WindowPtr; hGlobal,vGlobal: INTEGER; front: BOOLEAN); , MoveWindow moves theWindow to another part of the screen, without affecting its size or plane. The top left corner of the portRect of the window's grafPort is moved to the screen point indicated by the global coordinates hGlobal and vGlobal. The local coordinates of the top left corner remain the same; MoveWindow saves those coordinates before moving the window and calls the QuickDraw procedure SetOrigin to restore them before returning. If the front parameter is TRUE and theWindow isn't the active window, MoveWindow makes it the active window by calling SelectWindow(theWindow). PROCEDURE DragWindow (theWindow: WindowPtr; startPt: Point; boundsRect: Rect) ; When there's a mouse-down event in the drag region of theWindow, the application should call DragWindow with startPt equal to the point where the mouse button was pressed (in global coordinates, as stored in the where field of the event record). DragWindow pulls a gray outline \ of theWindow around, following the movements of the mouse until the button is released. When the mouse button is released, DragWindow calls MoveWindow to move theWindow to the location to which it was dragged. If theWindow is not the active window and the Command key was not being held down, DragWindow makes it the active window (by passing TRUE for the front parameter when calling MoveWindow). BoundsRect is also given in 'global coordinates. If the mouse button is released when the mouse position is outside the limits of boundsRect, DragWindow return's wi thout moving theWindow or making it the ac ti ve window. For a document window, boundsRect typically will be four pixels in from the menu bar and from the other edges of the screen, to 5/30/84 Rose-Davis /WMGR/WINDOW.Rl

WINDOW MANAGER ROUTINES ensure that there won't be less than a four-pixel-square area of the title bar visible on the screen.

29

Assembly-language note: By storing a pointer to a procedure in the global variable dragHook, you can specify a procedure to be executed repeatedly for as long as the user holds down the mouse button. (DragWindow calls DragGrayRgn, described under "Miscellaneous Utilities" below, and passes the pointer in dragHook as DragGrayRgn's actionProc parameter.)

FUNCTION GrowWindow (theWindow: WindowPtr; Rect) : LongInt;

st~rtPt:

Point; sizeRect:

When there's a mouse-down event in the grow region of theWindow, the application should call GrowWindow with startPt" equal to the point where the mouse button was pressed (in global coordinates, as stored in the where field of the event record). GrowWindow pulls a grow image of the window around, following the movements of the mouse until the button is released. The grow image for a document window, is a gray outline ,of the entire window and also the lines delimiting the title bar, size box, and scroll bar areas; Figure 8 illustrates this for a document window containing a. size box and scroll bars, but the grow image would be the same even if the window contained no size box, one scroll bar, or no scroll bars. In general, the grow image is defined in the window definition function and is whatever is appropriate to show that the window's size will change.

[====~==~~~~~~~:.==:~_~I
size returned in low-order word,
Figure 8. GrowWindow Operation on a Document Window The application should subsequently call SizeWindow (see below) to change the portRect of the window's grafPort to the new one outlined by 5/30/84 Rose-Davis /WMGR/WINDOW.Rl

30

Window Manager 'Programmer's Guide

the grow image. The sizeRect parameter specifies limits, in pixels, on the vertical and horizontal measurements of what will be the new portRect. SizeRect.top is the minimum vertical measurement, sizeRect.left is the ~inimum horizontal measurement, sizeRect.bottom is the maximum vertical measurement, and sizeRect.right is the maximum horizontal measurement. GrowWindow returns the actual size for the new portRect as outlined by the ,grow image when the mouse button is released. The high-order word of the LongInt is the vertical measurement in pixels and the low-order word is the horizontal measurement. A return value of ~ indicates that the size is the same as that of the current portRect. (note) The Toolbox Utility function HiWord takes a long integer as a parameter and returns an integer equal to its highorder word; the function LoWord returns the low-order word. PROCEDURE SizeWindow (theWindow: WindowPtr; w,h: INTEGER; fUpdate: BOOLEAN) ; Sizewindow enlarges or shrinks the portRect of theWindow's grafPort to the width and height specified by wand h, or does nothing if wand h are ~e The window's position on the screen does not change. The new \'lindo\rl frame is drawn; if the width of a document window changes, the title is again centered in the title bar, or is truncated at its end if it no longer fits. If fUpdate' is TRUE, SizeWindow accumulates any newly created area of the content region into the update region (see Figure 9); normally this is what you'll want. If you pass FALSE for fUpdate, you're responsible for the update region maintenance yourself. For more information, see InvalRect and ValidRect below.
After SizeWindow(wPtr, w1, h1, TRUE)

Title

h1

Area marked ~ is accumulated into update region

I

w1
Figure 9. SizeWindow Operation on a Document Window

5/30/84 Rose-Davis

,/WMGR/WINDOW. Rl

WINDOW MANAGER ROUTINES (note) You should change the window's size only when the user has done something specific to make it change. Update Region Maintenance

31

PROCEDURE InvalRect (badRect: Rect); InvalRect accumulates the given rectangle into the update region of the window whose grafPort is the current,port. This tells the Window Manager that the rectangle has changed and must be updated. The rectangle lies within the window's content region and is given in the local coordinates.· For example, this procedure is useful when you're calling SizeWindow (described above) for a document window that contains a size box or scroll bars. Suppose you're going to call SizeWindow with fUpdate=TRUE. If the window is enlarged as shown in Figure 8 above, you'll want not only the newly created part of the content region to be updated, but also the two rectangular areas containing the (former) size box and scroll bars; before calling Siz~Window, you can call InvalRect twice to accumulate those areas into the update region. In case the window is made smaller, you'll want the new size box and scroll bar areas to be updated, and so can similarly call InvalRect for those areas after calling SizeWindow. See Figure 1~ for an illustration of this type of update region maintenance.

Before SizeWindow with fUpdate= TRUE:

In case the window is enlarged,

ca II InvalRect for
The original windo~
Af1er SizeWindow:

~
I I

and

In case the window was made smaller"

call InvslAectfor
The new window

and

'L--__I...I

0

Figure

1~.

Update Region Maintenance with InvalRect

As another example, suppose your application scrolls up text in a document window and wants to show new text added at the bottom of the 5/30/84 Rose-Davis /WMGR/WINDOW.R1

32

Window Manager Programmer's Guide

window. You can cause the added text to be redrawn by accumulating that area into the update region with InvalRect. PROCEDURE InvalRgn (badRgn: RgnHandle); InvalRgn is the same as In~alRect (above) but for a region that has changed rather than a rectangle. PROCEDURE ValidRect (goodRect: Rect); ValidRect removes goodRect from the update region of th~ window whose grafPort is the current port. This tells the Window Manager that the application has already drawn the rectangle and to cancel any updates accumulated for that area. The rec~angle lies' within the window's content region and is given in local coordinates. Using ValidRect results in better performance and less redundant redrawing in the window. For example, suppose you've called SizeWindow (described above) with fUpdate=TRUE for a document window that contains a size box or scroll bars. Depending on the dimensions of the newly sized window, the new size box and scroll bar areas mayor may not have been accumulated into the window's update region. After calling SizeWindow, you can redraw the size box or scroll bars immediately and then call ValidRect for the areas they occupy in case they were in fact accumulated into the update region; this will avoid redundant drawing. PROCEDURE ValidRgn (goodRgn: RgnHandle); ValidRgn is the same as ValidRect (above) but for a region that has been drawn rather than a rectangle. PROCEDURE BeginUpdate (theWindow: WindowPtr); Call BeginUpdate when an update event occurs for theWindow •. BeginUpdate replaces the visRgn of,the window's grafPort with the intersection of the visRgn and the update region and then sets the window's up,date region to the empty region. You would then usually draw the entire content region, though it suffices to draw only the visRgn; in either case, only the parts of the window that require updating will actually be drawn on the screen. Every call to BeginUpdate must be balanced by a call to EndUpdate. (See below, and see "How a Window is Drawn".) PROCEDURE EndUpdate (theWindow: WindowPtr); Call EndUpdate to restore the normal visRgn of theWindow's grafPort, which was changed by BeginUpdate as described above.

GetWRefCon returns theWindow's current reference value. PROCEDURE SetWindowPic (theWindow: WindowPtr; pic: PicHandle); SetWindowPic stores the given picture handle in the window record for theWindow, so that when theWindow's contents are to be drawn, the Window Manager will draw this picture rather than generate a'n update event. FUNCTION GetWindowPic (theWindow: WindowPtr) : PicHandle; GetWindowPic .returns the handle to the picture that draws theWindow's contents, previously stored with SetWindowPic (above). FUNCTION PinRect (theRect: Rect; thePt: Point) : LongInt; PinRect "pins" thePt inside theRect: The high-order word of the function result is the vertical coordinate of thePt or, if thePt lies above or below theRect, the vertical coordinate of the t?P or bottom of theRect, respectively. The low-order word of the function result is the horizontal coordinate of thePt or, if thePt lies to the left or right of theRect, the horizontal coordinate of the left or right edge of theRect. FUNCTION DragGrayRgn (theRgn: RgnHandle; startPt: Point; limitRect,slopRect: Rect; axis: INTEGER; actionProc: ProcPtr) : LongInt; Called when the mouse button is down inside theRgn, DragGrayRgn pulls a gray outline of the region around, following the movements of the mouse until the button is released. DragWindow calls this function before actually moving the window, and the Control Manager routine DragControl similarly calls it for controls. You can call it yourself to pull around the outline of any region, and then use the information it returns to determine 'where to move the region. The startPt parameter is assumed to be, the point where the mouse button was originally pressed, in the local coordinates of the current 5/30/84 Rose-Davis /WMGR/WINDOW.Rl

34

Window Manager Programmer's Guide

grafPort. LimitRect and slopRect are also in the local coordinates of the current ( grafPort. To explain these parameters, the concept of "offset point" 'must be introduced: this is the point whose vertical and horizontal offsets from the top left corner of the region's enclosing rectangle are the same as those of~startPt. Initially the offset point is the same as the mouse position, but they may differ, depending on where the user moves the mouse. DragGrayRgn will never move the offset point outside limitRect; this limits the travel of the region's outline (but not the movements of the mouse). SlopRect, which should completely enclose limitRect, allows the user some "slop" in moving the mouse. DragGrayRgn's behavior while tracking the mouse depends on the position of the mouse with respect to these two rectangles:
,

- When the mouse is inside ,limitRect, the region's outline follows it normally. If the mouse button is released there, the region should be moved to the mouse position. - When the mouse is outside limitRect but inside slopRect, DragGrayRgn "pins" the offset point to the edge of limitRect. If the mouse button is released there, the region should be moved to this pinned location. - When the mouse is outside slopRect, the outline disappears from' the screen, but DragGrayRgn continues to follow the mouse; if it moves back into slopRect, the outline reappears. If the mouse button is released outside slopRect, the region should not be moved from its original position. Figure 11 illustrates what happens when t~e mouse is moved outside limitRect but inside slopRect, for a rectangular region. The offset point is pinned as the mouse position moves on.
------~------------- I

position
Figure 11. DragGrayRgn Operation on a Rectangular Region If the mouse button is released outside slopRect, DragGrayRgn returns

-32768 ($8000); otherwise, the high-order word of the value returned
contains the vertical coordinate of the ending mouse point minus that 5/30/84 Rose-Davis /WMGR/WINDOW.Rl

WINDOW MANAGER ROUTINES of startPt and the low-order word contains the difference between the horizontal coordinates.

35

The axis parameter allows you to constrain the outline's motion to only one axis. It has one of the following values: CONST noConstraint hAxisOnly vAxisOnly

0;, {no constraint}
1; 2; {horizontal axis only} {vertical axis only}

If an axis constraint is in effect, the outline will follow the mouse's movements along the specified axis only, ignoring motion along the other axis. With or without an axis constraint, the mouse must still be inside the slop rectangle for the outline to appear at all. The actionProc parameter is a pointer to a procedure that defines some action'to be performed repeatedly for as long as the user holds down the mouse button; the procedure should have no parameters. If actionProc is NIL, DragGrayRgn simply retains control until the mouse button is released, performing no action while the mouse button is down.

Assembly-language note: If you want the region's outline to be drawn in a pattern other than gray, you can store the pattern in the global variable dragPattern and call the above function at the entry point _DragTheRgn.

Low-Level Routines These low-level routines are not normally used by an application but may be of interest to advanced programmers. FUNCTION CheckUpdate (VAR theEvent: EventRecord) BOOLEAN;

CheckUpdate is called by the Toolbox Event Manager. From the front to the back in the window list, it looks for a visible window that needs updating (that is, whose update region is not empty). If it finds one whose window record contains a picture handle, it draws the picture (doing all the necessary region manipulation) and looks for the next visible window that needs updating. If it ever finds one whose window record doesn't contain a picture handle, it stores an update event for that window in theEvent and returns TRUE. If it never finds such a window, it returns FALSE.

5/30/84 Rose-Davis

/WMGR/WINDOW.R1

36,

Window Manager Programmer's Guide

PROCEDURE ClipAbove (window: WindowPeek); ClipAbove sets the clipRgn of the Window Manager port to be the desktop (global variable grayRgn) intersected with the current clipRgn, minus the structure regions of all the windows above the given window. PROCEDURE SaveOld (window: WindowPeek); SaveOld saves the given window's current structure region and content region for the DrawNew operation (see below). It must be balanced by a subsequent call to DrawNew. PROCEDURE DrawNew (window: WindowPeek; update: BOOLEAN); If the update parameter is TRUE, DrawNew updates the area (oldStruct XOR newStruct) UNION (oldContent XOR newContent) where oldStruct and oldContent are the structure and content regions saved by the SaveOld procedure, and newStruct and newContent are the current structure and content regions. It paints the area white and adds it to the window's update region. If update is FALSE, it only paints the area white. (warning) Save Old and DrawNew are not nestable. PROCEDURE PaintOne (window: WindowPeek; clobberedRgn: RgnHandle); PaintOne "paints" the given window, clipped to clobberedRgn and all windows above it: it draw~ the window frame and, if some content is exposed, paints the exposed area white and adds it to the window's update region. If the window parameter is NIL, the window is the desktop and so is painted gray. PROCEDURE PaintBehind (startWindow: WindowPeek; clobberedRgn: RgnHandle) ;. PaintBehind calls PaintOne (above) for startWindow and all the windows behind startWindow, clipped to clobberedRgn. PROCEDURE CalcVis (window: WindowPeek); CalcVis calculates the visRgn of the given window by starting with its content ,region and subtracting the structure region of each window in front of it.

CalcVisBehind calculates the visRgns of startWindow and all windows behind startWindow that intersect with clobberedRgn. It's called after PaintBehind ($ee above).

Assembly-language note: The macro you invoke to call CalcVisBehind from assembly language is named CalcVBehind.

DEFINING YOUR OWN WINDOWS Certain types of windows, such as the standard document window, are predefined for you. However, you may want to define your own type of, window--maybe a round or hexagon-shaped window, or even a window shaped like an apple. QuickDraw and the Window Manager make it possible for you to do this. (note) For the convenience of your application's user, remember to conform to the Macintosh User Interface Guidelines for windows as much as possible. To define your own type of window, you write a window definition function and (usually) store it in a resource file. '¥hen you create a w~ndow, you provide a window definition ID, which leads to the window definition function. The window definition ID is an integer that contains the resource ID of the window definition function in its upper 12 bits and a variation code in its lower four bits. Thus" for a given resource ID and variation code, the window definition ID is: 16

*

resource ID + variation code

The variation code allows a single window definition function to implement several related types of window as "variations on a theme". For example, the dBoxProc type of window is a variation of the standard document' window; both use the window definition functio~ whose resource ID is 0, but the document window has a variation code of 0 while the dBoxProc window has a variation code of 1. The Window Manager calls the Resource Manager to access the window definition function with the given resource ID. The'Resource Manager reads the window definition function into memory and returns a handle to it. The Window Manager stores this handle in the windowDefProc field of the window record, along with the variation code in the highorder byte of that field. Later, when it needs to perform a typedependent action on the window, it calls the window definition function and passes it the variation code as a parameter. Figure 12 summarizes 5/30/84 Rose-Davis /WMGR/WINDOW.D

\

38

Window Manager Programmer's Guide

this process.

You supply the window definition 10:

I

15
resource 10

4 3

Icode I

0

(resource '.10 of window definition function· and variation code)

The Window Manager calls the Resource Manager with

defHandle := GetResource ('WDEF'.. resourcelO) and stores into the windowOefProc field of the window record:

You may find it more convenient to include the window definition function with the code of your program instead of storing it as a separate resource. If you do this, you should supply the window definitionID of any standard window type when you create the window, and specify that the window initially be invisible. Once the window is created, you can replace the contents of the windowDefProc field with as handle to the actual window definition function (along with a variation code, if needed, in the high-order byte of the field). You can then call ShowWindow to make the window visible. The Window Definition Function The window definition function may be written in Pascal or assembly language; the only requirement is that its entry point must be at the beginning. You may choose any name you wish for your window definition function. Here's how you would declare one named MyWindow: FUNCTION MyWindow (varCode: INTEGER; theWindow: WindowPtr;. message: INTEGER; param: LongInt) : LongInt; VarCode is the variation code, as described above. TheWindow indicates the window that the operation will affect. If the window definition function needs to use a WindowPeek type of pointer more than a WindowPtr, you can simply specify WindowPeek instead of WindowPtr in the function declaration.

5/30/84 Rose-Davis

/WMGR/WINDOW.D

DEFINING YOUR OWN WINDOWS
I

39

The message parameter identifies the desired operation. the following values:

It has one of

CONST wDraw ~; . {draw window frame} wHit 1 ; {tell what region mouse button was pressed.in} wCalcRgns 2; {calculate strucRgn and contRgn} wNew 3; {do any additional window initialization} wDispose 4; {take any additional disposal actions} {draw window's grow image} . = 5; wGrow wDrawGIcon 6; {draw size box in content region} As described below in the discussions of the routines that perform these operations, the value passed for param, the last parameter of the window definition function, depends on the operation. Where it's not mentioned below, this parameter is ignored. Similarly, the window definition function is expected to return a function result only where indicated; in other cases, the function should return ~. (note) "Routine" here does not necessarily mean a procedure or function. While it's a good idea to set these up as subprograms inside the window definition function, you're not required to do so. The Draw Window Frame Routine When the window definition function receives a wDraw message, it should draw the window frame in the current grafPort, which will be the Window .Manager port. (For details on drawing, see the QuickDraw manual.) (warning) Do not change the visRgn or clipRgn of the Window Manager port, or overlapping windows may not be handled properly. This routine should make c~rtain checks to determine exactly what it should do. If the visible field in the window record is FALSE, the routine should do nothing; otherwise, it should examine the value of param received by the window definition function, as described below. If param is ~, the routine should draw the entire window frame. If the hili ted field in the window record is TRUE, the window frame should be highlighted in whatever way is appropriate to show that this is -the active window. If goAwayFlag in the window record is aiso TRUE, the highlighted window frame should include a go-away region; this is useful when you want to define a window such that a particular window of that type mayor may not have a go-away region, depending on the situation. Special action should be taken if the value of param is wlnGoAway (a predefined constant, equal to 4, which is one of those returned by the hit routine described below). If param is wInGoAway, the routine should do nothing but "toggle" the state of the window's go-away region from unhighlighted to highlighted 'or vice versa. The high~ighting 5/30/84 Rose-Davis /WMGR/WINDOW.D

40

Window Manager Programmer's Guide

should be whatever is appropriate to show that the mouse button has been pressed inside the region. Simple inverse highlighting may be used or, as in document windows, the appearance of the region may change considerably. In the latter case, the .routine could use a "mask" consisting of the unhighlighted state of the region XORed with its highlighted state (where XOR stands for the logic'al operation "exclusive or"). When such a mask is itself XORed with either state of the region, the result is the other state; Figure 13 illustrates this.

Dx~
Unhi gill ighted state

,1/ /1'
. state

= /1'

[lli
Mask

~ighlighted

DXOR [lli =
/1'
Figure 13.

,1/ /1'

XOA~=D ~
Toggling the Go-Away Region Typically the window frame will include the window's title, which should be in the system font and system font size for consistency with the Macintosh User Interface Guidelines. The Window Manager port will already be set to use the sy,stem font and system font size. (note) Nothing drawn outside the window's structure region will be visible. The Hit Routine When the window definition function receives a wHit message, it also receives as its param value the' point where the mouse button was pressed. This point is given in global coordinates, with the vertical coordinate in the high-order word of the LongInt and the horizontal coordinate in the low-order ·word. The window definition furiction should determine where the mouse button "hit" and then return one of these'predefined constants: CONST wNoHit wInContent wInDrag wInGrow wInGoAway 5/30/84 Rose-Davis

Usually, wNoHit means the given point isn't anywhere within the window, but this is not necessarily so. For example, the document window's hit routine returnswNoHit if the point is in the window frame but not in the title bar. The constants wlnGrow and wlnGoAway should be returned only if the window is active, since by convention the size box and go-away region won't be drawn if the window is inactive (or, if drawn, won't be operable). In an inactive document window, if the mouse button is pressed in the title bar where the close box would be if the window were active, the hit routine should return wInDrag. Of the regions that may have been hit, only the content region necessarily has the structure of a region and is included in the window record. The hit routine can determine in any way it likes whether the drag, grow, or go-away "region" has been hit. The Routine to Calculate Regions The routine executed in response to a wCalcRgns message should calculate the window's structure region and content region based on the current grafPort's portRect. These regions, whose handles are in the strucRgn and contRgn fields, are in global coordinates. The Window Manager will request this operation only if the window is visible. (warning) When you calculate regions for your own type of window, do not alter the clipRgn or the visRgn of the window's grafport. The Window Manager and QuickDraw take care of this for you. Altering the clipRgn or visRgn may result in damage to other windows. The Initialize Routine
~

After initializing fields as appropriate when creating a new window, the Window Manager sends the message wNew to the window definition function. This gives the definition function 'a chance to perform any type-specific initialization it may require.- For example, if the content region is unusually shaped" the initialize routine might allocate space for the region and store the region handle in the dataHandle field of the window record. The initialize routine for a document window does nothing. The Dispose Routine The Window Manager's CloseWindow and DisposeWindow procedures send the message wDispose to the window definition function, telling it to carry out any additional actions required when disposing of the window. The 'dispose routine might, for example, release space that was allocated by the initialize routine. The dispose routine for a document window does nothing. 5/30/84 Rose-Davis /WMGR/WINDOW.D

42

Window Manager Programmer's Guide

The Grow Routine When the window definition function receives a wGrow message, it also receives a pointer to a rectangle as its param value. The rectangle is in global coordinates and is usually aligned at its top left corner with the portRect of the window's grafPort. The grow routine should draw a grow image of the window to fit the given rectangle (that- is, whatever is appropriate to show that the window's size will change, 'such as an outline of the content region). The Window Manager requests this operation repeatedly as the user drags inside the grow region. The grow routine should draw in the current grafPort, which will be the Window Manager port, and should use the grafPort's current pen pattern and pen mode, which are set up (as gray and notPatXor) to conform to the Macintosh User Interface Guidelines. The grow routine for a document window draws a gray outline of the window and also the lines delimiting the title bar, size box, and scroll bar areas. The Draw Size Box Routine Thw wDrawGIcon message tells the window definition function to draw the size box in the ~ontent region of the window if the window is active (highlighted) or, if the window is inactive, whatever is appropriate to show that it temporarily can't be sized. For active document windows, this routine draws the size box icon in the bottom right corner of the portRect of the window's grafPort, along with the lines delimiting the size box and scroll bar areas; for inactive windows, it draws just the delimiting lines. (note) If the size box is located in the window frame rather than the content region, this routine should do nothing.

FORMATS OF RESOURCES FOR WINDOWS The Window Manager function GetNewWindow takes the resource ID of a window template as a parameter, and gets from the template the same infomation that the NewWindow function gets from six of its parameters. The resource type for a window template is 'WIND', and the resource data has the following format:

Contents Same as boundsRect parameter to NewWindow Same as procID parameter to NewWindow Same as visible parameter to NewWindow Same as goAwayFlag parameter to NewWindow . Same as ref Con parameter to NewWindow Same as title parameter to NewWindow (I-byte length in bytes) followed by the characters of the title)

The resource type for a window definition function is 'WDEF') and the resource data is simply the compiled or assembled code of the function.

GLOSSARY activate event: An event generated by the Window Manager when a window changes from active to inactive or vice versa. active window: The frontmost window on the desktop.

application window: A window created as the result of something done by the application, either directly or indirectly (as through the Dialog Manager).
r

content region: control list: window. desktop:

The area of a window that the application draws in. A list of all the controls associated with a given

The screen as a surface for doing work on the Macintosh. A s"tandard Macintosh window for presenting a

document window: document.

drag region: A region in the window frame. Dragging inside this region moves the window to a new location and makes it the active window unless the Command key was down. go-away region: A region in the window frame. Clicking inside this region of the active window makes the window close or disappear. grow image: The image pulled around when dragging inside the grow region occurs; 'whatever is appropriate to show that the window's size will change. grow region: A window region, usually within the content region, where dragging changes the size of an active window. highlight: To display an object on the screen in a distinctive yisual way, such as inverting it. inactive window: desktop. invert: Any window that isn't the frontmost window on the

To highlight by ,changing white pixels to black and vice versa. A window that's not drawn in its plane on the

invisible window: desktop.

modal dialog: A dialog that requires the.user to respond before doing any other work on the desktop. modeless dialog: A dialog that allows the user to work elsewhere on the desktop before responding.

5/30/84 Rose-Davis

/WMGR/WINDOW.G

GLOSSARY plane: The front-to-back position of a window on the desktop.

51

reference value: In a window record, a 32-bit field that the application program may store into and access for any purpose. structure region: system window: An entire window; its complete "structure".

A window in which a desk accessory is displayed.

update event: An event generated by the Window Manager when the update region of a window is to be drawn. update region: A window region consisting of all areas of the content region that have to be redrawn. variation code: A number that distinguishes closely related types of windows and is passed as part of a window definition 10 when a window is created. visible window: A window that's drawn in its plane on the desktop (but may be completely overlapped by another window or object on the screen) • window: An obj~ct on the desktop that presents information, such as a document or a message. window class: An indication of whether a window is a system window, a dialog or alert window, or a window created directly by the application. window definition function: A function called by the Window Manager when it needs to perform certain type-dependent operations on a particular type of window, such as drawing the window frame. window definition 10: A number passed to window-creation routines to indicate the type of window. -It consists of the window definition function's resource 10 and a variation code. window frame: The structure region minus the content region.
th~ir

window list: A list of all windows ordered according to back positions on the desktop.

front-to-

Window Manager port: A grafPort' that has the entire screen as its portRect and is used by the Window Manager to draw window frames. window record: The internal representation of a window, where the Window Manager stores all the information it needs for its operations on that window. window template: A resource that contains information from which the Window Manage'r can create a window.

5/30/84 Rose-Davis

/WMGR/WINDOW.G

MACINTOSH USER EDUCATION The Control Manager: See Also: A Programmmer's Guide /CMGR/CONTROLS

Controls are special objects on the Macintosh screen with which the user, using the mouse, can cause instant action with graphic results or change settings to modify a future action. The Macintosh Control Manager is the part of the User Interface Toolbox that enables applications to create and man.ipulate controls in a way that's consistent with the Macintosh User Interface Guidelines. This manual describes the Control Manager. Summary of significant changes and additions since last draft: •

- There's now a way to specify that you want the standard control definition functions to use the font associated with the control's window rather than the system font (page 8). - You can now detect when the mouse button was pressed in an inactive control as opposed to not in any control; see HiliteControl, TestControl, and FindControl (page 18). - The control definition function may itself contain an action procedure (pages 20 and 30). - Assembly-language notes were added ~here appropriate, and the summary was updated to include all assembly-language information.

2

Control Manager Programmer's Guide

TABLE OF CONTENTS 3 4 7 8 9 10 11 13 15 15 17 18 21 22 24 24 26 26 27 27 28 28 29 29 29 About This Manual About the Control Manager Controls and Windows Controls and Resources Part Codes Control Records The ControlRecord Data Type Using the Control Manager Control Manager Routines Initialization and Allocation Control Display 'Mouse Location Control Movement and Sizing Control ,Setting and Range Miscellaneous Utilities Defining Your Own Controls The Control Definition Function The Draw Routine The Test Routine The Routine to Calculate Regions The Initialize Routine The Dispose Routine The Drag Routine The Position Routine The Thumb Routine The Track Routine Formats of Resources for Controls Summary of the Control Manager Glossary

30 30
31 36

Copyright (c) 1984 Apple Computer) '-rnc.

All rights reserved.

ABOUT THIS MANUAL

3

ABOUT THIS MANUAL This manual describes the Control Manager of the Macintosh User Interface Toolbox. *** Eventually it will become a chapter in the comprehensive Inside Macintosh manual. *** The Control Manager is the part of the Toolbox that deals with controls, such as buttons, check' boxes, and scroll bars. Using it, your application can create, manipulate, and dispose of controls in a way that's consistent with the Macintosh User Interface Guidelines. Like all Toolbox documentation, this manual assumes you'~e familiar with the Macintosh User Interface Guidelines, Lisa Pascal, and the Macintosh Operating System's Memory Manager. You should also be familiar wiih the followi~g: Resources, as discussed in the Resource Manager manual. - The basic concepts and structures behind QuickDraw, particularly rectangles, regions, and grafPorts. You don't need a detailed knowledge of QuickDraw, since implementing controls through the Control Manager doesn't require calling QuickDraw directly. - The Toolbox Event Manager. The essence of a control is to respond to the user's actions with the mouse; your application finds out about those actions by calling the Event Manager. - The Window Manager. Every control you create with the Control Manager "belongs" to some window. The Window Manager and Control Manager are designed to be used together, and their structure and operation are parallel in many ways. (note) Except for scroll bars, most controls appear only in dialog or alert boxes. To learn how to implement dialogs and alerts in your application, you'll have to read the Dialog Manager manual. This manual is intended to serve the needs of both Pascal and assemblyl~nguage programmers. Information of interest to assembly-language programmers only is isolated and labeled so that Pascal programmers can conveniently skip it. The manual begins with an introduction to the Control Manager and what you can do with it. It then discusses some basic concepts about controls: the relationship between controls and windows; the relationship between controls and resources; and how controls and their various parts are identified. Following this is a discussion of control records, where the Control Manager keeps all the information it needs about a control. Next, a section on using the Control Manager introduces its routines and tells how they fit into the flow of your application program. This is followed by detailed descriptions of all Control Manager procedures 5/30/84 Chernicoff-Rose /CMGR/CONTROLS.2

4

Control Manager Programmer's Guide

and functions, their parameters, calling protocol, effects, side effects, and so on. Following these descriptions are sections that will not interest all readers: special information is provided for programmers who want to define their own controls, and the exact formats of resources related to controls are described. Finally, there's a 'summary of the Control Manager, for quick reference, followed by a glossary of terms used in this manual.

ABOUT THE CONTROL MANAGER The Control Manager is the part of ' the Macintosh User Interface Toolbox that deals with controls. A control is an object on the Macintosh screen with which the user, using the mouse, can cause instant action with graphic results or change settings to ~odify a future action. Using the Control Manager, your application can: create and dispose of controls - display or hide controls - monitor the user's operation of a control with the mouse and respond accordingly - read or change the setting or other properties of a control - change the size, location, or appearance of a control Your application performs these actions by calling th~ appropriate Control Manager routines. The Control Manager carries out the actual operations, but it's up to you to decide when, where, and how. Controls' may be of various types (see Figure 1), each with its own characteristic appearance on the sc~een and responses to the mouse. Each individual coritrol has its own specific properties--such as its location, size, and setting--but controls of the same type behave in the same general way.

o Radio Button 3
Figure 1. Controls Certain standard types of controls are predefined for you. Your application can easily create and use controls of these standard types, and can also define its own "custom" control types. Among the standard control types are the following: - Buttons cause an immediate or continuous action when clicked or pressed with the mouse. They appear on the screen as roundedcorner rectangles with a title centered inside. - Check boxes retain and d~splay a setting, either checked (on) or unchecked (off); clicking with the mouse reverses the setting. On the screen, a check box appears as a small square with a title alongside it; the box is either filled in with an "X" (checked) or empty (unchecked). Check boxes are frequently used to control or modify some future action, instead of causing an immediate action, of their own. - Radio buttons also retain and display an on-or-off setting. They're organized into groups, with the property that only one button in the group can be on at a time: clicking any button on turns off all the others in the group, like the buttons on a car radio. Radio buttons are used to offer a choice among several alternatives. On the screen, they look like round check boxes; the radio button that's on is filled with a small black circle instead of an "X". (note) The Control Manager doesn't know how radio buttons are grouped, and doesn't automatically turn one off when the user clicks another one on: it's up to your program to handle this.

5/30/84 Chernicoff-Rose

/CMGR/CONTROLS.2

6

Control Manager Programmer's Guide

Another important category of controls is dials. These display a quantitative setting or value, typically in some pseudoanalog form such as the position of a sliding switch, the reading on a thermometer scale, or the angle of a needle on a gauge; the setting may be displayed digitally as well. The control's moving part that displays the current setting is called the indicator. The user may be able to change a dial's setting by dragging its indicator with the mouse, or the dial may simply display a value not under the user's direct control (such as the amount of free space remaining on a disk). One type of dial is predefined for you: the standard Macintosh scroll bars. Figure 2 shows the five parts of a scroll bar and the terms used by the Control Manager (and this manual) to refer to them. Notice that the part of the scroll bar that Macintosh users know as the "scroll box" is called the "thumb" here. Also, for simplicity, the terms "up" and "down" are' used even when referring to horizontal scroll bars (in which case "up" really means "left" and "down" means "right").

Up arrow - - - - - - - - - - "Page up" region - - - - - - -

Thumb - - - - - - - "Page down" Down arrow - - -

t (¢ti·· ............ , · .. · .... ······ .... · .. ···IOI ' : :' : ' : -:-:::::' : ' : ' : :' : ' : :' : ' : ' : ' : ' : ' : -:: ...._......- !::::::::::::::::::::::::'- ..
Figure 2. Parts of a Scroll BarThe up and down arrows scroll the window's contents a line at a time. The two paging regions scroll a "page" (windowful) at a time. The thumb can be dragged to any position in the scroll bar, to 'scroll to a corresponding position within the document. Although they may seem to behave like individual controls, these are all parts of a single \ control, the scroll bar type of d~al. You can define other dials of any shape or complexity for yourself if your application needs them. When clicked or pressed, a control is usually highlighted (see Figure 3). Standard button controls ~re inverted, but some control types may use other forms of highlighting, such as making the outline heavier. It's also possible for just a part of a control to be highlighted: for example, when the user presses the mouse button fnside a scroll arrow or the thumb in a scroll bar, the arrow or thumb (not the whole scroll bar) becomes highlighted until the button is released.

A control may,be active or inactive. Active controls respond to the user's mouse actions; inactive controls don't. A control is made -inactive when it has no meaning or effect in the current context, such as an "Openl~ button when no document has been selected to open, or a scroll bar when there's currently nothing to scroll to. An inactive control remains visible, but is highlighted in some special way, depending on its control type (see Figure 4). For example, the title of an inactive button, check box, or radio button is dimmed (drawn in gray rather than black).

( Ilu110n )

I¢I
Figure 4.

101
Inactive Controls

CONTROLS AND WINDOWS
Every control "belongs" to a particular window: When displayed, thecontrol appears within that window's content region; when manipulated with the mouse, it acts on that window •. All coordinates pertaining to the control (such as those describing its location) are given in its window's local coordinate system. (warning) In order for the Control Manager to draw a control properly, the control's window must have the top left corner of its grafPort's portRect at coordinates (0,0). 5/30/84 Chernicoff-Rose

/CMGR/CONTROLS.2

8

Control Manager Programmer's Guide If you change a window's local coordinate system for any reason (with the QuickDraw procedure SetOrigin), be sure to change it back--so ,that the top left- corner is again at (0,0)--before drawing any of its controls. Since almost all of the Control Manager routines can (at least potentially) redraw a control, the safes t polic'y is simply to change the coordinate system back before calling any Control Manager routine.

Normally you'll include buttons and check boxes in dialog or alert windows only. You create such windows with the Dialog Manager, and the Dialog Manager takes care of drawing the controls and letting you know whether the user clicked one of them. See the Dialog Manager manual for,details.

CONTROLS AND RESOURCES The relationship between controls and resources is analogous to the relationship between windows and resources: just as there are window definition functions and window templates, there are control definition functions and control templates. Each type of control has a control definition function that determines how controls of that type look and behave. The Control Manager calls the control definition function whenever it needs to perform a typedependent action, such as drawing the control on the screen. Control definition functions are stored as resources and accessed through the Resource Manager. The system resource file includes definition functions for'the standard control types (buttons, check boxes, radio buttons, and scroll bars). If you want to define your own, nonstandard control types, you'll have to write your own definition functions for them, as described later in the section "Defining Your Own Controls". When you create a control, you specify its type with a control definition ID, which tells the Control Manager the resource ID of the definition function for that control type. The Control Manager, provides the following predefined constants for the definition IDs of the standard control types: CONST pushButProc checkBoxProc radioButProc scrollBarProc

= O; = =
1; 2; 16;

{simple button} {check box} {radio button} {scroll bar}

~

The title of a button, check box, or radio button normally appears in the system font, but you can add the following constant to the definition ID to specify that you instead want to use the fortt currently associated with the window's grafPort:, CONST useWFont.= 8; {use window's font}

5/30/84 Chernicoff-Rose

/CMGR/CONTROLS.2

CONTROLS AND RESOURCES

9

To create a control, the Control Manager needs to know not only the control definition ID but also other information specific to this "control, such as its title (if any), the window it belongs to, and its location within the window. You can supply all the needed information in individual parameters to a Control Manager routine, or you ,can store it in a control template in a resource file and just pass the ~emplate's resource ID. Using templates is highly recommended, since it simplifies the process of creating controls and isolates the control descriptions from your applicati~n's code. ' (note) You can create control templates and store them in resource ,files with the aid of the Resource Editor *** eventually (for now, the Resource Compiler) ***. The Resource Editor relieves you of having to know the exact format of a control template, but if you're interested, you'll find details in the section "Formats of Resources for Controls".

PART CODES Some controls, such as buttons, are simple and straightforward. Others can be complex objects with many parts: for example, a scroll bar has two scroll arrows, two paging regions, and a thumb (see Figure 2). To allow different parts of a control to respond to the mouse in different ways, many of the Control Manager routines accept a part code as a parameter or return one as a result. A part code is an integer between 1 and 253 that stands for a particular part 'of a control. Each type of control. has its own set of part codes, assigned by the control definition function for that type •. A simple control such as a button or check box might have just one "part" that encompasses the entire control; a more complex control such as a scroll bar can have as many parts as are needed to define how the control operates. Some of the Control Manager routines need to give special treatment to the indicator of a dial (such as the thumb of a scroll bar). To, allow the Control Manager to recognize such indicators, they always have part codes greater than 128. (note) The values 254 and 255 are not used for part codes because to some Control Manager routines they represent the entire control in its inactive state. The part codes for the standard control types are as follows:

Notice that inCheckBox applies to both check boxes and radio buttons. (note) The part code 128 is reserved for special use by the Control Manager and so should not be used for parts of your controls.

CONTROL RECORDS Every control is represented internally by a control record containing all pertinent information about that control. The control record contains the following: - A pointer to the window the control belongs to. - A handle to the next control in the window's control list. - A handle to the control definition function. - The control's title, if any. - A rectangle that completely encloses the control, which determines the control's size and location within its window. The entire control, including the title of a check box or radio button, is , drawn inside th~s rectangle. An indication of whether the control is currently active and how it's to be highlighted. - The current setting of the control (if this type of control retains a setting) and the minimum and maximum'values the setting can assume. For check boxes and radio buttons, a setting of 0 means the control. is off and 1 means it's on. The control record also contains an indication of whether the contr'ol is currently visible or invisible. These 'terms refer only to whether the control is drawn in its window, not to whether you can see it on the screen. A control may be "visible" and still not appear on the screen, because it's obscured by overlapping windows or other objects. There's a field in the control record for a pointer to the control's default action procedure. An action procedure defines some action to be performed repeatedly for as long as the user holds down the mouse button inside the control. The default action procedure may be used by 5/30/84 Chernicoff-Rose /'CMGR/CONTROLS.2

CONTROL RECORDS

11

the Control Manager function TrackControl if you call it without passing a pointer to an action procedure; this is discussed in detail in the description of TrackControl in the "Control Manager Routines" .' section. Finally, the control record includes a 32-bit reference value field, which is reserved for use by your application. You specify an initial reference value when you create a control, and can then read or change the reference value whenever you wish. The data type for a control record is called ControlRecord. record is referred to by a handle: TYPE ControlPtr ControlHandle . . ControlRecord; . . ControlPtr; A control

The Control Manager functions for creating a control return a handle to a newly allocated control record; thereafter, your program should normally refer to the control by this handle. Most of the Control Manager routines expect a control handle as their first parameter. You can store into and access most o.f a control record's fields wi th Control Manager routines, so normally you don't have to know the exact field names. However, if you want more information about the exact structure of a control record--if you're defining your own control types, for instance--it's given below. The ControlRecord Data Type The type ControlRecord is defined as follows: TYPE ControlRecord = RECORD nextControl: contrlOwner: contrlRect: contrlVis: contrlHilite: contrlValue: contrlMin: contrlMax: contrlDefProc: contrlData: contrlAction: contrlRfCon: contrlTitle: END;

NextControl is a handle to the next control associated with this control's window. All the controls belonging to a given window are kept in a linked list, beginning in the controlList field of the window record and chained together through the nextControl fields of the individual control records. The end of the list is marked by a NIL 5/30/84 Chernicoff-Rose /CMGR/CONTROLS.2

· 12

Control Manager Programmer's Guide

value; as new controls are created, they are added to the beginning of the list. ContrlOwner is a pointer to the window that this control belongs to. ContrlRect is the rectangle that completely encloses the control, in the local coordinates of the control's window. When contrlVis is TRUE, the control is currently visible. (note) The Control Manager sets the contrlVis field FALSE by storing 255 in it rather than 1. This may cause problems in Lisa Pascal; to be safe, you should check for the truth or falsity of this flag by comparing ORD of the flag to 0. ContrlHilite is an integer between 0 and 255 that specifies wheth~r and how the control is to be highlighted. It's declared as BOOLEAN so that Pascal will put the value in a byte; if declared as Byte, it would be put it in a word because of Pascal's packing conventions. Storing directly into the contrlHilite field limits it to a Boolean value, so you'll probably instead want to use the Control Manager routine that sets it (HiliteControl). See the description of HiliteControl in the "Control Manager Routines" section for information about the meaning of this field's value. ContrlValue is the control's current setting. For check boxes and radio buttons, 0 means the control is off and 1 means it's on. For dials, the fields contrlMin and contrlMax define the range of possible settings; contrlValue may take on any value within that range. Other (custom) control types can use these three fields as they see fit.
j

ContrlOefProc is a handle to the control definition function for this type of control. When you cr~ate a control, you identify its type with a control definition 10, which is converted into a handle to the control definition function and stored in the contrlOefProc field. Thereafter, the Control Manager uses this handle to access the definition function; you should never need to refer to this field directly. (note) The high-order byte of the contrlDefProc field contains some additional information that the Control Manager gets from the control definition 10; for details, see the section "Defining Your Own Controls". Also note that if you write your own control definition function, you can include it as part of your- application's code and just store a handle to it in the contrlDefProc field.· ContrlData is reserved for use by the control definition-function, typi~ally to hold additional information specific to a particular control ~ype. For example, the standard definition function for scroll bars uses this field for a1handle to the region containing the scroll 5/30/84 Chernicoff-Rose /CMGR/CONTROLS.2

CONTROL RECORDS

13

bar's thumb. If no more than four bytes of additional information are needed, the definition function can store the information directly in the contrlData field rather than use a handle. ContrlAction is a pointer to the control's default action procedure, if any. The Control Manager function TrackControl may call this procedure to respond to the user's dragging the mouse inside the control. ContrlRfCon is the control's reference value field, which the application may store into and access for any purpose. ContrlTitle is the control's title, if any.

Assembly-language note: The global constant contrlSize equals the length in bytes of a control record less its contrlTitle field.

USING THE CONTROL MANAGER This section discusses how the Control Manager' routines fit into the general flow of an application program and gives you an idea of which routines you'll need to use. The routines themselves are described in detail in the next section. (note) For controls in d~alogs or alerts, the Dialog Manager makes some of the basic Control Manager calls for you; see the Dialog Manager manual for more information. To use the Control Manager, you must have previously called InitGraf to initialize QuickDraw, InitFonts to initialize the Font Manager, and InitWindows to initialize the Window Manager. . Where appropriate in your program, use NewControl or GetNewControl to create any controls you need. NewControl takes descriptive information about the new control from its parameters; GetNewControl gets the information from a control template in a- resource file. When you no longer need a control, call DisposeControl to remove it from its window's control list and release the memory it occupies. To dispose of a~l' of a given window's controls at once, use KillControls. (note) The Window Manager procedures DisposeWindow and CloseWindow automatically dispose of all the controls associated with the given window. When the Toolbox Event Manager function GetNextEvent reports that an update event has occurred for a window, the application should call

5(30/84 Chernicoff-Rose

/CMGR/CONTROLS.2

14

Control Manager Programmer's Guide

DrawControls to redraw the window's controls as part of the process of updating the window. After receiving a mouse-down event from GetNextEvent, do the following: 1. 2. First call FindWindow to determine which part of which window the mouse button was pressed in. If it was in the content region of the active window, next call FindControl for that window to find out whether it was in an active control, and if so, in which part of which control. Finally, take whatever action ·is appropriate when the user presses the mouse button in that part of the control, using routines such as TrackControl (to perform some action repeatedly for as long as the mouse button is down, or to allow the user to drag the control's indicator with the mouse), DragControl (to pull an outline of the control across the screen and move the control to a new location), and HiliteControl (to change the way the control is highlighted).

3.

For the standard control types; step 3 involves calling TrackControl. TrackControl handles the highlighting of the control and determines whether the mouse is still in the control when the mouse button is released. It also handles the dragging of the thumb in a scroll bar and, via your action procedure, the response to presses or clicks in the other parts of a scroll bar. When TrackControl returns the part code for a button, check box, or radio button, the application must do whatever is appropriate as a response to a click of that control. When TrackControl returns the part ~ode for the thumb of a scroll bar, the application must scroll to the corresponding relative position in the document. The application's exact response to mouse activity in a control that retains a setting will depend on the current setting of the control, which is available from the GetCtlValue function. For controls whose values can be set by the user, the SetCtlValue procedure may be called to change the control's setting and redraw the control accordingly. You'll call SetCtlValue, for example, when a check box or radio button is clicked, to change the setting and draw or clear the mark inside the control. Wherever needed in your program, you can call HideControl to make a control invisible or ShowControl to make it visible. Similarly, MoveControl, which simply changes a control's location without pulling around an outline of it, can be called at any time, as 9an SizeControl, which changes its size. For example, when the user changes the size of a document window that contains a scroll bar, you'll call HideControl to remove the old scroll bar, MoveControl and SizeControl to change its location and size, and ShowControl to display it as changed. Whenever necessary, you can read various attributes. of a control with 6etCTitle, GetCtlMin, GetCtlMax, GetCRefCon, or GetCtlAction; you can change them with SetCTitle, SetCtlMin, SetCtlMax, SetCRefCon, or 5/30/84 Chernicoff-Rose /CMGR/CONTROLS.2

CONTROL MANAGER ROUTINES SetCtlAction.

15

CONTROL MANAGER ROUTINES This section describes all the Control Manager procedures and functions. They're presented in their Pascal form; for information on using them from assembly language, see Programming Macintosh Applications in Assembly Language. Initialization and Allocation

FUNCTION NewControl (theWindow: WindowPtr; boundsRect: Rect; title: Str255; visible: BOOLEAN; value: INTEGER; min,max: INTEGER; procID: INTEGER; ref Con: LongInt) : ControlHandle; NewControl creates a control, adds it to the beginning of theWindow's control list, and returns a handle to the new control. The values passed as parameters are stored in the corresponding fields of the control record, as described below. The field that determines highlighting is set to ~ (no highlighting) and the pointer to the default action procedure is set to NIL (none). (note) The control definition function may do additional initialization, including changing any of the fields of the control record. The only standard control for which additional initialization is done is the,scroll bar; its control definition function allocates space for a region to hold the thumb and stores the region handle in the contrlData field of the control record. TheWindow is the window the/new control will belong to. All coordinates pertaining to the control will be interpreted in this window's local coordinate system. BoundsRect, given in theWindow's local coordinates, is the rec~angle that encloses the control and thus determines its size and location. Note the following about the enclosing rectangle for the standard controls: - Simple buttons are drawn to fit the rectangle exactly. (The control definition function calls the QuickDraw pro~edure FrameRoundRect.) To allow for the tallest characters in the system font, there should be at -least a 2~-point difference between the top and bottom coordinates of the rectangle. - For check boxes and radio buttons, there should be at least a 16-point difference between the top and bottom coordinates.

5/30/84 Chernicoff-Rose

/CMGR/CONTROLS.R

16

Control Manager Programmer's Guide - By convention, scroll bars are 16 pixels wide, so there should be a 16-point difference between,the left and right (or top and bottom) coordinates. If there isn~t, the scroll bar will be scaled to fit the rectangle.

Title is the control's title, if any (if none, you can just pass the empty string as the title). Be sure the ,title will fit in the control's enclosing rectangle; if it won't, it will be truncated on the right for check boxes and radio buttons, or centered and truncated on both ends for simple buttons. If the visible parameter is TRUE, NewControl draws the control. (note) It does not use the standard window updating mechanism, but instead draws the control immediately in the window. The min and max parameters define the control's range of possible settings; the value parameter gives the initial setting. For controls that don't retain a setting, such as buttons, the values you supply for these parameters will be stored in the control record but will never be used. So it doesn't matter what values you give for those controls--0 for all three parameters will do. For controls that just retain an on-or-off setting, such as check boxes or radio buttons, min should be (meaning the control is off) and max should be 1 (meaning it's on). For dials, you can specify whatever values are appropriate for min, max, and value.

o

ProcID is the control definition ID, which leads to the control definition function for this type of control. The control definition IDs for the standard control types are listed above under "Controls and Resources". Control definition IDs for custom control types are discussed later under "Defining Your Own Controls". Ref Con is the control's reference value, set and used only by your application. FUNCTION
G~tNewControl

(controIID: INTEGER; theWindow: WindowPtr) ControlHandle;

GetN'ewControl creates a control from a control template stored in a resource file, adds it to the beginning of theWindow's control list, and returns a handle to the new control. ControlID is the resource ID of the template. 'GetNewControl works exactly the same as NewControl (above), except that it gets the initial values for the new control's fields from the specified control template instead of accepting them as parameters. PROCEDURE DisposeControl (theControl: ControIHandle)'; DisposeControl removes theControl from the screen, deletes it frQm its window's control list, and releases the memory occupied by the control 5/30/84 Chernicoff-Rose /CMGR/CONTROLS.R

CONTROL MANAGER ROUTINES record and all data structures associated with the control.

17

Assembly-language note: The macro you invoke. to call DisposeControl from assembly language is named _DisposControl.

PROCEDURE KillControls (theWindow: WindowPtr); KillControls disposes of all controls associated with theWindow by calling DisposeControl (above) for each. Control Display These procedures affect the appearance of a control but not its size or location. PROCEDURE SetCTitle (theControl: ControlHandle; title: Str255); SetCTitle sets theControl's title to the given string and redraws the control. PROCEDURE GetCTitle (theControl: ControlHandle; VAR title: Str255); GetCTitle returns theGontrol's title as the value of the title parameter. PROCEDURE HideControl (theControl: ControlHandle); HideControl makes theControl invisible. It fills the region the· control occupies within its window with the background pattern of the window's grafPort. It also adds the control's enclosing rectangle to the window's update region, so that anything else that was previously obscured by the control will reappear on the screen. If the control is already invisible, HideControl has no effect. PROCEDURE ShowControl (theControl: ControlHandle); ShowControl makes theControl visible. The control is drawn in its window but may be completely or partially obscured by overlapping windows or other objects. If the control is already visible, ShowControl has no effect.

5/30/84 Chernicoff-Rose

/CMGR/CONTROLS.R

18

"Control Manager Programmer's Guide

PROCEDURE DrawControls (theWindow: WindowPtr); DrawControls draws all controls currently visible in theWindow. The controls are drawn in reverse order of creation; thus in case of overlap the earliest-created controls appear frontmost in the window. (note) Window Manager routines such as SelectWindow, ShowWindow, and BringToFront do not automatically call DrawControls to display the window's controls. They just add the appropriate regions to the window's update region, generating an update event. Your program should always call DrawControls explicitly upon receiving an update event for a window that contains controls. PROCEDURE HiliteControl (theControl: ControlHandle; hiliteState: INTEGER) ; HiliteControl changes the way theControl is highlighted. is an int~ger between 0 and 255: - A value of 0 means no highlighting. - A value between 1 and 253 is interpreted as a part code designating the part of the control to be highlighted. - A value of 254 or 255 means that the control is to be made inactive and highlighted accordingly. Usually you'll want to use 254, because it enables you to detect when the mouse button was pressed in the inactive control as opposed to ~ot in any control; for more information, see FindControl under "Mouse Location" below. HiliteControl calls the control definition function to redraw the control with its new highlighting. Mouse Location HiliteState

FUNCTION TestControl (theControl: ControlHandle; thePoint: Point) INTEGER; If theControl is visible and active, TestControl tests which part of the control contains the Point (in 'the local coordinates of the control's window); it returns the corresponding part code, or ~ if the point is outside the control. If the control is visible and inactive with 254 highlighting, TestControl returns 254. If the control is invisible, or inactive with 255 highlighting, TestControl returns 0.

When the Window Manager function FindWindow reports that the mouse button was pressed in the content region of- a window, and the window contains controls, the application should call FindControl with theWindow equal to the window pointer and thePoint equal to the point where the mouse button was pressed (in the window's local coordinates). FindControl tells which of the window's controls, if any, the mouse button was pressed in: If it was pressed in a visible, active control, FindControl sets the whichControl parameter to the control handle and returns a part code identifying the part of the control that it was pressed in. If it was pressed in a visible, inactive control with 254 highlighting, FindControl sets whichControl to the control handle and returns 254 as its result. - If it was pressed in an invisible control, an inactive control with 255 highlighting, or not in any control, FindControl sets whichControl to NIL and returns 0 as its result. (warning) Notice that FindControl expects the mouse point in the window's local coordinates, whereas FindWindow expects it in global coordinates. Always be sure to convert the point to local coordinates with the QuickDraw procedure GlobalToLocal before calling FindControl. (note) FindControl also returns NIL for whichControl and 0 as its result if the window is invisible or doesn't contain the given point. In these cases, however, FindWindow wouldn't have returned this window in the first place, so the situation should never arise. FUNCTION TrackControl (theControl: ControlHandle; startPt: Point; actionProc: ProcPtr) INTEGER; When the mouse button is pressed in a visible, active control, the application s~ould call TrackControl with theControl equal to the control handl~ and startPt equal to the point where the mouse button was pressed (in the local coordinates of the control's window). TrackControl follows the movements of the mouse and responds in whatever way is appropriate until the mouse button is released; the exact response depends on the type of control and the part of the control in which the mouse button was pressed. If highlighting is appropriate, TrackControl does the highlighting, and undoes it beforereturning. When the mouse button is released, TrackControl returns with the part code if the mouse is in the same part of the control that it was originally in, or with 0 if not (in which case" the application 5/30/84 Chernicoff-Rose /CMGR/CONTROLS.R

20

Control Manager Programmer's Guide

should do nothing). If the mouse button was pressed in an indicator, TrackControl drags a gray outline of it to follow the mouse (by calling the Window Manager utility function DragGrayRgn). When the mouse button is released, TrackControl calls the control definition function to reposition the control's indicator. The control definition function for scroll bars responds by redrawing the thumb, calculating ~he control's current setting based on the new relative position of the thumb, and storing the current setting in the control record; for example, if the minimum and maximum settings are 0 and 10, and the thumb is in the middle of the scroll bar, 5 is stored as the current setting. The application must then scroll to the corresponding relative position in the document. TrackControl may take additional actions beyond highlighting the control or dragging the indicator, depending on the value passed in the actionProc parameter, as described below. Here you'll learn what to pass, for the standard control types; for a custom control, what you pass will depend on how the control is defined. - If actionProc is NIL, TrackControl performs no additional actions. This is appropriate for simple buttons, check boxes, radio buttons, and the thumb of a scroll bar. - ActionProc may be a pointer to an action procedure that defines some action to be performed repeatedly for as long as the user holds down the mouse button. (See below for details.) , - If actionProc is POINTER(-1), TrackControl looks in the control record for a pointer to the control's default action procedure. If that fie~d of the control record contains a procedure pointer, TrackControl uses the action procedure it points to; if the field contains POINTER(-1), TrackControl calls the control definition function to perform the necessary action. (If the field contains NIL, TrackControl does nothing.) The action procedure in t~e control definition function is described in the section "Defining Your Own Controls". The following paragraphs describe only the action procedure whose pointer is passed in the actionProc parameter or stored in the control record. If the mouse button was pressed in an indicator, the action procedure (if any) should have no parameters. This procedure must allow for the fact that the mouse may not be inside the original control part~ If the mouse button was pressed in a control part other than an indicator, the acti~n procedure should be of the form PROCEDURE MyAction (theControl: ControlHandle; partCode: INTEGER); In this case, TrackControl passes the control handle and the part code to the action procedure. (It passes 0 in the partCode parameter if the mouse has moved outside the original control part.) As an example of

5/30/84 Chernicoff-Rose

/CMGR/CONTROLS.R

CONTROL MANAGER ROUTINES

21

this type of action procedure, consider what should happen when the mouse button is pressed in a scroll arrow or paging region in a scroll bar. For these cases, your action procedure should examine the part code to determine exactly where the mouse button was pressed, scroll up or down a line or page as appropriate, and call SetCtlValue to change the control's setting and redraw the thumb. (warning) Since it has a different number of parameters depending on whether the mouse button was piessed in an indicator or elsewhere, the action procedure you pass to TrackControl (or whose pointer you store in the control record) can be set up for only one case or the other. If you store a pointer to a default action procedure in a control record, be sure it will be used only when appropriate for that type of action procedure. The only way to specify actions in response to all mouse-down events in a control, regardless of whether they're in an indicator, is via, the control definition function. Control Movement and Sizing

PROCEDURE MoveControl (theControl: ControlHandle; h,v: INTEGER); MoveControl moves theControl to a new location within its window. The top left corner of the control's enclosing rectangle is moved to the horizontal and vertical coordinates h and v (given in the local coordinates of the control's window); the bottom right corner is adjusted accordingly, to keep the size of the rectangle the same as before. If the control is currently visible, it's hidden and then redrawn at its new location. PROCEDURE DragControl (theControl: ControlHandle; startPt: Point; 1 imi tRect, slopRect: Rec t; axis:, INTEGER); Called with the mouse button down inside theControl, DragControl pulls a gray ou'tline 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 the control definition function to allow it to do its own "custom dragging" if it chooses. If the definition function doesn't choose to do any custom dragging, DragControl uses the default method of dragging described here.

5/30/84 Chernicoff-Rose

/CMGR/CONTROLS.R

22

Control Manager Programmer's Guide

DragControl calls the Window Manager utility function DragGrayRgn and then moves the control accordingly. The startPt, limitRect, slopRect, and axis parameters have the same meaning as for DragGrayRgn. These parameters are reviewed briefly below; see the description of DragGrayRgn in the Window Manager manual for more details. - StartPt parameter is assumed to be the point where the mouse button was originally pressed, in the local coordinates of the control's window. - LimitRect limits the travel of, the control's outline, and should normally coincide with or be contained within the window's content region. SlopRect allows the user some "slop" in moving the mouse; it should completely enclose limitRect. - The axis parameter allows you to constrain the control's motion to only'one axis. It has one of the following values: CONST noConstraint hAxisOnly vAxisOnly {no constraint} {horizontal axis only} {vertical axis only}

l

PROCEDURE SizeControl (theControl: ControlHandle; w,h: INTEGER); SizeControl changes the size of theControl's enclosing rectangle. The bottom right corner of the rectangle is adjusted to set the rectangle's width and height to the number of pixels specified by wand h; the position of the top left corner is not changed. If the control is currently visible, it's hidden and then redrawn in its new size. Control Setting and Range

PROCEDURE

S~tCtlValue

(theControl: ControlHandle; theValue: INTEGER);

SetCtlValue sets theCoQtrol's current setting to theValue and redraws the control to reflect the new setting. For check boxes and radio buttons, the value 1 fills the control with the appropriate mark, and clears it. For scroll bars, SetCtlValue redraws the thumb where appropriate. If the specified value is out of range, it's forced to the nearest endpoint of the current range (that is, if theValue is less than the minimum. setting, SetCtlValue sets the current setting to the minimum; if theValue is greater than the maximum setting, it sets the current setting to the maximum).

SetCtlMin sets theControl's minimum setting to minValue and redraws the control to reflect the new range. If the control's,current setting is less than minValue,. the setting is changed to the new minimum.

Assembly-language note: The macro you invoke to call SetCtlMin from assembly language is named SetMinCtl.

The macro you invoke to call GetCtlMin from assembly language is named GetMinCtl.

PROCEDURE SetCtlMax (theControl: ControlHandle; maxValue: INTEGER); SetCtlMax sets theControl's maximum setting to maxValue and redraws the control to reflect the new range. If maxValue is less than the control's current setting, the setting is. changed to the new ~aximum.

Assembly-Ianguage~:

The macro you invoke to call SetCtlMax from assembly language is named SetMaxCtl.

SetCtlAction sets theControl's default action procedure to actionProc. FUNCTION GetCtlAction (theControl: ControlHandle) : ProcPtr; GetCtlAction returns a pointer to theControl's default action procedure, if any. (It returns whatever is in that field of the control record.)

DEFINING YOUR OWN CONTROLS In addition to the standard, built-in control types (buttons, check boxes, radio buttons, and scroll bars), the Control Manager allows you to define "custom" control types of your own. Maybe you need a threeway selector ~witch, a memory-space indicator that looks like a thermomet~r, or a thruster control for a spacecraft simulator--whatever your application calls for. Controls and their indicators may occupy regions of any shape, in the full generality permitted by QuickDraw. To define your own type of control, you write a control definition function and (usually) store it in a resource file. When you create a control, you provide a control definition ID, which leads to the control definition function. The control definition ID is an integer that contains the resource ID of the control definition function in its upper 12 bits and a variation code in its lower four bits. Thus, for a given resource ID and variation code, the control definition ID is: 16

*

resource ID + variation code

For example, buttons, check boxes, a~d radio buttons all use the standard definition function whose resource ID is ~, but they have variati~n codes of ~, 1, and 2, respectively.

5/30/84 Chernicoff-Rose

/CMGR/CONTROLS.D

DEFINING YOUR OWN CONTROLS

25

The Control Manager calls the Resource Manager to access the control definition function with the given resource ID. The Resource Manager reads the control definition function into memory and returns a handle to it. The Control Manager stores this handle in the contrlDefProc field of the control record, along with the variation code in the highorder byte of the field. Later, when it needs to perform a typedependent action on the control, it calls the control definition function and passes it the variation code as a parameter. Figure 5 illustrates this process.

The variation code is passed to the control definition function. Figure 5. Control Definition Handling

Keep in mind that the calls your application makes to use a control depend heavily on the" control defini tion function. What you pass to the TrackControl function, for example, depends on whether the definition function contains an action ptocedure for the control. Just as you need to know how to call TrackControl for the standard controls, each custom control type will have a particular calling protocol that must be followed for the control to work properly. (note) You may find it more convenient to include the control definition function with the code of your program instead of storing it as a separate resource. If you do this, you should supply the control definition ID of any standard control type when you create the control, andspecify that the control initially be invisible. Once the control is created, you can replace the contents of the contrlDefProc field with a handle to the actual control definition function (along with a variation code, if needed, in the high-order byte of the field). You can then call ShowControl to make the control visible.

5/30/84 Chernicoff-Rose

/CMGR/CONTROLS.D

26

'Contro1 Manager Programmer's Guide

The Control Definition Function The control definition 'function may be written in Pascal or assembly language; the only requirement is that its entry point must be at the beginning. You can give your control definition function any name you like. Here's how you would declare one named MyContro1: FUNCTION MyControl (varCode: INTEGER; theContro1: Contro1Hand1e; message: INTEGER; param: LongInt) : LongInt; VarCode is the variation code, as described above. TheContro1 .is a handle to the control that the operation will affect. The message parameter identifies the desired operation. the following values: CONST drawCnt1 = J~; testCnt1 1; ca1cCRgns 2; initCnt1 = 3; dispCnt1 4; posCnt1 5j thumbCnt1'= 6; dragCnt1 7; auto Track 8; It has one of

As described below in the discussions of the routines that perform these operations, the value passed for param, the last parameter of the control definition function, depends on the operation. Where it's not mentioned below, this parameter is ignored. Similarly, the control definition func,tion is expected to return a function result only where indicated; in other cases, the function should return 0. (note) "Routine" here does not necessarily mean a procedure or function. While it's a good idea to set these up as subprograms inside the control definition function, you're not required to do so. The Draw Routine The message drawCnt1 asks the control definition function to draw all or part of the control within its enclosing ·rectang1e. Th~ value of param is a part code specifying which part of the control to draw, or 0 for the entire control. If the control is invisible (that is, if its contr1Vis field is FALSE), there's nothing to do; if it's visible, the definition function should draw it (or the requested part), taking into account the current values of its contr1Hi1ite and contr1Va1ue fields. The control may be either scaled or clipped to the enclosing rectangle.

5/30/84 Chernicoff-Rose

/CMGR/CONTROLs.n

DEFINING YOUR OWN CONTROLS

27

If param is the part code of the control's indicator t the draw routine can assume that the indicator hasn't moved; it might be called t for example t to highlight the indicator. There's a special case t though, in which the draw routine has to allow for the fact that the indicator may have moved: this happens when the Control Manager procedures SetCtlValue t SetCtlMin, and SetCtlMax call the control definition function to redraw the indicator after changing the control setting. Since they have no way of knowing what part code you chose for your indicator t they all pass 128 (the special reserved part code) to mean the indicator. The draw routine must detect this part code as a special case t and remove the indicator from its former location before drawing it. (note) If your control has more than one indicator, 128 should be interpreted to mean all indicators. The Test Routine -The Control Manager function FindControl sends the message testCntl to the control definition function when the mouse button is pressed in a visible control. This message asks in which part of the control, if anYt a given point lies. The point is passed as the value of param t in the local coordinates of the control's window; the vertical coordinate 'is in the high-order word of the Longlnt and the horizontal coordinate is in the low-order word. The control definition function should return the part code for the part of the control that contains the point; it should return 254 if the control is inactive with .254 highlighting, or ~ if the point is outside the control or if the control is inactive with 255 highlighting. The Routine to Calculate Regions The control definition function should respond to the message calcCRgns by calculating the region the control occupies within its window. Param is a QuickDraw region handle; the definition function should update this region to the region occupied by the control, expressed in the local coordinate system of its window. If the high-order bit of param is set t the region requested is that of the control's indicator rather than the control as a whole. The definition function should clear the high byte (not just the high bit) of the region handle before attempting to update the region.

5/30/84 Chernicoff-Rose

/CMGR/CONTROLS.D

28

Control Manager Programmer's Guide

The Initialize Routine After initializing fields as appropriate when creating a new control, the Control Manager sends the message initCntl to the control definition function. This gives the definition function a chance to perform any type-specific initialization it may require. For example, if you implement the control's action procedure in its control definition func~ion, you'll set up the initialize routine to store POINTER(-l) in the contrlAction field; TrackControl calls for this control would pass POINTER(-l) in the actionProc parameter. The control definition function for scroll bars allocates space for a region to hold the scroll bar's thumb and stores the region handle in the contrlData field of the new control record. The initialize routine for standard buttons, check boxes, and. radio buttons does nothing. The Dispose Routine The Control Manager's DisposeControl procedure sends the message dispCntl to the control definition function, telling it to carry out any additional actions required when disposing of the control. For example, the standard definition function for scroll bars releases the space occupied by the thumb region, whose handle is kept in the control's contrlData field. The dispose routine for standard buttons, check boxes, and radio buttons does nothing. The Drag Routine The message dragCntl asks the control definition function to drag the control or its indicator·around on the screen to follow the mouse until the user releases the mouse button. Param specifies whether to drag the indicator or the whole control: ~ means drag the whole control, while a nonzero value means just drag the indicator. The control·definition function need not implement any form of "custom dragging"; if it returns a result of ~, the Control Manager will use its own default method of dragging (calling DragControl to drag the control or the Window Manager function DragGrayRgn to drag its indicator). Conversely, if the control ~definition (unction chooses to do ,its own custom dragging, it should signal the Control Manager not to use the default method ,by returning a nonzero result. If the whole control is being dragged, the definition function should call MoveControl to reposition the control to its new location after the user releases the mouse button. If just the indicator is being dragged, the definition function should execute its own pos{tion routine (see below) to update the control's setting and redraw it in its window.

5/30/84 Chernicoff-Rose

/CMGR/CONTROLS.D

DEFINING YOUR OWN CONTROLS

29

The Position Routine For controls that don't use the Control Manager's default method of dragging the control's indicator (as performed by DragGrayRgn), the control definition function must include a position routine. When the mouse button is released inside the indicator of such a contiol, TrackControl calls the control definition function with the message ~osCntl to reposition the indicator and update the control's setting accordingly. The value of param is a point giving the vertical and horizontal offset, in pixels, by which the indicator is to be moved relative to its,current position. (Typically, this is the offset between the poi~ts where the user pressed and released the mouse button while dragging the indicator.) The vertical offset is given in the high-order ·word of the LongInt and the horizontal offset in the loworder word. The definition function should calculate the control's new setting based on the given offset, update the contrlValue field, and redraw the control within its window to reflect the new setting. (note) The Control Manager procedures SetCtlValue, SetCtlMin, and SetCtlMax do not call the control definition function with this message; instead, they pass the drawCntl message to execute the draw routine (see above) •. The Thumb Routine Like the position routine, the thumb routine is required only for controls that don't use the Control Manager's default method of dragging the control's indicator. The control definition function for such a control should respond to the message thumbCntl by calculating the limiting rectangle, slop rectangle, and axis constraint for dragging the control's indicator. Param is a pointer to the following data structure: RECORD limitRect, slopRect: Rect; axis: INTEGER END; On entry, paramA.limitRect.topLeft contains the point where the mouse button was first pressed. The definition function should store the appropriate values into the fields of the record pointed to by param; they're analogous to the similarly named parameters to DragGrayRgn.

5/30/84 Chernicoff-Rose

/CMGR/CONTROLS.D

30

Control Manager Programmer's Guide

The Track Routine You can design a control to have its action procedure in the control definition function. To do this, set up the control's initialize routine to store POINTER(-I) in the contrlAction field of the control record, and pass POINTER(-I) in the actionProc parameter to TrackControl. TrackControl will respond by calling the control definition function with the message autoTrack. The definition function sho~ld respond like an action procedure, as discussed in detail in the description of TrackControl. It can tell which part of the control the mouse button was pressed in from param" which contains the part code. The 'track routine for each of the standard control types does 'nothing.

FORMATS OF RESOURCES FOR CONTROLSThe GetNewControl function takes the resource ID of a control template as a parameter, and gets from that template the same information that the NewControl function gets from eight of its parameters. The resource type for a control template is 'CNTL', and the resource data has the following format: Number of bytes 8 bytes 2 bytes . 2 bytes 2 bytes 2 bytes 4 bytes 4 bytes n bytes Contents Same as boundsRect parameter to NewControl Same as value parameter to NewControl Same as visible parameter to NewControl Same as max parameter to NewControl Same as min parameter to NewControl Same as procID parameter to NewControl Same as ref Con parameter to NewControl Same as title parameter to NewControl (I-byte length in bytes, followed by the characters of the title)
~

The resource type for a control definition function is 'CDEF'. The resource data is simply the compiled or assembled code'of the function.

GLOSSARY action procedure: A procedure, used by the Control Manager function TrackControl, that defines an action to be performed repeatedly for as long as the mouse button is held down. active control: the mouse. A control that will respond to the user's actions with

button: A standard Macintosh control that causes some immediate or continuous action when clicked or pressed with the mouse. (See also: radio button) check box: A standard Macintosh control that displays a setting, either checked (on) or unchecked (off). Clicking inside a check box reverses its setting. control: An object in a window on the Macintosh screen with which the user, using the mouse, can cause instant action with graphic results or change settings to modify a future action. control definition function: A function called by the Control Manager when it needs to perform type-dependent operations on a particular type of control, such as drawing the control. control definition ID: A number passed to control-creation routines to indicate' the type of control. It consists of the control definition function's resource ID and a variation code. control list: window. A list of all the controls associated with a given

control record: The internal representation of a control, where the Control Manager stores all the information it needs for its operations on that control. control template: A resource that contains information from which the Control Manager can create a control. dial: A control with a moving indicator that displays a quantitative setting or value. Depending on the type of dial, the user mayor may not be able to change the ,setting by dragging the indicator with the mouse. dimmed: Drawn in gray rather than black.

inactive control: A control that will not respond to the user's actions with the mouse. An inactive control is high~ighted in some special way, such as dimmed. indicator: The moving part of a dial that displays its current setting. The part code of an indicator is always greater than 128 by convention. 5/30/84 Chernicoff-Rose /CMGR/CONTROLS.G

GLOSSARY invert:

37

To highlight by changing white pixels to black and vice versa. A control that's not drawn in its window.

invisible control:

part code: An integer between 1 and 253 that stands for a particular part of a control (possibly the entire control). Part codes greater than 128 represent indicators. radio button: A standard Macintosh control that displays a setting, either on or off, and is part of a group in which only one button can be on at a time. Clicking a radio button on turns off all the others in the group, like the buttons on a car radio. reference value: In a window record or control record, a 32-bit field that the application program may store into and access for any purpose. thumb: The Control Manager's term for the scroll box (the indicator of a scroll bar). variation code: The part of a window or control definition ID that distinguishes closely related types of windows or controls. visible control: A control that's drawn in its window (but may be completely overlapped by another window or other object on the screen).

Menus free the user from having to remember long strings of command words. The menu bar and pull-down menus let the user see all available menu- choices at any time. This manual describes the nature of pull-down menus and how to implement them with the Macintosh Menu Manager. Summary of significant changes and additions since last draft: - For menus stored in resource files t the menu ID isn't necessarily the resource ID (though the Resource Compiler sets the menu ID to the resource ID) (page 8). - Two new constants have been defined for symbols to mark menu items (the Command key symbol and a diamond symbol), and the constant appleSymbol has been changed to appleMark (page 12). - If no item is chosen from a menu, only the high-order word of the long integer returned by MenuSelect or MenuKey is 0; the low-order word is undefined. - Important changes have been made to "Defining Your Own Menus" (page 27).

ABOUT THIS MANUAL This manual describes the Menu Manager, a major component of the Macintosh User Interface Toolbox •••• Eventually it will become-part of the comprehensive Inside Macintosh manual. ••• The Menu Manager allows you to create sets of menus, and allows the user to choose from the commands in those menus in a manner consistent wfth the Macintosh User Interface guidelines. Like all Toolbox documentation, this manual assumes you're familiar with Lisa Pascal and the information in the following manuals: - Inside Macintosh: - Macintosh
~

A Road Map

Interface Guidelines
An Introduction

- Macintosh Memory Management:

- Programming Macintosh Applications in Assembly Language, if you're using assembly language You should also be familiar with: - Resources, as described in the Resource Manager manual. - The basic concepts and structures behind QuickDraw, particularly points, rectangles, and character style. - The Toolbox Event Manager. Some Menu Manager routines should be called only in response to certain events.

ABOUT THE MENU MANAGER The Menu Manager supports the use of menus, an integral part of the Macintosh user interface. Menus allow users to examine all choices available to them at any time without being -forced to choose one of them, and without having to remember command words or special keys. The Macintosh user simply positions the cursor.in the menu bar. and presses the mouse button over a menu title. The application then calls the Menu Manager, which highlights that title (by inverting it) and "pulls down" the menu below it. As long as the mouse button is held down, the menu is displayed. Dragging through the menu causes each of the menu items to be highlighted in turn. If the mouse button is released over an item, that item is "chosen". The item blinks briefly to confirm the choice, and the menu disappears. When the user chooses an item, the Menu Manager ,tells the application which item was chosen, and t~e application performs the corresponding action. When the application completes the action, it removes the highlighting from the menu title, indicating to the user that the operation is complete. ~ 9/24/84 Rose-Withey /MMGR/MENUS.2

4

Menu Manager Programmer's Guide

If the user moves the cursor out of the menu with the mouse button held down, the menu remains 'visible, though no menu items are highlighted. If the mouse button is released outside the menu, no choice is made: the menu just disappears and the application takes no action. The user can always look at a menu without causing any changes in the document or on the screen. The Menu Bar The menu bar always appears at the top of the Macintosh 8cre'en; nothing but the cur_sor ever appears in front of it,. The menu bar i.s white, 20 pixels high, and as wide as the screen, with a thin black lower border. The menu titles in it are always in the system font and the system font size (see Figure 1).

titles of
eneb led menJS

title of It disabled meru

Figure 1.

The Menu Bar

In applications 'that support desk accessories, the first menu should be the standard Apple menu (the menu whose title is an apple symbol). The Apple menu contains the names of all available desk accessories.. When the user chooses a desk accessory from the menu, the title of a menu belonging to the desk accessory may appear in the menu bar, for as long as the accessory is active, or the entire menu bar 'may be replaced by menus belonging to the desk accessory. (Desk accessories are discussed in detail in the Desk Manager manual.) A menu may be temporarily disabled, so that none of the items in it can be chosen. A Aisabled menu can still be' pulled down, but its title and all the items in it are dimmed. The maximum number of menu titles in the menu bar is 16; however, ten to twelve titles are usually all that will fit. If you're having trouble fitting your menus in the menu bar, you should review your menu organization and menu titles.

9/24/84 Rose-Withey

/l-n-lGR/MENUS.2

ABOUT THE MENU MANAGER

5

Appearance of Menus A standard menu consists of a number of menu items listed vertically inside a shadowed rectangle. A menu item may be the text of a command, or just a line dividing groups of choices (see Figure 2). An ellipsis ( ••• ) following the text of an item indicates that selecting the item will bring up a dialog box to get further information before the command is executed. Menus always appear in front of everything else (except the cursor); in Fig.ure 2, the menu appears in front of a document window already on the screen.

meru with

8 rnerMJ

items (including 2 dividing lines)

vWord Wrap
Figure 2. A Standard Menu

The text of a menu item always appears in the system font and the system font size. Each item can have a few visual variations from the standard appearance:
- An

icon to the left of the item's text, to give a symbolic representation of the item's meaning or effect.

- A check mark or other character to the left of the item's text (or icon, if any), to denote the status of the item or of the mode it controls. - The Command key symbol and another character to the right of the item's text, to show that the item may be invoked from the keyboard (that is, it has a keyboard equivalent). Pressing this key while holding down the Command key invokes the item just as if it had been chosen from the menu (see "Keyboard Equivalents for . Command s" below). - A character style other than the standard, such as bold,. italic, underline, or a combination of these. (The QuickDraw manual gives a full discussion of character style.) - A dimmed appearance, to indicate that the item is disabled, and can't be chosen. The Cut, Copy, and Clear commands in Figure 2 are disabled; dividing lines are always disabled.

9/24/84 Rose-Withey

/MMGR/MENuS.2

6

Menu Manager Programmer's Guide

(note) Special symbols or icons may have an unusual appearance when dimmed; notice the dimmed Command symbol in the Cut and Copy menu items in Figure 2. The maximum number of menu items that will fit in a standard menu is 20 (less 1 for each item that contains an icon). The fewer menu items you have, the simpler and clearer the menu appears to the user. If the standard menu doesn't suit your needs (for example, if you want more graphics or perhaps a nonlinear text arrangement), you can define a custom menu that, although visibly different to the user, responds to your application "s Menu Manager calls just like a standard menu.
I

Keyboard Equivalents for Commands Your program can set up a keyboard equivalent for any of its menu commands so the command can be invoked from the keyboard. The character you specify for a keyboard equivalent will usually be a letter. The user can type the letter in either uppercase or lowercase. For ~xample, typ.ing. either "c" or "c" while holding down the Command key invokes the command whose equivalent is "C". I (note) For consistency between applications, you should specify the letter in uppercase in the menu. You can specify characters other than letters for keyboard equivalents. However, the Shift key will be ignored when the equivalent is typed, so you shouldn't specify shifted characters. For example, when the user types Command-Shift-+, the system reads it as Command-Shift--. Command-Shift-number combinations are not keyboard equivalents. They're detected and handled by the Toolbox Event Manager function GetNextEvent, and are never returned to your program. (This is how disk ejection with Command-Shift-l or 2 is implemented.) Although it's possible to use unshifted, Command-number combinations as keyboard equivalents, you shouldn't do so, to avoid confusion. *** (CommandShift-number will be documented in the next draft of the· Toolbox Event Manager manual.) *** (warning) You must use the standard keyboard equivalents Z, X, C, and V for the editing commands Undo, Cut, Copy, and Paste, or editing won't work correctly in desk accessories.

9/24/84 Rose-Withey

/MMGR/MENUS.2

HENUS AND RESOURCES

7

MENUS AND RESOURCES

The general appearance and behavior of, a menu is determined by a routine called its ~ definition procedure, which is usually stored as a resource in a resource file. The menu definition procedure performs all actions that differ from o~e men~ type to another, such as drawing the menu. The Menu Manager calls the menu definition procedure whenever it needs to perform one of these basic actions, passing it a message that tells which action to perform. The standard menu definition procedure is part of the system resource file. It lists the menu items vertically, and each item may have an icon, a check mark or other symbol, a keyboard equivalent, a different character style, or a dimmed appearance. If y~u want to define your own, nonstandard menu types, you'll have to write your own menu definition procedure for them, as described later in the section "Defining Your Own Menus". You can also use a resource file to store the contents of your application's menus. This allows the menus to be edited or translated to foreign languages without affecting the application's source code. The ,Menu Manager lets.you read complete menu bars as well as individual menus from a resource file. Even if you don't store entire menus in resource file8~ it's a good idea to store the text striqgs they contain as_resources; you can call the Resource Manager directly to read them in. Icons in menus are read from resource files; the Menu Manager calls the Resource Ma~ager to read in the icons. (note) You can create menu-related resources and store them in resource files with the aid of the Resource Editor *** eventually (for now, the Respurce Compiler) ***. The Resource Editor relieves you of having to know the exact formats of these resources in the file, but for interested programmers this information is given in the section "Formats of Resources for Menus". There's a Menu Manager procedure that scans all open resource files for resources of a given type and installs the names of all available resources of that type into a given menu. This is how you fill a menu with the names of all available desk accessories or fonts, for example.

9/24/84 Rose-Withey

/MHGR/MENUS.2

8

Menu Manager Programmer's Guide

HENU RECORDS

The Menu Manager keeps all the information it needs for its operations on a particular menu in a ~,record. The menu record contains the following: - The menu ID, a number that identifies the menu. The menu ID can be the sa;; number as the menu's resource ID,lthough it doesn't have to be. - The menu title. - The contents of the menu--the text and other parts of each item. - The horizontal and vertical dimensions of the menu, in pixels. The menu items appear inside the rectangle formed by these dimensions; the black border and shadow of the menu appear 'outside that rectangle.

- A handle to the menu definition procedure •
.:. Flags telling whe,ther each menu item is enabled or disabled, and whether the menu itself is enabled or disabled. The data type for a menu record is called Menu Info. referred to by a handle: TYPE MenuPtr - iMenuInfo; MenuHandle - iMenuPtr; You can store into and access all the necessary fields of with Menu Manager routines, so normally you don't have to exact field names.. However, if you want more informatdon exact structure of a menu record--if you're defining your types, for instance--it's given below. The Me'nuInfo Data Type The type MenuInfo is defined as follows: 'lYPE; MenuInfo • RECORD menuID: menuWidth: menuHeight: menuProc: enableFlags: menuData: a mens record know the about the own menu

A menu record is

INTEGER; INTEGER; INTEGER;
Handle;

{menu {menu {menu ,{menu

ID} width in pixels} height in pixels} definition procedure}

LONGINT;
{tells if menu or items are enabled} {menu title (and other data)} Str255

END;

9/24/84 Rose-Withey

/MMGR/MENUS.2

MENU RECORDS

9

The menuID field contains the menu ID. MenuWidth and menuHeight are the menu's horizontal and, vertical dimensions in pixels. MenuProc is a handle to the menu definition procedure for this type of menu. Bit 0 of the enableFlags field is 1 if the menu is enabled, or 0 if it's disabled. ,Bits 1 to 31 similarly tell whether each item in the menu is enabled or disabled. The menuData field contains the menu title followed by variable-length data that defines the text and other parts of the menu items. The Str255 data type enables you to access the title from Pascal; there's actually additional data beyond the title that's inaccessible from Pascal and is not reflected in the Menulnfo data structure. (warning) You can read the menu title directly from the menuData field, but do not change the title directly, or the da~a defining the menu items be destroyed.

mar

The global constant me~uBlkSize equals the length in bytes- of all the f'felds of a menu record except menuData.
Assembly-language~:

MENU LISTS

A menu list contains handles to one or more menus, along with information about the position of each menu in the menu bar. The current menu list contains handles to all the menus currently in the menu bar; the menu bar shows the titles, in order, of all menus in the menu list. When you initialize the Menu Manager, it allocates space for the maximum size menu list. The Menu Manager provid,es all the necessary routines for manipulating the current menu list, so there's no need to access it directly yourself. As a general rule, routines that deal specifically with menus in the menu list use the menu ID to refer to menus; those that deal with any menus, whether in the menu list or not, use the menu handle to refer to menus. Some routines refer to the menu list as a whole, with a handle.

9/24/84 Rose-Withey

/HMGR/MENUS.2

10

Menu Manager Programmer's Guide

Assembly-Ianguage~: The global variable MenuList contains a handle to the current menu list. The menu list has the format shown below.

Number of bytes 2 bytes
2 bytes 2 bytes

Contents' Offset from beginning of menu list to last menu handle (the number of menus in the list times 6) Horizontal coordinate of right edge of menu title of last menu in list Not used Menu handle Horizontal coord~nate of left edge of menu

For each menu: 4 bytes 2 bytes

)

CREATING A MENU IN YOUR PROGRAM The best way to create your application's menus is to set them up as resources and read them in from a resource file. If you want your application to create the menus itself, though, it must call the NewMenu and AppendMenu routines. NewMenu creates a new menu.data structure, returning a handle to it • . AppendMenu takes a string and a handle to a menu and adds the items in the string to the end of the menu. The string passed to AppendMenu consists mainly of the text of the menu items. For a dividing line, use one hyphen (-); AppendMenu ignores any following characters, and draws a continuous line across the width of the menu. For a blank item, use one or more spaces. Other characters interspersed in the string have special meaning to the Menu Manager. These characters, called meta-characters, are used in conjunction with text to separate menu items or alter their appearance. The metacharacters aren't displayed in the menu.
~

Meta-character ; or Return

<
/
(

Meaning Separates items Item has an icon Item has a check or other mark Item has a special character style Item has a keyboard equivalent Item is disabled

None, any, or all of these meta-characters can appear in the AppendMenu string; they're described in detail below. To add one text-only item to a menu would require a simple string without any meta-characters:

9/24/84 Rose-Withey

/MMGR/MENUS.2

CREATING A MENU IN YOUR PROGRAM AppendMenu(thisMenu,'Just Enough')
An

11

extreme example could use many meta-characters: AppendMenu(thisMenu,'(Too MuchAl(B/T')

This example adds to the menu an item whose text is "Too Much", which is disabled, has icon number 1, is boldfaced, and can be invoked by Command-T. Your menu items shoula be much simpler than this. (note) If you want ~ny of the meta-characters to appear in the text of a menu item, you can include them by changing the text. with the Menu Manager procedure Setltem. Multiple Items Each call to AppendMenu can add one or many items to the menu. To add multiple items in the same call, use a semicolon (;) or a Return character to separate the items. The call
AppendMenu(thisMenu~'Cut;Copy!).

has exactly the same effect as the calls AppendMenu(thisMenu,'Cut'); AppendMenu(thisMenu,'Copy')

Items with Icons

A circumflex (A) followed by a digit from 1 to 9 indicates that an icon should appear to the left of the text in ~he menu. The digit, called the icon number, yields the resource ID of the icon in the resource file:--Icon resource IDs 257 through 511 are reserved for menu icons; thus the Menu Manager adds 256 to the icon number to get the proper resource ID.
(note) The Menu Manager gets the icon number by subtracting 48 from the ASCII code of the character following the itA" (since, for example, the ASCII code of "I" is 49). You can actually follow the itA" with any character that has an ASCII code greater than 48. You can also use the SetItemIcon procedure to install icons in a it accepts any icon number from 1 to 255.
menu;~

9/24/84 Rose-Withey

/MMGR/MENUS.2

12

Menu Manager Programmer's Guide

For example, suppose you want to use AppendMenu to specify a menu item that has the text "Word Wrap" (nine characters) and a check mark to its left. You can declare the string variable

Character Style of Items The system font is the only font available for menus; however, you can vary the character style for clarity and distinction. The meta-character used to specify the character style is the left angle bracket, "(". With AppendMenu. you can assign one and only one of the stylistic variations listed below.
(B

<I <U <0 (S

Bold Italic Underline Outline Shadow

The SetitemStyle procedure allows you to assign any character style to an item. For a further discussion of character style, see the QuickDraw manual. Items with Keyboard EqUivalents Any menu item that can be chosen from a menu may also be associated with a key on the keyboard. Pressing this key while holding down the Command key invokes the item just as if it had been chosen from the menu. A slash (tt/") followed by a character associates that character with the item. The specified character (preceded by the Command key symbol) appears at the right of the item's text in the menu. For consistency between applications, the character should be uppercase if it's a letter. When invoking the item, the user can type tpe letter in either uppercase or lowercase. For example, if you specify 'Copy/ct. the Copy command can be invoked by holding down the Command key and typing either C or c.

An application that receives a key down event with the Command key held down can call the Menu Manager with the typed character and receive the menu ID and item number of the item associated with that character.

11/1/83 Espinosa-Rose

/HMGR/MENUS.2

CREATING A MENU IN YOUR PROGRAM

13

The SetItemStyle procedure allows' you to assign any combination of stylistic variations to an item. For a further discussion of character style, see the OuickDraw manual. Items with Keyboard Equivalents A slash (I) followed by a character associates that character ~ith the item, allOtiing the item to be invoked from the keyboard with the Command key. The specified character (preceded by the-Command key symbol) appears at the right of the item's text in the menu. (note) Remember to specify the character in uppercase if it's a letter, and not to, specify other shifted characters or numbers. Given a keyboard equivalent typed by the user, you call the MenuKey function to find out what menu item was invoked. Disabled Items The meta-character that disables an item is the left parenthesis, "(". A disabled item cannot be chosen; it appears dimmed in the menu and 1s not highlighted when the cursor moves over it. Menu items that are used to ,separate groups of items (such as a line or a blank item) should always be disabled. For example, the call AppendMenu(thisMenu,'Undo;(-;Cut') adds two enabled menu items, Undo and Cut, with a disabled item consisting of a line between them. You can' change the enabled or disabled state of a menu item with the DisableItem and EnableItem procedures.

USING THE MENU MANAGER This section discusses how the Menu Manager routines fit into the general flow of an application program, and gives you an idea of which routines you'll need to use. The routines themselves are described in detail in the next section. To use the Menu Manager, you must have previously called InitGraf to initialize QuickDraw, InitFonts to initialize the Font Manager, and InitWindows to initialize the Window Manager. The first Menu Manager routine to call is the initialization procedure InitMenus.

9/24/84 Rose-Hithey

1MMGRI MENU s •2

14

Menu Manager Programmer's Guide

Your application can set up the menus it needs in any number of ways: - Read an entire prepared menu list from a resource file with GetNewMBar, and place it in the menu bar with SetMenuBar. - Read the menus individually from a resource file using GetMenu, and place them in the menu-bar using,InsertMenu. - Allocate the menus with NewMenu, fill them with items using AppendMenu, ~nd place them in the menu bar using InsertMenu. - Allocate a menu with NewMenu, fill it with items using AddResMenu to get the namp.s of all available resources of a given type, and place the menu in the menu bar using InsertMenu. You can use AddResMenu or InsertResMenu to add items from resource files to any menu, regardless of how you created the menu or whether it already contains any items. When you no longer need a menu, call the Resource Manager procedure Re1easeResource if you read the menu from a resource file, or DisposeMenu if you allocated it with NewMenu. If you call Ne~nu to allocate a menu, it will store a handle to the standard menu definition procedure in the menu record, so if you want . the menu to be one you've designed, you must replace that handle with a handle to your own menu definition procedure. For more information, ~ee "Defining Your Own Menus". After setting up the menu bar, you procedure.
n~ed

to draw it with the DrawMenuBar

At any time you can change or examine a menu item's text with the Setltem and Getltem procedures, or its icon, style, or mark with the procedures SetItemIcon, GetItemIcon, SetItemSty1e, GetItemSty1e, Checkltem, Set ItemMark , and GetItemMark. Individual items or whole menus can be enabled or disabled with the EnableItem and Disab1eItem procedures. You can change the number of menus in the menu list with InsertMenu or De1eteMenu, remove all the menus with C1earMenuBar, or change the entire menu list with GetNewMBar or GetMenuBar followed by SetMenuBar. When your application receives a mouse-down event, and the Window Man~ger's FindWindow function returns the predefined constant inMenuBar, your application should call the Menu Manager's MenuSe1ect function, supplying it with the point where the mouse button was pressed. MenuSe1ect will pull down the appropriate menu, and retain contro1--tracking the mouse, highlighting menu items, and pulling down other menus--unti1 the user releases the mouse button. MenuSe1ect returns a long integer to the appiication: the high-order word contains the menu ID of the menu that was chosen, and the low-order word contains the menu item number of the item that was chosen. The menu item number is the index, starting from 1, of the item in the

9/24/84 Rose-Withey

/MMGR/MENUS.2

USING THE tfENU MANAGER menu. If no item was chosen, the high-order word of the long integer is 0, and the low-order word is undefined. - If the high-order word of the long integer returned is 0, the application should just continue to poll for further events.

15

- If the high-order word is nonzero, the application should invoke the menu item specified by the low-order word, in the menu specified by the high-order word. Only after the action is completely finished (after all dialogs, alerts, or screen actions have been taken care of) should the application remove the highlighting from the menu bar by calling HiliteMenu(0), signaling the completion of the action. Keyboard equivalents are handled in much the same manner. When your application receives a key-down event with the Command key held down, it should call the MenuKey function, supplying it with the character that was typed. MenuKey will return a long integer with the same format as that of MenuSelect, and the application can handle the long integer in the manner described above. Applications should respond the same way to auto-key events as to key-down events when the Command key is held down.if the command being invoked is repeatable. (note) You can use the Toolbox Utility routines LoWord and HiWord to extract the high-order and low-order words of a given long integer, as described in the Toolbox Utilities manual. There are several miscellaneous Menu Manager routines that you normally won't need to use. CalcMenuSize calculates the dimensions of a menu. CountMltems counts the number of items in a menu. Get.MHandle returns the handle of a menu in the menu list. FlashMenuBar inverts the menu bar. SetMenuFlash controls the number of times a menu item blinks when it's chosen.

MENU MANAGER ROUTINES

Initialization and Allocation

PROCEDURE InitMenus; InitMenus initializes the Menu Manager. It allocates space for the menu list (a relocatable block on the heap large enough for the maximum size menu list), and draws the (empty) menu bar. Call InitMenus once before all other Menu Manager routines. An application should never have to call this procedure more than once; to start afresh with all new menus, use ClearMenuBar.

9/24/84 Rose-Withey

/MMGR/MENUS. R

16 (note)

Menu Manager Programmer's Guide

The Window Manager initialization procedure InitWindows has already drawn' the empty menu barj InitMenus redraws it. FUNCTION NewMenu (menuID: INTEGERj menuTitle: Str255) : MenuHandle; NewMenu allocates space for a new menu with the given menu ID and title, and returns a handle to it. It sets up the menu to use the standard menu definition procedure. The new menu (which is created empty) is not installed in the menu list. To use this menu, you must first call AppendMenu or AddResMenu to fill it with items, InsertMenu to place it in the 'menu list, and DrawMenuBar to update the menu bar to include the new title. Application menus should always have positive menu IDs. Negative menu IDs are reserved for menus belonging to desk accessories. No menu should ever have a menu ID of 0. If you want to set up the title of the Apple menu from your program instead of reading it in from a resource file, you can use the predefined constant appleMark (equal to $14, the value of the apple symbol). For example, you can declare the string variable VAR myTitle: STRING[1]; and do the following: myTitle := ' '; myTitle[1] := CHR(appleMark) To release the memory occupied by a menu that you created with NewMenu, call DisposeMenu. FUNCTION
GetMe~u

(resourceID: INTEGER) : MenuHandle;

GetMenu returns a menu handle for the menu having the given resource ID. It calls the Resource Manager to read the menu from the resource file into a menu record in memory. It stores the handle to the menu defi~ition procedure in the menu record, reading the procedure from the resource file into memory if necessary. To use this menu, you must call InsertMenu to place it in the menu list and DrawMenuBar to upd,ate the menu bar to include the new title. (warning) Only call GetMenu once for a particular menu. If you need the menu handle to a menu that's already in memory, use the Resource Manager function GetResource. To release the memory occupied by a menu that you read from a resource file with GetMenu, use ,the Resource Manager procedure ReleaseResource.

9/24/84 Rose-Withey

/MMGR/MENUS. R

MENU MANAGER ROUTINES

17

Assembly-Ianguage~:

The macro you ,invoke to call GetMenu from assembly language is named _GetRHenu •

. PROCEDURE DisposeHenu (theMenu: HenuHandle); Call DisposeHenu to release the memory occupied by a menu that you allocated with NewMenu. (For menus read from a resource file with GetMenu, use the Resource Manager procedure ReleaseResource instead.) This is useful if you've created temporary menus that you no longer need. (warning) Make sure you remove the menu from the menu list (with DeleteMenu) before disposing of it. Also be careful not to use the menu handle after disposing of the menu.

Assembly-Ianguage~:

The macro you invoke to call DisposeMenu from assembly language is named _DlsposMenu.

F~rmlng

the Menus

PROCEDURE AppendMenu (theMenu: MenuHandle; data: Str255); AppendMenu adds an item or items to the end of the given menu, which must previously have been allocated by NewMenu or read from a resource file by GetMenu. The data string consists of the text of the menu item; it may be blank but should not be the null string. If it begins with a hyphen (-), the item will be- a dividing line across the width of the menu. As described in the section "Creating a Menu in Your Program", the following meta-characters may be embedded in the data string:

9/24/84 Rose-Withey

/MMGR/MENUS. R

18

Menu Manager Programmer's Guide Meta-character ; or Return
A

<
/
{

Usage Separates multiple items Followed by an icon number, adds that icon to the item Followed by a character, marks the· item-with that character Followed by B, I, U, 0, or S, sets the character style of the item Followed by a character, associates a keyboard equivalent with the item Disables the item

Once items have been appended to a menu, they cannot be removed or rearranged. AppendMenu works properly whether or not the menu is in the menu list. PROCEDURE AddResMenu (theMenu: MenuHandle; theType: ResType); AddResMenu searches all open resource files for resources of type theType and appends the names of all resources it finds' to the given menu. Each resource name appears in the menu as an enabled item, without an icon or mark, and in the normal character style~ The standard Menu Manager calls can be used to get the name or change its appearance, as described below under "Controlling Items" Appe~rance". (note) So that you can have resources of the given type that won't appear in the menu, any resource names that begin with a period (.) or a percent sign (%) aren't appended by AddResMenu. Use this procedure to fill a menu with the names of all available fonts or desk accessories. For example, if you declare a variable as VAR fontMenu: MenuHandle; you can set up a menu containing all font names as follows: fontMenu := NewMenu{5, 'Fonts'); AddResMenu(fontMenu, 'FONT')

PROCEDURE InsertResMenu (theMenu: MenuHandle; theType: ResType; afterI~em: INTEGER); InsertResMenu is_ the same as AddResMenu (above) except that it inserts the resource names in the menu where specified by the afterItem parameter: if afterltem is 0, the names are inserted before the first menu item; if it's the item number of an item in the menu, they're inserted after that item; if it's equal to or greater than the last item number, they're appended to the menu.

9/24/84

Ros~-Withey

/MMGR/MENUS.R

MENU MANAGER ROUTINES (note) InsertResMenu inserts the names in the reverse of the order that AddResMenu appends them. For consistency between applications in the appearance of menus. use AddResMenu instead of InsertResMenu if posslble. Forming the Menu Bar

19

PROCEDURE InsertMenu (theMenu: MenuHandle; beforeID: INTEGER); InsertMenu inse~ts a menu into the menu list before the menu whose menu ID equals beforeID. If beforeID Is 0 (or Isn't the ID of any menu in the menu list). the new menu is added after all others. If the menu is already in the menu list or the menu list is already full. InsertMenu does nothing. Be sure to call DrawMenuBar to update the menu bar. PROCEDURE DrawMenuBar; DrawMenuBar redraws the menu bar accord-ing to the'" menu list. incorporating any changes since the last call to DrawMenuBar. Any highlighted menu ,title remains highlighted when drawn by DrawMenuBar. This procedure should always be called after a sequence of InsertMenu or DeleteMenu calls. and· after ClearMenuBar'. SetMenuBar. or any other routine that changes the menu list. PROCEDURE DeleteMenu (menuID: INTEGER); DeleteMenu deletes a menu from the menu list. If there's no menu with the given menu ID in the menu list. DeleteMenu has no effect. Be sure to call DrawMenuBar to update the menu bar; the menu titles following the deleted menu will move over to fill the vacancy. (note) DeleteMenu simply removes the menu from the list of currently available menus; it doesn't release the memory occupied by the menu data structure. PROCEDURE ClearMenuBar; Call ClearMenuBar to remove all menus from the menu list when you want to start afresh with all new menus. Be sure to call DrawMenuBar to update the menu bar. (note) ClearMenuBar, like DeleteMenu, doesn't release the memory occupied by the menu data structures; it merely removes them from the menu list.

9/24/84. Rose-Withey

/MMGR/MENUS. R

20

Menu Manager Programmer's Guide

You d'on't have to call ClearMenuBar at the beginning of your program, because In1 tMenus clears the menu list fo'r you. FUNCTION GetNewMBar
(~enuBarIO:

INTEGER) : Handle;

GetNewMBar creates a menu list as defined by the menu bar resource having the given resource 10, and returns s handle to it. If the resource isn't already in memory, GetNewMBar reads it .into memory from the resource file •. It calls GetMenu to get each of the individual menus. To make the menu list created by GetNewMBar the current menu list, call SetMenuBar. To release the memory o~cupied by the menu list, use the Memory Manager procedure OisposHandle. (warning) You don't have to know the individual menu IDs to use GetNewMBar, but that doesn't mean you don't have to know them at all: to do anything further with's particular menu~ you have to know its 10 or its handle (which you can get by passing the 10 to GetHHandle, as described below under "Miscellaneous Routines"). FUNCTION GetMenuBar : Handle; GetMenuBar cteates a copy of the current menu list and returns a handle to ,the copy. You can then add or remove menus from the menu list (with InsertMenu, DeleteMenu, or ClearMenuBar), and later restore the saved menu list with SetMenuBar. To release the memory occupied b'y the saved menu list, use the Memory Manager procedure OisposHandle •. (warning) GetMenuBar doesn't copy the menus themselves, only a list containing their handles. Do not dispose of any menus ' that might be in a saved menu list. PROCEDURE SetMenuBar (menuList: Handle); SetMenuBar copies the given menu list to the current menu list. You can use this procedure to restore a menu list previously saved by GetMenuBar, or pass it a handle returned by GetNewMBar. Be sure to call DrawMenuBar to update the menu bar.

9/24/84 Rose-Withey

/MMGR/MENUS.R

MENU MANAGER ROUTINES

21

Choosing From a MenU'

FUNCT~ON

MenuSelect (startPt: Point) : LONGINT;

When there's a mouse-down event in the menu bar, the application should call MenuSelect with startPt equal to the point (in global coordinates) where the mouse button was pressed. MenuSelect keeps control until the mouse button is released, tracking the mouse, pulling down menus as needed, and highligh.ting enabled menu items under the cursor. When the mouse button is released over an enabled item in an application menu, MenuSelect returns a long integer whose high-order word is the menu ID of the menu, and whose low-order word is the menu item number for the item chosen (see Figure 3). It leaves the selected menu title highlighted. After performing the chosen task, your applIcation should call HiliteMenu(0) to remove the highlighting from the menu titl~.

menu IDS
128 1.29 130

•

File
1 2 3
4

..

~------------~------------------------

131

menu
item
runbers

S 6 7 8

rnouseP1 is where the CU"SOf is pointing
~ord

Wrap

Menu5elect(mousePt) or MenuKey('V') returns:

I

130
high-order word
Figure 3.

I

5
low-order word

MenuSelect and MenuKey

If no choice is made, MenuSelect returns 0 in the high-order word of the long integer, and the low-order word is undefined. This includes the case where the mouse button is released over a disabled menu item (such as Cut, Copy, Clear, or one of the dividing lines in Figure 3), over any menu title, or outside the menu. If the mouse button is released over an enabled item-in a menu belonging to a desk accessory, MenuSelect passes the menu ID and item number to the Desk Manager procedure SystemMenu for processing, and returns 0 to your application in the high-order word of the result.

9/24/84 Rose-Withey

/MMGR/MENUS. R

22

Menu Manager

Progra~er's

Guide

Assembly-language~: If the global variable MBarEnable is nonzero, MenuSelect knows that every menu currently in the menu bar belongs to a desk accessory. (See the Desk Manager manual for more information.) The global variable MenuHook normally contains 0; if you store the address of a routine in MenuHook, MenuSelect will call that routine repeatedly (with no parameters) while the mouse button is down.

FUNCTION MenuKey (ch: CHAR) : LONGINT; MenuKey maps the given character to the associated menu and item for that character. When you get a key-down event with the Command key held down--or an auto-key event, if the command being invoked is repeatable--call MenuKey with the character that was typed. MenuKey highlights the appropriate menu title, and returns a long integer containing the menu 10 in its high-order word and the menu item number in its low-order word, just as MenuSelect does (see Figure 3 above). After performing the ehosen task, your application shduld call HiliteMenu(0) to remove the highlighting from the menu title. If the given character isn't associated with any enabled menu item currently in the menu list, MenuKey returns ~ in the high-order word of the long integer, and the low-order word is undefined. If the given character invokes a menu item in a menu belonging to a desk accessory, HenuKey (like MenuSelect) passes the menu 10 and item number to the Desk Manager procedure SystemMenu for processing, and returns 0 to your application in the high-order word of the result. (note) There should never be more than one item in the menu list with the same keyboard equivalent, but if there is, MenuKey returns the first such item it encounters, scanning the menus from right to left and their items from top to bottom. PROCEOURE HiliteMenu (menuIO: INTEGER); HiliteMenu highlights the title of the given menu, or does nothing if the title is already highlighted. Since only one menu title can be highlighted at a time, it unhighlights any previously highlighted menu title. If menuIO is 0 (or isn't the 10 of any menu in the menu list), HlliteMenu simply unhighlights whichever menu title is highlighted (if any). After MenuSelect or MenuKey, your application should perform the chosen task and then call HiliteMenu(0) to unhighlight the chosen menu title.

9/24/84 Rose-Withey

/MMGR/MENUS.R

MENU .MANAGER ROUTINES

23

Assembly-language~:

The global variable TheMenu contains the menu ID of the currently highlighted menu.

Controlling Items' Appearance

PROCEDURE SetItem (theMenu: MenuHandle; item: INTEGER; itemString: Str255) ; SetItem changes the text of the given menu item to itemString. It doesn't recogn~ze the meta-characters used in AppendMenu; if you include them in itemString, they will appear in the text of the menu item. The attributes already in effect for this item--its character style, icon, and so on--remain in effect. ItemString may be blank but should not be the null string. (nate) It's good practice to store the text of itemString in a resource file instead of passing it directly. Use SetItem to flip between two alternative menu items-- for example, to change "Show Clipboard" to "Hide Clipboard" when the Clipboard is already showing. (note) To avoid confusing the user, don't capriciously change the text of menu items. PROCEDURE GetItem (theMenu: MenuHandle; item: INTEGER; VAR itemString: Str25S); GetItem returns the text of the given menu item in itemString. It doesn't place any meta-characters in the string. This procedure is useful for getting the name of a menu item that was installed with AddResMenu or insertResMenu. PROCEDURE DisableItem (theMenu: MenuHandle; item: INTEGER); Given a menu item number in the item parameter, DisableItem disables that menu item; given 0 in the item parameter, it disables the entire menu. Disabled menu items appear dimmed and are not highlighted when the cursor moves over them. MenuSelect and MenuKey return 0 in the highorder word of their result if the user attempts t·o invoke a disabled item. Use DisableItem to disable all menu choices that aren't 9/24/84 .Rose-Withey /MMGR/MENUS.Ii

24

Menu Manager Programmer's Guide

appropriate at a given time (such as a Cut command when there's no text selection). All menu items are initially enabled unless you specify otherwise (such as by using the n( .. meta-character in a call t'o AppendMenu). Every menu item in a disabled menu is dimmed. The menu title is also dimmed. but you must ca11'DrawMenuBar to update the menu bar to show the dimmed title. PROCEDURE Enab1eItem (theMenu: MenuHandle; item: INTEGER); Given a menu item number in the item parameter. EnableItem enables the item; given 0 in the item parameter, it enables the entire menu. (The item or menu may have been disabled with the DisableItem procedure, or the item may have been disabled with the "(" meta-character in the AppendMenu string.) The item or menu title will no longer appear dimmed and can be chosen like any other enabled item or menu. PROCEDURE CheckItem (theMenu: MenuHandle; item: INTEGER; checked: BOOLEAN); CheckItem places or removes a check ma'tk at the left of the given menu item. After you call Check Item with checked-TRUE. a check mark will appear each subsequent time the menu is pulled down. Calling CheckItem with checked-FALSE removes the check mark from the menu item (or. if it's marked with a different character, removes that mark). Menu items are initially unmarked unless you ,specify otherwis-e (such as with the "!n meta-character in a call to AppendMenu). PROCEDURE SetItemMark (theMenu: MenuHandle; item: INTEGER; markChar: CHAR) ; SetItemMark marks the given menu item in a more general manner than CheckItem. It allows you to place any character in the system font, not just the check mark, to the left of the item. You can Ispecify some useful values for the markCharparameter with the following predefined constants: CONST noMark commandMark checkMark diamondMark appleMark -

GetItemHark returns in markChar whatever character the given menu item is marked with, or the NUL character (ASCII code 0) if no mark is present.

Assembly-Ianguage~: The macro you invoke to call GetItemMark from assembly language is named Get ItmMark.

PROCEDURE SetItemIcon (theMenu: MenuHandle; item: INTEGER; icon: Byte); Setltemlcon associates the given menu item with an icon. It sets the item's icon number to the given value (an integer from 1 to 255). The Menu Manager adds 256 to the icon number to get the icon's resource ID, which it passes to ,the Resource Manager to get the corresponding icon. (warning) If you deal directly with the Resource Manager to read or store menu icons, be sure to adjust your icon numbers accordingly. Menu items initially have no icons unless you specify otherwise (such as with the "A" meta-character in a call to AppendMenu).

Assembly-Ianguage~:

The macro you invoke to call SetItemlcon from assembly language is named Setltmlcon.

PROCEDURE GetItemIcon (theMenu: MenuHandle; item: INTEGER; VAR icon: Byte) ; GetltemIcon returns the icon number associated with the given menu item, as an integer from 1 to 255, or 0 if the item has not been associated with an icon •. The icon number is 256 less than the icon's resource ID.

Assembly-Ianguage~:

The macro you invoke to call Getltemlcon from assembly language is named GetltmIcon.

Assembly-language note: The macro you invoke to call GetItemStyle from assembly language is named _GetItmStyle.

Miscellaneous Routines

PROCEDURE CalcMenuSize (theMenu: MenuHandle); You can use CalcMenuSize to recalculate the horizontal and vertical dimensions of a menu whose contents have been changed (and store them in the appropriate fields of the menu record). CalcKenuSize is called internally by the Menu Manager after every AppendMenu, Setltem, SetltemIcon, and SetItemStyle call. FUNCTION CountMItems (theMenu: MenuHandle) : INTEGER; CountMItems returns
~he

number of menu items in the given menu.

9/24/84 Rose-Withey

/HMGR/MENUS. R

MENU MANAGER ROUTINES FUNCTION GetHHandle (menuID: INTEGER) : HenuHandle; Given the menu 1D of a menu currently installed in the menu list, GetHHandle returns a handle to that .menu; given any other menu ID, it returns NIL. PROCEDURE FlashMenuBar (menuID: INTEGER); If menuID is 0 (or isn't the ID of any menu in the menu list), FlashMenuBar inverts the entire menu bar; otherwise, it inverts the title of the given menu. PROCEDURE SetMenuFlash (count: INTEGER);

27

When the mouse button is released over an enabled menu item, the item blinks· briefly to confirm the choice. Normally, your application shouldn't be concerned with this blinking; the user sets it with the Control Panel desk accessory. If you're writing ,a desk accessory like the Control Panel, though, SetMenuFlash allows you to control the duration of this blinking. Count is the number of times menu items will blink; it's tnit.ially'3 if the user hasn't changed it. A count of o disables blinking. Values greater than 3 can be annoyingly slow. (warning) Don't call
SetMen~Flash

from your main program.

Assembly-language note: The macro you invoke to call SetMenuFlash from assembly language is named _SetMFlash. The current count is stored in the global variable MenuFlash.

(note) Items in both $tandard and nonstandard menus blink when chosen. The appearance of the blinking for a nonstandard menu depends on the menu definition procedure, as described below.

DEFINING YOUR OWN MENUS The standard you may'want or perhaps a Manager make type of Macintosh menu is predefined for you. However, to define your own type of menu--one with more graphics, nonlinear text arrangement. QuickDraw. and the Menu it possible for you to do this.

To define your own type of menu, you write a menu definition procedure and (usually) store it in a resource file. The Menu Manager calls the

A menu in a resource file contains the resource ID of itB menu ,definition procedure. The routine you use to read in the menu is GetMenu (or GetNewMBar, which calls GetMenu). If you store the resource ID of your own menu definition procedure in a ~enu in a resource file, GetMenu will take care of reading the procedure into memory and storing a handle to it in the menuProc field of the menu record.
If you create your' menus with NewMenu instead of storing them as resources, NewMenu stores a handle to the standard menu definition procedure in the menu record's menuProc field. You must replace this with a handle to your own menu definition procedure, then call CalcMenuSize. If your menu definition procedure is in a resource file, you get the handle by calling the Resource Manager to read it from the resource file into memory. (note) Advanced programmers can include the menu definition procedure in with the program code instead of storing it as a separate ~esource. The Menu Definition Procedure The menu definition procedure may be written in Pascal or assembly language; the only requirement is that its entry point must be at the beginning. You may choose any name you wish. for the procedure. Here's how you would declare one named MyMenu: PROCEDURE MyMenu (message: INTEGER; theMenu: MenuHandle; VAR menuRect: Rect; hitPt: Point; VAR whichltem: INTEGER); The message parameter identifies the operation to be performed. value will be one of the following predefined constants: CONST mDrawHsg - 0; mChooseMsg - 1; mSizeMsg {draw the menu} {tell which item was chosen and } { highlight it} {calculate the menu's dimensions} Its

= 2;

The parameter theMenu indicates the menu that the operation will affect. MenuRect is the rectangle (in global coordinates) in which the menu is located; it's used when the message is mDrawMsg or mChooseMsg. (note) MenuRect is declared as a VAR parameter not because its value is changed, but because of a Pascal feature that will cause an error when that parameter isn't used. The message mDrawMsg tells the menu definition procedure to draw the menu inside menuRect. The current ,grafPort will be the Window Manager 9/24/84 Rose-Withey /MMGR/MENUS.D

DEFINING YOUR OWN MENUS

29

port. (For details on drawing,' see the QuickDraw manual.) The standard menu definition procedure figures out how to draw the menu items ,by looking in the menu record at the data that defines them; thio data is described in detail under "Formats of Resources for Menus" below. For menus of your own definition, you may set up the data defining the menu items any way you like, or even omit it altogether. (in which case all the information necessary to draw the menu would be in the menu definition procedure itself). You should also check the enableFlags field of the menu record to see if the menu is disabled (or if any of the menu items are disabled, if you're using all the flags), and if so, draw it in gray. (warning) Don't change the font from the, system font for menu text. (The Window ~~nager port uses the system font.) , When the menu definition procedure receives the message mChooseMsg, th~ hitPt parameter is ~he point (in global coordinates) where the mouse button was released, and the whichItem parameter is the item number of the last item that was chosen from this menu. The procedure should determine if the mouse button was released in an enabled menu item, by checking, whether hitPt is inside menuRect, whether the menu is enabled II and whether hitPt is in an enabled menu item:

,

- If the mouse button was released in an enabled menu item, unhighlight whichltem and highlight the newly chosen item (unless the new item is the same as the whichltem), and return the item number of the new item in which Item. - If the mouse button wasn't released in an enabled item, unhighlight whichltem and return 0. (note) When the Menu Manager needs to make a chosen menu item blink, it repeatedly calls the menu definition procedure with the message mChooseMsg, causing the item to be alternately highlighted and unhighlig~ted. Finally, the message mSizeMsg tells the menu definition procedure to calculate the horizontal and vertical dimensions of the menu and store them in the menuWidth and menuHeight fields of the menu record.

FORMATS OF RESOURCES FOR MENUS The resource type for a menu definition procedure is 'MDEF'. The resource data is simply the compiled or assembled code of the procedure. Icons in menus must be stored in a resource file under the resource type 'ICON' with resource IDs from 257 to 511. Strings in resource files have the resource type 'STR '; if you use the Setltem procedure

9/24/84 Rose-Withey

/MMGR/MENUS .. D

30

Menu Manager Programmer's Guide

to change a menu item's text, you sh9uld store the alternate text as a string resource. The
~ormats

of menus and menu bars in resource files are given below.

I

Menus in a Resource File The resource type for a menu is 'MENU'. The resource data for a menu has the format shown below. Once read into memory, this data Is stored in a menu record (described earlier in the ''Menu Records" section). Number of bytes Contents 2 bytes Menu ID 2 bytes 0; placeholder for menu width 2 bytes0; placeholder for menu height 2 bytes Resource ID of menu definition procedure 2 bytes o (see comment below) 4 by,tes Same as enableFlags field of menu record 1 byte Length of following title in bytes n bytes Characters of menu title 'For each menu item: 1 byte Length of following text in bytes m bytes Text of menu item 1 byte Icon number, or 0 if no icon 1 byte Keyboard equivalent, or 0 if none 1 byte Character marking menu item, or 0 if none 1 byte Character style of item's text 1 byte 0, indicating end of menu items The four bytes beginning with the resource ID of the menu definition procedure' serve as a placeholder for the ha~dle to the procedure: When GetMenu is called to read the menu from the resource file, it also reads in the menu definition procedure if necessary, and replaces these four bytes with a handle to the procedure. The resource ID of, the standard menu definition procedure is: CONST textMenuProc ~

0;

The resource data for a nonstandard menu can define menu items in any way whatsoever,or not at all, depending on the requirements of its menu definition procedure. If the appearance of ' the items is basically the same as the standard, the resource data might be as shown above, but in fact everything following "For each menu item" can have any desired format or can be omitted altogether. Similarly, bits 1 to 31 of the enableFlags field may be set and used 'in any way desired by the menu definition procedure; bit 0 applies to the entire menu and must reflect whether it's enabled or disabled. If your menu definition procedure does use the enableFlags field, menus of that type may contain no more than 31 items (I per available bit); otherwise, the number of items they may contain is limited only by the amount of room on the screen.

9/24/84 Rose-Withey

/MMGR/MENUS. D

FORMATS OF RESOURCES FOR MENUS

31

(note) See "Using OuickDraw from Assembly Language" in the OuickDraw manual for the exact format of the character style byte. (warning) Menus in resource files must not be purgeable. Menu Bars in a Resource File The resource type for the contents of a menu bar is 'MBAR' and the resource data has the following format: Number of bytes 2 bytes For each menu: 2 bytes Contents Number of menus Resource 1D of menu

Meta-Characters for AppendMenu Meta-character ; or Return Usage Separates multiple items Followed by an icon number, adds that icon to the item Followed by a character, marks the item with that character Followed by B, I, U, 0, or S, sets the character style of the item Followed by a character, associates a keyboard equivalent with the item Disables the item

Contents Handle to current menu list Nonzero if menu bar belongs to a desk accessory Hook for routine to be called during Menu Select Menu ID of currently highlighted menu Count for duration of menu item blinking

9/24/84 Rose-Withey

/MMGR/MENUS.S

36

Menu Manager Programmer's Guide

GLOSSARY
character style: A set of stylistic variations. such 8S bold. italic. and underline. The empty set indicates plain text (no stylistic variations). dimmed: Drawn in gray rather than black.

disabled: A disabled menu item or menu is one that cannot be chosen; the menu item or menu title appears dimmed. icon: A 32-by-32 bit image that graphically represents an object. concept, or message. icon number: A digit from 1 to 255 to which the Menu Manager adds 256 to get the resource ID of an icon associated with a menu item. keyboard equivalent: The combination of the Command key and another key. used to invoke a menu item from the keyboard • . menu: A list of menu items that appears when the uoer points to a menu title in the menu bar and ·presses the mouse button. Dragging through the menu and releasing over an enabled menu- item chooses that item.
I

menu bar: The horizontal strip at the top of the ~mcintosh screen that contains the menu titles of all menus in the menu list. menu definition procedure: A procedure called by the Menu Manager when it needs to perform basic operations on a particular type of menu, such as drawing the menu. menu ID: A number in the menu record that identifies .the menu.

menu item: A choice in a menu. usually a command to the current application. menu item number: menu. The index. starting from 1, of a menu item in a

menu list: A list containing menu handles for all menus in the menu bar, along with information on the position of each menu. menu record: The internal representation of a menu, where the Menu Manager stores all the information it needs for its operations on that menu. menu title: A word or phrase in the menu bar that designates one menu.
A

meta-character: One of the characters; ! < / ( or Return appearing in the string passed to the Menu Manager routine AppendMenu, to separate menu items or alter their appearance.

TextEdit is the part of the Maci~tosh User Interface Toolbox'that handles basic text formatting and editing capabilities in a Macintosh application. This manual describes the TextEdit routines and data types in detail. Summary of significant changes and additions since,last draft: - Several field names in the edit record and the descriptions of some of the fields have changed; all fields are now shown (page

ABOUT THIS MANUAL TextEdit is the part of the Macintosh User Interface Toolbox that handles basic text formatting and editing capabilities in a Macintosh application. This manual describes the TextEdit routines and data types in detail. *** Eventually it will become a chapter in the comprehensive Inside Macintosh manual. *** Like all Toolbox documentation, this manual assumes you're familiar with Lisa Pascal and the information in the following manuals: - Inside Macintosh:

ABOUT TEXTEDIT TextEdit is a set of routines and data types that provide the basic text editing and formatting capabilities needed' in an application. These capabilities include: - inserting new text - deleting characters that are backspaced over - translating mouse activity into text selection - scrolling' text within a window - deleting selected text and possibly inserting it elsewhere, or copying text without deleting it The TextEdit routines follow the Macintosh User Interface Guidelines; using them ensures that your application will present a consistent user interface. For example, the Dialog Manager uses TextEdit for text editing in dialog boxes.

1/14/85 Ha'cker-Withey

/TEXTEDIT/EDIT.2

4

TextEdit Programmer's Guide

TextEdit supports these standard features: - Selecting text by clicking and dragging with the mouse, doubleclicking to select words. To TextEdit, a word is any series of printing characters, excluding spaces (ASCII code $2~) but including nonbreaking spaces (ASCII code $CA). - Extending or shortening the selection by Shift-clicking. - Inverse highlighting of the current text selection, or display of a blinking vertical bar at the insertion point. - Word wraparound, which prevents a word from being split between lines when text is drawn. \ Cutting (or copying) and pasting within an application via the Clipboard. TextEdit puts text you cut or copy into the TextEdit scrap. (note) The TextEdit scrap is used only by TextEdit; it's not the same as the "desk scrap" used by the Scrap Manager. To support cutting and pasting between applications, or between applications and desk accessories, you must transfer information between the two scraps. Although TextEdit is useful for'many standard text editing operations, there are some additional features that it doesn't support. TextEdit does not support: - use of more than one font or stylistic variation in a single edit record - fully justified text (text aligned with both the left and right margins) - "intelligent cut and paste" (adjusting spaces between words during cutting and .pasting) - tabs TextEdit also provides "hooks" for implementing some features such as automatic scrolling or a more precise definition of a word than that given above.

EDIT RECORDS To edit text on the screen, the text editing routines need to know where and how to display the text, where to store the text, and other information related to editing. This display, storage, and editing information is contained in an edit record that defines the complete editing environment. The data type of an edit record is called TERec. 1/14/85 Hacker-Withey /TEXTEDIT/EDIT.2

EDIT RECORDS

5

You prepare to edit text by specifying a destination rectangle in which to draw the text and a view rectangle in which the text will be visible. TextEdit incorporates the rectangles and the dra~ing environment of the current grafPort into an edit record, and returns a handle of type TEHand1e to the record: TYPE TEPtr TEHand1e

=

ATERec; ATEPtr;

Most of the text editing routines require you to pass this handle as a parameter. In addition to the two rectangles and a description of the drawing environment, the edit record also contains: - a handle to the text to be edited - a pointer to the,grafPort - the current selection range, which determines exactly which characters will be affected by the next editing operation - the justification of the text, as left, right, or center The special terms introduced here are described in detail below. For most operations, you don't need to know the exact structure of an edit record; TextEdit routines access the record for you. However, to support some operations, such as scrolling, you need to access the fields of the edit record directly. The structure of an edit record is given below. The Destination and View Rectangles The destination rectangle is the rectangle in which the text is drawn. The view rectangle is the rectangle within which the text is actually visible. In other words, the view of the text drawn in the destination rectangle is clipped to the view rectangle (see Figure 1). _

1/14/85 Hacker-Withey

/TEXTEDIT/EDIT.2

6

TextEdit Programmer's Guide

Th s document s full of choice bits of reading material. Note that text is drawn within the dest inet i on recteng I e, but visible only in

You specify both rectangles in the local coordinates of the grafPort. To ensure that the first and last characters in each line are legible in a document window, you may want to inset the destination rectangle at least four pixels from the left and right edg~s of the grafPort's portRect (20 pixels from the right edge if there's a scroll bar or size box) • Edit operations may of course lengthen or shorten the text. If the, text becomes too long to be enclosed by the destination rectangle, it's simply drawn beyond the bottom. In other words, you can think of the destination rectangle as bottomless--its sides determine/the beginning and end of each line of text, and its t,op determines the position of the first line. Normally, at the right edge of the destihation rectangle, the text automatically wraps around to the left edge to begin a new line. A new line also begins where explicitly specified by a Return character in the text. Word wraparound ensures that no word is ever split between lines unless it's too long to fit entirely on one line, in which case it's split at the right edge of the destination rectangle. The Selection Range In the text editing environment, a character position is an index into the text, with position 0 corresponding to the first character. The edit record includes fields for character positions that specify the beginning and end of the current selection range, which is the series of characters where the next editing operation will occur. For example, the procedures that cut or copy from the text of an edit record do so to the current selection range. The selection range, which is inversely highlighted when the window is active, extends from the beginning character position to the end character position. Figure 2 shows a selection range between positions 1/14/85 Hacker-Withey /TEXTEDIT/EDIT.2

EDIT RECORDS 3 and 8, consisting of five characters (the character at position 8 isn't included). The end position of a selection range may be 1 greater than the position of the last character of the text, so that the selection range can include the last character.

7

setection range beginning at p03ition 3 ,gnd end ing at pos i t ion 8

Insertion point at p03iti,')r. ,~

Figure 2.

Selection Range and Insertion Point

If the selection range is empty--that is, its beginning and end positions are the same--that position is the text's insertion point, the position where characters will be inserted. By default, it's marked with a blinking caret. If, for example, the insertion point is as illustrated in Figure 2 and the inserted characters are "edit ", the text will read "the edit insertion point". (note) We use the word caret here generically, to mean a symbol indicating where something is to be inserted; the specific symbol ~s a vertical bar (I). If you call a procedure to insert characters when there's a selection range of one or more characters rather than an insertion point, t~e editing procedure automatically 'deletes the selection range and replaces 'it with an insertion point before inserting the characters.

1/14/85 Hacker-Withey

/TEXTEDIT/EDIT.2

8

TextEdit Programmer's Guide

Justification TextEdit allows you to specify the justification of the lines of text, that is, their horizontal placement with- respect to the left and right edges of the destination rectangle. The different types of justification supported by TextEdit are illustrated in.Figure 3. - Left justification aligns the text with the left edge of the. destination rectangle. This is the default type of justification. - Center justification centers each line of text between the left and right edges of the destination rectangle. - Right justification aligns the text with the right edge of the destination rectangle.

This is an example of'left justification. See how the text is aligned with the left edge of the rectangle.

This is an example of center justification. See how the text is centered between the edges of the rectangle.
Figure 3. Justification

This is an example of right justification. See how the text is aligned with the right edge of the rectangle.

(note) Trailing spaces on a line are ignored for justification. For example, "Fred" and "Fred "will be aligned identically. (Leading spaces are not ignored.) TextEdit provides three predefined constants for setting the justification: CONST teJustLeft teJustCenter teJustRight

is the ascent of ,the text in pixels (the height of the tallest characters in the font from the base line). The lineHeight field specifies the vertical distance from the ascent line of one, line of text down to the ascent line of the next. For single-spaced text, this is the same as the font size, but in pixels. The values of the lineHeight and fontAscent fields for single-spaced text are shown in Figure 4. For more information on fonts, see the Font Manager manual. '

If you want to change the vertical spacing of the text, you should change both the lineHeight and fontAscent fields by the same amount, otherwise the placement of the caret or highlighting of the selection range may not look right. For example, to double the line spacing, add the value of lineHeight to both fields. (This doesn't change the size of the characters; it affects only the spacing between lines.) If you change the size of the text, you should also, change these fields; you can get font measurements you'~l need with the QuickDraw procedure GetFontInfo.

Assembly-language note: The selPoint field (whose assembly-language offset is named teSelPoint) contains the point selected with the mouse, in the local coordinates of the current grafPort. You'll need this for hit-testing if you use the routine pointed to by the global. variable TEDoText (see "Advanced Routines" in the "TextEdit Routines" section).

The selStart and selEnd fields ,specify the character positions of the beginning and end of the selection range. Remember that character position 0 refers to the first character, and that the end of a selection range can be 1 grea~er than the position of the last character of the text. The wordBreak field lets you change TextEdit's definition of a word, and the clikLoop field lets you implement automatic scrolling. These two fields are described in separate sections below. The just field specifies the justification of the text. "Justification", above.) (See

1/14/85 Hacker-Withey

/TEXTEDIT/EDIT.2

EDIT RECORDS

11

The teLength f~eld contains the number of characters in the text to be edited, and the hText field is a handle to the text. You can directly change the text of an edit record by changing these two fields. The crOnly field specifies whether or not text ,wraps around at the right edge of the destination rectangle, as shown in Figure 5. If crOnly is positive, text does wrap around. If crOnly is negative, text does not wrap around at the edge of the destination rectangle, and new lines are specified explicitly by Return characters only. This is faster than word wraparound, and is useful in an application similar to a programming-language editor, where you may not want a single line of code to be split onto two lines.
There's a Return character at the end There's a Return charec But not at the end, of tt

of this line. But not at the end of this line. Or this line.
new line 81' Return characters and edge of' dest i nati on rectang Ie

new I ine at Return
characters onl y
New Lines

Figure 5.

The txFont, txFace, txMode, and txSize fields' specify the font, character style, pen mode, and font size, respectively, of all the text in the edit record. (See the QuickDraw manua~ for more details about these characteristics.) If you change one of these values, the entire text of this edit record will have the new characteristics when it's redrawn. If you change the txSize field, remember to change the lineHeight and fontAscent fields, too. The inPort field contains a pointer to the grafPort associated with this edit record. (warning) The current port is not preserved when TextEdit is called; you must preserve it before all calls to TextEdit routines.

Assembly-language note': The highHook and caretHook fields--at the offsets teHiHook and teCarHook in assembly language--contain t~e addresses ~f routines that deal with text highlighting and the caret. These routines pass arguments in registers; the application must save and restore the registers. If you store the address of a routine in teHiHook, that routine . will be used instead of the QuickDraw procedur~ InvertRect whenever a selection range is to be highlighted. The routine 1/14/85 Hacker-Withey /TEXTEDIT/EDIT.2

12

TextEdit Programmer's Guide can destroy the contents of registers A0, AI, D0, Dl, and D2. On entry, A3 should-be a dereferenced handle to a locked edit record; teSelRect(A3) is the rectangle enclosing the text being highlighted. For example, if you store the a~dress of the following routine in teHiHook, selection ranges will be underlined instead of inverted: UnderHigh PEA teSelRect(A3) MOVE.L (SP) ,A0 MOVE bottom(A0),top(A0) SUBQ 111, top (A0) InverRect RTS jget address of rectangle to be ; highlighted ;make the top coordinate equal to ; the bottom coordinate minus 1 jinvert the resulting rectangle

The routine whose address is stored in teCarHook acts-exactly the same way as the teHiHook routine, but on the caret instead of the selection highlighting, allowing you to change the appearance of the caret. The routine is called with teSelRect(A3) containing the rectangle that encloses the caret.

The nLines field contains the number of" lines in the text. The lineStarts array contains the character position of the first character in each ~ine. It's declared to have 16001 elements to comply with Pascal range checking; it's actually a dynamic data structure having only as many elements as needed. You sho~ldn't change the elements of lineStarts. (note) The values of selStart, selEnd, and the elements of the lineStarts array are stored internally as unsigned integers. The Word Break Field The wordBreak field of an edit record lets you specify the record's word break routine--the routine tha_t determines the "word" that's highlighted when the user double-clicks in the text, and the position at which text is wrapped around at the end of a line. The default routine breaks words at any character with an ASCII value of $20 or less (the space character or nonprinting control characters). Normally the word break routine is written in assembly language. write it in Pascal, 'you must declare it as follows: FUNCTION
PasWordBre~k

To

(text: Ptr; charPos: INTEGER)

BOOLEAN;

The function must be named "PasWordBreak". It should return TRUE to break a word at the character at position charPos in the specified text, or FALSE not to break there. To access PasWordBreak, set: 1/14/85 Hacker-Withey /TEXTEDIT/EDIT.2

EDIT RECORDS myEditRecAA.wordBreak := @AsmWordBreak

13

AsmWordBreak is an assembly-language procedure provided for the convenience of Pascal programmers. It sets the necessary registers and calls PasWordBreak.

Assembly-language note: You can set this field to point to your own assembly-language word break routine instead of using AsmWordBreak. The registers must contain the following: On entry On exit A0: D0: pointer to text character position (word)

Z (zero) condition code: o to break at specified character 1 not to break there

The ClikLoop Field The clikLoop field contains the address of a routine that's called repeatedly (by the TEClick procedure, described below) as long as the mouse button is held down within the text. You can use this to implement the automatic scrolling of text when the user is making a selection and drags the cursor out of the view rectangle. The click loop routine, like the word break routine, is normally written in assembly language. To write it in Pascal, you must declar~ it as follows: FUNCTION PasClikLoop : BOOLEAN; The function must be named "PasClikLoop". access PasClikLoop, set: myEditRecAA.clikLoop It should return TRUE. To

:=

@AsmClikLoop

AsmClikLoop is an assembly-language procedure provided for 'the convenience of Pascal programmers. It sets the necessary registers and calls PasClikLoop. An automatic scrolling routine might check the mouse position, and call a scrolling routine if the mouse position is outside the view rectangle. (The scrolling routine can be the same routine that the Control Manager function TrackControl calls.) The handle to the current edit record should be kept as a global variable so the scrolling routine can access it.

1/14/85 Hacker-Withey

/TEXTEDIT/EDIT.2

14

TextEdit Programmer's Guide

(warning) Returning FALSE from PasClikLoop tells the TEClick procedure that the mouse button has been released, which aborts TEClick.

USING TEXTEDIT Before using TextEdit, you should initialize QuickDraw, the Font Manager, and the Window Manager, in that order. The first TextEdit routine to call is the initialization procedure TEInit. Call TENew to allocate an edit record; it returns a handle to the record. Most of the text editing routines require you to pass this handle as a parameter. When you've finished working with the text of an edit record, you can get a handle to the text as a packed· array of characters with' the TEGetText function. (note) To convert text from an edit record to a Pascal string, you can use the Dialog Manager procedure GetIText, passing it the text handle from the edit record. When you're completely done with an edit record and want to dispose of it, call TEDispose. (note) To change the cursor to an I-beam, you can call the Toolbox Utility functibn GetCursor and the QuickDraw procedure SetCursor. The resource ID for the I-beam cursor is defined in the ToolBox Utilities as the constant iBeamCursor. To make a blinking caret appear at the insertion point, call the TEldle procedure as often as possible (at least once each time through the main event loop); if it's not called often enough, the caret will blink irregularly. When a mouse-down event occurs in the view rectangle (and the window is active) call the TEClick procedure. TEClick controls the placement and highlighting o~ the selection range, including supporting use of the Shift key to make extended selections. . 1/14/85 Hacker-Withey /TEXTEDIT/EDIT.2

USING TEXTEDIT Key-down, auto-key, and mouse events that pertain to text editing can be handled by several TextEdit procedures: - TEKey inserts characters and deletes characters backspaced over. - TECut transfers the selection range to the TextEdit scrap,. removing the selection range from the text.

15

- TEPaste inserts the contents of the TextEdit scrap. By calling TECut, changing the insertion point, and then calling TEPaste, you can perform a~ "cut and paste" operation, moving text from one place to another. - TECopy copies the selection range to the TextEdit scrap. By calling TECopy, changing the insertion point, and then calling TEPaste, you can make multiple copies of text. - TEDelete removes the selection range (without transferring it to the scrap). You can use TEDelete to implement the Clear command. - TEInsert inserts specified text. You can use this to combine two or more documents. TEDelete and TEInsert do not modify the scrap, so they're useful for implementing the Undo command. After each editing procedure, TextEdit redraws the text if necessary from the insertion point to the end of the destination rectangle. You never have to set the ~election range or insertion point yourself; TEClick and the editing procedures leave it where it should be. If you want to modify the selection range directly, however--to highlight an initia'l default name or value, fo,r example--you can use the TESetSelect procedure. When GetNextEvent reports an update event for a text editing window, call TEUpdate--along with the Window Manager procedures BeginUpdate and EndUpdate--to redraw the text. (I).ote) You must call TEUpdate after you change any fields of the edit record if the fields affect the appearance, of the text. This ensures that the screen accurately reflects the changed ed~ting environment. The procedures TEActivate and TEDeactivate must be called each time GetNextEvent reports an activate event for a text editing window. TEActivate simply highlights 'the selection range or displays a caret at the insertion point; TEDeactivate unhighlights the selection range or removes the caret. To specify the justification of the text, you can use TESetJust. If you change the justification, be sure to call TEUpdate to redraw the text. To scroll text within the view rectangle, you can use the TEScro11 procedure.

1/14/85 Hacker-Withey

/TEXTEDIT/EDIT.2

16

TextEdit Programmer's Guide

The TESetText procedure lets you change the text being edited. For example, if your application has several separate pieces of text that must be edited one at a time, you don't have to allocate an edit record for each of them. Allocate a single edit record, then use TESetText to change th~ text. (This is the method used in dialog boxes.) (note) TESetText actually makes a copy of the text to be edited. Advanced programmers can save space by storing a handle to the text.in the hText field of the edit record itself, then calling TECalText to recalculate the beginning of each line. If you ever want to draw noneditable text in any given rectangle, you can use the TextBox procedure. To implement cutting and pasting of text between different applications, or between applications and desk accessories, you need to transfer the text between the TextEdit scrap (which is a private scrap used only by TextEdit) and the Scrap Manager's desk scrap. You can do this using the functions TEFromScrap and TEToScrap. For programmers who wish to access scrap information directly, the low-level routines TEScrapHandle, TEGetScrapLen, and TESetScrapLen are also provided. (See the Scrap Manager manual for more information about scrap handling.)

TEXTEDIT ROUTINES

Initialization and Allocation

PROCEDURE TElnit; TEInit initializes TextEdit by allocating a handle for the' TextEdit scrap. Thesc~ap is initially empty. Call this procedure once and only once at the beginning of your program. (note) You should call TEInit even if your application doesn't us~ TextEdit, so that desk accessories and dialog and alert boxes will work correctly. FUNCTION TENew (destRect,viewRect: Rect) : TEHandle; TENew allocates a handle ~or the text, creates and initializes an edit record, and returns a handle to the new edit record. DestRect and \ viewRect are the destination and view rectangles, respectively. Both rectangles ~te specified in the current grafPort's coordinates. The 1/14/85 Hacker-Withey /TEXTEDIT/EDIT.R

TEXTEDIT ROUTINES destination rectangle must always be at least as wide as the first character drawn (about 20 pixels is usually a good width). The view rectangle must not be empty (for example, don't make its right edge less than its left edge if you don't want any text visible--specify a rectangle off the screen instead). Call TENew once for every edit record you want allocated. The edit record incorporates the drawing environment of the grafPort, and is initialized for left-justified, single-spaced text with an insertion point at character position 0. (note) The caret won't appear until you call TEActivate. PROCEDURE TEDispose (hTE: TEHandle); TEDispose releases the memory allocated for the edit record and text specified by hTE. Call this procedure when you're completely through with an edit record. Accessing the Text of an Edit Record

17

PROCEDURE TESetText (text: Ptrj length: LONGINT; hTE: TEHandle); TESetText incorporates a copy of the specified text into the edit record specified by hTE. The text parameter points to the text, and the length parameter indicates the number of characters in the text. The selection range is set to an insertion point at the end of the text. TESetText doesn't affect the text drawn in the destination rectangle, so call TEUpdate afterward if necessary. TESetText doesn't dispose of any ~ext currently in the edit record. FUNCTION TEGetText (hTE: TEHandle) : CharsHandle; TEGetText returns a handle to the text of the specified edit record. The result is the same as the handle in the hText field of the edit record, but has the CharsHandle data type, which is defined as: . TYPE CharsHandle CharsPtr Chars ACharsPtrj AChars; PACKED ARRAY[0 •• 320001 OF CHAR;

You can get the length of the text from the teLength field of the edit record.

1/14/85 Hacker-Withey

/TEXTEDIT/EDIT.R

18

TextEdit Programmer's Guide

The Insertion Point and Selection Range

PROCEDURE TEIdle (hTE: TEHandle); Call TEIdle repeatedly to make a blinking caret appear at the insertion point (if any) in the text specified by'hTE. (The caret appears only 'when the window containing that text is active, of course.) TextEdit observes a minimum blink interval: No matter how often you call TEIdle, the time between blinks will never be less than the minimum interval. (note) The initial minimum blink interval setting is 30 ticks. The user can adjust this setting with the Control Panel desk accessory. To provide a constant frequency of blinking, you should call TEIdle as often as possible--at least once each time through your main event loop. Call it more than once if your application does an unusually large amount of processing each time through the loop. (note) You actually need to call TEIdle only when the window containing the text is active. PROCEDURE TEClick (pt: Point; extend: BOOLEAN; hTE: TEHandle); TEClick controls the placement and highlighting of the selection range as determined by mouse events. Call TEClick whenever a mouse-down event occurs in the view rectangle of the edit record specified by hTE, and the window associated with that edit record is active. TEClick keeps control until the mouse button is released. Pt is the mouse location (in local coordinates) at the time the button was pressed, obtainable from the event record. ' (note) Use the QuickDraw procedure GlobalToLocal to convert the global coordinates of the mouse location given in the event record to the local coordinate system for pt. Pass TRUE for the extend parameter if the Event Manager indicates that the Shift key was held down at the time of the click (to extend the selection) • TEClick unhighlights the old selection range unless the selection range is being extended. If the mouse moves, meaning that a drag is occurring, TEClick expands, or shortens the selection range accordingly. In the case of a double-click, the word under the cursor becomes the selection range; dragging expands or shortens the selection a word at a time. ' 1/14/85 Hacker-Withey /TEXTEDIT/EDIT.R

TEXTEOIT ROUTINES . PROCEDURE TESetSelect (selStart,selEnd: LONGINT; hTE: TEHandle); TESetSelect sets the selection range to the text between selStart and selEnd in the text specified by hTE. The old selection range is unhighlighted, and the new one is highlighted. If selStart equals selEnd, the selection range is an insertion point, and a caret is displayed.

19

SelEnd and selStart can range from ~ to 32767. If selEnd is anywhere beyond the last character of the text, the position just past the last character is used. PROCEDURE TEActi vate (hTE:, TEHandle); TEActivate highlights the selection range in the view rectangle of the edit record specified by hTE. If the selection range is an insertion point, it displays a caret there. This procedure should be called every time the Toolbox Event Manager function GetNextEvent reports that the window containing the edit record has become active. PROCEDURE TEDeactivate (hTE: TEHandle); TEDeactivate unhighlights the selection range in the view rectangle of the edit record specified by hTE. If the selection range is an insertion point, it removes th~~aret. This procedure should be called every time the Toolbox Event Manager function GetNextEvent reports that the window containing the edit ,record has become inactive. Editing

PROCEDURE TEKey (key: CHAR; hTE: TEHandle); TEKey replaces the selection range in the text specified by hTE with the character given by the key parameter, and leaves an insertion point just past the inserted character. If the selection range is an insertion point, TEKey just inserts the character there. If the key parameter contains a Backspace character, the selection range or the character immediately to the left of the insertion point is deleted. TEKey redraws the text as necessary. Call TEKey every time the Toolbox Event Manager function GetNextEvent reports a keyboard event that your application decides should be handled~by TextEdit. (note) TEKey inserts every character passed in the key parameter, so it's up to your application to filter out all characters that aren't actual text (such as keys typed {n conjunction with the Command key).

1/14/85 Hacker-Withey

/TEXTEDIT/EDIT.R

20

TextEdit Programmer's Guide

PROCEDURE TECut (hTE: TEHandle); TECut removes the selection range from the places it in the TextEdit scrap. The text Anything previously in the scrap is lost. selection range is an insertion point, the
Before TECut: This

text specified by hTE and is regrawn as necessary. (See Figure 6.) If the scrap is emptied.

isi.'iiiilia good illustration.
text
TextE di t scrap

After TECut:

IThis is a good illll3tration.
text
Figure 6. Cutting

I

lL...--pr_ob_sb_IY_-..J
TextEdit scrap

PROCEDURE TECopy (hTE: TEHandle); TECopy copies the selection range from the text specified by hTE into the TextEdit scrap. Anything previously in the scrap is deleted. The selection range is not deleted. If the selection range is an insertion point, the scrap is emptied. PROCEDURE TEPaste (hTE: TEHandle); TEPaste replaces the selection range in the text specified by hTE with the contents of the TextEdit scrap, and leaves an insertion point just past the inserted text. (See Figure 7.) The text is redrawn as necessary. If the scrap is empty, the selection range is deleted. If the selection range is an insertion point, TEPaste just inserts the scrap there.

1/14/85 Hacker-Withey

/TEXTEDIT/EDIT.R

TEXTEDIT ROUTINES

21

Before TECut: IllllJlbefore you leep
text TextE d it scrap

After rEcut: Ilbefore you leap text
Before TE F'8ste:

TextE d it scrap

I

before you eap

II

text
, After TEF'8$te:

TextE d it scrap
1look,

I

before you look.r leap text

TextE d i t ::crap

Figure 7.

Cutting and Pasting

PROCEDURE'TEDelete (hTE: TEHandle); TEDelete removes the selection range from the text specified by hTE, and redraws the text as necessary. TEDelete is the same as TECut (above) except that it doesn't transfer the selection range to the scrap. If the selection range is an insertion point, nothing happens. PROCEDURE TEInsert (text: Ptr; length: LONGINT; hTE: TEHandle); TEInsert takes the specified text and inserts it just before the selection range into the text indicated by hTE, redrawing the text as necessary. The text parameter points to the text to be inserted: and the length parameter indicates the number of characters to be inserted. TEInsert doesn't affect either the current sel.ection range or the . scrap. Text Display and Scrolling

By default, text is left-justified. If you change the justification, call TEUpdate after TESetJust, to redraw the text with the new justification. PROCEDURE TEUpdate (rUpdate: Rect; hTE: TEHandle); TEUpdate draws the text specified by hTE within the rectangle specified ,by rUpdate. The rUpdate rectangle must be given in the coordinates of the current grafPort. Call TEUpdate every time the Toolbox Event Manager function GetNextEvent reports an update event for a text edi~ing w~ndow--after you call the Window Manager procedure BeginUpdate, and before you call EndUpdate. Normally you'll do the following when an update event occurs: BeginUpdate(myWindow); EraseRect(myWindowA.portRect); TEUpdate(myWindowA.portRect,hTE); EndUpdate(myWindow) If you don't include the EraseRect call, the caret may sometimes remain visible when the window is deactivated. PROCEDURE TextBox (text: Ptr; length: LONGINT; box: Rect; just: INTEGER) ; TextBox draws the specified text in the rectangle indicated by the box parameter, \vith justification just. (See "Justification" under "Edit Records".) The text parameter points to the text, and the length parameter indicates the number of characters to draw. The rectangle is specified in local coordinates, and must be at least as 'wide as the first character drawn (about 2~ pixels is usually a good width). TextBox does not create an edit record, nor can the text that it draws be edtted; it's used solely for drawin~ text. For example: str := 'String in a box';' SetRect(r,100,100,200,200); TextBox(POINTER(ORD(@str)+l),LENGTH(str),r,teJustCenter); FrameRect(r) Because Pascal strings start with a length byte, you must advance the pointer one position past the beginning of the string to point to the start of the text.
I

PROCEDURE TEScroll (dh ,dv: INTEGER; hTE: TEHandle'); TEScroll scrolls the text within the view rectangle of the specified edit record by the number of pixels specified in the db and dv parameters. The edit record is specified by the hTE parameter. Positive dh and dv values move the text right and down, respectively, and negative values move the text left and up. For example, 1/14/85 Hacker-Withey /TEXTEDIT/EDIT.R

TEXTEDIT ROUTINES TEScroll(0,-hTE
AA

23

.lineHeight,hTE)

scrolls the text up one line. Remember that you scroll text up when the user clicks in the scroll arrow pointing down. The destination rectangle is offset by the amount you scroll. (note) To implement automatic scrolling, you store the address of a routine in the clikLoop field of the edit record, as described above under "The TERec Data Type". Scrap Handling The TEFromScrap and TEToScrap functions return a result code of the type OSErr (defined as INTEGER in the Operating System Utilities) indicating whether an error occurred. If no error occurred, they return the result code CONST noErr = 0 {no error}

Otherwise, they return an Operating System result code indicating an error. (See the Operating System Utilities manual for a list of all result codes.) FUNCTION TEFromScrap : OSErr; [Not in ROM]
~he

TEFromScrap copies the desk scrap to

TextEdit scrap.

Assembly-language note: From assembly language, you can store a handle to the desk scrap in the global variable TEScrpHandle, and the length of the desk scrap in global variable TEScrpLength; you can get these values with ~he Scrap Manager function GetScrap.

FUNCTION TEToScrap : OSErr;

[Not in ROM]

TEToScrap copies the TextEdit scrap to the desk scrap. (warning) You must call the Scrap Manager function ZeroScrap to initialize the desk scrap or clear its previous contents before calling TEToScrap.

1/14/85 Hacker-Withey

/TEXTEDIT/EDIT.R

24

TextEdit Programmer's Guide

Assembly-language note: From assembly language, you can call the Scrap Manager function PutScrap; you can get the values you need from the global variables TEScrpHandle and TEScrpLength.

FUNCTION TEScrapHandle : Handle;

[,Not in ROM]

TEScrapHandle returns a handle to the TextEdit scrap.

Assembly-language note: The global variable TEScrpHandle contains a handle to the TextEdit scrap.

FUNCTION TEGetScrapLen : LONGINT;

[Not in ROM]

TEGetScrapLen returns the size of the TextEdit scrap in bytes.

Assembly-language note: The global variable TEScrpLength contains the size of the TextEdit scrap in bytes.

PROCEDURE TESetScrapLen (length: LONGINT);

[Not in ROM]

TESetScrapLen sets the size of the TextEdit scrap to the given number of bytes.

Assembly-language note: From assembly language, you can set the global variable TEScrpLength.

1/14/85 Hacker-Withey

/TEXTEDIT/EDIT.R

TEXTEDIT ROUTINES

25

Advanced Routines

PROCEDURE TECalText (hTE: TEHandle); TECalText recalculates the beginnings of all lines of text in the edit record specified by hTE, updating elements of the lineStarts array. Call TECalText if you've changed the destination rectangle, the hText field, or any other field that'affects the number of characters per line. (note) There are two ways to specify text to be edited. The easiest method is to use TESetText, which takes an existing edit record, creates a copy of the specified text, and stores a handle to the copy in the edit record. You can instead directly change the hText field of the edit record, and then call TECalText to recalculate the lineStarts array to match the new text. If you have a lot of text, you can use the latter method to save space.

Assembly-language note: The global variable TEReCal contains the address of the routine called by TECalText to recalculate the line starts and set the first and last characters that need to be redrawn. The registers should contain the following: On entry A3: D7: On exit -D2: D3: D4: dereferenced handle to the locked edit record change in the length of the record (word) line start of the line containing the first character to be redrawn (word) position of first character to'be redrawn (word) position of last character to be redrawn (word)

1/14/85 Hacker-Withey

/TEXTEDIT/EDIT.R

26

TextEdit Programmer's Guide

Assembly-language note: The global variable TEDoText contains the address of a multi-purpose text editing 'routine that advanced programmers may find useful. It lets you display, highlight, and hit-test characters, and position the pen to draw the caret. "Hit-test" means decide where to place the insertion point when the user clicks the mouse button; the point selected with the mouse is in the teSelPoint field. The registers should contain the following: On entry A3: D3: D4: D7: dereferenced handle to the locked edit record position of first character to be redrawn (word) position of last character to be redrawn (word) (word) 0 to hit-test a character 1 to highlight the selection range -1 to display the text -2 to position the pen to draw the caret pointer to current grafPort if hit-testing, character position or -1 for none (word)

Caret, drawing routine On entry Variables TEScrpHandle TEScrpLength, TEReCal TEDoText TEReCal routine On entry On exit A3: D7: D2: D3: D4: TEDoText routine On entry A3: D3: D4: D7: dereferenced handle to locked edit record position of first character to be redrawn (word) position of last character to be redrawn (word) (word) ~ to hit-test a character 1 to highlight selection range -1 to display text -2 to position pen to draw caret pointer to current grafPort if hit-testing, character position or -1 for none (word) dereferenced handle to locked edit record change in length of edit record (word) line start of line containing first character to be redrawn (word) position of first character to be redrawn (word) position of last character to be redrawn (word) Handle to TextEdit scrap Size in bytes of TextEdit scrap (long) Address of routine to recalculate line starts (see below) Address of multi-purpose routine (see below) A3: dereferenced handle to locked edit record

On exit

A0: D0:

1/14/85 Hacker-Withey

/TEXTEDIT/EDIT.S

32

TextEdit Programmer's Guide

GLOSSARY ascent: line. The vertical distance from a font's base line to its ascent

ascent line: A horizontal line that coincides with the tops of the tallest characters in a font. base line: A horizontal line that coincides with the bottom of each character in a font, excluding descenders (such as the tail of a "p"). caret: A generic term meaning a symbol that indicates where something should be inserted in text. The specific symbol used is a vertical bar. character position: character. An index into text, starting at 0 for the first In TextEdit, the rectangle in which text is

destination rectangle: d'rawn.

edit record:· A complete editing environment in TextEdit, which includes the text_to be edited, the grafPort and rectangle in which to display the text, the arrangement of the .text within the rectangle, and other editing and display information. insertion point: An empty selection range; the character position where text will be inserted (usually marked with a blinking caret). justification: The horizontal placement of lines of text relative to the edges of the rectangle in which the text is drawn. selection range: The series of characters (inversely highlighted), or the character position (marked with a blinking caret), at which the next editing operation will occur. TextEdit scrap: The place where certain TextEdit routines store the characters most recently cut or copied from text. view rectangle: In TextEdit, the rectangle in which text is visible.

The Dialog Manager is the part of the Macintosh User Interface Toolbox that supports dialog boxes and the alert mechanism. This manual tells you how to manipulate dialogs and alerts with Dialog Manager routines. Summary of significant changes and additions since last draft: - EditText and statText items can't be more than 241 characters long. - A new procedure, SetDAFont, enables Pascal programmers to change the font used in dialogs and alerts (page 19). - There are two new procedures, CouldDialog and FreeDialog, that are analogous to CouldAlert and FreeAlert (page 23). - The description of IsDialogEvent now deals with handling keyboard equivalents of commands when a modeless dialog box is up (page 25). For Pascal programmers, there are also 'four new routines for handling standard editing commands in modeless dialogs (page 26). - For Pascal programmers, there are now routines for checking the stage of an alert and setting an alert back to its first stage (page 32).

ABOUT THIS MANUAL This manual describes the Dialog Manager of the Macintosh User Interface Toolbox. ***. Eventually it will become part of the' comprehensive Inside Macintosh manual. *** The Dialog Manager provides Macintosh programmers with routines for implementing dialog boxes and the alert mechanism, two means of communication between the application and the end user. Like all documentation about Toolbox units, this manual assumes you're familiar with the Macintosh User Interface Guidelines, Lisa Pascal, and the Macintosh Operating System's Memory Manager. You should also be familiar with the following: - resources, as discussed in the Resource Manager manual - the basic concepts and structures behind QuickDraw, particularly rectangles, grafPorts, and pictures - the Toolbox Event Manager, the Window Manager, and the Control Manager - TextEdit, to understand editing text in dialog boxes This manual is i~tended to serve the needs of both Pascal and assemblylanguage programmers. Information of interest to assembly-language programmers only is isolated and labeled so that Pascal programmers can conveniently skip it. The manual begins-with an introduction to' the Dialog Manager and what you can do with it~ It then discusses the basics of dialogs and alerts: their relationship to windows and resources, and the information stored in memory for the items in a dialog or alert. Following this is a discussion of dialog records, where the Dialog Manager keeps all/the information it needs about a dialog, and an ' overview of how alerts are handled. Next, a section on using the Dialog Manager introduces its routines and tells how they fit into the flow of your application program. This is followed by detailed descriptions of all Dialog Manager procedures and functions, their parameters, calling protocol, 'effects, side effects, and so on. . Following these descriptions are sections that will not interest all readers. There's a discussion of how to modify definitions of dialogs and alerts after they've been read from a resource file, and a section that gives the exact formats of resources related to dialogs and alerts. Finally, there's a summary of the Dialog Manager, for quick reference, followed by a glossary of terms used in this manual.
'i

7/6/84 Rose

/DMGR/DIALOG.2

4

Dialog Manager Programmer's Guide

ABOUT THE DIALOG MANAGER The Dialog Manager is a tool for handling dialogs and alerts in a way that's consistent with the Macintosh User Interface Guidelines. A dialog box appears. on the screen when a Macintosh application needs more information to carry out a command. As shown in Figure 1, it typically resembles a form on which the user checks boxes and fills in blanks.

By convention, a dialog box comes up slightly below the menu bar, is a bit narrower than the screen, and is centered between the left and right edges of the screen. It may contain any or all of the following: - informative or instructional text - rectangles in which text may be entered (initially blank or containing default text that can be edited) - controls of any kind - graphics (icons or QuickDraw pictures) - anything else, as defined by the application The user provides the necessary information in the dialog box, such as by entering text or clicking a check box. There's usually a button mar~ed "OK" to tell the application to accept the information provided and perform the command, and a button marked "Cancel" to cancel the command as though it had never been given (retracting all actions since its invocation). Some dialog boxes may use a more descriptive word than "OK"; for simplicity, this manual will still refer to the button as the "OK button". There may even be more than one button that will perform the command, each in a different way.
I

Most dialog boxes require the user-to respond before doing anything else. Clicking a button to perform or cancel the command makes the box go away; clicking outside the dialog box only causes a beep from the Macintosh's speaker. This type is called a modal dialog box because it puts the user in the state or "mode" of being able to work only inside the dialog box. It usually has the same general appearance as shown in 7/6/84 Rose /DMGR/DIALOG.2

ABOUT THE DIALOG MANAGER

5

Figure 1. One of the.buttons in the dialog box may be outlined boldly. Pressing the Return key or the Enter key has the same effect as 'clicking the outlined button or, if none, the OK button; the particular button whose effect occurs is called the dialog's default button and is the preferred ("safest") button to use in the current situation. If there's no boldly outlined or OK button, pressing Return or Enter will by convention have no effect. Other dialog boxes do not require the user to respond before doing anything else; these are called modeless dialog boxes' (Fig~re 2). The user can, for example, do work in document windows on the desktop before clicking a button in the dialog box, and modeless dialog boxes can be set up to respond to the standard editing commands in the Edit menu. Clicking a button in a modeless dialog box will not make the box go away: the box will stay around so that the user can perform the command again. A Cancel'button, if present, will simply stop the action currently being performed by the command; this would be useful for long printing or searching operations, for example.

A Modeless Dialog Box looks like a document active again, or closed with the command and want box or choose Close from

As shown in Figure 2, a modeless dialog box window. It can be moved, made inactive and like any document window. When you're done the box to go away, you can click its close the File menu when it's the active window.

Dialog boxes may in fact require no response at' all. For example, while an application is performing a time-consuming process, it can display a dialog box that contains only a message telling what it's doing; then, when the process is complete, it can simply remove the dialog box. The alert mechanism provides applications with a means of reporting errors or giving warnings. An alert box is similar to a modal dialog box, but it appears only when something has gone wrong or must be brought to the user's attention. Its conventional placement is slightly far.ther below the menu bar than a dialog box. To assist the user who isn't s~re how to proceed when an alert box appears, the preferred button to use in the current situation is outlined boldly so it stands out from the other buttons 'in the alert box (see Figure 3). 'The outlined button is also the alert's default button; if the user presses the Retu~ key or the Enter key, the effect is the same as 7/6/84 Rose /DMGR/DIALOG.2

There are three standard kinds of alerts--Stop, Note, and Caution--each indicated by a particular icon in the top left corner of the alert box. Figure 3 illustrates a Caution alert. The icons identifying Stop and Note 'alerts are similar; instead of a question mark, they show an exclamation point and an asterisk, respectively. Other alerts can have anything in the the top left corner, including blank space if desired. The alert mechanism also provides another type of signal: sound from the Macintosh's speaker. The application can base its response on the number of consecutive times an alert occurs; the first time, it'might ~imply beep, and thereafter it may present an alert box. The sound is not limited to a single beep but may be any sequence of tones, and may occur either alone or along with an alert box. As an error is repeated, there can also be a change in which button is the default button (perhaps from OK to Cancel). '-You can specify different responses for up to four occurrence"s of the same alert. With Dialog Manager routines, you can create dialog boxes or invoke alerts. The Dialog Manager gets most of the descriptive information about the dialogs and alerts from resources in a resource file. You use a program such as the Resource Editor to store the necessary information in the resource file *** (Resource Editor doesn't exist yet; for now, use the Resource Compiler) ***. The Dialog Manager calls the Resource Manager to read what it needs from the resource file into memory as necessary. In some cases you can modify the information after it's been read into memory.

DIALOG AND ALERT WINDOWS A dialog box appears in a dialog window. When you call a Dialog Manager routine to create a dialog, you supply the same information as when you create a window with a Window Manager routine. For example, you supply the window definition ID, which determines how the window looks and behaves, and a rectangle that becomes the portRect of the window's grafPort. You specify the window's plane (which, by convention, should initially be the frontmost) and whether the window is visible or invisible. The dialog window is created as specified.

7/6/84 Rose

/DMGR/DIALOG.2

DIALOG AND ALERT WINDOWS

7

You can manipulate a dialog window just like any other window wi~h Window Manager or QuickDraw routines, showing it, hiding it, -moving it, changing its size or plane, or whatever--all, of course, in conformance with the Macintosh User Interface Guidelines. The Dialog Manager observes the clipping region of the ~ialog window's grafPort, so if you want clipping to occur, you can set this region with a QuickDraw routine. Similarly, an alert box appears in an alert window. You don't have the same flexibility in defining and manipulating an alert window, however. The Dialog Manager chooses the window definition ID, so that all alert windows will have the standard appearance and behavior. The size' and location of the box are supplied as part of the definition of the alert and are not easily changed. You don't specify the al~rt window's plane; it always comes up in front of all other windows. Since an alert box requires the user to respond before doing anything else, and the response makes the box go away, the application doesn't do any manipulation of the alert window. Figure 4 illustrates a document window, dialog window, and alert window, all overlapping on the desktop.

Menu bar end desktop

Document 'til indow on desktop

Dialog window in front of docunent window
Figure 4.

A'Ier1 window in fralt of dialog window

Dialog and Alert Windows

DIALOGS, ALERTS, AND RESOURCES To create a dialog, the Dialog Manager needs the same information about the dialog window as the Window Manager needs when it creates a new window: the window definition ID along with other information specific to this window. The Dialog Manager also needs to know what items the dialog box contains. You can store the needed information as a resource in a resource file and pass the resource ID to a function that 7/6/84 Rose /DMGR/DIALOG.2

8

Dialog Manager Programmer's Guide

will create the dialog. This type of resource, which is called a dialog template, is analogous to a window template, and the function, GetNewDialog, is similar to the Window Manager function GetNewWindow. The Dialog Manager calls the Resource Manager to read the dialog template from the resource file. It then incorporates the information in the template into a dialog data structure in memory, called a dialog record. Similarly, the data that the Dialog Manager needs to create an alert is stored in an alert template in a resource file. The various routines for invoking alerts require the resource ID of the alert template as a parameter. ( The information about all the items (text, controls, or graphics) in a dialog or alert box is stored in an item list in a resource file. The resource ID of'the item list is included in the dialog or alert template •. The item list in turn contains the resource IDs of any icons or QuickDraw pictures in the dialog or alert box, and possibly the resource IDs of control templates for controls in the box. After calling the Resource Manager to read a dialog or alert template into memory, the Dialog Manager calls it again to read in the item list. It then makes a ~opy of the item list and uses that copy; for this reason, item lists should always be purgeable resources. Finally, the Dialog Manager calls the Resource Manager to read in any individual items as necessary.
,

(note) To create dialog or alert templates and item lists and store them in resource files, you can use the Resource Editor' *** (eventually; for now, the Resource Compiler) ***. The Resource Editor relieves you of having to know the exact format of these resources, but for interested programmers this information is given in the section "Formats of Resources for Dialogs, and Alerts". If desired, the application can gain some additional flexibility by calling the Resource Manager directly to read templates, 'item lists, or items from a resource file. For ,example, you can read in a dialog or alert template directly and modify some of the information in it before calling the routine to create the dialog or alert. Or, as an alternative to using a dialog template, you can read in a dialog's item list directly and then pass a handle to it along with other information to a function that will create the dialog (NewDialog, analogous to the Window Manager function NewWiridow). ' (note) The use of dialog templates is recommended wherever possible; like window templates, they isolate descriptive information from your application code for ease of modification or translation to foreign languages.

7/6/84 Rose

/DMGR/DIALOG.2

ITEM LISTS IN MEMORY

9

ITEM LISTS IN MEMORY This section discusses the contents of an item list once it's been read into memory from a resource file and the Dialog Manager has set it up as necessary to be able to work with it. An item list in memory contains the following information for each item: - The type of item. This includes not only whether the item is a control, text, or whatever, but also whether the Dialog Manager should return to the application when the item is clicked. - A handle to the item or, for special application-defined items, a pointer to a procedure that draws the item. - A display rectangle, which determines the location of the item within the dialog or alert box. These are discussed below along with item numbers, which identify particular items in the item list. There's a Dialog Manager procedure that, given a pointer to a dialog record and an item nu~ber, sets or returns that item's type, handle (or procedure pointer), and display rectangle. Item Types The item type is specified by a predefined constant or combination of constants, as listed below. Figure 5 illustrates some of these item types.

A control defined in a control template in a resource file. Static text; text that cannot be edited. (Dialogs only) Text that can be edited; the Dialog Manager accepts text typed by the user and allows editing.
An icon (a 32-by-32 bit image).

iconItem picItem userItem itemDisable+<any of the above>

A QuickDraw picture. (Dialogs only) An application-defined item t such as a picture whbse appearance changes. The item is disabled (the Dialog Manager doesn't report events involving this item).

(warning) StatText and editText items must not be more than 241 characters long. The, text of an 'edi tText item may ini tially be either default text or empty. Text entry and editing is handled in the conventional way, as in TextEdit--in fact t the Dialog Manager calls TextEdit to handle it: - Clicking in the item displays a blinking vertical bar, indicating an insertion point where text may be entered. - Dragging over text in the item selects that text, and doubleclicking selects a word; the selection is inverted and is replaced by what the user then types. - Clicking or dragging while holding down the Shift (key .extends or shortens the current selection. - The Backspace key deletes the current selection or the character preceding the insertion point. The Tab key advances to the next editText item in the item list (wrapping around to the first if there aren't any more). In an alert box or a modal dialog box (regardless of whether it contains an editText item),. the Return key or Enter key has the same effect as clicking the default button; for alerts. the default button is identified in the alert template, whereas for modal dialogs it's always 7/6/84 Rose /DMGR/DIALOG.3

ITEM LISTS IN MEMORY the first item in the item list.

11

If itemDisable is specified for an item, the Dialog Manager doesn't let the application know about events involving that item. For example, you may not have to be informed every time the user types a character or clicks in an editText item, but may only need to look at the text when the OK button is clicked. In this case, the editText item would be disabled. Standard buttons and check boxes should always be enabled, so your application will know when they've been clicked. (warning) Don't confuse disabling a control with making one "inactive" with the Control Manager procedure HiliteControl: When you want a control not to respond at all to being clicked, you make it inactive. Item Handle or Procedure Pointer The item list contains the following information for the of items: Item type any ctrlItem st'atText editText iconItem picltem userItem Contents A control handle A handle to the text A handle to the current text A handle to the icon A picture handle A procedure pointer
var~ous

types

The procedure for a userItem draws the ~tem; for example, if the item is a clock, it will draw the clock with the current time displayed'. When this procedure is called, the current port will have been set by the Dialog Manager to the dialog window's grafPort. The procedure must have two parameters, a window pointer and an item number. For example, this is how it would be declared if it were named MyItem: PROCEDURE MyItem (theWindow: WindowPtr; itemNo: INTEGER); TheWindow is a pointer to the dialog window; in case the procedure dr,aws in more than one dialog window, this parameter tells it which one to draw in. ItemNo is the item number; in case the procedure draws more than one item, this parameter tells it which one to draw. Display Rectangle Each item in the item list is displayed within its display rectangle: - For controls, the display rectangle becomes the control's enclosing rectangle. - For an editText item, it becomes TextEdit's destination rectangle and view rectangle. Word wrap occurs, and the text is clipped if 7/6/84 Rose /DMGR/DIALOG.3

12

Dialog Manager Programmer's Guide there's more than will fit in the rectangle. In addition, the Dialog Manager uses the QuickDraw procedure FrameRect to draw a, rectangle three pixels outside the display rectangle. - StatText items are displayed in exactly the same way as editText items, except that a rectangle isn't drawn outside the display \rectangle. - Icons and QuickDraw pictures are scaled to fit the display rectangle. For pictures, the Window Manager calls the QuickDraw procedure DrawPicture and passes it the display rectangle. -- If the procedure for a userltem draws outside the item's display rectangle, the drawing is clipped to the display rectangle.

(note) Clicking anywhere within the display rectangle is considered a click of that item. By giving an item a display rectangle that's off the screen, you can make the item invisible. This might be useful, for example, if your application needs to display a number of dialog boxes that are similar except that one item is missing or diffe-rent in some of them. You can use a single dialog box in which the item or items that aren't currently relevant are invisible. To remove an item'or make one reappear, you just change its display rectangle (and call the Window Manager procedure InvalRect to accumulate the changed area into' the dialog window's update region). The QuickDraw procedure OffsetRect is convenient for moving an item off the screen and then on again later. Note the following~ however: - You shouldn't make an editText item invisible, because it may cause strange things to happen. If one of several editText items is invisible, for example, pressing the Tab key may make the insertion point disappear. However, if you do' make this type of item invisible,.remember that the changed area includes the rectangle that's three pixels outside the item's display rectangle. - The rectangle for a statText item must always be at least as wide as the first character of the text; a good rule of thumb is to make it at least 20 pixels wide. - To change text in a statText item, it's easier to use the Dialog Manager procedure ParamText (as described later in the "Dialog Manager Routines" section).

7/6/84 Rose

/DMGR/DIALOG.3

ITEM LISTS It! MEMORY

13

Item Numbers Each item in an item list is identified by an item number, which is simply the index of the item in the list (starting from 1). By convention, the first item in an alert's item list should be the OK button (or, if none, then one of the buttons that will perform the command) and the second item should be the Cancel button. The Dialog Manager provides predefined constants equal to the item numbers for OK and Cancel: CONST OK Cancel

= 2;

= 1;

In a modal dialog's item list, the first item is assumed to be the dialog's default button; if the user presses the Return key or Enter key, the Dialog Manager normally returns item number 1, just as when that item is actually clicked. To conform to the Macintosh User Interface Guidelines, the application should boldly outline the dialog's default button if it isn't the OK button. The best way to do this is with a userItem. To allow for changes in the default button's size or location, the userltem shou,ld identify which button to outline by its item number and then use that number to get the button's display rectangle. The following QuickDraw calls will outline the rectangle in the standard way: PenSize(3,3); InsetRect(displayRect,-4,-4); FrameRoundRect(displayRect,16,16) (warning) If the first item in a modal dialog's item list isn't an OK button and you don't boldly outline it, you should set up the dialog to ignore Return and Enter. To learn how to do this, see ModalDialog under "Handling'Dialog ,Events" in the "Dialog Manager Routines" section.

DIALOG RECORDS To create a dialog, you pass information to the Dialog Manager in a dialog template and in individual parameters, or only in parameters; in either case, the Dialog Manager incorporates the information into a dialog record. The dialog record contains the window record for the , dialog window, a handle to the dialog's item list, and some additional fields. The Dialog Manager creates the dialog window by calling the Window Manager function NewWindow and then .setting the window class in the window record to indicate that it's a dialog window. The routine that creates the dialog returns a pointer to the dialog record, which you use thereafter to refer to the dialog in Dialog Manager routines or even in Window Manager or QuickDraw routines (see "Dialog Pointers" below). The Dialog Manager provides routines for handling events in the dialog window and disposing of the dialog when you're done. 7/6/84 Rose /DMGR/DIALOG.3

14

Dialog Manager Programmer's Guide

The data type for a dialog record is called DialogRecord. You can do all the necessary operations on a dialog without accessing the fields of the dialog record directly; for advanced programmers, however, the exact structure of a dialog record is given under "The DialogRecord Data Type" below. Dialog Pointers There are two types of dialog pointer, DialogPtr and DialogPeek, analogous to the window pointer types WindowPtr and WindowPeek. Most programmers will only need .to use DialogPtr.
,

The Dialog Manager defines the following type of dialog pointer: TYPE DialogPtr

= WindowPtr;

It can do this because the first field of a dialog record contains the window record for the dialog window. This type of pointer can be used to access fields of the window record or can be passed to Window Manager routines that expect window pointers as par,ameters. Since the Wind.owPtr data t·ype is itself defined as GrafPtr, this type of dialog pointer can also be used to access fields of-the dialog window's grafPort or passed to QuickDraw routines that expect pointers to grafPorts as parameters. For programmers who want to access dialog record fields beyond the window record, the Dialog Manager also defines the following type of dialog pointer: TYPE DialogPeek = ADialogRecord;

Assembly-language note: From assembly language, of course, 'there's no type checking on pointers, and the two types of pointer are equal.

The DialogRecord Data Type For those who want to know more about the data structure of a dialog record, the exact,structure is given here. TYPE DialogRecord

The window field contains the window record for the dialog window. The items field contains a handle to the item list used for the dialog. (Remember that after reading an item list from a resource file, the Dialog Manager makes a copy of it and uses that copy.) (note) To get or change information about an item in a dialog, you pass the dialog pointer and the item number to a Dialog Manager procedure. You'll never access information directly through the handle to the item list. The Dialog Manager uses the next three fields when there are one or more editText items in the dialog. If there's more than one such item, these fields apply to the one that currently is selected or displays the insertion point. The textH field contains the handle to the edit record used by TextEdit. EditField is 1 less than the item number of the current editText item, or -1 if there's no editText item in the dialog. The editOpen field is used internally by the Dialog Manager. (note) Actually, a single edit record is shared by all editText items; any changes you make. to it will apply to all such items. See the TextEdit manual for details about what kinds of changes you can make. The aDefItem field is used for modal dialogs and alerts, which are treated internally as special mod~l dialogs. It contains the item number of the default button. The default button for a modal dialog is the first item in the item list, so this field contains 1 for modal dialogs. The default button for an alert is specified in the alert template; see the following section for more information.

Assembly-language~:

The global constant dWindLen equals the length of a dialog record in bytes.

ALERTS When you call a Dialog Manager routine to invoke an alert, you pass it the resource ID of the alert template, which contains the following: - A rectangle, given in global coordinates, which determines the alert window's size and location. It becomes the portRect of the window's grafPort. To allow for the menu bar and the. border around the portRect, the top coordinate of the rectangle should be at least 25 points below the top of the screen. - The resource ID of the item list for the alert.

7/6/84 Rose

/DMGR/DIALOG.3

16

Dialog Manager Programmer's Guide - Information about exactly what should ,happen at each stage of the alert.

Every alert has four stages, corresponding to consecutive occurrences of the alert: the first three stages correspond to the first three occurrences, while the fourth s~age includes the fourth occurrence and any beyond the fourth. (The Dialog Manager compares the current alert's resource ID to the last alert's,resource ID to determine whether it's the same alert.) The actions for each stage are specified by the following three pieces of information: - which is the default button--the OK button (or, if·none, a button that will perform the command) or the Cancel button - whether the alert box is to be drawn - which of four sounds should be emitted at this stage of the alert The alert sounds are determined by a sound procedure that emits one of up to four tones or sequences of tones. The sound procedure has one parameter, an integer from 0 to 3; it can emit any sound for each of these numbers, which, identify the sounds in the alert template. For example, you might declare a sound procedure n~med MySound as follows: PROCEDURE MySound (soundNo: INTEGER); If you don~t write your own sound procedure, the Dialog Manager uses the standard one: sound number 0 represents no sound and sound numbers 1 through 3 represent the corresponding number of short beeps, each of the same pitch and duration. The volume 'of each beep depends on the current speaker volume setting, which the user can adjust with the Control Panel desk accessory. If the user has set the speaker volume to 0, the menu bar will blink in place of each beep. For example, if the second stage of an alert is to cause a beep and no alert box, you can just specify the following for that stage in the alert template: don't draw the alert box, and use sound number 1. If instead you want, say, two successive beeps of different, pitch, you need to write a procedure that will emit that sound for a particular sound number, and specify that number in the alert template. The Macintosh Operating System includes routines for emitting sound; see the Sound Driver manual, and also the simple SysBeep procedure in the Operating System Utilities manual *** neither manual currently exists ***. (The st~ndard sound procedure calls SysBeep.) (note) When the Dialog Manager detects a click outside an alert box or a modal dialog box, it emits sound number 1; thus, for consistency with the Macintosh User Interface Guidelines, sound number 1 should always be a single beep. Internally, alerts are treated as special modal dialogs. The alert routine creates the alert window by calling NewDialog. The Dialog 7/6/84 Rose /DMGR/DIALOG.3