Apple II Technical Notes _____________________________________________________________________________ Developer Technical Support Apple IIGS #42: Custom Windows Written by: Dan Oliver & Keith Rollin November 1988 This Technical Note describes custom windows which are now supported with Window Manager version 2.2. This Note supersedes all prior documentation on custom windows. _____________________________________________________________________________ With Window Manager version 2.2 or later, which is available on Apple IIGS System Disk 3.2 and later, you may now define your own type of window or window shape, such as a round or hexagonal window. You also may define a window which performs tasks that would normally be handled by an application. To define your own type of window, a custom window, you must write a routine that performs some window functions. This routine is a window definition procedure (defProc), and in this case it is a custom window defProc. When the Window Manager needs to do something window specific, it calls your defProc. The window defProc is a good part of the Window Manager, and writing one is not an easy task. A window defProc must perform complicated tasks that are very dependent on the state of the machine, and it must be very careful not to disturb the state of the machine. One of the problems in writing a defProc is knowing when it can do something and when it cannot. It is almost impossible to document all of the combinations of calls that you can or cannot make from one part or another of the defProc, and even if all cases were found, the resulting document would read like something from an obscure government bureau and probably be even harder to understand. Now that you know writing a defProc is tough, here's how to make things as easy as possible. Try to understand how the system interacts with the defProc and work with the system. For example, a defProc is called to hit test window parts when the user presses the mouse button. The Window Manager will pass that part back to the defProc to perform drawing while the Window Manager is tracking the pressed button. The defProc could keep control when asked to hit test and perform the tracking itself, but since this is not how the system is designed to work, your defProc will be hard to write, may not ever work correctly, and may break in future versions of the Window Manager. Try to stay on the path outlined in this Technical Note. Also understand that the interface to definition procedures is as general as possible to allow them to perform tasks which are as yet unknown. To allow for this future growth, the outlined path is not always a clear path. Another way to make things easier is to write conservative code. Do not assume things like the data bank being set to something nice when the defProc is called or the caller restoring the direct page pointer upon return if you have changed it. Use caution. A defProc can be very difficult to debug because it is not very linear and can be called when you least expect. Interaction Between the Window Manager and TaskMaster The Window Manager and TaskMaster actually do much less than many people think since window definition procedures perform most of the tasks. The definition procedures handle such things as title bars, information bars, and scroll bars, while the Window Manager and TaskMaster support these things by passing requests to the defProc in standard ways. The Window Manager knows that windows have some shape, overlap, may contain parts, may be invisible, and are created and deleted, but it does not know much else. TaskMaster knows to call GetNextEvent and performs some tasks, but much of what many people consider TaskMaster is contained in the standard document window defProc. In addition to the list mentioned above, the defProc handles calling TrackGoAway and scrolling the content. The remainder of this Note describes what is expected of a defProc and when. Telling the Window Manager About Your Window You tell the Window Manager about your custom window when NewWindow creates it. Instead of passing the parameter list defined in NewWindow, you pass a pointer to a custom window parameter list. A custom window parameter list is defined as follows: paramID WORD ID of parameter list, zero for custom. newDefProc LONG Address of your custom defProc. newData BYTE[n] Additional data defined by your defProc. NewWindow checks the paramID field and calls your defProc with the pointer to the parameter list. See the wNew operation under Calling the Custom DefProc for more information. Once NewWindow creates the window, the Window Manager will always know that it is defined by your defProc. Calling the Custom defProc A window defProc is called with the following items on the stack: 16 |result | LONG - result returned to Window Manager, |___________________________| defined by each operation 14 |windGlobals | LONG - pointer to Window Globals (defined below) |___________________________| 12 |OperationCode| WORD - operation number to be performed |_____________|_____________ 8 |theWindow | LONG - pointer to window's record |___________________________| 4 |param | LONG - pointer to additional parameter |___________________________| defined by each operation 1 | RTL address | BYTE[3] - long return address |____________________|______ | | <-- Stack Pointer | | Figure 1 - Stack Prior to Calling a Window defProc The defProc must return with the carry flag clear if there was no error or with the carry flag set and the y register set with an error code if there was an error. Window globals (windGlobals) is a pointer to a table of variables which the Window Manager maintains for use by the defProc. The table is defined as follows: lineW WORD Width of vertical lines (size depends on video mode). titleHeight WORD Height of a standard title bar. titleYPos WORD Y offset for the title (in system font) to center in a standard title bar. closeHeight WORD Height of the close box icon. closeWidth WORD Width of the close box icon. defWindClr LONG Pointer to the default window color table. windIconFont LONG Handle of the current window icon font. screenMode WORD TRUE if 640 mode, FALSE if 320 mode. pattern BYTE[32] Temporary pattern buffer. callerDpage WORD Direct page pointer of the last caller to TaskMaster. callerDataB WORD Data bank of the last caller to TaskMaster (bank in both bytes). Operation numbers are as follows (each operation is described later in its own section): wDraw 0 Draw the window's frame. wHit 1 Tell in what region the mouse button was pressed. wCalcRgns 2 Calculate wStrucRgn and wContRgn. wNew 3 Complete the creation of a window. wDispose 4 Complete the disposal of a window. wGetDrag 5 Return address that will draw the outline of the window while dragging. wGrowFrame 6 Draw the outline of a window being resized. wRecSize 7 Return size of the additional space needed in the window record. wPosition 8 Return RECT that is the window's portRect. wBehind 9 Return where the window should be placed in the window list. wCallDefProc 10 Generic call to a defProc, defined by the defProc. wDraw, Operation 0 The wDraw operation draws the window's frame and is only called for visible windows. This operation draws in local coordinates in the current GrafPort, which is the Window Manager's GrafPort. When the drawing is finished, the only states of the GrafPort that may have changed are the pen pattern, the fill pattern, and the pen size, as all other states must be the same as when the defProc was called. This means that if you change the font to print some text, you must save and restore the original font. For the pen, PenNormal will restore the pen to an acceptable state. Param is defined as follows: Bit 31 1 to highlight the indicated part, 0 to unhighlight. Bits 0-30 The part to draw (either highlighted or unhighlighted): 0 Draw the window's entire frame, including any frame controls and the items listed below. Note that you should check the window's fHilited flag to determine how to draw the frame. 1 Draw the go-away region. 2 Draw the zoom region. 3 Draw the information bar. Result returned must be zero and the carry flag must be clear. The Window Manager will draw the content. Need to Redraw Your Window? If your custom window defProc gets called to change some item in its window record (see wCallDefProc below), you may want to redraw your window. For instance, if your application makes a SetWTitle call, you would want to draw the name of the new title on the screen. The routine wCallDefProc can call the wDraw routine to do this drawing. However, it should bracket the calls to wDraw with two Window Manager calls that save and restore some internal variables: StartFrameDrawing $5A0E PUSH:LONG Pointer to the window record (not the GrafPort) This call does the setup for drawing a window frame and is only called by a window definition procedure before drawing the frame. You should call EndFrameDrawing when finished drawing. EndFrameDrawing $5B0E No input or output This call restores the Window Manager variables after a call to StartFrameDrawing and is only called by a window definition procedure after drawing a window frame. wHit, Operation 1 The wHit operation is called to hit test the window's frame. Given a set of screen coordinates, this operation should return what part, if any, of the window is at that coordinate. This operation is only called for visible windows. The current port will be that of the Window Manager and the window frame will be in local coordinates. Param is defined as: Bits 0-15 Vertical (Y) coordinate in local coordinates. Bits 16-31 Horizontal (X) coordinate in local coordinates. Result returned must be one of the following values and the carry flag must be clear: wNoHit 0 Not on the window at all. wInDrag 20 Coordinates are in the window's drag region (title bar). wInGrow 21 Coordinates are in the window's grow region (size box). wInGoAway 22 Coordinates are in the window's go-away region (close box). wInZoom 23 Coordinates are in the window's zoom region (zoom box). wInInfo 24 Coordinates are in the window's information bar. wInFrame 27 Coordinates are in the window, but not in any of the other areas. xx Any code the application can handle (bit 15 is reserved for theWindow Manager) wCalcRgns, Operation 2 The wCalcRgns operation, which is called only for visible windows, is used to calculate the window's entire region (frame plus content called StrucRgn) and just its content region (called ContRgn). Both regions must be set to global coordinates, and both will already be allocated with their handles stored in the window record's wStrucRgn and wContRgn fields. Use the portRect and the boundsRect of the window's GrafPort to calculate these two regions. The port will have been set from the information passed to NewWindow along with any size changes. A method for obtaining the global RECT of the content is given below. Refer to the QuickDraw II chapter in the Apple IIGS Toolbox Reference for a full description of ports. When calculating the regions, do not change the clip region (ClipRgn) or the visible region (VisRgn) of the GrafPort. Param is not defined and should not be used. Result returned must be zero and the carry flag must be clear. IN: window = pointer to window record. OUT: rect = global RECT of window's content. ldy #wPort+portRect+y1 lda [