Events
This chapter is not like the previous ones, in the sense that it is more about pure concepts than following an example. In fact, this chapter will not include a demo, although things said here will be applied in the next one.
We will get into detail about how EWS handles user input (and some other
stuff that may not come from the user). Almost every action done by EWS
is triggered by EVENT, which are some small objects usually
associated to user input or external events.
You may have noted that, except some setup, all of the application work
is made during the do_event_loop call. This routine works
calling repeatedly to the do_event_loop_iteration procedure
defined on your DISPLAY. This routine gets an event (it may
block or not to get one depending on its wait argument),
puts it on an internal queue, "processes" it (we will see soon what this
means), adds a new event to the queue if available, and repeats until no
events are available. After that, the display is updated.
New external events may be inserted to the queue by the
poll_event  routine of the DISPLAY.
wait_event is similar but ensures that a new event will be
added to the queue. These methods are defined in SDL_DISPLAY
to get the kind of input that SDL has access to, i.e.:
- Keyboard action (key presses and releases)
 - Mouse movement
 - Mouse buttons (press and release)
 - Timer
 
You can also add events artificially using the
add_event routine (you have seen this one before, being used
to add a quit event). next_event removes the first event from
the queue. event and event_available can be used
to query the queue.
Note that the above algorithm will produce usually a redraw for each event, except in the following cases:
- Events are coming too fast to be processed
 - Processing or redrawing takes long and new events start accumulating
      before being get by 
poll_event - Events are synthesized by the processing stage
 
Event processing consists in passing the event to the 
handle_event procedure of the appropiate windows. The display
passes the event to the root window, and trusts the window to pass it on.
This chain of calls to handle_event is called "event propagation".
Not all events propagate the same way. Events usually move from the root
to the branches of the window tree, but may be selective about which
branches to take. Each EVENT has a method propagate
which takes a WINDOW as argument, and selects the proper child(s)
to propagate itself calling handle_event of the child(s) It may
be important not just which childs it select but also the propagation order.
So, the usual propagation chain works like this:
- The display polls or wait for an event 
e, and it gets into the queue - Some time later, the event reaches the top of the queue
 - The display takes it from the top and calls 
root.handle_event (e) - The root window calls 
e.propagate (Current) - The event chooses a child 
cto propagate, and callsc.handle_event (Current) - c calls 
e.propagate (Current) - ...
 
This chain is not a sequence, it can grow and shrink for a while during the processing. For example, step 6 may finish and go back to step 5, where the event might choose another child. The chain will stop growing when the event decides not to get passed to any child (possibly because the window has no children), or when a window decides not to propagate the event.
The interesting part of all of this, is that windows will usually want to
do something else with the event besides tossing it around. So to add
behaviour to a window you have to redefine its handle_event
to do something useful besides (or instead of!) propagation. We will see an
example in the next chapter.
It is possible to have almost any propagation policy defining a new
heir of EVENT with some strange implementation of
propagate. Note that it could even be something that does not
traverse the code from root to branch. However, there are a few generally
useful propagation policies, and all of them are implemented in EWS as
deferred classes:
EVENT_BROADCAST: This events propagate to every visible child, in depth first order. Note that windows which are not visible (seehideandshowoperations inWINDOW) must be skipped by all event propagation schemes (see precondition ofhandle_event). Timer and quit events have this policy.EVENT_POSITIONAL: This event has a coordinate pair associated. It is propagated to children that are covering the position of the event. The receiving window will always receive the event with local coordinates. Windows which appear to be on the front will receive this event first. Mouse moves and clicks have this policy.EVENT_FOCUSED: This event propagates lineally from the root to the window having focus. Keyboard events have this policy
All events have a flag called handled that is initially
set to False, but can be enable using the routine
set_handled. Once enabled, it can not be disabled again.
This flag is used to indicate that the event is "consumed" and its
processing should stop. Most events will stop propagating after having
this flag set. Most windows will stop asking the event to propagate after
seeing it labeled as handled. In fact, the default implementation
for handle_event is
if not event.handled then event.propagate (Current) end
And a usual redefinition of handle_event will be
if event is interesting then do something event.set_handled elseif event should be filtered then event.set_handled end Precursor (event)
The precursor call can be at the top or at the bottom depending if you want the window to have priority on event handling over its children or not.
Most of the time you will be defining a few kind of new windows, and very rarely a new kind of event. New events can be useful when you have a new special kind of input, or as a very general intercommunication mechanism between parts of your application where direct procedure call is difficultor impractical. Most of the time, you will be working with the following predefined events:
EVENT_FOCUS: sent to a window when it gets or loses focus; synthesized byWINDOW. It has the same policy as keyboard events.EVENT_KEY: generated when a key is pressed or released.EVENT_MOUSE_BUTTON: generated when a mouse button is pressed or released over a window.EVENT_MOUSE_MOVE: generated when the mouse moves over a window.EVENT_MOUSE_NOTIFY: generated when the mouse enters or exits a window; synthesized byEVENT_MOUSE_MOVEEVENT_QUIT: generated when the close button of the window frame (if using windowed mode) is clickedEVENT_REMOVE: This event is quite artificial. It is generated by theremoveaction ofWINDOW, which instead of removing the window inmediatly queues one of these events to force the removal to happen while no other event is being processed. This event does not propagate, and only the root window will see it. This is done in this way to avoid some problems that would happen if a window were removed while still propagating events.
EVENT_QUIT has a little special handling by EWS besides
propagation. After the event has been processed, it stops the looping of
do_event_loop if it has not been handled. It is usually
synthesized to force a quit. You can set it as handled if you want to
block external (or internal) requests for quit, and it will be ignored
by the event loop. EVENT_MOUSE_MOVE has also some minor special
handling to update the mouse pointer (So, you can move the mouse pointer
sending synthetic mouse move events).
At this time, you are encouraged to read the short forms of 
WINDOW and DISPLAY; at this time all methods should
be clear. Now that you have mastered EWS basics, the next step is moving to
widget programming
 
| Previous | Table of contents | Next |