jimm@amiga.UUCP (Jim Mackraz) (12/13/85)
Hello net.micro.amiga, and thank you John Draper for forwarding the cause of IntuiEducation. Dale Luck posted a comment on John's main processing loop, but his correction itself was slightly in error. Furthermore, John commits another common error in his example, duplicated below. EXAMPLE 1 ************ John D's example for (;;) { if (message = (struct IntuiMessage *)GetMsg(w->UserPort)) { MessageClass = message->Class; code = message->Code; ReplyMsg(message); switch (MessageClass) { case GADGETUP : case GADGETDOWN : do_gadgets(message, w); break; case CLOSEWINDOW : close_things(); exit(0); break; case MOUSEBUTTONS: break; } /* Case */ } /* if */ } /* for */ COMMENTS ******** As Dale pointed out, a polling loop on the message port is not a proper multitasking way to behave. A more subtle error: note that the message is replied to before its contents is used in do_gadgets(). A general principle (metaphor by bobp) applies: A Message is a license to use a portion of the sender's data space, which no longer applies after the message is Reply'd. In this case, Intuition will reuse the message, its contents will change, and do_gadgets() may be confused, or crashed, if this happens. ** IMPORTANT **** I personally like the way John caches the code of the message, and replies as soon as possible. This might prevent Intuition from allocating another message for this window if it needs to send another, but the savings are marginal. With the exception of the very dangerous MENUVERIFY, REQVERIFY, and SIZEVERIFY messages, it doesn't really matter much if you Reply() before or after you use the data in the message. HOWEVER, be careful about your caching. In particular, IAddress is not guaranteed to hold a reasonable value if it is not defined for the particular class of message. So if you try to stash the Gadget ID ((struct Gadget *)message->IAddress)->GadgetID at the same place John stashes the class and code, and if the class is not GADGETUP or GADGETDOWN, you may get an address error (Guru Meditation 00000003.<your task here>). Check the Intuition Manual for the exact times that IAddress is used and therefore guaranteed vaild. EXAMPLE 2 ************ Dale's correction to busy loop for (;;) { Wait(1<<w->UserPort->mp_SigBit); /* wake up when message there */ if (message = (...... etc. } COMMENTS ******* This demonstrates the spirit of the block-until-message approach, but makes a subtle error: Messages queue, while Signals do not. Therefore, if two messages arrive while you are in the body of the loop, when you Wait() you will not sleep (signal has already been posted with the arrival of the messages), but will process only one message. Next time you Wait(), you will sleep although there is a message in the queue. EXAMPLE 3 ************ What I use. FOREVER /* define as for(;;) in intuition.h */ { if ((msg = (struct IntuiMessage *)GetMsg(window->UserPort)) == NULL) { Wait(1<<window->UserPort->mp_SigBit); continue; } ...... etc. ... } COMMENTS ***** You may feel free to use any flow of control you like, of course. I think I chose this one because it was different than the first solution I saw. GENERAL ***** I want to thank John again for his contributions. Unless I missed something, the remainder of his posting was accurate and clear. I'm the new guy at Amiga Software, and my responsibilities include maintenance and enhancement of Intuition. I welcome all questions and suggestions and comments. We have trouble mailing through ARPAnet gateways, so include your phone number or USnail address, if you might want a direct reply. It is my hope that I can also provide some examples for new Intuition and Amiga application programmers, but time ..., you know. {hplabs,decwr}!pyramid!amiga!jimm