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 }