Since the release of RoboFont 4.0, Subscriber is favored instead of Observers for handling events. Subscriber is easier to use, less error-prone and it allows event coalescing. It is a great improvement. Observers and mojo.events will not be technically deprecated – because Subscriber is built on top of them – but we encourage developers to move to Subscriber!

RoboFont is built around a software design model known as The Observer Pattern:

  • a dispatcher sends out notifications when certain events happen
  • observers can subscribe and unsubcribe from specific events

There are 3 different types of notifications in RoboFont:

font data
defcon notifications
user interface
RoboFont notifications
user interaction
NSEvent notifications

Observing changes to font data

The base font objects used by RoboFont are provided by defcon. Defcon includes its own object observing system which sends out notifications for changes to the font data.

Here’s a basic example showing how to subscribe to changes to the width of a glyph:

class MyInterface:

    def __init__(self, glyph):
        self.glyph = glyph
        self.glyph.addObserver(self, "glyphWidthChangedCallback", "Glyph.WidthChanged")

    def glyphWidthChangedCallback(self, notification):
        glyph = notification.object
        oldWidth = notification.data['oldValue']
        newWidth = notification.data['newValue']
        print(f"width of '{glyph.name}' changed! {oldWidth}{newWidth}")

MyInterface(CurrentGlyph())

All font objects in defcon have addObserver and removeObserver methods.

Each font object posts a set of individual notifications about specific kinds of changes. For example, a glyph has separate notifications for changes to width, contours, components, guidelines, anchors, etc.

Use help() to find out which notifications are posted by each object:

from defcon import Contour
help(Contour)
Help on class Contour in module defcon.objects.contour:

class Contour(defcon.objects.base.BaseObject)
 |  This object represents a contour and it contains a list of points.
 |
 |  **This object posts the following notifications:**
 |
 |  ===============================
 |  Name
 |  ===============================
 |  Contour.Changed
 |  Contour.WindingDirectionChanged
 |  Contour.PointsChanged
 |  Contour.IdentifierChanged
 |  ===============================
 |
 |  ...

Observing user interface actions

Font data is edited using the RoboFont interface, which consists of several windows, menus, panels, etc. RoboFont has its own object observing system which sends out notifications for user interface actions.

Here’s a basic example showing how to subscribe to changes in the current glyph:

from mojo.events import addObserver

class MyInterface:

    def __init__(self):
        addObserver(self, "currentGlyphChangedCallback", "currentGlyphChanged")

    def currentGlyphChangedCallback(self, notification):
        glyph = notification['glyph']
        print("current glyph is '%s'" % glyph.name)

MyInterface()

See RoboFont observers for a list all user interface notifications available.

Use the Event Observer extension to see all interface notifications while you work.

Observing user interaction

Last edited on 01/09/2021