The IDCMP_IDCMPUPDATE scheme presents a problem to an application that wants to make gadgets talk to each other and talk to the application. Boopsi gadgets only have one ICA_TARGET. One Boopsi gadget can talk to either another Boopsi object or its window's IDCMP port, but not both. Using this scheme alone would force the application to update the integer value of the gadgets, which is what we are trying to avoid in the first place. One of the standard Boopsi classes, icclass, is a class of information forwarders. An icclass object receives OM_UPDATE messages from one object and passes those messages on to its own ICA_TARGET. If it needs to map any incoming attributes, it can use its own ICA_MAP to do so. Icclass has a subclass called modelclass. Using a modelclass object, an application can chain a series of these objects together to set up a "broadcast list" of icclass objects. The modelclass object is similar to the icclass object in that it has its own ICA_TARGET and ICA_MAP. It differs in that an application can use the modelclass OM_ADDMEMBER method to add icclass objects to the modelclass object's broadcast list. The OM_ADDMEMBER method is defined by rootclass. It adds one Boopsi object to the personal list of another Boopsi object. It is up to the Boopsi object's class to determine the purpose of the objects in the list. Unlike the other methods mentioned so far in this chapter, OM_ADDMEMBER does not have an Intuition function equivalent. To pass an OM_ADDMEMBER message to an object use the amiga.lib function DoMethodA(), or its stack-based equivalent, DoMethod(): ULONG DoMethodA(Object *myobject, Msg boopsimessage); ULONG DoMethod(Object *myobject, ULONG methodID, ...); The return value is class-dependent. The first argument to both of these functions points to the object that will receive the Boopsi message. For DoMethodA(), boopsimessage is the actual Boopsi message. The layout of it depends on the method. Every method's message starts off with an Msg (from <intuition/classusr.h>): typedef struct { ULONG MethodID; /* Method-specific data may follow this field */ } *Msg; The message that the OM_ADDMEMBER method uses looks like this (from <intuition/classusr.h>): struct opMember { ULONG MethodID; Object *opam_Object; }; where MethodID is OM_ADDMEMBER and opam_Object points to the object to add to myobject's list. DoMethod() uses the stack to build a message. To use DoMethod(), just pass the elements of the method's message structure as arguments to DoMethod() in the order that they appear in the structure. For example, to ask the Boopsi object myobject to add the object addobject to its personal list: DoMethod(myobject, OM_ADDMEMBER, addobject); To rearrange Talk2boopsi.c so that it uses a modelclass object (also known as a model): * Create the integer and prop gadget. * Create the model. * Create two icclass objects, one called int2prop and the other called prop2int. * Make the model the ICA_TARGET of both the integer gadget and the prop gadget. The gadgets do not need an ICA_MAP. * Using DoMethod() to call OM_ADDMEMBER, add the icclass objects to the model's personal list. * Make the prop gadget the ICA_TARGET of int2prop. Make the integer gadget the ICA_TARGET of prop2int. * Create an ICA_MAP map list for int2prop that maps STRINGA_LongVal to PGA_Top. Create an ICA_MAP map list for prop2int that maps PGA_Top to STRINGA_LongVal. Make the ICA_TARGET of the model ICTARGET_IDCMP. Diagrammatically, the new Talk2boopsi.c should look something like this: Figure 12-4: ICC Diagram When either of these gadgets has some interim state change (caused by the user manipulating the gadgets), it sends an OM_UPDATE message to its ICA_TARGET, which in this case is the modelclass object. When this model gets the message, it does two things. It sends an IDCMP_IDCMPUPDATE to the IDCMP port of the gadget's window and it also sends OM_UPDATE messages to all of the objects in its personal list. When int2prop gets an OM_UPDATE message, it forwards that message to its ICA_TARGET, the prop gadget. Similarly, when prop2int gets an OM_UPDATE message, it forwards that message to its ICA_TARGET, the integer gadget. Although in this case it isn't a problem, icclass and modelclass objects contain loop inhibition capabilities. If an icclass object (or modelclass object) receives an OM_UPDATE message, it forwards the message to its target. If somehow that forwarded message gets forwarded (or broadcast) back to the icclass object, the icclass object ignores the message. This prevents the possibility of an infinite OM_UPDATE loop.