The following code, RKMModel.c, makes up an initialization function and the dispatcher function for a private class informally called rkmmodelclass. RKMModel.c Below is a diagram showing how an application could use an rkmmodelclass object: Figure 12-5: Rkmmodelclass Object Diagram In this diagram, the application uses buttongclass Boopsi gadgets to send the rkmmodelclass the RKMMOD_Up and RKMMOD_Down attribute pulses. The example takes advantage of an odd feature of buttongclass. When the user clicks on a buttongclass gadget, it sends an OM_UPDATE to its ICA_TARGET, even though no Boopsi attribute of buttongclass has changed. It does this because it's a convenient way to report button clicks. Whenever a gadget sends a notification, the list of attribute/value pairs in the OM_NOTIFY message always contains the gadget's GA_ID. This is an easy way for the button to inform its target of its ID so the target knows which gadget sent the OM_UPDATE message. When a buttongclass sends a notification because of a button click, it only sends out an OM_UPDATE about its GA_ID because none of its attributes changed. When the user clicks one of the buttons in the rkmmodelclass diagram, the button uses an ICA_MAP to map its GA_ID to one of the "dummy" pulse attributes, RKMMOD_Up and RKMMOD_Down. When the rkmmodel receives the OM_UPDATE message about RKMMOD_Up or RKMMOD_Down, it increments or decrements its internal value. There is one more important thing to note about rkmmodelclass. Looking at the rkmmodelclass Object diagram above, an rkmmodel's RKMMOD_CurrVal changes because it received an OM_UPDATE message from one of its gadgets. RKMMOD_CurrVal can also change if the application explicitly set RKMMOD_CurrVal using SetAttrs() or SetGadgetAttrs(). The primary difference between the OM_SET message that SetAttrs() sends and the OM_SET message that SetGadgetAttrs() sends is that SetAttrs() passes a NULL in opSet.ops_GInfo instead of a GadgetInfo pointer. This doesn't present a problem for the rkmmodel object, because it doesn't use the GadgetInfo structure. The problem is that when the rkmmodel notifies its targets, some of which are gadgets, they can't update their visual state because they need a GadgetInfo to render themselves. For this reason, the rkmmodelclass dispatcher returns a positive non-zero value when an attribute change occurs that could cause a change in the visual state of any objects in its broadcast list. An application that uses rkmmodelclass must test the return value when calling SetAttrs() on an rkmmodelclass object to tell if the attribute change requires a visual refresh of the gadgets (see the Intuition Autodocs for RefreshGadgets()). Boopsi Dispatchers Can Execute on Intuition's Context. ------------------------------------------------------ Notice that the gadgets in the figure above send OM_UPDATE messages to the rkmmodel when the user manipulates them. Because Intuition handles the user input that triggers the OM_UPDATE messages, Intuition itself is sending the OM_UPDATE messages. This means the rkmmodelclass dispatcher must be able to run on Intuition's context, which puts some limitations on what the dispatcher is permitted to do: it can't use dos.library, it can't wait on application signals or message ports, and it can't call any Intuition functions which might wait on Intuition. Although rkmmodelclass serves as an example of a class, it leaves a little to be desired in a real-world implementation. To create the "prop-integer-up/down" super gadget from the diagram above, the application has to create, initialize, and link nine Boopsi objects, which is tedious, especially if the application needs several of these super gadgets. Ideally, all these functions would be rolled into some subclass of gadgetclass. If there were such a class, an application would only have to create one instance of this subclass to get such a gadget. When the subclass received an OM_NEW message, it would take care of creating, initializing, and linking all of the Boopsi objects that make up the whole super gadget.