#include <ggi/gg.h>
typedef int (ggfunc_observer_update)(void *arg, int flag, void *data);
struct gg_observer {
ggfunc_observer_update *update;
void *arg;
GG_LIST_ENTRY(gg_observer) _others;
};
struct gg_publisher {
GG_LIST_HEAD(gg_observer_list, gg_observer) observers;
};
#define INIT_PUBLISHER(pub) GG_LIST_INIT(&((pub)->observers))
struct gg_observer * ggAddObserver(struct gg_publisher *,
ggfunc_observer_update *, void *);
void ggDelObserver(struct gg_observer *);
void ggNotifyObservers(struct gg_publisher *, int, void *);
void ggClearPublisher(struct gg_publisher *);
struct gg_publisher defines a channel on which observers can be registered. An observer is simply an opaque value and a callback receiving that value as first argument, a flag, and an opaque channel-specific message. The idea is that if you known the observable you're listening on, you know the semantics behind the flag and message. When the observable is triggered, all observers' callbacks will be fired.
ggAddObserver registers a new observer on a publisher.
ggDelObserver unregisters the given observer from its publisher and frees it.
ggNotifyObservers triggers all observers update functions for that publisher. The flag and message will be given to the observers' update callbacks. An observer *must not* call ggDelObserver on itself in the update function to unregister. Instead it must return a non-zero value.
#include <ggi/gg.h>
#include <stdio.h>
int update(void* o, int f, void *d) {
printf("update called for observer %p, flag=%i, data=%p\n", o, f ,d);
if (o == 1) {
return 1; /* unregister */
}
return 0;
}
int main() {
struct gg_publisher pub;
struct gg_observer *o1, *o2;
INIT_PUBLISHER(&pub);
o1 = ggAddObserver(&pub, update, (void*)1);
o2 = ggAddObserver(&pub, update, (void*)2);
ggNotifyObservers(&pub, 0, NULL);
ggNotifyObservers(&pub, 1, NULL);
ggClearPublisher(&pub);
return 0;
}