]> Pileus Git - ~andy/gtk/blob - gtk/gtkscrolledwindow.c
Move single-include guards inside include guards
[~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, see <http://www.gnu.org/licenses/>.
16  */
17
18 /*
19  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
20  * file for a list of people on the GTK+ Team.  See the ChangeLog
21  * files for a list of changes.  These files are distributed with
22  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
23  */
24
25 #include "config.h"
26
27 #include "gtkscrolledwindow.h"
28
29 #include "gtkadjustment.h"
30 #include "gtkbindings.h"
31 #include "gtkdnd.h"
32 #include "gtkintl.h"
33 #include "gtkmain.h"
34 #include "gtkmarshalers.h"
35 #include "gtkprivate.h"
36 #include "gtkscrollable.h"
37 #include "gtkscrollbar.h"
38 #include "gtktypebuiltins.h"
39 #include "gtkviewport.h"
40 #include "gtkwidgetprivate.h"
41 #include "gtkwindow.h"
42 #include "a11y/gtkscrolledwindowaccessible.h"
43
44 #include <math.h>
45
46 /**
47  * SECTION:gtkscrolledwindow
48  * @Short_description: Adds scrollbars to its child widget
49  * @Title: GtkScrolledWindow
50  * @See_also: #GtkScrollable, #GtkViewport, #GtkAdjustment
51  *
52  * #GtkScrolledWindow is a #GtkBin subclass: it's a container
53  * the accepts a single child widget. #GtkScrolledWindow adds scrollbars
54  * to the child widget and optionally draws a beveled frame around the
55  * child widget.
56  *
57  * The scrolled window can work in two ways. Some widgets have native
58  * scrolling support; these widgets implement the #GtkScrollable interface.
59  * Widgets with native scroll support include #GtkTreeView, #GtkTextView,
60  * and #GtkLayout.
61  *
62  * For widgets that lack native scrolling support, the #GtkViewport
63  * widget acts as an adaptor class, implementing scrollability for child
64  * widgets that lack their own scrolling capabilities. Use #GtkViewport
65  * to scroll child widgets such as #GtkGrid, #GtkBox, and so on.
66  *
67  * If a widget has native scrolling abilities, it can be added to the
68  * #GtkScrolledWindow with gtk_container_add(). If a widget does not, you
69  * must first add the widget to a #GtkViewport, then add the #GtkViewport
70  * to the scrolled window. The convenience function
71  * gtk_scrolled_window_add_with_viewport() does exactly this, so you can
72  * ignore the presence of the viewport.
73  *
74  * The position of the scrollbars is controlled by the scroll
75  * adjustments. See #GtkAdjustment for the fields in an adjustment - for
76  * #GtkScrollbar, used by #GtkScrolledWindow, the "value" field
77  * represents the position of the scrollbar, which must be between the
78  * "lower" field and "upper - page_size." The "page_size" field
79  * represents the size of the visible scrollable area. The
80  * "step_increment" and "page_increment" fields are used when the user
81  * asks to step down (using the small stepper arrows) or page down (using
82  * for example the PageDown key).
83  *
84  * If a #GtkScrolledWindow doesn't behave quite as you would like, or
85  * doesn't have exactly the right layout, it's very possible to set up
86  * your own scrolling with #GtkScrollbar and for example a #GtkGrid.
87  */
88
89
90 /* scrolled window policy and size requisition handling:
91  *
92  * gtk size requisition works as follows:
93  *   a widget upon size-request reports the width and height that it finds
94  *   to be best suited to display its contents, including children.
95  *   the width and/or height reported from a widget upon size requisition
96  *   may be overidden by the user by specifying a width and/or height
97  *   other than 0 through gtk_widget_set_size_request().
98  *
99  * a scrolled window needs (for implementing all three policy types) to
100  * request its width and height based on two different rationales.
101  * 1)   the user wants the scrolled window to just fit into the space
102  *      that it gets allocated for a specifc dimension.
103  * 1.1) this does not apply if the user specified a concrete value
104  *      value for that specific dimension by either specifying usize for the
105  *      scrolled window or for its child.
106  * 2)   the user wants the scrolled window to take as much space up as
107  *      is desired by the child for a specifc dimension (i.e. POLICY_NEVER).
108  *
109  * also, kinda obvious:
110  * 3)   a user would certainly not have choosen a scrolled window as a container
111  *      for the child, if the resulting allocation takes up more space than the
112  *      child would have allocated without the scrolled window.
113  *
114  * conclusions:
115  * A) from 1) follows: the scrolled window shouldn't request more space for a
116  *    specifc dimension than is required at minimum.
117  * B) from 1.1) follows: the requisition may be overidden by usize of the scrolled
118  *    window (done automatically) or by usize of the child (needs to be checked).
119  * C) from 2) follows: for POLICY_NEVER, the scrolled window simply reports the
120  *    child's dimension.
121  * D) from 3) follows: the scrolled window child's minimum width and minimum height
122  *    under A) at least correspond to the space taken up by its scrollbars.
123  */
124
125 #define DEFAULT_SCROLLBAR_SPACING  3
126 #define TOUCH_BYPASS_CAPTURED_THRESHOLD 30
127
128 /* Kinetic scrolling */
129 #define FRAME_INTERVAL (1000 / 60)
130 #define MAX_OVERSHOOT_DISTANCE 50
131 #define FRICTION_DECELERATION 0.003
132 #define OVERSHOOT_INVERSE_ACCELERATION 0.003
133 #define RELEASE_EVENT_TIMEOUT 1000
134
135 struct _GtkScrolledWindowPrivate
136 {
137   GtkWidget     *hscrollbar;
138   GtkWidget     *vscrollbar;
139
140   GtkCornerType  real_window_placement;
141   guint16  shadow_type;
142
143   guint    window_placement_set   : 1;
144   guint    hscrollbar_policy      : 2;
145   guint    vscrollbar_policy      : 2;
146   guint    hscrollbar_visible     : 1;
147   guint    vscrollbar_visible     : 1;
148   guint    window_placement       : 2;
149   guint    focus_out              : 1; /* Flag used by ::move-focus-out implementation */
150
151   gint     min_content_width;
152   gint     min_content_height;
153
154   /* Kinetic scrolling */
155   GdkEvent              *button_press_event;
156   GdkWindow             *overshoot_window;
157   GdkDevice             *drag_device;
158   guint                  kinetic_scrolling         : 1;
159   guint                  capture_button_press      : 1;
160   guint                  in_drag                   : 1;
161   guint                  last_button_event_valid   : 1;
162
163   guint                  release_timeout_id;
164   guint                  deceleration_id;
165
166   gdouble                last_button_event_x_root;
167   gdouble                last_button_event_y_root;
168
169   gdouble                last_motion_event_x_root;
170   gdouble                last_motion_event_y_root;
171   guint32                last_motion_event_time;
172
173   gdouble                x_velocity;
174   gdouble                y_velocity;
175
176   gdouble                unclamped_hadj_value;
177   gdouble                unclamped_vadj_value;
178 };
179
180 typedef struct
181 {
182   GtkScrolledWindow     *scrolled_window;
183   gint64                 last_deceleration_time;
184
185   gdouble                x_velocity;
186   gdouble                y_velocity;
187   gdouble                vel_cosine;
188   gdouble                vel_sine;
189 } KineticScrollData;
190
191 enum {
192   PROP_0,
193   PROP_HADJUSTMENT,
194   PROP_VADJUSTMENT,
195   PROP_HSCROLLBAR_POLICY,
196   PROP_VSCROLLBAR_POLICY,
197   PROP_WINDOW_PLACEMENT,
198   PROP_WINDOW_PLACEMENT_SET,
199   PROP_SHADOW_TYPE,
200   PROP_MIN_CONTENT_WIDTH,
201   PROP_MIN_CONTENT_HEIGHT,
202   PROP_KINETIC_SCROLLING
203 };
204
205 /* Signals */
206 enum
207 {
208   SCROLL_CHILD,
209   MOVE_FOCUS_OUT,
210   LAST_SIGNAL
211 };
212
213 static void     gtk_scrolled_window_set_property       (GObject           *object,
214                                                         guint              prop_id,
215                                                         const GValue      *value,
216                                                         GParamSpec        *pspec);
217 static void     gtk_scrolled_window_get_property       (GObject           *object,
218                                                         guint              prop_id,
219                                                         GValue            *value,
220                                                         GParamSpec        *pspec);
221
222 static void     gtk_scrolled_window_destroy            (GtkWidget         *widget);
223 static void     gtk_scrolled_window_screen_changed     (GtkWidget         *widget,
224                                                         GdkScreen         *previous_screen);
225 static gboolean gtk_scrolled_window_draw               (GtkWidget         *widget,
226                                                         cairo_t           *cr);
227 static void     gtk_scrolled_window_size_allocate      (GtkWidget         *widget,
228                                                         GtkAllocation     *allocation);
229 static gboolean gtk_scrolled_window_scroll_event       (GtkWidget         *widget,
230                                                         GdkEventScroll    *event);
231 static gboolean gtk_scrolled_window_captured_event     (GtkWidget         *widget,
232                                                         GdkEvent          *event);
233 static gboolean gtk_scrolled_window_focus              (GtkWidget         *widget,
234                                                         GtkDirectionType   direction);
235 static void     gtk_scrolled_window_add                (GtkContainer      *container,
236                                                         GtkWidget         *widget);
237 static void     gtk_scrolled_window_remove             (GtkContainer      *container,
238                                                         GtkWidget         *widget);
239 static void     gtk_scrolled_window_forall             (GtkContainer      *container,
240                                                         gboolean           include_internals,
241                                                         GtkCallback        callback,
242                                                         gpointer           callback_data);
243 static gboolean gtk_scrolled_window_scroll_child       (GtkScrolledWindow *scrolled_window,
244                                                         GtkScrollType      scroll,
245                                                         gboolean           horizontal);
246 static void     gtk_scrolled_window_move_focus_out     (GtkScrolledWindow *scrolled_window,
247                                                         GtkDirectionType   direction_type);
248
249 static void     gtk_scrolled_window_relative_allocation(GtkWidget         *widget,
250                                                         GtkAllocation     *allocation);
251 static void     gtk_scrolled_window_adjustment_changed (GtkAdjustment     *adjustment,
252                                                         gpointer           data);
253 static void     gtk_scrolled_window_adjustment_value_changed (GtkAdjustment     *adjustment,
254                                                               gpointer           data);
255
256 static void  gtk_scrolled_window_update_real_placement (GtkScrolledWindow *scrolled_window);
257
258 static void  gtk_scrolled_window_get_preferred_width   (GtkWidget           *widget,
259                                                         gint                *minimum_size,
260                                                         gint                *natural_size);
261 static void  gtk_scrolled_window_get_preferred_height  (GtkWidget           *widget,
262                                                         gint                *minimum_size,
263                                                         gint                *natural_size);
264 static void  gtk_scrolled_window_get_preferred_height_for_width  (GtkWidget           *layout,
265                                                         gint                 width,
266                                                         gint                *minimum_height,
267                                                         gint                *natural_height);
268 static void  gtk_scrolled_window_get_preferred_width_for_height  (GtkWidget           *layout,
269                                                         gint                 width,
270                                                         gint                *minimum_height,
271                                                         gint                *natural_height);
272
273 static void  gtk_scrolled_window_realize               (GtkWidget           *widget);
274 static void  gtk_scrolled_window_unrealize             (GtkWidget           *widget);
275 static void  gtk_scrolled_window_map                   (GtkWidget           *widget);
276 static void  gtk_scrolled_window_unmap                 (GtkWidget           *widget);
277
278 static void  gtk_scrolled_window_grab_notify           (GtkWidget           *widget,
279                                                         gboolean             was_grabbed);
280
281 static gboolean _gtk_scrolled_window_set_adjustment_value      (GtkScrolledWindow *scrolled_window,
282                                                                 GtkAdjustment     *adjustment,
283                                                                 gdouble            value,
284                                                                 gboolean           allow_overshooting,
285                                                                 gboolean           snap_to_border);
286
287 static guint signals[LAST_SIGNAL] = {0};
288
289 G_DEFINE_TYPE (GtkScrolledWindow, gtk_scrolled_window, GTK_TYPE_BIN)
290
291
292 static void
293 add_scroll_binding (GtkBindingSet  *binding_set,
294                     guint           keyval,
295                     GdkModifierType mask,
296                     GtkScrollType   scroll,
297                     gboolean        horizontal)
298 {
299   guint keypad_keyval = keyval - GDK_KEY_Left + GDK_KEY_KP_Left;
300   
301   gtk_binding_entry_add_signal (binding_set, keyval, mask,
302                                 "scroll-child", 2,
303                                 GTK_TYPE_SCROLL_TYPE, scroll,
304                                 G_TYPE_BOOLEAN, horizontal);
305   gtk_binding_entry_add_signal (binding_set, keypad_keyval, mask,
306                                 "scroll-child", 2,
307                                 GTK_TYPE_SCROLL_TYPE, scroll,
308                                 G_TYPE_BOOLEAN, horizontal);
309 }
310
311 static void
312 add_tab_bindings (GtkBindingSet    *binding_set,
313                   GdkModifierType   modifiers,
314                   GtkDirectionType  direction)
315 {
316   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, modifiers,
317                                 "move-focus-out", 1,
318                                 GTK_TYPE_DIRECTION_TYPE, direction);
319   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, modifiers,
320                                 "move-focus-out", 1,
321                                 GTK_TYPE_DIRECTION_TYPE, direction);
322 }
323
324 static void
325 gtk_scrolled_window_class_init (GtkScrolledWindowClass *class)
326 {
327   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
328   GtkWidgetClass *widget_class;
329   GtkContainerClass *container_class;
330   GtkBindingSet *binding_set;
331
332   widget_class = (GtkWidgetClass*) class;
333   container_class = (GtkContainerClass*) class;
334
335   gobject_class->set_property = gtk_scrolled_window_set_property;
336   gobject_class->get_property = gtk_scrolled_window_get_property;
337
338   widget_class->destroy = gtk_scrolled_window_destroy;
339   widget_class->screen_changed = gtk_scrolled_window_screen_changed;
340   widget_class->draw = gtk_scrolled_window_draw;
341   widget_class->size_allocate = gtk_scrolled_window_size_allocate;
342   widget_class->scroll_event = gtk_scrolled_window_scroll_event;
343   widget_class->focus = gtk_scrolled_window_focus;
344   widget_class->get_preferred_width = gtk_scrolled_window_get_preferred_width;
345   widget_class->get_preferred_height = gtk_scrolled_window_get_preferred_height;
346   widget_class->get_preferred_height_for_width = gtk_scrolled_window_get_preferred_height_for_width;
347   widget_class->get_preferred_width_for_height = gtk_scrolled_window_get_preferred_width_for_height;
348   widget_class->realize = gtk_scrolled_window_realize;
349   widget_class->unrealize = gtk_scrolled_window_unrealize;
350   widget_class->map = gtk_scrolled_window_map;
351   widget_class->unmap = gtk_scrolled_window_unmap;
352   widget_class->grab_notify = gtk_scrolled_window_grab_notify;
353
354   container_class->add = gtk_scrolled_window_add;
355   container_class->remove = gtk_scrolled_window_remove;
356   container_class->forall = gtk_scrolled_window_forall;
357   gtk_container_class_handle_border_width (container_class);
358
359   class->scrollbar_spacing = -1;
360
361   class->scroll_child = gtk_scrolled_window_scroll_child;
362   class->move_focus_out = gtk_scrolled_window_move_focus_out;
363   
364   g_object_class_install_property (gobject_class,
365                                    PROP_HADJUSTMENT,
366                                    g_param_spec_object ("hadjustment",
367                                                         P_("Horizontal Adjustment"),
368                                                         P_("The GtkAdjustment for the horizontal position"),
369                                                         GTK_TYPE_ADJUSTMENT,
370                                                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
371   g_object_class_install_property (gobject_class,
372                                    PROP_VADJUSTMENT,
373                                    g_param_spec_object ("vadjustment",
374                                                         P_("Vertical Adjustment"),
375                                                         P_("The GtkAdjustment for the vertical position"),
376                                                         GTK_TYPE_ADJUSTMENT,
377                                                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
378   g_object_class_install_property (gobject_class,
379                                    PROP_HSCROLLBAR_POLICY,
380                                    g_param_spec_enum ("hscrollbar-policy",
381                                                       P_("Horizontal Scrollbar Policy"),
382                                                       P_("When the horizontal scrollbar is displayed"),
383                                                       GTK_TYPE_POLICY_TYPE,
384                                                       GTK_POLICY_AUTOMATIC,
385                                                       GTK_PARAM_READABLE | GTK_PARAM_WRITABLE));
386   g_object_class_install_property (gobject_class,
387                                    PROP_VSCROLLBAR_POLICY,
388                                    g_param_spec_enum ("vscrollbar-policy",
389                                                       P_("Vertical Scrollbar Policy"),
390                                                       P_("When the vertical scrollbar is displayed"),
391                                                       GTK_TYPE_POLICY_TYPE,
392                                                       GTK_POLICY_AUTOMATIC,
393                                                       GTK_PARAM_READABLE | GTK_PARAM_WRITABLE));
394
395   g_object_class_install_property (gobject_class,
396                                    PROP_WINDOW_PLACEMENT,
397                                    g_param_spec_enum ("window-placement",
398                                                       P_("Window Placement"),
399                                                       P_("Where the contents are located with respect to the scrollbars. This property only takes effect if \"window-placement-set\" is TRUE."),
400                                                       GTK_TYPE_CORNER_TYPE,
401                                                       GTK_CORNER_TOP_LEFT,
402                                                       GTK_PARAM_READABLE | GTK_PARAM_WRITABLE));
403   
404   /**
405    * GtkScrolledWindow:window-placement-set:
406    *
407    * Whether "window-placement" should be used to determine the location 
408    * of the contents with respect to the scrollbars. Otherwise, the 
409    * "gtk-scrolled-window-placement" setting is used.
410    *
411    * Since: 2.10
412    */
413   g_object_class_install_property (gobject_class,
414                                    PROP_WINDOW_PLACEMENT_SET,
415                                    g_param_spec_boolean ("window-placement-set",
416                                                          P_("Window Placement Set"),
417                                                          P_("Whether \"window-placement\" should be used to determine the location of the contents with respect to the scrollbars."),
418                                                          FALSE,
419                                                          GTK_PARAM_READABLE | GTK_PARAM_WRITABLE));
420   g_object_class_install_property (gobject_class,
421                                    PROP_SHADOW_TYPE,
422                                    g_param_spec_enum ("shadow-type",
423                                                       P_("Shadow Type"),
424                                                       P_("Style of bevel around the contents"),
425                                                       GTK_TYPE_SHADOW_TYPE,
426                                                       GTK_SHADOW_NONE,
427                                                       GTK_PARAM_READABLE | GTK_PARAM_WRITABLE));
428
429   /**
430    * GtkScrolledWindow:scrollbars-within-bevel:
431    *
432    * Whether to place scrollbars within the scrolled window's bevel.
433    *
434    * Since: 2.12
435    */
436   gtk_widget_class_install_style_property (widget_class,
437                                            g_param_spec_boolean ("scrollbars-within-bevel",
438                                                                  P_("Scrollbars within bevel"),
439                                                                  P_("Place scrollbars within the scrolled window's bevel"),
440                                                                  FALSE,
441                                                                  GTK_PARAM_READABLE));
442
443   gtk_widget_class_install_style_property (widget_class,
444                                            g_param_spec_int ("scrollbar-spacing",
445                                                              P_("Scrollbar spacing"),
446                                                              P_("Number of pixels between the scrollbars and the scrolled window"),
447                                                              0,
448                                                              G_MAXINT,
449                                                              DEFAULT_SCROLLBAR_SPACING,
450                                                              GTK_PARAM_READABLE));
451
452   /**
453    * GtkScrolledWindow:min-content-width:
454    *
455    * The minimum content width of @scrolled_window, or -1 if not set.
456    *
457    * Since: 3.0
458    */
459   g_object_class_install_property (gobject_class,
460                                    PROP_MIN_CONTENT_WIDTH,
461                                    g_param_spec_int ("min-content-width",
462                                                      P_("Minimum Content Width"),
463                                                      P_("The minimum width that the scrolled window will allocate to its content"),
464                                                      -1, G_MAXINT, -1,
465                                                      GTK_PARAM_READWRITE));
466
467   /**
468    * GtkScrolledWindow:min-content-height:
469    *
470    * The minimum content height of @scrolled_window, or -1 if not set.
471    *
472    * Since: 3.0
473    */
474   g_object_class_install_property (gobject_class,
475                                    PROP_MIN_CONTENT_HEIGHT,
476                                    g_param_spec_int ("min-content-height",
477                                                      P_("Minimum Content Height"),
478                                                      P_("The minimum height that the scrolled window will allocate to its content"),
479                                                      -1, G_MAXINT, -1,
480                                                      GTK_PARAM_READWRITE));
481
482   /**
483    * GtkScrolledWindow:kinetic-scrolling:
484    *
485    * The kinetic scrolling behavior flags. Kinetic scrolling
486    * only applies to devices with source %GDK_SOURCE_TOUCHSCREEN
487    *
488    * Since: 3.4
489    */
490   g_object_class_install_property (gobject_class,
491                                    PROP_KINETIC_SCROLLING,
492                                    g_param_spec_boolean ("kinetic-scrolling",
493                                                          P_("Kinetic Scrolling"),
494                                                          P_("Kinetic scrolling mode."),
495                                                          TRUE,
496                                                          GTK_PARAM_READABLE |
497                                                          GTK_PARAM_WRITABLE));
498   /**
499    * GtkScrolledWindow::scroll-child:
500    * @scrolled_window: a #GtkScrolledWindow
501    * @scroll: a #GtkScrollType describing how much to scroll
502    * @horizontal: whether the keybinding scrolls the child
503    *   horizontally or not
504    *
505    * The ::scroll-child signal is a
506    * <link linkend="keybinding-signals">keybinding signal</link>
507    * which gets emitted when a keybinding that scrolls is pressed.
508    * The horizontal or vertical adjustment is updated which triggers a
509    * signal that the scrolled windows child may listen to and scroll itself.
510    */
511   signals[SCROLL_CHILD] =
512     g_signal_new (I_("scroll-child"),
513                   G_TYPE_FROM_CLASS (gobject_class),
514                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
515                   G_STRUCT_OFFSET (GtkScrolledWindowClass, scroll_child),
516                   NULL, NULL,
517                   _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
518                   G_TYPE_BOOLEAN, 2,
519                   GTK_TYPE_SCROLL_TYPE,
520                   G_TYPE_BOOLEAN);
521
522   /**
523    * GtkScrolledWindow::move-focus-out:
524    * @scrolled_window: a #GtkScrolledWindow
525    * @direction_type: either %GTK_DIR_TAB_FORWARD or
526    *   %GTK_DIR_TAB_BACKWARD
527    *
528    * The ::move-focus-out signal is a
529    * <link linkend="keybinding-signals">keybinding signal</link>
530    * which gets emitted when focus is moved away from the scrolled
531    * window by a keybinding.
532    * The #GtkWidget::move-focus signal is emitted with @direction_type
533    * on this scrolled windows toplevel parent in the container hierarchy.
534    * The default bindings for this signal are
535    * <keycombo><keycap>Tab</keycap><keycap>Ctrl</keycap></keycombo>
536    * and
537    * <keycombo><keycap>Tab</keycap><keycap>Ctrl</keycap><keycap>Shift</keycap></keycombo>.
538    */
539   signals[MOVE_FOCUS_OUT] =
540     g_signal_new (I_("move-focus-out"),
541                   G_TYPE_FROM_CLASS (gobject_class),
542                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
543                   G_STRUCT_OFFSET (GtkScrolledWindowClass, move_focus_out),
544                   NULL, NULL,
545                   _gtk_marshal_VOID__ENUM,
546                   G_TYPE_NONE, 1,
547                   GTK_TYPE_DIRECTION_TYPE);
548   
549   binding_set = gtk_binding_set_by_class (class);
550
551   add_scroll_binding (binding_set, GDK_KEY_Left,  GDK_CONTROL_MASK, GTK_SCROLL_STEP_BACKWARD, TRUE);
552   add_scroll_binding (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK, GTK_SCROLL_STEP_FORWARD,  TRUE);
553   add_scroll_binding (binding_set, GDK_KEY_Up,    GDK_CONTROL_MASK, GTK_SCROLL_STEP_BACKWARD, FALSE);
554   add_scroll_binding (binding_set, GDK_KEY_Down,  GDK_CONTROL_MASK, GTK_SCROLL_STEP_FORWARD,  FALSE);
555
556   add_scroll_binding (binding_set, GDK_KEY_Page_Up,   GDK_CONTROL_MASK, GTK_SCROLL_PAGE_BACKWARD, TRUE);
557   add_scroll_binding (binding_set, GDK_KEY_Page_Down, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_FORWARD,  TRUE);
558   add_scroll_binding (binding_set, GDK_KEY_Page_Up,   0,                GTK_SCROLL_PAGE_BACKWARD, FALSE);
559   add_scroll_binding (binding_set, GDK_KEY_Page_Down, 0,                GTK_SCROLL_PAGE_FORWARD,  FALSE);
560
561   add_scroll_binding (binding_set, GDK_KEY_Home, GDK_CONTROL_MASK, GTK_SCROLL_START, TRUE);
562   add_scroll_binding (binding_set, GDK_KEY_End,  GDK_CONTROL_MASK, GTK_SCROLL_END,   TRUE);
563   add_scroll_binding (binding_set, GDK_KEY_Home, 0,                GTK_SCROLL_START, FALSE);
564   add_scroll_binding (binding_set, GDK_KEY_End,  0,                GTK_SCROLL_END,   FALSE);
565
566   add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
567   add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
568
569   g_type_class_add_private (class, sizeof (GtkScrolledWindowPrivate));
570
571   gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_SCROLLED_WINDOW_ACCESSIBLE);
572 }
573
574 static void
575 gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
576 {
577   GtkScrolledWindowPrivate *priv;
578
579   scrolled_window->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (scrolled_window,
580                                                               GTK_TYPE_SCROLLED_WINDOW,
581                                                               GtkScrolledWindowPrivate);
582
583   gtk_widget_set_has_window (GTK_WIDGET (scrolled_window), FALSE);
584   gtk_widget_set_can_focus (GTK_WIDGET (scrolled_window), TRUE);
585
586   priv->hscrollbar = NULL;
587   priv->vscrollbar = NULL;
588   priv->hscrollbar_policy = GTK_POLICY_AUTOMATIC;
589   priv->vscrollbar_policy = GTK_POLICY_AUTOMATIC;
590   priv->hscrollbar_visible = FALSE;
591   priv->vscrollbar_visible = FALSE;
592   priv->focus_out = FALSE;
593   priv->window_placement = GTK_CORNER_TOP_LEFT;
594   gtk_scrolled_window_update_real_placement (scrolled_window);
595   priv->min_content_width = -1;
596   priv->min_content_height = -1;
597
598   gtk_scrolled_window_set_kinetic_scrolling (scrolled_window, TRUE);
599   gtk_scrolled_window_set_capture_button_press (scrolled_window, TRUE);
600 }
601
602 /**
603  * gtk_scrolled_window_new:
604  * @hadjustment: (allow-none): horizontal adjustment
605  * @vadjustment: (allow-none): vertical adjustment
606  *
607  * Creates a new scrolled window.
608  *
609  * The two arguments are the scrolled window's adjustments; these will be
610  * shared with the scrollbars and the child widget to keep the bars in sync 
611  * with the child. Usually you want to pass %NULL for the adjustments, which 
612  * will cause the scrolled window to create them for you.
613  *
614  * Returns: a new scrolled window
615  */
616 GtkWidget*
617 gtk_scrolled_window_new (GtkAdjustment *hadjustment,
618                          GtkAdjustment *vadjustment)
619 {
620   GtkWidget *scrolled_window;
621
622   if (hadjustment)
623     g_return_val_if_fail (GTK_IS_ADJUSTMENT (hadjustment), NULL);
624
625   if (vadjustment)
626     g_return_val_if_fail (GTK_IS_ADJUSTMENT (vadjustment), NULL);
627
628   scrolled_window = g_object_new (GTK_TYPE_SCROLLED_WINDOW,
629                                     "hadjustment", hadjustment,
630                                     "vadjustment", vadjustment,
631                                     NULL);
632
633   return scrolled_window;
634 }
635
636 /**
637  * gtk_scrolled_window_set_hadjustment:
638  * @scrolled_window: a #GtkScrolledWindow
639  * @hadjustment: horizontal scroll adjustment
640  *
641  * Sets the #GtkAdjustment for the horizontal scrollbar.
642  */
643 void
644 gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
645                                      GtkAdjustment     *hadjustment)
646 {
647   GtkScrolledWindowPrivate *priv;
648   GtkBin *bin;
649   GtkWidget *child;
650
651   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
652   if (hadjustment)
653     g_return_if_fail (GTK_IS_ADJUSTMENT (hadjustment));
654   else
655     hadjustment = (GtkAdjustment*) g_object_new (GTK_TYPE_ADJUSTMENT, NULL);
656
657   bin = GTK_BIN (scrolled_window);
658   priv = scrolled_window->priv;
659
660   if (!priv->hscrollbar)
661     {
662       gtk_widget_push_composite_child ();
663       priv->hscrollbar = gtk_scrollbar_new (GTK_ORIENTATION_HORIZONTAL, hadjustment);
664       gtk_widget_set_composite_name (priv->hscrollbar, "hscrollbar");
665       gtk_widget_pop_composite_child ();
666
667       gtk_widget_set_parent (priv->hscrollbar, GTK_WIDGET (scrolled_window));
668       g_object_ref (priv->hscrollbar);
669       gtk_widget_show (priv->hscrollbar);
670     }
671   else
672     {
673       GtkAdjustment *old_adjustment;
674
675       old_adjustment = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
676       if (old_adjustment == hadjustment)
677         return;
678
679       g_signal_handlers_disconnect_by_func (old_adjustment,
680                                             gtk_scrolled_window_adjustment_changed,
681                                             scrolled_window);
682       gtk_range_set_adjustment (GTK_RANGE (priv->hscrollbar),
683                                 hadjustment);
684     }
685   hadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
686   g_signal_connect (hadjustment,
687                     "changed",
688                     G_CALLBACK (gtk_scrolled_window_adjustment_changed),
689                     scrolled_window);
690   g_signal_connect (hadjustment,
691                     "value-changed",
692                     G_CALLBACK (gtk_scrolled_window_adjustment_value_changed),
693                     scrolled_window);
694   gtk_scrolled_window_adjustment_changed (hadjustment, scrolled_window);
695   gtk_scrolled_window_adjustment_value_changed (hadjustment, scrolled_window);
696
697   child = gtk_bin_get_child (bin);
698   if (GTK_IS_SCROLLABLE (child))
699     gtk_scrollable_set_hadjustment (GTK_SCROLLABLE (child), hadjustment);
700
701   g_object_notify (G_OBJECT (scrolled_window), "hadjustment");
702 }
703
704 /**
705  * gtk_scrolled_window_set_vadjustment:
706  * @scrolled_window: a #GtkScrolledWindow
707  * @vadjustment: vertical scroll adjustment
708  *
709  * Sets the #GtkAdjustment for the vertical scrollbar.
710  */
711 void
712 gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
713                                      GtkAdjustment     *vadjustment)
714 {
715   GtkScrolledWindowPrivate *priv;
716   GtkBin *bin;
717   GtkWidget *child;
718
719   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
720   if (vadjustment)
721     g_return_if_fail (GTK_IS_ADJUSTMENT (vadjustment));
722   else
723     vadjustment = (GtkAdjustment*) g_object_new (GTK_TYPE_ADJUSTMENT, NULL);
724
725   bin = GTK_BIN (scrolled_window);
726   priv = scrolled_window->priv;
727
728   if (!priv->vscrollbar)
729     {
730       gtk_widget_push_composite_child ();
731       priv->vscrollbar = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, vadjustment);
732       gtk_widget_set_composite_name (priv->vscrollbar, "vscrollbar");
733       gtk_widget_pop_composite_child ();
734
735       gtk_widget_set_parent (priv->vscrollbar, GTK_WIDGET (scrolled_window));
736       g_object_ref (priv->vscrollbar);
737       gtk_widget_show (priv->vscrollbar);
738     }
739   else
740     {
741       GtkAdjustment *old_adjustment;
742       
743       old_adjustment = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar));
744       if (old_adjustment == vadjustment)
745         return;
746
747       g_signal_handlers_disconnect_by_func (old_adjustment,
748                                             gtk_scrolled_window_adjustment_changed,
749                                             scrolled_window);
750       gtk_range_set_adjustment (GTK_RANGE (priv->vscrollbar),
751                                 vadjustment);
752     }
753   vadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar));
754   g_signal_connect (vadjustment,
755                     "changed",
756                     G_CALLBACK (gtk_scrolled_window_adjustment_changed),
757                     scrolled_window);
758   g_signal_connect (vadjustment,
759                     "value-changed",
760                     G_CALLBACK (gtk_scrolled_window_adjustment_value_changed),
761                     scrolled_window);
762   gtk_scrolled_window_adjustment_changed (vadjustment, scrolled_window);
763   gtk_scrolled_window_adjustment_value_changed (vadjustment, scrolled_window);
764
765   child = gtk_bin_get_child (bin);
766   if (GTK_IS_SCROLLABLE (child))
767     gtk_scrollable_set_vadjustment (GTK_SCROLLABLE (child), vadjustment);
768
769   g_object_notify (G_OBJECT (scrolled_window), "vadjustment");
770 }
771
772 /**
773  * gtk_scrolled_window_get_hadjustment:
774  * @scrolled_window: a #GtkScrolledWindow
775  *
776  * Returns the horizontal scrollbar's adjustment, used to connect the
777  * horizontal scrollbar to the child widget's horizontal scroll
778  * functionality.
779  *
780  * Returns: (transfer none): the horizontal #GtkAdjustment
781  */
782 GtkAdjustment*
783 gtk_scrolled_window_get_hadjustment (GtkScrolledWindow *scrolled_window)
784 {
785   GtkScrolledWindowPrivate *priv;
786
787   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
788
789   priv = scrolled_window->priv;
790
791   return (priv->hscrollbar ?
792           gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar)) :
793           NULL);
794 }
795
796 /**
797  * gtk_scrolled_window_get_vadjustment:
798  * @scrolled_window: a #GtkScrolledWindow
799  * 
800  * Returns the vertical scrollbar's adjustment, used to connect the
801  * vertical scrollbar to the child widget's vertical scroll functionality.
802  * 
803  * Returns: (transfer none): the vertical #GtkAdjustment
804  */
805 GtkAdjustment*
806 gtk_scrolled_window_get_vadjustment (GtkScrolledWindow *scrolled_window)
807 {
808   GtkScrolledWindowPrivate *priv;
809
810   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
811
812   priv = scrolled_window->priv;
813
814   return (priv->vscrollbar ?
815           gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)) :
816           NULL);
817 }
818
819 /**
820  * gtk_scrolled_window_get_hscrollbar:
821  * @scrolled_window: a #GtkScrolledWindow
822  *
823  * Returns the horizontal scrollbar of @scrolled_window.
824  *
825  * Returns: (transfer none): the horizontal scrollbar of the scrolled window,
826  *     or %NULL if it does not have one.
827  *
828  * Since: 2.8
829  */
830 GtkWidget*
831 gtk_scrolled_window_get_hscrollbar (GtkScrolledWindow *scrolled_window)
832 {
833   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
834
835   return scrolled_window->priv->hscrollbar;
836 }
837
838 /**
839  * gtk_scrolled_window_get_vscrollbar:
840  * @scrolled_window: a #GtkScrolledWindow
841  * 
842  * Returns the vertical scrollbar of @scrolled_window.
843  *
844  * Returns: (transfer none): the vertical scrollbar of the scrolled window,
845  *     or %NULL if it does not have one.
846  *
847  * Since: 2.8
848  */
849 GtkWidget*
850 gtk_scrolled_window_get_vscrollbar (GtkScrolledWindow *scrolled_window)
851 {
852   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
853
854   return scrolled_window->priv->vscrollbar;
855 }
856
857 /**
858  * gtk_scrolled_window_set_policy:
859  * @scrolled_window: a #GtkScrolledWindow
860  * @hscrollbar_policy: policy for horizontal bar
861  * @vscrollbar_policy: policy for vertical bar
862  * 
863  * Sets the scrollbar policy for the horizontal and vertical scrollbars.
864  *
865  * The policy determines when the scrollbar should appear; it is a value
866  * from the #GtkPolicyType enumeration. If %GTK_POLICY_ALWAYS, the
867  * scrollbar is always present; if %GTK_POLICY_NEVER, the scrollbar is
868  * never present; if %GTK_POLICY_AUTOMATIC, the scrollbar is present only
869  * if needed (that is, if the slider part of the bar would be smaller
870  * than the trough - the display is larger than the page size).
871  */
872 void
873 gtk_scrolled_window_set_policy (GtkScrolledWindow *scrolled_window,
874                                 GtkPolicyType      hscrollbar_policy,
875                                 GtkPolicyType      vscrollbar_policy)
876 {
877   GtkScrolledWindowPrivate *priv;
878   GObject *object = G_OBJECT (scrolled_window);
879   
880   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
881
882   priv = scrolled_window->priv;
883
884   if ((priv->hscrollbar_policy != hscrollbar_policy) ||
885       (priv->vscrollbar_policy != vscrollbar_policy))
886     {
887       priv->hscrollbar_policy = hscrollbar_policy;
888       priv->vscrollbar_policy = vscrollbar_policy;
889
890       gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
891
892       g_object_freeze_notify (object);
893       g_object_notify (object, "hscrollbar-policy");
894       g_object_notify (object, "vscrollbar-policy");
895       g_object_thaw_notify (object);
896     }
897 }
898
899 /**
900  * gtk_scrolled_window_get_policy:
901  * @scrolled_window: a #GtkScrolledWindow
902  * @hscrollbar_policy: (out) (allow-none): location to store the policy 
903  *     for the horizontal scrollbar, or %NULL.
904  * @vscrollbar_policy: (out) (allow-none): location to store the policy
905  *     for the vertical scrollbar, or %NULL.
906  * 
907  * Retrieves the current policy values for the horizontal and vertical
908  * scrollbars. See gtk_scrolled_window_set_policy().
909  */
910 void
911 gtk_scrolled_window_get_policy (GtkScrolledWindow *scrolled_window,
912                                 GtkPolicyType     *hscrollbar_policy,
913                                 GtkPolicyType     *vscrollbar_policy)
914 {
915   GtkScrolledWindowPrivate *priv;
916
917   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
918
919   priv = scrolled_window->priv;
920
921   if (hscrollbar_policy)
922     *hscrollbar_policy = priv->hscrollbar_policy;
923   if (vscrollbar_policy)
924     *vscrollbar_policy = priv->vscrollbar_policy;
925 }
926
927 static void
928 gtk_scrolled_window_update_real_placement (GtkScrolledWindow *scrolled_window)
929 {
930   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
931   GtkSettings *settings;
932
933   settings = gtk_widget_get_settings (GTK_WIDGET (scrolled_window));
934
935   if (priv->window_placement_set || settings == NULL)
936     priv->real_window_placement = priv->window_placement;
937   else
938     g_object_get (settings,
939                   "gtk-scrolled-window-placement",
940                   &priv->real_window_placement,
941                   NULL);
942 }
943
944 static void
945 gtk_scrolled_window_set_placement_internal (GtkScrolledWindow *scrolled_window,
946                                             GtkCornerType      window_placement)
947 {
948   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
949
950   if (priv->window_placement != window_placement)
951     {
952       priv->window_placement = window_placement;
953
954       gtk_scrolled_window_update_real_placement (scrolled_window);
955       gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
956       
957       g_object_notify (G_OBJECT (scrolled_window), "window-placement");
958     }
959 }
960
961 static void
962 gtk_scrolled_window_set_placement_set (GtkScrolledWindow *scrolled_window,
963                                        gboolean           placement_set,
964                                        gboolean           emit_resize)
965 {
966   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
967
968   if (priv->window_placement_set != placement_set)
969     {
970       priv->window_placement_set = placement_set;
971
972       gtk_scrolled_window_update_real_placement (scrolled_window);
973       if (emit_resize)
974         gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
975
976       g_object_notify (G_OBJECT (scrolled_window), "window-placement-set");
977     }
978 }
979
980 /**
981  * gtk_scrolled_window_set_placement:
982  * @scrolled_window: a #GtkScrolledWindow
983  * @window_placement: position of the child window
984  *
985  * Sets the placement of the contents with respect to the scrollbars
986  * for the scrolled window.
987  * 
988  * The default is %GTK_CORNER_TOP_LEFT, meaning the child is
989  * in the top left, with the scrollbars underneath and to the right.
990  * Other values in #GtkCornerType are %GTK_CORNER_TOP_RIGHT,
991  * %GTK_CORNER_BOTTOM_LEFT, and %GTK_CORNER_BOTTOM_RIGHT.
992  *
993  * See also gtk_scrolled_window_get_placement() and
994  * gtk_scrolled_window_unset_placement().
995  */
996 void
997 gtk_scrolled_window_set_placement (GtkScrolledWindow *scrolled_window,
998                                    GtkCornerType      window_placement)
999 {
1000   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
1001
1002   gtk_scrolled_window_set_placement_set (scrolled_window, TRUE, FALSE);
1003   gtk_scrolled_window_set_placement_internal (scrolled_window, window_placement);
1004 }
1005
1006 /**
1007  * gtk_scrolled_window_get_placement:
1008  * @scrolled_window: a #GtkScrolledWindow
1009  *
1010  * Gets the placement of the contents with respect to the scrollbars
1011  * for the scrolled window. See gtk_scrolled_window_set_placement().
1012  *
1013  * Return value: the current placement value.
1014  *
1015  * See also gtk_scrolled_window_set_placement() and
1016  * gtk_scrolled_window_unset_placement().
1017  **/
1018 GtkCornerType
1019 gtk_scrolled_window_get_placement (GtkScrolledWindow *scrolled_window)
1020 {
1021   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), GTK_CORNER_TOP_LEFT);
1022
1023   return scrolled_window->priv->window_placement;
1024 }
1025
1026 /**
1027  * gtk_scrolled_window_unset_placement:
1028  * @scrolled_window: a #GtkScrolledWindow
1029  *
1030  * Unsets the placement of the contents with respect to the scrollbars
1031  * for the scrolled window. If no window placement is set for a scrolled
1032  * window, it obeys the "gtk-scrolled-window-placement" XSETTING.
1033  *
1034  * See also gtk_scrolled_window_set_placement() and
1035  * gtk_scrolled_window_get_placement().
1036  *
1037  * Since: 2.10
1038  **/
1039 void
1040 gtk_scrolled_window_unset_placement (GtkScrolledWindow *scrolled_window)
1041 {
1042   GtkScrolledWindowPrivate *priv;
1043
1044   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
1045
1046   priv = scrolled_window->priv;
1047
1048   if (priv->window_placement_set)
1049     {
1050       priv->window_placement_set = FALSE;
1051
1052       gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
1053
1054       g_object_notify (G_OBJECT (scrolled_window), "window-placement-set");
1055     }
1056 }
1057
1058 /**
1059  * gtk_scrolled_window_set_shadow_type:
1060  * @scrolled_window: a #GtkScrolledWindow
1061  * @type: kind of shadow to draw around scrolled window contents
1062  *
1063  * Changes the type of shadow drawn around the contents of
1064  * @scrolled_window.
1065  * 
1066  **/
1067 void
1068 gtk_scrolled_window_set_shadow_type (GtkScrolledWindow *scrolled_window,
1069                                      GtkShadowType      type)
1070 {
1071   GtkScrolledWindowPrivate *priv;
1072
1073   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
1074   g_return_if_fail (type >= GTK_SHADOW_NONE && type <= GTK_SHADOW_ETCHED_OUT);
1075
1076   priv = scrolled_window->priv;
1077
1078   if (priv->shadow_type != type)
1079     {
1080       priv->shadow_type = type;
1081
1082       if (gtk_widget_is_drawable (GTK_WIDGET (scrolled_window)))
1083         gtk_widget_queue_draw (GTK_WIDGET (scrolled_window));
1084
1085       gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
1086
1087       g_object_notify (G_OBJECT (scrolled_window), "shadow-type");
1088     }
1089 }
1090
1091 /**
1092  * gtk_scrolled_window_get_shadow_type:
1093  * @scrolled_window: a #GtkScrolledWindow
1094  *
1095  * Gets the shadow type of the scrolled window. See 
1096  * gtk_scrolled_window_set_shadow_type().
1097  *
1098  * Return value: the current shadow type
1099  **/
1100 GtkShadowType
1101 gtk_scrolled_window_get_shadow_type (GtkScrolledWindow *scrolled_window)
1102 {
1103   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_NONE);
1104
1105   return scrolled_window->priv->shadow_type;
1106 }
1107
1108 /**
1109  * gtk_scrolled_window_set_kinetic_scrolling:
1110  * @scrolled_window: a #GtkScrolledWindow
1111  * @kinetic_scrolling: %TRUE to enable kinetic scrolling
1112  *
1113  * Turns kinetic scrolling on or off.
1114  * Kinetic scrolling only applies to devices with source
1115  * %GDK_SOURCE_TOUCHSCREEN.
1116  *
1117  * Since: 3.4
1118  **/
1119 void
1120 gtk_scrolled_window_set_kinetic_scrolling (GtkScrolledWindow *scrolled_window,
1121                                            gboolean           kinetic_scrolling)
1122 {
1123   GtkScrolledWindowPrivate *priv;
1124
1125   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
1126
1127   priv = scrolled_window->priv;
1128   if (priv->kinetic_scrolling == kinetic_scrolling)
1129     return;
1130
1131   priv->kinetic_scrolling = kinetic_scrolling;
1132   if (priv->kinetic_scrolling)
1133     {
1134       _gtk_widget_set_captured_event_handler (GTK_WIDGET (scrolled_window),
1135                                               gtk_scrolled_window_captured_event);
1136     }
1137   else
1138     {
1139       _gtk_widget_set_captured_event_handler (GTK_WIDGET (scrolled_window), NULL);
1140       if (priv->release_timeout_id)
1141         {
1142           g_source_remove (priv->release_timeout_id);
1143           priv->release_timeout_id = 0;
1144         }
1145       if (priv->deceleration_id)
1146         {
1147           g_source_remove (priv->deceleration_id);
1148           priv->deceleration_id = 0;
1149         }
1150     }
1151   g_object_notify (G_OBJECT (scrolled_window), "kinetic-scrolling");
1152 }
1153
1154 /**
1155  * gtk_scrolled_window_get_kinetic_scrolling:
1156  * @scrolled_window: a #GtkScrolledWindow
1157  *
1158  * Returns the specified kinetic scrolling behavior.
1159  *
1160  * Return value: the scrolling behavior flags.
1161  *
1162  * Since: 3.4
1163  */
1164 gboolean
1165 gtk_scrolled_window_get_kinetic_scrolling (GtkScrolledWindow *scrolled_window)
1166 {
1167   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), FALSE);
1168
1169   return scrolled_window->priv->kinetic_scrolling;
1170 }
1171
1172 /**
1173  * gtk_scrolled_window_set_capture_button_press:
1174  * @scrolled_window: a #GtkScrolledWindow
1175  * @capture_button_press: %TRUE to capture button presses
1176  *
1177  * Changes the behaviour of @scrolled_window wrt. to the initial
1178  * event that possibly starts kinetic scrolling. When @capture_button_press
1179  * is set to %TRUE, the event is captured by the scrolled window, and
1180  * then later replayed if it is meant to go to the child widget.
1181  *
1182  * This should be enabled if any child widgets perform non-reversible
1183  * actions on #GtkWidget::button-press-event. If they don't, and handle
1184  * additionally handle #GtkWidget::grab-broken-event, it might be better
1185  * to set @capture_button_press to %FALSE.
1186  *
1187  * This setting only has an effect if kinetic scrolling is enabled.
1188  *
1189  * Since: 3.4
1190  */
1191 void
1192 gtk_scrolled_window_set_capture_button_press (GtkScrolledWindow *scrolled_window,
1193                                               gboolean           capture_button_press)
1194 {
1195   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
1196
1197   scrolled_window->priv->capture_button_press = capture_button_press;
1198 }
1199
1200 /**
1201  * gtk_scrolled_window_get_capture_button_press:
1202  * @scrolled_window: a #GtkScrolledWindow
1203  *
1204  * Return whether button presses are captured during kinetic
1205  * scrolling. See gtk_scrolled_window_set_capture_button_press().
1206  *
1207  * Returns: %TRUE if button presses are captured during kinetic scrolling
1208  *
1209  * Since: 3.4
1210  */
1211 gboolean
1212 gtk_scrolled_window_get_capture_button_press (GtkScrolledWindow *scrolled_window)
1213 {
1214   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), FALSE);
1215
1216   return scrolled_window->priv->capture_button_press;
1217 }
1218
1219
1220 static void
1221 gtk_scrolled_window_destroy (GtkWidget *widget)
1222 {
1223   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
1224   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
1225
1226   if (priv->hscrollbar)
1227     {
1228       g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar)),
1229                                             gtk_scrolled_window_adjustment_changed,
1230                                             scrolled_window);
1231       gtk_widget_unparent (priv->hscrollbar);
1232       gtk_widget_destroy (priv->hscrollbar);
1233       g_object_unref (priv->hscrollbar);
1234       priv->hscrollbar = NULL;
1235     }
1236   if (priv->vscrollbar)
1237     {
1238       g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)),
1239                                             gtk_scrolled_window_adjustment_changed,
1240                                             scrolled_window);
1241       gtk_widget_unparent (priv->vscrollbar);
1242       gtk_widget_destroy (priv->vscrollbar);
1243       g_object_unref (priv->vscrollbar);
1244       priv->vscrollbar = NULL;
1245     }
1246
1247   if (priv->release_timeout_id)
1248     {
1249       g_source_remove (priv->release_timeout_id);
1250       priv->release_timeout_id = 0;
1251     }
1252   if (priv->deceleration_id)
1253     {
1254       g_source_remove (priv->deceleration_id);
1255       priv->deceleration_id = 0;
1256     }
1257
1258   if (priv->button_press_event)
1259     {
1260       gdk_event_free (priv->button_press_event);
1261       priv->button_press_event = NULL;
1262     }
1263
1264   GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->destroy (widget);
1265 }
1266
1267 static void
1268 gtk_scrolled_window_set_property (GObject      *object,
1269                                   guint         prop_id,
1270                                   const GValue *value,
1271                                   GParamSpec   *pspec)
1272 {
1273   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (object);
1274   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
1275
1276   switch (prop_id)
1277     {
1278     case PROP_HADJUSTMENT:
1279       gtk_scrolled_window_set_hadjustment (scrolled_window,
1280                                            g_value_get_object (value));
1281       break;
1282     case PROP_VADJUSTMENT:
1283       gtk_scrolled_window_set_vadjustment (scrolled_window,
1284                                            g_value_get_object (value));
1285       break;
1286     case PROP_HSCROLLBAR_POLICY:
1287       gtk_scrolled_window_set_policy (scrolled_window,
1288                                       g_value_get_enum (value),
1289                                       priv->vscrollbar_policy);
1290       break;
1291     case PROP_VSCROLLBAR_POLICY:
1292       gtk_scrolled_window_set_policy (scrolled_window,
1293                                       priv->hscrollbar_policy,
1294                                       g_value_get_enum (value));
1295       break;
1296     case PROP_WINDOW_PLACEMENT:
1297       gtk_scrolled_window_set_placement_internal (scrolled_window,
1298                                                   g_value_get_enum (value));
1299       break;
1300     case PROP_WINDOW_PLACEMENT_SET:
1301       gtk_scrolled_window_set_placement_set (scrolled_window,
1302                                              g_value_get_boolean (value),
1303                                              TRUE);
1304       break;
1305     case PROP_SHADOW_TYPE:
1306       gtk_scrolled_window_set_shadow_type (scrolled_window,
1307                                            g_value_get_enum (value));
1308       break;
1309     case PROP_MIN_CONTENT_WIDTH:
1310       gtk_scrolled_window_set_min_content_width (scrolled_window,
1311                                                  g_value_get_int (value));
1312       break;
1313     case PROP_MIN_CONTENT_HEIGHT:
1314       gtk_scrolled_window_set_min_content_height (scrolled_window,
1315                                                   g_value_get_int (value));
1316       break;
1317     case PROP_KINETIC_SCROLLING:
1318       gtk_scrolled_window_set_kinetic_scrolling (scrolled_window,
1319                                                  g_value_get_boolean (value));
1320       break;
1321     default:
1322       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1323       break;
1324     }
1325 }
1326
1327 static void
1328 gtk_scrolled_window_get_property (GObject    *object,
1329                                   guint       prop_id,
1330                                   GValue     *value,
1331                                   GParamSpec *pspec)
1332 {
1333   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (object);
1334   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
1335
1336   switch (prop_id)
1337     {
1338     case PROP_HADJUSTMENT:
1339       g_value_set_object (value,
1340                           G_OBJECT (gtk_scrolled_window_get_hadjustment (scrolled_window)));
1341       break;
1342     case PROP_VADJUSTMENT:
1343       g_value_set_object (value,
1344                           G_OBJECT (gtk_scrolled_window_get_vadjustment (scrolled_window)));
1345       break;
1346     case PROP_WINDOW_PLACEMENT:
1347       g_value_set_enum (value, priv->window_placement);
1348       break;
1349     case PROP_WINDOW_PLACEMENT_SET:
1350       g_value_set_boolean (value, priv->window_placement_set);
1351       break;
1352     case PROP_SHADOW_TYPE:
1353       g_value_set_enum (value, priv->shadow_type);
1354       break;
1355     case PROP_HSCROLLBAR_POLICY:
1356       g_value_set_enum (value, priv->hscrollbar_policy);
1357       break;
1358     case PROP_VSCROLLBAR_POLICY:
1359       g_value_set_enum (value, priv->vscrollbar_policy);
1360       break;
1361     case PROP_MIN_CONTENT_WIDTH:
1362       g_value_set_int (value, priv->min_content_width);
1363       break;
1364     case PROP_MIN_CONTENT_HEIGHT:
1365       g_value_set_int (value, priv->min_content_height);
1366       break;
1367     case PROP_KINETIC_SCROLLING:
1368       g_value_set_boolean (value, priv->kinetic_scrolling);
1369       break;
1370     default:
1371       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1372       break;
1373     }
1374 }
1375
1376 static void
1377 traverse_container (GtkWidget *widget,
1378                     gpointer   data)
1379 {
1380   if (GTK_IS_SCROLLED_WINDOW (widget))
1381     {
1382       gtk_scrolled_window_update_real_placement (GTK_SCROLLED_WINDOW (widget));
1383       gtk_widget_queue_resize (widget);
1384     }
1385   else if (GTK_IS_CONTAINER (widget))
1386     gtk_container_forall (GTK_CONTAINER (widget), traverse_container, NULL);
1387 }
1388
1389 static void
1390 gtk_scrolled_window_settings_changed (GtkSettings *settings)
1391 {
1392   GList *list, *l;
1393
1394   list = gtk_window_list_toplevels ();
1395
1396   for (l = list; l; l = l->next)
1397     gtk_container_forall (GTK_CONTAINER (l->data), 
1398                           traverse_container, NULL);
1399
1400   g_list_free (list);
1401 }
1402
1403 static void
1404 gtk_scrolled_window_screen_changed (GtkWidget *widget,
1405                                     GdkScreen *previous_screen)
1406 {
1407   GtkSettings *settings;
1408   guint window_placement_connection;
1409
1410   gtk_scrolled_window_update_real_placement (GTK_SCROLLED_WINDOW (widget));
1411
1412   if (!gtk_widget_has_screen (widget))
1413     return;
1414
1415   settings = gtk_widget_get_settings (widget);
1416
1417   window_placement_connection = 
1418     GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (settings), 
1419                                          "gtk-scrolled-window-connection"));
1420   
1421   if (window_placement_connection)
1422     return;
1423
1424   window_placement_connection =
1425     g_signal_connect (settings, "notify::gtk-scrolled-window-placement",
1426                       G_CALLBACK (gtk_scrolled_window_settings_changed), NULL);
1427   g_object_set_data (G_OBJECT (settings), 
1428                      I_("gtk-scrolled-window-connection"),
1429                      GUINT_TO_POINTER (window_placement_connection));
1430 }
1431
1432 static void
1433 gtk_scrolled_window_draw_scrollbars_junction (GtkScrolledWindow *scrolled_window,
1434                                               cairo_t *cr)
1435 {
1436   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
1437   GtkWidget *widget = GTK_WIDGET (scrolled_window);
1438   GtkAllocation wid_allocation, hscr_allocation, vscr_allocation;
1439   GtkStyleContext *context;
1440   GdkRectangle junction_rect;
1441   gboolean is_rtl, scrollbars_within_bevel;
1442
1443   is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1444   gtk_widget_get_allocation (widget, &wid_allocation);
1445   gtk_widget_get_allocation (GTK_WIDGET (priv->hscrollbar), &hscr_allocation);
1446   gtk_widget_get_allocation (GTK_WIDGET (priv->vscrollbar), &vscr_allocation);
1447
1448   gtk_widget_style_get (widget,
1449                         "scrollbars-within-bevel", &scrollbars_within_bevel,
1450                         NULL);
1451   context = gtk_widget_get_style_context (widget);
1452
1453   if (scrollbars_within_bevel &&
1454       priv->shadow_type != GTK_SHADOW_NONE)
1455     {
1456       GtkStateFlags state;
1457       GtkBorder padding, border;
1458
1459       state = gtk_widget_get_state_flags (widget);
1460
1461       gtk_style_context_save (context);
1462       gtk_style_context_add_class (context, GTK_STYLE_CLASS_FRAME);
1463       gtk_style_context_get_padding (context, state, &padding);
1464       gtk_style_context_get_border (context, state, &border);
1465       gtk_style_context_restore (context);
1466
1467       junction_rect.x = padding.left + border.left;
1468       junction_rect.y = padding.top + border.top;
1469     }
1470   else
1471     {
1472       junction_rect.x = 0;
1473       junction_rect.y = 0;
1474     }
1475
1476   junction_rect.width = vscr_allocation.width;
1477   junction_rect.height = hscr_allocation.height;
1478   
1479   if ((is_rtl && 
1480        (priv->real_window_placement == GTK_CORNER_TOP_RIGHT ||
1481         priv->real_window_placement == GTK_CORNER_BOTTOM_RIGHT)) ||
1482       (!is_rtl && 
1483        (priv->real_window_placement == GTK_CORNER_TOP_LEFT ||
1484         priv->real_window_placement == GTK_CORNER_BOTTOM_LEFT)))
1485     junction_rect.x += hscr_allocation.width;
1486
1487   if (priv->real_window_placement == GTK_CORNER_TOP_LEFT ||
1488       priv->real_window_placement == GTK_CORNER_TOP_RIGHT)
1489     junction_rect.y += vscr_allocation.height;
1490
1491   gtk_style_context_save (context);
1492   gtk_style_context_add_class (context, GTK_STYLE_CLASS_SCROLLBARS_JUNCTION);
1493
1494   gtk_render_background (context, cr,
1495                          junction_rect.x, junction_rect.y,
1496                          junction_rect.width, junction_rect.height);
1497   gtk_render_frame (context, cr,
1498                     junction_rect.x, junction_rect.y,
1499                     junction_rect.width, junction_rect.height);
1500
1501   gtk_style_context_restore (context);
1502 }
1503
1504 static gboolean
1505 gtk_scrolled_window_draw (GtkWidget *widget,
1506                           cairo_t   *cr)
1507 {
1508   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
1509   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
1510   GtkAllocation relative_allocation;
1511   GtkStyleContext *context;
1512
1513   context = gtk_widget_get_style_context (widget);
1514   gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
1515
1516   gtk_render_background (context, cr,
1517                          0, 0,
1518                          gtk_widget_get_allocated_width (widget), gtk_widget_get_allocated_height (widget));
1519
1520   if (priv->hscrollbar_visible && 
1521       priv->vscrollbar_visible)
1522     gtk_scrolled_window_draw_scrollbars_junction (scrolled_window, cr);
1523
1524   if (priv->shadow_type != GTK_SHADOW_NONE)
1525     {
1526       gboolean scrollbars_within_bevel;
1527
1528       gtk_style_context_save (context);
1529       gtk_style_context_add_class (context, GTK_STYLE_CLASS_FRAME);
1530
1531       gtk_widget_style_get (widget, "scrollbars-within-bevel", &scrollbars_within_bevel, NULL);
1532
1533       if (!scrollbars_within_bevel)
1534         {
1535           GtkStateFlags state;
1536           GtkBorder padding, border;
1537
1538           state = gtk_widget_get_state_flags (widget);
1539           gtk_style_context_get_padding (context, state, &padding);
1540           gtk_style_context_get_border (context, state, &border);
1541
1542           relative_allocation.x -= padding.left + border.left;
1543           relative_allocation.y -= padding.top + border.top;
1544           relative_allocation.width += padding.left + padding.right + border.left + border.right;
1545           relative_allocation.height += padding.top + padding.bottom + border.top + border.bottom;
1546         }
1547       else
1548         {
1549           relative_allocation.x = 0;
1550           relative_allocation.y = 0;
1551           relative_allocation.width = gtk_widget_get_allocated_width (widget);
1552           relative_allocation.height = gtk_widget_get_allocated_height (widget);
1553         }
1554
1555       gtk_render_frame (context, cr,
1556                         relative_allocation.x,
1557                         relative_allocation.y,
1558                         relative_allocation.width,
1559                         relative_allocation.height);
1560
1561       gtk_style_context_restore (context);
1562     }
1563
1564   GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->draw (widget, cr);
1565
1566   return FALSE;
1567 }
1568
1569 static void
1570 gtk_scrolled_window_forall (GtkContainer *container,
1571                             gboolean      include_internals,
1572                             GtkCallback   callback,
1573                             gpointer      callback_data)
1574 {
1575   GtkScrolledWindowPrivate *priv;
1576   GtkScrolledWindow *scrolled_window;
1577
1578   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
1579   g_return_if_fail (callback != NULL);
1580
1581   GTK_CONTAINER_CLASS (gtk_scrolled_window_parent_class)->forall (container,
1582                                               include_internals,
1583                                               callback,
1584                                               callback_data);
1585   if (include_internals)
1586     {
1587       scrolled_window = GTK_SCROLLED_WINDOW (container);
1588       priv = scrolled_window->priv;
1589
1590       if (priv->vscrollbar)
1591         callback (priv->vscrollbar, callback_data);
1592       if (priv->hscrollbar)
1593         callback (priv->hscrollbar, callback_data);
1594     }
1595 }
1596
1597 static gboolean
1598 gtk_scrolled_window_scroll_child (GtkScrolledWindow *scrolled_window,
1599                                   GtkScrollType      scroll,
1600                                   gboolean           horizontal)
1601 {
1602   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
1603   GtkAdjustment *adjustment = NULL;
1604   
1605   switch (scroll)
1606     {
1607     case GTK_SCROLL_STEP_UP:
1608       scroll = GTK_SCROLL_STEP_BACKWARD;
1609       horizontal = FALSE;
1610       break;
1611     case GTK_SCROLL_STEP_DOWN:
1612       scroll = GTK_SCROLL_STEP_FORWARD;
1613       horizontal = FALSE;
1614       break;
1615     case GTK_SCROLL_STEP_LEFT:
1616       scroll = GTK_SCROLL_STEP_BACKWARD;
1617       horizontal = TRUE;
1618       break;
1619     case GTK_SCROLL_STEP_RIGHT:
1620       scroll = GTK_SCROLL_STEP_FORWARD;
1621       horizontal = TRUE;
1622       break;
1623     case GTK_SCROLL_PAGE_UP:
1624       scroll = GTK_SCROLL_PAGE_BACKWARD;
1625       horizontal = FALSE;
1626       break;
1627     case GTK_SCROLL_PAGE_DOWN:
1628       scroll = GTK_SCROLL_PAGE_FORWARD;
1629       horizontal = FALSE;
1630       break;
1631     case GTK_SCROLL_PAGE_LEFT:
1632       scroll = GTK_SCROLL_STEP_BACKWARD;
1633       horizontal = TRUE;
1634       break;
1635     case GTK_SCROLL_PAGE_RIGHT:
1636       scroll = GTK_SCROLL_STEP_FORWARD;
1637       horizontal = TRUE;
1638       break;
1639     case GTK_SCROLL_STEP_BACKWARD:
1640     case GTK_SCROLL_STEP_FORWARD:
1641     case GTK_SCROLL_PAGE_BACKWARD:
1642     case GTK_SCROLL_PAGE_FORWARD:
1643     case GTK_SCROLL_START:
1644     case GTK_SCROLL_END:
1645       break;
1646     default:
1647       g_warning ("Invalid scroll type %u for GtkScrolledWindow::scroll-child", scroll);
1648       return FALSE;
1649     }
1650
1651   if ((horizontal && (!priv->hscrollbar || !priv->hscrollbar_visible)) ||
1652       (!horizontal && (!priv->vscrollbar || !priv->vscrollbar_visible)))
1653     return FALSE;
1654
1655   if (horizontal)
1656     {
1657       if (priv->hscrollbar)
1658         adjustment = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
1659     }
1660   else
1661     {
1662       if (priv->vscrollbar)
1663         adjustment = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar));
1664     }
1665
1666   if (adjustment)
1667     {
1668       gdouble value = gtk_adjustment_get_value (adjustment);
1669       
1670       switch (scroll)
1671         {
1672         case GTK_SCROLL_STEP_FORWARD:
1673           value += gtk_adjustment_get_step_increment (adjustment);
1674           break;
1675         case GTK_SCROLL_STEP_BACKWARD:
1676           value -= gtk_adjustment_get_step_increment (adjustment);
1677           break;
1678         case GTK_SCROLL_PAGE_FORWARD:
1679           value += gtk_adjustment_get_page_increment (adjustment);
1680           break;
1681         case GTK_SCROLL_PAGE_BACKWARD:
1682           value -= gtk_adjustment_get_page_increment (adjustment);
1683           break;
1684         case GTK_SCROLL_START:
1685           value = gtk_adjustment_get_lower (adjustment);
1686           break;
1687         case GTK_SCROLL_END:
1688           value = gtk_adjustment_get_upper (adjustment);
1689           break;
1690         default:
1691           g_assert_not_reached ();
1692           break;
1693         }
1694
1695       gtk_adjustment_set_value (adjustment, value);
1696
1697       return TRUE;
1698     }
1699
1700   return FALSE;
1701 }
1702
1703 static void
1704 gtk_scrolled_window_move_focus_out (GtkScrolledWindow *scrolled_window,
1705                                     GtkDirectionType   direction_type)
1706 {
1707   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
1708   GtkWidget *toplevel;
1709   
1710   /* Focus out of the scrolled window entirely. We do this by setting
1711    * a flag, then propagating the focus motion to the notebook.
1712    */
1713   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (scrolled_window));
1714   if (!gtk_widget_is_toplevel (toplevel))
1715     return;
1716
1717   g_object_ref (scrolled_window);
1718
1719   priv->focus_out = TRUE;
1720   g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1721   priv->focus_out = FALSE;
1722
1723   g_object_unref (scrolled_window);
1724 }
1725
1726 static void
1727 gtk_scrolled_window_relative_allocation (GtkWidget     *widget,
1728                                          GtkAllocation *allocation)
1729 {
1730   GtkAllocation widget_allocation;
1731   GtkScrolledWindow *scrolled_window;
1732   GtkScrolledWindowPrivate *priv;
1733   gint sb_spacing;
1734   gint sb_width;
1735   gint sb_height;
1736
1737   g_return_if_fail (widget != NULL);
1738   g_return_if_fail (allocation != NULL);
1739
1740   scrolled_window = GTK_SCROLLED_WINDOW (widget);
1741   priv = scrolled_window->priv;
1742
1743   /* Get possible scrollbar dimensions */
1744   sb_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
1745   gtk_widget_get_preferred_height (priv->hscrollbar, &sb_height, NULL);
1746   gtk_widget_get_preferred_width (priv->vscrollbar, &sb_width, NULL);
1747
1748   gtk_widget_get_allocation (widget, &widget_allocation);
1749
1750   allocation->x = 0;
1751   allocation->y = 0;
1752   allocation->width = widget_allocation.width;
1753   allocation->height = widget_allocation.height;
1754
1755   /* Subtract some things from our available allocation size */
1756   if (priv->shadow_type != GTK_SHADOW_NONE)
1757     {
1758       GtkStyleContext *context;
1759       GtkStateFlags state;
1760       GtkBorder padding, border;
1761
1762       context = gtk_widget_get_style_context (widget);
1763       state = gtk_widget_get_state_flags (widget);
1764
1765       gtk_style_context_save (context);
1766       gtk_style_context_add_class (context, GTK_STYLE_CLASS_FRAME);
1767
1768       gtk_style_context_get_border (context, state, &border);
1769       gtk_style_context_get_padding (context, state, &padding);
1770
1771       allocation->x += padding.left + border.left;
1772       allocation->y += padding.top + border.top;
1773       allocation->width = MAX (1, allocation->width - (padding.left + border.left + padding.right + border.right));
1774       allocation->height = MAX (1, allocation->height - (padding.top + border.top + padding.bottom + border.bottom));
1775
1776       gtk_style_context_restore (context);
1777     }
1778
1779   if (priv->vscrollbar_visible)
1780     {
1781       gboolean is_rtl;
1782
1783       is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1784   
1785       if ((!is_rtl && 
1786            (priv->real_window_placement == GTK_CORNER_TOP_RIGHT ||
1787             priv->real_window_placement == GTK_CORNER_BOTTOM_RIGHT)) ||
1788           (is_rtl && 
1789            (priv->real_window_placement == GTK_CORNER_TOP_LEFT ||
1790             priv->real_window_placement == GTK_CORNER_BOTTOM_LEFT)))
1791         allocation->x += (sb_width +  sb_spacing);
1792
1793       allocation->width = MAX (1, allocation->width - (sb_width + sb_spacing));
1794     }
1795   if (priv->hscrollbar_visible)
1796     {
1797
1798       if (priv->real_window_placement == GTK_CORNER_BOTTOM_LEFT ||
1799           priv->real_window_placement == GTK_CORNER_BOTTOM_RIGHT)
1800         allocation->y += (sb_height + sb_spacing);
1801
1802       allocation->height = MAX (1, allocation->height - (sb_height + sb_spacing));
1803     }
1804 }
1805
1806 static gboolean
1807 _gtk_scrolled_window_get_overshoot (GtkScrolledWindow *scrolled_window,
1808                                     gint              *overshoot_x,
1809                                     gint              *overshoot_y)
1810 {
1811   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
1812   GtkAdjustment *vadjustment, *hadjustment;
1813   gdouble lower, upper, x, y;
1814
1815   /* Vertical overshoot */
1816   vadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar));
1817   lower = gtk_adjustment_get_lower (vadjustment);
1818   upper = gtk_adjustment_get_upper (vadjustment) -
1819     gtk_adjustment_get_page_size (vadjustment);
1820
1821   if (priv->unclamped_vadj_value < lower)
1822     y = priv->unclamped_vadj_value - lower;
1823   else if (priv->unclamped_vadj_value > upper)
1824     y = priv->unclamped_vadj_value - upper;
1825   else
1826     y = 0;
1827
1828   /* Horizontal overshoot */
1829   hadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
1830   lower = gtk_adjustment_get_lower (hadjustment);
1831   upper = gtk_adjustment_get_upper (hadjustment) -
1832     gtk_adjustment_get_page_size (hadjustment);
1833
1834   if (priv->unclamped_hadj_value < lower)
1835     x = priv->unclamped_hadj_value - lower;
1836   else if (priv->unclamped_hadj_value > upper)
1837     x = priv->unclamped_hadj_value - upper;
1838   else
1839     x = 0;
1840
1841   if (overshoot_x)
1842     *overshoot_x = x;
1843
1844   if (overshoot_y)
1845     *overshoot_y = y;
1846
1847   return (x != 0 || y != 0);
1848 }
1849
1850 static void
1851 _gtk_scrolled_window_allocate_overshoot_window (GtkScrolledWindow *scrolled_window)
1852 {
1853   GtkAllocation window_allocation, relative_allocation, allocation;
1854   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
1855   GtkWidget *widget = GTK_WIDGET (scrolled_window);
1856   gint overshoot_x, overshoot_y;
1857
1858   if (!gtk_widget_get_realized (widget))
1859     return;
1860
1861   gtk_widget_get_allocation (widget, &allocation);
1862   gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
1863   _gtk_scrolled_window_get_overshoot (scrolled_window,
1864                                       &overshoot_x, &overshoot_y);
1865
1866   window_allocation = relative_allocation;
1867   window_allocation.x += allocation.x;
1868   window_allocation.y += allocation.y;
1869
1870   /* Handle displacement to the left/top by moving the overshoot
1871    * window, overshooting to the bottom/right is handled in
1872    * gtk_scrolled_window_allocate_child()
1873    */
1874   if (overshoot_x < 0)
1875     window_allocation.x += -overshoot_x;
1876
1877   if (overshoot_y < 0)
1878     window_allocation.y += -overshoot_y;
1879
1880   window_allocation.width -= ABS (overshoot_x);
1881   window_allocation.height -= ABS (overshoot_y);
1882
1883   gdk_window_move_resize (priv->overshoot_window,
1884                           window_allocation.x, window_allocation.y,
1885                           window_allocation.width, window_allocation.height);
1886 }
1887
1888 static void
1889 gtk_scrolled_window_allocate_child (GtkScrolledWindow *swindow,
1890                                     GtkAllocation     *relative_allocation)
1891 {
1892   GtkWidget     *widget = GTK_WIDGET (swindow), *child;
1893   GtkAllocation  allocation;
1894   GtkAllocation  child_allocation;
1895   gint           overshoot_x, overshoot_y;
1896
1897   child = gtk_bin_get_child (GTK_BIN (widget));
1898
1899   gtk_widget_get_allocation (widget, &allocation);
1900
1901   gtk_scrolled_window_relative_allocation (widget, relative_allocation);
1902   _gtk_scrolled_window_get_overshoot (swindow, &overshoot_x, &overshoot_y);
1903
1904   /* Handle overshooting to the right/bottom by relocating the
1905    * widget allocation to negative coordinates, so these edges
1906    * stick to the overshoot window border.
1907    */
1908   if (overshoot_x > 0)
1909     child_allocation.x = -overshoot_x;
1910   else
1911     child_allocation.x = 0;
1912
1913   if (overshoot_y > 0)
1914     child_allocation.y = -overshoot_y;
1915   else
1916     child_allocation.y = 0;
1917
1918   child_allocation.width = relative_allocation->width;
1919   child_allocation.height = relative_allocation->height;
1920
1921   gtk_widget_size_allocate (child, &child_allocation);
1922 }
1923
1924 static void
1925 gtk_scrolled_window_size_allocate (GtkWidget     *widget,
1926                                    GtkAllocation *allocation)
1927 {
1928   GtkScrolledWindow *scrolled_window;
1929   GtkScrolledWindowPrivate *priv;
1930   GtkStyleContext *context;
1931   GtkStateFlags state;
1932   GtkBorder padding, border;
1933   GtkBin *bin;
1934   GtkAllocation relative_allocation;
1935   GtkAllocation child_allocation;
1936   GtkWidget *child;
1937   gboolean scrollbars_within_bevel;
1938   gint sb_spacing;
1939   gint sb_width;
1940   gint sb_height;
1941
1942   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
1943   g_return_if_fail (allocation != NULL);
1944
1945   scrolled_window = GTK_SCROLLED_WINDOW (widget);
1946   bin = GTK_BIN (scrolled_window);
1947   priv = scrolled_window->priv;
1948
1949   /* Get possible scrollbar dimensions */
1950   sb_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
1951   gtk_widget_get_preferred_height (priv->hscrollbar, &sb_height, NULL);
1952   gtk_widget_get_preferred_width (priv->vscrollbar, &sb_width, NULL);
1953
1954   context = gtk_widget_get_style_context (widget);
1955   state = gtk_widget_get_state_flags (widget);
1956
1957   gtk_style_context_save (context);
1958   gtk_style_context_add_class (context, GTK_STYLE_CLASS_FRAME);
1959
1960   gtk_style_context_get_padding (context, state, &padding);
1961   gtk_style_context_get_border (context, state, &border);
1962
1963   gtk_widget_style_get (widget, "scrollbars-within-bevel", &scrollbars_within_bevel, NULL);
1964
1965   gtk_widget_set_allocation (widget, allocation);
1966   gtk_style_context_restore (context);
1967
1968   if (priv->hscrollbar_policy == GTK_POLICY_ALWAYS)
1969     priv->hscrollbar_visible = TRUE;
1970   else if (priv->hscrollbar_policy == GTK_POLICY_NEVER)
1971     priv->hscrollbar_visible = FALSE;
1972   if (priv->vscrollbar_policy == GTK_POLICY_ALWAYS)
1973     priv->vscrollbar_visible = TRUE;
1974   else if (priv->vscrollbar_policy == GTK_POLICY_NEVER)
1975     priv->vscrollbar_visible = FALSE;
1976
1977   child = gtk_bin_get_child (bin);
1978   if (child && gtk_widget_get_visible (child))
1979     {
1980       gint child_scroll_width;
1981       gint child_scroll_height;
1982       gboolean previous_hvis;
1983       gboolean previous_vvis;
1984       guint count = 0;
1985
1986       /* Determine scrollbar visibility first via hfw apis */
1987       if (gtk_widget_get_request_mode (child) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
1988         {
1989           if (gtk_scrollable_get_hscroll_policy (GTK_SCROLLABLE (child)) == GTK_SCROLL_MINIMUM)
1990             gtk_widget_get_preferred_width (child, &child_scroll_width, NULL);
1991           else
1992             gtk_widget_get_preferred_width (child, NULL, &child_scroll_width);
1993           
1994           if (priv->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
1995             {
1996               /* First try without a vertical scrollbar if the content will fit the height
1997                * given the extra width of the scrollbar */
1998               if (gtk_scrollable_get_vscroll_policy (GTK_SCROLLABLE (child)) == GTK_SCROLL_MINIMUM)
1999                 gtk_widget_get_preferred_height_for_width (child, 
2000                                                            MAX (allocation->width, child_scroll_width), 
2001                                                            &child_scroll_height, NULL);
2002               else
2003                 gtk_widget_get_preferred_height_for_width (child,
2004                                                            MAX (allocation->width, child_scroll_width), 
2005                                                            NULL, &child_scroll_height);
2006               
2007               if (priv->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
2008                 {
2009                   /* Does the content height fit the allocation height ? */
2010                   priv->vscrollbar_visible = child_scroll_height > allocation->height;
2011                   
2012                   /* Does the content width fit the allocation with minus a possible scrollbar ? */
2013                   priv->hscrollbar_visible = 
2014                     child_scroll_width > allocation->width - 
2015                     (priv->vscrollbar_visible ? sb_width + sb_spacing : 0);
2016                   
2017                   /* Now that we've guessed the hscrollbar, does the content height fit
2018                    * the possible new allocation height ? */
2019                   priv->vscrollbar_visible = 
2020                     child_scroll_height > allocation->height - 
2021                     (priv->hscrollbar_visible ? sb_height + sb_spacing : 0);
2022                   
2023                   /* Now that we've guessed the vscrollbar, does the content width fit
2024                    * the possible new allocation width ? */
2025                   priv->hscrollbar_visible = 
2026                     child_scroll_width > allocation->width - 
2027                     (priv->vscrollbar_visible ? sb_width + sb_spacing : 0);
2028                 }
2029               else /* priv->hscrollbar_policy != GTK_POLICY_AUTOMATIC */
2030                 {
2031                   priv->hscrollbar_visible = priv->hscrollbar_policy != GTK_POLICY_NEVER;
2032                   priv->vscrollbar_visible = child_scroll_height > allocation->height - 
2033                     (priv->hscrollbar_visible ? sb_height + sb_spacing : 0);
2034                 }
2035             }
2036           else /* priv->vscrollbar_policy != GTK_POLICY_AUTOMATIC */
2037             {
2038               priv->vscrollbar_visible = priv->vscrollbar_policy != GTK_POLICY_NEVER;
2039               
2040               if (priv->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
2041                 priv->hscrollbar_visible = 
2042                   child_scroll_width > allocation->width - 
2043                   (priv->vscrollbar_visible ? 0 : sb_width + sb_spacing);
2044               else
2045                 priv->hscrollbar_visible = priv->hscrollbar_policy != GTK_POLICY_NEVER;
2046             }
2047         } 
2048       else /* GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT */
2049         {
2050           if (gtk_scrollable_get_vscroll_policy (GTK_SCROLLABLE (child)) == GTK_SCROLL_MINIMUM)
2051             gtk_widget_get_preferred_height (child, &child_scroll_height, NULL);
2052           else
2053             gtk_widget_get_preferred_height (child, NULL, &child_scroll_height);
2054           
2055           if (priv->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
2056             {
2057               /* First try without a horizontal scrollbar if the content will fit the width
2058                * given the extra height of the scrollbar */
2059               if (gtk_scrollable_get_hscroll_policy (GTK_SCROLLABLE (child)) == GTK_SCROLL_MINIMUM)
2060                 gtk_widget_get_preferred_width_for_height (child, 
2061                                                            MAX (allocation->height, child_scroll_height), 
2062                                                            &child_scroll_width, NULL);
2063               else
2064                 gtk_widget_get_preferred_width_for_height (child, 
2065                                                            MAX (allocation->height, child_scroll_height), 
2066                                                            NULL, &child_scroll_width);
2067               
2068               if (priv->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
2069                 {
2070                   /* Does the content width fit the allocation width ? */
2071                   priv->hscrollbar_visible = child_scroll_width > allocation->width;
2072                   
2073                   /* Does the content height fit the allocation with minus a possible scrollbar ? */
2074                   priv->vscrollbar_visible = 
2075                     child_scroll_height > allocation->height - 
2076                     (priv->hscrollbar_visible ? sb_height + sb_spacing : 0);
2077                   
2078                   /* Now that we've guessed the vscrollbar, does the content width fit
2079                    * the possible new allocation width ? */
2080                   priv->hscrollbar_visible = 
2081                     child_scroll_width > allocation->width - 
2082                     (priv->vscrollbar_visible ? sb_width + sb_spacing : 0);
2083                   
2084                   /* Now that we've guessed the hscrollbar, does the content height fit
2085                    * the possible new allocation height ? */
2086                   priv->vscrollbar_visible = 
2087                     child_scroll_height > allocation->height - 
2088                     (priv->hscrollbar_visible ? sb_height + sb_spacing : 0);
2089                 }
2090               else /* priv->vscrollbar_policy != GTK_POLICY_AUTOMATIC */
2091                 {
2092                   priv->vscrollbar_visible = priv->vscrollbar_policy != GTK_POLICY_NEVER;
2093                   priv->hscrollbar_visible = child_scroll_width > allocation->width - 
2094                     (priv->vscrollbar_visible ? sb_width + sb_spacing : 0);
2095                 }
2096             }
2097           else /* priv->hscrollbar_policy != GTK_POLICY_AUTOMATIC */
2098             {
2099               priv->hscrollbar_visible = priv->hscrollbar_policy != GTK_POLICY_NEVER;
2100               
2101               if (priv->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
2102                 priv->vscrollbar_visible = 
2103                   child_scroll_height > allocation->height - 
2104                   (priv->hscrollbar_visible ? 0 : sb_height + sb_spacing);
2105               else
2106                 priv->vscrollbar_visible = priv->vscrollbar_policy != GTK_POLICY_NEVER;
2107             }
2108         }
2109
2110       /* Now after guessing scrollbar visibility; fall back on the allocation loop which 
2111        * observes the adjustments to detect scrollbar visibility and also avoids 
2112        * infinite recursion
2113        */
2114       do
2115         {
2116           previous_hvis = priv->hscrollbar_visible;
2117           previous_vvis = priv->vscrollbar_visible;
2118           gtk_scrolled_window_allocate_child (scrolled_window, &relative_allocation);
2119
2120           /* Explicitly force scrollbar visibility checks.
2121            *
2122            * Since we make a guess above, the child might not decide to update the adjustments 
2123            * if they logically did not change since the last configuration
2124            */
2125           if (priv->hscrollbar)
2126             gtk_scrolled_window_adjustment_changed 
2127               (gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar)), scrolled_window);
2128
2129           if (priv->vscrollbar)
2130             gtk_scrolled_window_adjustment_changed 
2131               (gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)), scrolled_window);
2132
2133           /* If, after the first iteration, the hscrollbar and the
2134            * vscrollbar flip visiblity... or if one of the scrollbars flip
2135            * on each itteration indefinitly/infinitely, then we just need both 
2136            * at this size.
2137            */
2138           if ((count &&
2139                previous_hvis != priv->hscrollbar_visible &&
2140                previous_vvis != priv->vscrollbar_visible) || count > 3)
2141             {
2142               priv->hscrollbar_visible = TRUE;
2143               priv->vscrollbar_visible = TRUE;
2144
2145               gtk_scrolled_window_allocate_child (scrolled_window, &relative_allocation);
2146
2147               break;
2148             }
2149           
2150           count++;
2151         }
2152       while (previous_hvis != priv->hscrollbar_visible ||
2153              previous_vvis != priv->vscrollbar_visible);
2154     }
2155   else
2156     {
2157       priv->hscrollbar_visible = priv->hscrollbar_policy == GTK_POLICY_ALWAYS;
2158       priv->vscrollbar_visible = priv->vscrollbar_policy == GTK_POLICY_ALWAYS;
2159       gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
2160     }
2161
2162   if (priv->hscrollbar_visible)
2163     {
2164       if (!gtk_widget_get_visible (priv->hscrollbar))
2165         gtk_widget_show (priv->hscrollbar);
2166
2167       child_allocation.x = relative_allocation.x;
2168       if (priv->real_window_placement == GTK_CORNER_TOP_LEFT ||
2169           priv->real_window_placement == GTK_CORNER_TOP_RIGHT)
2170         child_allocation.y = (relative_allocation.y +
2171                               relative_allocation.height +
2172                               sb_spacing);
2173       else
2174         child_allocation.y = relative_allocation.y - sb_spacing - sb_height;
2175
2176       child_allocation.width = relative_allocation.width;
2177       child_allocation.height = sb_height;
2178       child_allocation.x += allocation->x;
2179       child_allocation.y += allocation->y;
2180
2181       if (priv->shadow_type != GTK_SHADOW_NONE)
2182         {
2183           if (!scrollbars_within_bevel)
2184             {
2185               child_allocation.x -= padding.left + border.left;
2186               child_allocation.width += padding.left + padding.right + border.left + border.right;
2187
2188               if (priv->real_window_placement == GTK_CORNER_TOP_LEFT ||
2189                   priv->real_window_placement == GTK_CORNER_TOP_RIGHT)
2190                 child_allocation.y += padding.bottom + border.bottom;
2191               else
2192                 child_allocation.y -= padding.top + border.top;
2193             }
2194         }
2195
2196       gtk_widget_size_allocate (priv->hscrollbar, &child_allocation);
2197     }
2198   else if (gtk_widget_get_visible (priv->hscrollbar))
2199     gtk_widget_hide (priv->hscrollbar);
2200
2201   if (priv->vscrollbar_visible)
2202     {
2203       if (!gtk_widget_get_visible (priv->vscrollbar))
2204         gtk_widget_show (priv->vscrollbar);
2205
2206       if ((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL && 
2207            (priv->real_window_placement == GTK_CORNER_TOP_RIGHT ||
2208             priv->real_window_placement == GTK_CORNER_BOTTOM_RIGHT)) ||
2209           (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR && 
2210            (priv->real_window_placement == GTK_CORNER_TOP_LEFT ||
2211             priv->real_window_placement == GTK_CORNER_BOTTOM_LEFT)))
2212         child_allocation.x = (relative_allocation.x +
2213                               relative_allocation.width +
2214                               sb_spacing);
2215       else
2216         child_allocation.x = relative_allocation.x - sb_spacing - sb_width;
2217
2218       child_allocation.y = relative_allocation.y;
2219       child_allocation.width = sb_width;
2220       child_allocation.height = relative_allocation.height;
2221       child_allocation.x += allocation->x;
2222       child_allocation.y += allocation->y;
2223
2224       if (priv->shadow_type != GTK_SHADOW_NONE)
2225         {
2226           if (!scrollbars_within_bevel)
2227             {
2228               child_allocation.y -= padding.top + border.top;
2229               child_allocation.height += padding.top + padding.bottom + border.top + border.bottom;
2230
2231               if ((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL &&
2232                    (priv->real_window_placement == GTK_CORNER_TOP_RIGHT ||
2233                     priv->real_window_placement == GTK_CORNER_BOTTOM_RIGHT)) ||
2234                   (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR &&
2235                    (priv->real_window_placement == GTK_CORNER_TOP_LEFT ||
2236                     priv->real_window_placement == GTK_CORNER_BOTTOM_LEFT)))
2237                 child_allocation.x += padding.right + border.right;
2238               else
2239                 child_allocation.x -= padding.left + border.left;
2240             }
2241         }
2242
2243       gtk_widget_size_allocate (priv->vscrollbar, &child_allocation);
2244     }
2245   else if (gtk_widget_get_visible (priv->vscrollbar))
2246     gtk_widget_hide (priv->vscrollbar);
2247
2248   _gtk_scrolled_window_allocate_overshoot_window (scrolled_window);
2249 }
2250
2251 static gboolean
2252 gtk_scrolled_window_scroll_event (GtkWidget      *widget,
2253                                   GdkEventScroll *event)
2254 {
2255   GtkScrolledWindowPrivate *priv;
2256   GtkScrolledWindow *scrolled_window;
2257   gboolean handled = FALSE;
2258   gdouble delta_x;
2259   gdouble delta_y;
2260   gdouble delta;
2261
2262   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (widget), FALSE);
2263   g_return_val_if_fail (event != NULL, FALSE);
2264
2265   scrolled_window = GTK_SCROLLED_WINDOW (widget);
2266   priv = scrolled_window->priv;
2267
2268   if (gdk_event_get_scroll_deltas ((GdkEvent *) event, &delta_x, &delta_y))
2269     {
2270       if (delta_x != 0.0 && priv->hscrollbar &&
2271           gtk_widget_get_visible (priv->hscrollbar))
2272         {
2273           GtkAdjustment *adj;
2274           gdouble new_value;
2275           gdouble page_size;
2276           gdouble scroll_unit;
2277
2278           adj = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
2279           page_size = gtk_adjustment_get_page_size (adj);
2280           scroll_unit = pow (page_size, 2.0 / 3.0);
2281
2282           new_value = CLAMP (gtk_adjustment_get_value (adj) + delta_x * scroll_unit,
2283                              gtk_adjustment_get_lower (adj),
2284                              gtk_adjustment_get_upper (adj) -
2285                              gtk_adjustment_get_page_size (adj));
2286
2287           gtk_adjustment_set_value (adj, new_value);
2288
2289           handled = TRUE;
2290         }
2291
2292       if (delta_y != 0.0 && priv->vscrollbar &&
2293           gtk_widget_get_visible (priv->vscrollbar))
2294         {
2295           GtkAdjustment *adj;
2296           gdouble new_value;
2297           gdouble page_size;
2298           gdouble scroll_unit;
2299
2300           adj = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar));
2301           page_size = gtk_adjustment_get_page_size (adj);
2302           scroll_unit = pow (page_size, 2.0 / 3.0);
2303
2304           new_value = CLAMP (gtk_adjustment_get_value (adj) + delta_y * scroll_unit,
2305                              gtk_adjustment_get_lower (adj),
2306                              gtk_adjustment_get_upper (adj) -
2307                              gtk_adjustment_get_page_size (adj));
2308
2309           gtk_adjustment_set_value (adj, new_value);
2310
2311           handled = TRUE;
2312         }
2313     }
2314   else
2315     {
2316       GtkWidget *range;
2317
2318       if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_DOWN)
2319         range = priv->vscrollbar;
2320       else
2321         range = priv->hscrollbar;
2322
2323       if (range && gtk_widget_get_visible (range))
2324         {
2325           GtkAdjustment *adj = gtk_range_get_adjustment (GTK_RANGE (range));
2326           gdouble new_value;
2327
2328           delta = _gtk_range_get_wheel_delta (GTK_RANGE (range), event);
2329
2330           new_value = CLAMP (gtk_adjustment_get_value (adj) + delta,
2331                              gtk_adjustment_get_lower (adj),
2332                              gtk_adjustment_get_upper (adj) -
2333                              gtk_adjustment_get_page_size (adj));
2334
2335           gtk_adjustment_set_value (adj, new_value);
2336
2337           handled = TRUE;
2338         }
2339     }
2340
2341   return handled;
2342 }
2343
2344 static gboolean
2345 _gtk_scrolled_window_set_adjustment_value (GtkScrolledWindow *scrolled_window,
2346                                            GtkAdjustment     *adjustment,
2347                                            gdouble            value,
2348                                            gboolean           allow_overshooting,
2349                                            gboolean           snap_to_border)
2350 {
2351   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
2352   gdouble lower, upper, *prev_value;
2353
2354   lower = gtk_adjustment_get_lower (adjustment);
2355   upper = gtk_adjustment_get_upper (adjustment) -
2356     gtk_adjustment_get_page_size (adjustment);
2357
2358   if (adjustment == gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar)))
2359     prev_value = &priv->unclamped_hadj_value;
2360   else if (adjustment == gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)))
2361     prev_value = &priv->unclamped_vadj_value;
2362   else
2363     return FALSE;
2364
2365   if (snap_to_border)
2366     {
2367       if (*prev_value < 0 && value > 0)
2368         value = 0;
2369       else if (*prev_value > upper && value < upper)
2370         value = upper;
2371     }
2372
2373   if (allow_overshooting)
2374     {
2375       lower -= MAX_OVERSHOOT_DISTANCE;
2376       upper += MAX_OVERSHOOT_DISTANCE;
2377     }
2378
2379   *prev_value = CLAMP (value, lower, upper);
2380   gtk_adjustment_set_value (adjustment, value);
2381
2382   return (*prev_value != value);
2383 }
2384
2385 static gboolean
2386 scrolled_window_deceleration_cb (gpointer user_data)
2387 {
2388   KineticScrollData *data = user_data;
2389   GtkScrolledWindow *scrolled_window = data->scrolled_window;
2390   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
2391   GtkAdjustment *hadjustment, *vadjustment;
2392   gint old_overshoot_x, old_overshoot_y, overshoot_x, overshoot_y;
2393   gdouble value;
2394   gint64 current_time;
2395   guint elapsed;
2396
2397   hadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
2398   vadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar));
2399
2400   _gtk_scrolled_window_get_overshoot (scrolled_window,
2401                                       &old_overshoot_x, &old_overshoot_y);
2402
2403   current_time = g_get_monotonic_time ();
2404   elapsed = (current_time - data->last_deceleration_time) / 1000;
2405   data->last_deceleration_time = current_time;
2406
2407   if (hadjustment && priv->hscrollbar_visible)
2408     {
2409       value = priv->unclamped_hadj_value + (data->x_velocity * elapsed);
2410
2411       if (_gtk_scrolled_window_set_adjustment_value (scrolled_window,
2412                                                      hadjustment,
2413                                                      value, TRUE, TRUE))
2414         data->x_velocity = 0;
2415     }
2416   else
2417     data->x_velocity = 0;
2418
2419   if (vadjustment && priv->vscrollbar_visible)
2420     {
2421       value = priv->unclamped_vadj_value + (data->y_velocity * elapsed);
2422
2423       if (_gtk_scrolled_window_set_adjustment_value (scrolled_window,
2424                                                      vadjustment,
2425                                                      value, TRUE, TRUE))
2426         data->y_velocity = 0;
2427     }
2428   else
2429     data->y_velocity = 0;
2430
2431   _gtk_scrolled_window_get_overshoot (scrolled_window,
2432                                       &overshoot_x, &overshoot_y);
2433
2434   if (overshoot_x == 0)
2435     {
2436       if (old_overshoot_x != 0)
2437         {
2438           /* Overshooting finished snapping back */
2439           data->x_velocity = 0;
2440         }
2441       else if (data->x_velocity > 0)
2442         {
2443           data->x_velocity -= FRICTION_DECELERATION * elapsed * data->vel_sine;
2444           data->x_velocity = MAX (0, data->x_velocity);
2445         }
2446       else if (data->x_velocity < 0)
2447         {
2448           data->x_velocity += FRICTION_DECELERATION * elapsed * data->vel_sine;
2449           data->x_velocity = MIN (0, data->x_velocity);
2450         }
2451     }
2452   else if (overshoot_x < 0)
2453     data->x_velocity += OVERSHOOT_INVERSE_ACCELERATION * elapsed;
2454   else if (overshoot_x > 0)
2455     data->x_velocity -= OVERSHOOT_INVERSE_ACCELERATION * elapsed;
2456
2457   if (overshoot_y == 0)
2458     {
2459       if (old_overshoot_y != 0)
2460         {
2461           /* Overshooting finished snapping back */
2462           data->y_velocity = 0;
2463         }
2464       else if (data->y_velocity > 0)
2465         {
2466           data->y_velocity -= FRICTION_DECELERATION * elapsed * data->vel_cosine;
2467           data->y_velocity = MAX (0, data->y_velocity);
2468         }
2469       else if (data->y_velocity < 0)
2470         {
2471           data->y_velocity += FRICTION_DECELERATION * elapsed * data->vel_cosine;
2472           data->y_velocity = MIN (0, data->y_velocity);
2473         }
2474     }
2475   else if (overshoot_y < 0)
2476     data->y_velocity += OVERSHOOT_INVERSE_ACCELERATION * elapsed;
2477   else if (overshoot_y > 0)
2478     data->y_velocity -= OVERSHOOT_INVERSE_ACCELERATION * elapsed;
2479
2480   if (old_overshoot_x != overshoot_x ||
2481       old_overshoot_y != overshoot_y)
2482     {
2483       if (overshoot_x >= 0 || overshoot_y >= 0)
2484         {
2485           /* We need to reallocate the widget to have it at
2486            * negative offset, so there's a "gravity" on the
2487            * bottom/right corner
2488            */
2489           gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
2490         }
2491       else if (overshoot_x < 0 || overshoot_y < 0)
2492         _gtk_scrolled_window_allocate_overshoot_window (scrolled_window);
2493     }
2494
2495   if (overshoot_x != 0 || overshoot_y != 0 ||
2496       data->x_velocity != 0 || data->y_velocity != 0)
2497     return TRUE;
2498   else
2499     {
2500       priv->deceleration_id = 0;
2501       return FALSE;
2502     }
2503 }
2504
2505 static void
2506 gtk_scrolled_window_cancel_deceleration (GtkScrolledWindow *scrolled_window)
2507 {
2508   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
2509
2510   if (priv->deceleration_id)
2511     {
2512       g_source_remove (priv->deceleration_id);
2513       priv->deceleration_id = 0;
2514     }
2515 }
2516
2517 static void
2518 gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window)
2519 {
2520   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
2521   KineticScrollData *data;
2522   gdouble angle;
2523
2524   data = g_new0 (KineticScrollData, 1);
2525   data->scrolled_window = scrolled_window;
2526   data->last_deceleration_time = g_get_monotonic_time ();
2527   data->x_velocity = priv->x_velocity;
2528   data->y_velocity = priv->y_velocity;
2529
2530   /* We use sine/cosine as a factor to deceleration x/y components
2531    * of the vector, so we care about the sign later.
2532    */
2533   angle = atan2 (ABS (data->x_velocity), ABS (data->y_velocity));
2534   data->vel_cosine = cos (angle);
2535   data->vel_sine = sin (angle);
2536
2537   scrolled_window->priv->deceleration_id =
2538     gdk_threads_add_timeout_full (G_PRIORITY_DEFAULT,
2539                                   FRAME_INTERVAL,
2540                                   scrolled_window_deceleration_cb,
2541                                   data, (GDestroyNotify) g_free);
2542 }
2543
2544 static gboolean
2545 gtk_scrolled_window_release_captured_event (GtkScrolledWindow *scrolled_window)
2546 {
2547   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
2548
2549   /* Cancel the scrolling and send the button press
2550    * event to the child widget
2551    */
2552   if (!priv->button_press_event)
2553     return FALSE;
2554
2555   if (priv->drag_device)
2556     {
2557       gtk_device_grab_remove (GTK_WIDGET (scrolled_window), priv->drag_device);
2558       priv->drag_device = NULL;
2559     }
2560
2561   if (priv->capture_button_press)
2562     {
2563       GtkWidget *event_widget;
2564
2565       event_widget = gtk_get_event_widget (priv->button_press_event);
2566
2567       if (!_gtk_propagate_captured_event (event_widget,
2568                                           priv->button_press_event,
2569                                           gtk_bin_get_child (GTK_BIN (scrolled_window))))
2570         gtk_propagate_event (event_widget, priv->button_press_event);
2571
2572       gdk_event_free (priv->button_press_event);
2573       priv->button_press_event = NULL;
2574     }
2575
2576   if (_gtk_scrolled_window_get_overshoot (scrolled_window, NULL, NULL))
2577     gtk_scrolled_window_start_deceleration (scrolled_window);
2578
2579   return FALSE;
2580 }
2581
2582 static gboolean
2583 gtk_scrolled_window_calculate_velocity (GtkScrolledWindow *scrolled_window,
2584                                         GdkEvent          *event)
2585 {
2586   GtkScrolledWindowPrivate *priv;
2587   gdouble x_root, y_root;
2588   guint32 _time;
2589
2590 #define STILL_THRESHOLD 40
2591
2592   if (!gdk_event_get_root_coords (event, &x_root, &y_root))
2593     return FALSE;
2594
2595   priv = scrolled_window->priv;
2596   _time = gdk_event_get_time (event);
2597
2598   if (priv->last_motion_event_x_root != x_root ||
2599       priv->last_motion_event_y_root != y_root ||
2600       ABS (_time - priv->last_motion_event_time) > STILL_THRESHOLD)
2601     {
2602       priv->x_velocity = (priv->last_motion_event_x_root - x_root) /
2603         (gdouble) (_time - priv->last_motion_event_time);
2604       priv->y_velocity = (priv->last_motion_event_y_root - y_root) /
2605         (gdouble) (_time - priv->last_motion_event_time);
2606     }
2607
2608   priv->last_motion_event_x_root = x_root;
2609   priv->last_motion_event_y_root = y_root;
2610   priv->last_motion_event_time = _time;
2611
2612 #undef STILL_THRESHOLD
2613
2614   return TRUE;
2615 }
2616
2617 static gboolean
2618 gtk_scrolled_window_captured_button_release (GtkWidget *widget,
2619                                              GdkEvent  *event)
2620 {
2621   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
2622   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
2623   GtkWidget *child;
2624   gboolean overshoot;
2625   guint button;
2626   gdouble x_root, y_root;
2627
2628   if (gdk_event_get_button (event, &button) && button != 1)
2629     return FALSE;
2630
2631   child = gtk_bin_get_child (GTK_BIN (widget));
2632   if (!child)
2633     return FALSE;
2634
2635   gtk_device_grab_remove (widget, priv->drag_device);
2636   priv->drag_device = NULL;
2637
2638   if (priv->release_timeout_id)
2639     {
2640       g_source_remove (priv->release_timeout_id);
2641       priv->release_timeout_id = 0;
2642     }
2643
2644   overshoot = _gtk_scrolled_window_get_overshoot (scrolled_window, NULL, NULL);
2645
2646   if (priv->in_drag)
2647     gdk_device_ungrab (gdk_event_get_device (event), gdk_event_get_time (event));
2648   else
2649     {
2650       /* There hasn't been scrolling at all, so just let the
2651        * child widget handle the button press normally
2652        */
2653       gtk_scrolled_window_release_captured_event (scrolled_window);
2654
2655       if (!overshoot)
2656         return FALSE;
2657     }
2658   priv->in_drag = FALSE;
2659
2660   if (priv->button_press_event)
2661     {
2662       gdk_event_free (priv->button_press_event);
2663       priv->button_press_event = NULL;
2664     }
2665
2666   gtk_scrolled_window_calculate_velocity (scrolled_window, event);
2667
2668   /* Zero out vector components without a visible scrollbar */
2669   if (!priv->hscrollbar_visible)
2670     priv->x_velocity = 0;
2671   if (!priv->vscrollbar_visible)
2672     priv->y_velocity = 0;
2673
2674   if (priv->x_velocity != 0 || priv->y_velocity != 0 || overshoot)
2675     {
2676       gtk_scrolled_window_start_deceleration (scrolled_window);
2677       priv->x_velocity = priv->y_velocity = 0;
2678       priv->last_button_event_valid = FALSE;
2679     }
2680   else
2681     {
2682       gdk_event_get_root_coords (event, &x_root, &y_root);
2683       priv->last_button_event_x_root = x_root;
2684       priv->last_button_event_y_root = y_root;
2685       priv->last_button_event_valid = TRUE;
2686     }
2687
2688   if (priv->capture_button_press)
2689     return TRUE;
2690   else
2691     return FALSE;
2692 }
2693
2694 static gboolean
2695 gtk_scrolled_window_captured_motion_notify (GtkWidget *widget,
2696                                             GdkEvent  *event)
2697 {
2698   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
2699   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
2700   gint old_overshoot_x, old_overshoot_y;
2701   gint new_overshoot_x, new_overshoot_y;
2702   GtkWidget *child;
2703   GtkAdjustment *hadjustment;
2704   GtkAdjustment *vadjustment;
2705   gdouble dx, dy;
2706   GdkModifierType state;
2707   gdouble x_root, y_root;
2708
2709   gdk_event_get_state (event, &state);
2710   if (!(state & GDK_BUTTON1_MASK))
2711     return FALSE;
2712
2713   child = gtk_bin_get_child (GTK_BIN (widget));
2714   if (!child)
2715     return FALSE;
2716
2717   /* Check if we've passed the drag threshold */
2718   gdk_event_get_root_coords (event, &x_root, &y_root);
2719   if (!priv->in_drag)
2720     {
2721       if (gtk_drag_check_threshold (widget,
2722                                     priv->last_button_event_x_root,
2723                                     priv->last_button_event_y_root,
2724                                     x_root, y_root))
2725         {
2726           if (priv->release_timeout_id)
2727             {
2728               g_source_remove (priv->release_timeout_id);
2729               priv->release_timeout_id = 0;
2730             }
2731
2732           priv->last_button_event_valid = FALSE;
2733           priv->in_drag = TRUE;
2734         }
2735       else
2736         return TRUE;
2737     }
2738
2739   gdk_device_grab (priv->drag_device,
2740                    gtk_widget_get_window (widget),
2741                    GDK_OWNERSHIP_WINDOW,
2742                    TRUE,
2743                    GDK_BUTTON_RELEASE_MASK | GDK_BUTTON1_MOTION_MASK,
2744                    NULL,
2745                    gdk_event_get_time (event));
2746
2747   priv->last_button_event_valid = FALSE;
2748
2749   if (priv->button_press_event)
2750     {
2751       gdk_event_free (priv->button_press_event);
2752       priv->button_press_event = NULL;
2753     }
2754
2755   _gtk_scrolled_window_get_overshoot (scrolled_window,
2756                                       &old_overshoot_x, &old_overshoot_y);
2757
2758   hadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
2759   if (hadjustment && priv->hscrollbar_visible)
2760     {
2761       dx = (priv->last_motion_event_x_root - x_root) + priv->unclamped_hadj_value;
2762       _gtk_scrolled_window_set_adjustment_value (scrolled_window, hadjustment,
2763                                                  dx, TRUE, FALSE);
2764     }
2765
2766   vadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar));
2767   if (vadjustment && priv->vscrollbar_visible)
2768     {
2769       dy = (priv->last_motion_event_y_root - y_root) + priv->unclamped_vadj_value;
2770       _gtk_scrolled_window_set_adjustment_value (scrolled_window, vadjustment,
2771                                                  dy, TRUE, FALSE);
2772     }
2773
2774   _gtk_scrolled_window_get_overshoot (scrolled_window,
2775                                       &new_overshoot_x, &new_overshoot_y);
2776
2777   if (old_overshoot_x != new_overshoot_x ||
2778       old_overshoot_y != new_overshoot_y)
2779     {
2780       if (new_overshoot_x >= 0 || new_overshoot_y >= 0)
2781         {
2782           /* We need to reallocate the widget to have it at
2783            * negative offset, so there's a "gravity" on the
2784            * bottom/right corner
2785            */
2786           gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
2787         }
2788       else if (new_overshoot_x < 0 || new_overshoot_y < 0)
2789         _gtk_scrolled_window_allocate_overshoot_window (scrolled_window);
2790     }
2791
2792   gtk_scrolled_window_calculate_velocity (scrolled_window, event);
2793
2794   return TRUE;
2795 }
2796
2797 static gboolean
2798 gtk_scrolled_window_captured_button_press (GtkWidget *widget,
2799                                            GdkEvent  *event)
2800 {
2801   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
2802   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
2803   GtkWidget *child;
2804   GtkWidget *event_widget;
2805   GdkDevice *source_device;
2806   GdkInputSource source;
2807   gdouble x_root, y_root;
2808   guint button;
2809
2810   /* If scrollbars are not visible, we don't do kinetic scrolling */
2811   if (!priv->vscrollbar_visible && !priv->hscrollbar_visible)
2812     return FALSE;
2813
2814   source_device = gdk_event_get_source_device (event);
2815   source = gdk_device_get_source (source_device);
2816
2817   if (source != GDK_SOURCE_TOUCHSCREEN)
2818     return FALSE;
2819
2820   event_widget = gtk_get_event_widget (event);
2821
2822   /* If there's another scrolled window between the widget
2823    * receiving the event and this capturing scrolled window,
2824    * let it handle the events.
2825    */
2826   if (widget != gtk_widget_get_ancestor (event_widget, GTK_TYPE_SCROLLED_WINDOW))
2827     return FALSE;
2828
2829   /* Check whether the button press is close to the previous one,
2830    * take that as a shortcut to get the child widget handle events
2831    */
2832   gdk_event_get_root_coords (event, &x_root, &y_root);
2833   if (priv->last_button_event_valid &&
2834       ABS (x_root - priv->last_button_event_x_root) < TOUCH_BYPASS_CAPTURED_THRESHOLD &&
2835       ABS (y_root - priv->last_button_event_y_root) < TOUCH_BYPASS_CAPTURED_THRESHOLD)
2836     {
2837       priv->last_button_event_valid = FALSE;
2838       return FALSE;
2839     }
2840
2841   priv->last_button_event_x_root = priv->last_motion_event_x_root = x_root;
2842   priv->last_button_event_y_root = priv->last_motion_event_y_root = y_root;
2843   priv->last_motion_event_time = gdk_event_get_time (event);
2844   priv->last_button_event_valid = TRUE;
2845
2846   if (gdk_event_get_button (event, &button) && button != 1)
2847     return FALSE;
2848
2849   child = gtk_bin_get_child (GTK_BIN (widget));
2850   if (!child)
2851     return FALSE;
2852
2853   if (priv->hscrollbar == event_widget || priv->vscrollbar == event_widget)
2854     return FALSE;
2855
2856   priv->drag_device = gdk_event_get_device (event);
2857   gtk_device_grab_add (widget, priv->drag_device, TRUE);
2858
2859   gtk_scrolled_window_cancel_deceleration (scrolled_window);
2860
2861   /* Only set the timeout if we're going to store an event */
2862   if (priv->capture_button_press)
2863     priv->release_timeout_id =
2864       gdk_threads_add_timeout (RELEASE_EVENT_TIMEOUT,
2865                                (GSourceFunc) gtk_scrolled_window_release_captured_event,
2866                                scrolled_window);
2867
2868   priv->in_drag = FALSE;
2869
2870   if (priv->capture_button_press)
2871     {
2872       /* Store the button press event in
2873        * case we need to propagate it later
2874        */
2875       priv->button_press_event = gdk_event_copy (event);
2876       return TRUE;
2877     }
2878   else
2879     return FALSE;
2880 }
2881
2882 static gboolean
2883 gtk_scrolled_window_captured_event (GtkWidget *widget,
2884                                     GdkEvent  *event)
2885 {
2886   gboolean retval = FALSE;
2887   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW (widget)->priv;
2888
2889   if (gdk_window_get_window_type (event->any.window) == GDK_WINDOW_TEMP)
2890     return FALSE;
2891
2892   switch (event->type)
2893     {
2894     case GDK_TOUCH_BEGIN:
2895     case GDK_BUTTON_PRESS:
2896       retval = gtk_scrolled_window_captured_button_press (widget, event);
2897       break;
2898     case GDK_TOUCH_END:
2899     case GDK_BUTTON_RELEASE:
2900       if (priv->drag_device)
2901         retval = gtk_scrolled_window_captured_button_release (widget, event);
2902       else
2903         priv->last_button_event_valid = FALSE;
2904       break;
2905     case GDK_TOUCH_UPDATE:
2906     case GDK_MOTION_NOTIFY:
2907       if (priv->drag_device)
2908         retval = gtk_scrolled_window_captured_motion_notify (widget, event);
2909       break;
2910     case GDK_LEAVE_NOTIFY:
2911     case GDK_ENTER_NOTIFY:
2912       if (priv->in_drag &&
2913           event->crossing.mode != GDK_CROSSING_GRAB)
2914         retval = TRUE;
2915       break;
2916     default:
2917       break;
2918     }
2919
2920   return retval;
2921 }
2922
2923 static gboolean
2924 gtk_scrolled_window_focus (GtkWidget        *widget,
2925                            GtkDirectionType  direction)
2926 {
2927   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
2928   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
2929   GtkWidget *child;
2930   gboolean had_focus_child;
2931
2932   had_focus_child = gtk_container_get_focus_child (GTK_CONTAINER (widget)) != NULL;
2933
2934   if (priv->focus_out)
2935     {
2936       priv->focus_out = FALSE; /* Clear this to catch the wrap-around case */
2937       return FALSE;
2938     }
2939   
2940   if (gtk_widget_is_focus (widget))
2941     return FALSE;
2942
2943   /* We only put the scrolled window itself in the focus chain if it
2944    * isn't possible to focus any children.
2945    */
2946   child = gtk_bin_get_child (GTK_BIN (widget));
2947   if (child)
2948     {
2949       if (gtk_widget_child_focus (child, direction))
2950         return TRUE;
2951     }
2952
2953   if (!had_focus_child && gtk_widget_get_can_focus (widget))
2954     {
2955       gtk_widget_grab_focus (widget);
2956       return TRUE;
2957     }
2958   else
2959     return FALSE;
2960 }
2961
2962 static void
2963 gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment,
2964                                         gpointer       data)
2965 {
2966   GtkScrolledWindowPrivate *priv;
2967   GtkScrolledWindow *scrolled_window;
2968
2969   g_return_if_fail (adjustment != NULL);
2970   g_return_if_fail (data != NULL);
2971
2972   scrolled_window = GTK_SCROLLED_WINDOW (data);
2973   priv = scrolled_window->priv;
2974
2975   if (priv->hscrollbar &&
2976       adjustment == gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar)))
2977     {
2978       if (priv->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
2979         {
2980           gboolean visible;
2981
2982           visible = priv->hscrollbar_visible;
2983           priv->hscrollbar_visible = (gtk_adjustment_get_upper (adjustment) - gtk_adjustment_get_lower (adjustment) >
2984                                       gtk_adjustment_get_page_size (adjustment));
2985
2986           if (priv->hscrollbar_visible != visible)
2987             gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
2988         }
2989     }
2990   else if (priv->vscrollbar &&
2991            adjustment == gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)))
2992     {
2993       if (priv->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
2994         {
2995           gboolean visible;
2996
2997           visible = priv->vscrollbar_visible;
2998           priv->vscrollbar_visible = (gtk_adjustment_get_upper (adjustment) - gtk_adjustment_get_lower (adjustment) >
2999                                       gtk_adjustment_get_page_size (adjustment));
3000
3001           if (priv->vscrollbar_visible != visible)
3002             gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
3003         }
3004     }
3005 }
3006
3007 static void
3008 gtk_scrolled_window_adjustment_value_changed (GtkAdjustment *adjustment,
3009                                               gpointer       user_data)
3010 {
3011   GtkScrolledWindow *scrolled_window = user_data;
3012   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
3013
3014   /* Allow overshooting for kinetic scrolling operations */
3015   if (priv->drag_device || priv->deceleration_id)
3016     return;
3017
3018   /* Ensure GtkAdjustment and unclamped values are in sync */
3019   if (priv->vscrollbar &&
3020       adjustment == gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)))
3021     priv->unclamped_vadj_value = gtk_adjustment_get_value (adjustment);
3022   else if (priv->hscrollbar &&
3023            adjustment == gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar)))
3024     priv->unclamped_hadj_value = gtk_adjustment_get_value (adjustment);
3025 }
3026
3027 static void
3028 gtk_scrolled_window_add (GtkContainer *container,
3029                          GtkWidget    *child)
3030 {
3031   GtkScrolledWindowPrivate *priv;
3032   GtkScrolledWindow *scrolled_window;
3033   GtkBin *bin;
3034   GtkWidget *child_widget;
3035   GtkAdjustment *hadj, *vadj;
3036
3037   bin = GTK_BIN (container);
3038   child_widget = gtk_bin_get_child (bin);
3039   g_return_if_fail (child_widget == NULL);
3040
3041   scrolled_window = GTK_SCROLLED_WINDOW (container);
3042   priv = scrolled_window->priv;
3043
3044   if (gtk_widget_get_realized (GTK_WIDGET (bin)))
3045     gtk_widget_set_parent_window (child, priv->overshoot_window);
3046
3047   _gtk_bin_set_child (bin, child);
3048   gtk_widget_set_parent (child, GTK_WIDGET (bin));
3049
3050   hadj = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
3051   vadj = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar));
3052
3053   if (GTK_IS_SCROLLABLE (child))
3054     g_object_set (child, "hadjustment", hadj, "vadjustment", vadj, NULL);
3055   else
3056     g_warning ("gtk_scrolled_window_add(): cannot add non scrollable widget "
3057                "use gtk_scrolled_window_add_with_viewport() instead");
3058 }
3059
3060 static void
3061 gtk_scrolled_window_remove (GtkContainer *container,
3062                             GtkWidget    *child)
3063 {
3064   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
3065   g_return_if_fail (child != NULL);
3066   g_return_if_fail (gtk_bin_get_child (GTK_BIN (container)) == child);
3067
3068   g_object_set (child, "hadjustment", NULL, "vadjustment", NULL, NULL);
3069
3070   /* chain parent class handler to remove child */
3071   GTK_CONTAINER_CLASS (gtk_scrolled_window_parent_class)->remove (container, child);
3072 }
3073
3074 /**
3075  * gtk_scrolled_window_add_with_viewport:
3076  * @scrolled_window: a #GtkScrolledWindow
3077  * @child: the widget you want to scroll
3078  *
3079  * Used to add children without native scrolling capabilities. This
3080  * is simply a convenience function; it is equivalent to adding the
3081  * unscrollable child to a viewport, then adding the viewport to the
3082  * scrolled window. If a child has native scrolling, use
3083  * gtk_container_add() instead of this function.
3084  *
3085  * The viewport scrolls the child by moving its #GdkWindow, and takes
3086  * the size of the child to be the size of its toplevel #GdkWindow. 
3087  * This will be very wrong for most widgets that support native scrolling;
3088  * for example, if you add a widget such as #GtkTreeView with a viewport,
3089  * the whole widget will scroll, including the column headings. Thus, 
3090  * widgets with native scrolling support should not be used with the 
3091  * #GtkViewport proxy.
3092  *
3093  * A widget supports scrolling natively if it implements the
3094  * #GtkScrollable interface.
3095  */
3096 void
3097 gtk_scrolled_window_add_with_viewport (GtkScrolledWindow *scrolled_window,
3098                                        GtkWidget         *child)
3099 {
3100   GtkBin *bin;
3101   GtkWidget *viewport;
3102   GtkWidget *child_widget;
3103
3104   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
3105   g_return_if_fail (GTK_IS_WIDGET (child));
3106   g_return_if_fail (gtk_widget_get_parent (child) == NULL);
3107
3108   bin = GTK_BIN (scrolled_window);
3109   child_widget = gtk_bin_get_child (bin);
3110
3111   if (child_widget)
3112     {
3113       g_return_if_fail (GTK_IS_VIEWPORT (child_widget));
3114       g_return_if_fail (gtk_bin_get_child (GTK_BIN (child_widget)) == NULL);
3115
3116       viewport = child_widget;
3117     }
3118   else
3119     {
3120       viewport =
3121         gtk_viewport_new (gtk_scrolled_window_get_hadjustment (scrolled_window),
3122                           gtk_scrolled_window_get_vadjustment (scrolled_window));
3123       gtk_container_add (GTK_CONTAINER (scrolled_window), viewport);
3124     }
3125
3126   gtk_widget_show (viewport);
3127   gtk_container_add (GTK_CONTAINER (viewport), child);
3128 }
3129
3130 /*
3131  * _gtk_scrolled_window_get_spacing:
3132  * @scrolled_window: a scrolled window
3133  * 
3134  * Gets the spacing between the scrolled window's scrollbars and
3135  * the scrolled widget. Used by GtkCombo
3136  * 
3137  * Return value: the spacing, in pixels.
3138  */
3139 gint
3140 _gtk_scrolled_window_get_scrollbar_spacing (GtkScrolledWindow *scrolled_window)
3141 {
3142   GtkScrolledWindowClass *class;
3143     
3144   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), 0);
3145
3146   class = GTK_SCROLLED_WINDOW_GET_CLASS (scrolled_window);
3147
3148   if (class->scrollbar_spacing >= 0)
3149     return class->scrollbar_spacing;
3150   else
3151     {
3152       gint scrollbar_spacing;
3153       
3154       gtk_widget_style_get (GTK_WIDGET (scrolled_window),
3155                             "scrollbar-spacing", &scrollbar_spacing,
3156                             NULL);
3157
3158       return scrollbar_spacing;
3159     }
3160 }
3161
3162
3163 static void
3164 gtk_scrolled_window_get_preferred_size (GtkWidget      *widget,
3165                                         GtkOrientation  orientation,
3166                                         gint           *minimum_size,
3167                                         gint           *natural_size)
3168 {
3169   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
3170   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
3171   GtkBin *bin = GTK_BIN (scrolled_window);
3172   gint extra_width;
3173   gint extra_height;
3174   gint scrollbar_spacing;
3175   GtkRequisition hscrollbar_requisition;
3176   GtkRequisition vscrollbar_requisition;
3177   GtkRequisition minimum_req, natural_req;
3178   GtkWidget *child;
3179   gint min_child_size, nat_child_size;
3180
3181   scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
3182
3183   extra_width = 0;
3184   extra_height = 0;
3185   minimum_req.width = 0;
3186   minimum_req.height = 0;
3187   natural_req.width = 0;
3188   natural_req.height = 0;
3189
3190   gtk_widget_get_preferred_size (priv->hscrollbar,
3191                                  &hscrollbar_requisition, NULL);
3192   gtk_widget_get_preferred_size (priv->vscrollbar,
3193                                  &vscrollbar_requisition, NULL);
3194
3195   child = gtk_bin_get_child (bin);
3196   if (child && gtk_widget_get_visible (child))
3197     {
3198       if (orientation == GTK_ORIENTATION_HORIZONTAL)
3199         {
3200           gtk_widget_get_preferred_width (child,
3201                                           &min_child_size,
3202                                           &nat_child_size);
3203
3204           if (priv->hscrollbar_policy == GTK_POLICY_NEVER)
3205             {
3206               minimum_req.width += min_child_size;
3207               natural_req.width += nat_child_size;
3208             }
3209           else
3210             {
3211               gint min_content_width = priv->min_content_width;
3212
3213               if (min_content_width >= 0)
3214                 {
3215                   minimum_req.width = MAX (minimum_req.width, min_content_width);
3216                   natural_req.width = MAX (natural_req.width, min_content_width);
3217                   extra_width = -1;
3218                 }
3219               else
3220                 {
3221                   minimum_req.width += vscrollbar_requisition.width;
3222                   natural_req.width += vscrollbar_requisition.width;
3223                 }
3224             }
3225         }
3226       else /* GTK_ORIENTATION_VERTICAL */
3227         {
3228           gtk_widget_get_preferred_height (child,
3229                                            &min_child_size,
3230                                            &nat_child_size);
3231
3232           if (priv->vscrollbar_policy == GTK_POLICY_NEVER)
3233             {
3234               minimum_req.height += min_child_size;
3235               natural_req.height += nat_child_size;
3236             }
3237           else
3238             {
3239               gint min_content_height = priv->min_content_height;
3240
3241               if (min_content_height >= 0)
3242                 {
3243                   minimum_req.height = MAX (minimum_req.height, min_content_height);
3244                   natural_req.height = MAX (natural_req.height, min_content_height);
3245                   extra_height = -1;
3246                 }
3247               else
3248                 {
3249                   minimum_req.height += vscrollbar_requisition.height;
3250                   natural_req.height += vscrollbar_requisition.height;
3251                 }
3252             }
3253         }
3254     }
3255
3256   if (priv->hscrollbar_policy == GTK_POLICY_AUTOMATIC ||
3257       priv->hscrollbar_policy == GTK_POLICY_ALWAYS)
3258     {
3259       minimum_req.width = MAX (minimum_req.width, hscrollbar_requisition.width);
3260       natural_req.width = MAX (natural_req.width, hscrollbar_requisition.width);
3261       if (!extra_height || priv->hscrollbar_policy == GTK_POLICY_ALWAYS)
3262         extra_height = scrollbar_spacing + hscrollbar_requisition.height;
3263     }
3264
3265   if (priv->vscrollbar_policy == GTK_POLICY_AUTOMATIC ||
3266       priv->vscrollbar_policy == GTK_POLICY_ALWAYS)
3267     {
3268       minimum_req.height = MAX (minimum_req.height, vscrollbar_requisition.height);
3269       natural_req.height = MAX (natural_req.height, vscrollbar_requisition.height);
3270       if (!extra_width || priv->vscrollbar_policy == GTK_POLICY_ALWAYS)
3271         extra_width = scrollbar_spacing + vscrollbar_requisition.width;
3272     }
3273
3274   minimum_req.width  += MAX (0, extra_width);
3275   minimum_req.height += MAX (0, extra_height);
3276   natural_req.width  += MAX (0, extra_width);
3277   natural_req.height += MAX (0, extra_height);
3278
3279   if (priv->shadow_type != GTK_SHADOW_NONE)
3280     {
3281       GtkStyleContext *context;
3282       GtkStateFlags state;
3283       GtkBorder padding, border;
3284
3285       context = gtk_widget_get_style_context (GTK_WIDGET (widget));
3286       state = gtk_widget_get_state_flags (GTK_WIDGET (widget));
3287
3288       gtk_style_context_save (context);
3289       gtk_style_context_add_class (context, GTK_STYLE_CLASS_FRAME);
3290
3291       gtk_style_context_get_padding (context, state, &padding);
3292       gtk_style_context_get_border (context, state, &border);
3293
3294       minimum_req.width += padding.left + padding.right + border.left + border.right;
3295       minimum_req.height += padding.top + padding.bottom + border.top + border.bottom;
3296       natural_req.width += padding.left + padding.right + border.left + border.right;
3297       natural_req.height += padding.top + padding.bottom + border.top + border.bottom;
3298
3299       gtk_style_context_restore (context);
3300     }
3301
3302   if (orientation == GTK_ORIENTATION_HORIZONTAL)
3303     {
3304       if (minimum_size)
3305         *minimum_size = minimum_req.width;
3306       if (natural_size)
3307         *natural_size = natural_req.width;
3308     }
3309   else
3310     {
3311       if (minimum_size)
3312         *minimum_size = minimum_req.height;
3313       if (natural_size)
3314         *natural_size = natural_req.height;
3315     }
3316 }
3317
3318 static void     
3319 gtk_scrolled_window_get_preferred_width (GtkWidget *widget,
3320                                          gint      *minimum_size,
3321                                          gint      *natural_size)
3322 {
3323   gtk_scrolled_window_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size);
3324 }
3325
3326 static void
3327 gtk_scrolled_window_get_preferred_height (GtkWidget *widget,
3328                                           gint      *minimum_size,
3329                                           gint      *natural_size)
3330 {  
3331   gtk_scrolled_window_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size);
3332 }
3333
3334 static void
3335 gtk_scrolled_window_get_preferred_height_for_width (GtkWidget *widget,
3336                                                     gint       width,
3337                                                     gint      *minimum_height,
3338                                                     gint      *natural_height)
3339 {
3340   g_return_if_fail (GTK_IS_WIDGET (widget));
3341
3342   GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, minimum_height, natural_height);
3343 }
3344
3345 static void
3346 gtk_scrolled_window_get_preferred_width_for_height (GtkWidget *widget,
3347                                                     gint       height,
3348                                                     gint      *minimum_width,
3349                                                     gint      *natural_width)
3350 {
3351   g_return_if_fail (GTK_IS_WIDGET (widget));
3352
3353   GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, minimum_width, natural_width);
3354 }
3355
3356 static void
3357 gtk_scrolled_window_realize (GtkWidget *widget)
3358 {
3359   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
3360   GtkAllocation allocation, relative_allocation;
3361   GdkWindowAttr attributes;
3362   GtkWidget *child_widget;
3363   gint attributes_mask;
3364
3365   gtk_widget_set_realized (widget, TRUE);
3366   gtk_widget_get_allocation (widget, &allocation);
3367   gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
3368
3369   attributes.window_type = GDK_WINDOW_CHILD;
3370   attributes.x = allocation.x + relative_allocation.x;
3371   attributes.y = allocation.y + relative_allocation.y;
3372   attributes.width = allocation.width;
3373   attributes.height = allocation.height;
3374   attributes.wclass = GDK_INPUT_OUTPUT;
3375   attributes.visual = gtk_widget_get_visual (widget);
3376   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK |
3377     GDK_BUTTON_MOTION_MASK | GDK_TOUCH_MASK | GDK_EXPOSURE_MASK;
3378
3379   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3380
3381   scrolled_window->priv->overshoot_window =
3382     gdk_window_new (gtk_widget_get_parent_window (widget),
3383                     &attributes, attributes_mask);
3384   gdk_window_set_user_data (scrolled_window->priv->overshoot_window, widget);
3385
3386   child_widget = gtk_bin_get_child (GTK_BIN (widget));
3387
3388   if (child_widget)
3389     gtk_widget_set_parent_window (child_widget,
3390                                   scrolled_window->priv->overshoot_window);
3391
3392   GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->realize (widget);
3393 }
3394
3395 static void
3396 gtk_scrolled_window_unrealize (GtkWidget *widget)
3397 {
3398   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
3399
3400   gdk_window_set_user_data (scrolled_window->priv->overshoot_window, NULL);
3401   gdk_window_destroy (scrolled_window->priv->overshoot_window);
3402   scrolled_window->priv->overshoot_window = NULL;
3403
3404   gtk_widget_set_realized (widget, FALSE);
3405
3406   GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->unrealize (widget);
3407 }
3408
3409 static void
3410 gtk_scrolled_window_map (GtkWidget *widget)
3411 {
3412   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
3413
3414   gdk_window_show (scrolled_window->priv->overshoot_window);
3415
3416   GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->map (widget);
3417 }
3418
3419 static void
3420 gtk_scrolled_window_unmap (GtkWidget *widget)
3421 {
3422   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
3423
3424   gdk_window_hide (scrolled_window->priv->overshoot_window);
3425
3426   GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->unmap (widget);
3427 }
3428
3429 static void
3430 gtk_scrolled_window_grab_notify (GtkWidget *widget,
3431                                  gboolean   was_grabbed)
3432 {
3433   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
3434   GtkScrolledWindowPrivate *priv = scrolled_window->priv;
3435
3436   if (priv->drag_device &&
3437       gtk_widget_device_is_shadowed (widget,
3438                                      priv->drag_device))
3439     {
3440       gdk_device_ungrab (priv->drag_device,
3441                          gtk_get_current_event_time ());
3442       priv->drag_device = NULL;
3443       priv->in_drag = FALSE;
3444
3445       if (priv->release_timeout_id)
3446         {
3447           g_source_remove (priv->release_timeout_id);
3448           priv->release_timeout_id = 0;
3449         }
3450
3451       if (_gtk_scrolled_window_get_overshoot (scrolled_window, NULL, NULL))
3452         gtk_scrolled_window_start_deceleration (scrolled_window);
3453       else
3454         gtk_scrolled_window_cancel_deceleration (scrolled_window);
3455
3456       priv->last_button_event_valid = FALSE;
3457     }
3458 }
3459
3460 /**
3461  * gtk_scrolled_window_get_min_content_width:
3462  * @scrolled_window: a #GtkScrolledWindow
3463  *
3464  * Gets the minimum content width of @scrolled_window, or -1 if not set.
3465  *
3466  * Returns: the minimum content width
3467  *
3468  * Since: 3.0
3469  */
3470 gint
3471 gtk_scrolled_window_get_min_content_width (GtkScrolledWindow *scrolled_window)
3472 {
3473   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), 0);
3474
3475   return scrolled_window->priv->min_content_width;
3476 }
3477
3478 /**
3479  * gtk_scrolled_window_set_min_content_width:
3480  * @scrolled_window: a #GtkScrolledWindow
3481  * @width: the minimal content width
3482  *
3483  * Sets the minimum width that @scrolled_window should keep visible.
3484  * Note that this can and (usually will) be smaller than the minimum
3485  * size of the content.
3486  *
3487  * Since: 3.0
3488  */
3489 void
3490 gtk_scrolled_window_set_min_content_width (GtkScrolledWindow *scrolled_window,
3491                                            gint               width)
3492 {
3493   GtkScrolledWindowPrivate *priv;
3494
3495   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
3496
3497   priv = scrolled_window->priv;
3498
3499   if (priv->min_content_width != width)
3500     {
3501       priv->min_content_width = width;
3502
3503       gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
3504
3505       g_object_notify (G_OBJECT (scrolled_window), "min-content-width");
3506     }
3507 }
3508
3509 /**
3510  * gtk_scrolled_window_get_min_content_height:
3511  * @scrolled_window: a #GtkScrolledWindow
3512  *
3513  * Gets the minimal content height of @scrolled_window, or -1 if not set.
3514  *
3515  * Returns: the minimal content height
3516  *
3517  * Since: 3.0
3518  */
3519 gint
3520 gtk_scrolled_window_get_min_content_height (GtkScrolledWindow *scrolled_window)
3521 {
3522   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), 0);
3523
3524   return scrolled_window->priv->min_content_height;
3525 }
3526
3527 /**
3528  * gtk_scrolled_window_set_min_content_height:
3529  * @scrolled_window: a #GtkScrolledWindow
3530  * @height: the minimal content height
3531  *
3532  * Sets the minimum height that @scrolled_window should keep visible.
3533  * Note that this can and (usually will) be smaller than the minimum
3534  * size of the content.
3535  *
3536  * Since: 3.0
3537  */
3538 void
3539 gtk_scrolled_window_set_min_content_height (GtkScrolledWindow *scrolled_window,
3540                                             gint               height)
3541 {
3542   GtkScrolledWindowPrivate *priv;
3543
3544   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
3545
3546   priv = scrolled_window->priv;
3547
3548   if (priv->min_content_height != height)
3549     {
3550       priv->min_content_height = height;
3551
3552       gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
3553
3554       g_object_notify (G_OBJECT (scrolled_window), "min-content-height");
3555     }
3556 }