[comp.sys.amiga] Dealing with lots of messages

john13@garfield.UUCP (John Russell) (01/06/88)

None of the messages on dealing with many messages (esp. mousemove) from one
or more ports has mentioned a very simple technique that can speed up
response time greatly.

It goes something like this (this is from memory):

	msg = GetMsg(window->UserPort);

	class = msg->Class;
	x = msg->MouseX , y = msg->MouseY;

	ReplyMsg(msg);

	switch(class) {
		case MOUSEMOVE:
			if (window->MouseX != x || window->MouseY != y) 
			/* user has moved the mouse since this message
			   so I will ignore it */
				break;
			else
			<normal routine to deal with mouse movements>
	}

By doing this you can minimize the number of redraws (say when rubberbanding
a line). It gives a really great speedup when applied to a time-consuming
interactive operation, eg dragging a DPaint-style curve around the screen.
If you try to process all movement messages for that, you can easily move
the mouse enough so that it will take >10 seconds for the drawing to catch up.

John
-- 
"I hate to be the one to tell you this, Bryce, but there's more to life than
 interactive systems analysis."
"I know. It also involves number crunching!"
				-- Max Headroom

steveb@cbmvax.UUCP (Steve Beats) (01/07/88)

In article <4346@garfield.UUCP> john13@garfield.UUCP (John Russell) writes:
>None of the messages on dealing with many messages (esp. mousemove) from one
>or more ports has mentioned a very simple technique that can speed up
>response time greatly.
>
>It goes something like this (this is from memory):
>
>	msg = GetMsg(window->UserPort);
>
>	class = msg->Class;
>	x = msg->MouseX , y = msg->MouseY;
>
>	ReplyMsg(msg);
>
>	switch(class) {
>		case MOUSEMOVE:
>			if (window->MouseX != x || window->MouseY != y) 
>			/* user has moved the mouse since this message
>			   so I will ignore it */
>				break;
>			else
>			<normal routine to deal with mouse movements>
>	}
>
>By doing this you can minimize the number of redraws (say when rubberbanding
>a line). It gives a really great speedup when applied to a time-consuming
>interactive operation, eg dragging a DPaint-style curve around the screen.
>If you try to process all movement messages for that, you can easily move
>the mouse enough so that it will take >10 seconds for the drawing to catch up.
>

Actually, I have found that the best way to handle MOUSEMOVE events is to use
the ReportMouse( window, BOOLEAN) function.  When you receive a mouse event,
switch off mouse reporting before you begin to process the event and switch it
back on again when you have finished. (Of course, you still should check the
x and y values to see if there is any work to do).  This has the effect of
making the mouse reports more granular and you don't get problems with memory
being eaten if Intuition gets tons of MOUSEMOVES while you're processing the
last one.  So I guess it would go something like this:-

	Wait( 1<<w->UserPort.mp_SigBit );
	while( msg = GetMsg(w->UserPort) ) {
		switch( msg->Class ) {
			CASE : MOUSEMOVE
				ReportMouse( w, FALSE );
				DoNeatStuff( msg );
				ReportMouse( w, TRUE);
				break;
			CASE etc. etc
		}
		ReplyMsg( msg );
	}

My 'C' is really rusty, I've spent the last year writing in assembler so don't
try to compile this :-)  (Anyone want an assembler example ?)

	Steve

jimm@amiga.UUCP (Jim Mackraz) (01/07/88)

In article <3094@cbmvax.UUCP> steveb@cbmvax.UUCP (Steve Beats) writes:
>In article <4346@garfield.UUCP> john13@garfield.UUCP (John Russell) writes:
>> [ good idea number 1 ] -John

> [ interesting idea number 2 ] -Steve

These are both OK.  I am proposing that in next release (V1.4?),
a flag be added to the Window named SIGNALMOUSE.  When set, if
you are to be sent a mouse movement message, it won't be sent. 
Rather your Window->UserPort will be signalled.  You'll wake up,
GetMsg() NULL, and then just check Window->MouseX/Y or
PropInfo->Horiz/VertPot, or whatever, in a kind of prodded polling
fashion.

No backlog, unsightly comparisons, distasteful state toggling.

Religious leaders might not like some of the synchronicity implications
of this, but it will serve lots of uses.  Note that mouse clicks and
other discrete events are still to be used with the X/Y position
synchonously associated with them in the message.

Great idea.  Think I'll put it in.  Oh, look, it's done.   ;&)
	jimm

-- 
	Jim Mackraz, I and I Computing	  
	amiga!jimm	BIX:jmackraz
Opinions are my own.  Comments regarding the Amiga operating system, and
all others, are NOT to be taken as Commodore official policy.

bryce@hoser.berkeley.edu (Bryce Nesbitt) (01/07/88)

In article <4346@garfield.UUCP> john13@garfield.UUCP (John Russell) writes:
>None of the messages on dealing with many messages (esp. mousemove) from one
>or more ports has mentioned a very simple technique that can speed up
>response time greatly.
>
>It goes something like this...
>
>	msg = GetMsg(window->UserPort);
>	....
>		case MOUSEMOVE:
>			if (window->MouseX != x || window->MouseY != y)
>			/* user has moved the mouse since this message
>			   so I will ignore it */
>				break;
>			else
>			<normal routine to deal with mouse movements>

*YUCK!* This technique combines a timestamped mouse message and compares it
syncronously as a crude aproximation of the current mouse position! This
also has the potential of getting out of sync.  Either method alone is
ok.  Combining them is asking for problems.

The much better way is just to eat all of the mouse messages you don't
want.  I'll drag an example out of my bag of disks and post it as AmigaLine
#5.

(Note: anyone is welcome to write an AmigaLine... just send it to me first
so the numbers stay straight).

The Intuition manual has an example like this, but I consider it defective.
It processes "normal" messages before the mouse moves.  This means that the
user might use the mouse, then pull down a menu.  Both messages will be
queued to the port.  The Intuition manual code would handle the menu THEN
handle the mouse move.	Potential problems abound.


<By doing this you can minimize the number of redraws (say when rubberbanding
<a line).

Yes. It is a valuable technique.  (-: (-: One Intuition should use :-) :-)
It also keeps piles of unwanted mouse messages from piling up at your
ports.


BTW: I would not recommend depending on the Window's relative mouse
co-ordinates always getting updated (unless the window is the active one).
Not a problem for your code, of course.

|\ /|  . Ack! (NAK, SOH, EOT)
{o O} . bryce@hoser.berkeley.EDU -or- ucbvax!hoser!bryce (or try "cogsci")
 (")
  U	"Your theory is crazy... but not crazy enought to be true." -Niels Bohr

bryce@hoser.berkeley.edu (Bryce Nesbitt) (01/08/88)

In article <3094@cbmvax.UUCP> steveb@cbmvax.UUCP (Steve Beats) writes:
>
>Actually, I have found that the best way to handle MOUSEMOVE events is to use
>the ReportMouse( window, BOOLEAN) function.

WARNING!!! WARNING!!! DANGER!!! BUG CITY!!! DANGER!!! 

(Dramatic enough?)

ReportMouse() is 100% defective.  Totally useless.  It can *NEVER* be
called safely by user code.  No, I'm not talking about the bug
that swaps the order of the parameters depending on compiler/
options.  I'm talking about something more fundamental:

WARNING!!! WARNING!!! DANGER!!! BUG CITY!!! DANGER!!! 

When a gadget is pressed it records the state of the REPORTMOUSE flag.
When the gadget is relased it restores that flag.

Your program does this:

>				ReportMouse( w, FALSE );
>				DoNeatStuff( msg );
>				ReportMouse( w, TRUE);

Think what happens if a person presses a gadget after the first ReportMouse()
and releases it after the second ReportMouse().

1> The gadget reads in "REPORTMOUSE OFF"
2> The program sets "REPORTMOUSE ON"
3> The release of the gadget sets "REPORTMOUSE OFF"

You program is screwed.  One of the gadgets that does this to you is
the standard page forward gadget.  I have a test program that demonstrates
this clearly (the darn bug bit me HARD). 


WARNING!!! WARNING!!! DANGER!!! BUG CITY!!! DANGER!!! 

The solution is jimm's new flag.  But we'll need to wait two Kickstart
releases for that.  (What's the bit number?)


>My 'C' is really rusty, I've spent the last year writing in assembler so don't
>try to compile this :-)  (Anyone want an assembler example ?)

Sure.  But I'll take my example in the fast-filesystem flavor.  :-)


|\ /|  . Ack! (NAK, SOH, EOT)
{o O} . bryce@hoser.berkeley.EDU -or- ucbvax!hoser!bryce (or try "cogsci")
 (")
  U	"Your theory is crazy... but not crazy enought to be true." -Niels Bohr
|\ /|  . Ack! (NAK, SOH, EOT)
{o O} . bryce@hoser.berkeley.EDU -or- ucbvax!hoser!bryce (or try "cogsci")
 (")
  U	"Your theory is crazy... but not crazy enought to be true." -Niels Bohr

steveb@cbmvax.UUCP (Steve Beats) (01/09/88)

In article <22456@ucbvax.BERKELEY.EDU> bryce@hoser.berkeley.edu UUCP (Bryce Nesbitt) writes:
>
>WARNING!!! WARNING!!! DANGER!!! BUG CITY!!! DANGER!!! 
>
>When a gadget is pressed it records the state of the REPORTMOUSE flag.
>When the gadget is relased it restores that flag.
>
>Your program does this:
>
>>				ReportMouse( w, FALSE );
>>				DoNeatStuff( msg );
>>				ReportMouse( w, TRUE);
>
>Think what happens if a person presses a gadget after the first ReportMouse()
>and releases it after the second ReportMouse().
>
>1> The gadget reads in "REPORTMOUSE OFF"
>2> The program sets "REPORTMOUSE ON"
>3> The release of the gadget sets "REPORTMOUSE OFF"
>
>You program is screwed.  One of the gadgets that does this to you is
>the standard page forward gadget.  I have a test program that demonstrates
>this clearly (the darn bug bit me HARD). 
>
OK, red face time.  Of course your dead right Bryce, but I would like to
qualify my statement a bit.  I guess I made the mistake of not specifying
that this only works for things that are activated by a left mouse click.
I've used it for file requesters (where FOLLOWMOUSE is set on the scroll
gadget) and for drawing type things (where you must click the left mouse
button before anything happens) and had no problems at all.

	Steve

bryce@hoser.berkeley.edu (Bryce Nesbitt) (01/09/88)

How could this be!  I posted this horrid bug, and forgot to give a
workaround!  What is this world comming to?

It's quite simple, since gadgets are the cause of the problem, we'll
only call ReportMouse() when none are active:

long key;
	...
	key=LockIBase(0L); /* Wait utill Intuition is not busy, then lock */
	ReportMouse(boolean,Window);
	UnlockIBase(key);


Tomas Rokicki pointed out that ModifyIDCMP() could also be used for this
function.  I plugged it into the program I had that was failing, and sure
enought it works ok.  ModifyIDCMP() does not need the LockIBase() kludge.

		Thanks Tomas!

|\ /|  . Ack! (NAK, SOH, EOT)
{o O} . bryce@hoser.berkeley.EDU -or- ucbvax!hoser!bryce (or try "cogsci")
 (")
  U	"Your theory is crazy... but not crazy enought to be true." -Niels Bohr

peter@nuchat.UUCP (Peter da Silva) (01/11/88)

In article <1983@amiga.amiga.UUCP>, jimm@amiga.UUCP (Jim Mackraz) writes:
> In article <3094@cbmvax.UUCP> steveb@cbmvax.UUCP (Steve Beats) writes:
> >In article <4346@garfield.UUCP> john13@garfield.UUCP (John Russell) writes:
> >> [ good idea number 1 ] -John
> > [ interesting idea number 2 ] -Steve
> [ kludge #3 ] Jim

Your idea, I'm sorry to say, is a kludge.

BUT, while we're talking about enhancements for 1.4(?), how about just making
MOUSEMOVE work like INTUITICKS... that is, you don't send a new MOUSEMOVE
message to a window until it's ReplyMsg-ed the previous one. Simple, clean,
consistant. What more can you want?

dillon@CORY.BERKELEY.EDU (Matt Dillon) (01/13/88)

>Your idea, I'm sorry to say, is a kludge.
>
>BUT, while we're talking about enhancements for 1.4(?), how about just making
>MOUSEMOVE work like INTUITICKS... that is, you don't send a new MOUSEMOVE
>message to a window until it's ReplyMsg-ed the previous one. Simple, clean,
>consistant. What more can you want?

	Nahhh.  Sometimes you want the accuracy (say somebody is tracing
a curve) even if the system is loaded.   When I want to handle mousemove at
program speed rather than message port speed, I simply flag the move and the
last coordinates and handle it after GetMsg() returns NULL... easy.

	Checkout the source to FILES on mod sources for an example.

					-Matt

john13@garfield.UUCP (John Russell) (01/14/88)

In article <525@nuchat.UUCP> peter@nuchat.UUCP (Peter da Silva) writes:
>In article <1983@amiga.amiga.UUCP>, jimm@amiga.UUCP (Jim Mackraz) writes:
>> In article <3094@cbmvax.UUCP> steveb@cbmvax.UUCP (Steve Beats) writes:
>> >In article <4346@garfield.UUCP> john13@garfield.UUCP (John Russell) writes:
>> >> [ good idea number 1 ] -John
>> > [ interesting idea number 2 ] -Steve
>> [ kludge #3 ] Jim
>Your idea, I'm sorry to say, is a kludge.

Interesting that neither of the other 2 referenced articles have gotten here
yet.

>BUT, while we're talking about enhancements for 1.4(?), how about just making
>MOUSEMOVE work like INTUITICKS... 

I would have to say no, since there may be times when it's desirable to have
very fine reading of the mouse, even if it does lead to long lag times. Not
often, but most other cases where this is a factor involve simple actions
like rubberbanding where the workarounds like the one I proposed are no more
than 1 or 2 lines.

Speaking of INTUITICKS, when I installed timer routines from Ali Ozer in a
program that processed them, they stopped coming. Anyone know why? I didn't
do anything other than set up requests to be signalled N times a second.

ModifyIDCMP is turning out to be quite useful. I would recommend that anyone
writing intui-message controlled programs test out all sorts of weird
combinations (like activating your window with right button down so you
get a MENUUP before MENUDOWN) and mask out ones you don't want to see at
certain times. Aside from the RMB messages I just mentioned I used 'udlr'
vanillakeys to tweak positioning of a rubberbanded box; it looks messy if you
change the offsets while it is trying to erase itself.

John
-- 
"Operating systems room, prepare for shutdown."
"I never thought I'd be HAPPY to see our ratings do DOWN!"
		-- lots of these were sprinkled throughout the 
		   last broadcast episode of _Max_Headroom_

bryce@hoser.berkeley.edu (Bryce Nesbitt) (01/16/88)

In article <> somebody (lost to the winds of history) wrote:
>>
>>[Description of new flag added to Intuition]
>>
>>Your idea, I'm sorry to say, is a kludge.
>>
>>BUT, while we're talking about enhancements for 1.4(?), how about just making
>>MOUSEMOVE work like INTUITICKS... [Ie: don't send another until the first
>>is replied]

Bad for this reason:

You get sent the message and take a long time replying to it.  Now you
have a very old mouse message, but all the mouse moves since it have been
discarded.

I think jimm's new flag is just right.  IF you are only interested in
the LASTEST position of the mouse, just look.  The signal wakes you
up to the fact that the mouse moved.  Compare X,Y.  Perfect.

Before jimm suggested this, my idea was a counter:  "If XX mouse
messages queue up, then stop sending new ones.  At that point just
update the latest message with the new position.".

So a drawing program would trace a smooth curve until it gets too far behind.
Then it would jump ahead.  If you like things the old way, set the
counter to something very high (Say, 200).


>I would recommend that anyone
>writing intui-message controlled programs test out all sorts of weird
>combinations (like activating your window with right button down so you
>get a MENUUP before MENUDOWN)...

Good software practice.  Software should handle such events with grace.


|\ /|  . Ack! (NAK, SOH, EOT)
{o O} . bryce@hoser.berkeley.EDU -or- ucbvax!hoser!bryce (or try "cogsci")
 (")
  U	"Your theory is crazy... but not crazy enought to be true." -Niels Bohr

peter@sugar.UUCP (Peter da Silva) (01/16/88)

In article <8801130131.AA26382@cory.Berkeley.EDU>, dillon@CORY.BERKELEY.EDU (Matt Dillon) writes:
> >BUT, while we're talking about enhancements for 1.4(?), how about just making
> >MOUSEMOVE work like INTUITICKS... that is, you don't send a new MOUSEMOVE
> >message to a window until it's ReplyMsg-ed the previous one. Simple, clean,
> >consistant. What more can you want?

> 	Nahhh.  Sometimes you want the accuracy (say somebody is tracing
> a curve) even if the system is loaded.   When I want to handle mousemove at
> program speed rather than message port speed, I simply flag the move and the
> last coordinates and handle it after GetMsg() returns NULL... easy.

> 	Checkout the source to FILES on mod sources for an example.

Good point. OK then, how about this:

Add a new flag, but call it FASTMOUSE. FASTMOUSE would work like MOUSEMOVE
crossed with INTUITICKS. I avoid MOUSEMOVE these days because of all the
overhead.

I realise it should possibly be called SLOWMOUSE, but I want to retain
compatibility with COMPLEXREFRESH and STUPIDREFRESH windows :->.
-- 
-- Peter da Silva  `-_-'  ...!hoptoad!academ!uhnix1!sugar!peter
-- Disclaimer: These U aren't mere opinions... these are *values*.

dillon@CORY.BERKELEY.EDU (Matt Dillon) (01/18/88)

:> >MOUSEMOVE work like INTUITICKS... that is, you don't send a new MOUSEMOVE
:> >message to a window until it's ReplyMsg-ed the previous one. Simple, clean,
:> >consistant. What more can you want?
:
:> 	Nahhh.  Sometimes you want the accuracy (say somebody is tracing
:> a curve) even if the system is loaded.   When I want to handle mousemove at

	Also, you can simply NOT specify MOUSEMOVE, but only MOUSEBUTTONS
and INTUITICKS... Then simply look at the mouse variables in the window
structure every tick while the mouse button is down (or up, or whatever).

				-Matt