Besides building and modifying the scene graph, python scripts can react when a user interacts with the system, some time has elapsed or any other input has arrived. More specifically, apps can tell libavg objects - so-called Publishers - that they would like to be notified in the case of an event. This is called subscribing; the notification takes the form of a function call from libavg to the app.

The app displays a "Hello World" text that is moved to a new position when the mouse button is pressed over the item. In this case, the WordsNode is the Publisher. The app registers for the event using node.subscribe(), and when the click happens, MainDiv.onDown is called by libavg.

The simple example above illustrates the general mechanism: To register for an event, call Publisher.subscribe() with the MessageID (in the example, Node.CURSOR_DOWN) and a Python callable (in the example, self.onClick) as parameters. Events you can subscribe to include all user input (e.g., key presses, mouse clicks and movements, touches on a touchscreen,...), but the principle is much broader: This is libavg's general notification mechanism. There are events that are triggered on each frame (player.ON_FRAME), when the end of a media file has been reached (player.END_OF_FILE), etc.. Any number of clients can subscribe to a message, and all of them will be invoked when the event occurs. In most cases, you don’t have to deregister messages to clean up either. Subscriptions are based on weak references wherever possible, so when the object they refer to disappears, the subscription will just disappear as well. In cases where you would like to explicitly stop receiving a certain event, call Publisher.unsubscribe().

Like most user interface libraries, libavg is based on an event-driven programming model. This means that the flow of the program is determined by external events such as user actions or timers. Internally, libavg runs a main loop that looks approximately like this:

1whilenot(stopping):
2 handleTimers()
3 handleEvents()
4 render()

All python code is executed in handleTimers() and handleEvents(). As a consequence, the display is only updated after the python code returns, when render() runs. It also means that an event handler that takes a significant amout of time (such as waiting for network transmission) will cause screen updates to hang during this time.

Timers that fire after a set interval are an exception to the 'all notifications use a publish-subscribe mechanism' principle declared above: There is a separate Player.setTimeout() method that handles this event type.

The setTimeout() call is what makes this happen. It tells libavg to call the routine specified (in this case, moveText()) after a certain time has elapsed (in this case, 1000 milliseconds). In addition to setTimeout(), there is a setInterval() method that lets you register a routine to call regularly.

Any Python callable can be registered as a callback, including standalone functions, class methods, lambdas and even class constructors. For simple callbacks - standalone functions or class methods -, this simply means passing the function name without parentheses to subscribe():

1node.subscribe(avg.Node.CURSOR_DOWN, self.onDown)

In this case, onDown is called with an additional parameter, event, so you need to declare it as follows:

1defonDown(self, event):

In some cases however, it becomes necessary to pass additional parameters to the callback when subscribe is called. To do this, you can use lambdas. An in-depth explanation of how lambda works is out of scope for this article (http://www.diveintopython.net/power_of_introspection/lambda_functions.html has a good explanation), but as an example for the power of this construct, have a look at this extremely compact number pad implementation that creates ten buttons which act differently: