]> Pileus Git - ~andy/gtk/blob - gtk/gtkscrolledwindow.c
Reduce includes of gtktypeutils.h to a minimum
[~andy/gtk] / gtk / gtkscrolledwindow.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, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
25  */
26
27 #include "config.h"
28 #include <math.h>
29 #include <gdk/gdkkeysyms.h>
30 #include "gtkbindings.h"
31 #include "gtkmarshalers.h"
32 #include "gtkscrollable.h"
33 #include "gtkscrolledwindow.h"
34 #include "gtkwindow.h"
35 #include "gtkprivate.h"
36 #include "gtkintl.h"
37
38
39 /**
40  * SECTION:gtkscrolledwindow
41  * @Short_description: Adds scrollbars to its child widget
42  * @Title: GtkScrolledWindow
43  * @See_also: #GtkScrollable, #GtkViewport, #GtkAdjustment
44  *
45  * #GtkScrolledWindow is a #GtkBin subclass: it's a container
46  * the accepts a single child widget. #GtkScrolledWindow adds scrollbars
47  * to the child widget and optionally draws a beveled frame around the
48  * child widget.
49  *
50  * The scrolled window can work in two ways. Some widgets have native
51  * scrolling support; these widgets implement the #GtkScrollable interface.
52  * Widgets with native scroll support include #GtkTreeView, #GtkTextView,
53  * and #GtkLayout.
54  *
55  * For widgets that lack native scrolling support, the #GtkViewport
56  * widget acts as an adaptor class, implementing scrollability for child
57  * widgets that lack their own scrolling capabilities. Use #GtkViewport
58  * to scroll child widgets such as #GtkTable, #GtkBox, and so on.
59  *
60  * If a widget has native scrolling abilities, it can be added to the
61  * #GtkScrolledWindow with gtk_container_add(). If a widget does not, you
62  * must first add the widget to a #GtkViewport, then add the #GtkViewport
63  * to the scrolled window. The convenience function
64  * gtk_scrolled_window_add_with_viewport() does exactly this, so you can
65  * ignore the presence of the viewport.
66  *
67  * The position of the scrollbars is controlled by the scroll
68  * adjustments. See #GtkAdjustment for the fields in an adjustment - for
69  * #GtkScrollbar, used by #GtkScrolledWindow, the "value" field
70  * represents the position of the scrollbar, which must be between the
71  * "lower" field and "upper - page_size." The "page_size" field
72  * represents the size of the visible scrollable area. The
73  * "step_increment" and "page_increment" fields are used when the user
74  * asks to step down (using the small stepper arrows) or page down (using
75  * for example the PageDown key).
76  *
77  * If a #GtkScrolledWindow doesn't behave quite as you would like, or
78  * doesn't have exactly the right layout, it's very possible to set up
79  * your own scrolling with #GtkScrollbar and for example a #GtkTable.
80  */
81
82
83 /* scrolled window policy and size requisition handling:
84  *
85  * gtk size requisition works as follows:
86  *   a widget upon size-request reports the width and height that it finds
87  *   to be best suited to display its contents, including children.
88  *   the width and/or height reported from a widget upon size requisition
89  *   may be overidden by the user by specifying a width and/or height
90  *   other than 0 through gtk_widget_set_size_request().
91  *
92  * a scrolled window needs (for implementing all three policy types) to
93  * request its width and height based on two different rationales.
94  * 1)   the user wants the scrolled window to just fit into the space
95  *      that it gets allocated for a specifc dimension.
96  * 1.1) this does not apply if the user specified a concrete value
97  *      value for that specific dimension by either specifying usize for the
98  *      scrolled window or for its child.
99  * 2)   the user wants the scrolled window to take as much space up as
100  *      is desired by the child for a specifc dimension (i.e. POLICY_NEVER).
101  *
102  * also, kinda obvious:
103  * 3)   a user would certainly not have choosen a scrolled window as a container
104  *      for the child, if the resulting allocation takes up more space than the
105  *      child would have allocated without the scrolled window.
106  *
107  * conclusions:
108  * A) from 1) follows: the scrolled window shouldn't request more space for a
109  *    specifc dimension than is required at minimum.
110  * B) from 1.1) follows: the requisition may be overidden by usize of the scrolled
111  *    window (done automatically) or by usize of the child (needs to be checked).
112  * C) from 2) follows: for POLICY_NEVER, the scrolled window simply reports the
113  *    child's dimension.
114  * D) from 3) follows: the scrolled window child's minimum width and minimum height
115  *    under A) at least correspond to the space taken up by its scrollbars.
116  */
117
118 #define DEFAULT_SCROLLBAR_SPACING  3
119
120 struct _GtkScrolledWindowPrivate
121 {
122   GtkCornerType  real_window_placement;
123   GtkWidget     *hscrollbar;
124   GtkWidget     *vscrollbar;
125
126   gboolean window_placement_set;
127
128   guint16  shadow_type;
129
130   guint    hscrollbar_policy      : 2;
131   guint    vscrollbar_policy      : 2;
132   guint    hscrollbar_visible     : 1;
133   guint    vscrollbar_visible     : 1;
134   guint    window_placement       : 2;
135   guint    focus_out              : 1;   /* Flag used by ::move-focus-out implementation */
136
137   gint     min_content_width;
138   gint     min_content_height;
139 };
140
141
142 enum {
143   PROP_0,
144   PROP_HADJUSTMENT,
145   PROP_VADJUSTMENT,
146   PROP_HSCROLLBAR_POLICY,
147   PROP_VSCROLLBAR_POLICY,
148   PROP_WINDOW_PLACEMENT,
149   PROP_WINDOW_PLACEMENT_SET,
150   PROP_SHADOW_TYPE,
151   PROP_MIN_CONTENT_WIDTH,
152   PROP_MIN_CONTENT_HEIGHT
153 };
154
155 /* Signals */
156 enum
157 {
158   SCROLL_CHILD,
159   MOVE_FOCUS_OUT,
160   LAST_SIGNAL
161 };
162
163 static void     gtk_scrolled_window_set_property       (GObject           *object,
164                                                         guint              prop_id,
165                                                         const GValue      *value,
166                                                         GParamSpec        *pspec);
167 static void     gtk_scrolled_window_get_property       (GObject           *object,
168                                                         guint              prop_id,
169                                                         GValue            *value,
170                                                         GParamSpec        *pspec);
171
172 static void     gtk_scrolled_window_destroy            (GtkWidget         *widget);
173 static void     gtk_scrolled_window_screen_changed     (GtkWidget         *widget,
174                                                         GdkScreen         *previous_screen);
175 static gboolean gtk_scrolled_window_draw               (GtkWidget         *widget,
176                                                         cairo_t           *cr);
177 static void     gtk_scrolled_window_size_allocate      (GtkWidget         *widget,
178                                                         GtkAllocation     *allocation);
179 static gboolean gtk_scrolled_window_scroll_event       (GtkWidget         *widget,
180                                                         GdkEventScroll    *event);
181 static gboolean gtk_scrolled_window_focus              (GtkWidget         *widget,
182                                                         GtkDirectionType   direction);
183 static void     gtk_scrolled_window_add                (GtkContainer      *container,
184                                                         GtkWidget         *widget);
185 static void     gtk_scrolled_window_remove             (GtkContainer      *container,
186                                                         GtkWidget         *widget);
187 static void     gtk_scrolled_window_forall             (GtkContainer      *container,
188                                                         gboolean           include_internals,
189                                                         GtkCallback        callback,
190                                                         gpointer           callback_data);
191 static gboolean gtk_scrolled_window_scroll_child       (GtkScrolledWindow *scrolled_window,
192                                                         GtkScrollType      scroll,
193                                                         gboolean           horizontal);
194 static void     gtk_scrolled_window_move_focus_out     (GtkScrolledWindow *scrolled_window,
195                                                         GtkDirectionType   direction_type);
196
197 static void     gtk_scrolled_window_relative_allocation(GtkWidget         *widget,
198                                                         GtkAllocation     *allocation);
199 static void     gtk_scrolled_window_adjustment_changed (GtkAdjustment     *adjustment,
200                                                         gpointer           data);
201
202 static void  gtk_scrolled_window_update_real_placement (GtkScrolledWindow *scrolled_window);
203
204 static void  gtk_scrolled_window_get_preferred_width   (GtkWidget           *widget,
205                                                         gint                *minimum_size,
206                                                         gint                *natural_size);
207 static void  gtk_scrolled_window_get_preferred_height  (GtkWidget           *widget,
208                                                         gint                *minimum_size,
209                                                         gint                *natural_size);
210 static void  gtk_scrolled_window_get_preferred_height_for_width  (GtkWidget           *layout,
211                                                         gint                 width,
212                                                         gint                *minimum_height,
213                                                         gint                *natural_height);
214 static void  gtk_scrolled_window_get_preferred_width_for_height  (GtkWidget           *layout,
215                                                         gint                 width,
216                                                         gint                *minimum_height,
217                                                         gint                *natural_height);
218
219 static guint signals[LAST_SIGNAL] = {0};
220
221 G_DEFINE_TYPE (GtkScrolledWindow, gtk_scrolled_window, GTK_TYPE_BIN)
222
223
224 static void
225 add_scroll_binding (GtkBindingSet  *binding_set,
226                     guint           keyval,
227                     GdkModifierType mask,
228                     GtkScrollType   scroll,
229                     gboolean        horizontal)
230 {
231   guint keypad_keyval = keyval - GDK_KEY_Left + GDK_KEY_KP_Left;
232   
233   gtk_binding_entry_add_signal (binding_set, keyval, mask,
234                                 "scroll-child", 2,
235                                 GTK_TYPE_SCROLL_TYPE, scroll,
236                                 G_TYPE_BOOLEAN, horizontal);
237   gtk_binding_entry_add_signal (binding_set, keypad_keyval, mask,
238                                 "scroll-child", 2,
239                                 GTK_TYPE_SCROLL_TYPE, scroll,
240                                 G_TYPE_BOOLEAN, horizontal);
241 }
242
243 static void
244 add_tab_bindings (GtkBindingSet    *binding_set,
245                   GdkModifierType   modifiers,
246                   GtkDirectionType  direction)
247 {
248   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, modifiers,
249                                 "move-focus-out", 1,
250                                 GTK_TYPE_DIRECTION_TYPE, direction);
251   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, modifiers,
252                                 "move-focus-out", 1,
253                                 GTK_TYPE_DIRECTION_TYPE, direction);
254 }
255
256 static void
257 gtk_scrolled_window_class_init (GtkScrolledWindowClass *class)
258 {
259   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
260   GtkWidgetClass *widget_class;
261   GtkContainerClass *container_class;
262   GtkBindingSet *binding_set;
263
264   widget_class = (GtkWidgetClass*) class;
265   container_class = (GtkContainerClass*) class;
266
267   gobject_class->set_property = gtk_scrolled_window_set_property;
268   gobject_class->get_property = gtk_scrolled_window_get_property;
269
270   widget_class->destroy = gtk_scrolled_window_destroy;
271   widget_class->screen_changed = gtk_scrolled_window_screen_changed;
272   widget_class->draw = gtk_scrolled_window_draw;
273   widget_class->size_allocate = gtk_scrolled_window_size_allocate;
274   widget_class->scroll_event = gtk_scrolled_window_scroll_event;
275   widget_class->focus = gtk_scrolled_window_focus;
276   widget_class->get_preferred_width = gtk_scrolled_window_get_preferred_width;
277   widget_class->get_preferred_height = gtk_scrolled_window_get_preferred_height;
278   widget_class->get_preferred_height_for_width = gtk_scrolled_window_get_preferred_height_for_width;
279   widget_class->get_preferred_width_for_height = gtk_scrolled_window_get_preferred_width_for_height;
280
281   container_class->add = gtk_scrolled_window_add;
282   container_class->remove = gtk_scrolled_window_remove;
283   container_class->forall = gtk_scrolled_window_forall;
284   gtk_container_class_handle_border_width (container_class);
285
286   class->scrollbar_spacing = -1;
287
288   class->scroll_child = gtk_scrolled_window_scroll_child;
289   class->move_focus_out = gtk_scrolled_window_move_focus_out;
290   
291   g_object_class_install_property (gobject_class,
292                                    PROP_HADJUSTMENT,
293                                    g_param_spec_object ("hadjustment",
294                                                         P_("Horizontal Adjustment"),
295                                                         P_("The GtkAdjustment for the horizontal position"),
296                                                         GTK_TYPE_ADJUSTMENT,
297                                                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
298   g_object_class_install_property (gobject_class,
299                                    PROP_VADJUSTMENT,
300                                    g_param_spec_object ("vadjustment",
301                                                         P_("Vertical Adjustment"),
302                                                         P_("The GtkAdjustment for the vertical position"),
303                                                         GTK_TYPE_ADJUSTMENT,
304                                                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
305   g_object_class_install_property (gobject_class,
306                                    PROP_HSCROLLBAR_POLICY,
307                                    g_param_spec_enum ("hscrollbar-policy",
308                                                       P_("Horizontal Scrollbar Policy"),
309                                                       P_("When the horizontal scrollbar is displayed"),
310                                                       GTK_TYPE_POLICY_TYPE,
311                                                       GTK_POLICY_AUTOMATIC,
312                                                       GTK_PARAM_READABLE | GTK_PARAM_WRITABLE));
313   g_object_class_install_property (gobject_class,
314                                    PROP_VSCROLLBAR_POLICY,
315                                    g_param_spec_enum ("vscrollbar-policy",
316                                                       P_("Vertical Scrollbar Policy"),
317                                                       P_("When the vertical scrollbar is displayed"),
318                                                       GTK_TYPE_POLICY_TYPE,
319                                                       GTK_POLICY_AUTOMATIC,
320                                                       GTK_PARAM_READABLE | GTK_PARAM_WRITABLE));
321
322   g_object_class_install_property (gobject_class,
323                                    PROP_WINDOW_PLACEMENT,
324                                    g_param_spec_enum ("window-placement",
325                                                       P_("Window Placement"),
326                                                       P_("Where the contents are located with respect to the scrollbars. This property only takes effect if \"window-placement-set\" is TRUE."),
327                                                       GTK_TYPE_CORNER_TYPE,
328                                                       GTK_CORNER_TOP_LEFT,
329                                                       GTK_PARAM_READABLE | GTK_PARAM_WRITABLE));
330   
331   /**
332    * GtkScrolledWindow:window-placement-set:
333    *
334    * Whether "window-placement" should be used to determine the location 
335    * of the contents with respect to the scrollbars. Otherwise, the 
336    * "gtk-scrolled-window-placement" setting is used.
337    *
338    * Since: 2.10
339    */
340   g_object_class_install_property (gobject_class,
341                                    PROP_WINDOW_PLACEMENT_SET,
342                                    g_param_spec_boolean ("window-placement-set",
343                                                          P_("Window Placement Set"),
344                                                          P_("Whether \"window-placement\" should be used to determine the location of the contents with respect to the scrollbars."),
345                                                          FALSE,
346                                                          GTK_PARAM_READABLE | GTK_PARAM_WRITABLE));
347   g_object_class_install_property (gobject_class,
348                                    PROP_SHADOW_TYPE,
349                                    g_param_spec_enum ("shadow-type",
350                                                       P_("Shadow Type"),
351                                                       P_("Style of bevel around the contents"),
352                                                       GTK_TYPE_SHADOW_TYPE,
353                                                       GTK_SHADOW_NONE,
354                                                       GTK_PARAM_READABLE | GTK_PARAM_WRITABLE));
355
356   /**
357    * GtkScrolledWindow:scrollbars-within-bevel:
358    *
359    * Whether to place scrollbars within the scrolled window's bevel.
360    *
361    * Since: 2.12
362    */
363   gtk_widget_class_install_style_property (widget_class,
364                                            g_param_spec_boolean ("scrollbars-within-bevel",
365                                                                  P_("Scrollbars within bevel"),
366                                                                  P_("Place scrollbars within the scrolled window's bevel"),
367                                                                  FALSE,
368                                                                  GTK_PARAM_READABLE));
369
370   gtk_widget_class_install_style_property (widget_class,
371                                            g_param_spec_int ("scrollbar-spacing",
372                                                              P_("Scrollbar spacing"),
373                                                              P_("Number of pixels between the scrollbars and the scrolled window"),
374                                                              0,
375                                                              G_MAXINT,
376                                                              DEFAULT_SCROLLBAR_SPACING,
377                                                              GTK_PARAM_READABLE));
378
379   g_object_class_install_property (gobject_class,
380                                    PROP_MIN_CONTENT_WIDTH,
381                                    g_param_spec_int ("min-content-width",
382                                                      P_("Minimum Content Width"),
383                                                      P_("The minimum width that the scrolled window will allocate to its content"),
384                                                      -1, G_MAXINT, -1,
385                                                      GTK_PARAM_READWRITE));
386   g_object_class_install_property (gobject_class,
387                                    PROP_MIN_CONTENT_HEIGHT,
388                                    g_param_spec_int ("min-content-height",
389                                                      P_("Minimum Content Height"),
390                                                      P_("The minimum height that the scrolled window will allocate to its content"),
391                                                      -1, G_MAXINT, -1,
392                                                      GTK_PARAM_READWRITE));
393   /**
394    * GtkScrolledWindow::scroll-child:
395    * @scrolled_window: a #GtkScrolledWindow
396    * @scroll: a #GtkScrollType describing how much to scroll
397    * @horizontal: whether the keybinding scrolls the child
398    *   horizontally or not
399    *
400    * The ::scroll-child signal is a
401    * <link linkend="keybinding-signals">keybinding signal</link>
402    * which gets emitted when a keybinding that scrolls is pressed.
403    * The horizontal or vertical adjustment is updated which triggers a
404    * signal that the scrolled windows child may listen to and scroll itself.
405    */
406   signals[SCROLL_CHILD] =
407     g_signal_new (I_("scroll-child"),
408                   G_TYPE_FROM_CLASS (gobject_class),
409                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
410                   G_STRUCT_OFFSET (GtkScrolledWindowClass, scroll_child),
411                   NULL, NULL,
412                   _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
413                   G_TYPE_BOOLEAN, 2,
414                   GTK_TYPE_SCROLL_TYPE,
415                   G_TYPE_BOOLEAN);
416
417   /**
418    * GtkScrolledWindow::move-focus-out:
419    * @scrolled_window: a #GtkScrolledWindow
420    * @direction_type: either %GTK_DIR_TAB_FORWARD or
421    *   %GTK_DIR_TAB_BACKWARD
422    *
423    * The ::move-focus-out signal is a
424    * <link linkend="keybinding-signals">keybinding signal</link>
425    * which gets emitted when focus is moved away from the scrolled
426    * window by a keybinding.
427    * The #GtkWidget::move-focus signal is emitted with @direction_type
428    * on this scrolled windows toplevel parent in the container hierarchy.
429    * The default bindings for this signal are
430    * <keycombo><keycap>Tab</keycap><keycap>Ctrl</keycap></keycombo>
431    * and
432    * <keycombo><keycap>Tab</keycap><keycap>Ctrl</keycap><keycap>Shift</keycap></keycombo>.
433    */
434   signals[MOVE_FOCUS_OUT] =
435     g_signal_new (I_("move-focus-out"),
436                   G_TYPE_FROM_CLASS (gobject_class),
437                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
438                   G_STRUCT_OFFSET (GtkScrolledWindowClass, move_focus_out),
439                   NULL, NULL,
440                   _gtk_marshal_VOID__ENUM,
441                   G_TYPE_NONE, 1,
442                   GTK_TYPE_DIRECTION_TYPE);
443   
444   binding_set = gtk_binding_set_by_class (class);
445
446   add_scroll_binding (binding_set, GDK_KEY_Left,  GDK_CONTROL_MASK, GTK_SCROLL_STEP_BACKWARD, TRUE);
447   add_scroll_binding (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK, GTK_SCROLL_STEP_FORWARD,  TRUE);
448   add_scroll_binding (binding_set, GDK_KEY_Up,    GDK_CONTROL_MASK, GTK_SCROLL_STEP_BACKWARD, FALSE);
449   add_scroll_binding (binding_set, GDK_KEY_Down,  GDK_CONTROL_MASK, GTK_SCROLL_STEP_FORWARD,  FALSE);
450
451   add_scroll_binding (binding_set, GDK_KEY_Page_Up,   GDK_CONTROL_MASK, GTK_SCROLL_PAGE_BACKWARD, TRUE);
452   add_scroll_binding (binding_set, GDK_KEY_Page_Down, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_FORWARD,  TRUE);
453   add_scroll_binding (binding_set, GDK_KEY_Page_Up,   0,                GTK_SCROLL_PAGE_BACKWARD, FALSE);
454   add_scroll_binding (binding_set, GDK_KEY_Page_Down, 0,                GTK_SCROLL_PAGE_FORWARD,  FALSE);
455
456   add_scroll_binding (binding_set, GDK_KEY_Home, GDK_CONTROL_MASK, GTK_SCROLL_START, TRUE);
457   add_scroll_binding (binding_set, GDK_KEY_End,  GDK_CONTROL_MASK, GTK_SCROLL_END,   TRUE);
458   add_scroll_binding (binding_set, GDK_KEY_Home, 0,                GTK_SCROLL_START, FALSE);
459   add_scroll_binding (binding_set, GDK_KEY_End,  0,                GTK_SCROLL_END,   FALSE);
460
461   add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
462   add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
463
464   g_type_class_add_private (class, sizeof (GtkScrolledWindowPrivate));
465 }
466
467 static void
468 gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
469 {
470   GtkScrolledWindowPrivate *priv;
471
472   scrolled_window->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (scrolled_window,
473                                                               GTK_TYPE_SCROLLED_WINDOW,
474                                                               GtkScrolledWindowPrivate);
475
476   gtk_widget_set_has_window (GTK_WIDGET (scrolled_window), FALSE);
477   gtk_widget_set_can_focus (GTK_WIDGET (scrolled_window), TRUE);
478
479   priv->hscrollbar = NULL;
480   priv->vscrollbar = NULL;
481   priv->hscrollbar_policy = GTK_POLICY_AUTOMATIC;
482   priv->vscrollbar_policy = GTK_POLICY_AUTOMATIC;
483   priv->hscrollbar_visible = FALSE;
484   priv->vscrollbar_visible = FALSE;
485   priv->focus_out = FALSE;
486   priv->window_placement = GTK_CORNER_TOP_LEFT;
487   gtk_scrolled_window_update_real_placement (scrolled_window);
488   priv->min_content_width = -1;
489   priv->min_content_height = -1;
490 }
491
492 /**
493  * gtk_scrolled_window_new:
494  * @hadjustment: (allow-none): horizontal adjustment
495  * @vadjustment: (allow-none): vertical adjustment
496  *
497  * Creates a new scrolled window.
498  *
499  * The two arguments are the scrolled window's adjustments; these will be
500  * shared with the scrollbars and the child widget to keep the bars in sync 
501  * with the child. Usually you want to pass %NULL for the adjustments, which 
502  * will cause the scrolled window to create them for you.
503  *
504  * Returns: a new scrolled window
505  */
506 GtkWidget*
507 gtk_scrolled_window_new (GtkAdjustment *hadjustment,
508                          GtkAdjustment *vadjustment)
509 {
510   GtkWidget *scrolled_window;
511
512   if (hadjustment)
513     g_return_val_if_fail (GTK_IS_ADJUSTMENT (hadjustment), NULL);
514
515   if (vadjustment)
516     g_return_val_if_fail (GTK_IS_ADJUSTMENT (vadjustment), NULL);
517
518   scrolled_window = g_object_new (GTK_TYPE_SCROLLED_WINDOW,
519                                     "hadjustment", hadjustment,
520                                     "vadjustment", vadjustment,
521                                     NULL);
522
523   return scrolled_window;
524 }
525
526 /**
527  * gtk_scrolled_window_set_hadjustment:
528  * @scrolled_window: a #GtkScrolledWindow
529  * @hadjustment: horizontal scroll adjustment
530  *
531  * Sets the #GtkAdjustment for the horizontal scrollbar.
532  */
533 void
534 gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
535                                      GtkAdjustment     *hadjustment)
536 {
537   GtkScrolledWindowPrivate *priv;
538   GtkBin *bin;
539   GtkWidget *child;
540
541   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
542   if (hadjustment)
543     g_return_if_fail (GTK_IS_ADJUSTMENT (hadjustment));
544   else
545     hadjustment = (GtkAdjustment*) g_object_new (GTK_TYPE_ADJUSTMENT, NULL);
546
547   bin = GTK_BIN (scrolled_window);
548   priv = scrolled_window->priv;
549
550   if (!priv->hscrollbar)
551     {
552       gtk_widget_push_composite_child ();
553       priv->hscrollbar = gtk_scrollbar_new (GTK_ORIENTATION_HORIZONTAL, hadjustment);
554       gtk_widget_set_composite_name (priv->hscrollbar, "hscrollbar");
555       gtk_widget_pop_composite_child ();
556
557       gtk_widget_set_parent (priv->hscrollbar, GTK_WIDGET (scrolled_window));
558       g_object_ref (priv->hscrollbar);
559       gtk_widget_show (priv->hscrollbar);
560     }
561   else
562     {
563       GtkAdjustment *old_adjustment;
564
565       old_adjustment = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
566       if (old_adjustment == hadjustment)
567         return;
568
569       g_signal_handlers_disconnect_by_func (old_adjustment,
570                                             gtk_scrolled_window_adjustment_changed,
571                                             scrolled_window);
572       gtk_range_set_adjustment (GTK_RANGE (priv->hscrollbar),
573                                 hadjustment);
574     }
575   hadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
576   g_signal_connect (hadjustment,
577                     "changed",
578                     G_CALLBACK (gtk_scrolled_window_adjustment_changed),
579                     scrolled_window);
580   gtk_scrolled_window_adjustment_changed (hadjustment, scrolled_window);
581
582   child = gtk_bin_get_child (bin);
583   if (GTK_IS_SCROLLABLE (child))
584     gtk_scrollable_set_hadjustment (GTK_SCROLLABLE (child), hadjustment);
585
586   g_object_notify (G_OBJECT (scrolled_window), "hadjustment");
587 }
588
589 /**
590  * gtk_scrolled_window_set_vadjustment:
591  * @scrolled_window: a #GtkScrolledWindow
592  * @vadjustment: vertical scroll adjustment
593  *
594  * Sets the #GtkAdjustment for the vertical scrollbar.
595  */
596 void
597 gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
598                                      GtkAdjustment     *vadjustment)
599 {
600   GtkScrolledWindowPrivate *priv;
601   GtkBin *bin;
602   GtkWidget *child;
603
604   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
605   if (vadjustment)
606     g_return_if_fail (GTK_IS_ADJUSTMENT (vadjustment));
607   else
608     vadjustment = (GtkAdjustment*) g_object_new (GTK_TYPE_ADJUSTMENT, NULL);
609
610   bin = GTK_BIN (scrolled_window);
611   priv = scrolled_window->priv;
612
613   if (!priv->vscrollbar)
614     {
615       gtk_widget_push_composite_child ();
616       priv->vscrollbar = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, vadjustment);
617       gtk_widget_set_composite_name (priv->vscrollbar, "vscrollbar");
618       gtk_widget_pop_composite_child ();
619
620       gtk_widget_set_parent (priv->vscrollbar, GTK_WIDGET (scrolled_window));
621       g_object_ref (priv->vscrollbar);
622       gtk_widget_show (priv->vscrollbar);
623     }
624   else
625     {
626       GtkAdjustment *old_adjustment;
627       
628       old_adjustment = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar));
629       if (old_adjustment == vadjustment)
630         return;
631
632       g_signal_handlers_disconnect_by_func (old_adjustment,
633                                             gtk_scrolled_window_adjustment_changed,
634                                             scrolled_window);
635       gtk_range_set_adjustment (GTK_RANGE (priv->vscrollbar),
636                                 vadjustment);
637     }
638   vadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar));
639   g_signal_connect (vadjustment,
640                     "changed",
641                     G_CALLBACK (gtk_scrolled_window_adjustment_changed),
642                     scrolled_window);
643   gtk_scrolled_window_adjustment_changed (vadjustment, scrolled_window);
644
645   child = gtk_bin_get_child (bin);
646   if (GTK_IS_SCROLLABLE (child))
647     gtk_scrollable_set_vadjustment (GTK_SCROLLABLE (child), vadjustment);
648
649   g_object_notify (G_OBJECT (scrolled_window), "vadjustment");
650 }
651
652 /**
653  * gtk_scrolled_window_get_hadjustment:
654  * @scrolled_window: a #GtkScrolledWindow
655  *
656  * Returns the horizontal scrollbar's adjustment, used to connect the
657  * horizontal scrollbar to the child widget's horizontal scroll
658  * functionality.
659  *
660  * Returns: (transfer none): the horizontal #GtkAdjustment
661  */
662 GtkAdjustment*
663 gtk_scrolled_window_get_hadjustment (GtkScrolledWindow *scrolled_window)
664 {
665   GtkScrolledWindowPrivate *priv;
666
667   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
668
669   priv = scrolled_window->priv;
670
671   return (priv->hscrollbar ?
672           gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar)) :
673           NULL);
674 }
675
676 /**
677  * gtk_scrolled_window_get_vadjustment:
678  * @scrolled_window: a #GtkScrolledWindow
679  * 
680  * Returns the vertical scrollbar's adjustment, used to connect the
681  * vertical scrollbar to the child widget's vertical scroll functionality.
682  * 
683  * Returns: (transfer none): the vertical #GtkAdjustment
684  */
685 GtkAdjustment*
686 gtk_scrolled_window_get_vadjustment (GtkScrolledWindow *scrolled_window)
687 {
688   GtkScrolledWindowPrivate *priv;
689
690   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
691
692   priv = scrolled_window->priv;
693
694   return (priv->vscrollbar ?
695           gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)) :
696           NULL);
697 }
698
699 /**
700  * gtk_scrolled_window_get_hscrollbar:
701  * @scrolled_window: a #GtkScrolledWindow
702  *
703  * Returns the horizontal scrollbar of @scrolled_window.
704  *
705  * Returns: (transfer none): the horizontal scrollbar of the scrolled window,
706  *     or %NULL if it does not have one.
707  *
708  * Since: 2.8
709  */
710 GtkWidget*
711 gtk_scrolled_window_get_hscrollbar (GtkScrolledWindow *scrolled_window)
712 {
713   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
714
715   return scrolled_window->priv->hscrollbar;
716 }
717
718 /**
719  * gtk_scrolled_window_get_vscrollbar:
720  * @scrolled_window: a #GtkScrolledWindow
721  * 
722  * Returns the vertical scrollbar of @scrolled_window.
723  *
724  * Returns: (transfer none): the vertical scrollbar of the scrolled window,
725  *     or %NULL if it does not have one.
726  *
727  * Since: 2.8
728  */
729 GtkWidget*
730 gtk_scrolled_window_get_vscrollbar (GtkScrolledWindow *scrolled_window)
731 {
732   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
733
734   return scrolled_window->priv->vscrollbar;
735 }
736
737 /**
738  * gtk_scrolled_window_set_policy:
739  * @scrolled_window: a #GtkScrolledWindow
740  * @hscrollbar_policy: policy for horizontal bar
741  * @vscrollbar_policy: policy for vertical bar
742  * 
743  * Sets the scrollbar policy for the horizontal and vertical scrollbars.
744  *
745  * The policy determines when the scrollbar should appear; it is a value
746  * from the #GtkPolicyType enumeration. If %GTK_POLICY_ALWAYS, the
747  * scrollbar is always present; if %GTK_POLICY_NEVER, the scrollbar is
748  * never present; if %GTK_POLICY_AUTOMATIC, the scrollbar is present only
749  * if needed (that is, if the slider part of the bar would be smaller
750  * than the trough - the display is larger than the page size).
751  */
752 void
753 gtk_scrolled_window_set_policy (GtkScrolledWindow *scrolled_window,
754                                 GtkPolicyType      hscrollbar_policy,
755                                 GtkPolicyType      vscrollbar_policy)
756 {
757   GtkScrolledWindowPrivate *priv;
758   GObject *object = G_OBJECT (scrolled_window);
759   
760   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
761
762   priv = scrolled_window->priv;
763
764   if ((priv->hscrollbar_policy != hscrollbar_policy) ||
765       (priv->vscrollbar_policy != vscrollbar_policy))
766     {
767       priv->hscrollbar_policy = hscrollbar_policy;
768       priv->vscrollbar_policy = vscrollbar_policy;
769
770       gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
771
772       g_object_freeze_notify (object);
773       g_object_notify (object, "hscrollbar-policy");
774       g_object_notify (object, "vscrollbar-policy");
775       g_object_thaw_notify (object);
776     }
777 }
778
779 /**
780  * gtk_scrolled_window_get_policy:
781  * @scrolled_window: a #GtkScrolledWindow
782  * @hscrollbar_policy: location to store the policy for the horizontal 
783  *     scrollbar, or %NULL.
784  * @vscrollbar_policy: location to store the policy for the vertical
785  *     scrollbar, or %NULL.
786  * 
787  * Retrieves the current policy values for the horizontal and vertical
788  * scrollbars. See gtk_scrolled_window_set_policy().
789  */
790 void
791 gtk_scrolled_window_get_policy (GtkScrolledWindow *scrolled_window,
792                                 GtkPolicyType     *hscrollbar_policy,
793                                 GtkPolicyType     *vscrollbar_policy)
794 {
795   GtkScrolledWindowPrivate *priv;
796
797   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
798
799   priv = scrolled_window->priv;
800
801   if (hscrollbar_policy)
802     *hscrollbar_policy = priv->hscrollbar_policy;
803   if (vscrollbar_policy)
804     *vscrollbar_policy = priv->vscrollbar_policy;
805 }
806
807 static void
808 gtk_scrolled_window_update_real_placement (GtkScrolledWindow *scrolled_window)
809 {
810   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
811   GtkSettings *settings;
812
813   settings = gtk_widget_get_settings (GTK_WIDGET (scrolled_window));
814
815   if (priv->window_placement_set || settings == NULL)
816     priv->real_window_placement = priv->window_placement;
817   else
818     g_object_get (settings,
819                   "gtk-scrolled-window-placement",
820                   &priv->real_window_placement,
821                   NULL);
822 }
823
824 static void
825 gtk_scrolled_window_set_placement_internal (GtkScrolledWindow *scrolled_window,
826                                             GtkCornerType      window_placement)
827 {
828   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
829
830   if (priv->window_placement != window_placement)
831     {
832       priv->window_placement = window_placement;
833
834       gtk_scrolled_window_update_real_placement (scrolled_window);
835       gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
836       
837       g_object_notify (G_OBJECT (scrolled_window), "window-placement");
838     }
839 }
840
841 static void
842 gtk_scrolled_window_set_placement_set (GtkScrolledWindow *scrolled_window,
843                                        gboolean           placement_set,
844                                        gboolean           emit_resize)
845 {
846   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
847
848   if (priv->window_placement_set != placement_set)
849     {
850       priv->window_placement_set = placement_set;
851
852       gtk_scrolled_window_update_real_placement (scrolled_window);
853       if (emit_resize)
854         gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
855
856       g_object_notify (G_OBJECT (scrolled_window), "window-placement-set");
857     }
858 }
859
860 /**
861  * gtk_scrolled_window_set_placement:
862  * @scrolled_window: a #GtkScrolledWindow
863  * @window_placement: position of the child window
864  *
865  * Sets the placement of the contents with respect to the scrollbars
866  * for the scrolled window.
867  * 
868  * The default is %GTK_CORNER_TOP_LEFT, meaning the child is
869  * in the top left, with the scrollbars underneath and to the right.
870  * Other values in #GtkCornerType are %GTK_CORNER_TOP_RIGHT,
871  * %GTK_CORNER_BOTTOM_LEFT, and %GTK_CORNER_BOTTOM_RIGHT.
872  *
873  * See also gtk_scrolled_window_get_placement() and
874  * gtk_scrolled_window_unset_placement().
875  */
876 void
877 gtk_scrolled_window_set_placement (GtkScrolledWindow *scrolled_window,
878                                    GtkCornerType      window_placement)
879 {
880   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
881
882   gtk_scrolled_window_set_placement_set (scrolled_window, TRUE, FALSE);
883   gtk_scrolled_window_set_placement_internal (scrolled_window, window_placement);
884 }
885
886 /**
887  * gtk_scrolled_window_get_placement:
888  * @scrolled_window: a #GtkScrolledWindow
889  *
890  * Gets the placement of the contents with respect to the scrollbars
891  * for the scrolled window. See gtk_scrolled_window_set_placement().
892  *
893  * Return value: the current placement value.
894  *
895  * See also gtk_scrolled_window_set_placement() and
896  * gtk_scrolled_window_unset_placement().
897  **/
898 GtkCornerType
899 gtk_scrolled_window_get_placement (GtkScrolledWindow *scrolled_window)
900 {
901   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), GTK_CORNER_TOP_LEFT);
902
903   return scrolled_window->priv->window_placement;
904 }
905
906 /**
907  * gtk_scrolled_window_unset_placement:
908  * @scrolled_window: a #GtkScrolledWindow
909  *
910  * Unsets the placement of the contents with respect to the scrollbars
911  * for the scrolled window. If no window placement is set for a scrolled
912  * window, it obeys the "gtk-scrolled-window-placement" XSETTING.
913  *
914  * See also gtk_scrolled_window_set_placement() and
915  * gtk_scrolled_window_get_placement().
916  *
917  * Since: 2.10
918  **/
919 void
920 gtk_scrolled_window_unset_placement (GtkScrolledWindow *scrolled_window)
921 {
922   GtkScrolledWindowPrivate *priv;
923
924   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
925
926   priv = scrolled_window->priv;
927
928   if (priv->window_placement_set)
929     {
930       priv->window_placement_set = FALSE;
931
932       gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
933
934       g_object_notify (G_OBJECT (scrolled_window), "window-placement-set");
935     }
936 }
937
938 /**
939  * gtk_scrolled_window_set_shadow_type:
940  * @scrolled_window: a #GtkScrolledWindow
941  * @type: kind of shadow to draw around scrolled window contents
942  *
943  * Changes the type of shadow drawn around the contents of
944  * @scrolled_window.
945  * 
946  **/
947 void
948 gtk_scrolled_window_set_shadow_type (GtkScrolledWindow *scrolled_window,
949                                      GtkShadowType      type)
950 {
951   GtkScrolledWindowPrivate *priv;
952
953   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
954   g_return_if_fail (type >= GTK_SHADOW_NONE && type <= GTK_SHADOW_ETCHED_OUT);
955
956   priv = scrolled_window->priv;
957
958   if (priv->shadow_type != type)
959     {
960       priv->shadow_type = type;
961
962       if (gtk_widget_is_drawable (GTK_WIDGET (scrolled_window)))
963         gtk_widget_queue_draw (GTK_WIDGET (scrolled_window));
964
965       gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
966
967       g_object_notify (G_OBJECT (scrolled_window), "shadow-type");
968     }
969 }
970
971 /**
972  * gtk_scrolled_window_get_shadow_type:
973  * @scrolled_window: a #GtkScrolledWindow
974  *
975  * Gets the shadow type of the scrolled window. See 
976  * gtk_scrolled_window_set_shadow_type().
977  *
978  * Return value: the current shadow type
979  **/
980 GtkShadowType
981 gtk_scrolled_window_get_shadow_type (GtkScrolledWindow *scrolled_window)
982 {
983   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_NONE);
984
985   return scrolled_window->priv->shadow_type;
986 }
987
988 static void
989 gtk_scrolled_window_destroy (GtkWidget *widget)
990 {
991   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
992   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
993
994   if (priv->hscrollbar)
995     {
996       g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar)),
997                                             gtk_scrolled_window_adjustment_changed,
998                                             scrolled_window);
999       gtk_widget_unparent (priv->hscrollbar);
1000       gtk_widget_destroy (priv->hscrollbar);
1001       g_object_unref (priv->hscrollbar);
1002       priv->hscrollbar = NULL;
1003     }
1004   if (priv->vscrollbar)
1005     {
1006       g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)),
1007                                             gtk_scrolled_window_adjustment_changed,
1008                                             scrolled_window);
1009       gtk_widget_unparent (priv->vscrollbar);
1010       gtk_widget_destroy (priv->vscrollbar);
1011       g_object_unref (priv->vscrollbar);
1012       priv->vscrollbar = NULL;
1013     }
1014
1015   GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->destroy (widget);
1016 }
1017
1018 static void
1019 gtk_scrolled_window_set_property (GObject      *object,
1020                                   guint         prop_id,
1021                                   const GValue *value,
1022                                   GParamSpec   *pspec)
1023 {
1024   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (object);
1025   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
1026
1027   switch (prop_id)
1028     {
1029     case PROP_HADJUSTMENT:
1030       gtk_scrolled_window_set_hadjustment (scrolled_window,
1031                                            g_value_get_object (value));
1032       break;
1033     case PROP_VADJUSTMENT:
1034       gtk_scrolled_window_set_vadjustment (scrolled_window,
1035                                            g_value_get_object (value));
1036       break;
1037     case PROP_HSCROLLBAR_POLICY:
1038       gtk_scrolled_window_set_policy (scrolled_window,
1039                                       g_value_get_enum (value),
1040                                       priv->vscrollbar_policy);
1041       break;
1042     case PROP_VSCROLLBAR_POLICY:
1043       gtk_scrolled_window_set_policy (scrolled_window,
1044                                       priv->hscrollbar_policy,
1045                                       g_value_get_enum (value));
1046       break;
1047     case PROP_WINDOW_PLACEMENT:
1048       gtk_scrolled_window_set_placement_internal (scrolled_window,
1049                                                   g_value_get_enum (value));
1050       break;
1051     case PROP_WINDOW_PLACEMENT_SET:
1052       gtk_scrolled_window_set_placement_set (scrolled_window,
1053                                              g_value_get_boolean (value),
1054                                              TRUE);
1055       break;
1056     case PROP_SHADOW_TYPE:
1057       gtk_scrolled_window_set_shadow_type (scrolled_window,
1058                                            g_value_get_enum (value));
1059       break;
1060     case PROP_MIN_CONTENT_WIDTH:
1061       gtk_scrolled_window_set_min_content_width (scrolled_window,
1062                                                  g_value_get_int (value));
1063       break;
1064     case PROP_MIN_CONTENT_HEIGHT:
1065       gtk_scrolled_window_set_min_content_height (scrolled_window,
1066                                                   g_value_get_int (value));
1067       break;
1068     default:
1069       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1070       break;
1071     }
1072 }
1073
1074 static void
1075 gtk_scrolled_window_get_property (GObject    *object,
1076                                   guint       prop_id,
1077                                   GValue     *value,
1078                                   GParamSpec *pspec)
1079 {
1080   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (object);
1081   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
1082
1083   switch (prop_id)
1084     {
1085     case PROP_HADJUSTMENT:
1086       g_value_set_object (value,
1087                           G_OBJECT (gtk_scrolled_window_get_hadjustment (scrolled_window)));
1088       break;
1089     case PROP_VADJUSTMENT:
1090       g_value_set_object (value,
1091                           G_OBJECT (gtk_scrolled_window_get_vadjustment (scrolled_window)));
1092       break;
1093     case PROP_WINDOW_PLACEMENT:
1094       g_value_set_enum (value, priv->window_placement);
1095       break;
1096     case PROP_WINDOW_PLACEMENT_SET:
1097       g_value_set_boolean (value, priv->window_placement_set);
1098       break;
1099     case PROP_SHADOW_TYPE:
1100       g_value_set_enum (value, priv->shadow_type);
1101       break;
1102     case PROP_HSCROLLBAR_POLICY:
1103       g_value_set_enum (value, priv->hscrollbar_policy);
1104       break;
1105     case PROP_VSCROLLBAR_POLICY:
1106       g_value_set_enum (value, priv->vscrollbar_policy);
1107       break;
1108     case PROP_MIN_CONTENT_WIDTH:
1109       g_value_set_int (value, priv->min_content_width);
1110       break;
1111     case PROP_MIN_CONTENT_HEIGHT:
1112       g_value_set_int (value, priv->min_content_height);
1113       break;
1114     default:
1115       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1116       break;
1117     }
1118 }
1119
1120 static void
1121 traverse_container (GtkWidget *widget,
1122                     gpointer   data)
1123 {
1124   if (GTK_IS_SCROLLED_WINDOW (widget))
1125     {
1126       gtk_scrolled_window_update_real_placement (GTK_SCROLLED_WINDOW (widget));
1127       gtk_widget_queue_resize (widget);
1128     }
1129   else if (GTK_IS_CONTAINER (widget))
1130     gtk_container_forall (GTK_CONTAINER (widget), traverse_container, NULL);
1131 }
1132
1133 static void
1134 gtk_scrolled_window_settings_changed (GtkSettings *settings)
1135 {
1136   GList *list, *l;
1137
1138   list = gtk_window_list_toplevels ();
1139
1140   for (l = list; l; l = l->next)
1141     gtk_container_forall (GTK_CONTAINER (l->data), 
1142                           traverse_container, NULL);
1143
1144   g_list_free (list);
1145 }
1146
1147 static void
1148 gtk_scrolled_window_screen_changed (GtkWidget *widget,
1149                                     GdkScreen *previous_screen)
1150 {
1151   GtkSettings *settings;
1152   guint window_placement_connection;
1153
1154   gtk_scrolled_window_update_real_placement (GTK_SCROLLED_WINDOW (widget));
1155
1156   if (!gtk_widget_has_screen (widget))
1157     return;
1158
1159   settings = gtk_widget_get_settings (widget);
1160
1161   window_placement_connection = 
1162     GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (settings), 
1163                                          "gtk-scrolled-window-connection"));
1164   
1165   if (window_placement_connection)
1166     return;
1167
1168   window_placement_connection =
1169     g_signal_connect (settings, "notify::gtk-scrolled-window-placement",
1170                       G_CALLBACK (gtk_scrolled_window_settings_changed), NULL);
1171   g_object_set_data (G_OBJECT (settings), 
1172                      I_("gtk-scrolled-window-connection"),
1173                      GUINT_TO_POINTER (window_placement_connection));
1174 }
1175
1176 static gboolean
1177 gtk_scrolled_window_draw (GtkWidget *widget,
1178                           cairo_t   *cr)
1179 {
1180   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
1181   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
1182
1183   if (priv->shadow_type != GTK_SHADOW_NONE)
1184     {
1185       GtkAllocation relative_allocation;
1186       GtkStyleContext *context;
1187       gboolean scrollbars_within_bevel;
1188
1189       context = gtk_widget_get_style_context (widget);
1190
1191       gtk_style_context_save (context);
1192       gtk_style_context_add_class (context, GTK_STYLE_CLASS_FRAME);
1193
1194       gtk_widget_style_get (widget, "scrollbars-within-bevel", &scrollbars_within_bevel, NULL);
1195
1196       if (!scrollbars_within_bevel)
1197         {
1198           GtkStateFlags state;
1199           GtkBorder padding, border;
1200
1201           state = gtk_widget_get_state_flags (widget);
1202           gtk_style_context_get_padding (context, state, &padding);
1203           gtk_style_context_get_border (context, state, &border);
1204
1205           gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
1206
1207           relative_allocation.x -= padding.left + border.left;
1208           relative_allocation.y -= padding.top + border.top;
1209           relative_allocation.width += padding.left + padding.right + border.left + border.right;
1210           relative_allocation.height += padding.top + padding.bottom + border.top + border.bottom;
1211         }
1212       else
1213         {
1214           relative_allocation.x = 0;
1215           relative_allocation.y = 0;
1216           relative_allocation.width = gtk_widget_get_allocated_width (widget);
1217           relative_allocation.height = gtk_widget_get_allocated_height (widget);
1218         }
1219
1220       gtk_render_frame (context, cr,
1221                         relative_allocation.x,
1222                         relative_allocation.y,
1223                         relative_allocation.width,
1224                         relative_allocation.height);
1225
1226       gtk_style_context_restore (context);
1227     }
1228
1229   GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->draw (widget, cr);
1230
1231   return FALSE;
1232 }
1233
1234 static void
1235 gtk_scrolled_window_forall (GtkContainer *container,
1236                             gboolean      include_internals,
1237                             GtkCallback   callback,
1238                             gpointer      callback_data)
1239 {
1240   GtkScrolledWindowPrivate *priv;
1241   GtkScrolledWindow *scrolled_window;
1242
1243   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
1244   g_return_if_fail (callback != NULL);
1245
1246   GTK_CONTAINER_CLASS (gtk_scrolled_window_parent_class)->forall (container,
1247                                               include_internals,
1248                                               callback,
1249                                               callback_data);
1250   if (include_internals)
1251     {
1252       scrolled_window = GTK_SCROLLED_WINDOW (container);
1253       priv = scrolled_window->priv;
1254
1255       if (priv->vscrollbar)
1256         callback (priv->vscrollbar, callback_data);
1257       if (priv->hscrollbar)
1258         callback (priv->hscrollbar, callback_data);
1259     }
1260 }
1261
1262 static gboolean
1263 gtk_scrolled_window_scroll_child (GtkScrolledWindow *scrolled_window,
1264                                   GtkScrollType      scroll,
1265                                   gboolean           horizontal)
1266 {
1267   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
1268   GtkAdjustment *adjustment = NULL;
1269   
1270   switch (scroll)
1271     {
1272     case GTK_SCROLL_STEP_UP:
1273       scroll = GTK_SCROLL_STEP_BACKWARD;
1274       horizontal = FALSE;
1275       break;
1276     case GTK_SCROLL_STEP_DOWN:
1277       scroll = GTK_SCROLL_STEP_FORWARD;
1278       horizontal = FALSE;
1279       break;
1280     case GTK_SCROLL_STEP_LEFT:
1281       scroll = GTK_SCROLL_STEP_BACKWARD;
1282       horizontal = TRUE;
1283       break;
1284     case GTK_SCROLL_STEP_RIGHT:
1285       scroll = GTK_SCROLL_STEP_FORWARD;
1286       horizontal = TRUE;
1287       break;
1288     case GTK_SCROLL_PAGE_UP:
1289       scroll = GTK_SCROLL_PAGE_BACKWARD;
1290       horizontal = FALSE;
1291       break;
1292     case GTK_SCROLL_PAGE_DOWN:
1293       scroll = GTK_SCROLL_PAGE_FORWARD;
1294       horizontal = FALSE;
1295       break;
1296     case GTK_SCROLL_PAGE_LEFT:
1297       scroll = GTK_SCROLL_STEP_BACKWARD;
1298       horizontal = TRUE;
1299       break;
1300     case GTK_SCROLL_PAGE_RIGHT:
1301       scroll = GTK_SCROLL_STEP_FORWARD;
1302       horizontal = TRUE;
1303       break;
1304     case GTK_SCROLL_STEP_BACKWARD:
1305     case GTK_SCROLL_STEP_FORWARD:
1306     case GTK_SCROLL_PAGE_BACKWARD:
1307     case GTK_SCROLL_PAGE_FORWARD:
1308     case GTK_SCROLL_START:
1309     case GTK_SCROLL_END:
1310       break;
1311     default:
1312       g_warning ("Invalid scroll type %u for GtkScrolledWindow::scroll-child", scroll);
1313       return FALSE;
1314     }
1315
1316   if ((horizontal && (!priv->hscrollbar || !priv->hscrollbar_visible)) ||
1317       (!horizontal && (!priv->vscrollbar || !priv->vscrollbar_visible)))
1318     return FALSE;
1319
1320   if (horizontal)
1321     {
1322       if (priv->hscrollbar)
1323         adjustment = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
1324     }
1325   else
1326     {
1327       if (priv->vscrollbar)
1328         adjustment = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar));
1329     }
1330
1331   if (adjustment)
1332     {
1333       gdouble value = adjustment->value;
1334       
1335       switch (scroll)
1336         {
1337         case GTK_SCROLL_STEP_FORWARD:
1338           value += adjustment->step_increment;
1339           break;
1340         case GTK_SCROLL_STEP_BACKWARD:
1341           value -= adjustment->step_increment;
1342           break;
1343         case GTK_SCROLL_PAGE_FORWARD:
1344           value += adjustment->page_increment;
1345           break;
1346         case GTK_SCROLL_PAGE_BACKWARD:
1347           value -= adjustment->page_increment;
1348           break;
1349         case GTK_SCROLL_START:
1350           value = adjustment->lower;
1351           break;
1352         case GTK_SCROLL_END:
1353           value = adjustment->upper;
1354           break;
1355         default:
1356           g_assert_not_reached ();
1357           break;
1358         }
1359
1360       gtk_adjustment_set_value (adjustment, value);
1361
1362       return TRUE;
1363     }
1364
1365   return FALSE;
1366 }
1367
1368 static void
1369 gtk_scrolled_window_move_focus_out (GtkScrolledWindow *scrolled_window,
1370                                     GtkDirectionType   direction_type)
1371 {
1372   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
1373   GtkWidget *toplevel;
1374   
1375   /* Focus out of the scrolled window entirely. We do this by setting
1376    * a flag, then propagating the focus motion to the notebook.
1377    */
1378   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (scrolled_window));
1379   if (!gtk_widget_is_toplevel (toplevel))
1380     return;
1381
1382   g_object_ref (scrolled_window);
1383
1384   priv->focus_out = TRUE;
1385   g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1386   priv->focus_out = FALSE;
1387
1388   g_object_unref (scrolled_window);
1389 }
1390
1391 static void
1392 gtk_scrolled_window_relative_allocation (GtkWidget     *widget,
1393                                          GtkAllocation *allocation)
1394 {
1395   GtkAllocation widget_allocation;
1396   GtkScrolledWindow *scrolled_window;
1397   GtkScrolledWindowPrivate *priv;
1398   gint sb_spacing;
1399   gint sb_width;
1400   gint sb_height;
1401
1402   g_return_if_fail (widget != NULL);
1403   g_return_if_fail (allocation != NULL);
1404
1405   scrolled_window = GTK_SCROLLED_WINDOW (widget);
1406   priv = scrolled_window->priv;
1407
1408   /* Get possible scrollbar dimensions */
1409   sb_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
1410   gtk_widget_get_preferred_height (priv->hscrollbar, &sb_height, NULL);
1411   gtk_widget_get_preferred_width (priv->vscrollbar, &sb_width, NULL);
1412
1413   /* Subtract some things from our available allocation size */
1414   allocation->x = 0;
1415   allocation->y = 0;
1416
1417   if (priv->shadow_type != GTK_SHADOW_NONE)
1418     {
1419       GtkStyleContext *context;
1420       GtkStateFlags state;
1421       GtkBorder padding, border;
1422
1423       context = gtk_widget_get_style_context (widget);
1424       state = gtk_widget_get_state_flags (widget);
1425
1426       gtk_style_context_save (context);
1427       gtk_style_context_add_class (context, GTK_STYLE_CLASS_FRAME);
1428
1429       gtk_style_context_get_border (context, state, &border);
1430       gtk_style_context_get_padding (context, state, &padding);
1431
1432       allocation->x += padding.left + border.left;
1433       allocation->y += padding.top + border.top;
1434
1435       gtk_style_context_restore (context);
1436     }
1437
1438   gtk_widget_get_allocation (widget, &widget_allocation);
1439   allocation->width = MAX (1, (gint) widget_allocation.width - allocation->x * 2);
1440   allocation->height = MAX (1, (gint) widget_allocation.height - allocation->y * 2);
1441
1442   if (priv->vscrollbar_visible)
1443     {
1444       gboolean is_rtl;
1445
1446       is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1447   
1448       if ((!is_rtl && 
1449            (priv->real_window_placement == GTK_CORNER_TOP_RIGHT ||
1450             priv->real_window_placement == GTK_CORNER_BOTTOM_RIGHT)) ||
1451           (is_rtl && 
1452            (priv->real_window_placement == GTK_CORNER_TOP_LEFT ||
1453             priv->real_window_placement == GTK_CORNER_BOTTOM_LEFT)))
1454         allocation->x += (sb_width +  sb_spacing);
1455
1456       allocation->width = MAX (1, allocation->width - (sb_width + sb_spacing));
1457     }
1458   if (priv->hscrollbar_visible)
1459     {
1460
1461       if (priv->real_window_placement == GTK_CORNER_BOTTOM_LEFT ||
1462           priv->real_window_placement == GTK_CORNER_BOTTOM_RIGHT)
1463         allocation->y += (sb_height + sb_spacing);
1464
1465       allocation->height = MAX (1, allocation->height - (sb_height + sb_spacing));
1466     }
1467 }
1468
1469 static void
1470 gtk_scrolled_window_allocate_child (GtkScrolledWindow *swindow,
1471                                     GtkAllocation     *relative_allocation)
1472 {
1473   GtkWidget     *widget = GTK_WIDGET (swindow), *child;
1474   GtkAllocation  allocation;
1475   GtkAllocation  child_allocation;
1476
1477   child = gtk_bin_get_child (GTK_BIN (widget));
1478
1479   gtk_widget_get_allocation (widget, &allocation);
1480
1481   gtk_scrolled_window_relative_allocation (widget, relative_allocation);
1482   child_allocation.x = relative_allocation->x + allocation.x;
1483   child_allocation.y = relative_allocation->y + allocation.y;
1484   child_allocation.width = relative_allocation->width;
1485   child_allocation.height = relative_allocation->height;
1486
1487   gtk_widget_size_allocate (child, &child_allocation);
1488 }
1489
1490 static void
1491 gtk_scrolled_window_size_allocate (GtkWidget     *widget,
1492                                    GtkAllocation *allocation)
1493 {
1494   GtkScrolledWindow *scrolled_window;
1495   GtkScrolledWindowPrivate *priv;
1496   GtkStyleContext *context;
1497   GtkStateFlags state;
1498   GtkBorder padding, border;
1499   GtkBin *bin;
1500   GtkAllocation relative_allocation;
1501   GtkAllocation child_allocation;
1502   GtkWidget *child;
1503   gboolean scrollbars_within_bevel;
1504   gint sb_spacing;
1505   gint sb_width;
1506   gint sb_height;
1507  
1508   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
1509   g_return_if_fail (allocation != NULL);
1510
1511   scrolled_window = GTK_SCROLLED_WINDOW (widget);
1512   bin = GTK_BIN (scrolled_window);
1513   priv = scrolled_window->priv;
1514
1515   /* Get possible scrollbar dimensions */
1516   sb_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
1517   gtk_widget_get_preferred_height (priv->hscrollbar, &sb_height, NULL);
1518   gtk_widget_get_preferred_width (priv->vscrollbar, &sb_width, NULL);
1519
1520   context = gtk_widget_get_style_context (widget);
1521   state = gtk_widget_get_state_flags (widget);
1522
1523   gtk_style_context_save (context);
1524   gtk_style_context_add_class (context, GTK_STYLE_CLASS_FRAME);
1525
1526   gtk_style_context_get_padding (context, state, &padding);
1527   gtk_style_context_get_border (context, state, &border);
1528
1529   gtk_widget_style_get (widget, "scrollbars-within-bevel", &scrollbars_within_bevel, NULL);
1530
1531   gtk_widget_set_allocation (widget, allocation);
1532
1533   gtk_style_context_restore (context);
1534
1535   if (priv->hscrollbar_policy == GTK_POLICY_ALWAYS)
1536     priv->hscrollbar_visible = TRUE;
1537   else if (priv->hscrollbar_policy == GTK_POLICY_NEVER)
1538     priv->hscrollbar_visible = FALSE;
1539   if (priv->vscrollbar_policy == GTK_POLICY_ALWAYS)
1540     priv->vscrollbar_visible = TRUE;
1541   else if (priv->vscrollbar_policy == GTK_POLICY_NEVER)
1542     priv->vscrollbar_visible = FALSE;
1543
1544   child = gtk_bin_get_child (bin);
1545   if (child && gtk_widget_get_visible (child))
1546     {
1547       gint child_scroll_width;
1548       gint child_scroll_height;
1549       gboolean previous_hvis;
1550       gboolean previous_vvis;
1551       guint count = 0;
1552
1553       /* Determine scrollbar visibility first via hfw apis */
1554       if (gtk_widget_get_request_mode (child) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
1555         {
1556           if (gtk_scrollable_get_hscroll_policy (GTK_SCROLLABLE (child)) == GTK_SCROLL_MINIMUM)
1557             gtk_widget_get_preferred_width (child, &child_scroll_width, NULL);
1558           else
1559             gtk_widget_get_preferred_width (child, NULL, &child_scroll_width);
1560           
1561           if (priv->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
1562             {
1563               /* First try without a vertical scrollbar if the content will fit the height
1564                * given the extra width of the scrollbar */
1565               if (gtk_scrollable_get_vscroll_policy (GTK_SCROLLABLE (child)) == GTK_SCROLL_MINIMUM)
1566                 gtk_widget_get_preferred_height_for_width (child, 
1567                                                            MAX (allocation->width, child_scroll_width), 
1568                                                            &child_scroll_height, NULL);
1569               else
1570                 gtk_widget_get_preferred_height_for_width (child,
1571                                                            MAX (allocation->width, child_scroll_width), 
1572                                                            NULL, &child_scroll_height);
1573               
1574               if (priv->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
1575                 {
1576                   /* Does the content height fit the allocation height ? */
1577                   priv->vscrollbar_visible = child_scroll_height > allocation->height;
1578                   
1579                   /* Does the content width fit the allocation with minus a possible scrollbar ? */
1580                   priv->hscrollbar_visible = 
1581                     child_scroll_width > allocation->width - 
1582                     (priv->vscrollbar_visible ? sb_width + sb_spacing : 0);
1583                   
1584                   /* Now that we've guessed the hscrollbar, does the content height fit
1585                    * the possible new allocation height ? */
1586                   priv->vscrollbar_visible = 
1587                     child_scroll_height > allocation->height - 
1588                     (priv->hscrollbar_visible ? sb_height + sb_spacing : 0);
1589                   
1590                   /* Now that we've guessed the vscrollbar, does the content width fit
1591                    * the possible new allocation width ? */
1592                   priv->hscrollbar_visible = 
1593                     child_scroll_width > allocation->width - 
1594                     (priv->vscrollbar_visible ? sb_width + sb_spacing : 0);
1595                 }
1596               else /* priv->hscrollbar_policy != GTK_POLICY_AUTOMATIC */
1597                 {
1598                   priv->hscrollbar_visible = priv->hscrollbar_policy != GTK_POLICY_NEVER;
1599                   priv->vscrollbar_visible = child_scroll_height > allocation->height - 
1600                     (priv->hscrollbar_visible ? sb_height + sb_spacing : 0);
1601                 }
1602             }
1603           else /* priv->vscrollbar_policy != GTK_POLICY_AUTOMATIC */
1604             {
1605               priv->vscrollbar_visible = priv->vscrollbar_policy != GTK_POLICY_NEVER;
1606               
1607               if (priv->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
1608                 priv->hscrollbar_visible = 
1609                   child_scroll_width > allocation->width - 
1610                   (priv->vscrollbar_visible ? 0 : sb_width + sb_spacing);
1611               else
1612                 priv->hscrollbar_visible = priv->hscrollbar_policy != GTK_POLICY_NEVER;
1613             }
1614         } 
1615       else /* GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT */
1616         {
1617           if (gtk_scrollable_get_vscroll_policy (GTK_SCROLLABLE (child)) == GTK_SCROLL_MINIMUM)
1618             gtk_widget_get_preferred_height (child, &child_scroll_height, NULL);
1619           else
1620             gtk_widget_get_preferred_height (child, NULL, &child_scroll_height);
1621           
1622           if (priv->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
1623             {
1624               /* First try without a horizontal scrollbar if the content will fit the width
1625                * given the extra height of the scrollbar */
1626               if (gtk_scrollable_get_hscroll_policy (GTK_SCROLLABLE (child)) == GTK_SCROLL_MINIMUM)
1627                 gtk_widget_get_preferred_width_for_height (child, 
1628                                                            MAX (allocation->height, child_scroll_height), 
1629                                                            &child_scroll_width, NULL);
1630               else
1631                 gtk_widget_get_preferred_width_for_height (child, 
1632                                                            MAX (allocation->height, child_scroll_height), 
1633                                                            NULL, &child_scroll_width);
1634               
1635               if (priv->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
1636                 {
1637                   /* Does the content width fit the allocation width ? */
1638                   priv->hscrollbar_visible = child_scroll_width > allocation->width;
1639                   
1640                   /* Does the content height fit the allocation with minus a possible scrollbar ? */
1641                   priv->vscrollbar_visible = 
1642                     child_scroll_height > allocation->height - 
1643                     (priv->hscrollbar_visible ? sb_height + sb_spacing : 0);
1644                   
1645                   /* Now that we've guessed the vscrollbar, does the content width fit
1646                    * the possible new allocation width ? */
1647                   priv->hscrollbar_visible = 
1648                     child_scroll_width > allocation->width - 
1649                     (priv->vscrollbar_visible ? sb_width + sb_spacing : 0);
1650                   
1651                   /* Now that we've guessed the hscrollbar, does the content height fit
1652                    * the possible new allocation height ? */
1653                   priv->vscrollbar_visible = 
1654                     child_scroll_height > allocation->height - 
1655                     (priv->hscrollbar_visible ? sb_height + sb_spacing : 0);
1656                 }
1657               else /* priv->vscrollbar_policy != GTK_POLICY_AUTOMATIC */
1658                 {
1659                   priv->vscrollbar_visible = priv->vscrollbar_policy != GTK_POLICY_NEVER;
1660                   priv->hscrollbar_visible = child_scroll_width > allocation->width - 
1661                     (priv->vscrollbar_visible ? sb_width + sb_spacing : 0);
1662                 }
1663             }
1664           else /* priv->hscrollbar_policy != GTK_POLICY_AUTOMATIC */
1665             {
1666               priv->hscrollbar_visible = priv->hscrollbar_policy != GTK_POLICY_NEVER;
1667               
1668               if (priv->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
1669                 priv->vscrollbar_visible = 
1670                   child_scroll_height > allocation->height - 
1671                   (priv->hscrollbar_visible ? 0 : sb_height + sb_spacing);
1672               else
1673                 priv->vscrollbar_visible = priv->vscrollbar_policy != GTK_POLICY_NEVER;
1674             }
1675         }
1676
1677       /* Now after guessing scrollbar visibility; fall back on the allocation loop which 
1678        * observes the adjustments to detect scrollbar visibility and also avoids 
1679        * infinite recursion
1680        */
1681       do
1682         {
1683           previous_hvis = priv->hscrollbar_visible;
1684           previous_vvis = priv->vscrollbar_visible;
1685           gtk_scrolled_window_allocate_child (scrolled_window, &relative_allocation);
1686
1687           /* Explicitly force scrollbar visibility checks.
1688            *
1689            * Since we make a guess above, the child might not decide to update the adjustments 
1690            * if they logically did not change since the last configuration
1691            */
1692           if (priv->hscrollbar)
1693             gtk_scrolled_window_adjustment_changed 
1694               (gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar)), scrolled_window);
1695
1696           if (priv->vscrollbar)
1697             gtk_scrolled_window_adjustment_changed 
1698               (gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)), scrolled_window);
1699
1700           /* If, after the first iteration, the hscrollbar and the
1701            * vscrollbar flip visiblity... or if one of the scrollbars flip
1702            * on each itteration indefinitly/infinitely, then we just need both 
1703            * at this size.
1704            */
1705           if ((count &&
1706                previous_hvis != priv->hscrollbar_visible &&
1707                previous_vvis != priv->vscrollbar_visible) || count > 3)
1708             {
1709               priv->hscrollbar_visible = TRUE;
1710               priv->vscrollbar_visible = TRUE;
1711
1712               gtk_scrolled_window_allocate_child (scrolled_window, &relative_allocation);
1713
1714               break;
1715             }
1716           
1717           count++;
1718         }
1719       while (previous_hvis != priv->hscrollbar_visible ||
1720              previous_vvis != priv->vscrollbar_visible);
1721     }
1722   else
1723     {
1724       priv->hscrollbar_visible = priv->hscrollbar_policy == GTK_POLICY_ALWAYS;
1725       priv->vscrollbar_visible = priv->vscrollbar_policy == GTK_POLICY_ALWAYS;
1726       gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
1727     }
1728
1729   if (priv->hscrollbar_visible)
1730     {
1731       if (!gtk_widget_get_visible (priv->hscrollbar))
1732         gtk_widget_show (priv->hscrollbar);
1733
1734       child_allocation.x = relative_allocation.x;
1735       if (priv->real_window_placement == GTK_CORNER_TOP_LEFT ||
1736           priv->real_window_placement == GTK_CORNER_TOP_RIGHT)
1737         child_allocation.y = (relative_allocation.y +
1738                               relative_allocation.height +
1739                               sb_spacing +
1740                               (priv->shadow_type == GTK_SHADOW_NONE ?
1741                                0 : padding.top + border.top));
1742       else
1743         child_allocation.y = 0;
1744
1745       child_allocation.width = relative_allocation.width;
1746       child_allocation.height = sb_height;
1747       child_allocation.x += allocation->x;
1748       child_allocation.y += allocation->y;
1749
1750       if (priv->shadow_type != GTK_SHADOW_NONE)
1751         {
1752           if (!scrollbars_within_bevel)
1753             {
1754               child_allocation.x -= padding.left + border.left;
1755               child_allocation.width += padding.left + padding.right + border.left + border.right;
1756             }
1757           else if (GTK_CORNER_TOP_RIGHT == priv->real_window_placement ||
1758                    GTK_CORNER_TOP_LEFT == priv->real_window_placement)
1759             {
1760               child_allocation.y -= padding.top + border.top;
1761             }
1762           else
1763             {
1764               child_allocation.y += padding.top + border.top;
1765             }
1766         }
1767
1768       gtk_widget_size_allocate (priv->hscrollbar, &child_allocation);
1769     }
1770   else if (gtk_widget_get_visible (priv->hscrollbar))
1771     gtk_widget_hide (priv->hscrollbar);
1772
1773   if (priv->vscrollbar_visible)
1774     {
1775       if (!gtk_widget_get_visible (priv->vscrollbar))
1776         gtk_widget_show (priv->vscrollbar);
1777
1778       if ((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL && 
1779            (priv->real_window_placement == GTK_CORNER_TOP_RIGHT ||
1780             priv->real_window_placement == GTK_CORNER_BOTTOM_RIGHT)) ||
1781           (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR && 
1782            (priv->real_window_placement == GTK_CORNER_TOP_LEFT ||
1783             priv->real_window_placement == GTK_CORNER_BOTTOM_LEFT)))
1784         child_allocation.x = (relative_allocation.x +
1785                               relative_allocation.width +
1786                               sb_spacing +
1787                               (priv->shadow_type == GTK_SHADOW_NONE ?
1788                                0 : padding.left + border.left));
1789       else
1790         child_allocation.x = 0;
1791
1792       child_allocation.y = relative_allocation.y;
1793       child_allocation.width = sb_width;
1794       child_allocation.height = relative_allocation.height;
1795       child_allocation.x += allocation->x;
1796       child_allocation.y += allocation->y;
1797
1798       if (priv->shadow_type != GTK_SHADOW_NONE)
1799         {
1800           if (!scrollbars_within_bevel)
1801             {
1802               child_allocation.y -= padding.top + border.top;
1803               child_allocation.height += padding.top + padding.bottom + border.top + border.bottom;
1804             }
1805           else if (GTK_CORNER_BOTTOM_LEFT == priv->real_window_placement ||
1806                    GTK_CORNER_TOP_LEFT == priv->real_window_placement)
1807             {
1808               child_allocation.x -= padding.left + border.left;
1809             }
1810           else
1811             {
1812               child_allocation.x += padding.left + border.left;
1813             }
1814         }
1815
1816       gtk_widget_size_allocate (priv->vscrollbar, &child_allocation);
1817     }
1818   else if (gtk_widget_get_visible (priv->vscrollbar))
1819     gtk_widget_hide (priv->vscrollbar);
1820 }
1821
1822 static gboolean
1823 gtk_scrolled_window_scroll_event (GtkWidget      *widget,
1824                                   GdkEventScroll *event)
1825 {
1826   GtkScrolledWindowPrivate *priv;
1827   GtkScrolledWindow *scrolled_window;
1828   GtkWidget *range;
1829
1830   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (widget), FALSE);
1831   g_return_val_if_fail (event != NULL, FALSE);  
1832
1833   scrolled_window = GTK_SCROLLED_WINDOW (widget);
1834   priv = scrolled_window->priv;
1835
1836   if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_DOWN)
1837     range = priv->vscrollbar;
1838   else
1839     range = priv->hscrollbar;
1840
1841   if (range && gtk_widget_get_visible (range))
1842     {
1843       GtkAdjustment *adj = gtk_range_get_adjustment (GTK_RANGE (range));
1844       gdouble delta;
1845
1846       delta = _gtk_range_get_wheel_delta (GTK_RANGE (range), event->direction);
1847
1848       gtk_adjustment_set_value (adj, adj->value + delta);
1849
1850       return TRUE;
1851     }
1852
1853   return FALSE;
1854 }
1855
1856 static gboolean
1857 gtk_scrolled_window_focus (GtkWidget        *widget,
1858                            GtkDirectionType  direction)
1859 {
1860   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
1861   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
1862   GtkWidget *child;
1863   gboolean had_focus_child;
1864
1865   had_focus_child = gtk_container_get_focus_child (GTK_CONTAINER (widget)) != NULL;
1866
1867   if (priv->focus_out)
1868     {
1869       priv->focus_out = FALSE; /* Clear this to catch the wrap-around case */
1870       return FALSE;
1871     }
1872   
1873   if (gtk_widget_is_focus (widget))
1874     return FALSE;
1875
1876   /* We only put the scrolled window itself in the focus chain if it
1877    * isn't possible to focus any children.
1878    */
1879   child = gtk_bin_get_child (GTK_BIN (widget));
1880   if (child)
1881     {
1882       if (gtk_widget_child_focus (child, direction))
1883         return TRUE;
1884     }
1885
1886   if (!had_focus_child && gtk_widget_get_can_focus (widget))
1887     {
1888       gtk_widget_grab_focus (widget);
1889       return TRUE;
1890     }
1891   else
1892     return FALSE;
1893 }
1894
1895 static void
1896 gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment,
1897                                         gpointer       data)
1898 {
1899   GtkScrolledWindowPrivate *priv;
1900   GtkScrolledWindow *scrolled_window;
1901
1902   g_return_if_fail (adjustment != NULL);
1903   g_return_if_fail (data != NULL);
1904
1905   scrolled_window = GTK_SCROLLED_WINDOW (data);
1906   priv = scrolled_window->priv;
1907
1908   if (priv->hscrollbar &&
1909       adjustment == gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar)))
1910     {
1911       if (priv->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
1912         {
1913           gboolean visible;
1914
1915           visible = priv->hscrollbar_visible;
1916           priv->hscrollbar_visible = (adjustment->upper - adjustment->lower >
1917                                               adjustment->page_size);
1918
1919           if (priv->hscrollbar_visible != visible)
1920             gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
1921         }
1922     }
1923   else if (priv->vscrollbar &&
1924            adjustment == gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)))
1925     {
1926       if (priv->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
1927         {
1928           gboolean visible;
1929
1930           visible = priv->vscrollbar_visible;
1931           priv->vscrollbar_visible = (adjustment->upper - adjustment->lower >
1932                                               adjustment->page_size);
1933
1934           if (priv->vscrollbar_visible != visible)
1935             gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
1936         }
1937     }
1938 }
1939
1940 static void
1941 gtk_scrolled_window_add (GtkContainer *container,
1942                          GtkWidget    *child)
1943 {
1944   GtkScrolledWindowPrivate *priv;
1945   GtkScrolledWindow *scrolled_window;
1946   GtkBin *bin;
1947   GtkWidget *child_widget;
1948   GtkAdjustment *hadj, *vadj;
1949
1950   bin = GTK_BIN (container);
1951   child_widget = gtk_bin_get_child (bin);
1952   g_return_if_fail (child_widget == NULL);
1953
1954   scrolled_window = GTK_SCROLLED_WINDOW (container);
1955   priv = scrolled_window->priv;
1956
1957   _gtk_bin_set_child (bin, child);
1958   gtk_widget_set_parent (child, GTK_WIDGET (bin));
1959
1960   hadj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->priv->hscrollbar));
1961   vadj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->priv->vscrollbar));
1962
1963   if (GTK_IS_SCROLLABLE (child))
1964     g_object_set (child, "hadjustment", hadj, "vadjustment", vadj, NULL);
1965   else
1966     g_warning ("gtk_scrolled_window_add(): cannot add non scrollable widget "
1967                "use gtk_scrolled_window_add_with_viewport() instead");
1968 }
1969
1970 static void
1971 gtk_scrolled_window_remove (GtkContainer *container,
1972                             GtkWidget    *child)
1973 {
1974   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
1975   g_return_if_fail (child != NULL);
1976   g_return_if_fail (gtk_bin_get_child (GTK_BIN (container)) == child);
1977
1978   g_object_set (child, "hadjustment", NULL, "vadjustment", NULL, NULL);
1979
1980   /* chain parent class handler to remove child */
1981   GTK_CONTAINER_CLASS (gtk_scrolled_window_parent_class)->remove (container, child);
1982 }
1983
1984 /**
1985  * gtk_scrolled_window_add_with_viewport:
1986  * @scrolled_window: a #GtkScrolledWindow
1987  * @child: the widget you want to scroll
1988  *
1989  * Used to add children without native scrolling capabilities. This
1990  * is simply a convenience function; it is equivalent to adding the
1991  * unscrollable child to a viewport, then adding the viewport to the
1992  * scrolled window. If a child has native scrolling, use
1993  * gtk_container_add() instead of this function.
1994  *
1995  * The viewport scrolls the child by moving its #GdkWindow, and takes
1996  * the size of the child to be the size of its toplevel #GdkWindow. 
1997  * This will be very wrong for most widgets that support native scrolling;
1998  * for example, if you add a widget such as #GtkTreeView with a viewport,
1999  * the whole widget will scroll, including the column headings. Thus, 
2000  * widgets with native scrolling support should not be used with the 
2001  * #GtkViewport proxy.
2002  *
2003  * A widget supports scrolling natively if it implements the
2004  * #GtkScrollable interface.
2005  */
2006 void
2007 gtk_scrolled_window_add_with_viewport (GtkScrolledWindow *scrolled_window,
2008                                        GtkWidget         *child)
2009 {
2010   GtkBin *bin;
2011   GtkWidget *viewport;
2012   GtkWidget *child_widget;
2013
2014   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
2015   g_return_if_fail (GTK_IS_WIDGET (child));
2016   g_return_if_fail (gtk_widget_get_parent (child) == NULL);
2017
2018   bin = GTK_BIN (scrolled_window);
2019   child_widget = gtk_bin_get_child (bin);
2020
2021   if (child_widget)
2022     {
2023       g_return_if_fail (GTK_IS_VIEWPORT (child_widget));
2024       g_return_if_fail (gtk_bin_get_child (GTK_BIN (child_widget)) == NULL);
2025
2026       viewport = child_widget;
2027     }
2028   else
2029     {
2030       viewport =
2031         gtk_viewport_new (gtk_scrolled_window_get_hadjustment (scrolled_window),
2032                           gtk_scrolled_window_get_vadjustment (scrolled_window));
2033       gtk_container_add (GTK_CONTAINER (scrolled_window), viewport);
2034     }
2035
2036   gtk_widget_show (viewport);
2037   gtk_container_add (GTK_CONTAINER (viewport), child);
2038 }
2039
2040 /*
2041  * _gtk_scrolled_window_get_spacing:
2042  * @scrolled_window: a scrolled window
2043  * 
2044  * Gets the spacing between the scrolled window's scrollbars and
2045  * the scrolled widget. Used by GtkCombo
2046  * 
2047  * Return value: the spacing, in pixels.
2048  */
2049 gint
2050 _gtk_scrolled_window_get_scrollbar_spacing (GtkScrolledWindow *scrolled_window)
2051 {
2052   GtkScrolledWindowClass *class;
2053     
2054   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), 0);
2055
2056   class = GTK_SCROLLED_WINDOW_GET_CLASS (scrolled_window);
2057
2058   if (class->scrollbar_spacing >= 0)
2059     return class->scrollbar_spacing;
2060   else
2061     {
2062       gint scrollbar_spacing;
2063       
2064       gtk_widget_style_get (GTK_WIDGET (scrolled_window),
2065                             "scrollbar-spacing", &scrollbar_spacing,
2066                             NULL);
2067
2068       return scrollbar_spacing;
2069     }
2070 }
2071
2072
2073 static void
2074 gtk_scrolled_window_get_preferred_size (GtkWidget      *widget,
2075                                         GtkOrientation  orientation,
2076                                         gint           *minimum_size,
2077                                         gint           *natural_size)
2078 {
2079   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
2080   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
2081   GtkBin *bin = GTK_BIN (scrolled_window);
2082   gint extra_width;
2083   gint extra_height;
2084   gint scrollbar_spacing;
2085   GtkRequisition hscrollbar_requisition;
2086   GtkRequisition vscrollbar_requisition;
2087   GtkRequisition minimum_req, natural_req;
2088   GtkWidget *child;
2089   gint min_child_size, nat_child_size;
2090
2091   scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
2092
2093   extra_width = 0;
2094   extra_height = 0;
2095   minimum_req.width = 0;
2096   minimum_req.height = 0;
2097   natural_req.width = 0;
2098   natural_req.height = 0;
2099
2100   gtk_widget_get_preferred_size (priv->hscrollbar,
2101                                  &hscrollbar_requisition, NULL);
2102   gtk_widget_get_preferred_size (priv->vscrollbar,
2103                                  &vscrollbar_requisition, NULL);
2104
2105   child = gtk_bin_get_child (bin);
2106   if (child && gtk_widget_get_visible (child))
2107     {
2108       if (orientation == GTK_ORIENTATION_HORIZONTAL)
2109         {
2110           gtk_widget_get_preferred_width (child,
2111                                           &min_child_size,
2112                                           &nat_child_size);
2113
2114           if (priv->hscrollbar_policy == GTK_POLICY_NEVER)
2115             {
2116               minimum_req.width += min_child_size;
2117               natural_req.width += nat_child_size;
2118             }
2119           else
2120             {
2121               gint min_content_width = priv->min_content_width;
2122
2123               if (min_content_width >= 0)
2124                 {
2125                   minimum_req.width = MAX (minimum_req.width, min_content_width);
2126                   natural_req.width = MAX (natural_req.width, min_content_width);
2127                   extra_width = -1;
2128                 }
2129               else
2130                 {
2131                   minimum_req.width += vscrollbar_requisition.width;
2132                   natural_req.width += vscrollbar_requisition.width;
2133                 }
2134             }
2135         }
2136       else /* GTK_ORIENTATION_VERTICAL */
2137         {
2138           gtk_widget_get_preferred_height (child,
2139                                            &min_child_size,
2140                                            &nat_child_size);
2141
2142           if (priv->vscrollbar_policy == GTK_POLICY_NEVER)
2143             {
2144               minimum_req.height += min_child_size;
2145               natural_req.height += nat_child_size;
2146             }
2147           else
2148             {
2149               gint min_content_height = priv->min_content_height;
2150
2151               if (min_content_height >= 0)
2152                 {
2153                   minimum_req.height = MAX (minimum_req.height, min_content_height);
2154                   natural_req.height = MAX (natural_req.height, min_content_height);
2155                   extra_height = -1;
2156                 }
2157               else
2158                 {
2159                   minimum_req.height += vscrollbar_requisition.height;
2160                   natural_req.height += vscrollbar_requisition.height;
2161                 }
2162             }
2163         }
2164     }
2165
2166   if (priv->hscrollbar_policy == GTK_POLICY_AUTOMATIC ||
2167       priv->hscrollbar_policy == GTK_POLICY_ALWAYS)
2168     {
2169       minimum_req.width = MAX (minimum_req.width, hscrollbar_requisition.width);
2170       natural_req.width = MAX (natural_req.width, hscrollbar_requisition.width);
2171       if (!extra_height || priv->hscrollbar_policy == GTK_POLICY_ALWAYS)
2172         extra_height = scrollbar_spacing + hscrollbar_requisition.height;
2173     }
2174
2175   if (priv->vscrollbar_policy == GTK_POLICY_AUTOMATIC ||
2176       priv->vscrollbar_policy == GTK_POLICY_ALWAYS)
2177     {
2178       minimum_req.height = MAX (minimum_req.height, vscrollbar_requisition.height);
2179       natural_req.height = MAX (natural_req.height, vscrollbar_requisition.height);
2180       if (!extra_width || priv->vscrollbar_policy == GTK_POLICY_ALWAYS)
2181         extra_width = scrollbar_spacing + vscrollbar_requisition.width;
2182     }
2183
2184   minimum_req.width  += MAX (0, extra_width);
2185   minimum_req.height += MAX (0, extra_height);
2186   natural_req.width  += MAX (0, extra_width);
2187   natural_req.height += MAX (0, extra_height);
2188
2189   if (priv->shadow_type != GTK_SHADOW_NONE)
2190     {
2191       GtkStyleContext *context;
2192       GtkStateFlags state;
2193       GtkBorder padding, border;
2194
2195       context = gtk_widget_get_style_context (GTK_WIDGET (widget));
2196       state = gtk_widget_get_state_flags (GTK_WIDGET (widget));
2197
2198       gtk_style_context_save (context);
2199       gtk_style_context_add_class (context, GTK_STYLE_CLASS_FRAME);
2200
2201       gtk_style_context_get_padding (context, state, &padding);
2202       gtk_style_context_get_border (context, state, &border);
2203
2204       minimum_req.width += padding.left + padding.right + border.left + border.right;
2205       minimum_req.height += padding.top + padding.bottom + border.top + border.bottom;
2206       natural_req.width += padding.left + padding.right + border.left + border.right;
2207       natural_req.height += padding.top + padding.bottom + border.top + border.bottom;
2208
2209       gtk_style_context_restore (context);
2210     }
2211
2212   if (orientation == GTK_ORIENTATION_HORIZONTAL)
2213     {
2214       if (minimum_size)
2215         *minimum_size = minimum_req.width;
2216       if (natural_size)
2217         *natural_size = natural_req.width;
2218     }
2219   else
2220     {
2221       if (minimum_size)
2222         *minimum_size = minimum_req.height;
2223       if (natural_size)
2224         *natural_size = natural_req.height;
2225     }
2226 }
2227
2228 static void     
2229 gtk_scrolled_window_get_preferred_width (GtkWidget *widget,
2230                                          gint      *minimum_size,
2231                                          gint      *natural_size)
2232 {
2233   gtk_scrolled_window_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size);
2234 }
2235
2236 static void
2237 gtk_scrolled_window_get_preferred_height (GtkWidget *widget,
2238                                           gint      *minimum_size,
2239                                           gint      *natural_size)
2240 {  
2241   gtk_scrolled_window_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size);
2242 }
2243
2244 static void
2245 gtk_scrolled_window_get_preferred_height_for_width (GtkWidget *widget,
2246                                                     gint       width,
2247                                                     gint      *minimum_height,
2248                                                     gint      *natural_height)
2249 {
2250   g_return_if_fail (GTK_IS_WIDGET (widget));
2251
2252   GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, minimum_height, natural_height);
2253 }
2254
2255 static void
2256 gtk_scrolled_window_get_preferred_width_for_height (GtkWidget *widget,
2257                                                     gint       height,
2258                                                     gint      *minimum_width,
2259                                                     gint      *natural_width)
2260 {
2261   g_return_if_fail (GTK_IS_WIDGET (widget));
2262
2263   GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, minimum_width, natural_width);
2264 }
2265
2266 /**
2267  * gtk_scrolled_window_get_min_content_width:
2268  * @scrolled_window: a #GtkScrolledWindow
2269  *
2270  * Gets the minimum content width of @scrolled_window, or -1 if not set.
2271  *
2272  * Returns: the minimum content width
2273  *
2274  * Since: 3.0
2275  */
2276 gint
2277 gtk_scrolled_window_get_min_content_width (GtkScrolledWindow *scrolled_window)
2278 {
2279   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), 0);
2280
2281   return scrolled_window->priv->min_content_width;
2282 }
2283
2284 /**
2285  * gtk_scrolled_window_set_min_content_width:
2286  * @scrolled_window: a #GtkScrolledWindow
2287  * @width: the minimal content width
2288  *
2289  * Sets the minimum width that @scrolled_window should keep visible.
2290  * Note that this can and (usually will) be smaller than the minimum
2291  * size of the content.
2292  *
2293  * Since: 3.0
2294  */
2295 void
2296 gtk_scrolled_window_set_min_content_width (GtkScrolledWindow *scrolled_window,
2297                                            gint               width)
2298 {
2299   GtkScrolledWindowPrivate *priv;
2300
2301   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
2302
2303   priv = scrolled_window->priv;
2304
2305   if (priv->min_content_width != width)
2306     {
2307       priv->min_content_width = width;
2308
2309       gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
2310
2311       g_object_notify (G_OBJECT (scrolled_window), "min-content-width");
2312     }
2313 }
2314
2315 /**
2316  * gtk_scrolled_window_get_min_content_height:
2317  * @scrolled_window: a #GtkScrolledWindow
2318  *
2319  * Gets the minimal content height of @scrolled_window, or -1 if not set.
2320  *
2321  * Returns: the minimal content height
2322  *
2323  * Since: 3.0
2324  */
2325 gint
2326 gtk_scrolled_window_get_min_content_height (GtkScrolledWindow *scrolled_window)
2327 {
2328   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), 0);
2329
2330   return scrolled_window->priv->min_content_height;
2331 }
2332
2333 /**
2334  * gtk_scrolled_window_set_min_content_height:
2335  * @scrolled_window: a #GtkScrolledWindow
2336  * @height: the minimal content height
2337  *
2338  * Sets the minimum height that @scrolled_window should keep visible.
2339  * Note that this can and (usually will) be smaller than the minimum
2340  * size of the content.
2341  *
2342  * Since: 3.0
2343  */
2344 void
2345 gtk_scrolled_window_set_min_content_height (GtkScrolledWindow *scrolled_window,
2346                                             gint               height)
2347 {
2348   GtkScrolledWindowPrivate *priv;
2349
2350   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
2351
2352   priv = scrolled_window->priv;
2353
2354   if (priv->min_content_height != height)
2355     {
2356       priv->min_content_height = height;
2357
2358       gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
2359
2360       g_object_notify (G_OBJECT (scrolled_window), "min-content-height");
2361     }
2362 }