[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re : [Chicken-users] gui api design -- some thought -- long mail
From: |
minh thu |
Subject: |
Re : [Chicken-users] gui api design -- some thought -- long mail |
Date: |
Tue, 13 Feb 2007 20:55:38 +0100 |
A simple alternative is that often you just want to call yourself
later. That is, register a timer which when it expires, will call the
given function which you give when you register the timer. It can be
a one-shot or a repeating timer.
In my conception of the event queue, each event has a timestamp
indicating when it has to be dispatched. So an event can be inserted
in the queue before already present events.
> b) (which is related) Since a function call results
> from an event, you can't generate an event whose
> callback needs the end of
> the event-generating-computation (i.e. it's not
> asynchronous).
>
> I'd rather like to finish a computation which generates
> an event before processing it.
If you generate the event and put it in the queue, it will be
processed later when the code gets around to checking the queue,
right?
Yes. The code could be a scheduler (provided by the library) or user code.
> c) Also, say you want to code "When the left mouse button
> is pressed (elsewhere than above my two main widgets),
> make the first widget be blue and the second one be red.".
> (Call this the blue-red exemple for later reuse.)
> You'll need to register a callback on the background widget.
> This callback needs to access (to be aware of) the two
> other widgets. I don't like this.
Whereas in an immediate mode UI, the main "do" function is both
finding out that the button is pressed, and drawing the blue and red
widgets directly right?
I guess so.
An alternative way to get this behavior with callbacks would be to
make it possible for every widget to register interest in any kind of
event, whether or not it would seem relevant to that widget. The
callback can have an extra parameter to indicate the relevance. So a
normal button registers only for a click event on himself, and your
special button registers for a click event anywhere, and is given a
"true" when the click is on him, and a "false" if it's somewhere else,
along with coordinates etc. Or maybe your special button does two
registrations of two different callbacks so that the parameter is not
necessary...
The first part of your description sticks to my idea. Hwever, when you
say 'the widget registers interest', I would say 'you register a
callback that will only cares of one widget'.
So to implement the button, I would make a handler for
'left-mouse-button-pressed which insert a new event,
'that-button-clicked. This step could be hidden for the user of the
GUI.
> "My" Idea.
>
> I call it mine but I don't know .. maybe it's as old
> as the world ?
>
> - The callback mechanism is exposed and made not mandatory.
> - The widgets are aware of events, not the contrary
> (see c) above).
> - The event facility can be used for application-generated
> events.
> - The ol'callback way is still available.
>
>
> How.
>
> An event-queue keeps the not-yet-processed events.
> (For some application, it might be useful to timestamp
> events so they are dispatched later or even keep the
> already-processed events to be able to reverse time.)
That's probably a really good idea. I think in general the trend is
that as memory gets cheaper (RAM and disk both, and I believe they
will be the same thing some day when nonvolatile RAM is cheap enough),
you can find reasons to keep data around, timestamp it, take diffs,
even build a sort of version control system for some classes of data,
rather than assume that only the latest, most current data is relevant
and letting new stuff overwrite old stuff. Especially, any text which
the user enters himself ought to be considered sacred and never
garbage-collected unless the user asks for it to be deleted. The book
"The Humane Interface" makes this point. I was thinking a few years
ago that a computer's disk ought to be structured as a giant log,
where the data the user creates is appended to the log, and then data
structures which the software creates to organize that data never
duplicate it - they just point to it. The user enters a stream of
data, and the computer makes sense of it over time. You would have
built-in version control - edits are actually a special kind of diff
that is appended to the log, so you will have the new version and the
old version at the same time. Like CVS or subversion but implemented
more efficiently. That is what early versions of the Xanadu project
were about...but there is more than one way to implement it, and I
can't make up my mind which is the best one (and neither could the
Xanadu guys, which is why it never got done).
Anyway I'm not sure that mouse events have the same kind of perennial
lasting importance that text does, but in graphical documents, like
diagrams, a persistent history would be nice, with unlimited undo and
the ability to compare different versions. I want to build something
like that when I get the GUI stuff done.
Interesting point. Although it was not clear, I was thinking of some
functions to get events but also query the existence of a event. We
could add the possibility to keep scheduled(processed) events. But in
fact, I think it's appplication specific and I don't see if it would
be really interesting; maybe would you prefer your own event data
structure.
> For some event, the current state is kept. Exemple:
> You might not want to have code run each time the
> <enter> key is pressed but only want to be able to
> query its state; is it pressed ?
In the embedded system I described above I have a bitmask which keeps
the state of every button. How else will I detect that it was just
pressed, or just released, in order to generate an event? But in a PC
keyboard the microcontroller would have to do something similar, and
then it sends scan codes across the serial link to the PC. So you
have to re-create the state of the enter key when an event occurs
which indicates the state changed.
I'm not sure I understand this paragraph. Usually you receive
different event for key-pressed and key-released. In my paragraph, I
said you can both keep the timestamped event *and* the current state
related to the event.
If you poll not enough (not a sufficiently high rate) the current
state, you can miss events (key-pressed then key-released: the state
is 'released' and you didn't see the two events). But you might not
care of events but only state, so the API should provide both.
> The base API let you test the existence of an event.
> The test can be blocking or not. It can removes the
> event from the queue or not. (The api has to be
> extended so an event can be removed automatically
> when every interested widget has already received it.)
Are you sure you would want to have events removed from the queue, if
you are depending on them to be there so that applications which
started up after those events can still process them?
Sure, I'm not :) ... do you have an example in mind (not me) ?
> (This last point let you write the blue-red program:
> the two widgets are aware of the events.)
>
> At this point, we have access to events. But how (when)
> the code accessing the events is run ? How the gui
> event-polling is done ?
>
> Here again we gain some flexibility. You can write
> yourself a loop that calls one API function to
> pump gui events then calls the event-testing-related
> API functions.
Testing the existence of an event is a search, isn't it? So you could
have potentially hundreds of widgets all doing the same search over
and over again to comb through the whole event queue and find out what
is of interest to them? or at least combing through the "tail" of the
event queue (and keeping track where they left off, so at the next
polling cycle they know where to start). This is why registering a
callback is a nice concept - when the event occurs, the main event
handler can immediately build a list of callbacks that need to be
notified, and then call them.
I've done no math but I believe that if you build a Callback
abstraction on top of the low level part of the api you will not have
that much events to search for.
On a multi-processor system the
callbacks could even be simultaneous. If the red button expressed
interest in receiving all mouse clicks then he will be notified at
once (practically instantaneously) when the mouse is clicked, maybe
even at the same time the blue button also gets notified.
I don't think so. GUI (user) event processing is unithreaded for me :
a simple gui button has to see the press then the release of the mouse
button; those two events have to be processed by the same thread. You
can run multiple threads if those events are not related or you'll
have to keep trak of shared information about those events.
> Or you can use an API function set
> to let you register functions to be called regularly
> (independently of events) and then launch an API-
> provided main loop. Or register functions to
> be called only for some specific events.
>
> Yep, we approached the well-known callback mechanism.
Yeah maybe we're thinking pretty much the same.
> To make it really feels like that, we can provide a
> function which makes the widget generate an event
What does that mean, the widget generating an event? Usually the user
generates an event by clicking or moving or typing.
(Read above, I provide an example in this answer.)
> *and* register a callback for that specific event.
>
> By 'specific event', I mean an event has some kind
> of name. When you register a function, you have to
> say for which event names you want it to respond.
> So the function I talked about in the previous
> paragraph can generate a unique name so only *that*
> widget and *that* callback are tied.
Is a "name" really just a generated ID, or is it some kind of
concatenation of an event ID, a widget ID and a callback?
Just a event type or kind. For example, 'key-pressed or 'mouse-button-released.
So (this answer your question below too), a callback and a gui element
can be related by a unique event name. No other callback would receive
that event since the event name is generated when registering the
callback for it and making the gui element send an event with that
name. (I think Scheme has a gensym function for that.)
Would you say that every widget has to create its own callbacks
yes
or
you'd have a globally unique, generated widget ID which is passed as a
parameter to the callbacks, so that the callbacks can service multiple
widgets?
yes too but the event is passed to callback that are registered for
that/those event name(s).
(This is an ancient Java AWT thing - is it OK sometimes to
have one button handler for several buttons, or do you have to create
new ones for each? If you share the handler, then you have to have
some if's inside to decide which button was pressed. Worse yet, the
callback included only the string that labeled the button, so the if's
would be doing string comparisons. But before anonymous inner classes
were added to the language, it was hard to write separate handlers for
every button. Now both ways are still possible, as far as I know.)
Sorry for responding so late but I knew I would have some time to
answer correctly.
Thanks for the discussion,
thu