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