"earthrexx.library" DOCUMENTATION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MAKING USE OF AN IDCMP LOOP ~~~~~~~~~~~~~~~~~~~~~~~~~~~ ===================================================================== What is an IDCMP loop? ~~~~~~~~~~~~~~~~~~~~~~ Most Intuition-based programs will have as their central core something called an "IDCMP" loop. An IDCMP is a message port which Intuition makes use of. (IDCMP stands for Intuition Direct Communication Message Port). An IDCMP loop, then, is a loop which repeatedly processes Intuition messages. Since an Intuition message (a struct IntuiMessage) can represent anything from a key press to a menu selection to a gadget selection, the IDCMP loop forms the main loop of many an Amiga program. A typical IDCMP loop, written in 'C', might look like this: for (;;) { Wait(1<UserPort->mp_SigBit); while (Message = GetMsg(Window->UserPort)) { /* Process one intuition message here */ } } The above example assumes Window is a pointer to a struct Window. There are variations on the above theme. For instance, sometimes you might have an IDCMP which is shared across several Windows, or even which doesn't HAVE a window - in such cases you can replace both occurances of Window->UserPort with a pointer to the MsgPort. One thing an IDCMP CANNOT do, however, is recieve ARexx messages. This is because ARexx messages have a structure very different from an IntuiMessage. This is why you also need a RexxPort - the IDCMP collects the IntuiMessages, while the RexxPort collects the RexxMsgs. To manage two ports instead of just one requires a small variation on the above loop, as follows: ===================================================================== Modifying the IDCMP loop ~~~~~~~~~~~~~~~~~~~~~~~~ The first trick involves fiddling with the Wait() call. Instead of doing everything in one line, you split it into two lines, so it becomes: waitmask = 1<UserPort->mp_SigBit; Wait(waitmask); It is easy to see that the above two lines are functionally identical to the original single line (provided you declare waitmask as a ULONG). Next you insert a new line between the above two, to get: waitmask = 1<UserPort->mp_SigBit; if (RexxPort) waitmask |= RexxPort->rp_WaitMask; Wait(waitmask); (assuming that RexxPort is a pointer to a struct RexxPort). The "if (RexxPort)" bit ensures that if your application runs on a machine which does not have ARexx then the waitmask will be unmodified, and so the application will behave exactly as it would have done without the ARexx interface. Otherwise, additional bits are set in the waitmask. When this is used as a parameter for Wait(), the upshot is that there are additional circumstances in which your application will wake up - namely, the arrival of a RexxMsg at the RexxPort. Now you call ProcessRexx() to deal with it. The fully modified IDCMP loop will probably end up looking something like this: for (;;) { waitmask = 1<UserPort->mp_SigBit; if (RexxPort) waitmask |= RexxPort->rp_WaitMask; Wait(waitmask); ProcessRexx(RexxPort); while (Message = GetMsg(Window->UserPort)) { /* Process one intuition message here */ } } Notice that the Wait() call will wake up when EITHER one or more Rexx messages OR one or more Intuition messages show up (or BOTH). If only a Rexx message turns up then the "while (Message = GetMsg(Window->UserPort))" loop will be a null loop, since the while condition will fail. If only an Intuition message turns up then ProcessRexx() will find an empty message port and return immediately. Lastly, notice that I used "ProcessRexx(RexxPort)" rather than "if (RexxPort) ProcessRexx(RexxPort)". This is because the function ProcessRexx() is quite tolerant about being passed a NULL pointer (as are ALL of the "earthrexx.library" functions which require a pointer to a RexxPort, including CloseRexxPort())! And incidently, since ProcessRexx() is written in machine code, it can test for NULL faster than you can in 'C' anyway. =====================================================================