]> Pileus Git - ~andy/gtk/blob - gtk/gtkadjustment.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / gtk / gtkadjustment.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 /*
19  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
20  * file for a list of people on the GTK+ Team.  See the ChangeLog
21  * files for a list of changes.  These files are distributed with
22  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
23  */
24
25 #include "config.h"
26 #include "gtkadjustment.h"
27 #include "gtkmarshalers.h"
28 #include "gtkprivate.h"
29 #include "gtkintl.h"
30
31
32 /**
33  * SECTION:gtkadjustment
34  * @Short_description: A representation of an adjustable bounded value
35  * @Title: GtkAdjustment
36  *
37  * The #GtkAdjustment object represents a value which has an associated lower
38  * and upper bound, together with step and page increments, and a page size.
39  * It is used within several GTK+ widgets, including
40  * #GtkSpinButton, #GtkViewport, and #GtkRange (which is a base class for
41  * #GtkHScrollbar, #GtkVScrollbar, #GtkHScale, and #GtkVScale).
42  *
43  * The #GtkAdjustment object does not update the value itself. Instead
44  * it is left up to the owner of the #GtkAdjustment to control the value.
45  *
46  * The owner of the #GtkAdjustment typically calls the
47  * gtk_adjustment_value_changed() and gtk_adjustment_changed() functions
48  * after changing the value and its bounds. This results in the emission of the
49  * #GtkAdjustment::value_changed or #GtkAdjustment::changed signal respectively.
50  */
51
52
53 struct _GtkAdjustmentPrivate {
54   gdouble lower;
55   gdouble upper;
56   gdouble value;
57   gdouble step_increment;
58   gdouble page_increment;
59   gdouble page_size;
60 };
61
62 enum
63 {
64   PROP_0,
65   PROP_VALUE,
66   PROP_LOWER,
67   PROP_UPPER,
68   PROP_STEP_INCREMENT,
69   PROP_PAGE_INCREMENT,
70   PROP_PAGE_SIZE
71 };
72
73 enum
74 {
75   CHANGED,
76   VALUE_CHANGED,
77   LAST_SIGNAL
78 };
79
80
81 static void gtk_adjustment_get_property                (GObject      *object,
82                                                         guint         prop_id,
83                                                         GValue       *value,
84                                                         GParamSpec   *pspec);
85 static void gtk_adjustment_set_property                (GObject      *object,
86                                                         guint         prop_id,
87                                                         const GValue *value,
88                                                         GParamSpec   *pspec);
89 static void gtk_adjustment_dispatch_properties_changed (GObject      *object,
90                                                         guint         n_pspecs,
91                                                         GParamSpec  **pspecs);
92
93 static guint adjustment_signals[LAST_SIGNAL] = { 0 };
94
95 static guint64 adjustment_changed_stamp = 0; /* protected by global gdk lock */
96
97 G_DEFINE_TYPE (GtkAdjustment, gtk_adjustment, G_TYPE_INITIALLY_UNOWNED)
98
99 static void
100 gtk_adjustment_class_init (GtkAdjustmentClass *class)
101 {
102   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
103
104   gobject_class->set_property                = gtk_adjustment_set_property;
105   gobject_class->get_property                = gtk_adjustment_get_property;
106   gobject_class->dispatch_properties_changed = gtk_adjustment_dispatch_properties_changed;
107
108   class->changed = NULL;
109   class->value_changed = NULL;
110
111   /**
112    * GtkAdjustment:value:
113    * 
114    * The value of the adjustment.
115    * 
116    * Since: 2.4
117    */
118   g_object_class_install_property (gobject_class,
119                                    PROP_VALUE,
120                                    g_param_spec_double ("value",
121                                                         P_("Value"),
122                                                         P_("The value of the adjustment"),
123                                                         -G_MAXDOUBLE, 
124                                                         G_MAXDOUBLE, 
125                                                         0.0, 
126                                                         GTK_PARAM_READWRITE));
127   
128   /**
129    * GtkAdjustment:lower:
130    * 
131    * The minimum value of the adjustment.
132    * 
133    * Since: 2.4
134    */
135   g_object_class_install_property (gobject_class,
136                                    PROP_LOWER,
137                                    g_param_spec_double ("lower",
138                                                         P_("Minimum Value"),
139                                                         P_("The minimum value of the adjustment"),
140                                                         -G_MAXDOUBLE, 
141                                                         G_MAXDOUBLE, 
142                                                         0.0,
143                                                         GTK_PARAM_READWRITE));
144   
145   /**
146    * GtkAdjustment:upper:
147    * 
148    * The maximum value of the adjustment. 
149    * Note that values will be restricted by 
150    * <literal>upper - page-size</literal> if the page-size 
151    * property is nonzero.
152    *
153    * Since: 2.4
154    */
155   g_object_class_install_property (gobject_class,
156                                    PROP_UPPER,
157                                    g_param_spec_double ("upper",
158                                                         P_("Maximum Value"),
159                                                         P_("The maximum value of the adjustment"),
160                                                         -G_MAXDOUBLE, 
161                                                         G_MAXDOUBLE, 
162                                                         0.0, 
163                                                         GTK_PARAM_READWRITE));
164   
165   /**
166    * GtkAdjustment:step-increment:
167    * 
168    * The step increment of the adjustment.
169    * 
170    * Since: 2.4
171    */
172   g_object_class_install_property (gobject_class,
173                                    PROP_STEP_INCREMENT,
174                                    g_param_spec_double ("step-increment",
175                                                         P_("Step Increment"),
176                                                         P_("The step increment of the adjustment"),
177                                                         -G_MAXDOUBLE, 
178                                                         G_MAXDOUBLE, 
179                                                         0.0, 
180                                                         GTK_PARAM_READWRITE));
181   
182   /**
183    * GtkAdjustment:page-increment:
184    * 
185    * The page increment of the adjustment.
186    * 
187    * Since: 2.4
188    */
189   g_object_class_install_property (gobject_class,
190                                    PROP_PAGE_INCREMENT,
191                                    g_param_spec_double ("page-increment",
192                                                         P_("Page Increment"),
193                                                         P_("The page increment of the adjustment"),
194                                                         -G_MAXDOUBLE, 
195                                                         G_MAXDOUBLE, 
196                                                         0.0, 
197                                                         GTK_PARAM_READWRITE));
198   
199   /**
200    * GtkAdjustment:page-size:
201    * 
202    * The page size of the adjustment. 
203    * Note that the page-size is irrelevant and should be set to zero
204    * if the adjustment is used for a simple scalar value, e.g. in a 
205    * #GtkSpinButton.
206    * 
207    * Since: 2.4
208    */
209   g_object_class_install_property (gobject_class,
210                                    PROP_PAGE_SIZE,
211                                    g_param_spec_double ("page-size",
212                                                         P_("Page Size"),
213                                                         P_("The page size of the adjustment"),
214                                                         -G_MAXDOUBLE, 
215                                                         G_MAXDOUBLE, 
216                                                         0.0, 
217                                                         GTK_PARAM_READWRITE));
218
219   /**
220    * GtkAdjustment::changed:
221    * @adjustment: the object which received the signal.
222    *
223    * Emitted when one or more of the #GtkAdjustment properties have been
224    * changed, other than the #GtkAdjustment:value property.
225    */
226   adjustment_signals[CHANGED] =
227     g_signal_new (I_("changed"),
228                   G_OBJECT_CLASS_TYPE (class),
229                   G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE,
230                   G_STRUCT_OFFSET (GtkAdjustmentClass, changed),
231                   NULL, NULL,
232                   _gtk_marshal_VOID__VOID,
233                   G_TYPE_NONE, 0);
234
235   /**
236    * GtkAdjustment::value-changed:
237    * @adjustment: the object which received the signal.
238    *
239    * Emitted when the #GtkAdjustment:value property has been changed.
240    */
241   adjustment_signals[VALUE_CHANGED] =
242     g_signal_new (I_("value-changed"),
243                   G_OBJECT_CLASS_TYPE (class),
244                   G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE,
245                   G_STRUCT_OFFSET (GtkAdjustmentClass, value_changed),
246                   NULL, NULL,
247                   _gtk_marshal_VOID__VOID,
248                   G_TYPE_NONE, 0);
249
250   g_type_class_add_private (class, sizeof (GtkAdjustmentPrivate));
251 }
252
253 static void
254 gtk_adjustment_init (GtkAdjustment *adjustment)
255 {
256   adjustment->priv = G_TYPE_INSTANCE_GET_PRIVATE (adjustment,
257                                                   GTK_TYPE_ADJUSTMENT,
258                                                   GtkAdjustmentPrivate);
259 }
260
261 static void
262 gtk_adjustment_get_property (GObject    *object,
263                              guint       prop_id,
264                              GValue     *value,
265                              GParamSpec *pspec)
266 {
267   GtkAdjustment *adjustment = GTK_ADJUSTMENT (object);
268   GtkAdjustmentPrivate *priv = adjustment->priv;
269
270   switch (prop_id)
271     {
272     case PROP_VALUE:
273       g_value_set_double (value, priv->value);
274       break;
275     case PROP_LOWER:
276       g_value_set_double (value, priv->lower);
277       break;
278     case PROP_UPPER:
279       g_value_set_double (value, priv->upper);
280       break;
281     case PROP_STEP_INCREMENT:
282       g_value_set_double (value, priv->step_increment);
283       break;
284     case PROP_PAGE_INCREMENT:
285       g_value_set_double (value, priv->page_increment);
286       break;
287     case PROP_PAGE_SIZE:
288       g_value_set_double (value, priv->page_size);
289       break;
290     default:
291       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
292       break;
293     }
294 }
295
296 static void
297 gtk_adjustment_set_property (GObject      *object,
298                              guint         prop_id,
299                              const GValue *value,
300                              GParamSpec   *pspec)
301 {
302   GtkAdjustment *adjustment = GTK_ADJUSTMENT (object);
303   gdouble double_value = g_value_get_double (value);
304   GtkAdjustmentPrivate *priv = adjustment->priv;
305
306   switch (prop_id)
307     {
308     case PROP_VALUE:
309       gtk_adjustment_set_value (adjustment, double_value);
310       break;
311     case PROP_LOWER:
312       priv->lower = double_value;
313       break;
314     case PROP_UPPER:
315       priv->upper = double_value;
316       break;
317     case PROP_STEP_INCREMENT:
318       priv->step_increment = double_value;
319       break;
320     case PROP_PAGE_INCREMENT:
321       priv->page_increment = double_value;
322       break;
323     case PROP_PAGE_SIZE:
324       priv->page_size = double_value;
325       break;
326     default:
327       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
328       break;
329     }
330 }
331
332 static void
333 gtk_adjustment_dispatch_properties_changed (GObject     *object,
334                                             guint        n_pspecs,
335                                             GParamSpec **pspecs)
336 {
337   gboolean changed = FALSE;
338   gint i;
339
340   G_OBJECT_CLASS (gtk_adjustment_parent_class)->dispatch_properties_changed (object, n_pspecs, pspecs);
341
342   for (i = 0; i < n_pspecs; i++)
343     switch (pspecs[i]->param_id)
344       {
345       case PROP_LOWER:
346       case PROP_UPPER:
347       case PROP_STEP_INCREMENT:
348       case PROP_PAGE_INCREMENT:
349       case PROP_PAGE_SIZE:
350         changed = TRUE;
351         break;
352       default:
353         break;
354       }
355
356   if (changed)
357     {
358       adjustment_changed_stamp++;
359       gtk_adjustment_changed (GTK_ADJUSTMENT (object));
360     }
361 }
362
363 /**
364  * gtk_adjustment_new:
365  * @value: the initial value.
366  * @lower: the minimum value.
367  * @upper: the maximum value.
368  * @step_increment: the step increment.
369  * @page_increment: the page increment.
370  * @page_size: the page size.
371  *
372  * Creates a new #GtkAdjustment.
373  *
374  * Returns: a new #GtkAdjustment.
375  */
376 GtkAdjustment *
377 gtk_adjustment_new (gdouble value,
378                     gdouble lower,
379                     gdouble upper,
380                     gdouble step_increment,
381                     gdouble page_increment,
382                     gdouble page_size)
383 {
384   return g_object_new (GTK_TYPE_ADJUSTMENT,
385                        "lower", lower,
386                        "upper", upper,
387                        "step-increment", step_increment,
388                        "page-increment", page_increment,
389                        "page-size", page_size,
390                        "value", value,
391                        NULL);
392 }
393
394 /**
395  * gtk_adjustment_get_value:
396  * @adjustment: a #GtkAdjustment
397  *
398  * Gets the current value of the adjustment. See
399  * gtk_adjustment_set_value ().
400  *
401  * Return value: The current value of the adjustment.
402  **/
403 gdouble
404 gtk_adjustment_get_value (GtkAdjustment *adjustment)
405 {
406   g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0.0);
407
408   return adjustment->priv->value;
409 }
410
411 /**
412  * gtk_adjustment_set_value:
413  * @adjustment: a #GtkAdjustment.
414  * @value: the new value.
415  *
416  * Sets the #GtkAdjustment value. The value is clamped to lie between
417  * #GtkAdjustment:lower and #GtkAdjustment:upper.
418  *
419  * Note that for adjustments which are used in a #GtkScrollbar, the effective
420  * range of allowed values goes from #GtkAdjustment:lower to
421  * #GtkAdjustment:upper - #GtkAdjustment:page_size.
422  */
423 void
424 gtk_adjustment_set_value (GtkAdjustment *adjustment,
425                           gdouble        value)
426 {
427   GtkAdjustmentPrivate *priv;
428   
429   g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
430
431   priv = adjustment->priv;
432
433   /* don't use CLAMP() so we don't end up below lower if upper - page_size
434    * is smaller than lower
435    */
436   value = MIN (value, priv->upper - priv->page_size);
437   value = MAX (value, priv->lower);
438
439   if (value != priv->value)
440     {
441       priv->value = value;
442
443       gtk_adjustment_value_changed (adjustment);
444     }
445 }
446
447 /**
448  * gtk_adjustment_get_lower:
449  * @adjustment: a #GtkAdjustment
450  *
451  * Retrieves the minimum value of the adjustment.
452  *
453  * Return value: The current minimum value of the adjustment.
454  *
455  * Since: 2.14
456  **/
457 gdouble
458 gtk_adjustment_get_lower (GtkAdjustment *adjustment)
459 {
460   g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0.0);
461
462   return adjustment->priv->lower;
463 }
464
465 /**
466  * gtk_adjustment_set_lower:
467  * @adjustment: a #GtkAdjustment
468  * @lower: the new minimum value
469  *
470  * Sets the minimum value of the adjustment.
471  *
472  * When setting multiple adjustment properties via their individual
473  * setters, multiple #GtkAdjustment::changed signals will be emitted. However, since
474  * the emission of the #GtkAdjustment::changed signal is tied to the emission of the
475  * #GObject::notify signals of the changed properties, it's possible
476  * to compress the #GtkAdjustment::changed signals into one by calling
477  * g_object_freeze_notify() and g_object_thaw_notify() around the
478  * calls to the individual setters.
479  *
480  * Alternatively, using a single g_object_set() for all the properties
481  * to change, or using gtk_adjustment_configure() has the same effect
482  * of compressing #GtkAdjustment::changed emissions.
483  *
484  * Since: 2.14
485  **/
486 void
487 gtk_adjustment_set_lower (GtkAdjustment *adjustment,
488                           gdouble        lower)
489 {
490   g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
491
492   if (lower != adjustment->priv->lower)
493     g_object_set (adjustment, "lower", lower, NULL);
494 }
495
496 /**
497  * gtk_adjustment_get_upper:
498  * @adjustment: a #GtkAdjustment
499  *
500  * Retrieves the maximum value of the adjustment.
501  *
502  * Return value: The current maximum value of the adjustment.
503  *
504  * Since: 2.14
505  **/
506 gdouble
507 gtk_adjustment_get_upper (GtkAdjustment *adjustment)
508 {
509   g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0.0);
510
511   return adjustment->priv->upper;
512 }
513
514 /**
515  * gtk_adjustment_set_upper:
516  * @adjustment: a #GtkAdjustment
517  * @upper: the new maximum value
518  *
519  * Sets the maximum value of the adjustment.
520  *
521  * Note that values will be restricted by
522  * <literal>upper - page-size</literal> if the page-size
523  * property is nonzero.
524  *
525  * See gtk_adjustment_set_lower() about how to compress multiple
526  * emissions of the #GtkAdjustment::changed signal when setting multiple adjustment
527  * properties.
528  *
529  * Since: 2.14
530  **/
531 void
532 gtk_adjustment_set_upper (GtkAdjustment *adjustment,
533                           gdouble        upper)
534 {
535   g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
536
537   if (upper != adjustment->priv->upper)
538     g_object_set (adjustment, "upper", upper, NULL);
539 }
540
541 /**
542  * gtk_adjustment_get_step_increment:
543  * @adjustment: a #GtkAdjustment
544  *
545  * Retrieves the step increment of the adjustment.
546  *
547  * Return value: The current step increment of the adjustment.
548  *
549  * Since: 2.14
550  **/
551 gdouble
552 gtk_adjustment_get_step_increment (GtkAdjustment *adjustment)
553 {
554   g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0.0);
555
556   return adjustment->priv->step_increment;
557 }
558
559 /**
560  * gtk_adjustment_set_step_increment:
561  * @adjustment: a #GtkAdjustment
562  * @step_increment: the new step increment
563  *
564  * Sets the step increment of the adjustment.
565  *
566  * See gtk_adjustment_set_lower() about how to compress multiple
567  * emissions of the #GtkAdjustment::changed signal when setting multiple adjustment
568  * properties.
569  *
570  * Since: 2.14
571  **/
572 void
573 gtk_adjustment_set_step_increment (GtkAdjustment *adjustment,
574                                    gdouble        step_increment)
575 {
576   g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
577
578   if (step_increment != adjustment->priv->step_increment)
579     g_object_set (adjustment, "step-increment", step_increment, NULL);
580 }
581
582 /**
583  * gtk_adjustment_get_page_increment:
584  * @adjustment: a #GtkAdjustment
585  *
586  * Retrieves the page increment of the adjustment.
587  *
588  * Return value: The current page increment of the adjustment.
589  *
590  * Since: 2.14
591  **/
592 gdouble
593 gtk_adjustment_get_page_increment (GtkAdjustment *adjustment)
594 {
595   g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0.0);
596
597   return adjustment->priv->page_increment;
598 }
599
600 /**
601  * gtk_adjustment_set_page_increment:
602  * @adjustment: a #GtkAdjustment
603  * @page_increment: the new page increment
604  *
605  * Sets the page increment of the adjustment.
606  *
607  * See gtk_adjustment_set_lower() about how to compress multiple
608  * emissions of the #GtkAdjustment::changed signal when setting multiple adjustment
609  * properties.
610  *
611  * Since: 2.14
612  **/
613 void
614 gtk_adjustment_set_page_increment (GtkAdjustment *adjustment,
615                                    gdouble        page_increment)
616 {
617   g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
618
619   if (page_increment != adjustment->priv->page_increment)
620     g_object_set (adjustment, "page-increment", page_increment, NULL);
621 }
622
623 /**
624  * gtk_adjustment_get_page_size:
625  * @adjustment: a #GtkAdjustment
626  *
627  * Retrieves the page size of the adjustment.
628  *
629  * Return value: The current page size of the adjustment.
630  *
631  * Since: 2.14
632  **/
633 gdouble
634 gtk_adjustment_get_page_size (GtkAdjustment *adjustment)
635 {
636   g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0.0);
637
638   return adjustment->priv->page_size;
639 }
640
641 /**
642  * gtk_adjustment_set_page_size:
643  * @adjustment: a #GtkAdjustment
644  * @page_size: the new page size
645  *
646  * Sets the page size of the adjustment.
647  *
648  * See gtk_adjustment_set_lower() about how to compress multiple
649  * emissions of the GtkAdjustment::changed signal when setting multiple adjustment
650  * properties.
651  *
652  * Since: 2.14
653  **/
654 void
655 gtk_adjustment_set_page_size (GtkAdjustment *adjustment,
656                               gdouble        page_size)
657 {
658   g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
659
660   if (page_size != adjustment->priv->page_size)
661     g_object_set (adjustment, "page-size", page_size, NULL);
662 }
663
664 /**
665  * gtk_adjustment_configure:
666  * @adjustment: a #GtkAdjustment
667  * @value: the new value
668  * @lower: the new minimum value
669  * @upper: the new maximum value
670  * @step_increment: the new step increment
671  * @page_increment: the new page increment
672  * @page_size: the new page size
673  *
674  * Sets all properties of the adjustment at once.
675  *
676  * Use this function to avoid multiple emissions of the #GtkAdjustment::changed
677  * signal. See gtk_adjustment_set_lower() for an alternative way
678  * of compressing multiple emissions of #GtkAdjustment::changed into one.
679  *
680  * Since: 2.14
681  **/
682 void
683 gtk_adjustment_configure (GtkAdjustment *adjustment,
684                           gdouble        value,
685                           gdouble        lower,
686                           gdouble        upper,
687                           gdouble        step_increment,
688                           gdouble        page_increment,
689                           gdouble        page_size)
690 {
691   GtkAdjustmentPrivate *priv;
692   gboolean value_changed = FALSE;
693   guint64 old_stamp = adjustment_changed_stamp;
694
695   g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
696
697   priv = adjustment->priv;
698
699   g_object_freeze_notify (G_OBJECT (adjustment));
700
701   g_object_set (adjustment,
702                 "lower", lower,
703                 "upper", upper,
704                 "step-increment", step_increment,
705                 "page-increment", page_increment,
706                 "page-size", page_size,
707                 NULL);
708
709   /* don't use CLAMP() so we don't end up below lower if upper - page_size
710    * is smaller than lower
711    */
712   value = MIN (value, upper - page_size);
713   value = MAX (value, lower);
714
715   if (value != priv->value)
716     {
717       /* set value manually to make sure "changed" is emitted with the
718        * new value in place and is emitted before "value-changed"
719        */
720       priv->value = value;
721       value_changed = TRUE;
722     }
723
724   g_object_thaw_notify (G_OBJECT (adjustment));
725
726   if (old_stamp == adjustment_changed_stamp)
727     gtk_adjustment_changed (adjustment); /* force emission before ::value-changed */
728
729   if (value_changed)
730     gtk_adjustment_value_changed (adjustment);
731 }
732
733 /**
734  * gtk_adjustment_changed:
735  * @adjustment: a #GtkAdjustment
736  *
737  * Emits a #GtkAdjustment::changed signal from the #GtkAdjustment.
738  * This is typically called by the owner of the #GtkAdjustment after it has
739  * changed any of the #GtkAdjustment properties other than the value.
740  */
741 void
742 gtk_adjustment_changed (GtkAdjustment *adjustment)
743 {
744   g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
745
746   g_signal_emit (adjustment, adjustment_signals[CHANGED], 0);
747 }
748
749 /**
750  * gtk_adjustment_value_changed:
751  * @adjustment: a #GtkAdjustment
752  *
753  * Emits a #GtkAdjustment::value_changed signal from the #GtkAdjustment.
754  * This is typically called by the owner of the #GtkAdjustment after it has
755  * changed the #GtkAdjustment:value property.
756  */
757 void
758 gtk_adjustment_value_changed (GtkAdjustment *adjustment)
759 {
760   g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
761
762   g_signal_emit (adjustment, adjustment_signals[VALUE_CHANGED], 0);
763   g_object_notify (G_OBJECT (adjustment), "value");
764 }
765
766 /**
767  * gtk_adjustment_clamp_page:
768  * @adjustment: a #GtkAdjustment.
769  * @lower: the lower value.
770  * @upper: the upper value.
771  *
772  * Updates the #GtkAdjustment:value property to ensure that the range
773  * between @lower and @upper is in the current page (i.e. between
774  * #GtkAdjustment:value and #GtkAdjustment:value + #GtkAdjustment:page_size).
775  * If the range is larger than the page size, then only the start of it will
776  * be in the current page.
777  * A #GtkAdjustment::changed signal will be emitted if the value is changed.
778  */
779 void
780 gtk_adjustment_clamp_page (GtkAdjustment *adjustment,
781                            gdouble        lower,
782                            gdouble        upper)
783 {
784   GtkAdjustmentPrivate *priv;
785   gboolean need_emission;
786
787   g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
788
789   priv = adjustment->priv;
790
791   lower = CLAMP (lower, priv->lower, priv->upper);
792   upper = CLAMP (upper, priv->lower, priv->upper);
793
794   need_emission = FALSE;
795
796   if (priv->value + priv->page_size < upper)
797     {
798       priv->value = upper - priv->page_size;
799       need_emission = TRUE;
800     }
801   if (priv->value > lower)
802     {
803       priv->value = lower;
804       need_emission = TRUE;
805     }
806
807   if (need_emission)
808     gtk_adjustment_value_changed (adjustment);
809 }
810
811 /**
812  * gtk_adjustment_get_minimum_increment:
813  * @adjustment: a #GtkAdjustment
814  *
815  * Gets the smaller of step increment and page increment.
816  *
817  * Returns: the minimum increment of @adjustment
818  *
819  * Since: 3.2
820  */
821 gdouble
822 gtk_adjustment_get_minimum_increment (GtkAdjustment *adjustment)
823 {
824   GtkAdjustmentPrivate *priv;
825   gdouble minimum_increment;
826
827   g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0);
828
829   priv = adjustment->priv;
830
831     if (priv->step_increment != 0 && priv->page_increment != 0)
832     {
833       if (ABS (priv->step_increment) < ABS (priv->page_increment))
834         minimum_increment = priv->step_increment;
835       else
836         minimum_increment = priv->page_increment;
837     }
838   else if (priv->step_increment == 0 && priv->page_increment == 0)
839     {
840       minimum_increment = 0;
841     }
842   else if (priv->step_increment == 0)
843     {
844       minimum_increment = priv->page_increment;
845     }
846   else
847     {
848       minimum_increment = priv->step_increment;
849     }
850
851   return minimum_increment;
852 }
853