Bug 617446 - Allow custom code to be executed when dispatching a NotifyQueue
Allow custom code to be executed when dispatching a NotifyQueue
Status: NEW
Product: glib
Classification: Platform
Component: gobject
unspecified
Other Linux
: Normal enhancement
: ---
Assigned To: gtkdev
gtkdev
:
Depends on:
Blocks: gcontroller
  Show dependency tree
 
Reported: 2010-05-02 14:40 UTC by Emmanuele Bassi (:ebassi)
Modified: 2013-08-19 11:43 UTC (History)
3 users (show)

See Also:
GNOME target: ---
GNOME version: ---


Attachments
object: Add ::thaw-notify signal (2.15 KB, patch)
2010-06-02 13:56 UTC, Emmanuele Bassi (:ebassi)
none Details | Diff | Review

Description Emmanuele Bassi (:ebassi) 2010-05-02 14:40:06 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.
Comment 1 Ray Strode [halfline] 2010-05-12 02:51:48 UTC
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.
Comment 2 Emmanuele Bassi (:ebassi) 2010-05-12 09:37:37 UTC
I like the idea of a ::thaw-notify signal. a lot, actually.
Comment 3 Emmanuele Bassi (:ebassi) 2010-06-02 13:56:18 UTC
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.
Comment 4 Emmanuele Bassi (:ebassi) 2013-08-19 11:43:48 UTC
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.

Note You need to log in before you can comment on or make changes to this bug.