Important: The information in this document is obsolete and should not be used for new development.
Writing a Monitors Extension Function
You create a monitors extension function to implement the feature for your video card and manage the controls that allow the user to set values for that feature. The Monitors control panel calls your monitors extension function, requesting it to perform an action or handle an event in response to the user's manipulation of the controls for your video card. Themessageparameter identifies the action or event.Your monitors extension function should perform the requested action and return a function result to the Monitors control panel. This function result should be either a standard value indicating that your monitors extension function has not allocated memory, a handle to any memory you allocate, or an error code. Here is how you declare a monitors extension function:
FUNCTION MyMntrExt (message, item, numItems: Integer; monitorValue: LongInt; mDialog: DialogPtr; theEvent: EventRecord; screenNum: Integer; VAR screens: ScrnRsrcHandle; VAR scrnChanged: Boolean): LongInt;Themessageparameter can contain any of the values defined by these constants:
CONST startupMsg = 12; {status of user (whether a superuser)} initMsg = 1; {perform initialization} okMsg = 2; {user clicked OK button} cancelMsg = 3; {user clicked Cancel button} hitMsg = 4; {user clicked enabled control} nulMsg = 5; {null event} keyEvtMsg = 9; {keyboard event} updateMsg = 6; {update event}The value of themessageparameter indicates the action your monitors extension function should perform:
In addition, the
startupMsg. Informs your monitors extension function that it has been loaded into memory. Your function can determine whether the user has superuser status by examining theitemparameter. The Monitors control panel sets theitemparameter to 1 if the user is a superuser. Your code should load any resources and modify them if necessary for the capabilities of the computer system or selection of superuser status. You can also allocate memory in response to this message, and store the value identifying the user's status.
initMsg. Requests your monitors extension function to perform initialization.
okMsg. Indicates that the user clicked the OK button. Your function should check for any values the user changed, release any memory it allocated, and return control to the Monitors control panel.
cancelMsg. Indicates that the user clicked the Cancel button. Your function should restore the system to the state it was in before the user clicked the Options button, release any memory it allocated, and return control to the Monitors control panel. If the user modified any values before clicking the Cancel button, reinstate the original values.
hitMsg. Indicates that the user clicked an enabled control in your monitors extension. Your function should handle the click.
nulMsg. Requests your control device function to handle a null event by performing any idle processing. Your monitors extension function should do minimal processing in response to a null event; for example, it should not refresh control settings. The Monitors control panel passes the event record for the null event in the parametertheEvent.
keyEvtMsg. Requests your monitors extension function to handle a key-down or auto-key event.
updateMsg. Requests your monitors extension function to update any user items and redraw any controls that are not standard dialog items handled by the Dialog Manager.
messageparameter can contain any of the values defined by these constants:
CONST activateMsg = 7; {becoming active (not currently used)} deactivateMsg = 8; {becoming inactive (not currently used)} superMsg = 10; {user is a superuser} normalMsg = 11; {user is not a superuser}These messages either are provided for backward compatibility or are not currently used:
activateMsg. Requests your monitors extension function to respond to an activate event by making your video card's controls active. Currently, this message is not used because the Options dialog box is modal. However, your monitors extension function should handle this message as it would any activate event because in future implementations the Options dialog box might be modeless.
deactivateMsg. Requests your monitors extension function to respond to an activate event by making your video card's controls inactive. Currently, this message is not used because the Options dialog box is modal. However, your monitors extension function should handle this message as it would any activate event because in future implementations the Options dialog box might be modeless.
superMsg. Informs your monitors extension function that the user has selected superuser status. This message is provided for backward compatibility with System 6. However, your monitors extension function can respond to it by initializing any controls that you have reserved for superusers, if your function has not already done so in response to either thestartupMsgorinitMsgmessage. If your function does not handle this message, it should return as its function result a handle to any memory it previously allocated. The Monitors control panel sends the messagesuperMsgornormalMsgimmediately following the initialization message.
normalMsg. Informs your monitors extension function that the user has not selected superuser status. This message is provided for backward compatibility with System 6. However, your monitors extension function can respond to it by initializing any controls, if your code has not already done so in response to either thestartupMsgorinitMsgmessage. If your function does not handle this message, it should return as its function result a handle to any memory it previously allocated. The Monitors control panel sends the messagenormalMsgorsuperMsgimmediately following the initialization message.
For a description of the remaining parameters of the monitors extension function, see "Monitors Extension Functions" beginning on page 8-79.
- IMPORTANT
- If your monitors extension function cannot handle a message, it should return as its function result a handle to any memory it previously allocated. Otherwise, it should return the value passed in the
monitorValueparameter.
Your monitors extension function can return either an error code or a handle to memory it allocated. Each time the Monitors control panel calls your monitors extension function, the
monitorValueparameter contains the value that your function returned as its function result the last time it was called.If an error occurs, your monitors extension function should display an error dialog box and then return a value between 1 and 255. If your function returns a value in this range, the Monitors control panel closes the Options dialog box immediately and does not call your monitors extension function again.
The monitors extension used as an example in this chapter adds controls to the Options dialog box for a video card called SurfBoard. The Magnify Enabled checkbox allows the user to magnify the display of text and graphics on the monitor connected to the SurfBoard video card. The SurfBoard monitors extension also includes controls for superusers, which illustrate how to implement the rectangle extension in which
the superuser controls are displayed. The SurfBoard monitors extension shows one way of handling messages from the Monitors control panel.Listing 8-25 shows the SurfBoard monitors extension function,
MyMonExtend. It includes aCASEstatement that handles messages that the Monitors control panel passes toMyMonExtend. First the function sets up a handle for memory that it allocates in response to the startup message. The function returns a handle to the storage it allocates as its function result in response to the startup message, unless an error occurs (see Listing 8-26 on page 8-66). For all subsequent messages, the Monitors control panel passes, in themonitorValueparameter, the previous function result. TheMyMonExtendfunction returns the handle to the allocated memory as its function result for any messages that it does not handle.Listing 8-25 A monitors extension function
UNIT SurfBoardMonExt; INTERFACE {include a Uses statement if your programming environment requires it} CONST kTextItem = 1; {static text item} kSuperUserDivLine = 2; {separation line} kFilterControl = 4; {radio button filter} kAntiAliasingCntl = 5; {radio button aliasing} kMagnifyControl = 6; {checkbox for Magnify Enabled} kMemErrAlert = 130; {resource ID of out-of-memory alert box} kdeepAlert = 131; {resource ID of alert box} kResID = 133; {all other errors} TYPE MonitorDataRec = RECORD {local data for the extension} isSuperUser: Boolean; filteringSetting: Integer; oldFiltering: Integer; toggleMagnifyValue: Integer; END; MonitorDataPtr = ^MonitorDataRec; MonitorDataHandle = ^MonitorDataPtr; MyRectHandle = ^RectPtr; MyIntPtr = ^Integer; MyIntHandle = ^MyIntPtr; FUNCTION MyMonExtend (message, item, numItems: Integer; monitorValue: LongInt; mDialog: DialogPtr; theEvent: EventRecord; ScreenNum: Integer; VAR Screens: ScrnRsrcHandle; VAR ScrnChanged: Boolean): LongInt; IMPLEMENTATION {any support routines your monitors extension function uses} PROCEDURE MyHandleStartupMsg(item: Integer; mDialog: DialogPtr; VAR monitorValue: LongInt); FORWARD; PROCEDURE MyHandleInitMsg(numItems: Integer; mDialog: DialogPtr; dataRecHand: MonitorDataHandle); FORWARD; PROCEDURE MyDrawRect(theWindow: WindowPtr; itemNo: Integer); FORWARD; FUNCTION MySetUpData (superUser: Integer; storage: MonitorDataHandle): OSErr; FORWARD; PROCEDURE MyHandleHits (mDialog: DialogPtr; whichItem, numItems: Integer; dataRecHand: MonitorDataHandle); FORWARD; PROCEDURE MySaveNewValues (dataRecHand: MonitorDataHandle); FORWARD; PROCEDURE MyUndoChanges (item, numItems: Integer; mDialog: DialogPtr; dataRecHand: MonitorDataHandle); FORWARD; FUNCTION MyMonExtend (message, item, numItems: Integer; monitorValue: LongInt; mDialog: DialogPtr; theEvent: EventRecord; ScreenNum: Integer; VAR Screens: ScrnRsrcHandle; VAR ScrnChanged: Boolean): LongInt; VAR dataRecHand: MonitorDataHandle; BEGIN IF message <> startupMsg THEN dataRecHand := MonitorDataHandle(monitorValue); {set up handle} CASE message OF startupMsg: MyHandleStartupMsg(item, mDialog, monitorValue); initMsg: MyHandleInitMsg(numItems, mDialog, dataRecHand); hitMsg: MyHandleHits(mDialog, item, numItems, dataRecHand); okMsg: MySaveNewValues(dataRecHand); cancelMsg: MyUndoChanges(item, numItems, mDialog, dataRecHand); END; {of CASE} MyMonExtend := monitorValue;{return value with handle} END; {MyMonExtend}Handling the Startup Message
After the code in your monitors ('mntr') code resource is loaded and before the Monitors control panel finds any resources to which your monitors extension function refers, the Monitors control panel calls your function with a startup (startupMsg) message. If the user is a superuser, the Monitors control panel sets theitemparameter to 1 for the startup message.The startup message requests your monitors extension function to load and modify any resources that must allow for the capabilities of the computer or for superusers. For example, your monitors extension function should modify the rectangle resource if the user is a superuser.
In response to a startup message, your function can also create a handle and allocate any memory that it needs to store values between calls from the Monitors control panel. For example, if your function initializes its controls in response to the initialization (
initMsg) message, it should store a value indicating whether or not the user is a superuser. When the Monitors control panel calls your monitors extension function with an initialization message, theitemparameter no longer indicates the user's status. If your code allocates memory, your function should return as its function result a handle to the memory it allocates in response to the startup message, unless an error occurs. If an error occurs, your function can display an error dialog box and return a function result of 255, indicating an error condition. Listing 8-26 shows how theMyMonExtendfunction handles the startup message.Listing 8-26 Handling the startup message
PROCEDURE MyHandleStartupMsg (item: Integer; mDialog: DialogPtr; VAR monitorValue: LongInt); VAR dataRecHand: MonitorDataHandle; result: OSErr; i: Integer; BEGIN {allocate memory to store data} dataRecHand := MonitorDataHandle(NewHandle(sizeof(MonitorDataRec))); IF dataRecHand <> NIL THEN BEGIN result := MySetUpData(item, dataRecHand); IF result = noErr THEN monitorValue := LongInt(dataRecHand) ELSE {error function result stops any further action} monitorValue := result; END ELSE BEGIN {dataRecHand not allocated} i := StopAlert(kMemErrAlert, NIL); {error function result stops any further action} monitorValue := 255; END; END;If your function returns an error in response to the startup message, the Monitors control panel does not display the Options dialog box. Your code can display an alert box describing the error before returning control to the Monitors control panel.
- Allocating Storage in Response to the Initialization Message
- If your monitors extension function does not allocate memory in response to a startup message, it can do so in response to an initialization message, and then use the superuser (
superMsg) or the normal user (normalMsg) message to initialize control values and user items, if any. The Monitors control panel does not display the Options dialog box until after your monitors extension function returns from either of these messages.
After it allocates storage, the function shown in Listing 8-26 calls its own
MySetUpDatafunction to check the value of theitemparameter. This value indicates whether the user has selected superuser status.Listing 8-27 shows the
MySetUpDatafunction. If the user is not a superuser, the SurfBoard monitors extension uses the default values for the rectangle resource. (This rectangle ends just before the dividing line, so that the superuser controls are not displayed.) If the user is a superuser,MySetUpDataextends the rectangle in the rectangle ('RECT') resource to include all of the controls in the item list resource ('DITL') resource. If an error occurs, the function notifies the user and returns an error code value of 255 as its function result.Listing 8-27 Using a normal user rectangle or extending it to display superuser controls
FUNCTION MySetUpData(superUser: Integer; storage: MonitorDataHandle): OSErr; VAR magnifyHdl: Handle; intensityLevelHdl: Handle; resHandle: Handle; i: Integer; result: OSErr; BEGIN result := noErr; HLock(Handle(storage)); WITH storage^^ DO BEGIN {open preferences file first if needed} magnifyHdl := GetResource('MAGN', kResID); IF magnifyHdl <> NIL THEN BEGIN toggleMagnifyValue := MyIntHandle(magnifyHdl)^^; ReleaseResource(magnifyHdl); END; IF superUser = 1 THEN BEGIN isSuperUser := TRUE; intensityLevelHdl := GetResource('INTE', kResID); IF intensityLevelHdl <> NIL THEN BEGIN oldFiltering := MyIntHandle(intensityLevelHdl)^^; filteringSetting := oldFiltering; ReleaseResource(intensityLevelHdl); resHandle:= GetResource('RECT', -4096); IF resHandle <> NIL THEN RectHandle(resHandle)^^.top := -160 ELSE result := 255 END ELSE result := 255; END {of superuser = 1} {close preferences file} END; {of WITH} IF result = 255 THEN BEGIN DisposeHandle(Handle(storage)); i := StopAlert(kdeepAlert, NIL); END; HUnlock(Handle(storage)); MySetUpData := result; END;Performing Initialization
Before it displays the Options dialog box and after it has located any resources that your monitors extension includes, such as gamma table ('gama') resources, the Monitors control panel calls your monitors extension function with aninitMsgmessage. When your monitors extension function receives this message, it should set default values for controls. To handle this message, your function can initialize the settings of its controls. If it hasn't already allocated memory in response to the startup message, your function can allocate memory when it performs initialization. The Monitors control panel calls your monitors extension with an initialization message after the startup message and before either the superuser or normal message.If your function returns an error in response to the
initMsgmessage, the Monitors control panel does not display the Options dialog box. Your function can display an alert box describing the error before returning control to the Monitors control panel.Listing 8-28 shows the
MyHandleInitMsgprocedure, which theMyMonExtendfunction calls to handle the initialization message. FirstMyHandleInitMsgsets its controls to their initial values;MyHandleInitMsgcalls the Dialog Manager'sGetDialogItemand the Control Manager'sSetControlValueprocedures for this purpose. Then, if the user is a superuser, the procedure installs the procedure that draws the dividing line between the normal controls and superuser controls, then initializes the settings of its superuser controls.Listing 8-28 Initializing a monitors extension
PROCEDURE MyHandleInitMsg (numItems: Integer; mDialog: DialogPtr; dataRecHand: MonitorDataHandle); VAR itemType: Integer; itemHandle: Handle; itemRect: Rect; BEGIN GetDialogItem(mDialog, numItems+kMagnifyControl, itemType, itemHandle, itemRect); SetControlValue(ControlHandle(itemHandle), (dataRecHand^^.toggleMagnifyValue)); IF dataRecHand^^.isSuperUser THEN BEGIN GetDialogItem(mDialog, numItems+kSuperUserDivLine, itemType, itemHandle, itemRect); SetDialogItem(mDialog, numItems+kSuperUserDivLine, itemType, @MyDrawRect, itemRect); IF dataRecHand^^.oldFiltering = 0 THEN GetDialogItem(mDialog, numItems+kAntiAliasingCntl, itemType, itemHandle, itemRect) ELSE GetDialogItem(mDialog, numItems+kFilterControl, itemType, itemHandle, itemRect); SetControlValue(ControlHandle(itemHandle), 1); END; END;Listing 8-29 shows theMyDrawRectprocedure, which draws the line dividing superuser controls from other controls. TheMyDrawRectprocedure uses theFrameRectprocedure to draw a 1-pixel-high rectangle. Note thatMyDrawRectspecifies the coordinates for the dividing line in the coordinate system used by its rectangle ('RECT') resource. If you wish, you can draw this line in a gray pattern so that it looks similar to the dividers in menus. (For information on theFrameRectprocedure, see Inside Macintosh: Imaging with QuickDraw.)Listing 8-29 Drawing a line to separate superuser controls
PROCEDURE MyDrawRect (theWindow: WindowPtr; itemNo: Integer); VAR itemType: Integer; itemHdl: Handle; itemRect: Rect; BEGIN GetDialogItem(theWindow, itemNo, itemType, itemHdl, itemRect); FrameRect(itemRect); END;Responding to a Click in the OK Button
The Monitors control panel calls your monitors extension function with an OK (okMsg) message when the user clicks the OK button. The OK button is a standard control defined for the Options dialog box by the Monitors control panel. When the user clicks the OK button, the Monitors control panel hides the Options dialog box.This message is a signal to put user preferences into effect. You should not make any changes requested by the user irreversible until you receive this message. This is your last chance to check the values of any controls or editable text items that the user might have changed. Your monitors extension function should update the resources in which it saves values; it should also make any hardware changes necessary. Your function should release any memory it has allocated before returning control to the Monitors control panel.
The
MyMonExtendfunction (see Listing 8-25 on page 8-64) calls its ownMySaveNewValuesprocedure to handle an OK message from the Monitors control panel. This procedure checks if the user has changed the setting of the Magnify Enabled checkbox. If the user is a superuser, it also checks the values of the Anti-Aliasing and Zirconian Filtration radio buttons. If the user changed values,MyMonExtendwrites the values to its preferences file, which is stored in the Preferences folder, and releases any memory it has allocated before it returns to the Monitors control panel.Responding to a Cancel Request
When the user clicks the Cancel button, the Monitors control panel calls your monitors extension function with a cancel (cancelMsg) message. The Cancel button is a standard control defined for the Options dialog box by the Monitors control panel. To handle the cancel request, your monitors extension function should restore the system to its former state, before the user clicked the Options button; release any memory it allocated; and return control to the Monitors control panel. If your function modified any values the user specified before clicking the Cancel button, reinstate the original values.Handling Mouse Events for a Monitors Extension
When the user clicks any active enabled control that your monitors extension defined for the Options dialog box, system software generates mouse events. The Monitors control panel intercepts these events and passes them to your monitors extension function as ahitMsgmessage. Your monitors extension function typically changes the setting of the control or performs the appropriate action in response to ahitMsgmessage.Along with the
hitMsgmessage, the Monitors control panel passes three values that your monitors extension function uses to determine which item the user clicked.
The Monitors control panel appends the items you define in your monitors extension item list to the item list for the standard controls in the Options dialog box. Therefore, to get the actual number of your item, subtract
- In the
itemparameter, the number of the item clicked. This is not the number you assign in your item list, but the number after the Monitors control panel appends your item list to the item list of the Options dialog box.- In the
numItemsparameter, the number of items in the item list of the standard Options dialog box.- In the parameter
theEvent, the event record for the mouse event that generated thehitMsgmessage.
numItemsfromitem.Listing 8-30 shows the
MyHandleHitsprocedure, whichMyMonExtendcalls to handle ahitMsgmessage. This procedure determines the item number of the clicked control, as defined in the monitors extension's item list resource. It does this by subtracting the number of items in the item list of the Options dialog box (numItems) from the item the user clicked (whichItem) to get the correct item number. ThenMyHandleHitscalls the Dialog Manager'sGetDialogItemprocedure and the Control Manager'sSetControlValueprocedure to set the control to the new value indicated by the user.Listing 8-30 Responding when a user clicks a control
PROCEDURE MyHandleHits (mDialog: DialogPtr; whichItem, numItems: Integer; dataRecHand: MonitorDataHandle); VAR itemType: Integer; itemHandle: Handle; itemRect: Rect; BEGIN HLock(Handle(dataRecHand)); WITH dataRecHand^^ DO BEGIN CASE whichItem - numItems OF kFilterControl: BEGIN GetDialogItem(mDialog, whichItem, itemType, itemHandle, itemRect); SetControlValue(ControlHandle(itemHandle),1); GetDialogItem(mDialog, numItems+kAntiAliasingCntl, itemType, itemHandle, itemRect); SetControlValue(ControlHandle(itemHandle),0); filteringSetting := 1; END; kAntiAliasingCntl: BEGIN GetDialogItem(mDialog, numItems+kFilterControl, itemType, itemHandle, itemRect); SetControlValue(ControlHandle(itemHandle),0); GetDialogItem(mDialog, whichItem, itemType, itemHandle, itemRect); SetControlValue(ControlHandle(itemHandle),1); filteringSetting := 0; END; kMagnifyControl: BEGIN GetDialogItem(mDialog, whichItem, itemType, itemHandle, itemRect); toggleMagnifyValue := 1 - toggleMagnifyValue; SetControlValue(ControlHandle(itemHandle), toggleMagnifyValue); END; END; {end of CASE} END; HUnlock(Handle(dataRecHand)); END;Handling Keyboard Events
The Monitors control panel intercepts all key-down and auto-key events for your monitors extension and sends your monitors extension function a keyboard event through thekeyEvtMsgmessage. The Monitors control panel passes, in the parametertheEvent, the event record for the keyboard event. If your monitors extension includes an editable text item and the user issues a Cut, Copy, or Paste command using the Command-key equivalent, the Monitors control panel passes this event to your monitors extension function in the event record.
 
  
  
 