diff --git a/gtk/gtkadjustment.c b/gtk/gtkadjustment.c
index dd1b3f6..0c1a168 100644
--- a/gtk/gtkadjustment.c
+++ b/gtk/gtkadjustment.c
@@ -24,12 +24,153 @@
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
  */
 
+/**
+ * SECTION:gtkadjustment
+ * @Short_description: A GtkObject representing an adjustable bounded value
+ * @Title: GtkAdjustment
+ * @See_also: #GtkSpinButton, #GtkViewport, #GtkRange,#GtkHScrollbar,
+ *            #GtkVScrollbar, #GtkHScale, #GtkVScale, #GtkScrolledWindow
+ *
+ * The #GtkAdjustment object represents a value which has an associated lower
+ * and upper bound, together with step increment, page increment and page size.
+ *
+ * All aforementioned values are represented by six properties of
+ * #GtkAdjustment: value is represented by #GtkAdjustment:value property, lower
+ * is represented by #GtkAdjustment:lower property, upper is represented by
+ * #GtkAdjustment:upper property, step increment is represented by
+ * #GtkAdjustment:step-increment property, page increment is represented by
+ * #GtkAdjustment:page-increment property and page size is represented by
+ * #GtkAdjustment:page-size property.
+ *
+ * There are some rules that should be followed when using #GtkAdjustment:
+ *
+ * <orderedlist>
+ *   <listitem>
+ *     <para>lower <= upper</para>
+ *   </listitem>
+ *   <listitem>
+ *     <para>page_size belongs to the interval [0, upper - lower]</para>
+ *   </listitem>
+ *   <listitem>
+ *     <para>value belongs to the interval [lower, upper - page_size]</para>
+ *   </listitem>
+ * </orderedlist>
+ *
+ * When applications sets one of the properties to invalid value, #GtkAdjustment
+ * will automatically resolve the conflict.
+ *
+ * <table>
+ *   <title>Conflict resolution table for #GtkAdjustment</title>
+ *   <tgroup cols="2">
+ *     <thead>
+ *       <row>
+ *         <entry>Conflict</entry>
+ *         <entry>Resolution</entry>
+ *       </row>
+ *     </thead>
+ *     <tbody>
+ *       <row>
+ *         <entry><programlisting>lower > upper</programlisting></entry>
+ *         <entry><programlisting>upper = lower</programlisting></entry>
+ *       </row>
+ *       <row>
+ *         <entry><programlisting>page_size < 0 ||
+ * page_size > upper - lower</programlisting></entry>
+ *         <entry><programlisting>page_size = CLAMP (page_size, 0,
+ *                    upper - lower)</programlisting></entry>
+ *       </row>
+ *       <row>
+ *         <entry><programlisting>value < lower ||
+ * value > upper - page_size</programlisting></entry>
+ *         <entry><programlisting>value = CLAMP (value, lower,
+ *                upper - page_size)</programlisting></entry>
+ *       </row>
+ *     </tbody>
+ *   </tgroup>
+ * </table>
+ *
+ * #GtkAdjustment is usually used in two kinds of situations: when simple scalar
+ * values needs to be restricted to a certain range and when two widgets need to
+ * be coupled together.
+ *
+ * In first case, #GtkAdjustment:page-size property should be set to 0 (scalars
+ * do not have a dimension that would need to be represented in
+ * #GtkAdjustment:page-size property). Sample widgets that use #GtkAdjustment in
+ * this manner are #GtkSpinButton and #GtkHScale.
+ *
+ * When two widgets are coupled together by #GtkAdjustment, one widget usually
+ * controls #GtkAdjustment:value property; other widget controls all other
+ * properties. #GtkScrollbar<!---->s are connected to the widget they are
+ * scrolling (for example #GtkTreeView) like this. In this setting,
+ * #GtkScrollbar would control #GtkAdjustment:value property while #GtkTreeView
+ * controls all other properties.
+ *
+ * When setting multiple properties of #GtkAdjustment using individual setters,
+ * #GtkAdjustment::changed signal will also be emitted multiple times. There are
+ * several ways of compressing emissions:
+ *
+ * <orderedlist>
+ *   <listitem>
+ *     <para>Use g_object_set() to set multiple properties at once.</para>
+ *   </listitem>
+ *   <listitem>
+ *     <para>Use gtk_adjustment_configure() to set all properties at
+ *           once.</para>
+ *   </listitem>
+ *   <listitem>
+ *     <para>Enclose all setter calls with g_object_freeze_notify() and
+ *           g_object_thaw_notify() like this:</para>
+ *     <informalexample><programlisting><![CDATA[
+ * GtkAdjustment *adjustment;
+ *
+ * g_object_freeze_notify (G_OBJECT (adjustment));
+ * gtk_adjustment_set_upper (adjustment, 100.0);
+ * gtk_adjustment_set_lower (adjustment, 30.0);
+ * gtk_adjustment_set_page_size (adjustment, 10.0);
+ * g_object_thaw_notify (G_OBJECT (adjustment));
+ *     ]]></programlisting></informalexample>
+ *   </listitem>
+ * </orderedlist>
+ *
+ * You also need to use one those methods when setting multiple properties that
+ * would cause conflicts. Conflict resolution will give strange results if not
+ * properly delayed.
+ *
+ * <programlisting>
+ * /&ast; Bad &ast;/
+ * GtkAdjustment *adj = gtk_adjustment_new (40.0, 30.0, 50.0, 1.0, 2.0, 10.0);
+ * gtk_adjustment_set_upper (adj, 20.0);
+ * gtk_adjustment_set_lower (adj, 0.0);
+ * /&ast; Result: value = 30.0,
+ *  *         lower = 0.0,
+ *  *         upper = 30.0
+ *  *         page_size = 0.0
+ * &ast;/
+ *
+ * /&ast; Good &ast;/
+ * GtkAdjustment *adj = gtk_adjustment_new (40.0, 30.0, 50.0, 1.0, 2.0, 10.0);
+ * g_object_set (adj,
+ *               "upper", 20.0,
+ *               "lower", 0.0,
+ *               NULL);
+ * /&ast; Result: value = 20.0,
+ *  *         lower = 0.0,
+ *  *         upper = 20.0
+ *  *         page_size = 10.0
+ * &ast;/
+ * </programlisting>
+ */
+
 #include "config.h"
 #include "gtkadjustment.h"
 #include "gtkmarshalers.h"
 #include "gtkprivate.h"
 #include "gtkintl.h"
 #include "gtkalias.h"
+#include <math.h>
+
+/* This value is open for discussion */
+#define DELTA 1e-10
 
 enum
 {
@@ -49,24 +190,47 @@ enum
   LAST_SIGNAL
 };
 
+enum
+{
+  OLD_VAL,
+  NEW_VAL,
+  NO_VALS
+};
 
-static void gtk_adjustment_get_property                (GObject      *object,
-                                                        guint         prop_id,
-                                                        GValue       *value,
-                                                        GParamSpec   *pspec);
-static void gtk_adjustment_set_property                (GObject      *object,
-                                                        guint         prop_id,
-                                                        const GValue *value,
-                                                        GParamSpec   *pspec);
-static void gtk_adjustment_dispatch_properties_changed (GObject      *object,
-                                                        guint         n_pspecs,
-                                                        GParamSpec  **pspecs);
+/* Value of each property is stored twice in order to be able to compare values
+ * and emit proper signal only when property has changed.
+ */
+struct _GtkAdjustmentPriv
+{
+  gdouble value[NO_VALS];
+  gdouble lower[NO_VALS];
+  gdouble upper[NO_VALS];
+  gdouble step_increment[NO_VALS];
+  gdouble page_increment[NO_VALS];
+  gdouble page_size[NO_VALS];
+};
 
-static guint adjustment_signals[LAST_SIGNAL] = { 0 };
+static void gtk_adjustment_get_property                (GObject        *object,
+                                                        guint           prop_id,
+                                                        GValue         *value,
+                                                        GParamSpec     *pspec);
+static void gtk_adjustment_set_property                (GObject        *object,
+                                                        guint           prop_id,
+                                                        const GValue   *value,
+                                                        GParamSpec     *pspec);
+static void gtk_adjustment_dispatch_properties_changed (GObject        *object,
+                                                        guint           n_pspecs,
+                                                        GParamSpec    **pspecs);
+
+/* Local helper functions */
+static void enforce_restrictions                       (GtkAdjustment  *adjustment);
+static gint check_and_emit_notify                      (GObject        *object,
+							gdouble        *vals,
+							const char     *prop);
 
-static guint64 adjustment_changed_stamp = 0; /* protected by global gdk lock */
+static guint adjustment_signals[LAST_SIGNAL] = { 0 };
 
-G_DEFINE_TYPE (GtkAdjustment, gtk_adjustment, GTK_TYPE_OBJECT)
+G_DEFINE_TYPE (GtkAdjustment, gtk_adjustment, G_TYPE_INITIALLY_UNOWNED)
 
 static void
 gtk_adjustment_class_init (GtkAdjustmentClass *class)
@@ -118,9 +282,6 @@ gtk_adjustment_class_init (GtkAdjustmentClass *class)
    * GtkAdjustment:upper:
    * 
    * The maximum value of the adjustment. 
-   * Note that values will be restricted by 
-   * <literal>upper - page-size</literal> if the page-size 
-   * property is nonzero.
    *
    * Since: 2.4
    */
@@ -172,9 +333,6 @@ gtk_adjustment_class_init (GtkAdjustmentClass *class)
    * GtkAdjustment:page-size:
    * 
    * The page size of the adjustment. 
-   * Note that the page-size is irrelevant and should be set to zero
-   * if the adjustment is used for a simple scalar value, e.g. in a 
-   * #GtkSpinButton.
    * 
    * Since: 2.4
    */
@@ -210,12 +368,21 @@ gtk_adjustment_class_init (GtkAdjustmentClass *class)
 static void
 gtk_adjustment_init (GtkAdjustment *adjustment)
 {
-  adjustment->value = 0.0;
-  adjustment->lower = 0.0;
-  adjustment->upper = 0.0;
-  adjustment->step_increment = 0.0;
-  adjustment->page_increment = 0.0;
-  adjustment->page_size = 0.0;
+  adjustment->priv = G_TYPE_INSTANCE_GET_PRIVATE (adjustment,
+						  GTK_TYPE_ADJUSTMENT,
+						  GtkAdjustmentPriv);
+  adjustment->priv->value[OLD_VAL] = 0.0;
+  adjustment->priv->value[NEW_VAL] = 0.0;
+  adjustment->priv->lower[OLD_VAL] = 0.0;
+  adjustment->priv->lower[NEW_VAL] = 0.0;
+  adjustment->priv->upper[OLD_VAL] = 0.0;
+  adjustment->priv->upper[NEW_VAL] = 0.0;
+  adjustment->priv->step_increment[OLD_VAL] = 0.0;
+  adjustment->priv->step_increment[NEW_VAL] = 0.0;
+  adjustment->priv->page_increment[OLD_VAL] = 0.0;
+  adjustment->priv->page_increment[NEW_VAL] = 0.0;
+  adjustment->priv->page_size[OLD_VAL] = 0.0;
+  adjustment->priv->page_size[NEW_VAL] = 0.0;
 }
 
 static void
@@ -224,27 +391,29 @@ gtk_adjustment_get_property (GObject    *object,
                              GValue     *value,
                              GParamSpec *pspec)
 {
-  GtkAdjustment *adjustment = GTK_ADJUSTMENT (object);
+  GtkAdjustmentPriv *priv = GTK_ADJUSTMENT (object)->priv;
 
+  /* If getter is called before we had a chance to process everyting, we return
+   * old values, since we know they are OK. */
   switch (prop_id)
     {
     case PROP_VALUE:
-      g_value_set_double (value, adjustment->value);
+      g_value_set_double (value, priv->value[OLD_VAL]);
       break;
     case PROP_LOWER:
-      g_value_set_double (value, adjustment->lower);
+      g_value_set_double (value, priv->lower[OLD_VAL]);
       break;
     case PROP_UPPER:
-      g_value_set_double (value, adjustment->upper);
+      g_value_set_double (value, priv->upper[OLD_VAL]);
       break;
     case PROP_STEP_INCREMENT:
-      g_value_set_double (value, adjustment->step_increment);
+      g_value_set_double (value, priv->step_increment[OLD_VAL]);
       break;
     case PROP_PAGE_INCREMENT:
-      g_value_set_double (value, adjustment->page_increment);
+      g_value_set_double (value, priv->page_increment[OLD_VAL]);
       break;
     case PROP_PAGE_SIZE:
-      g_value_set_double (value, adjustment->page_size);
+      g_value_set_double (value, priv->page_size[OLD_VAL]);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -258,28 +427,28 @@ gtk_adjustment_set_property (GObject      *object,
                              const GValue *value,
                              GParamSpec   *pspec)
 {
-  GtkAdjustment *adjustment = GTK_ADJUSTMENT (object);
+  GtkAdjustmentPriv *priv = GTK_ADJUSTMENT (object)->priv;
   gdouble double_value = g_value_get_double (value);
 
   switch (prop_id)
     {
     case PROP_VALUE:
-      gtk_adjustment_set_value (adjustment, double_value);
+      priv->value[1] = double_value;
       break;
     case PROP_LOWER:
-      adjustment->lower = double_value;
+      priv->lower[1] = double_value;
       break;
     case PROP_UPPER:
-      adjustment->upper = double_value;
+      priv->upper[1] = double_value;
       break;
     case PROP_STEP_INCREMENT:
-      adjustment->step_increment = double_value;
+      priv->step_increment[1] = double_value;
       break;
     case PROP_PAGE_INCREMENT:
-      adjustment->page_increment = double_value;
+      priv->page_increment[1] = double_value;
       break;
     case PROP_PAGE_SIZE:
-      adjustment->page_size = double_value;
+      priv->page_size[1] = double_value;
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -292,33 +461,93 @@ gtk_adjustment_dispatch_properties_changed (GObject     *object,
                                             guint        n_pspecs,
                                             GParamSpec **pspecs)
 {
-  gboolean changed = FALSE;
-  gint i;
-
+  /* This function operates in three steps:
+   * 1. ensure adjustment is in sane state
+   * 2. emit notifications for every modified property (properties can be
+   *    modified either in _set_property() or during step 1)
+   * 3. emit proper signals; if both ::changed and ::value-changed need to be
+   *    emitted, ::changed is emitted first, ::value-changed second
+   */
+  GtkAdjustmentPriv *priv = GTK_ADJUSTMENT (object)->priv;
+  gint ch = 0;     /* Should ::changed signal be emitted? */
+  gint val_ch = 0; /* Should ::value-changed signal be emitted? */
+
+  /* Step 1 */
+  enforce_restrictions (GTK_ADJUSTMENT (object));
+
+  /* Step 2 */
+  /* NOTE:
+   * This is done manually, because GObject's notify dispatcher will not emit
+   * notifications for properties we only modified inside
+   * enforce_restrictions() (when for example, upper has been set to be smaller
+   * than current value, which caused value to be clamped).
+   */
+  val_ch = check_and_emit_notify (object, priv->value, "value");
+  ch += check_and_emit_notify (object, priv->lower, "lower");
+  ch += check_and_emit_notify (object, priv->upper, "upper");
+  ch += check_and_emit_notify (object, priv->step_increment, "step-increment");
+  ch += check_and_emit_notify (object, priv->page_increment, "page-increment");
+  ch += check_and_emit_notify (object, priv->page_size, "page-size");
+
+  /* Give GObject's machinery a chance to do it's work */
   G_OBJECT_CLASS (gtk_adjustment_parent_class)->dispatch_properties_changed (object, n_pspecs, pspecs);
 
-  for (i = 0; i < n_pspecs; i++)
-    switch (pspecs[i]->param_id)
-      {
-      case PROP_LOWER:
-      case PROP_UPPER:
-      case PROP_STEP_INCREMENT:
-      case PROP_PAGE_INCREMENT:
-      case PROP_PAGE_SIZE:
-        changed = TRUE;
-        break;
-      default:
-        break;
-      }
-
-  if (changed)
+  /* Step 3 */
+  if (ch)
+    g_signal_emit (object, adjustment_signals[CHANGED], 0);
+
+  if (val_ch)
+    g_signal_emit (object, adjustment_signals[VALUE_CHANGED], 0);
+}
+
+static void
+enforce_restrictions (GtkAdjustment *adjustment)
+{
+  GtkAdjustmentPriv *priv = adjustment->priv;
+
+  /* NOTE TO MYSELF: Keep those checks properly sorted!! */
+
+  /* Check if lower > upper */
+  priv->upper[NEW_VAL] = MAX (priv->upper[NEW_VAL], priv->lower[NEW_VAL]);
+
+  /* Check page_size */
+  priv->page_size[NEW_VAL] = CLAMP (priv->page_size[NEW_VAL], 0,
+				    priv->upper[NEW_VAL] - priv->lower[NEW_VAL]);
+
+  /* Check value */
+  priv->value[NEW_VAL] = CLAMP (priv->value[NEW_VAL], priv->lower[NEW_VAL],
+				priv->upper[NEW_VAL] - priv->page_size[NEW_VAL]);
+}
+
+static gint
+check_and_emit_notify (GObject    *object,
+		       gdouble    *vals,
+		       const char *prop)
+{
+  if (fabs (vals[0] - vals[1]) > DELTA)
     {
-      adjustment_changed_stamp++;
-      gtk_adjustment_changed (GTK_ADJUSTMENT (object));
+      vals[OLD_VAL] = vals[NEW_VAL];
+      g_object_notify (object, prop);
+      return 1;
     }
+  else
+    return 0;
 }
 
-GtkObject *
+/**
+ * gtk_adjustment_new:
+ * @value: the initial value.
+ * @lower: the minimum value.
+ * @upper: the maximum value.
+ * @step_increment: the step increment.
+ * @page_increment: the page increment.
+ * @page_size: the page size.
+ *
+ * Creates a new #GtkAdjustment.
+ *
+ * Returns: a new #GtkAdjustment.
+ */
+GtkAdjustment *
 gtk_adjustment_new (gdouble value,
 		    gdouble lower,
 		    gdouble upper,
@@ -350,27 +579,251 @@ gtk_adjustment_get_value (GtkAdjustment *adjustment)
 {
   g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0.0);
 
-  return adjustment->value;
+  return adjustment->priv->value[OLD_VAL];
+}
+
+/**
+ * gtk_adjustment_get_max_value:
+ * @adjustment: #GtkAdjustment from which to retrieve the value
+ *
+ * This is a convenience wrapper that allows you to obtain maximal allowed value
+ * for #GtkAdjustment:value property.
+ *
+ * This function can be emulated like this:
+ * <programlisting><![CDATA[
+ * gdouble max = gtk_adjustment_get_upper (adj) -
+ *               gtk_adjustment_get_page_size (adj)
+ * ]]></programlisting>
+ *
+ * Return value: Maximal allowed value for this adjustment.
+ *
+ * Since: 3.0
+ */
+gdouble
+gtk_adjustment_get_max_value (GtkAdjustment *adjustment)
+{
+  g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0.0);
+
+  return (adjustment->priv->upper[OLD_VAL] -
+	  adjustment->priv->page_size[OLD_VAL]);
 }
 
+/**
+ * gtk_adjustment_set_value:
+ * @adjustment: a #GtkAdjustment.
+ * @value: the new value.
+ *
+ * Sets the #GtkAdjustment:value property.
+ *
+ * Consult description section for more information about valid ranges.
+ */
 void
 gtk_adjustment_set_value (GtkAdjustment *adjustment,
 			  gdouble        value)
 {
   g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
 
-  /* don't use CLAMP() so we don't end up below lower if upper - page_size
-   * is smaller than lower
-   */
-  value = MIN (value, adjustment->upper - adjustment->page_size);
-  value = MAX (value, adjustment->lower);
+  g_object_set (adjustment, "value", value, NULL);
+}
 
-  if (value != adjustment->value)
-    {
-      adjustment->value = value;
+/**
+ * gtk_adjustment_set_value_to_min:
+ * @adjustment: #GtkAdjustment to modify
+ *
+ * This is a convenience wrapper that allows you to set #GtkAdjustment:value to
+ * the smallest possible value. This function can be emulated using
+ * gtk_adjustment_get_lower() and gtk_adjustment_set_value(), but it is slightly
+ * more efficient.
+ *
+ * Since: 3.0
+ */
+void
+gtk_adjustment_set_value_to_min (GtkAdjustment *adjustment)
+{
+  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
 
-      gtk_adjustment_value_changed (adjustment);
-    }
+  g_object_set (adjustment, "value", adjustment->priv->lower[OLD_VAL], NULL);
+}
+
+/**
+ * gtk_adjustment_set_value_to_max:
+ * @adjustment: #GtkAdjustment to modify
+ *
+ * This is a convenience wrapper that allows you to set #GtkAdjustment:value to
+ * the largest possible value. This function can be emulated using
+ * gtk_adjustment_get_upper(), gtk_adjustment_get_page_size() and
+ * gtk_adjustment_set_value(), but is slightly more efficient.
+ *
+ * Since: 3.0
+ */
+void
+gtk_adjustment_set_value_to_max (GtkAdjustment *adjustment)
+{
+  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+
+  g_object_set (adjustment, "value",
+		adjustment->priv->upper[OLD_VAL] -
+		adjustment->priv->page_size[OLD_VAL], NULL);
+}
+
+/**
+ * gtk_adjustment_increment_value:
+ * @adjustment: #GtkAdjustment you wan to modify
+ * @increment: the amount to increment for
+ *
+ * This is a convenience wrapper that allows you to increment
+ * #GtkAdjustment:value property without retrieving #GtkAdjustment:value first.
+ *
+ * This function can be emulated like this:
+ * <programlisting><![CDATA[
+ * gdouble value = gtk_adjustment_get_value (adjustment);
+ * gtk_adjustment_set_value (adjustment, value + increment);
+ * ]]></programlisting>
+ * but using this function is slightly more efficient.
+ *
+ * @increment can be negative, in which case this function will perform exactly
+ * the same action as gtk_adjustment_decrement_value();
+ *
+ * Since: 3.0
+ */
+void
+gtk_adjustment_increment_value (GtkAdjustment *adjustment,
+				gdouble        increment)
+{
+  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+
+  g_object_set (adjustment, "value",
+		adjustment->priv->value[OLD_VAL] + increment, NULL);
+}
+
+/**
+ * gtk_adjustment_decrement_value:
+ * @adjustment: #GtkAdjustment you wan to modify
+ * @decrement: the amount to decrement for
+ *
+ * This is a convenience wrapper that allows you to decrement
+ * #GtkAdjustment:value property without retrieving #GtkAdjustment:value first.
+ *
+ * This function can be emulated like this:
+ * <programlisting><![CDATA[
+ * gdouble value = gtk_adjustment_get_value (adjustment);
+ * gtk_adjustment_set_value (adjustment, value - increment);
+ * ]]></programlisting>
+ * but using this function is slightly more efficient.
+ *
+ * @decrement can be negative, in which case this function will perform exactly
+ * the same action as gtk_adjustment_increment_value();
+ *
+ * Since: 3.0
+ */
+void
+gtk_adjustment_decrement_value (GtkAdjustment *adjustment,
+				gdouble        decrement)
+{
+  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+
+  g_object_set (adjustment, "value",
+		adjustment->priv->value[OLD_VAL] - decrement, NULL);
+}
+
+/**
+ * gtk_adjustment_increment_value_by_steps:
+ * @adjustment: #GtkAdjustment you want to modify
+ * @no_steps: number of #GtkAdjustment:step-increment<!---->s to use when
+ *            incrementing
+ *
+ * This function is a convenience wrapper that allows you to modify
+ * #GtkAdjustment:value in #GtkAdjustment:step-increment intervals.
+ *
+ * @no_steps can be negative, in which case this function operates exactly the
+ * same as gtk_adjustment_decrement_value_by_steps().
+ *
+ * Since: 3.0
+ */
+void
+gtk_adjustment_increment_value_by_steps (GtkAdjustment *adjustment,
+					 gint           no_steps)
+{
+  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+
+  g_object_set (adjustment, "value",
+		adjustment->priv->value[OLD_VAL] + no_steps *
+		adjustment->priv->step_increment[OLD_VAL], NULL);
+}
+
+/**
+ * gtk_adjustment_decrement_value_by_steps:
+ * @adjustment: #GtkAdjustment you want to modify
+ * @no_steps: number of #GtkAdjustment:step-increment<!---->s to use when
+ *            decrementing
+ *
+ * This function is a convenience wrapper that allows you to modify
+ * #GtkAdjustment:value in #GtkAdjustment:step-increment intervals.
+ *
+ * @no_steps can be negative, in which case this function operates exactly the
+ * same as gtk_adjustment_increment_value_by_steps().
+ *
+ * Since: 3.0
+ */
+void
+gtk_adjustment_decrement_value_by_steps (GtkAdjustment *adjustment,
+					 gint           no_steps)
+{
+  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+
+  g_object_set (adjustment, "value",
+		adjustment->priv->value[OLD_VAL] - no_steps *
+		adjustment->priv->step_increment[OLD_VAL], NULL);
+}
+
+/**
+ * gtk_adjustment_increment_value_by_pages:
+ * @adjustment: #GtkAdjustment you wish to modify
+ * @no_pages: number of #GtkAdjustment:page-increment<!---->s to use when
+ *            incrementing
+ *
+ * This is a convenience wrapper that allows you to increment
+ * #GtkAdjustment:value in #GtkAdjustment:page-increment steps.
+ *
+ * @no_pages can be negative, in which case this function operates exactly like
+ * gtk_adjustment_decrement_value_by_pages().
+ *
+ * Since: 3.0
+ */
+void
+gtk_adjustment_increment_value_by_pages (GtkAdjustment *adjustment,
+					 gint           no_pages)
+{
+  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+
+  g_object_set (adjustment, "value",
+		adjustment->priv->value[OLD_VAL] + no_pages *
+		adjustment->priv->page_increment[OLD_VAL], NULL);
+}
+
+/**
+ * gtk_adjustment_decrement_value_by_pages:
+ * @adjustment: #GtkAdjustment you wish to modify
+ * @no_pages: number of #GtkAdjustment:page-increment<!---->s to use when
+ *            decrementing
+ *
+ * This is a convenience wrapper that allows you to decrement
+ * #GtkAdjustment:value in #GtkAdjustment:page-increment steps.
+ *
+ * @no_pages can be negative, in which case this function operates exactly like
+ * gtk_adjustment_increment_value_by_pages().
+ *
+ * Since: 3.0
+ */
+void
+gtk_adjustment_decrement_value_by_pages (GtkAdjustment *adjustment,
+					 gint           no_pages)
+{
+  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+
+  g_object_set (adjustment, "value",
+		adjustment->priv->value[OLD_VAL] + no_pages *
+		adjustment->priv->page_increment[OLD_VAL], NULL);
 }
 
 /**
@@ -388,7 +841,7 @@ gtk_adjustment_get_lower (GtkAdjustment *adjustment)
 {
   g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0.0);
 
-  return adjustment->lower;
+  return adjustment->priv->lower[OLD_VAL];
 }
 
 /**
@@ -398,18 +851,6 @@ gtk_adjustment_get_lower (GtkAdjustment *adjustment)
  *
  * Sets the minimum value of the adjustment.
  *
- * When setting multiple adjustment properties via their individual
- * setters, multiple "changed" signals will be emitted. However, since
- * the emission of the "changed" signal is tied to the emission of the
- * "GObject::notify" signals of the changed properties, it's possible
- * to compress the "changed" signals into one by calling
- * g_object_freeze_notify() and g_object_thaw_notify() around the
- * calls to the individual setters.
- *
- * Alternatively, using a single g_object_set() for all the properties
- * to change, or using gtk_adjustment_configure() has the same effect
- * of compressing "changed" emissions.
- *
  * Since: 2.14
  **/
 void
@@ -418,8 +859,7 @@ gtk_adjustment_set_lower (GtkAdjustment *adjustment,
 {
   g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
 
-  if (lower != adjustment->lower)
-    g_object_set (adjustment, "lower", lower, NULL);
+  g_object_set (adjustment, "lower", lower, NULL);
 }
 
 /**
@@ -437,7 +877,7 @@ gtk_adjustment_get_upper (GtkAdjustment *adjustment)
 {
   g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0.0);
 
-  return adjustment->upper;
+  return adjustment->priv->upper[OLD_VAL];
 }
 
 /**
@@ -447,14 +887,6 @@ gtk_adjustment_get_upper (GtkAdjustment *adjustment)
  *
  * Sets the maximum value of the adjustment.
  *
- * Note that values will be restricted by
- * <literal>upper - page-size</literal> if the page-size
- * property is nonzero.
- *
- * See gtk_adjustment_set_lower() about how to compress multiple
- * emissions of the "changed" signal when setting multiple adjustment
- * properties.
- *
  * Since: 2.14
  **/
 void
@@ -463,8 +895,7 @@ gtk_adjustment_set_upper (GtkAdjustment *adjustment,
 {
   g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
 
-  if (upper != adjustment->upper)
-    g_object_set (adjustment, "upper", upper, NULL);
+  g_object_set (adjustment, "upper", upper, NULL);
 }
 
 /**
@@ -482,7 +913,7 @@ gtk_adjustment_get_step_increment (GtkAdjustment *adjustment)
 {
   g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0.0);
 
-  return adjustment->step_increment;
+  return adjustment->priv->step_increment[OLD_VAL];
 }
 
 /**
@@ -492,10 +923,6 @@ gtk_adjustment_get_step_increment (GtkAdjustment *adjustment)
  *
  * Sets the step increment of the adjustment.
  *
- * See gtk_adjustment_set_lower() about how to compress multiple
- * emissions of the "changed" signal when setting multiple adjustment
- * properties.
- *
  * Since: 2.14
  **/
 void
@@ -504,8 +931,7 @@ gtk_adjustment_set_step_increment (GtkAdjustment *adjustment,
 {
   g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
 
-  if (step_increment != adjustment->step_increment)
-    g_object_set (adjustment, "step-increment", step_increment, NULL);
+  g_object_set (adjustment, "step-increment", step_increment, NULL);
 }
 
 /**
@@ -523,7 +949,7 @@ gtk_adjustment_get_page_increment (GtkAdjustment *adjustment)
 {
   g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0.0);
 
-  return adjustment->page_increment;
+  return adjustment->priv->page_increment[OLD_VAL];
 }
 
 /**
@@ -533,10 +959,6 @@ gtk_adjustment_get_page_increment (GtkAdjustment *adjustment)
  *
  * Sets the page increment of the adjustment.
  *
- * See gtk_adjustment_set_lower() about how to compress multiple
- * emissions of the "changed" signal when setting multiple adjustment
- * properties.
- *
  * Since: 2.14
  **/
 void
@@ -545,8 +967,7 @@ gtk_adjustment_set_page_increment (GtkAdjustment *adjustment,
 {
   g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
 
-  if (page_increment != adjustment->page_increment)
-    g_object_set (adjustment, "page-increment", page_increment, NULL);
+  g_object_set (adjustment, "page-increment", page_increment, NULL);
 }
 
 /**
@@ -564,7 +985,7 @@ gtk_adjustment_get_page_size (GtkAdjustment *adjustment)
 {
   g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0.0);
 
-  return adjustment->page_size;
+  return adjustment->priv->page_size[OLD_VAL];
 }
 
 /**
@@ -574,10 +995,6 @@ gtk_adjustment_get_page_size (GtkAdjustment *adjustment)
  *
  * Sets the page size of the adjustment.
  *
- * See gtk_adjustment_set_lower() about how to compress multiple
- * emissions of the "changed" signal when setting multiple adjustment
- * properties.
- *
  * Since: 2.14
  **/
 void
@@ -586,8 +1003,7 @@ gtk_adjustment_set_page_size (GtkAdjustment *adjustment,
 {
   g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
 
-  if (page_size != adjustment->page_size)
-    g_object_set (adjustment, "page-size", page_size, NULL);
+  g_object_set (adjustment, "page-size", page_size, NULL);
 }
 
 /**
@@ -602,10 +1018,6 @@ gtk_adjustment_set_page_size (GtkAdjustment *adjustment,
  *
  * Sets all properties of the adjustment at once.
  *
- * Use this function to avoid multiple emissions of the "changed"
- * signal. See gtk_adjustment_set_lower() for an alternative way
- * of compressing multiple emissions of "changed" into one.
- *
  * Since: 2.14
  **/
 void
@@ -617,89 +1029,55 @@ gtk_adjustment_configure (GtkAdjustment *adjustment,
                           gdouble        page_increment,
                           gdouble        page_size)
 {
-  gboolean value_changed = FALSE;
-  guint64 old_stamp = adjustment_changed_stamp;
-
   g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
 
-  g_object_freeze_notify (G_OBJECT (adjustment));
-
   g_object_set (adjustment,
                 "lower", lower,
                 "upper", upper,
                 "step-increment", step_increment,
                 "page-increment", page_increment,
                 "page-size", page_size,
+		"value", value,
                 NULL);
-
-  /* don't use CLAMP() so we don't end up below lower if upper - page_size
-   * is smaller than lower
-   */
-  value = MIN (value, upper - page_size);
-  value = MAX (value, lower);
-
-  if (value != adjustment->value)
-    {
-      /* set value manually to make sure "changed" is emitted with the
-       * new value in place and is emitted before "value-changed"
-       */
-      adjustment->value = value;
-      value_changed = TRUE;
-    }
-
-  g_object_thaw_notify (G_OBJECT (adjustment));
-
-  if (old_stamp == adjustment_changed_stamp)
-    gtk_adjustment_changed (adjustment); /* force emission before ::value-changed */
-
-  if (value_changed)
-    gtk_adjustment_value_changed (adjustment);
-}
-
-void
-gtk_adjustment_changed (GtkAdjustment *adjustment)
-{
-  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
-
-  g_signal_emit (adjustment, adjustment_signals[CHANGED], 0);
-}
-
-void
-gtk_adjustment_value_changed (GtkAdjustment *adjustment)
-{
-  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
-
-  g_signal_emit (adjustment, adjustment_signals[VALUE_CHANGED], 0);
-  g_object_notify (G_OBJECT (adjustment), "value");
 }
 
+/**
+ * gtk_adjustment_clamp_page:
+ * @adjustment: a #GtkAdjustment.
+ * @lower: the lower value.
+ * @upper: the upper value.
+ *
+ * Updates the #GtkAdjustment:value property to ensure that the range between
+ * @lower and @upper is in the current page (i.e. between @value and @value +
+ * @page_size). If the range is larger than the page size, then only the start
+ * of it will be in the current page. A #GtkAdjustment::value-changed signal
+ * will be emitted if the value is changed.
+ */
 void
 gtk_adjustment_clamp_page (GtkAdjustment *adjustment,
 			   gdouble        lower,
 			   gdouble        upper)
 {
-  gboolean need_emission;
+  gdouble new_value;
 
   g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
 
-  lower = CLAMP (lower, adjustment->lower, adjustment->upper);
-  upper = CLAMP (upper, adjustment->lower, adjustment->upper);
+  lower = CLAMP (lower,
+		 adjustment->priv->lower[OLD_VAL],
+		 adjustment->priv->upper[OLD_VAL]);
+  upper = CLAMP (upper,
+		 adjustment->priv->lower[OLD_VAL],
+		 adjustment->priv->upper[OLD_VAL]);
+  new_value = adjustment->priv->value[OLD_VAL];
 
-  need_emission = FALSE;
+  if (new_value + adjustment->priv->page_size[OLD_VAL] < upper)
+      new_value = upper - adjustment->priv->page_size[OLD_VAL];
 
-  if (adjustment->value + adjustment->page_size < upper)
-    {
-      adjustment->value = upper - adjustment->page_size;
-      need_emission = TRUE;
-    }
-  if (adjustment->value > lower)
-    {
-      adjustment->value = lower;
-      need_emission = TRUE;
-    }
+  if (new_value > lower)
+      new_value = lower;
 
-  if (need_emission)
-    gtk_adjustment_value_changed (adjustment);
+  if (new_value != adjustment->priv->value[OLD_VAL])
+    g_object_set (adjustment, "value", new_value, NULL);
 }
 
 #define __GTK_ADJUSTMENT_C__
