]> Pileus Git - ~andy/gtk/blob - gtk/gtkscrolledwindow.c
Forgotten commit
[~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: horizontal adjustment
381  * @vadjustment: 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_DRAWABLE (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       gtk_widget_unparent (scrolled_window->hscrollbar);
856       gtk_widget_destroy (scrolled_window->hscrollbar);
857       g_object_unref (scrolled_window->hscrollbar);
858       scrolled_window->hscrollbar = NULL;
859     }
860   if (scrolled_window->vscrollbar)
861     {
862       gtk_widget_unparent (scrolled_window->vscrollbar);
863       gtk_widget_destroy (scrolled_window->vscrollbar);
864       g_object_unref (scrolled_window->vscrollbar);
865       scrolled_window->vscrollbar = NULL;
866     }
867
868   GTK_OBJECT_CLASS (gtk_scrolled_window_parent_class)->destroy (object);
869 }
870
871 static void
872 gtk_scrolled_window_set_property (GObject      *object,
873                                   guint         prop_id,
874                                   const GValue *value,
875                                   GParamSpec   *pspec)
876 {
877   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (object);
878   
879   switch (prop_id)
880     {
881     case PROP_HADJUSTMENT:
882       gtk_scrolled_window_set_hadjustment (scrolled_window,
883                                            g_value_get_object (value));
884       break;
885     case PROP_VADJUSTMENT:
886       gtk_scrolled_window_set_vadjustment (scrolled_window,
887                                            g_value_get_object (value));
888       break;
889     case PROP_HSCROLLBAR_POLICY:
890       gtk_scrolled_window_set_policy (scrolled_window,
891                                       g_value_get_enum (value),
892                                       scrolled_window->vscrollbar_policy);
893       break;
894     case PROP_VSCROLLBAR_POLICY:
895       gtk_scrolled_window_set_policy (scrolled_window,
896                                       scrolled_window->hscrollbar_policy,
897                                       g_value_get_enum (value));
898       break;
899     case PROP_WINDOW_PLACEMENT:
900       gtk_scrolled_window_set_placement_internal (scrolled_window,
901                                                   g_value_get_enum (value));
902       break;
903     case PROP_WINDOW_PLACEMENT_SET:
904       gtk_scrolled_window_set_placement_set (scrolled_window,
905                                              g_value_get_boolean (value),
906                                              TRUE);
907       break;
908     case PROP_SHADOW_TYPE:
909       gtk_scrolled_window_set_shadow_type (scrolled_window,
910                                            g_value_get_enum (value));
911       break;
912     default:
913       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
914       break;
915     }
916 }
917
918 static void
919 gtk_scrolled_window_get_property (GObject    *object,
920                                   guint       prop_id,
921                                   GValue     *value,
922                                   GParamSpec *pspec)
923 {
924   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (object);
925   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
926   
927   switch (prop_id)
928     {
929     case PROP_HADJUSTMENT:
930       g_value_set_object (value,
931                           G_OBJECT (gtk_scrolled_window_get_hadjustment (scrolled_window)));
932       break;
933     case PROP_VADJUSTMENT:
934       g_value_set_object (value,
935                           G_OBJECT (gtk_scrolled_window_get_vadjustment (scrolled_window)));
936       break;
937     case PROP_HSCROLLBAR_POLICY:
938       g_value_set_enum (value, scrolled_window->hscrollbar_policy);
939       break;
940     case PROP_VSCROLLBAR_POLICY:
941       g_value_set_enum (value, scrolled_window->vscrollbar_policy);
942       break;
943     case PROP_WINDOW_PLACEMENT:
944       g_value_set_enum (value, scrolled_window->window_placement);
945       break;
946     case PROP_WINDOW_PLACEMENT_SET:
947       g_value_set_boolean (value, priv->window_placement_set);
948       break;
949     case PROP_SHADOW_TYPE:
950       g_value_set_enum (value, scrolled_window->shadow_type);
951       break;
952     default:
953       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
954       break;
955     }
956 }
957
958 static void
959 traverse_container (GtkWidget *widget,
960                     gpointer   data)
961 {
962   if (GTK_IS_SCROLLED_WINDOW (widget))
963     {
964       gtk_scrolled_window_update_real_placement (GTK_SCROLLED_WINDOW (widget));
965       gtk_widget_queue_resize (widget);
966     }
967   else if (GTK_IS_CONTAINER (widget))
968     gtk_container_forall (GTK_CONTAINER (widget), traverse_container, NULL);
969 }
970
971 static void
972 gtk_scrolled_window_settings_changed (GtkSettings *settings)
973 {
974   GList *list, *l;
975
976   list = gtk_window_list_toplevels ();
977
978   for (l = list; l; l = l->next)
979     gtk_container_forall (GTK_CONTAINER (l->data), 
980                           traverse_container, NULL);
981
982   g_list_free (list);
983 }
984
985 static void
986 gtk_scrolled_window_screen_changed (GtkWidget *widget,
987                                     GdkScreen *previous_screen)
988 {
989   GtkSettings *settings;
990   guint window_placement_connection;
991
992   gtk_scrolled_window_update_real_placement (GTK_SCROLLED_WINDOW (widget));
993
994   if (!gtk_widget_has_screen (widget))
995     return;
996
997   settings = gtk_widget_get_settings (widget);
998
999   window_placement_connection = 
1000     GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (settings), 
1001                                          "gtk-scrolled-window-connection"));
1002   
1003   if (window_placement_connection)
1004     return;
1005
1006   window_placement_connection =
1007     g_signal_connect (settings, "notify::gtk-scrolled-window-placement",
1008                       G_CALLBACK (gtk_scrolled_window_settings_changed), NULL);
1009   g_object_set_data (G_OBJECT (settings), 
1010                      I_("gtk-scrolled-window-connection"),
1011                      GUINT_TO_POINTER (window_placement_connection));
1012 }
1013
1014 static void
1015 gtk_scrolled_window_paint (GtkWidget    *widget,
1016                            GdkRectangle *area)
1017 {
1018   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
1019
1020   if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
1021     {
1022       GtkAllocation relative_allocation;
1023       gboolean scrollbars_within_bevel;
1024
1025       gtk_widget_style_get (widget, "scrollbars-within-bevel", &scrollbars_within_bevel, NULL);
1026       
1027       if (!scrollbars_within_bevel)
1028         {
1029           gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
1030
1031           relative_allocation.x -= widget->style->xthickness;
1032           relative_allocation.y -= widget->style->ythickness;
1033           relative_allocation.width += 2 * widget->style->xthickness;
1034           relative_allocation.height += 2 * widget->style->ythickness;
1035         }
1036       else
1037         {
1038           GtkContainer *container = GTK_CONTAINER (widget);
1039
1040           relative_allocation.x = container->border_width;
1041           relative_allocation.y = container->border_width;
1042           relative_allocation.width = widget->allocation.width - 2 * container->border_width;
1043           relative_allocation.height = widget->allocation.height - 2 * container->border_width;
1044         }
1045
1046       gtk_paint_shadow (widget->style, widget->window,
1047                         GTK_STATE_NORMAL, scrolled_window->shadow_type,
1048                         area, widget, "scrolled_window",
1049                         widget->allocation.x + relative_allocation.x,
1050                         widget->allocation.y + relative_allocation.y,
1051                         relative_allocation.width,
1052                         relative_allocation.height);
1053     }
1054 }
1055
1056 static gboolean
1057 gtk_scrolled_window_expose (GtkWidget      *widget,
1058                             GdkEventExpose *event)
1059 {
1060   if (GTK_WIDGET_DRAWABLE (widget))
1061     {
1062       gtk_scrolled_window_paint (widget, &event->area);
1063
1064       GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->expose_event (widget, event);
1065     }
1066
1067   return FALSE;
1068 }
1069
1070 static void
1071 gtk_scrolled_window_forall (GtkContainer *container,
1072                             gboolean      include_internals,
1073                             GtkCallback   callback,
1074                             gpointer      callback_data)
1075 {
1076   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
1077   g_return_if_fail (callback != NULL);
1078
1079   GTK_CONTAINER_CLASS (gtk_scrolled_window_parent_class)->forall (container,
1080                                               include_internals,
1081                                               callback,
1082                                               callback_data);
1083   if (include_internals)
1084     {
1085       GtkScrolledWindow *scrolled_window;
1086
1087       scrolled_window = GTK_SCROLLED_WINDOW (container);
1088       
1089       if (scrolled_window->vscrollbar)
1090         callback (scrolled_window->vscrollbar, callback_data);
1091       if (scrolled_window->hscrollbar)
1092         callback (scrolled_window->hscrollbar, callback_data);
1093     }
1094 }
1095
1096 static gboolean
1097 gtk_scrolled_window_scroll_child (GtkScrolledWindow *scrolled_window,
1098                                   GtkScrollType      scroll,
1099                                   gboolean           horizontal)
1100 {
1101   GtkAdjustment *adjustment = NULL;
1102   
1103   switch (scroll)
1104     {
1105     case GTK_SCROLL_STEP_UP:
1106       scroll = GTK_SCROLL_STEP_BACKWARD;
1107       horizontal = FALSE;
1108       break;
1109     case GTK_SCROLL_STEP_DOWN:
1110       scroll = GTK_SCROLL_STEP_FORWARD;
1111       horizontal = FALSE;
1112       break;
1113     case GTK_SCROLL_STEP_LEFT:
1114       scroll = GTK_SCROLL_STEP_BACKWARD;
1115       horizontal = TRUE;
1116       break;
1117     case GTK_SCROLL_STEP_RIGHT:
1118       scroll = GTK_SCROLL_STEP_FORWARD;
1119       horizontal = TRUE;
1120       break;
1121     case GTK_SCROLL_PAGE_UP:
1122       scroll = GTK_SCROLL_PAGE_BACKWARD;
1123       horizontal = FALSE;
1124       break;
1125     case GTK_SCROLL_PAGE_DOWN:
1126       scroll = GTK_SCROLL_PAGE_FORWARD;
1127       horizontal = FALSE;
1128       break;
1129     case GTK_SCROLL_PAGE_LEFT:
1130       scroll = GTK_SCROLL_STEP_BACKWARD;
1131       horizontal = TRUE;
1132       break;
1133     case GTK_SCROLL_PAGE_RIGHT:
1134       scroll = GTK_SCROLL_STEP_FORWARD;
1135       horizontal = TRUE;
1136       break;
1137     case GTK_SCROLL_STEP_BACKWARD:
1138     case GTK_SCROLL_STEP_FORWARD:
1139     case GTK_SCROLL_PAGE_BACKWARD:
1140     case GTK_SCROLL_PAGE_FORWARD:
1141     case GTK_SCROLL_START:
1142     case GTK_SCROLL_END:
1143       break;
1144     default:
1145       g_warning ("Invalid scroll type %u for GtkScrolledWindow::scroll-child", scroll);
1146       return FALSE;
1147     }
1148
1149   if ((horizontal && (!scrolled_window->hscrollbar || !scrolled_window->hscrollbar_visible)) ||
1150       (!horizontal && (!scrolled_window->vscrollbar || !scrolled_window->vscrollbar_visible)))
1151     return FALSE;
1152
1153   if (horizontal)
1154     {
1155       if (scrolled_window->hscrollbar)
1156         adjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
1157     }
1158   else
1159     {
1160       if (scrolled_window->vscrollbar)
1161         adjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
1162     }
1163
1164   if (adjustment)
1165     {
1166       gdouble value = adjustment->value;
1167       
1168       switch (scroll)
1169         {
1170         case GTK_SCROLL_STEP_FORWARD:
1171           value += adjustment->step_increment;
1172           break;
1173         case GTK_SCROLL_STEP_BACKWARD:
1174           value -= adjustment->step_increment;
1175           break;
1176         case GTK_SCROLL_PAGE_FORWARD:
1177           value += adjustment->page_increment;
1178           break;
1179         case GTK_SCROLL_PAGE_BACKWARD:
1180           value -= adjustment->page_increment;
1181           break;
1182         case GTK_SCROLL_START:
1183           value = adjustment->lower;
1184           break;
1185         case GTK_SCROLL_END:
1186           value = adjustment->upper;
1187           break;
1188         default:
1189           g_assert_not_reached ();
1190           break;
1191         }
1192
1193       gtk_adjustment_set_value (adjustment, value);
1194
1195       return TRUE;
1196     }
1197
1198   return FALSE;
1199 }
1200
1201 static void
1202 gtk_scrolled_window_move_focus_out (GtkScrolledWindow *scrolled_window,
1203                                     GtkDirectionType   direction_type)
1204 {
1205   GtkWidget *toplevel;
1206   
1207   /* Focus out of the scrolled window entirely. We do this by setting
1208    * a flag, then propagating the focus motion to the notebook.
1209    */
1210   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (scrolled_window));
1211   if (!GTK_WIDGET_TOPLEVEL (toplevel))
1212     return;
1213
1214   g_object_ref (scrolled_window);
1215   
1216   scrolled_window->focus_out = TRUE;
1217   g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1218   scrolled_window->focus_out = FALSE;
1219   
1220   g_object_unref (scrolled_window);
1221 }
1222
1223 static void
1224 gtk_scrolled_window_size_request (GtkWidget      *widget,
1225                                   GtkRequisition *requisition)
1226 {
1227   GtkScrolledWindow *scrolled_window;
1228   GtkBin *bin;
1229   gint extra_width;
1230   gint extra_height;
1231   gint scrollbar_spacing;
1232   GtkRequisition hscrollbar_requisition;
1233   GtkRequisition vscrollbar_requisition;
1234   GtkRequisition child_requisition;
1235
1236   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
1237   g_return_if_fail (requisition != NULL);
1238
1239   scrolled_window = GTK_SCROLLED_WINDOW (widget);
1240   bin = GTK_BIN (scrolled_window);
1241
1242   scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
1243
1244   extra_width = 0;
1245   extra_height = 0;
1246   requisition->width = 0;
1247   requisition->height = 0;
1248   
1249   gtk_widget_size_request (scrolled_window->hscrollbar,
1250                            &hscrollbar_requisition);
1251   gtk_widget_size_request (scrolled_window->vscrollbar,
1252                            &vscrollbar_requisition);
1253   
1254   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
1255     {
1256       gtk_widget_size_request (bin->child, &child_requisition);
1257
1258       if (scrolled_window->hscrollbar_policy == GTK_POLICY_NEVER)
1259         requisition->width += child_requisition.width;
1260       else
1261         {
1262           GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (bin->child, FALSE);
1263
1264           if (aux_info && aux_info->width > 0)
1265             {
1266               requisition->width += aux_info->width;
1267               extra_width = -1;
1268             }
1269           else
1270             requisition->width += vscrollbar_requisition.width;
1271         }
1272
1273       if (scrolled_window->vscrollbar_policy == GTK_POLICY_NEVER)
1274         requisition->height += child_requisition.height;
1275       else
1276         {
1277           GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (bin->child, FALSE);
1278
1279           if (aux_info && aux_info->height > 0)
1280             {
1281               requisition->height += aux_info->height;
1282               extra_height = -1;
1283             }
1284           else
1285             requisition->height += hscrollbar_requisition.height;
1286         }
1287     }
1288
1289   if (scrolled_window->hscrollbar_policy == GTK_POLICY_AUTOMATIC ||
1290       scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
1291     {
1292       requisition->width = MAX (requisition->width, hscrollbar_requisition.width);
1293       if (!extra_height || scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
1294         extra_height = scrollbar_spacing + hscrollbar_requisition.height;
1295     }
1296
1297   if (scrolled_window->vscrollbar_policy == GTK_POLICY_AUTOMATIC ||
1298       scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
1299     {
1300       requisition->height = MAX (requisition->height, vscrollbar_requisition.height);
1301       if (!extra_height || scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
1302         extra_width = scrollbar_spacing + vscrollbar_requisition.width;
1303     }
1304
1305   requisition->width += GTK_CONTAINER (widget)->border_width * 2 + MAX (0, extra_width);
1306   requisition->height += GTK_CONTAINER (widget)->border_width * 2 + MAX (0, extra_height);
1307
1308   if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
1309     {
1310       requisition->width += 2 * widget->style->xthickness;
1311       requisition->height += 2 * widget->style->ythickness;
1312     }
1313 }
1314
1315 static void
1316 gtk_scrolled_window_relative_allocation (GtkWidget     *widget,
1317                                          GtkAllocation *allocation)
1318 {
1319   GtkScrolledWindow *scrolled_window;
1320   GtkScrolledWindowPrivate *priv;
1321   gint scrollbar_spacing;
1322
1323   g_return_if_fail (widget != NULL);
1324   g_return_if_fail (allocation != NULL);
1325
1326   scrolled_window = GTK_SCROLLED_WINDOW (widget);
1327   scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
1328
1329   priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
1330
1331   allocation->x = GTK_CONTAINER (widget)->border_width;
1332   allocation->y = GTK_CONTAINER (widget)->border_width;
1333
1334   if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
1335     {
1336       allocation->x += widget->style->xthickness;
1337       allocation->y += widget->style->ythickness;
1338     }
1339   
1340   allocation->width = MAX (1, (gint)widget->allocation.width - allocation->x * 2);
1341   allocation->height = MAX (1, (gint)widget->allocation.height - allocation->y * 2);
1342
1343   if (scrolled_window->vscrollbar_visible)
1344     {
1345       GtkRequisition vscrollbar_requisition;
1346       gboolean is_rtl;
1347
1348       gtk_widget_get_child_requisition (scrolled_window->vscrollbar,
1349                                         &vscrollbar_requisition);
1350       is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1351   
1352       if ((!is_rtl && 
1353            (priv->real_window_placement == GTK_CORNER_TOP_RIGHT ||
1354             priv->real_window_placement == GTK_CORNER_BOTTOM_RIGHT)) ||
1355           (is_rtl && 
1356            (priv->real_window_placement == GTK_CORNER_TOP_LEFT ||
1357             priv->real_window_placement == GTK_CORNER_BOTTOM_LEFT)))
1358         allocation->x += (vscrollbar_requisition.width +  scrollbar_spacing);
1359
1360       allocation->width = MAX (1, allocation->width - (vscrollbar_requisition.width + scrollbar_spacing));
1361     }
1362   if (scrolled_window->hscrollbar_visible)
1363     {
1364       GtkRequisition hscrollbar_requisition;
1365       gtk_widget_get_child_requisition (scrolled_window->hscrollbar,
1366                                         &hscrollbar_requisition);
1367   
1368       if (priv->real_window_placement == GTK_CORNER_BOTTOM_LEFT ||
1369           priv->real_window_placement == GTK_CORNER_BOTTOM_RIGHT)
1370         allocation->y += (hscrollbar_requisition.height + scrollbar_spacing);
1371
1372       allocation->height = MAX (1, allocation->height - (hscrollbar_requisition.height + scrollbar_spacing));
1373     }
1374 }
1375
1376 static void
1377 gtk_scrolled_window_size_allocate (GtkWidget     *widget,
1378                                    GtkAllocation *allocation)
1379 {
1380   GtkScrolledWindow *scrolled_window;
1381   GtkScrolledWindowPrivate *priv;
1382   GtkBin *bin;
1383   GtkAllocation relative_allocation;
1384   GtkAllocation child_allocation;
1385   gboolean scrollbars_within_bevel;
1386   gint scrollbar_spacing;
1387   
1388   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
1389   g_return_if_fail (allocation != NULL);
1390
1391   scrolled_window = GTK_SCROLLED_WINDOW (widget);
1392   bin = GTK_BIN (scrolled_window);
1393
1394   scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
1395   gtk_widget_style_get (widget, "scrollbars-within-bevel", &scrollbars_within_bevel, NULL);
1396
1397   priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
1398
1399   widget->allocation = *allocation;
1400
1401   if (scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
1402     scrolled_window->hscrollbar_visible = TRUE;
1403   else if (scrolled_window->hscrollbar_policy == GTK_POLICY_NEVER)
1404     scrolled_window->hscrollbar_visible = FALSE;
1405   if (scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
1406     scrolled_window->vscrollbar_visible = TRUE;
1407   else if (scrolled_window->vscrollbar_policy == GTK_POLICY_NEVER)
1408     scrolled_window->vscrollbar_visible = FALSE;
1409
1410   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
1411     {
1412       gboolean previous_hvis;
1413       gboolean previous_vvis;
1414       guint count = 0;
1415       
1416       do
1417         {
1418           gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
1419           
1420           child_allocation.x = relative_allocation.x + allocation->x;
1421           child_allocation.y = relative_allocation.y + allocation->y;
1422           child_allocation.width = relative_allocation.width;
1423           child_allocation.height = relative_allocation.height;
1424           
1425           previous_hvis = scrolled_window->hscrollbar_visible;
1426           previous_vvis = scrolled_window->vscrollbar_visible;
1427           
1428           gtk_widget_size_allocate (bin->child, &child_allocation);
1429
1430           /* If, after the first iteration, the hscrollbar and the
1431            * vscrollbar flip visiblity, then we need both.
1432            */
1433           if (count &&
1434               previous_hvis != scrolled_window->hscrollbar_visible &&
1435               previous_vvis != scrolled_window->vscrollbar_visible)
1436             {
1437               scrolled_window->hscrollbar_visible = TRUE;
1438               scrolled_window->vscrollbar_visible = TRUE;
1439
1440               /* a new resize is already queued at this point,
1441                * so we will immediatedly get reinvoked
1442                */
1443               return;
1444             }
1445           
1446           count++;
1447         }
1448       while (previous_hvis != scrolled_window->hscrollbar_visible ||
1449              previous_vvis != scrolled_window->vscrollbar_visible);
1450     }
1451   else
1452     {
1453       scrolled_window->hscrollbar_visible = scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS;
1454       scrolled_window->vscrollbar_visible = scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS;
1455       gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
1456     }
1457   
1458   if (scrolled_window->hscrollbar_visible)
1459     {
1460       GtkRequisition hscrollbar_requisition;
1461       gtk_widget_get_child_requisition (scrolled_window->hscrollbar,
1462                                         &hscrollbar_requisition);
1463   
1464       if (!GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar))
1465         gtk_widget_show (scrolled_window->hscrollbar);
1466
1467       child_allocation.x = relative_allocation.x;
1468       if (priv->real_window_placement == GTK_CORNER_TOP_LEFT ||
1469           priv->real_window_placement == GTK_CORNER_TOP_RIGHT)
1470         child_allocation.y = (relative_allocation.y +
1471                               relative_allocation.height +
1472                               scrollbar_spacing +
1473                               (scrolled_window->shadow_type == GTK_SHADOW_NONE ?
1474                                0 : widget->style->ythickness));
1475       else
1476         child_allocation.y = GTK_CONTAINER (scrolled_window)->border_width;
1477
1478       child_allocation.width = relative_allocation.width;
1479       child_allocation.height = hscrollbar_requisition.height;
1480       child_allocation.x += allocation->x;
1481       child_allocation.y += allocation->y;
1482
1483       if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
1484         {
1485           if (!scrollbars_within_bevel)
1486             {
1487               child_allocation.x -= widget->style->xthickness;
1488               child_allocation.width += 2 * widget->style->xthickness;
1489             }
1490           else if (GTK_CORNER_TOP_RIGHT == priv->real_window_placement ||
1491                    GTK_CORNER_TOP_LEFT == priv->real_window_placement)
1492             {
1493               child_allocation.y -= widget->style->ythickness;
1494             }
1495           else
1496             {
1497               child_allocation.y += widget->style->ythickness;
1498             }
1499         }
1500
1501       gtk_widget_size_allocate (scrolled_window->hscrollbar, &child_allocation);
1502     }
1503   else if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar))
1504     gtk_widget_hide (scrolled_window->hscrollbar);
1505
1506   if (scrolled_window->vscrollbar_visible)
1507     {
1508       GtkRequisition vscrollbar_requisition;
1509       if (!GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar))
1510         gtk_widget_show (scrolled_window->vscrollbar);
1511
1512       gtk_widget_get_child_requisition (scrolled_window->vscrollbar,
1513                                         &vscrollbar_requisition);
1514
1515       if ((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL && 
1516            (priv->real_window_placement == GTK_CORNER_TOP_RIGHT ||
1517             priv->real_window_placement == GTK_CORNER_BOTTOM_RIGHT)) ||
1518           (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR && 
1519            (priv->real_window_placement == GTK_CORNER_TOP_LEFT ||
1520             priv->real_window_placement == GTK_CORNER_BOTTOM_LEFT)))
1521         child_allocation.x = (relative_allocation.x +
1522                               relative_allocation.width +
1523                               scrollbar_spacing +
1524                               (scrolled_window->shadow_type == GTK_SHADOW_NONE ?
1525                                0 : widget->style->xthickness));
1526       else
1527         child_allocation.x = GTK_CONTAINER (scrolled_window)->border_width;
1528
1529       child_allocation.y = relative_allocation.y;
1530       child_allocation.width = vscrollbar_requisition.width;
1531       child_allocation.height = relative_allocation.height;
1532       child_allocation.x += allocation->x;
1533       child_allocation.y += allocation->y;
1534
1535       if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
1536         {
1537           if (!scrollbars_within_bevel)
1538             {
1539               child_allocation.y -= widget->style->ythickness;
1540               child_allocation.height += 2 * widget->style->ythickness;
1541             }
1542           else if (GTK_CORNER_BOTTOM_LEFT == priv->real_window_placement ||
1543                    GTK_CORNER_TOP_LEFT == priv->real_window_placement)
1544             {
1545               child_allocation.x -= widget->style->xthickness;
1546             }
1547           else
1548             {
1549               child_allocation.x += widget->style->xthickness;
1550             }
1551         }
1552
1553       gtk_widget_size_allocate (scrolled_window->vscrollbar, &child_allocation);
1554     }
1555   else if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar))
1556     gtk_widget_hide (scrolled_window->vscrollbar);
1557 }
1558
1559 static gboolean
1560 gtk_scrolled_window_scroll_event (GtkWidget      *widget,
1561                                   GdkEventScroll *event)
1562 {
1563   GtkWidget *range;
1564
1565   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (widget), FALSE);
1566   g_return_val_if_fail (event != NULL, FALSE);  
1567
1568   if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_DOWN)
1569     range = GTK_SCROLLED_WINDOW (widget)->vscrollbar;
1570   else
1571     range = GTK_SCROLLED_WINDOW (widget)->hscrollbar;
1572
1573   if (range && GTK_WIDGET_VISIBLE (range))
1574     {
1575       GtkAdjustment *adj = GTK_RANGE (range)->adjustment;
1576       gdouble delta;
1577
1578       delta = _gtk_range_get_wheel_delta (GTK_RANGE (range), event->direction);
1579
1580       gtk_adjustment_set_value (adj, adj->value + delta);
1581
1582       return TRUE;
1583     }
1584
1585   return FALSE;
1586 }
1587
1588 static gboolean
1589 gtk_scrolled_window_focus (GtkWidget        *widget,
1590                            GtkDirectionType  direction)
1591 {
1592   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
1593   gboolean had_focus_child = GTK_CONTAINER (widget)->focus_child != NULL;
1594   
1595   if (scrolled_window->focus_out)
1596     {
1597       scrolled_window->focus_out = FALSE; /* Clear this to catch the wrap-around case */
1598       return FALSE;
1599     }
1600   
1601   if (gtk_widget_is_focus (widget))
1602     return FALSE;
1603
1604   /* We only put the scrolled window itself in the focus chain if it
1605    * isn't possible to focus any children.
1606    */
1607   if (GTK_BIN (widget)->child)
1608     {
1609       if (gtk_widget_child_focus (GTK_BIN (widget)->child, direction))
1610         return TRUE;
1611     }
1612
1613   if (!had_focus_child && GTK_WIDGET_CAN_FOCUS (widget))
1614     {
1615       gtk_widget_grab_focus (widget);
1616       return TRUE;
1617     }
1618   else
1619     return FALSE;
1620 }
1621
1622 static void
1623 gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment,
1624                                         gpointer       data)
1625 {
1626   GtkScrolledWindow *scrolled_win;
1627
1628   g_return_if_fail (adjustment != NULL);
1629   g_return_if_fail (data != NULL);
1630
1631   scrolled_win = GTK_SCROLLED_WINDOW (data);
1632
1633   if (scrolled_win->hscrollbar &&
1634       adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_win->hscrollbar)))
1635     {
1636       if (scrolled_win->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
1637         {
1638           gboolean visible;
1639           
1640           visible = scrolled_win->hscrollbar_visible;
1641           scrolled_win->hscrollbar_visible = (adjustment->upper - adjustment->lower >
1642                                               adjustment->page_size);
1643           if (scrolled_win->hscrollbar_visible != visible)
1644             gtk_widget_queue_resize (GTK_WIDGET (scrolled_win));
1645         }
1646     }
1647   else if (scrolled_win->vscrollbar &&
1648            adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_win->vscrollbar)))
1649     {
1650       if (scrolled_win->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
1651         {
1652           gboolean visible;
1653
1654           visible = scrolled_win->vscrollbar_visible;
1655           scrolled_win->vscrollbar_visible = (adjustment->upper - adjustment->lower >
1656                                               adjustment->page_size);
1657           if (scrolled_win->vscrollbar_visible != visible)
1658             gtk_widget_queue_resize (GTK_WIDGET (scrolled_win));
1659         }
1660     }
1661 }
1662
1663 static void
1664 gtk_scrolled_window_add (GtkContainer *container,
1665                          GtkWidget    *child)
1666 {
1667   GtkScrolledWindow *scrolled_window;
1668   GtkBin *bin;
1669
1670   bin = GTK_BIN (container);
1671   g_return_if_fail (bin->child == NULL);
1672
1673   scrolled_window = GTK_SCROLLED_WINDOW (container);
1674
1675   bin->child = child;
1676   gtk_widget_set_parent (child, GTK_WIDGET (bin));
1677
1678   /* this is a temporary message */
1679   if (!gtk_widget_set_scroll_adjustments (child,
1680                                           gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
1681                                           gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar))))
1682     g_warning ("gtk_scrolled_window_add(): cannot add non scrollable widget "
1683                "use gtk_scrolled_window_add_with_viewport() instead");
1684 }
1685
1686 static void
1687 gtk_scrolled_window_remove (GtkContainer *container,
1688                             GtkWidget    *child)
1689 {
1690   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
1691   g_return_if_fail (child != NULL);
1692   g_return_if_fail (GTK_BIN (container)->child == child);
1693   
1694   gtk_widget_set_scroll_adjustments (child, NULL, NULL);
1695
1696   /* chain parent class handler to remove child */
1697   GTK_CONTAINER_CLASS (gtk_scrolled_window_parent_class)->remove (container, child);
1698 }
1699
1700 /**
1701  * gtk_scrolled_window_add_with_viewport:
1702  * @scrolled_window: a #GtkScrolledWindow
1703  * @child: the widget you want to scroll
1704  *
1705  * Used to add children without native scrolling capabilities. This
1706  * is simply a convenience function; it is equivalent to adding the
1707  * unscrollable child to a viewport, then adding the viewport to the
1708  * scrolled window. If a child has native scrolling, use
1709  * gtk_container_add() instead of this function.
1710  *
1711  * The viewport scrolls the child by moving its #GdkWindow, and takes
1712  * the size of the child to be the size of its toplevel #GdkWindow. 
1713  * This will be very wrong for most widgets that support native scrolling;
1714  * for example, if you add a widget such as #GtkTreeView with a viewport,
1715  * the whole widget will scroll, including the column headings. Thus, 
1716  * widgets with native scrolling support should not be used with the 
1717  * #GtkViewport proxy.
1718  *
1719  * A widget supports scrolling natively if the 
1720  * set_scroll_adjustments_signal field in #GtkWidgetClass is non-zero,
1721  * i.e. has been filled in with a valid signal identifier.
1722  */
1723 void
1724 gtk_scrolled_window_add_with_viewport (GtkScrolledWindow *scrolled_window,
1725                                        GtkWidget         *child)
1726 {
1727   GtkBin *bin;
1728   GtkWidget *viewport;
1729
1730   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
1731   g_return_if_fail (GTK_IS_WIDGET (child));
1732   g_return_if_fail (child->parent == NULL);
1733
1734   bin = GTK_BIN (scrolled_window);
1735
1736   if (bin->child != NULL)
1737     {
1738       g_return_if_fail (GTK_IS_VIEWPORT (bin->child));
1739       g_return_if_fail (GTK_BIN (bin->child)->child == NULL);
1740
1741       viewport = bin->child;
1742     }
1743   else
1744     {
1745       viewport =
1746         gtk_viewport_new (gtk_scrolled_window_get_hadjustment (scrolled_window),
1747                           gtk_scrolled_window_get_vadjustment (scrolled_window));
1748       gtk_container_add (GTK_CONTAINER (scrolled_window), viewport);
1749     }
1750
1751   gtk_widget_show (viewport);
1752   gtk_container_add (GTK_CONTAINER (viewport), child);
1753 }
1754
1755 /*
1756  * _gtk_scrolled_window_get_spacing:
1757  * @scrolled_window: a scrolled window
1758  * 
1759  * Gets the spacing between the scrolled window's scrollbars and
1760  * the scrolled widget. Used by GtkCombo
1761  * 
1762  * Return value: the spacing, in pixels.
1763  */
1764 gint
1765 _gtk_scrolled_window_get_scrollbar_spacing (GtkScrolledWindow *scrolled_window)
1766 {
1767   GtkScrolledWindowClass *class;
1768     
1769   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), 0);
1770
1771   class = GTK_SCROLLED_WINDOW_GET_CLASS (scrolled_window);
1772
1773   if (class->scrollbar_spacing >= 0)
1774     return class->scrollbar_spacing;
1775   else
1776     {
1777       gint scrollbar_spacing;
1778       
1779       gtk_widget_style_get (GTK_WIDGET (scrolled_window),
1780                             "scrollbar-spacing", &scrollbar_spacing,
1781                             NULL);
1782
1783       return scrollbar_spacing;
1784     }
1785 }
1786
1787 #define __GTK_SCROLLED_WINDOW_C__
1788 #include "gtkaliasdef.c"