Cleaning up Messaging

Over time, libavg has accumulated support for a number of message callbacks. These are:

In addition, we’re currently adding some widget classes, and that adds more callbacks for button presses, list scrolling, etc.

While this allows you to get a lot of things done, it’s not consistent and hence not very easy to learn. The methods used to register for messages aren’t standardized. They have inconsistent names and varying parameters. Some allow you to register several callbacks for an event, some don’t. For an example, compare Node.connectEventHandler() to the gesture interface using constructor parameters. In addition, the implementation is just as problematic. We have multiple callback implementations in C++ and Python, which results in error-prone, high-maintanance code.

Publishers

When work on the new widget classes promised to make things even more convulted, we decided to do something about the situation and implement a unified, consistent messaging system. The result is a publisher-subscriber system:

  • Publishers register MessageIDs.
  • Anyone can subscribe to these MessageIDs by registering callbacks. Several subscribers are possible in all cases.
  • When an event occurs, all registered callbacks are invoked.

We spent quite a bit of time to make a lot of things “just work”. The subscription interface is very simple. As an example, this is how you register for a mouse or touch down event:

node.subscribe(node.CURSOR_DOWN, self.onDown)

Any Python callable can be registered as a callback, including standalone functions, class methods, lambdas and even class constructors. 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.

You can write your own publishers can be written in Python or C++ by simply deriving from the Publisher class. In Python, you need two lines of code to register a message:

class Button(avg.DivNode):
    CLICKED = avg.Publisher.genMessageID()
    [...]
    def __init__(...):
        self.publish(self.CLICKED)
    [...]

and this line invokes all registered subscribers:

self.notifySubscribers(self.CLICKED, [])

The second parameter to notifySubscribers is a list of parameters to pass to the subscribers.

Transitioning

Transitioning old programs to the new interface is not very hard and involves replacing old calls to Node.connectEventHandler(), VideoNode.setEOFCallback(), Contact.connectListener() and so on with invocations of subscribe(). We’ll keep the old interfaces around for a while, but they’ll probably be removed when we release ver 2.0.

One thought on “Cleaning up Messaging

  1. Pingback: Version 1.8 Released | libavg

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>