From: Arthur van Hoff <arthur@turing.ac.uk>
Subject: TNT menus
To: Don Hopkins <hopkins@Sun.COM>, Rafael Bracho <rxb@Sun.COM>
Date: Tue, 15 Jan 91 9:02:20 BST
Cc: Jim Rudolf <rudolf@turing.ac.uk>, Tim Niblett <tim@turing.ac.uk>,
        Cathy Waite <cathy@turing.ac.uk>

Hi Don,

Thanks for the phone conversation. Here are some remarks
about the TNT menus...

HyperNeWS will have to subclass both ClassMenu (and its sister classes)
and ClassCanvas in order to provide a similar service for menus
as the getanimated service does for tracking. This means that
a process must be allowed to do call a 'showmenu' routine to
show a menu and return when the menu is popped down.
I have send you an implementation of this. I had to change this
radically since TNT2.0b (you have changes the internal class structure of
menus).

There is also the problem of menu states. A the moment you can
detect two states: MenuStart and MenuStop. 
More states should be detectible (either by ClassCanvas or by
ClassMenu).

	MenuStart:	Show the menu.
	MenuStuck:	Mouse is up but menu stays.
	MenuPin:	Menu is about to become pinned.
	MenuStop:	Menu is down.

The detection of these states is important if you want to implement
the menu buttons and other objects properly.

More problems with pinning menus:
1) I would like to share the unpinned menu among many windows/objects. 
   This means that its state should not affect a pinned copy.
2) When a menu gets pinned it should be associated to an object. This
   does not have to be a TNT object (it could be a HyperNeWS object).
3) HyperNeWS requires that a pinned menu can be stuck on a button since
   the menu must disappear/appear as the button becomes visible/invisible
   due to the showing of different cards/layouts.
4) The above should also be possible for submenus.

Problem:
I think that ClassCommandMenu and ClassSettings should always ask
ClassMenu to execute the notifier. If you don't do this it is impossible
to subclass ClassMenu and change the ExecuteNotifier method.
Actually this is true for many aspects which are now passed on
from ClassMenu to the other menu classes.

Have fun,

	Arthur van Hoff 		     arthur@turing.ac.uk

	The Turing Institute
	36 North Hannover street, Glasgow G1 2AD, +44 41 5526400
	Beltstraat 94a, 7512 AB Enschede, Holland, +31 53 324366


Date: Tue, 15 Jan 91 03:14:17 PST
From: hopkins (Don Hopkins)
To: arthur@turing.ac.uk
Cc: hopkins
Subject: tracking using ClassEventMgr

It would be good if you could use ClassEventMgr to do your tracking.
One of the nice things about ClassEventMgr and ClassInterest, is the
way any process can express interests on behalf of the event manager,
via the /addclient method, instead of requiring the event manager to
express its own interests (whenever it gets around to it). This way
you are guaranteed not to lose any events. With this technique, the
"null blockinputqueue { ... unblockinputqueue ... } fork" cliche is no
longer necessary (it doesn't really keep you from losing events,
anyway...). The /NewObject method of ClassEventMgr forks a process and
returns it to you as the EventMgr instance. That process enters an
infinite awaitevent loop, and executes all its callbacks via
executable matches in the interests.  It starts out with a
DoItInterest that you can use to force it to do anything you want.
But you don't even need that much of its cooperation to set it up with
some more interests: while you still have the input queue blocked from
the triggering event, you could send /new to ClassEventMgr to fork off
a new tracker process, then express some interests on its behalf (i.e.
activate some instances of ClassInterest), by sending /addclients to
the event manager with an array of ClassInterest instances as args.
Since the interests are expressed on behalf of the tracking process,
while the input queue is still blocked, before the tracker process
even gets a chance to run, you never lose any events!

What you seem to be doing in the code you sent, is recursing the event
manager into another awaitevent loop, in track_state?  Hmm...  You
should be able to do the same thing, using ClassEventMgr, but do you
really need to? What if track_state just returned /track_down in the
case of a trackable canvas with a track_state of null (which as I
understand it, could happen in the user-supplied /onadjust hander,
before a call to track.) Why would you want to test the track_state
before calling track? Wouldn't it be sufficient in that case to say
that track_state was /track_down?  

In the code you sent me, when /track_state defines /$track_proc to go
"currentprocess /track_state 3 -1 roll put", I think you meant to say
/track_evt instead of /track_state.

The menu stuff is really weird, but I think I see what is going on.
You need a thread of control that gets started when the menu button
goes down, that makes a call to showmenu to pop up the menu, and
showmenu blocks until the menu pops down, returning to the caller who
can then use the results of the menu selection to do something. In
other words, the menu notifier is not enough, you want another
notifier that pops up the menu, waits around until the menu pops down
(and executes *its* notifier), then continues on, possibly doing
something based on the result of the menu selection (if one was made).

If you could have the menu button event come in through /TrackStart
just like the other buttons, could you use your tracking mechanism to
deal with menus?

Is it an essential feature of the design, that the procedure passed to
track is able to leave stuff on the stack, that's returned from track
underneath the status name on the stack?

That is, is it meant to be easy to go "[ { [ mousexy ] } track pop ]"
to create an array of [x y] mouse motion points?

Is another essential feature that the handler is one procedure,
structurally "{Down{Move}Up}", instead of three, "{Down}{Move}{Up}"?

Encourage me if I'm stating the obvious. This will help explain it to
other people.

Please give me examples of how you'd write an /onadjust handler,
especially ones that depends on recursing the event loop. 

	-Don

