]> Pileus Git - ~andy/gtk/blob - gtk/gtkscrolledwindow.c
Don't use GTK_WIDGET_*SET_FLAGS (wid, GTK_CAN_FOCUS)
[~andy/gtk] / gtk / gtkscrolledwindow.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
25  */
26
27 #include "config.h"
28 #include <math.h>
29 #include <gdk/gdkkeysyms.h>
30 #include "gtkbindings.h"
31 #include "gtkextendedlayout.h"
32 #include "gtkmarshalers.h"
33 #include "gtkscrolledwindow.h"
34 #include "gtkwindow.h"
35 #include "gtkprivate.h"
36 #include "gtkintl.h"
37 #include "gtkalias.h"
38
39
40 /* scrolled window policy and size requisition handling:
41  *
42  * gtk size requisition works as follows:
43  *   a widget upon size-request reports the width and height that it finds
44  *   to be best suited to display its contents, including children.
45  *   the width and/or height reported from a widget upon size requisition
46  *   may be overidden by the user by specifying a width and/or height
47  *   other than 0 through gtk_widget_set_size_request().
48  *
49  * a scrolled window needs (for implementing all three policy types) to
50  * request its width and height based on two different rationales.
51  * 1)   the user wants the scrolled window to just fit into the space
52  *      that it gets allocated for a specifc dimension.
53  * 1.1) this does not apply if the user specified a concrete value
54  *      value for that specific dimension by either specifying usize for the
55  *      scrolled window or for its child.
56  * 2)   the user wants the scrolled window to take as much space up as
57  *      is desired by the child for a specifc dimension (i.e. POLICY_NEVER).
58  *
59  * also, kinda obvious:
60  * 3)   a user would certainly not have choosen a scrolled window as a container
61  *      for the child, if the resulting allocation takes up more space than the
62  *      child would have allocated without the scrolled window.
63  *
64  * conclusions:
65  * A) from 1) follows: the scrolled window shouldn't request more space for a
66  *    specifc dimension than is required at minimum.
67  * B) from 1.1) follows: the requisition may be overidden by usize of the scrolled
68  *    window (done automatically) or by usize of the child (needs to be checked).
69  * C) from 2) follows: for POLICY_NEVER, the scrolled window simply reports the
70  *    child's dimension.
71  * D) from 3) follows: the scrolled window child's minimum width and minimum height
72  *    under A) at least correspond to the space taken up by its scrollbars.
73  */
74
75 #define DEFAULT_SCROLLBAR_SPACING  3
76
77 typedef struct {
78         gboolean window_placement_set;
79         GtkCornerType real_window_placement;
80 } GtkScrolledWindowPrivate;
81
82 #define GTK_SCROLLED_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_SCROLLED_WINDOW, GtkScrolledWindowPrivate))
83
84 enum {
85   PROP_0,
86   PROP_HADJUSTMENT,
87   PROP_VADJUSTMENT,
88   PROP_HSCROLLBAR_POLICY,
89   PROP_VSCROLLBAR_POLICY,
90   PROP_WINDOW_PLACEMENT,
91   PROP_WINDOW_PLACEMENT_SET,
92   PROP_SHADOW_TYPE
93 };
94
95 /* Signals */
96 enum
97 {
98   SCROLL_CHILD,
99   MOVE_FOCUS_OUT,
100   LAST_SIGNAL
101 };
102
103 static void     gtk_scrolled_window_destroy            (GtkObject         *object);
104 static void     gtk_scrolled_window_set_property       (GObject           *object,
105                                                         guint              prop_id,
106                                                         const GValue      *value,
107                                                         GParamSpec        *pspec);
108 static void     gtk_scrolled_window_get_property       (GObject           *object,
109                                                         guint              prop_id,
110                                                         GValue            *value,
111                                                         GParamSpec        *pspec);
112
113 static void     gtk_scrolled_window_screen_changed     (GtkWidget         *widget,
114                                                         GdkScreen         *previous_screen);
115 static gboolean gtk_scrolled_window_expose             (GtkWidget         *widget,
116                                                         GdkEventExpose    *event);
117 static void     gtk_scrolled_window_size_request       (GtkWidget         *widget,
118                                                         GtkRequisition    *requisition);
119 static void     gtk_scrolled_window_size_allocate      (GtkWidget         *widget,
120                                                         GtkAllocation     *allocation);
121 static gboolean gtk_scrolled_window_scroll_event       (GtkWidget         *widget,
122                                                         GdkEventScroll    *event);
123 static gboolean gtk_scrolled_window_focus              (GtkWidget         *widget,
124                                                         GtkDirectionType   direction);
125 static void     gtk_scrolled_window_add                (GtkContainer      *container,
126                                                         GtkWidget         *widget);
127 static void     gtk_scrolled_window_remove             (GtkContainer      *container,
128                                                         GtkWidget         *widget);
129 static void     gtk_scrolled_window_forall             (GtkContainer      *container,
130                                                         gboolean           include_internals,
131                                                         GtkCallback        callback,
132                                                         gpointer           callback_data);
133 static gboolean gtk_scrolled_window_scroll_child       (GtkScrolledWindow *scrolled_window,
134                                                         GtkScrollType      scroll,
135                                                         gboolean           horizontal);
136 static void     gtk_scrolled_window_move_focus_out     (GtkScrolledWindow *scrolled_window,
137                                                         GtkDirectionType   direction_type);
138
139 static void     gtk_scrolled_window_relative_allocation(GtkWidget         *widget,
140                                                         GtkAllocation     *allocation);
141 static void     gtk_scrolled_window_adjustment_changed (GtkAdjustment     *adjustment,
142                                                         gpointer           data);
143
144 static void  gtk_scrolled_window_update_real_placement (GtkScrolledWindow *scrolled_window);
145
146 static void  gtk_scrolled_window_extended_layout_init  (GtkExtendedLayoutIface *iface);
147
148 static guint signals[LAST_SIGNAL] = {0};
149
150 G_DEFINE_TYPE_WITH_CODE (GtkScrolledWindow, gtk_scrolled_window, GTK_TYPE_BIN,
151                          G_IMPLEMENT_INTERFACE (GTK_TYPE_EXTENDED_LAYOUT,
152                                                 gtk_scrolled_window_extended_layout_init))
153
154
155 static void
156 add_scroll_binding (GtkBindingSet  *binding_set,
157                     guint           keyval,
158                     GdkModifierType mask,
159                     GtkScrollType   scroll,
160                     gboolean        horizontal)
161 {
162   guint keypad_keyval = keyval - GDK_Left + GDK_KP_Left;
163   
164   gtk_binding_entry_add_signal (binding_set, keyval, mask,
165                                 "scroll-child", 2,
166                                 GTK_TYPE_SCROLL_TYPE, scroll,
167                                 G_TYPE_BOOLEAN, horizontal);
168   gtk_binding_entry_add_signal (binding_set, keypad_keyval, mask,
169                                 "scroll-child", 2,
170                                 GTK_TYPE_SCROLL_TYPE, scroll,
171                                 G_TYPE_BOOLEAN, horizontal);
172 }
173
174 static void
175 add_tab_bindings (GtkBindingSet    *binding_set,
176                   GdkModifierType   modifiers,
177                   GtkDirectionType  direction)
178 {
179   gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
180                                 "move-focus-out", 1,
181                                 GTK_TYPE_DIRECTION_TYPE, direction);
182   gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
183                                 "move-focus-out", 1,
184                                 GTK_TYPE_DIRECTION_TYPE, direction);
185 }
186
187 static void
188 gtk_scrolled_window_class_init (GtkScrolledWindowClass *class)
189 {
190   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
191   GtkObjectClass *object_class;
192   GtkWidgetClass *widget_class;
193   GtkContainerClass *container_class;
194   GtkBindingSet *binding_set;
195
196   object_class = (GtkObjectClass*) class;
197   widget_class = (GtkWidgetClass*) class;
198   container_class = (GtkContainerClass*) class;
199
200   gobject_class->set_property = gtk_scrolled_window_set_property;
201   gobject_class->get_property = gtk_scrolled_window_get_property;
202
203   object_class->destroy = gtk_scrolled_window_destroy;
204
205   widget_class->screen_changed = gtk_scrolled_window_screen_changed;
206   widget_class->expose_event = gtk_scrolled_window_expose;
207   widget_class->size_request = gtk_scrolled_window_size_request;
208   widget_class->size_allocate = gtk_scrolled_window_size_allocate;
209   widget_class->scroll_event = gtk_scrolled_window_scroll_event;
210   widget_class->focus = gtk_scrolled_window_focus;
211
212   container_class->add = gtk_scrolled_window_add;
213   container_class->remove = gtk_scrolled_window_remove;
214   container_class->forall = gtk_scrolled_window_forall;
215
216   class->scrollbar_spacing = -1;
217
218   class->scroll_child = gtk_scrolled_window_scroll_child;
219   class->move_focus_out = gtk_scrolled_window_move_focus_out;
220   
221   g_object_class_install_property (gobject_class,
222                                    PROP_HADJUSTMENT,
223                                    g_param_spec_object ("hadjustment",
224                                                         P_("Horizontal Adjustment"),
225                                                         P_("The GtkAdjustment for the horizontal position"),
226                                                         GTK_TYPE_ADJUSTMENT,
227                                                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
228   g_object_class_install_property (gobject_class,
229                                    PROP_VADJUSTMENT,
230                                    g_param_spec_object ("vadjustment",
231                                                         P_("Vertical Adjustment"),
232                                                         P_("The GtkAdjustment for the vertical position"),
233                                                         GTK_TYPE_ADJUSTMENT,
234                                                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
235   g_object_class_install_property (gobject_class,
236                                    PROP_HSCROLLBAR_POLICY,
237                                    g_param_spec_enum ("hscrollbar-policy",
238                                                       P_("Horizontal Scrollbar Policy"),
239                                                       P_("When the horizontal scrollbar is displayed"),
240                                                       GTK_TYPE_POLICY_TYPE,
241                                                       GTK_POLICY_ALWAYS,
242                                                       GTK_PARAM_READABLE | GTK_PARAM_WRITABLE));
243   g_object_class_install_property (gobject_class,
244                                    PROP_VSCROLLBAR_POLICY,
245                                    g_param_spec_enum ("vscrollbar-policy",
246                                                       P_("Vertical Scrollbar Policy"),
247                                                       P_("When the vertical scrollbar is displayed"),
248                                                       GTK_TYPE_POLICY_TYPE,
249                                                       GTK_POLICY_ALWAYS,
250                                                       GTK_PARAM_READABLE | GTK_PARAM_WRITABLE));
251
252   g_object_class_install_property (gobject_class,
253                                    PROP_WINDOW_PLACEMENT,
254                                    g_param_spec_enum ("window-placement",
255                                                       P_("Window Placement"),
256                                                       P_("Where the contents are located with respect to the scrollbars. This property only takes effect if \"window-placement-set\" is TRUE."),
257                                                       GTK_TYPE_CORNER_TYPE,
258                                                       GTK_CORNER_TOP_LEFT,
259                                                       GTK_PARAM_READABLE | GTK_PARAM_WRITABLE));
260   
261   /**
262    * GtkScrolledWindow:window-placement-set:
263    *
264    * Whether "window-placement" should be used to determine the location 
265    * of the contents with respect to the scrollbars. Otherwise, the 
266    * "gtk-scrolled-window-placement" setting is used.
267    *
268    * Since: 2.10
269    */
270   g_object_class_install_property (gobject_class,
271                                    PROP_WINDOW_PLACEMENT_SET,
272                                    g_param_spec_boolean ("window-placement-set",
273                                                          P_("Window Placement Set"),
274                                                          P_("Whether \"window-placement\" should be used to determine the location of the contents with respect to the scrollbars."),
275                                                          FALSE,
276                                                          GTK_PARAM_READABLE | GTK_PARAM_WRITABLE));
277   g_object_class_install_property (gobject_class,
278                                    PROP_SHADOW_TYPE,
279                                    g_param_spec_enum ("shadow-type",
280                                                       P_("Shadow Type"),
281                                                       P_("Style of bevel around the contents"),
282                                                       GTK_TYPE_SHADOW_TYPE,
283                                                       GTK_SHADOW_NONE,
284                                                       GTK_PARAM_READABLE | GTK_PARAM_WRITABLE));
285
286   /**
287    * GtkScrolledWindow:scrollbars-within-bevel:
288    *
289    * Whether to place scrollbars within the scrolled window's bevel.
290    *
291    * Since: 2.12
292    */
293   gtk_widget_class_install_style_property (widget_class,
294                                            g_param_spec_boolean ("scrollbars-within-bevel",
295                                                                  P_("Scrollbars within bevel"),
296                                                                  P_("Place scrollbars within the scrolled window's bevel"),
297                                                                  FALSE,
298                                                                  GTK_PARAM_READABLE));
299
300   gtk_widget_class_install_style_property (widget_class,
301                                            g_param_spec_int ("scrollbar-spacing",
302                                                              P_("Scrollbar spacing"),
303                                                              P_("Number of pixels between the scrollbars and the scrolled window"),
304                                                              0,
305                                                              G_MAXINT,
306                                                              DEFAULT_SCROLLBAR_SPACING,
307                                                              GTK_PARAM_READABLE));
308
309   /**
310    * GtkSettings:gtk-scrolled-window-placement:
311    *
312    * Where the contents of scrolled windows are located with respect to the 
313    * scrollbars, if not overridden by the scrolled window's own placement.
314    *
315    * Since: 2.10
316    */
317   gtk_settings_install_property (g_param_spec_enum ("gtk-scrolled-window-placement",
318                                                     P_("Scrolled Window Placement"),
319                                                     P_("Where the contents of scrolled windows are located with respect to the scrollbars, if not overridden by the scrolled window's own placement."),
320                                                     GTK_TYPE_CORNER_TYPE,
321                                                     GTK_CORNER_TOP_LEFT,
322                                                     G_PARAM_READABLE | G_PARAM_WRITABLE));
323
324
325   signals[SCROLL_CHILD] =
326     g_signal_new (I_("scroll-child"),
327                   G_TYPE_FROM_CLASS (object_class),
328                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
329                   G_STRUCT_OFFSET (GtkScrolledWindowClass, scroll_child),
330                   NULL, NULL,
331                   _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
332                   G_TYPE_BOOLEAN, 2,
333                   GTK_TYPE_SCROLL_TYPE,
334                   G_TYPE_BOOLEAN);
335   signals[MOVE_FOCUS_OUT] =
336     g_signal_new (I_("move-focus-out"),
337                   G_TYPE_FROM_CLASS (object_class),
338                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
339                   G_STRUCT_OFFSET (GtkScrolledWindowClass, move_focus_out),
340                   NULL, NULL,
341                   _gtk_marshal_VOID__ENUM,
342                   G_TYPE_NONE, 1,
343                   GTK_TYPE_DIRECTION_TYPE);
344   
345   binding_set = gtk_binding_set_by_class (class);
346
347   add_scroll_binding (binding_set, GDK_Left,  GDK_CONTROL_MASK, GTK_SCROLL_STEP_BACKWARD, TRUE);
348   add_scroll_binding (binding_set, GDK_Right, GDK_CONTROL_MASK, GTK_SCROLL_STEP_FORWARD,  TRUE);
349   add_scroll_binding (binding_set, GDK_Up,    GDK_CONTROL_MASK, GTK_SCROLL_STEP_BACKWARD, FALSE);
350   add_scroll_binding (binding_set, GDK_Down,  GDK_CONTROL_MASK, GTK_SCROLL_STEP_FORWARD,  FALSE);
351
352   add_scroll_binding (binding_set, GDK_Page_Up,   GDK_CONTROL_MASK, GTK_SCROLL_PAGE_BACKWARD, TRUE);
353   add_scroll_binding (binding_set, GDK_Page_Down, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_FORWARD,  TRUE);
354   add_scroll_binding (binding_set, GDK_Page_Up,   0,                GTK_SCROLL_PAGE_BACKWARD, FALSE);
355   add_scroll_binding (binding_set, GDK_Page_Down, 0,                GTK_SCROLL_PAGE_FORWARD,  FALSE);
356
357   add_scroll_binding (binding_set, GDK_Home, GDK_CONTROL_MASK, GTK_SCROLL_START, TRUE);
358   add_scroll_binding (binding_set, GDK_End,  GDK_CONTROL_MASK, GTK_SCROLL_END,   TRUE);
359   add_scroll_binding (binding_set, GDK_Home, 0,                GTK_SCROLL_START, FALSE);
360   add_scroll_binding (binding_set, GDK_End,  0,                GTK_SCROLL_END,   FALSE);
361
362   add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
363   add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
364
365   g_type_class_add_private (class, sizeof (GtkScrolledWindowPrivate));
366 }
367
368 static void
369 gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
370 {
371   GTK_WIDGET_SET_FLAGS (scrolled_window, GTK_NO_WINDOW);
372   gtk_widget_set_can_focus (GTK_WIDGET (scrolled_window), TRUE);
373
374   scrolled_window->hscrollbar = NULL;
375   scrolled_window->vscrollbar = NULL;
376   scrolled_window->hscrollbar_policy = GTK_POLICY_ALWAYS;
377   scrolled_window->vscrollbar_policy = GTK_POLICY_ALWAYS;
378   scrolled_window->hscrollbar_visible = FALSE;
379   scrolled_window->vscrollbar_visible = FALSE;
380   scrolled_window->focus_out = FALSE;
381   scrolled_window->window_placement = GTK_CORNER_TOP_LEFT;
382   gtk_scrolled_window_update_real_placement (scrolled_window);
383 }
384
385 /**
386  * gtk_scrolled_window_new:
387  * @hadjustment: (allow-none): horizontal adjustment
388  * @vadjustment: (allow-none): vertical adjustment
389  *
390  * Creates a new scrolled window.
391  *
392  * The two arguments are the scrolled window's adjustments; these will be
393  * shared with the scrollbars and the child widget to keep the bars in sync 
394  * with the child. Usually you want to pass %NULL for the adjustments, which 
395  * will cause the scrolled window to create them for you.
396  *
397  * Returns: a new scrolled window
398  */
399 GtkWidget*
400 gtk_scrolled_window_new (GtkAdjustment *hadjustment,
401                          GtkAdjustment *vadjustment)
402 {
403   GtkWidget *scrolled_window;
404
405   if (hadjustment)
406     g_return_val_if_fail (GTK_IS_ADJUSTMENT (hadjustment), NULL);
407
408   if (vadjustment)
409     g_return_val_if_fail (GTK_IS_ADJUSTMENT (vadjustment), NULL);
410
411   scrolled_window = g_object_new (GTK_TYPE_SCROLLED_WINDOW,
412                                     "hadjustment", hadjustment,
413                                     "vadjustment", vadjustment,
414                                     NULL);
415
416   return scrolled_window;
417 }
418
419 /**
420  * gtk_scrolled_window_set_hadjustment:
421  * @scrolled_window: a #GtkScrolledWindow
422  * @hadjustment: horizontal scroll adjustment
423  *
424  * Sets the #GtkAdjustment for the horizontal scrollbar.
425  */
426 void
427 gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
428                                      GtkAdjustment     *hadjustment)
429 {
430   GtkBin *bin;
431
432   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
433   if (hadjustment)
434     g_return_if_fail (GTK_IS_ADJUSTMENT (hadjustment));
435   else
436     hadjustment = (GtkAdjustment*) g_object_new (GTK_TYPE_ADJUSTMENT, NULL);
437
438   bin = GTK_BIN (scrolled_window);
439
440   if (!scrolled_window->hscrollbar)
441     {
442       gtk_widget_push_composite_child ();
443       scrolled_window->hscrollbar = gtk_hscrollbar_new (hadjustment);
444       gtk_widget_set_composite_name (scrolled_window->hscrollbar, "hscrollbar");
445       gtk_widget_pop_composite_child ();
446
447       gtk_widget_set_parent (scrolled_window->hscrollbar, GTK_WIDGET (scrolled_window));
448       g_object_ref (scrolled_window->hscrollbar);
449       gtk_widget_show (scrolled_window->hscrollbar);
450     }
451   else
452     {
453       GtkAdjustment *old_adjustment;
454       
455       old_adjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
456       if (old_adjustment == hadjustment)
457         return;
458
459       g_signal_handlers_disconnect_by_func (old_adjustment,
460                                             gtk_scrolled_window_adjustment_changed,
461                                             scrolled_window);
462       gtk_range_set_adjustment (GTK_RANGE (scrolled_window->hscrollbar),
463                                 hadjustment);
464     }
465   hadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
466   g_signal_connect (hadjustment,
467                     "changed",
468                     G_CALLBACK (gtk_scrolled_window_adjustment_changed),
469                     scrolled_window);
470   gtk_scrolled_window_adjustment_changed (hadjustment, scrolled_window);
471   
472   if (bin->child)
473     gtk_widget_set_scroll_adjustments (bin->child,
474                                        gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
475                                        gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)));
476
477   g_object_notify (G_OBJECT (scrolled_window), "hadjustment");
478 }
479
480 /**
481  * gtk_scrolled_window_set_vadjustment:
482  * @scrolled_window: a #GtkScrolledWindow
483  * @vadjustment: vertical scroll adjustment
484  *
485  * Sets the #GtkAdjustment for the vertical scrollbar.
486  */
487 void
488 gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
489                                      GtkAdjustment     *vadjustment)
490 {
491   GtkBin *bin;
492
493   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
494   if (vadjustment)
495     g_return_if_fail (GTK_IS_ADJUSTMENT (vadjustment));
496   else
497     vadjustment = (GtkAdjustment*) g_object_new (GTK_TYPE_ADJUSTMENT, NULL);
498
499   bin = GTK_BIN (scrolled_window);
500
501   if (!scrolled_window->vscrollbar)
502     {
503       gtk_widget_push_composite_child ();
504       scrolled_window->vscrollbar = gtk_vscrollbar_new (vadjustment);
505       gtk_widget_set_composite_name (scrolled_window->vscrollbar, "vscrollbar");
506       gtk_widget_pop_composite_child ();
507
508       gtk_widget_set_parent (scrolled_window->vscrollbar, GTK_WIDGET (scrolled_window));
509       g_object_ref (scrolled_window->vscrollbar);
510       gtk_widget_show (scrolled_window->vscrollbar);
511     }
512   else
513     {
514       GtkAdjustment *old_adjustment;
515       
516       old_adjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
517       if (old_adjustment == vadjustment)
518         return;
519
520       g_signal_handlers_disconnect_by_func (old_adjustment,
521                                             gtk_scrolled_window_adjustment_changed,
522                                             scrolled_window);
523       gtk_range_set_adjustment (GTK_RANGE (scrolled_window->vscrollbar),
524                                 vadjustment);
525     }
526   vadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
527   g_signal_connect (vadjustment,
528                     "changed",
529                     G_CALLBACK (gtk_scrolled_window_adjustment_changed),
530                     scrolled_window);
531   gtk_scrolled_window_adjustment_changed (vadjustment, scrolled_window);
532
533   if (bin->child)
534     gtk_widget_set_scroll_adjustments (bin->child,
535                                        gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
536                                        gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)));
537
538   g_object_notify (G_OBJECT (scrolled_window), "vadjustment");
539 }
540
541 /**
542  * gtk_scrolled_window_get_hadjustment:
543  * @scrolled_window: a #GtkScrolledWindow
544  *
545  * Returns the horizontal scrollbar's adjustment, used to connect the
546  * horizontal scrollbar to the child widget's horizontal scroll
547  * functionality.
548  *
549  * Returns: the horizontal #GtkAdjustment
550  */
551 GtkAdjustment*
552 gtk_scrolled_window_get_hadjustment (GtkScrolledWindow *scrolled_window)
553 {
554   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
555
556   return (scrolled_window->hscrollbar ?
557           gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)) :
558           NULL);
559 }
560
561 /**
562  * gtk_scrolled_window_get_vadjustment:
563  * @scrolled_window: a #GtkScrolledWindow
564  * 
565  * Returns the vertical scrollbar's adjustment, used to connect the
566  * vertical scrollbar to the child widget's vertical scroll
567  * functionality.
568  * 
569  * Returns: the vertical #GtkAdjustment
570  */
571 GtkAdjustment*
572 gtk_scrolled_window_get_vadjustment (GtkScrolledWindow *scrolled_window)
573 {
574   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
575
576   return (scrolled_window->vscrollbar ?
577           gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)) :
578           NULL);
579 }
580
581 /**
582  * gtk_scrolled_window_get_hscrollbar:
583  * @scrolled_window: a #GtkScrolledWindow
584  * 
585  * Returns the horizontal scrollbar of @scrolled_window.
586  *
587  * Returns: the horizontal scrollbar of the scrolled window, or 
588  *  %NULL if it does not have one.
589  *
590  * Since: 2.8
591  */
592 GtkWidget*
593 gtk_scrolled_window_get_hscrollbar (GtkScrolledWindow *scrolled_window)
594 {
595   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
596   
597   return scrolled_window->hscrollbar;
598 }
599
600 /**
601  * gtk_scrolled_window_get_vscrollbar:
602  * @scrolled_window: a #GtkScrolledWindow
603  * 
604  * Returns the vertical scrollbar of @scrolled_window.
605  *
606  * Returns: the vertical scrollbar of the scrolled window, or
607  *  %NULL if it does not have one.
608  *
609  * Since: 2.8
610  */
611 GtkWidget*
612 gtk_scrolled_window_get_vscrollbar (GtkScrolledWindow *scrolled_window)
613 {
614   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
615
616   return scrolled_window->vscrollbar;
617 }
618
619 /**
620  * gtk_scrolled_window_set_policy:
621  * @scrolled_window: a #GtkScrolledWindow
622  * @hscrollbar_policy: policy for horizontal bar
623  * @vscrollbar_policy: policy for vertical bar
624  * 
625  * Sets the scrollbar policy for the horizontal and vertical scrollbars.
626  *
627  * The policy determines when the scrollbar should appear; it is a value
628  * from the #GtkPolicyType enumeration. If %GTK_POLICY_ALWAYS, the
629  * scrollbar is always present; if %GTK_POLICY_NEVER, the scrollbar is
630  * never present; if %GTK_POLICY_AUTOMATIC, the scrollbar is present only
631  * if needed (that is, if the slider part of the bar would be smaller
632  * than the trough - the display is larger than the page size).
633  */
634 void
635 gtk_scrolled_window_set_policy (GtkScrolledWindow *scrolled_window,
636                                 GtkPolicyType      hscrollbar_policy,
637                                 GtkPolicyType      vscrollbar_policy)
638 {
639   GObject *object = G_OBJECT (scrolled_window);
640   
641   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
642
643   if ((scrolled_window->hscrollbar_policy != hscrollbar_policy) ||
644       (scrolled_window->vscrollbar_policy != vscrollbar_policy))
645     {
646       scrolled_window->hscrollbar_policy = hscrollbar_policy;
647       scrolled_window->vscrollbar_policy = vscrollbar_policy;
648
649       gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
650
651       g_object_freeze_notify (object);
652       g_object_notify (object, "hscrollbar-policy");
653       g_object_notify (object, "vscrollbar-policy");
654       g_object_thaw_notify (object);
655     }
656 }
657
658 /**
659  * gtk_scrolled_window_get_policy:
660  * @scrolled_window: a #GtkScrolledWindow
661  * @hscrollbar_policy: location to store the policy for the horizontal 
662  *     scrollbar, or %NULL.
663  * @vscrollbar_policy: location to store the policy for the vertical
664  *     scrollbar, or %NULL.
665  * 
666  * Retrieves the current policy values for the horizontal and vertical
667  * scrollbars. See gtk_scrolled_window_set_policy().
668  */
669 void
670 gtk_scrolled_window_get_policy (GtkScrolledWindow *scrolled_window,
671                                 GtkPolicyType     *hscrollbar_policy,
672                                 GtkPolicyType     *vscrollbar_policy)
673 {
674   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
675
676   if (hscrollbar_policy)
677     *hscrollbar_policy = scrolled_window->hscrollbar_policy;
678   if (vscrollbar_policy)
679     *vscrollbar_policy = scrolled_window->vscrollbar_policy;
680 }
681
682 static void
683 gtk_scrolled_window_update_real_placement (GtkScrolledWindow *scrolled_window)
684 {
685   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
686   GtkSettings *settings;
687
688   settings = gtk_widget_get_settings (GTK_WIDGET (scrolled_window));
689
690   if (priv->window_placement_set || settings == NULL)
691     priv->real_window_placement = scrolled_window->window_placement;
692   else
693     g_object_get (settings,
694                   "gtk-scrolled-window-placement",
695                   &priv->real_window_placement,
696                   NULL);
697 }
698
699 static void
700 gtk_scrolled_window_set_placement_internal (GtkScrolledWindow *scrolled_window,
701                                             GtkCornerType      window_placement)
702 {
703   if (scrolled_window->window_placement != window_placement)
704     {
705       scrolled_window->window_placement = window_placement;
706
707       gtk_scrolled_window_update_real_placement (scrolled_window);
708       gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
709       
710       g_object_notify (G_OBJECT (scrolled_window), "window-placement");
711     }
712 }
713
714 static void
715 gtk_scrolled_window_set_placement_set (GtkScrolledWindow *scrolled_window,
716                                        gboolean           placement_set,
717                                        gboolean           emit_resize)
718 {
719   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
720
721   if (priv->window_placement_set != placement_set)
722     {
723       priv->window_placement_set = placement_set;
724
725       gtk_scrolled_window_update_real_placement (scrolled_window);
726       if (emit_resize)
727         gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
728
729       g_object_notify (G_OBJECT (scrolled_window), "window-placement-set");
730     }
731 }
732
733 /**
734  * gtk_scrolled_window_set_placement:
735  * @scrolled_window: a #GtkScrolledWindow
736  * @window_placement: position of the child window
737  *
738  * Sets the placement of the contents with respect to the scrollbars
739  * for the scrolled window.
740  * 
741  * The default is %GTK_CORNER_TOP_LEFT, meaning the child is
742  * in the top left, with the scrollbars underneath and to the right.
743  * Other values in #GtkCornerType are %GTK_CORNER_TOP_RIGHT,
744  * %GTK_CORNER_BOTTOM_LEFT, and %GTK_CORNER_BOTTOM_RIGHT.
745  *
746  * See also gtk_scrolled_window_get_placement() and
747  * gtk_scrolled_window_unset_placement().
748  */
749 void
750 gtk_scrolled_window_set_placement (GtkScrolledWindow *scrolled_window,
751                                    GtkCornerType      window_placement)
752 {
753   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
754
755   gtk_scrolled_window_set_placement_set (scrolled_window, TRUE, FALSE);
756   gtk_scrolled_window_set_placement_internal (scrolled_window, window_placement);
757 }
758
759 /**
760  * gtk_scrolled_window_get_placement:
761  * @scrolled_window: a #GtkScrolledWindow
762  *
763  * Gets the placement of the contents with respect to the scrollbars
764  * for the scrolled window. See gtk_scrolled_window_set_placement().
765  *
766  * Return value: the current placement value.
767  *
768  * See also gtk_scrolled_window_set_placement() and
769  * gtk_scrolled_window_unset_placement().
770  **/
771 GtkCornerType
772 gtk_scrolled_window_get_placement (GtkScrolledWindow *scrolled_window)
773 {
774   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), GTK_CORNER_TOP_LEFT);
775
776   return scrolled_window->window_placement;
777 }
778
779 /**
780  * gtk_scrolled_window_unset_placement:
781  * @scrolled_window: a #GtkScrolledWindow
782  *
783  * Unsets the placement of the contents with respect to the scrollbars
784  * for the scrolled window. If no window placement is set for a scrolled
785  * window, it obeys the "gtk-scrolled-window-placement" XSETTING.
786  *
787  * See also gtk_scrolled_window_set_placement() and
788  * gtk_scrolled_window_get_placement().
789  *
790  * Since: 2.10
791  **/
792 void
793 gtk_scrolled_window_unset_placement (GtkScrolledWindow *scrolled_window)
794 {
795   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
796
797   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
798
799   if (priv->window_placement_set)
800     {
801       priv->window_placement_set = FALSE;
802
803       gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
804
805       g_object_notify (G_OBJECT (scrolled_window), "window-placement-set");
806     }
807 }
808
809 /**
810  * gtk_scrolled_window_set_shadow_type:
811  * @scrolled_window: a #GtkScrolledWindow
812  * @type: kind of shadow to draw around scrolled window contents
813  *
814  * Changes the type of shadow drawn around the contents of
815  * @scrolled_window.
816  * 
817  **/
818 void
819 gtk_scrolled_window_set_shadow_type (GtkScrolledWindow *scrolled_window,
820                                      GtkShadowType      type)
821 {
822   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
823   g_return_if_fail (type >= GTK_SHADOW_NONE && type <= GTK_SHADOW_ETCHED_OUT);
824   
825   if (scrolled_window->shadow_type != type)
826     {
827       scrolled_window->shadow_type = type;
828
829       if (gtk_widget_is_drawable (GTK_WIDGET (scrolled_window)))
830         gtk_widget_queue_draw (GTK_WIDGET (scrolled_window));
831
832       gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
833
834       g_object_notify (G_OBJECT (scrolled_window), "shadow-type");
835     }
836 }
837
838 /**
839  * gtk_scrolled_window_get_shadow_type:
840  * @scrolled_window: a #GtkScrolledWindow
841  *
842  * Gets the shadow type of the scrolled window. See 
843  * gtk_scrolled_window_set_shadow_type().
844  *
845  * Return value: the current shadow type
846  **/
847 GtkShadowType
848 gtk_scrolled_window_get_shadow_type (GtkScrolledWindow *scrolled_window)
849 {
850   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_NONE);
851
852   return scrolled_window->shadow_type;
853 }
854
855 static void
856 gtk_scrolled_window_destroy (GtkObject *object)
857 {
858   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (object);
859
860   if (scrolled_window->hscrollbar)
861     {
862       g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
863                                             gtk_scrolled_window_adjustment_changed,
864                                             scrolled_window);
865       gtk_widget_unparent (scrolled_window->hscrollbar);
866       gtk_widget_destroy (scrolled_window->hscrollbar);
867       g_object_unref (scrolled_window->hscrollbar);
868       scrolled_window->hscrollbar = NULL;
869     }
870   if (scrolled_window->vscrollbar)
871     {
872       g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)),
873                                             gtk_scrolled_window_adjustment_changed,
874                                             scrolled_window);
875       gtk_widget_unparent (scrolled_window->vscrollbar);
876       gtk_widget_destroy (scrolled_window->vscrollbar);
877       g_object_unref (scrolled_window->vscrollbar);
878       scrolled_window->vscrollbar = NULL;
879     }
880
881   GTK_OBJECT_CLASS (gtk_scrolled_window_parent_class)->destroy (object);
882 }
883
884 static void
885 gtk_scrolled_window_set_property (GObject      *object,
886                                   guint         prop_id,
887                                   const GValue *value,
888                                   GParamSpec   *pspec)
889 {
890   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (object);
891   
892   switch (prop_id)
893     {
894     case PROP_HADJUSTMENT:
895       gtk_scrolled_window_set_hadjustment (scrolled_window,
896                                            g_value_get_object (value));
897       break;
898     case PROP_VADJUSTMENT:
899       gtk_scrolled_window_set_vadjustment (scrolled_window,
900                                            g_value_get_object (value));
901       break;
902     case PROP_HSCROLLBAR_POLICY:
903       gtk_scrolled_window_set_policy (scrolled_window,
904                                       g_value_get_enum (value),
905                                       scrolled_window->vscrollbar_policy);
906       break;
907     case PROP_VSCROLLBAR_POLICY:
908       gtk_scrolled_window_set_policy (scrolled_window,
909                                       scrolled_window->hscrollbar_policy,
910                                       g_value_get_enum (value));
911       break;
912     case PROP_WINDOW_PLACEMENT:
913       gtk_scrolled_window_set_placement_internal (scrolled_window,
914                                                   g_value_get_enum (value));
915       break;
916     case PROP_WINDOW_PLACEMENT_SET:
917       gtk_scrolled_window_set_placement_set (scrolled_window,
918                                              g_value_get_boolean (value),
919                                              TRUE);
920       break;
921     case PROP_SHADOW_TYPE:
922       gtk_scrolled_window_set_shadow_type (scrolled_window,
923                                            g_value_get_enum (value));
924       break;
925     default:
926       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
927       break;
928     }
929 }
930
931 static void
932 gtk_scrolled_window_get_property (GObject    *object,
933                                   guint       prop_id,
934                                   GValue     *value,
935                                   GParamSpec *pspec)
936 {
937   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (object);
938   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
939   
940   switch (prop_id)
941     {
942     case PROP_HADJUSTMENT:
943       g_value_set_object (value,
944                           G_OBJECT (gtk_scrolled_window_get_hadjustment (scrolled_window)));
945       break;
946     case PROP_VADJUSTMENT:
947       g_value_set_object (value,
948                           G_OBJECT (gtk_scrolled_window_get_vadjustment (scrolled_window)));
949       break;
950     case PROP_HSCROLLBAR_POLICY:
951       g_value_set_enum (value, scrolled_window->hscrollbar_policy);
952       break;
953     case PROP_VSCROLLBAR_POLICY:
954       g_value_set_enum (value, scrolled_window->vscrollbar_policy);
955       break;
956     case PROP_WINDOW_PLACEMENT:
957       g_value_set_enum (value, scrolled_window->window_placement);
958       break;
959     case PROP_WINDOW_PLACEMENT_SET:
960       g_value_set_boolean (value, priv->window_placement_set);
961       break;
962     case PROP_SHADOW_TYPE:
963       g_value_set_enum (value, scrolled_window->shadow_type);
964       break;
965     default:
966       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
967       break;
968     }
969 }
970
971 static void
972 traverse_container (GtkWidget *widget,
973                     gpointer   data)
974 {
975   if (GTK_IS_SCROLLED_WINDOW (widget))
976     {
977       gtk_scrolled_window_update_real_placement (GTK_SCROLLED_WINDOW (widget));
978       gtk_widget_queue_resize (widget);
979     }
980   else if (GTK_IS_CONTAINER (widget))
981     gtk_container_forall (GTK_CONTAINER (widget), traverse_container, NULL);
982 }
983
984 static void
985 gtk_scrolled_window_settings_changed (GtkSettings *settings)
986 {
987   GList *list, *l;
988
989   list = gtk_window_list_toplevels ();
990
991   for (l = list; l; l = l->next)
992     gtk_container_forall (GTK_CONTAINER (l->data), 
993                           traverse_container, NULL);
994
995   g_list_free (list);
996 }
997
998 static void
999 gtk_scrolled_window_screen_changed (GtkWidget *widget,
1000                                     GdkScreen *previous_screen)
1001 {
1002   GtkSettings *settings;
1003   guint window_placement_connection;
1004
1005   gtk_scrolled_window_update_real_placement (GTK_SCROLLED_WINDOW (widget));
1006
1007   if (!gtk_widget_has_screen (widget))
1008     return;
1009
1010   settings = gtk_widget_get_settings (widget);
1011
1012   window_placement_connection = 
1013     GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (settings), 
1014                                          "gtk-scrolled-window-connection"));
1015   
1016   if (window_placement_connection)
1017     return;
1018
1019   window_placement_connection =
1020     g_signal_connect (settings, "notify::gtk-scrolled-window-placement",
1021                       G_CALLBACK (gtk_scrolled_window_settings_changed), NULL);
1022   g_object_set_data (G_OBJECT (settings), 
1023                      I_("gtk-scrolled-window-connection"),
1024                      GUINT_TO_POINTER (window_placement_connection));
1025 }
1026
1027 static void
1028 gtk_scrolled_window_paint (GtkWidget    *widget,
1029                            GdkRectangle *area)
1030 {
1031   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
1032
1033   if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
1034     {
1035       GtkAllocation relative_allocation;
1036       gboolean scrollbars_within_bevel;
1037
1038       gtk_widget_style_get (widget, "scrollbars-within-bevel", &scrollbars_within_bevel, NULL);
1039       
1040       if (!scrollbars_within_bevel)
1041         {
1042           gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
1043
1044           relative_allocation.x -= widget->style->xthickness;
1045           relative_allocation.y -= widget->style->ythickness;
1046           relative_allocation.width += 2 * widget->style->xthickness;
1047           relative_allocation.height += 2 * widget->style->ythickness;
1048         }
1049       else
1050         {
1051           GtkContainer *container = GTK_CONTAINER (widget);
1052
1053           relative_allocation.x = container->border_width;
1054           relative_allocation.y = container->border_width;
1055           relative_allocation.width = widget->allocation.width - 2 * container->border_width;
1056           relative_allocation.height = widget->allocation.height - 2 * container->border_width;
1057         }
1058
1059       gtk_paint_shadow (widget->style, widget->window,
1060                         GTK_STATE_NORMAL, scrolled_window->shadow_type,
1061                         area, widget, "scrolled_window",
1062                         widget->allocation.x + relative_allocation.x,
1063                         widget->allocation.y + relative_allocation.y,
1064                         relative_allocation.width,
1065                         relative_allocation.height);
1066     }
1067 }
1068
1069 static gboolean
1070 gtk_scrolled_window_expose (GtkWidget      *widget,
1071                             GdkEventExpose *event)
1072 {
1073   if (gtk_widget_is_drawable (widget))
1074     {
1075       gtk_scrolled_window_paint (widget, &event->area);
1076
1077       GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->expose_event (widget, event);
1078     }
1079
1080   return FALSE;
1081 }
1082
1083 static void
1084 gtk_scrolled_window_forall (GtkContainer *container,
1085                             gboolean      include_internals,
1086                             GtkCallback   callback,
1087                             gpointer      callback_data)
1088 {
1089   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
1090   g_return_if_fail (callback != NULL);
1091
1092   GTK_CONTAINER_CLASS (gtk_scrolled_window_parent_class)->forall (container,
1093                                               include_internals,
1094                                               callback,
1095                                               callback_data);
1096   if (include_internals)
1097     {
1098       GtkScrolledWindow *scrolled_window;
1099
1100       scrolled_window = GTK_SCROLLED_WINDOW (container);
1101       
1102       if (scrolled_window->vscrollbar)
1103         callback (scrolled_window->vscrollbar, callback_data);
1104       if (scrolled_window->hscrollbar)
1105         callback (scrolled_window->hscrollbar, callback_data);
1106     }
1107 }
1108
1109 static gboolean
1110 gtk_scrolled_window_scroll_child (GtkScrolledWindow *scrolled_window,
1111                                   GtkScrollType      scroll,
1112                                   gboolean           horizontal)
1113 {
1114   GtkAdjustment *adjustment = NULL;
1115   
1116   switch (scroll)
1117     {
1118     case GTK_SCROLL_STEP_UP:
1119       scroll = GTK_SCROLL_STEP_BACKWARD;
1120       horizontal = FALSE;
1121       break;
1122     case GTK_SCROLL_STEP_DOWN:
1123       scroll = GTK_SCROLL_STEP_FORWARD;
1124       horizontal = FALSE;
1125       break;
1126     case GTK_SCROLL_STEP_LEFT:
1127       scroll = GTK_SCROLL_STEP_BACKWARD;
1128       horizontal = TRUE;
1129       break;
1130     case GTK_SCROLL_STEP_RIGHT:
1131       scroll = GTK_SCROLL_STEP_FORWARD;
1132       horizontal = TRUE;
1133       break;
1134     case GTK_SCROLL_PAGE_UP:
1135       scroll = GTK_SCROLL_PAGE_BACKWARD;
1136       horizontal = FALSE;
1137       break;
1138     case GTK_SCROLL_PAGE_DOWN:
1139       scroll = GTK_SCROLL_PAGE_FORWARD;
1140       horizontal = FALSE;
1141       break;
1142     case GTK_SCROLL_PAGE_LEFT:
1143       scroll = GTK_SCROLL_STEP_BACKWARD;
1144       horizontal = TRUE;
1145       break;
1146     case GTK_SCROLL_PAGE_RIGHT:
1147       scroll = GTK_SCROLL_STEP_FORWARD;
1148       horizontal = TRUE;
1149       break;
1150     case GTK_SCROLL_STEP_BACKWARD:
1151     case GTK_SCROLL_STEP_FORWARD:
1152     case GTK_SCROLL_PAGE_BACKWARD:
1153     case GTK_SCROLL_PAGE_FORWARD:
1154     case GTK_SCROLL_START:
1155     case GTK_SCROLL_END:
1156       break;
1157     default:
1158       g_warning ("Invalid scroll type %u for GtkScrolledWindow::scroll-child", scroll);
1159       return FALSE;
1160     }
1161
1162   if ((horizontal && (!scrolled_window->hscrollbar || !scrolled_window->hscrollbar_visible)) ||
1163       (!horizontal && (!scrolled_window->vscrollbar || !scrolled_window->vscrollbar_visible)))
1164     return FALSE;
1165
1166   if (horizontal)
1167     {
1168       if (scrolled_window->hscrollbar)
1169         adjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
1170     }
1171   else
1172     {
1173       if (scrolled_window->vscrollbar)
1174         adjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
1175     }
1176
1177   if (adjustment)
1178     {
1179       gdouble value = adjustment->value;
1180       
1181       switch (scroll)
1182         {
1183         case GTK_SCROLL_STEP_FORWARD:
1184           value += adjustment->step_increment;
1185           break;
1186         case GTK_SCROLL_STEP_BACKWARD:
1187           value -= adjustment->step_increment;
1188           break;
1189         case GTK_SCROLL_PAGE_FORWARD:
1190           value += adjustment->page_increment;
1191           break;
1192         case GTK_SCROLL_PAGE_BACKWARD:
1193           value -= adjustment->page_increment;
1194           break;
1195         case GTK_SCROLL_START:
1196           value = adjustment->lower;
1197           break;
1198         case GTK_SCROLL_END:
1199           value = adjustment->upper;
1200           break;
1201         default:
1202           g_assert_not_reached ();
1203           break;
1204         }
1205
1206       value = CLAMP (value, adjustment->lower, adjustment->upper - adjustment->page_size);
1207       
1208       gtk_adjustment_set_value (adjustment, value);
1209
1210       return TRUE;
1211     }
1212
1213   return FALSE;
1214 }
1215
1216 static void
1217 gtk_scrolled_window_move_focus_out (GtkScrolledWindow *scrolled_window,
1218                                     GtkDirectionType   direction_type)
1219 {
1220   GtkWidget *toplevel;
1221   
1222   /* Focus out of the scrolled window entirely. We do this by setting
1223    * a flag, then propagating the focus motion to the notebook.
1224    */
1225   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (scrolled_window));
1226   if (!gtk_widget_is_toplevel (toplevel))
1227     return;
1228
1229   g_object_ref (scrolled_window);
1230   
1231   scrolled_window->focus_out = TRUE;
1232   g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1233   scrolled_window->focus_out = FALSE;
1234   
1235   g_object_unref (scrolled_window);
1236 }
1237
1238 static void
1239 gtk_scrolled_window_real_size_request (GtkWidget      *widget,
1240                                        GtkRequisition *min_requisition,
1241                                        GtkRequisition *nat_requisition)
1242 {
1243   GtkScrolledWindow *scrolled_window;
1244   GtkBin *bin;
1245   gint extra_width;
1246   gint extra_height;
1247   gint scrollbar_spacing;
1248   GtkRequisition hscrollbar_requisition;
1249   GtkRequisition vscrollbar_requisition;
1250   GtkRequisition min_child_requisition;
1251   GtkRequisition nat_child_requisition;
1252
1253   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
1254
1255   scrolled_window = GTK_SCROLLED_WINDOW (widget);
1256   bin = GTK_BIN (scrolled_window);
1257
1258   scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
1259
1260   extra_width = 0;
1261   extra_height = 0;
1262   min_requisition->width = 0;
1263   min_requisition->height = 0;
1264   nat_requisition->width = 0;
1265   nat_requisition->height = 0;
1266   
1267   gtk_widget_size_request (scrolled_window->hscrollbar,
1268                            &hscrollbar_requisition);
1269   gtk_widget_size_request (scrolled_window->vscrollbar,
1270                            &vscrollbar_requisition);
1271   
1272   if (bin->child && gtk_widget_get_visible (bin->child))
1273     {
1274       gtk_extended_layout_get_desired_size (GTK_EXTENDED_LAYOUT (bin->child),
1275                                             &min_child_requisition,
1276                                             &nat_child_requisition);
1277
1278       if (scrolled_window->hscrollbar_policy == GTK_POLICY_NEVER)
1279         {
1280           min_requisition->width += min_child_requisition.width;
1281           nat_requisition->width += nat_child_requisition.width;
1282         }
1283       else
1284         {
1285           GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (bin->child, FALSE);
1286
1287           if (aux_info && aux_info->width > 0)
1288             {
1289               min_requisition->width += aux_info->width;
1290               nat_requisition->width += aux_info->width;
1291               extra_width = -1;
1292             }
1293           else
1294             {
1295               min_requisition->width += vscrollbar_requisition.width;
1296               nat_requisition->width += vscrollbar_requisition.width;
1297             }
1298         }
1299
1300       if (scrolled_window->vscrollbar_policy == GTK_POLICY_NEVER)
1301         {
1302           min_requisition->height += min_child_requisition.height;
1303           nat_requisition->height += nat_child_requisition.height;
1304         }
1305       else
1306         {
1307           GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (bin->child, FALSE);
1308
1309           if (aux_info && aux_info->height > 0)
1310             {
1311               min_requisition->height += aux_info->height;
1312               nat_requisition->height += aux_info->height;
1313               extra_height = -1;
1314             }
1315           else
1316             {
1317               min_requisition->height += hscrollbar_requisition.height;
1318               nat_requisition->height += hscrollbar_requisition.height;
1319             }
1320         }
1321     }
1322
1323   if (scrolled_window->hscrollbar_policy == GTK_POLICY_AUTOMATIC ||
1324       scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
1325     {
1326       min_requisition->width = MAX (min_requisition->width, hscrollbar_requisition.width);
1327       nat_requisition->width = MAX (nat_requisition->width, hscrollbar_requisition.width);
1328       if (!extra_height || scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
1329         extra_height = scrollbar_spacing + hscrollbar_requisition.height;
1330     }
1331
1332   if (scrolled_window->vscrollbar_policy == GTK_POLICY_AUTOMATIC ||
1333       scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
1334     {
1335       min_requisition->height = MAX (min_requisition->height, vscrollbar_requisition.height);
1336       nat_requisition->height = MAX (nat_requisition->height, vscrollbar_requisition.height);
1337       if (!extra_height || scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
1338         extra_width = scrollbar_spacing + vscrollbar_requisition.width;
1339     }
1340
1341   min_requisition->width += GTK_CONTAINER (widget)->border_width * 2 + MAX (0, extra_width);
1342   min_requisition->height += GTK_CONTAINER (widget)->border_width * 2 + MAX (0, extra_height);
1343   nat_requisition->width += GTK_CONTAINER (widget)->border_width * 2 + MAX (0, extra_width);
1344   nat_requisition->height += GTK_CONTAINER (widget)->border_width * 2 + MAX (0, extra_height);
1345
1346   if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
1347     {
1348       min_requisition->width += 2 * widget->style->xthickness;
1349       min_requisition->height += 2 * widget->style->ythickness;
1350       nat_requisition->width += 2 * widget->style->xthickness;
1351       nat_requisition->height += 2 * widget->style->ythickness;
1352     }
1353 }
1354
1355 static void
1356 gtk_scrolled_window_size_request (GtkWidget      *widget,
1357                                  GtkRequisition *requisition)
1358 {
1359   GtkRequisition nat_req;
1360
1361   gtk_scrolled_window_real_size_request (widget, requisition, &nat_req);
1362 }
1363
1364 static void
1365 gtk_scrolled_window_relative_allocation (GtkWidget     *widget,
1366                                          GtkAllocation *allocation)
1367 {
1368   GtkScrolledWindow *scrolled_window;
1369   GtkScrolledWindowPrivate *priv;
1370   gint scrollbar_spacing;
1371
1372   g_return_if_fail (widget != NULL);
1373   g_return_if_fail (allocation != NULL);
1374
1375   scrolled_window = GTK_SCROLLED_WINDOW (widget);
1376   scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
1377
1378   priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
1379
1380   allocation->x = GTK_CONTAINER (widget)->border_width;
1381   allocation->y = GTK_CONTAINER (widget)->border_width;
1382
1383   if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
1384     {
1385       allocation->x += widget->style->xthickness;
1386       allocation->y += widget->style->ythickness;
1387     }
1388   
1389   allocation->width = MAX (1, (gint)widget->allocation.width - allocation->x * 2);
1390   allocation->height = MAX (1, (gint)widget->allocation.height - allocation->y * 2);
1391
1392   if (scrolled_window->vscrollbar_visible)
1393     {
1394       GtkRequisition vscrollbar_requisition;
1395       gboolean is_rtl;
1396
1397       gtk_widget_get_child_requisition (scrolled_window->vscrollbar,
1398                                         &vscrollbar_requisition);
1399       is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1400   
1401       if ((!is_rtl && 
1402            (priv->real_window_placement == GTK_CORNER_TOP_RIGHT ||
1403             priv->real_window_placement == GTK_CORNER_BOTTOM_RIGHT)) ||
1404           (is_rtl && 
1405            (priv->real_window_placement == GTK_CORNER_TOP_LEFT ||
1406             priv->real_window_placement == GTK_CORNER_BOTTOM_LEFT)))
1407         allocation->x += (vscrollbar_requisition.width +  scrollbar_spacing);
1408
1409       allocation->width = MAX (1, allocation->width - (vscrollbar_requisition.width + scrollbar_spacing));
1410     }
1411   if (scrolled_window->hscrollbar_visible)
1412     {
1413       GtkRequisition hscrollbar_requisition;
1414       gtk_widget_get_child_requisition (scrolled_window->hscrollbar,
1415                                         &hscrollbar_requisition);
1416   
1417       if (priv->real_window_placement == GTK_CORNER_BOTTOM_LEFT ||
1418           priv->real_window_placement == GTK_CORNER_BOTTOM_RIGHT)
1419         allocation->y += (hscrollbar_requisition.height + scrollbar_spacing);
1420
1421       allocation->height = MAX (1, allocation->height - (hscrollbar_requisition.height + scrollbar_spacing));
1422     }
1423 }
1424
1425 static void
1426 gtk_scrolled_window_size_allocate (GtkWidget     *widget,
1427                                    GtkAllocation *allocation)
1428 {
1429   GtkScrolledWindow *scrolled_window;
1430   GtkScrolledWindowPrivate *priv;
1431   GtkBin *bin;
1432   GtkAllocation relative_allocation;
1433   GtkAllocation child_allocation;
1434   gboolean scrollbars_within_bevel;
1435   gint scrollbar_spacing;
1436   
1437   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
1438   g_return_if_fail (allocation != NULL);
1439
1440   scrolled_window = GTK_SCROLLED_WINDOW (widget);
1441   bin = GTK_BIN (scrolled_window);
1442
1443   scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
1444   gtk_widget_style_get (widget, "scrollbars-within-bevel", &scrollbars_within_bevel, NULL);
1445
1446   priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
1447
1448   widget->allocation = *allocation;
1449
1450   if (scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
1451     scrolled_window->hscrollbar_visible = TRUE;
1452   else if (scrolled_window->hscrollbar_policy == GTK_POLICY_NEVER)
1453     scrolled_window->hscrollbar_visible = FALSE;
1454   if (scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
1455     scrolled_window->vscrollbar_visible = TRUE;
1456   else if (scrolled_window->vscrollbar_policy == GTK_POLICY_NEVER)
1457     scrolled_window->vscrollbar_visible = FALSE;
1458
1459   if (bin->child && gtk_widget_get_visible (bin->child))
1460     {
1461       gboolean previous_hvis;
1462       gboolean previous_vvis;
1463       guint count = 0;
1464       
1465       do
1466         {
1467           gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
1468           
1469           child_allocation.x = relative_allocation.x + allocation->x;
1470           child_allocation.y = relative_allocation.y + allocation->y;
1471           child_allocation.width = relative_allocation.width;
1472           child_allocation.height = relative_allocation.height;
1473           
1474           previous_hvis = scrolled_window->hscrollbar_visible;
1475           previous_vvis = scrolled_window->vscrollbar_visible;
1476           
1477           gtk_widget_size_allocate (bin->child, &child_allocation);
1478
1479           /* If, after the first iteration, the hscrollbar and the
1480            * vscrollbar flip visiblity, then we need both.
1481            */
1482           if (count &&
1483               previous_hvis != scrolled_window->hscrollbar_visible &&
1484               previous_vvis != scrolled_window->vscrollbar_visible)
1485             {
1486               scrolled_window->hscrollbar_visible = TRUE;
1487               scrolled_window->vscrollbar_visible = TRUE;
1488
1489               /* a new resize is already queued at this point,
1490                * so we will immediatedly get reinvoked
1491                */
1492               return;
1493             }
1494           
1495           count++;
1496         }
1497       while (previous_hvis != scrolled_window->hscrollbar_visible ||
1498              previous_vvis != scrolled_window->vscrollbar_visible);
1499     }
1500   else
1501     {
1502       scrolled_window->hscrollbar_visible = scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS;
1503       scrolled_window->vscrollbar_visible = scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS;
1504       gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
1505     }
1506   
1507   if (scrolled_window->hscrollbar_visible)
1508     {
1509       GtkRequisition hscrollbar_requisition;
1510       gtk_widget_get_child_requisition (scrolled_window->hscrollbar,
1511                                         &hscrollbar_requisition);
1512   
1513       if (!gtk_widget_get_visible (scrolled_window->hscrollbar))
1514         gtk_widget_show (scrolled_window->hscrollbar);
1515
1516       child_allocation.x = relative_allocation.x;
1517       if (priv->real_window_placement == GTK_CORNER_TOP_LEFT ||
1518           priv->real_window_placement == GTK_CORNER_TOP_RIGHT)
1519         child_allocation.y = (relative_allocation.y +
1520                               relative_allocation.height +
1521                               scrollbar_spacing +
1522                               (scrolled_window->shadow_type == GTK_SHADOW_NONE ?
1523                                0 : widget->style->ythickness));
1524       else
1525         child_allocation.y = GTK_CONTAINER (scrolled_window)->border_width;
1526
1527       child_allocation.width = relative_allocation.width;
1528       child_allocation.height = hscrollbar_requisition.height;
1529       child_allocation.x += allocation->x;
1530       child_allocation.y += allocation->y;
1531
1532       if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
1533         {
1534           if (!scrollbars_within_bevel)
1535             {
1536               child_allocation.x -= widget->style->xthickness;
1537               child_allocation.width += 2 * widget->style->xthickness;
1538             }
1539           else if (GTK_CORNER_TOP_RIGHT == priv->real_window_placement ||
1540                    GTK_CORNER_TOP_LEFT == priv->real_window_placement)
1541             {
1542               child_allocation.y -= widget->style->ythickness;
1543             }
1544           else
1545             {
1546               child_allocation.y += widget->style->ythickness;
1547             }
1548         }
1549
1550       gtk_widget_size_allocate (scrolled_window->hscrollbar, &child_allocation);
1551     }
1552   else if (gtk_widget_get_visible (scrolled_window->hscrollbar))
1553     gtk_widget_hide (scrolled_window->hscrollbar);
1554
1555   if (scrolled_window->vscrollbar_visible)
1556     {
1557       GtkRequisition vscrollbar_requisition;
1558       if (!gtk_widget_get_visible (scrolled_window->vscrollbar))
1559         gtk_widget_show (scrolled_window->vscrollbar);
1560
1561       gtk_widget_get_child_requisition (scrolled_window->vscrollbar,
1562                                         &vscrollbar_requisition);
1563
1564       if ((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL && 
1565            (priv->real_window_placement == GTK_CORNER_TOP_RIGHT ||
1566             priv->real_window_placement == GTK_CORNER_BOTTOM_RIGHT)) ||
1567           (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR && 
1568            (priv->real_window_placement == GTK_CORNER_TOP_LEFT ||
1569             priv->real_window_placement == GTK_CORNER_BOTTOM_LEFT)))
1570         child_allocation.x = (relative_allocation.x +
1571                               relative_allocation.width +
1572                               scrollbar_spacing +
1573                               (scrolled_window->shadow_type == GTK_SHADOW_NONE ?
1574                                0 : widget->style->xthickness));
1575       else
1576         child_allocation.x = GTK_CONTAINER (scrolled_window)->border_width;
1577
1578       child_allocation.y = relative_allocation.y;
1579       child_allocation.width = vscrollbar_requisition.width;
1580       child_allocation.height = relative_allocation.height;
1581       child_allocation.x += allocation->x;
1582       child_allocation.y += allocation->y;
1583
1584       if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
1585         {
1586           if (!scrollbars_within_bevel)
1587             {
1588               child_allocation.y -= widget->style->ythickness;
1589               child_allocation.height += 2 * widget->style->ythickness;
1590             }
1591           else if (GTK_CORNER_BOTTOM_LEFT == priv->real_window_placement ||
1592                    GTK_CORNER_TOP_LEFT == priv->real_window_placement)
1593             {
1594               child_allocation.x -= widget->style->xthickness;
1595             }
1596           else
1597             {
1598               child_allocation.x += widget->style->xthickness;
1599             }
1600         }
1601
1602       gtk_widget_size_allocate (scrolled_window->vscrollbar, &child_allocation);
1603     }
1604   else if (gtk_widget_get_visible (scrolled_window->vscrollbar))
1605     gtk_widget_hide (scrolled_window->vscrollbar);
1606 }
1607
1608 static gboolean
1609 gtk_scrolled_window_scroll_event (GtkWidget      *widget,
1610                                   GdkEventScroll *event)
1611 {
1612   GtkWidget *range;
1613
1614   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (widget), FALSE);
1615   g_return_val_if_fail (event != NULL, FALSE);  
1616
1617   if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_DOWN)
1618     range = GTK_SCROLLED_WINDOW (widget)->vscrollbar;
1619   else
1620     range = GTK_SCROLLED_WINDOW (widget)->hscrollbar;
1621
1622   if (range && gtk_widget_get_visible (range))
1623     {
1624       GtkAdjustment *adj = GTK_RANGE (range)->adjustment;
1625       gdouble delta, new_value;
1626
1627       delta = _gtk_range_get_wheel_delta (GTK_RANGE (range), event->direction);
1628
1629       new_value = CLAMP (adj->value + delta, adj->lower, adj->upper - adj->page_size);
1630       
1631       gtk_adjustment_set_value (adj, new_value);
1632
1633       return TRUE;
1634     }
1635
1636   return FALSE;
1637 }
1638
1639 static gboolean
1640 gtk_scrolled_window_focus (GtkWidget        *widget,
1641                            GtkDirectionType  direction)
1642 {
1643   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
1644   gboolean had_focus_child = GTK_CONTAINER (widget)->focus_child != NULL;
1645   
1646   if (scrolled_window->focus_out)
1647     {
1648       scrolled_window->focus_out = FALSE; /* Clear this to catch the wrap-around case */
1649       return FALSE;
1650     }
1651   
1652   if (gtk_widget_is_focus (widget))
1653     return FALSE;
1654
1655   /* We only put the scrolled window itself in the focus chain if it
1656    * isn't possible to focus any children.
1657    */
1658   if (GTK_BIN (widget)->child)
1659     {
1660       if (gtk_widget_child_focus (GTK_BIN (widget)->child, direction))
1661         return TRUE;
1662     }
1663
1664   if (!had_focus_child && gtk_widget_get_can_focus (widget))
1665     {
1666       gtk_widget_grab_focus (widget);
1667       return TRUE;
1668     }
1669   else
1670     return FALSE;
1671 }
1672
1673 static void
1674 gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment,
1675                                         gpointer       data)
1676 {
1677   GtkScrolledWindow *scrolled_win;
1678
1679   g_return_if_fail (adjustment != NULL);
1680   g_return_if_fail (data != NULL);
1681
1682   scrolled_win = GTK_SCROLLED_WINDOW (data);
1683
1684   if (scrolled_win->hscrollbar &&
1685       adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_win->hscrollbar)))
1686     {
1687       if (scrolled_win->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
1688         {
1689           gboolean visible;
1690           
1691           visible = scrolled_win->hscrollbar_visible;
1692           scrolled_win->hscrollbar_visible = (adjustment->upper - adjustment->lower >
1693                                               adjustment->page_size);
1694           if (scrolled_win->hscrollbar_visible != visible)
1695             gtk_widget_queue_resize (GTK_WIDGET (scrolled_win));
1696         }
1697     }
1698   else if (scrolled_win->vscrollbar &&
1699            adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_win->vscrollbar)))
1700     {
1701       if (scrolled_win->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
1702         {
1703           gboolean visible;
1704
1705           visible = scrolled_win->vscrollbar_visible;
1706           scrolled_win->vscrollbar_visible = (adjustment->upper - adjustment->lower >
1707                                               adjustment->page_size);
1708           if (scrolled_win->vscrollbar_visible != visible)
1709             gtk_widget_queue_resize (GTK_WIDGET (scrolled_win));
1710         }
1711     }
1712 }
1713
1714 static void
1715 gtk_scrolled_window_add (GtkContainer *container,
1716                          GtkWidget    *child)
1717 {
1718   GtkScrolledWindow *scrolled_window;
1719   GtkBin *bin;
1720
1721   bin = GTK_BIN (container);
1722   g_return_if_fail (bin->child == NULL);
1723
1724   scrolled_window = GTK_SCROLLED_WINDOW (container);
1725
1726   bin->child = child;
1727   gtk_widget_set_parent (child, GTK_WIDGET (bin));
1728
1729   /* this is a temporary message */
1730   if (!gtk_widget_set_scroll_adjustments (child,
1731                                           gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
1732                                           gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar))))
1733     g_warning ("gtk_scrolled_window_add(): cannot add non scrollable widget "
1734                "use gtk_scrolled_window_add_with_viewport() instead");
1735 }
1736
1737 static void
1738 gtk_scrolled_window_remove (GtkContainer *container,
1739                             GtkWidget    *child)
1740 {
1741   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
1742   g_return_if_fail (child != NULL);
1743   g_return_if_fail (GTK_BIN (container)->child == child);
1744   
1745   gtk_widget_set_scroll_adjustments (child, NULL, NULL);
1746
1747   /* chain parent class handler to remove child */
1748   GTK_CONTAINER_CLASS (gtk_scrolled_window_parent_class)->remove (container, child);
1749 }
1750
1751 /**
1752  * gtk_scrolled_window_add_with_viewport:
1753  * @scrolled_window: a #GtkScrolledWindow
1754  * @child: the widget you want to scroll
1755  *
1756  * Used to add children without native scrolling capabilities. This
1757  * is simply a convenience function; it is equivalent to adding the
1758  * unscrollable child to a viewport, then adding the viewport to the
1759  * scrolled window. If a child has native scrolling, use
1760  * gtk_container_add() instead of this function.
1761  *
1762  * The viewport scrolls the child by moving its #GdkWindow, and takes
1763  * the size of the child to be the size of its toplevel #GdkWindow. 
1764  * This will be very wrong for most widgets that support native scrolling;
1765  * for example, if you add a widget such as #GtkTreeView with a viewport,
1766  * the whole widget will scroll, including the column headings. Thus, 
1767  * widgets with native scrolling support should not be used with the 
1768  * #GtkViewport proxy.
1769  *
1770  * A widget supports scrolling natively if the 
1771  * set_scroll_adjustments_signal field in #GtkWidgetClass is non-zero,
1772  * i.e. has been filled in with a valid signal identifier.
1773  */
1774 void
1775 gtk_scrolled_window_add_with_viewport (GtkScrolledWindow *scrolled_window,
1776                                        GtkWidget         *child)
1777 {
1778   GtkBin *bin;
1779   GtkWidget *viewport;
1780
1781   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
1782   g_return_if_fail (GTK_IS_WIDGET (child));
1783   g_return_if_fail (child->parent == NULL);
1784
1785   bin = GTK_BIN (scrolled_window);
1786
1787   if (bin->child != NULL)
1788     {
1789       g_return_if_fail (GTK_IS_VIEWPORT (bin->child));
1790       g_return_if_fail (GTK_BIN (bin->child)->child == NULL);
1791
1792       viewport = bin->child;
1793     }
1794   else
1795     {
1796       viewport =
1797         gtk_viewport_new (gtk_scrolled_window_get_hadjustment (scrolled_window),
1798                           gtk_scrolled_window_get_vadjustment (scrolled_window));
1799       gtk_container_add (GTK_CONTAINER (scrolled_window), viewport);
1800     }
1801
1802   gtk_widget_show (viewport);
1803   gtk_container_add (GTK_CONTAINER (viewport), child);
1804 }
1805
1806 /*
1807  * _gtk_scrolled_window_get_spacing:
1808  * @scrolled_window: a scrolled window
1809  * 
1810  * Gets the spacing between the scrolled window's scrollbars and
1811  * the scrolled widget. Used by GtkCombo
1812  * 
1813  * Return value: the spacing, in pixels.
1814  */
1815 gint
1816 _gtk_scrolled_window_get_scrollbar_spacing (GtkScrolledWindow *scrolled_window)
1817 {
1818   GtkScrolledWindowClass *class;
1819     
1820   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), 0);
1821
1822   class = GTK_SCROLLED_WINDOW_GET_CLASS (scrolled_window);
1823
1824   if (class->scrollbar_spacing >= 0)
1825     return class->scrollbar_spacing;
1826   else
1827     {
1828       gint scrollbar_spacing;
1829       
1830       gtk_widget_style_get (GTK_WIDGET (scrolled_window),
1831                             "scrollbar-spacing", &scrollbar_spacing,
1832                             NULL);
1833
1834       return scrollbar_spacing;
1835     }
1836 }
1837
1838 static void
1839 gtk_scrolled_window_extended_layout_get_desired_size (GtkExtendedLayout *layout,
1840                                                       GtkRequisition    *minimal_size,
1841                                                       GtkRequisition    *natural_size)
1842 {
1843   GtkRequisition min_req, nat_req;
1844
1845   gtk_scrolled_window_real_size_request (GTK_WIDGET (layout), &min_req, &nat_req);
1846
1847   if (minimal_size)
1848     *minimal_size = min_req;
1849
1850   if (natural_size)
1851     *natural_size = nat_req;
1852 }
1853
1854 static void
1855 gtk_scrolled_window_extended_layout_init (GtkExtendedLayoutIface *iface)
1856 {
1857   iface->get_desired_size = gtk_scrolled_window_extended_layout_get_desired_size;
1858 }
1859
1860 #define __GTK_SCROLLED_WINDOW_C__
1861 #include "gtkaliasdef.c"