]> Pileus Git - ~andy/gtk/blob - gtk/gtkscrolledwindow.c
Updated Spanish translation
[~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_has_window (GTK_WIDGET (scrolled_window), FALSE);
366   gtk_widget_set_can_focus (GTK_WIDGET (scrolled_window), TRUE);
367
368   scrolled_window->hscrollbar = NULL;
369   scrolled_window->vscrollbar = NULL;
370   scrolled_window->hscrollbar_policy = GTK_POLICY_ALWAYS;
371   scrolled_window->vscrollbar_policy = GTK_POLICY_ALWAYS;
372   scrolled_window->hscrollbar_visible = FALSE;
373   scrolled_window->vscrollbar_visible = FALSE;
374   scrolled_window->focus_out = FALSE;
375   scrolled_window->window_placement = GTK_CORNER_TOP_LEFT;
376   gtk_scrolled_window_update_real_placement (scrolled_window);
377 }
378
379 /**
380  * gtk_scrolled_window_new:
381  * @hadjustment: (allow-none): horizontal adjustment
382  * @vadjustment: (allow-none): vertical adjustment
383  *
384  * Creates a new scrolled window.
385  *
386  * The two arguments are the scrolled window's adjustments; these will be
387  * shared with the scrollbars and the child widget to keep the bars in sync 
388  * with the child. Usually you want to pass %NULL for the adjustments, which 
389  * will cause the scrolled window to create them for you.
390  *
391  * Returns: a new scrolled window
392  */
393 GtkWidget*
394 gtk_scrolled_window_new (GtkAdjustment *hadjustment,
395                          GtkAdjustment *vadjustment)
396 {
397   GtkWidget *scrolled_window;
398
399   if (hadjustment)
400     g_return_val_if_fail (GTK_IS_ADJUSTMENT (hadjustment), NULL);
401
402   if (vadjustment)
403     g_return_val_if_fail (GTK_IS_ADJUSTMENT (vadjustment), NULL);
404
405   scrolled_window = g_object_new (GTK_TYPE_SCROLLED_WINDOW,
406                                     "hadjustment", hadjustment,
407                                     "vadjustment", vadjustment,
408                                     NULL);
409
410   return scrolled_window;
411 }
412
413 /**
414  * gtk_scrolled_window_set_hadjustment:
415  * @scrolled_window: a #GtkScrolledWindow
416  * @hadjustment: horizontal scroll adjustment
417  *
418  * Sets the #GtkAdjustment for the horizontal scrollbar.
419  */
420 void
421 gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
422                                      GtkAdjustment     *hadjustment)
423 {
424   GtkBin *bin;
425
426   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
427   if (hadjustment)
428     g_return_if_fail (GTK_IS_ADJUSTMENT (hadjustment));
429   else
430     hadjustment = (GtkAdjustment*) g_object_new (GTK_TYPE_ADJUSTMENT, NULL);
431
432   bin = GTK_BIN (scrolled_window);
433
434   if (!scrolled_window->hscrollbar)
435     {
436       gtk_widget_push_composite_child ();
437       scrolled_window->hscrollbar = gtk_hscrollbar_new (hadjustment);
438       gtk_widget_set_composite_name (scrolled_window->hscrollbar, "hscrollbar");
439       gtk_widget_pop_composite_child ();
440
441       gtk_widget_set_parent (scrolled_window->hscrollbar, GTK_WIDGET (scrolled_window));
442       g_object_ref (scrolled_window->hscrollbar);
443       gtk_widget_show (scrolled_window->hscrollbar);
444     }
445   else
446     {
447       GtkAdjustment *old_adjustment;
448       
449       old_adjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
450       if (old_adjustment == hadjustment)
451         return;
452
453       g_signal_handlers_disconnect_by_func (old_adjustment,
454                                             gtk_scrolled_window_adjustment_changed,
455                                             scrolled_window);
456       gtk_range_set_adjustment (GTK_RANGE (scrolled_window->hscrollbar),
457                                 hadjustment);
458     }
459   hadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
460   g_signal_connect (hadjustment,
461                     "changed",
462                     G_CALLBACK (gtk_scrolled_window_adjustment_changed),
463                     scrolled_window);
464   gtk_scrolled_window_adjustment_changed (hadjustment, scrolled_window);
465   
466   if (bin->child)
467     gtk_widget_set_scroll_adjustments (bin->child,
468                                        gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
469                                        gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)));
470
471   g_object_notify (G_OBJECT (scrolled_window), "hadjustment");
472 }
473
474 /**
475  * gtk_scrolled_window_set_vadjustment:
476  * @scrolled_window: a #GtkScrolledWindow
477  * @vadjustment: vertical scroll adjustment
478  *
479  * Sets the #GtkAdjustment for the vertical scrollbar.
480  */
481 void
482 gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
483                                      GtkAdjustment     *vadjustment)
484 {
485   GtkBin *bin;
486
487   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
488   if (vadjustment)
489     g_return_if_fail (GTK_IS_ADJUSTMENT (vadjustment));
490   else
491     vadjustment = (GtkAdjustment*) g_object_new (GTK_TYPE_ADJUSTMENT, NULL);
492
493   bin = GTK_BIN (scrolled_window);
494
495   if (!scrolled_window->vscrollbar)
496     {
497       gtk_widget_push_composite_child ();
498       scrolled_window->vscrollbar = gtk_vscrollbar_new (vadjustment);
499       gtk_widget_set_composite_name (scrolled_window->vscrollbar, "vscrollbar");
500       gtk_widget_pop_composite_child ();
501
502       gtk_widget_set_parent (scrolled_window->vscrollbar, GTK_WIDGET (scrolled_window));
503       g_object_ref (scrolled_window->vscrollbar);
504       gtk_widget_show (scrolled_window->vscrollbar);
505     }
506   else
507     {
508       GtkAdjustment *old_adjustment;
509       
510       old_adjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
511       if (old_adjustment == vadjustment)
512         return;
513
514       g_signal_handlers_disconnect_by_func (old_adjustment,
515                                             gtk_scrolled_window_adjustment_changed,
516                                             scrolled_window);
517       gtk_range_set_adjustment (GTK_RANGE (scrolled_window->vscrollbar),
518                                 vadjustment);
519     }
520   vadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
521   g_signal_connect (vadjustment,
522                     "changed",
523                     G_CALLBACK (gtk_scrolled_window_adjustment_changed),
524                     scrolled_window);
525   gtk_scrolled_window_adjustment_changed (vadjustment, scrolled_window);
526
527   if (bin->child)
528     gtk_widget_set_scroll_adjustments (bin->child,
529                                        gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
530                                        gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)));
531
532   g_object_notify (G_OBJECT (scrolled_window), "vadjustment");
533 }
534
535 /**
536  * gtk_scrolled_window_get_hadjustment:
537  * @scrolled_window: a #GtkScrolledWindow
538  *
539  * Returns the horizontal scrollbar's adjustment, used to connect the
540  * horizontal scrollbar to the child widget's horizontal scroll
541  * functionality.
542  *
543  * Returns: the horizontal #GtkAdjustment
544  */
545 GtkAdjustment*
546 gtk_scrolled_window_get_hadjustment (GtkScrolledWindow *scrolled_window)
547 {
548   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
549
550   return (scrolled_window->hscrollbar ?
551           gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)) :
552           NULL);
553 }
554
555 /**
556  * gtk_scrolled_window_get_vadjustment:
557  * @scrolled_window: a #GtkScrolledWindow
558  * 
559  * Returns the vertical scrollbar's adjustment, used to connect the
560  * vertical scrollbar to the child widget's vertical scroll
561  * functionality.
562  * 
563  * Returns: the vertical #GtkAdjustment
564  */
565 GtkAdjustment*
566 gtk_scrolled_window_get_vadjustment (GtkScrolledWindow *scrolled_window)
567 {
568   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
569
570   return (scrolled_window->vscrollbar ?
571           gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)) :
572           NULL);
573 }
574
575 /**
576  * gtk_scrolled_window_get_hscrollbar:
577  * @scrolled_window: a #GtkScrolledWindow
578  * 
579  * Returns the horizontal scrollbar of @scrolled_window.
580  *
581  * Returns: the horizontal scrollbar of the scrolled window, or 
582  *  %NULL if it does not have one.
583  *
584  * Since: 2.8
585  */
586 GtkWidget*
587 gtk_scrolled_window_get_hscrollbar (GtkScrolledWindow *scrolled_window)
588 {
589   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
590   
591   return scrolled_window->hscrollbar;
592 }
593
594 /**
595  * gtk_scrolled_window_get_vscrollbar:
596  * @scrolled_window: a #GtkScrolledWindow
597  * 
598  * Returns the vertical scrollbar of @scrolled_window.
599  *
600  * Returns: the vertical scrollbar of the scrolled window, or
601  *  %NULL if it does not have one.
602  *
603  * Since: 2.8
604  */
605 GtkWidget*
606 gtk_scrolled_window_get_vscrollbar (GtkScrolledWindow *scrolled_window)
607 {
608   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
609
610   return scrolled_window->vscrollbar;
611 }
612
613 /**
614  * gtk_scrolled_window_set_policy:
615  * @scrolled_window: a #GtkScrolledWindow
616  * @hscrollbar_policy: policy for horizontal bar
617  * @vscrollbar_policy: policy for vertical bar
618  * 
619  * Sets the scrollbar policy for the horizontal and vertical scrollbars.
620  *
621  * The policy determines when the scrollbar should appear; it is a value
622  * from the #GtkPolicyType enumeration. If %GTK_POLICY_ALWAYS, the
623  * scrollbar is always present; if %GTK_POLICY_NEVER, the scrollbar is
624  * never present; if %GTK_POLICY_AUTOMATIC, the scrollbar is present only
625  * if needed (that is, if the slider part of the bar would be smaller
626  * than the trough - the display is larger than the page size).
627  */
628 void
629 gtk_scrolled_window_set_policy (GtkScrolledWindow *scrolled_window,
630                                 GtkPolicyType      hscrollbar_policy,
631                                 GtkPolicyType      vscrollbar_policy)
632 {
633   GObject *object = G_OBJECT (scrolled_window);
634   
635   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
636
637   if ((scrolled_window->hscrollbar_policy != hscrollbar_policy) ||
638       (scrolled_window->vscrollbar_policy != vscrollbar_policy))
639     {
640       scrolled_window->hscrollbar_policy = hscrollbar_policy;
641       scrolled_window->vscrollbar_policy = vscrollbar_policy;
642
643       gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
644
645       g_object_freeze_notify (object);
646       g_object_notify (object, "hscrollbar-policy");
647       g_object_notify (object, "vscrollbar-policy");
648       g_object_thaw_notify (object);
649     }
650 }
651
652 /**
653  * gtk_scrolled_window_get_policy:
654  * @scrolled_window: a #GtkScrolledWindow
655  * @hscrollbar_policy: location to store the policy for the horizontal 
656  *     scrollbar, or %NULL.
657  * @vscrollbar_policy: location to store the policy for the vertical
658  *     scrollbar, or %NULL.
659  * 
660  * Retrieves the current policy values for the horizontal and vertical
661  * scrollbars. See gtk_scrolled_window_set_policy().
662  */
663 void
664 gtk_scrolled_window_get_policy (GtkScrolledWindow *scrolled_window,
665                                 GtkPolicyType     *hscrollbar_policy,
666                                 GtkPolicyType     *vscrollbar_policy)
667 {
668   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
669
670   if (hscrollbar_policy)
671     *hscrollbar_policy = scrolled_window->hscrollbar_policy;
672   if (vscrollbar_policy)
673     *vscrollbar_policy = scrolled_window->vscrollbar_policy;
674 }
675
676 static void
677 gtk_scrolled_window_update_real_placement (GtkScrolledWindow *scrolled_window)
678 {
679   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
680   GtkSettings *settings;
681
682   settings = gtk_widget_get_settings (GTK_WIDGET (scrolled_window));
683
684   if (priv->window_placement_set || settings == NULL)
685     priv->real_window_placement = scrolled_window->window_placement;
686   else
687     g_object_get (settings,
688                   "gtk-scrolled-window-placement",
689                   &priv->real_window_placement,
690                   NULL);
691 }
692
693 static void
694 gtk_scrolled_window_set_placement_internal (GtkScrolledWindow *scrolled_window,
695                                             GtkCornerType      window_placement)
696 {
697   if (scrolled_window->window_placement != window_placement)
698     {
699       scrolled_window->window_placement = window_placement;
700
701       gtk_scrolled_window_update_real_placement (scrolled_window);
702       gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
703       
704       g_object_notify (G_OBJECT (scrolled_window), "window-placement");
705     }
706 }
707
708 static void
709 gtk_scrolled_window_set_placement_set (GtkScrolledWindow *scrolled_window,
710                                        gboolean           placement_set,
711                                        gboolean           emit_resize)
712 {
713   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
714
715   if (priv->window_placement_set != placement_set)
716     {
717       priv->window_placement_set = placement_set;
718
719       gtk_scrolled_window_update_real_placement (scrolled_window);
720       if (emit_resize)
721         gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
722
723       g_object_notify (G_OBJECT (scrolled_window), "window-placement-set");
724     }
725 }
726
727 /**
728  * gtk_scrolled_window_set_placement:
729  * @scrolled_window: a #GtkScrolledWindow
730  * @window_placement: position of the child window
731  *
732  * Sets the placement of the contents with respect to the scrollbars
733  * for the scrolled window.
734  * 
735  * The default is %GTK_CORNER_TOP_LEFT, meaning the child is
736  * in the top left, with the scrollbars underneath and to the right.
737  * Other values in #GtkCornerType are %GTK_CORNER_TOP_RIGHT,
738  * %GTK_CORNER_BOTTOM_LEFT, and %GTK_CORNER_BOTTOM_RIGHT.
739  *
740  * See also gtk_scrolled_window_get_placement() and
741  * gtk_scrolled_window_unset_placement().
742  */
743 void
744 gtk_scrolled_window_set_placement (GtkScrolledWindow *scrolled_window,
745                                    GtkCornerType      window_placement)
746 {
747   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
748
749   gtk_scrolled_window_set_placement_set (scrolled_window, TRUE, FALSE);
750   gtk_scrolled_window_set_placement_internal (scrolled_window, window_placement);
751 }
752
753 /**
754  * gtk_scrolled_window_get_placement:
755  * @scrolled_window: a #GtkScrolledWindow
756  *
757  * Gets the placement of the contents with respect to the scrollbars
758  * for the scrolled window. See gtk_scrolled_window_set_placement().
759  *
760  * Return value: the current placement value.
761  *
762  * See also gtk_scrolled_window_set_placement() and
763  * gtk_scrolled_window_unset_placement().
764  **/
765 GtkCornerType
766 gtk_scrolled_window_get_placement (GtkScrolledWindow *scrolled_window)
767 {
768   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), GTK_CORNER_TOP_LEFT);
769
770   return scrolled_window->window_placement;
771 }
772
773 /**
774  * gtk_scrolled_window_unset_placement:
775  * @scrolled_window: a #GtkScrolledWindow
776  *
777  * Unsets the placement of the contents with respect to the scrollbars
778  * for the scrolled window. If no window placement is set for a scrolled
779  * window, it obeys the "gtk-scrolled-window-placement" XSETTING.
780  *
781  * See also gtk_scrolled_window_set_placement() and
782  * gtk_scrolled_window_get_placement().
783  *
784  * Since: 2.10
785  **/
786 void
787 gtk_scrolled_window_unset_placement (GtkScrolledWindow *scrolled_window)
788 {
789   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
790
791   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
792
793   if (priv->window_placement_set)
794     {
795       priv->window_placement_set = FALSE;
796
797       gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
798
799       g_object_notify (G_OBJECT (scrolled_window), "window-placement-set");
800     }
801 }
802
803 /**
804  * gtk_scrolled_window_set_shadow_type:
805  * @scrolled_window: a #GtkScrolledWindow
806  * @type: kind of shadow to draw around scrolled window contents
807  *
808  * Changes the type of shadow drawn around the contents of
809  * @scrolled_window.
810  * 
811  **/
812 void
813 gtk_scrolled_window_set_shadow_type (GtkScrolledWindow *scrolled_window,
814                                      GtkShadowType      type)
815 {
816   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
817   g_return_if_fail (type >= GTK_SHADOW_NONE && type <= GTK_SHADOW_ETCHED_OUT);
818   
819   if (scrolled_window->shadow_type != type)
820     {
821       scrolled_window->shadow_type = type;
822
823       if (gtk_widget_is_drawable (GTK_WIDGET (scrolled_window)))
824         gtk_widget_queue_draw (GTK_WIDGET (scrolled_window));
825
826       gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
827
828       g_object_notify (G_OBJECT (scrolled_window), "shadow-type");
829     }
830 }
831
832 /**
833  * gtk_scrolled_window_get_shadow_type:
834  * @scrolled_window: a #GtkScrolledWindow
835  *
836  * Gets the shadow type of the scrolled window. See 
837  * gtk_scrolled_window_set_shadow_type().
838  *
839  * Return value: the current shadow type
840  **/
841 GtkShadowType
842 gtk_scrolled_window_get_shadow_type (GtkScrolledWindow *scrolled_window)
843 {
844   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_NONE);
845
846   return scrolled_window->shadow_type;
847 }
848
849 static void
850 gtk_scrolled_window_destroy (GtkObject *object)
851 {
852   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (object);
853
854   if (scrolled_window->hscrollbar)
855     {
856       g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
857                                             gtk_scrolled_window_adjustment_changed,
858                                             scrolled_window);
859       gtk_widget_unparent (scrolled_window->hscrollbar);
860       gtk_widget_destroy (scrolled_window->hscrollbar);
861       g_object_unref (scrolled_window->hscrollbar);
862       scrolled_window->hscrollbar = NULL;
863     }
864   if (scrolled_window->vscrollbar)
865     {
866       g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)),
867                                             gtk_scrolled_window_adjustment_changed,
868                                             scrolled_window);
869       gtk_widget_unparent (scrolled_window->vscrollbar);
870       gtk_widget_destroy (scrolled_window->vscrollbar);
871       g_object_unref (scrolled_window->vscrollbar);
872       scrolled_window->vscrollbar = NULL;
873     }
874
875   GTK_OBJECT_CLASS (gtk_scrolled_window_parent_class)->destroy (object);
876 }
877
878 static void
879 gtk_scrolled_window_set_property (GObject      *object,
880                                   guint         prop_id,
881                                   const GValue *value,
882                                   GParamSpec   *pspec)
883 {
884   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (object);
885   
886   switch (prop_id)
887     {
888     case PROP_HADJUSTMENT:
889       gtk_scrolled_window_set_hadjustment (scrolled_window,
890                                            g_value_get_object (value));
891       break;
892     case PROP_VADJUSTMENT:
893       gtk_scrolled_window_set_vadjustment (scrolled_window,
894                                            g_value_get_object (value));
895       break;
896     case PROP_HSCROLLBAR_POLICY:
897       gtk_scrolled_window_set_policy (scrolled_window,
898                                       g_value_get_enum (value),
899                                       scrolled_window->vscrollbar_policy);
900       break;
901     case PROP_VSCROLLBAR_POLICY:
902       gtk_scrolled_window_set_policy (scrolled_window,
903                                       scrolled_window->hscrollbar_policy,
904                                       g_value_get_enum (value));
905       break;
906     case PROP_WINDOW_PLACEMENT:
907       gtk_scrolled_window_set_placement_internal (scrolled_window,
908                                                   g_value_get_enum (value));
909       break;
910     case PROP_WINDOW_PLACEMENT_SET:
911       gtk_scrolled_window_set_placement_set (scrolled_window,
912                                              g_value_get_boolean (value),
913                                              TRUE);
914       break;
915     case PROP_SHADOW_TYPE:
916       gtk_scrolled_window_set_shadow_type (scrolled_window,
917                                            g_value_get_enum (value));
918       break;
919     default:
920       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
921       break;
922     }
923 }
924
925 static void
926 gtk_scrolled_window_get_property (GObject    *object,
927                                   guint       prop_id,
928                                   GValue     *value,
929                                   GParamSpec *pspec)
930 {
931   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (object);
932   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
933   
934   switch (prop_id)
935     {
936     case PROP_HADJUSTMENT:
937       g_value_set_object (value,
938                           G_OBJECT (gtk_scrolled_window_get_hadjustment (scrolled_window)));
939       break;
940     case PROP_VADJUSTMENT:
941       g_value_set_object (value,
942                           G_OBJECT (gtk_scrolled_window_get_vadjustment (scrolled_window)));
943       break;
944     case PROP_HSCROLLBAR_POLICY:
945       g_value_set_enum (value, scrolled_window->hscrollbar_policy);
946       break;
947     case PROP_VSCROLLBAR_POLICY:
948       g_value_set_enum (value, scrolled_window->vscrollbar_policy);
949       break;
950     case PROP_WINDOW_PLACEMENT:
951       g_value_set_enum (value, scrolled_window->window_placement);
952       break;
953     case PROP_WINDOW_PLACEMENT_SET:
954       g_value_set_boolean (value, priv->window_placement_set);
955       break;
956     case PROP_SHADOW_TYPE:
957       g_value_set_enum (value, scrolled_window->shadow_type);
958       break;
959     default:
960       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
961       break;
962     }
963 }
964
965 static void
966 traverse_container (GtkWidget *widget,
967                     gpointer   data)
968 {
969   if (GTK_IS_SCROLLED_WINDOW (widget))
970     {
971       gtk_scrolled_window_update_real_placement (GTK_SCROLLED_WINDOW (widget));
972       gtk_widget_queue_resize (widget);
973     }
974   else if (GTK_IS_CONTAINER (widget))
975     gtk_container_forall (GTK_CONTAINER (widget), traverse_container, NULL);
976 }
977
978 static void
979 gtk_scrolled_window_settings_changed (GtkSettings *settings)
980 {
981   GList *list, *l;
982
983   list = gtk_window_list_toplevels ();
984
985   for (l = list; l; l = l->next)
986     gtk_container_forall (GTK_CONTAINER (l->data), 
987                           traverse_container, NULL);
988
989   g_list_free (list);
990 }
991
992 static void
993 gtk_scrolled_window_screen_changed (GtkWidget *widget,
994                                     GdkScreen *previous_screen)
995 {
996   GtkSettings *settings;
997   guint window_placement_connection;
998
999   gtk_scrolled_window_update_real_placement (GTK_SCROLLED_WINDOW (widget));
1000
1001   if (!gtk_widget_has_screen (widget))
1002     return;
1003
1004   settings = gtk_widget_get_settings (widget);
1005
1006   window_placement_connection = 
1007     GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (settings), 
1008                                          "gtk-scrolled-window-connection"));
1009   
1010   if (window_placement_connection)
1011     return;
1012
1013   window_placement_connection =
1014     g_signal_connect (settings, "notify::gtk-scrolled-window-placement",
1015                       G_CALLBACK (gtk_scrolled_window_settings_changed), NULL);
1016   g_object_set_data (G_OBJECT (settings), 
1017                      I_("gtk-scrolled-window-connection"),
1018                      GUINT_TO_POINTER (window_placement_connection));
1019 }
1020
1021 static void
1022 gtk_scrolled_window_paint (GtkWidget    *widget,
1023                            GdkRectangle *area)
1024 {
1025   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
1026
1027   if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
1028     {
1029       GtkAllocation relative_allocation;
1030       gboolean scrollbars_within_bevel;
1031
1032       gtk_widget_style_get (widget, "scrollbars-within-bevel", &scrollbars_within_bevel, NULL);
1033       
1034       if (!scrollbars_within_bevel)
1035         {
1036           gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
1037
1038           relative_allocation.x -= widget->style->xthickness;
1039           relative_allocation.y -= widget->style->ythickness;
1040           relative_allocation.width += 2 * widget->style->xthickness;
1041           relative_allocation.height += 2 * widget->style->ythickness;
1042         }
1043       else
1044         {
1045           GtkContainer *container = GTK_CONTAINER (widget);
1046
1047           relative_allocation.x = container->border_width;
1048           relative_allocation.y = container->border_width;
1049           relative_allocation.width = widget->allocation.width - 2 * container->border_width;
1050           relative_allocation.height = widget->allocation.height - 2 * container->border_width;
1051         }
1052
1053       gtk_paint_shadow (widget->style, widget->window,
1054                         GTK_STATE_NORMAL, scrolled_window->shadow_type,
1055                         area, widget, "scrolled_window",
1056                         widget->allocation.x + relative_allocation.x,
1057                         widget->allocation.y + relative_allocation.y,
1058                         relative_allocation.width,
1059                         relative_allocation.height);
1060     }
1061 }
1062
1063 static gboolean
1064 gtk_scrolled_window_expose (GtkWidget      *widget,
1065                             GdkEventExpose *event)
1066 {
1067   if (gtk_widget_is_drawable (widget))
1068     {
1069       gtk_scrolled_window_paint (widget, &event->area);
1070
1071       GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->expose_event (widget, event);
1072     }
1073
1074   return FALSE;
1075 }
1076
1077 static void
1078 gtk_scrolled_window_forall (GtkContainer *container,
1079                             gboolean      include_internals,
1080                             GtkCallback   callback,
1081                             gpointer      callback_data)
1082 {
1083   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
1084   g_return_if_fail (callback != NULL);
1085
1086   GTK_CONTAINER_CLASS (gtk_scrolled_window_parent_class)->forall (container,
1087                                               include_internals,
1088                                               callback,
1089                                               callback_data);
1090   if (include_internals)
1091     {
1092       GtkScrolledWindow *scrolled_window;
1093
1094       scrolled_window = GTK_SCROLLED_WINDOW (container);
1095       
1096       if (scrolled_window->vscrollbar)
1097         callback (scrolled_window->vscrollbar, callback_data);
1098       if (scrolled_window->hscrollbar)
1099         callback (scrolled_window->hscrollbar, callback_data);
1100     }
1101 }
1102
1103 static gboolean
1104 gtk_scrolled_window_scroll_child (GtkScrolledWindow *scrolled_window,
1105                                   GtkScrollType      scroll,
1106                                   gboolean           horizontal)
1107 {
1108   GtkAdjustment *adjustment = NULL;
1109   
1110   switch (scroll)
1111     {
1112     case GTK_SCROLL_STEP_UP:
1113       scroll = GTK_SCROLL_STEP_BACKWARD;
1114       horizontal = FALSE;
1115       break;
1116     case GTK_SCROLL_STEP_DOWN:
1117       scroll = GTK_SCROLL_STEP_FORWARD;
1118       horizontal = FALSE;
1119       break;
1120     case GTK_SCROLL_STEP_LEFT:
1121       scroll = GTK_SCROLL_STEP_BACKWARD;
1122       horizontal = TRUE;
1123       break;
1124     case GTK_SCROLL_STEP_RIGHT:
1125       scroll = GTK_SCROLL_STEP_FORWARD;
1126       horizontal = TRUE;
1127       break;
1128     case GTK_SCROLL_PAGE_UP:
1129       scroll = GTK_SCROLL_PAGE_BACKWARD;
1130       horizontal = FALSE;
1131       break;
1132     case GTK_SCROLL_PAGE_DOWN:
1133       scroll = GTK_SCROLL_PAGE_FORWARD;
1134       horizontal = FALSE;
1135       break;
1136     case GTK_SCROLL_PAGE_LEFT:
1137       scroll = GTK_SCROLL_STEP_BACKWARD;
1138       horizontal = TRUE;
1139       break;
1140     case GTK_SCROLL_PAGE_RIGHT:
1141       scroll = GTK_SCROLL_STEP_FORWARD;
1142       horizontal = TRUE;
1143       break;
1144     case GTK_SCROLL_STEP_BACKWARD:
1145     case GTK_SCROLL_STEP_FORWARD:
1146     case GTK_SCROLL_PAGE_BACKWARD:
1147     case GTK_SCROLL_PAGE_FORWARD:
1148     case GTK_SCROLL_START:
1149     case GTK_SCROLL_END:
1150       break;
1151     default:
1152       g_warning ("Invalid scroll type %u for GtkScrolledWindow::scroll-child", scroll);
1153       return FALSE;
1154     }
1155
1156   if ((horizontal && (!scrolled_window->hscrollbar || !scrolled_window->hscrollbar_visible)) ||
1157       (!horizontal && (!scrolled_window->vscrollbar || !scrolled_window->vscrollbar_visible)))
1158     return FALSE;
1159
1160   if (horizontal)
1161     {
1162       if (scrolled_window->hscrollbar)
1163         adjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
1164     }
1165   else
1166     {
1167       if (scrolled_window->vscrollbar)
1168         adjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
1169     }
1170
1171   if (adjustment)
1172     {
1173       gdouble value = adjustment->value;
1174       
1175       switch (scroll)
1176         {
1177         case GTK_SCROLL_STEP_FORWARD:
1178           value += adjustment->step_increment;
1179           break;
1180         case GTK_SCROLL_STEP_BACKWARD:
1181           value -= adjustment->step_increment;
1182           break;
1183         case GTK_SCROLL_PAGE_FORWARD:
1184           value += adjustment->page_increment;
1185           break;
1186         case GTK_SCROLL_PAGE_BACKWARD:
1187           value -= adjustment->page_increment;
1188           break;
1189         case GTK_SCROLL_START:
1190           value = adjustment->lower;
1191           break;
1192         case GTK_SCROLL_END:
1193           value = adjustment->upper;
1194           break;
1195         default:
1196           g_assert_not_reached ();
1197           break;
1198         }
1199
1200       value = CLAMP (value, adjustment->lower, adjustment->upper - adjustment->page_size);
1201       
1202       gtk_adjustment_set_value (adjustment, value);
1203
1204       return TRUE;
1205     }
1206
1207   return FALSE;
1208 }
1209
1210 static void
1211 gtk_scrolled_window_move_focus_out (GtkScrolledWindow *scrolled_window,
1212                                     GtkDirectionType   direction_type)
1213 {
1214   GtkWidget *toplevel;
1215   
1216   /* Focus out of the scrolled window entirely. We do this by setting
1217    * a flag, then propagating the focus motion to the notebook.
1218    */
1219   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (scrolled_window));
1220   if (!gtk_widget_is_toplevel (toplevel))
1221     return;
1222
1223   g_object_ref (scrolled_window);
1224   
1225   scrolled_window->focus_out = TRUE;
1226   g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1227   scrolled_window->focus_out = FALSE;
1228   
1229   g_object_unref (scrolled_window);
1230 }
1231
1232 static void
1233 gtk_scrolled_window_size_request (GtkWidget      *widget,
1234                                   GtkRequisition *requisition)
1235 {
1236   GtkScrolledWindow *scrolled_window;
1237   GtkBin *bin;
1238   gint extra_width;
1239   gint extra_height;
1240   gint scrollbar_spacing;
1241   GtkRequisition hscrollbar_requisition;
1242   GtkRequisition vscrollbar_requisition;
1243   GtkRequisition child_requisition;
1244
1245   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
1246   g_return_if_fail (requisition != NULL);
1247
1248   scrolled_window = GTK_SCROLLED_WINDOW (widget);
1249   bin = GTK_BIN (scrolled_window);
1250
1251   scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
1252
1253   extra_width = 0;
1254   extra_height = 0;
1255   requisition->width = 0;
1256   requisition->height = 0;
1257   
1258   gtk_widget_size_request (scrolled_window->hscrollbar,
1259                            &hscrollbar_requisition);
1260   gtk_widget_size_request (scrolled_window->vscrollbar,
1261                            &vscrollbar_requisition);
1262   
1263   if (bin->child && gtk_widget_get_visible (bin->child))
1264     {
1265       gtk_widget_size_request (bin->child, &child_requisition);
1266
1267       if (scrolled_window->hscrollbar_policy == GTK_POLICY_NEVER)
1268         requisition->width += child_requisition.width;
1269       else
1270         {
1271           GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (bin->child, FALSE);
1272
1273           if (aux_info && aux_info->width > 0)
1274             {
1275               requisition->width += aux_info->width;
1276               extra_width = -1;
1277             }
1278           else
1279             requisition->width += vscrollbar_requisition.width;
1280         }
1281
1282       if (scrolled_window->vscrollbar_policy == GTK_POLICY_NEVER)
1283         requisition->height += child_requisition.height;
1284       else
1285         {
1286           GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (bin->child, FALSE);
1287
1288           if (aux_info && aux_info->height > 0)
1289             {
1290               requisition->height += aux_info->height;
1291               extra_height = -1;
1292             }
1293           else
1294             requisition->height += hscrollbar_requisition.height;
1295         }
1296     }
1297
1298   if (scrolled_window->hscrollbar_policy == GTK_POLICY_AUTOMATIC ||
1299       scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
1300     {
1301       requisition->width = MAX (requisition->width, hscrollbar_requisition.width);
1302       if (!extra_height || scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
1303         extra_height = scrollbar_spacing + hscrollbar_requisition.height;
1304     }
1305
1306   if (scrolled_window->vscrollbar_policy == GTK_POLICY_AUTOMATIC ||
1307       scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
1308     {
1309       requisition->height = MAX (requisition->height, vscrollbar_requisition.height);
1310       if (!extra_height || scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
1311         extra_width = scrollbar_spacing + vscrollbar_requisition.width;
1312     }
1313
1314   requisition->width += GTK_CONTAINER (widget)->border_width * 2 + MAX (0, extra_width);
1315   requisition->height += GTK_CONTAINER (widget)->border_width * 2 + MAX (0, extra_height);
1316
1317   if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
1318     {
1319       requisition->width += 2 * widget->style->xthickness;
1320       requisition->height += 2 * widget->style->ythickness;
1321     }
1322 }
1323
1324 static void
1325 gtk_scrolled_window_relative_allocation (GtkWidget     *widget,
1326                                          GtkAllocation *allocation)
1327 {
1328   GtkScrolledWindow *scrolled_window;
1329   GtkScrolledWindowPrivate *priv;
1330   gint scrollbar_spacing;
1331
1332   g_return_if_fail (widget != NULL);
1333   g_return_if_fail (allocation != NULL);
1334
1335   scrolled_window = GTK_SCROLLED_WINDOW (widget);
1336   scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
1337
1338   priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
1339
1340   allocation->x = GTK_CONTAINER (widget)->border_width;
1341   allocation->y = GTK_CONTAINER (widget)->border_width;
1342
1343   if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
1344     {
1345       allocation->x += widget->style->xthickness;
1346       allocation->y += widget->style->ythickness;
1347     }
1348   
1349   allocation->width = MAX (1, (gint)widget->allocation.width - allocation->x * 2);
1350   allocation->height = MAX (1, (gint)widget->allocation.height - allocation->y * 2);
1351
1352   if (scrolled_window->vscrollbar_visible)
1353     {
1354       GtkRequisition vscrollbar_requisition;
1355       gboolean is_rtl;
1356
1357       gtk_widget_get_child_requisition (scrolled_window->vscrollbar,
1358                                         &vscrollbar_requisition);
1359       is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1360   
1361       if ((!is_rtl && 
1362            (priv->real_window_placement == GTK_CORNER_TOP_RIGHT ||
1363             priv->real_window_placement == GTK_CORNER_BOTTOM_RIGHT)) ||
1364           (is_rtl && 
1365            (priv->real_window_placement == GTK_CORNER_TOP_LEFT ||
1366             priv->real_window_placement == GTK_CORNER_BOTTOM_LEFT)))
1367         allocation->x += (vscrollbar_requisition.width +  scrollbar_spacing);
1368
1369       allocation->width = MAX (1, allocation->width - (vscrollbar_requisition.width + scrollbar_spacing));
1370     }
1371   if (scrolled_window->hscrollbar_visible)
1372     {
1373       GtkRequisition hscrollbar_requisition;
1374       gtk_widget_get_child_requisition (scrolled_window->hscrollbar,
1375                                         &hscrollbar_requisition);
1376   
1377       if (priv->real_window_placement == GTK_CORNER_BOTTOM_LEFT ||
1378           priv->real_window_placement == GTK_CORNER_BOTTOM_RIGHT)
1379         allocation->y += (hscrollbar_requisition.height + scrollbar_spacing);
1380
1381       allocation->height = MAX (1, allocation->height - (hscrollbar_requisition.height + scrollbar_spacing));
1382     }
1383 }
1384
1385 static void
1386 gtk_scrolled_window_size_allocate (GtkWidget     *widget,
1387                                    GtkAllocation *allocation)
1388 {
1389   GtkScrolledWindow *scrolled_window;
1390   GtkScrolledWindowPrivate *priv;
1391   GtkBin *bin;
1392   GtkAllocation relative_allocation;
1393   GtkAllocation child_allocation;
1394   gboolean scrollbars_within_bevel;
1395   gint scrollbar_spacing;
1396   
1397   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
1398   g_return_if_fail (allocation != NULL);
1399
1400   scrolled_window = GTK_SCROLLED_WINDOW (widget);
1401   bin = GTK_BIN (scrolled_window);
1402
1403   scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
1404   gtk_widget_style_get (widget, "scrollbars-within-bevel", &scrollbars_within_bevel, NULL);
1405
1406   priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
1407
1408   widget->allocation = *allocation;
1409
1410   if (scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
1411     scrolled_window->hscrollbar_visible = TRUE;
1412   else if (scrolled_window->hscrollbar_policy == GTK_POLICY_NEVER)
1413     scrolled_window->hscrollbar_visible = FALSE;
1414   if (scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
1415     scrolled_window->vscrollbar_visible = TRUE;
1416   else if (scrolled_window->vscrollbar_policy == GTK_POLICY_NEVER)
1417     scrolled_window->vscrollbar_visible = FALSE;
1418
1419   if (bin->child && gtk_widget_get_visible (bin->child))
1420     {
1421       gboolean previous_hvis;
1422       gboolean previous_vvis;
1423       guint count = 0;
1424       
1425       do
1426         {
1427           gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
1428           
1429           child_allocation.x = relative_allocation.x + allocation->x;
1430           child_allocation.y = relative_allocation.y + allocation->y;
1431           child_allocation.width = relative_allocation.width;
1432           child_allocation.height = relative_allocation.height;
1433           
1434           previous_hvis = scrolled_window->hscrollbar_visible;
1435           previous_vvis = scrolled_window->vscrollbar_visible;
1436           
1437           gtk_widget_size_allocate (bin->child, &child_allocation);
1438
1439           /* If, after the first iteration, the hscrollbar and the
1440            * vscrollbar flip visiblity, then we need both.
1441            */
1442           if (count &&
1443               previous_hvis != scrolled_window->hscrollbar_visible &&
1444               previous_vvis != scrolled_window->vscrollbar_visible)
1445             {
1446               scrolled_window->hscrollbar_visible = TRUE;
1447               scrolled_window->vscrollbar_visible = TRUE;
1448
1449               /* a new resize is already queued at this point,
1450                * so we will immediatedly get reinvoked
1451                */
1452               return;
1453             }
1454           
1455           count++;
1456         }
1457       while (previous_hvis != scrolled_window->hscrollbar_visible ||
1458              previous_vvis != scrolled_window->vscrollbar_visible);
1459     }
1460   else
1461     {
1462       scrolled_window->hscrollbar_visible = scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS;
1463       scrolled_window->vscrollbar_visible = scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS;
1464       gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
1465     }
1466   
1467   if (scrolled_window->hscrollbar_visible)
1468     {
1469       GtkRequisition hscrollbar_requisition;
1470       gtk_widget_get_child_requisition (scrolled_window->hscrollbar,
1471                                         &hscrollbar_requisition);
1472   
1473       if (!gtk_widget_get_visible (scrolled_window->hscrollbar))
1474         gtk_widget_show (scrolled_window->hscrollbar);
1475
1476       child_allocation.x = relative_allocation.x;
1477       if (priv->real_window_placement == GTK_CORNER_TOP_LEFT ||
1478           priv->real_window_placement == GTK_CORNER_TOP_RIGHT)
1479         child_allocation.y = (relative_allocation.y +
1480                               relative_allocation.height +
1481                               scrollbar_spacing +
1482                               (scrolled_window->shadow_type == GTK_SHADOW_NONE ?
1483                                0 : widget->style->ythickness));
1484       else
1485         child_allocation.y = GTK_CONTAINER (scrolled_window)->border_width;
1486
1487       child_allocation.width = relative_allocation.width;
1488       child_allocation.height = hscrollbar_requisition.height;
1489       child_allocation.x += allocation->x;
1490       child_allocation.y += allocation->y;
1491
1492       if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
1493         {
1494           if (!scrollbars_within_bevel)
1495             {
1496               child_allocation.x -= widget->style->xthickness;
1497               child_allocation.width += 2 * widget->style->xthickness;
1498             }
1499           else if (GTK_CORNER_TOP_RIGHT == priv->real_window_placement ||
1500                    GTK_CORNER_TOP_LEFT == priv->real_window_placement)
1501             {
1502               child_allocation.y -= widget->style->ythickness;
1503             }
1504           else
1505             {
1506               child_allocation.y += widget->style->ythickness;
1507             }
1508         }
1509
1510       gtk_widget_size_allocate (scrolled_window->hscrollbar, &child_allocation);
1511     }
1512   else if (gtk_widget_get_visible (scrolled_window->hscrollbar))
1513     gtk_widget_hide (scrolled_window->hscrollbar);
1514
1515   if (scrolled_window->vscrollbar_visible)
1516     {
1517       GtkRequisition vscrollbar_requisition;
1518       if (!gtk_widget_get_visible (scrolled_window->vscrollbar))
1519         gtk_widget_show (scrolled_window->vscrollbar);
1520
1521       gtk_widget_get_child_requisition (scrolled_window->vscrollbar,
1522                                         &vscrollbar_requisition);
1523
1524       if ((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL && 
1525            (priv->real_window_placement == GTK_CORNER_TOP_RIGHT ||
1526             priv->real_window_placement == GTK_CORNER_BOTTOM_RIGHT)) ||
1527           (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR && 
1528            (priv->real_window_placement == GTK_CORNER_TOP_LEFT ||
1529             priv->real_window_placement == GTK_CORNER_BOTTOM_LEFT)))
1530         child_allocation.x = (relative_allocation.x +
1531                               relative_allocation.width +
1532                               scrollbar_spacing +
1533                               (scrolled_window->shadow_type == GTK_SHADOW_NONE ?
1534                                0 : widget->style->xthickness));
1535       else
1536         child_allocation.x = GTK_CONTAINER (scrolled_window)->border_width;
1537
1538       child_allocation.y = relative_allocation.y;
1539       child_allocation.width = vscrollbar_requisition.width;
1540       child_allocation.height = relative_allocation.height;
1541       child_allocation.x += allocation->x;
1542       child_allocation.y += allocation->y;
1543
1544       if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
1545         {
1546           if (!scrollbars_within_bevel)
1547             {
1548               child_allocation.y -= widget->style->ythickness;
1549               child_allocation.height += 2 * widget->style->ythickness;
1550             }
1551           else if (GTK_CORNER_BOTTOM_LEFT == priv->real_window_placement ||
1552                    GTK_CORNER_TOP_LEFT == priv->real_window_placement)
1553             {
1554               child_allocation.x -= widget->style->xthickness;
1555             }
1556           else
1557             {
1558               child_allocation.x += widget->style->xthickness;
1559             }
1560         }
1561
1562       gtk_widget_size_allocate (scrolled_window->vscrollbar, &child_allocation);
1563     }
1564   else if (gtk_widget_get_visible (scrolled_window->vscrollbar))
1565     gtk_widget_hide (scrolled_window->vscrollbar);
1566 }
1567
1568 static gboolean
1569 gtk_scrolled_window_scroll_event (GtkWidget      *widget,
1570                                   GdkEventScroll *event)
1571 {
1572   GtkWidget *range;
1573
1574   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (widget), FALSE);
1575   g_return_val_if_fail (event != NULL, FALSE);  
1576
1577   if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_DOWN)
1578     range = GTK_SCROLLED_WINDOW (widget)->vscrollbar;
1579   else
1580     range = GTK_SCROLLED_WINDOW (widget)->hscrollbar;
1581
1582   if (range && gtk_widget_get_visible (range))
1583     {
1584       GtkAdjustment *adj = GTK_RANGE (range)->adjustment;
1585       gdouble delta, new_value;
1586
1587       delta = _gtk_range_get_wheel_delta (GTK_RANGE (range), event->direction);
1588
1589       new_value = CLAMP (adj->value + delta, adj->lower, adj->upper - adj->page_size);
1590       
1591       gtk_adjustment_set_value (adj, new_value);
1592
1593       return TRUE;
1594     }
1595
1596   return FALSE;
1597 }
1598
1599 static gboolean
1600 gtk_scrolled_window_focus (GtkWidget        *widget,
1601                            GtkDirectionType  direction)
1602 {
1603   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
1604   gboolean had_focus_child = GTK_CONTAINER (widget)->focus_child != NULL;
1605   
1606   if (scrolled_window->focus_out)
1607     {
1608       scrolled_window->focus_out = FALSE; /* Clear this to catch the wrap-around case */
1609       return FALSE;
1610     }
1611   
1612   if (gtk_widget_is_focus (widget))
1613     return FALSE;
1614
1615   /* We only put the scrolled window itself in the focus chain if it
1616    * isn't possible to focus any children.
1617    */
1618   if (GTK_BIN (widget)->child)
1619     {
1620       if (gtk_widget_child_focus (GTK_BIN (widget)->child, direction))
1621         return TRUE;
1622     }
1623
1624   if (!had_focus_child && gtk_widget_get_can_focus (widget))
1625     {
1626       gtk_widget_grab_focus (widget);
1627       return TRUE;
1628     }
1629   else
1630     return FALSE;
1631 }
1632
1633 static void
1634 gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment,
1635                                         gpointer       data)
1636 {
1637   GtkScrolledWindow *scrolled_win;
1638
1639   g_return_if_fail (adjustment != NULL);
1640   g_return_if_fail (data != NULL);
1641
1642   scrolled_win = GTK_SCROLLED_WINDOW (data);
1643
1644   if (scrolled_win->hscrollbar &&
1645       adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_win->hscrollbar)))
1646     {
1647       if (scrolled_win->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
1648         {
1649           gboolean visible;
1650           
1651           visible = scrolled_win->hscrollbar_visible;
1652           scrolled_win->hscrollbar_visible = (adjustment->upper - adjustment->lower >
1653                                               adjustment->page_size);
1654           if (scrolled_win->hscrollbar_visible != visible)
1655             gtk_widget_queue_resize (GTK_WIDGET (scrolled_win));
1656         }
1657     }
1658   else if (scrolled_win->vscrollbar &&
1659            adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_win->vscrollbar)))
1660     {
1661       if (scrolled_win->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
1662         {
1663           gboolean visible;
1664
1665           visible = scrolled_win->vscrollbar_visible;
1666           scrolled_win->vscrollbar_visible = (adjustment->upper - adjustment->lower >
1667                                               adjustment->page_size);
1668           if (scrolled_win->vscrollbar_visible != visible)
1669             gtk_widget_queue_resize (GTK_WIDGET (scrolled_win));
1670         }
1671     }
1672 }
1673
1674 static void
1675 gtk_scrolled_window_add (GtkContainer *container,
1676                          GtkWidget    *child)
1677 {
1678   GtkScrolledWindow *scrolled_window;
1679   GtkBin *bin;
1680
1681   bin = GTK_BIN (container);
1682   g_return_if_fail (bin->child == NULL);
1683
1684   scrolled_window = GTK_SCROLLED_WINDOW (container);
1685
1686   bin->child = child;
1687   gtk_widget_set_parent (child, GTK_WIDGET (bin));
1688
1689   /* this is a temporary message */
1690   if (!gtk_widget_set_scroll_adjustments (child,
1691                                           gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
1692                                           gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar))))
1693     g_warning ("gtk_scrolled_window_add(): cannot add non scrollable widget "
1694                "use gtk_scrolled_window_add_with_viewport() instead");
1695 }
1696
1697 static void
1698 gtk_scrolled_window_remove (GtkContainer *container,
1699                             GtkWidget    *child)
1700 {
1701   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
1702   g_return_if_fail (child != NULL);
1703   g_return_if_fail (GTK_BIN (container)->child == child);
1704   
1705   gtk_widget_set_scroll_adjustments (child, NULL, NULL);
1706
1707   /* chain parent class handler to remove child */
1708   GTK_CONTAINER_CLASS (gtk_scrolled_window_parent_class)->remove (container, child);
1709 }
1710
1711 /**
1712  * gtk_scrolled_window_add_with_viewport:
1713  * @scrolled_window: a #GtkScrolledWindow
1714  * @child: the widget you want to scroll
1715  *
1716  * Used to add children without native scrolling capabilities. This
1717  * is simply a convenience function; it is equivalent to adding the
1718  * unscrollable child to a viewport, then adding the viewport to the
1719  * scrolled window. If a child has native scrolling, use
1720  * gtk_container_add() instead of this function.
1721  *
1722  * The viewport scrolls the child by moving its #GdkWindow, and takes
1723  * the size of the child to be the size of its toplevel #GdkWindow. 
1724  * This will be very wrong for most widgets that support native scrolling;
1725  * for example, if you add a widget such as #GtkTreeView with a viewport,
1726  * the whole widget will scroll, including the column headings. Thus, 
1727  * widgets with native scrolling support should not be used with the 
1728  * #GtkViewport proxy.
1729  *
1730  * A widget supports scrolling natively if the 
1731  * set_scroll_adjustments_signal field in #GtkWidgetClass is non-zero,
1732  * i.e. has been filled in with a valid signal identifier.
1733  */
1734 void
1735 gtk_scrolled_window_add_with_viewport (GtkScrolledWindow *scrolled_window,
1736                                        GtkWidget         *child)
1737 {
1738   GtkBin *bin;
1739   GtkWidget *viewport;
1740
1741   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
1742   g_return_if_fail (GTK_IS_WIDGET (child));
1743   g_return_if_fail (child->parent == NULL);
1744
1745   bin = GTK_BIN (scrolled_window);
1746
1747   if (bin->child != NULL)
1748     {
1749       g_return_if_fail (GTK_IS_VIEWPORT (bin->child));
1750       g_return_if_fail (GTK_BIN (bin->child)->child == NULL);
1751
1752       viewport = bin->child;
1753     }
1754   else
1755     {
1756       viewport =
1757         gtk_viewport_new (gtk_scrolled_window_get_hadjustment (scrolled_window),
1758                           gtk_scrolled_window_get_vadjustment (scrolled_window));
1759       gtk_container_add (GTK_CONTAINER (scrolled_window), viewport);
1760     }
1761
1762   gtk_widget_show (viewport);
1763   gtk_container_add (GTK_CONTAINER (viewport), child);
1764 }
1765
1766 /*
1767  * _gtk_scrolled_window_get_spacing:
1768  * @scrolled_window: a scrolled window
1769  * 
1770  * Gets the spacing between the scrolled window's scrollbars and
1771  * the scrolled widget. Used by GtkCombo
1772  * 
1773  * Return value: the spacing, in pixels.
1774  */
1775 gint
1776 _gtk_scrolled_window_get_scrollbar_spacing (GtkScrolledWindow *scrolled_window)
1777 {
1778   GtkScrolledWindowClass *class;
1779     
1780   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), 0);
1781
1782   class = GTK_SCROLLED_WINDOW_GET_CLASS (scrolled_window);
1783
1784   if (class->scrollbar_spacing >= 0)
1785     return class->scrollbar_spacing;
1786   else
1787     {
1788       gint scrollbar_spacing;
1789       
1790       gtk_widget_style_get (GTK_WIDGET (scrolled_window),
1791                             "scrollbar-spacing", &scrollbar_spacing,
1792                             NULL);
1793
1794       return scrollbar_spacing;
1795     }
1796 }
1797
1798 #define __GTK_SCROLLED_WINDOW_C__
1799 #include "gtkaliasdef.c"