Search guides and the APICtrl K
  1. API reference
  2. Applications

broadcaster.h

"Something changed": told to whoever asked, without either side knowing the other.

#include <sonore/broadcaster.h>
On this page

Design notes

What it is for

A preset was loaded, and four parts of the editor need to redraw. A sample finished loading on a worker thread, and the waveform, the length readout and the keyboard map all care. Without something like this, whatever performs the change has to hold a pointer to every part of the interface that reacts to it -- which is how a DSP object ends up including a header for a scroll bar.

The important half is the COALESCING

A synchronous callback is four lines and nobody needs a class for it. What is actually worth having is the asynchronous form: mark that something changed, as often as you like, and have the listeners told ONCE on the next UI tick.

That is the difference between a preset load notifying forty parameter listeners forty times -- each one repainting -- and notifying them once. The synchronous version of a "reload everything" handler called forty times is the classic reason loading a preset takes a visible second.

What it is not

Not thread-safe for REGISTRATION. Listeners are added and removed on the UI thread, which is where components live, and a mutex around that would be protecting a race nobody has. markChanged IS callable from another thread: it sets one atomic flag and nothing else, so a worker finishing a load can say so without touching the listener list.

Types 3

Anything that wants to hear about a change.

A plain interface rather than a std::function, because a listener has to be REMOVABLE -- and two std::functions cannot be compared, so a list of them can be added to and never pruned. A component that outlived its subscription would be called through a dangling pointer, which is the one failure this class exists to make impossible.

A list of ChangeListeners, told that something changed: at once (sendSynchronousChangeMessage) or once per dispatch however many changes were marked (sendChangeMessage). Mirrors the reference's class of the same name; see the file comment for why the coalescing form is the one that matters.

Nothing dispatches by itself, unlike there: whoever owns the broadcaster calls dispatchPendingChanges() from a UI-thread tick. sendChangeMessage is the only call safe from any thread; registration and both deliveries belong to the UI thread. Listeners are not owned -- one that is destroyed removes itself first. A listener may remove itself or another, or delete the broadcaster, from inside its callback; after a delete the rest are not called. Usually a base class, as FileBasedDocument and PropertiesFile use it.

class LambdaChangeListener : public ChangeListener

A listener made from a lambda, for the common case where the thing reacting is not a class that wants a base.

It has to be OWNED by whoever it belongs to -- a member, not a temporary -- because the broadcaster holds a pointer. That is the same rule every listener has and the reason this is a named object rather than an overload of addChangeListener taking a function.

↑↓ to move↵ to openEvery public name in the headers, and every guide