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