Moving GtkAdjustment's public fields into private structure

Background

GtkAdjustment is used by quite a few widgets throughout the GTK+. Two main (only?) uses are:

  • serve as a value repository (GtkRange uses it for this)

  • interconnect two widgets (scrollable widgets and their parents are connected like this)

Before public fields removal, owner of the adjustment changed it's fields directly and emitted proper signal. This simple principle allowed signal emission to be done separately form field changes, which was used to "compress" multiple signal emissions into single one. GtkRange relies on this to implement it's various update policies.

With direct access, no verification could be done on values of adjustment and owner of adjustment was completely responsible for keeping it in consistent state. Most developers created wrappers for setting adjustment's values that kept adjustment in sane state.

As a last thing, signals were sometimes emitted by GtkAdjustment even if the underlying value haven't changed.

Problem

With removal of public fields, accessors are now responsible for signal emission. In order to be able to implement delayed-update policies, GtkAdjustment needs to have some mean of delaying signal emission. Most of the accessors allow this by means of g_object_freeze_notify()/g_object_thaw_notify() functions, but gtk_adjustment_set_value() always emits ::value-changed signal as soon as value has been changed.

Solution

This problem can be relatively easily solved by adapting gtk_adjustment_set_value() setter to work like all other setters in GtkAdjustment.

Possible enhancements

With fields protected form direct modification, burden of ensuring the consistency can be moved from application code directly into GtkAdjustment. There are quite a few benefits:

  • less code duplication (currently each "user" of GtkAdjustment needs to create it's own wrappers)

  • lower the overhead (with fields hidden from public, all value retrievals need to go through accessors; if the code is moved inside GtkAdjustment, some checks can be avoided)

  • smarter/stricter rules can be enforced

Signal emission can also be improved by ensuring that signals are only emitted when real change occurred.

To demonstrate this, I took one typical function that ensures consistency from GtkIconView (this function also used by GtkLayout, GtkTextView). Second fragment shows how this function would look like if no checking is added to GtkAdjustment.

Original Function

2779 static void
2780 gtk_icon_view_set_adjustment_upper (GtkAdjustment *adj,
2781                                     gdouble        upper)
2782 {
2783   if (upper != adj->upper)
2784     {
2785       gdouble min = MAX (0.0, upper - adj->page_size);
2786       gboolean value_changed = FALSE;
2787 
2788       adj->upper = upper;
2789 
2790       if (adj->value > min)
2791         {
2792           adj->value = min;
2793           value_changed = TRUE;
2794         }
2795 
2796       gtk_adjustment_changed (adj);
2797 
2798       if (value_changed)
2799         gtk_adjustment_value_changed (adj);
2800     }
2801 }

Updated function (uses accessors)

2779 static void
2780 gtk_icon_view_set_adjustment_upper (GtkAdjustment *adj,
2781                                     gdouble        upper)
2782 {
2783   if (upper != gtk_adjustment_get_upper (adj))
2784     {
2785       gdouble min = MAX (0.0, upper - gtk_adjustment_get_page_size (adj));
2786 
2787       /* Postpone signal emission until all fields are set */
2788       g_object_freeze_notify (G_OBJECT (adj));
2789 
2790       gtk_adjustment_set_upper (adj, upper);
2791 
2792       if (gtk_adjustment_get_value (adj) > min)
2793         gtk_adjustment_set_value (adj, min);
2794 
2795       g_object_thaw_notify (G_OBJECT (adj));
2796     }
2797 }

Projects/GTK+/GtkAdjustment (last edited 2013-11-22 15:37:05 by WilliamJonMcCann)