GNOME Bugzilla – Bug 617446
Allow custom code to be executed when dispatching a NotifyQueue
Last modified: 2018-05-24 12:15:56 UTC
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.
What about a 'thaw-notify' signal that gets emitted at the top of g_object_notify_queue_thaw or 'notify-thawed' at the bottom of that function? It would be very similar to your 'dispatch-properties-changed' idea but be specific to freezing/thawing batched updates instead of getting emitted for every change. This way it would sort of fit along-side 'notify' in the API instead of rendering it redundant.
I like the idea of a ::thaw-notify signal. a lot, actually.
Created attachment 162539 [details] [review] object: Add ::thaw-notify signal The ::thaw-notify signal is emitted then the NotifyQueue for an object is fully thawed, and the property changes are dispatched. The signal allows arbitrary code to get a bulk notification in case multiple properties changed in the same queue, to avoid multiple invocations of the GObject::notify signal.
given the high overhead of a signal, and given the critical path of property notification, I was thinking of having a GDispatchFunc callback registered on a per-object basis. aside from GController, this could would be useful for animation frameworks based on properties; it would allow compressing all animation changes done during the frame advancement to cause a single state update, even for interdependent properties - e.g. change the transformation matrix once, after the decomposed transformations (rotate, scale, translate) have been updated; or update the boundaries of a scene graph element once, after the positional and dimensional properties have been changed. the API would look like: g_object_add_dispatch_notify (GObject *, GDispatchFunc, gpointer, GDestroyNotify) and GDispatchFunc would have the following signature: void (* GDispatchFunc) (GObject *, GParamSpec **pspec, guint n_pspecs) something cute would be dispatching the property notification in the same main context as the g_object_add_dispatch_notify() func was called.
-- GitLab Migration Automatic Message -- This bug has been migrated to GNOME's GitLab instance and has been closed from further activity. You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.gnome.org/GNOME/glib/issues/290.