Allow custom code to be executed when dispatching a NotifyQueue
@ebassi
Submitted by Emmanuele Bassi Link to original bug (#617446)
Description
currently, the ::notify signal is emitted per-property. for complex objects changing different properties at the same time it's possible to compress the notification queue using the freeze...notify+...thaw mechanism. this, however, keeps the ::notify signal emission per-property, to maintain invariants and API guarantees.
it is not possible though, from within the ::notify signal emission, to know how many properties are going to be notified, or how many are left.
for instance, given a GObjectController class following the design at:
http://live.gnome.org/EmmanueleBassi/GController
which would allow emitting a ::changed signal with a reference to all the properties that have been changed between a freeze_notify() and a thaw_notify(), there is no way to actually implement bulk notification without sub-classing GObject and change the dispatch_properties_changed virtual function inside the GObjectClass vtable. this obviously lacks generality, as it would only work with a specific sub-type of GObject.
rationale: this is a slightly more complex way of dealing with the notification of changes on object properties by it allows:
• better performance in case of bulk changes (a single notification function instead of multiple ones); • a reusable MVC design for creating UI elements binding to objects; • a structured property change notification that is detached from the GObject class and allows further changes without requiring changes to the GObject class itself.
unfortunately, I have no well defined proposal on how to make this work within the GObject class implementation; creating a ::dispatch-properties-changed signal would overlap the ::notify signal and would confuse the overall GObject design.
adding a callback mechanism similar to the weak/toggle references would in theory work:
void g_object_add_property_dispatch (GObject *gobject, GPropertyDispatchCallback callback, gpointer user_data, GDestroyNotify notify);
though I feel it's a bit on the clunky side of the API.
another possible angle of attack would be the ability to retrieve the GObjectNotifyContext from an object and add a callback for the dispatcher to allow third party code to run before/after the GObject dispatcher.
finally, a fourth option would be to allow querying a GObject during the ::notify signal emission how many properties are left, so that third party code can connect to the ::notify signal and do something like:
static void on_notify (GObject *gobject, GParamSpec *pspec, GController *controller) { static GControllerReference *ref; static guint counter = 0;
guint n_props = g_object_get_notify_count (gobject);
/* first emission */
if (ref == NULL)
ref = g_controller_create_reference (controller, ...);
g_controller_reference_add_index (ref, counter, pspec->name);
/* last property: emit the ::changed signal */
if (n_props == 0)
{
g_controller_emit_changed (controller, ref);
g_object_unref (ref);
/* reset for the next notification emission */
ref = NULL
counter = 0;
}
else
counter += 1;
}
which is slightly more clunky but still feasible.