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.:

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:

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:

  1. The display polls or wait for an event e, and it gets into the queue
  2. Some time later, the event reaches the top of the queue
  3. The display takes it from the top and calls root.handle_event (e)
  4. The root window calls e.propagate (Current)
  5. The event chooses a child c to propagate, and calls c.handle_event (Current)
  6. c calls e.propagate (Current)
  7. ...

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:

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_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