[comp.sys.amiga.programmer] Window Waiting

markv@kuhub.cc.ukans.edu (05/24/91)

> Currently I am delaying by Delay(60) and then checking the windows message
> port for a message, outputting my info, then looping back to the Delay.
> ... 
> So the basic idea is, how can I start a timed event that will pump a signal
> to me when it completes, so that I can have the program waiting for a signal
> from that timer or from the window message port...hence if the user clicks
> on the close gadget, it immediately can respond ?

There are two solutions.  One, if you only wan't to update the display
when your window is active, and if you aren't real picky about
precision, try INTUITICKS messsage.  I do this to update a clock
counter, recheck memory, like this:

    while(!QuitFlag) {
	WaitPort(MyWindow->UserPort);
	while ((MyMsg = GetMsg(MyWindow->UserPort)) != NULL) {
	    switch(MyMsg->Class) {
		case INTUITICK:
			if((TickCount++) % 10) == 0) {
				DoUpdateStuff();
			}
			break;
		case CLOSEWINDOW:
			QuitFlag = FALSE;
			break;
		/* ... etc ... */
	    }
	    ReplyMsg(MyMsg);
	}
    }	

Intuiticks arrive roughly 10 per second when your window is active.
Also, Intuition only sends one at a time, so you dont get a 2nd
Intuitick until you reply the 1st.  The catch is they aren't very
precise, and dont' get sent if your window isn't active.  But they are
good for "kicker" events.

If you need more precision, or events when you window is inactive, or
really *only* want to wake up once per second, then you'll have to use
the timer.device and set up 1 second timer requests.  Then you can
wait on the Bitwise or of the signal bits for the timer reply port and
the window's port like this:

#define BIT(x)	(1L << x)
ULONG	WakeupMask;
#define WindowBit BIT(MyWindow->UserPort->mp_Sigbit)
#define TimerBit  BIT(TimerReplyPort->mp_Sigbit)

WakeupMask = Wait(WindowBit | TimerBit); 

if (WakeupMask & WindowBit) {
	/* Do IDCMP stuff */
}
if (WakeupMask & TimerBit) {
	/* Do update stuff */
}

This way you will get awakened by the timer IO coming back, meaning
your time is expired, or by a window event.  You must check the
WakeupMask for ALL bits you've used, since it is possible (and likely
sooner or later) that you will get awakend by more than just one of
the possibilities.

> Assembly or C answers....

Hope this helps.  I won't get into all the details of the timer device
stuff unless you ask.  Also, this is off the top of my head at work,
so excuse minor errors in names or case.
 
> Thanks,
> 
> Robert Lang.
For now,

-- 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Mark Gooderum			Only...		\    Good Cheer !!!
Academic Computing Services	       ///	  \___________________________
University of Kansas		     ///  /|         __    _
Bix:	  mgooderum	      \\\  ///  /__| |\/| | | _   /_\  makes it
Bitnet:   MARKV@UKANVAX		\/\/  /    | |  | | |__| /   \ possible...
Internet: markv@kuhub.cc.ukans.edu
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

milamber@caen.engin.umich.edu (Daryl Cantrell) (05/25/91)

In article <1991May24.092943.31027@kuhub.cc.ukans.edu> markv@kuhub.cc.ukans.edu writes:
[...]
>#define BIT(x)	(1L << x)
>ULONG	WakeupMask;
>#define WindowBit BIT(MyWindow->UserPort->mp_Sigbit)
>#define TimerBit  BIT(TimerReplyPort->mp_Sigbit)
>
>WakeupMask = Wait(WindowBit | TimerBit); 
>
>if (WakeupMask & WindowBit) {
>	/* Do IDCMP stuff */
>}
>if (WakeupMask & TimerBit) {
>	/* Do update stuff */
>}
[...]

  This is close, but there is one problem.  From 1.3 AutoDocs, exec.library/
WaitPort : "It is possible to get a signal for a port WITHOUT a message
showing up.  Plan for this.".  What I usually do is something like:

struct Message *Msg;

FOREVER
   {
   Wait(WindowBit | TimerBit);
   while (Msg = GetMsg(MyWindow->UserPort))
      DoIDCMP(Msg);
   while (Msg = GetMsg(TimerReplyPort))
      DoTimer(Msg);
   }

>Mark Gooderum			Only...		\    Good Cheer !!!
>Internet: markv@kuhub.cc.ukans.edu


--
+---------------------------------------+----------------------------+
|   // Daryl S. Cantrell                |   These opinions are       |
| |\\\ milamber@caen.engin.umich.edu    |    shared by all of    //  |
| |//  Evolution's over.  We won.       |        Humanity.     \X/   |
+---------------------------------------+----------------------------+

bj@cbmvax.commodore.com (Brian Jackson) (05/25/91)

In article <1991May24.092943.31027@kuhub.cc.ukans.edu> markv@kuhub.cc.ukans.edu writes:
>
>There are two solutions.  One, if you only wan't to update the display
>when your window is active, and if you aren't real picky about
>precision, try INTUITICKS messsage.  I do this to update a clock
>counter, recheck memory, like this:
>
>    while(!QuitFlag) {
>	WaitPort(MyWindow->UserPort);
>	while ((MyMsg = GetMsg(MyWindow->UserPort)) != NULL) {
>	    switch(MyMsg->Class) {
>		case INTUITICK:
>			if((TickCount++) % 10) == 0) {
>				DoUpdateStuff();
>			}
>			break;
>		case CLOSEWINDOW:
>			QuitFlag = FALSE;
>			break;
>		/* ... etc ... */
>	    }
>	    ReplyMsg(MyMsg);
>	}
>    }	
>
>Mark Gooderum

The only change that I would make to this is that the ReplyMsg() call
should come much sooner.  Let Intuition have it's message back asap.

	ULONG class ;

	...

	while((MyMsg = GetMsg(MyWindow->UserPort)) != NULL) {
		class = MyMsg->Class ;   /* make a local copy */
		ReplyMsg(MyMsg) ;        /* reply asap        */
		switch(class) {
			...
		}
	}

If 'DoUpdateStuff()' is large, you hang onto Intuition's message
for a long time. If Intuition can't find an existing message to use
for the NEXT thing it wants to send to you, it will allocate memory
for a new one rather than use one already in existance. 

Brian

 -----------------------------------------------------------------------
/ Brian Jackson  Software Engineer, Commodore-Amiga Inc.    GEnie: B.J. \
\ bj@cbmvax.cbm.commodore.com      or     ...{uunet|rutgers}!cbmvax!bj  /
/ "Anyone considering the purchase of a high-end Macintosh or IBM-      \
\ compatible computer should try an Amiga 3000 for a few hours before   /
/ making the final decision." - Consumer Reports ('91 Buying Guide)     \
-------------------------------------------------------------------------

mykes@amiga0.SF-Bay.ORG (Mike Schwartz) (05/27/91)

In article <21912@cbmvax.commodore.com> bj@cbmvax.commodore.com (Brian Jackson) writes:
>In article <1991May24.092943.31027@kuhub.cc.ukans.edu> markv@kuhub.cc.ukans.edu writes:
>>
>>There are two solutions.  One, if you only wan't to update the display
>>when your window is active, and if you aren't real picky about
>>precision, try INTUITICKS messsage.  I do this to update a clock
>>counter, recheck memory, like this:
>>
>>    while(!QuitFlag) {
>>	WaitPort(MyWindow->UserPort);
>>	while ((MyMsg = GetMsg(MyWindow->UserPort)) != NULL) {
>>	    switch(MyMsg->Class) {
>>		case INTUITICK:
>>			if((TickCount++) % 10) == 0) {
>>				DoUpdateStuff();
>>			}
>>			break;
>>		case CLOSEWINDOW:
>>			QuitFlag = FALSE;
>>			break;
>>		/* ... etc ... */
>>	    }
>>	    ReplyMsg(MyMsg);
>>	}
>>    }	
>>
>>Mark Gooderum
>
>The only change that I would make to this is that the ReplyMsg() call
>should come much sooner.  Let Intuition have it's message back asap.
>
>	ULONG class ;
>
>	...
>
>	while((MyMsg = GetMsg(MyWindow->UserPort)) != NULL) {
>		class = MyMsg->Class ;   /* make a local copy */
>		ReplyMsg(MyMsg) ;        /* reply asap        */
>		switch(class) {
>			...
>		}
>	}
>
>If 'DoUpdateStuff()' is large, you hang onto Intuition's message
>for a long time. If Intuition can't find an existing message to use
>for the NEXT thing it wants to send to you, it will allocate memory
>for a new one rather than use one already in existance. 
>
>Brian
>

Or even better is to use a structure assignment to copy the entire contents
of the message to a private message struct before replying...

> -----------------------------------------------------------------------
>/ Brian Jackson  Software Engineer, Commodore-Amiga Inc.    GEnie: B.J. \
>\ bj@cbmvax.cbm.commodore.com      or     ...{uunet|rutgers}!cbmvax!bj  /
>/ "Anyone considering the purchase of a high-end Macintosh or IBM-      \
>\ compatible computer should try an Amiga 3000 for a few hours before   /
>/ making the final decision." - Consumer Reports ('91 Buying Guide)     \
>-------------------------------------------------------------------------

--
****************************************************
* I want games that look like Shadow of the Beast  *
* but play like Leisure Suit Larry.                *
****************************************************

bj@cbmvax.commodore.com (Brian Jackson) (05/28/91)

In article <mykes.2894@amiga0.SF-Bay.ORG> mykes@amiga0.SF-Bay.ORG (Mike Schwartz) writes:
>In article <21912@cbmvax.commodore.com> bj@cbmvax.commodore.com (Brian Jackson) writes:
>>The only change that I would make to this is that the ReplyMsg() call
>>should come much sooner.  Let Intuition have it's message back asap.
>>
>>	while((MyMsg = GetMsg(MyWindow->UserPort)) != NULL) {
>>		class = MyMsg->Class ;   /* make a local copy */
>>		ReplyMsg(MyMsg) ;        /* reply asap        */
>>		switch(class) {
>>			...
>>		}
>>	}
>>
>>If 'DoUpdateStuff()' is large, you hang onto Intuition's message
>>for a long time. If Intuition can't find an existing message to use
>>for the NEXT thing it wants to send to you, it will allocate memory
>>for a new one rather than use one already in existance. 
>>
>Or even better is to use a structure assignment to copy the entire contents
>of the message to a private message struct before replying...

It's only 'better' if you need the contents of the entire message. If
my program only needs, say, the Class and Code fields of an
IntuiMessage then what purpose (other than to slow things down) is
served by copying the entire 56 bytes of the IntuiMessage every time
rather than simply extracting the 6 bytes that I need ?

Brian

 -----------------------------------------------------------------------
 | Brian Jackson  Software Engineer, Commodore-Amiga Inc.  GEnie: B.J. |
 | bj@cbmvax.cbm.commodore.com    or  ...{uunet|rutgers}!cbmvax!bj     |
 | "We defy augury"                                                    |
 -----------------------------------------------------------------------

mykes@amiga0.SF-Bay.ORG (Mike Schwartz) (05/28/91)

In article <21943@cbmvax.commodore.com> bj@cbmvax.commodore.com (Brian Jackson) writes:
>In article <mykes.2894@amiga0.SF-Bay.ORG> mykes@amiga0.SF-Bay.ORG (Mike Schwartz) writes:
>>In article <21912@cbmvax.commodore.com> bj@cbmvax.commodore.com (Brian Jackson) writes:
>>>The only change that I would make to this is that the ReplyMsg() call
>>>should come much sooner.  Let Intuition have it's message back asap.
>>>
>>>	while((MyMsg = GetMsg(MyWindow->UserPort)) != NULL) {
>>>		class = MyMsg->Class ;   /* make a local copy */
>>>		ReplyMsg(MyMsg) ;        /* reply asap        */
>>>		switch(class) {
>>>			...
>>>		}
>>>	}
>>>
>>>If 'DoUpdateStuff()' is large, you hang onto Intuition's message
>>>for a long time. If Intuition can't find an existing message to use
>>>for the NEXT thing it wants to send to you, it will allocate memory
>>>for a new one rather than use one already in existance. 
>>>
>>Or even better is to use a structure assignment to copy the entire contents
>>of the message to a private message struct before replying...
>
>It's only 'better' if you need the contents of the entire message. If
>my program only needs, say, the Class and Code fields of an
>IntuiMessage then what purpose (other than to slow things down) is
>served by copying the entire 56 bytes of the IntuiMessage every time
>rather than simply extracting the 6 bytes that I need ?
>
>Brian
>
> -----------------------------------------------------------------------
> | Brian Jackson  Software Engineer, Commodore-Amiga Inc.  GEnie: B.J. |
> | bj@cbmvax.cbm.commodore.com    or  ...{uunet|rutgers}!cbmvax!bj     |
> | "We defy augury"                                                    |
> -----------------------------------------------------------------------

If you are only doing simple keyboard and menupick type events, you
are right, but you might also want the Qualifier and IAddress, too.
if you are doing MouseButtons, you're going to want MouseX, MouseY,
and possibly Seconds and Micros, too.  You aren't going to know what fields
you need until the "switch" statement, which is after where you should ReplyMsg().
And you should NEVER try to look at the message fields after doing the Reply...

Again, I suggest a structure copy, even though you are also copying the ExecMessage,
because it is a much easier/maintainable way to write event driven code.  When you
decide a month later that you need another field from the message structure...  And
the code generated by the compiler is going to be much much smaller and potentially
a lot faster, especially depending on the compiler and version you use as well as the
CPU (68010 and up).

--
****************************************************
* I want games that look like Shadow of the Beast  *
* but play like Leisure Suit Larry.                *
****************************************************

markv@kuhub.cc.ukans.edu (05/29/91)

>>The only change that I would make to this is that the ReplyMsg() call
>>should come much sooner.  Let Intuition have it's message back asap....
>>for the NEXT thing it wants to send to you, it will allocate memory
>>for a new one rather than use one already in existance. 

> Or even better is to use a structure assignment to copy the entire contents
> of the message to a private message struct before replying...

True, however, Intuition will only send 1 Refresh or Intuitick at a
time, and a "long time" by computer processing standards isn't
nessescarily too long.  So I only worry about copying if I'm doing
something like FOLLOWMOUSE or like in an editor where I can get a lot of
RAW/VANILLAKEY messages.

Note that if you going off for a real long time its better to
ModifyIDCMP().  INUTITICK by itself works nicely here since you only
get one until you reply, so you can ModifyIDCMP(), reply old
messages, and know only one more will queue up.
-- 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Mark Gooderum			Only...		\    Good Cheer !!!
Academic Computing Services	       ///	  \___________________________
University of Kansas		     ///  /|         __    _
Bix:	  mgooderum	      \\\  ///  /__| |\/| | | _   /_\  makes it
Bitnet:   MARKV@UKANVAX		\/\/  /    | |  | | |__| /   \ possible...
Internet: markv@kuhub.cc.ukans.edu
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

dale@boing.UUCP (Dale Luck) (05/31/91)

In article <mykes.2938@amiga0.SF-Bay.ORG> mykes@amiga0.SF-Bay.ORG (Mike Schwartz) writes:
>>>Or even better is to use a structure assignment to copy the entire contents
>>>of the message to a private message struct before replying...
>>Brian
>Again, I suggest a structure copy, even though you are also copying the ExecMessage,

In general it is not a good idea to use structure copies of system structures
that have any chance of changing size. There are some fields that of course
we all depend on but there maybe fields application programmers do not
depend on. These fields will come and go as Intuition progresses.

You should only copy the fields you need, no more. Do not copy the fields
you have no need for. It is a waste of time, code space, data space, and
potentially a major problem when Commodore-Amiga decides it needs to change
something that is private to itself.

-- 
Dale Luck     GfxBase/Boing, Inc.
{uunet!cbmvax|pyramid}!amiga!boing!dale