Though SPRepr provides "signals" for notification when individual nodes change, there is no mechanism to receive notification for overall document changes. This means you can attach a function to a specific change in a specific node, not to any changes in the entire document. However, with the addition of the transactions code, it would not be very hard to implement if you wanted it.
SPRepr doesn't use GObject signals; SPReprs maintain lists of SPReprEventVectors (added via sp_repr_add_listener), which are used to specify callbacks when something changes. Use
sp_repr_add_listener(SPRepr *repr, SPReprEventVector const *vector, void *data);
to add a vector of listeners to the repr (i.e. node). The data is what will be sent to the vector's functions as the last parameter (see below). When no longer needed, you can remove a vector from the repr using data as the selector:
sp_repr_remove_listener_by_data(SPRepr *repr, void *data);
The vector contains pointers to callback functions (those that you don't need may be NULL) in this order:
static SPReprEventVector vector = {
NULL, /* destroy */
NULL, /* add_child */
NULL, /* child_added */
NULL, /* remove_child */
NULL, /* child_removed */
NULL, /* change_attr */
NULL, /* attr_changed */
NULL, /* change_list */
NULL, /* content_changed */
NULL, /* change_order */
NULL /* order_changed */
};
See node-context.cpp or widgets/sp-xmlview-attr-list.cpp for an example implementation. Here are the details on each of the callbacks:
void (* destroy) (SPRepr *repr, void *data);
Called when the repr is destroyed.
unsigned int (* add_child) (SPRepr *repr, SPRepr *child, SPRepr *ref, void *data);
Called before a child is added; the handler can return FALSE to veto the addition. ref is the child after which the new child is to be added.
void (* child_added) (SPRepr *repr, SPRepr *child, SPRepr *ref, void *data);
Called once a child has been added.
unsigned int (* remove_child) (SPRepr *repr, SPRepr *child, SPRepr *ref, void *data);
Called before a child is to be removed; it may veto the removal by returning FALSE. ref is the child before the child to be removed.
void (* child_removed) (SPRepr *repr, SPRepr *child, SPRepr *ref, void *data);
Called after a child is removed; ref is the child that used to precede the removed child.
unsigned int (* change_attr) (SPRepr *repr, gchar const *key, gchar const *oldval, gchar const *newval, void *data);
For Element nodes. Called before an attribute is changed; can veto by returning FALSE.
void (* attr_changed) (SPRepr *repr, gchar const *key, gchar const *oldval, gchar const *newval, void *data);
Called after an attribute has been changed.
unsigned int (* change_content) (SPRepr *repr, gchar const *oldcontent, gchar const *newcontent, void *data);
For Text nodes. Called before an element's content is changed; can veto by returning FALSE.
void (* content_changed) (SPRepr *repr, gchar const *oldcontent, gchar const *newcontent, void *data);
Called after an element's content has been changed.
unsigned int (* change_order) (SPRepr *repr, SPRepr *child, SPRepr *oldref, SPRepr *newref, void *data);
Called before a child of repr is rearranged in its list of children. oldref is the child currently preceding the child; the child will be moved to the position after newref. Can veto by returning FALSE.
void (* order_changed) (SPRepr *repr, SPRepr *child, SPRepr *oldref, SPRepr *newref, void *data);
Called once the child has been moved to its new position in the child order.
- NOTE!!!!! the veto callbacks are currently not useful because some functions SPObjects register for callbacks have side-effects -- by the time the veto was made, other callbacks might already have modified things...
- Although it wasn't seen as a problem in Sodipodi, this is on my personal list of things to fix... -- mental