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