]> Pileus Git - ~andy/gtk/blob - gtk/gtkscrolledwindow.c
GTK_MENU_DIR_CHILD: check for the existance of
[~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 Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library 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 #include "gtkscrolledwindow.h"
20 #include "gtksignal.h"
21
22
23 #define SCROLLBAR_SPACING(w) (GTK_SCROLLED_WINDOW_CLASS (GTK_OBJECT (w)->klass)->scrollbar_spacing)
24
25 enum {
26   ARG_0,
27   ARG_VIEWPORT,
28   ARG_HSCROLLBAR_POLICY,
29   ARG_VSCROLLBAR_POLICY
30 };
31
32
33 static void gtk_scrolled_window_class_init         (GtkScrolledWindowClass *klass);
34 static void gtk_scrolled_window_init               (GtkScrolledWindow      *scrolled_window);
35 static void gtk_scrolled_window_set_arg            (GtkObject              *object,
36                                                     GtkArg                 *arg,
37                                                     guint                   arg_id);
38 static void gtk_scrolled_window_get_arg            (GtkObject              *object,
39                                                     GtkArg                 *arg,
40                                                     guint                   arg_id);
41 static void gtk_scrolled_window_destroy            (GtkObject              *object);
42 static void gtk_scrolled_window_finalize           (GtkObject              *object);
43 static void gtk_scrolled_window_map                (GtkWidget              *widget);
44 static void gtk_scrolled_window_unmap              (GtkWidget              *widget);
45 static void gtk_scrolled_window_draw               (GtkWidget              *widget,
46                                                     GdkRectangle           *area);
47 static void gtk_scrolled_window_size_request       (GtkWidget              *widget,
48                                                     GtkRequisition         *requisition);
49 static void gtk_scrolled_window_size_allocate      (GtkWidget              *widget,
50                                                     GtkAllocation          *allocation);
51 static void gtk_scrolled_window_add                (GtkContainer           *container,
52                                                     GtkWidget              *widget);
53 static void gtk_scrolled_window_remove             (GtkContainer           *container,
54                                                     GtkWidget              *widget);
55 static void gtk_scrolled_window_forall             (GtkContainer           *container,
56                                                     gboolean                include_internals,
57                                                     GtkCallback             callback,
58                                                     gpointer                callback_data);
59 static void gtk_scrolled_window_viewport_allocate  (GtkWidget              *widget,
60                                                     GtkAllocation          *allocation);
61 static void gtk_scrolled_window_adjustment_changed (GtkAdjustment          *adjustment,
62                                                     gpointer                data);
63
64
65 static GtkContainerClass *parent_class = NULL;
66
67
68 GtkType
69 gtk_scrolled_window_get_type (void)
70 {
71   static GtkType scrolled_window_type = 0;
72
73   if (!scrolled_window_type)
74     {
75       GtkTypeInfo scrolled_window_info =
76       {
77         "GtkScrolledWindow",
78         sizeof (GtkScrolledWindow),
79         sizeof (GtkScrolledWindowClass),
80         (GtkClassInitFunc) gtk_scrolled_window_class_init,
81         (GtkObjectInitFunc) gtk_scrolled_window_init,
82         /* reserved_1 */ NULL,
83         /* reserved_2 */ NULL,
84         (GtkClassInitFunc) NULL,
85       };
86
87       scrolled_window_type = gtk_type_unique (GTK_TYPE_CONTAINER, &scrolled_window_info);
88     }
89
90   return scrolled_window_type;
91 }
92
93 static void
94 gtk_scrolled_window_class_init (GtkScrolledWindowClass *class)
95 {
96   GtkObjectClass *object_class;
97   GtkWidgetClass *widget_class;
98   GtkContainerClass *container_class;
99
100   object_class = (GtkObjectClass*) class;
101   widget_class = (GtkWidgetClass*) class;
102   container_class = (GtkContainerClass*) class;
103   parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
104
105   gtk_object_add_arg_type ("GtkScrolledWindow::viewport",
106                            GTK_TYPE_VIEWPORT,
107                            GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT,
108                            ARG_VIEWPORT);
109   gtk_object_add_arg_type ("GtkScrolledWindow::hscrollbar_policy",
110                            GTK_TYPE_POLICY_TYPE,
111                            GTK_ARG_READWRITE,
112                            ARG_HSCROLLBAR_POLICY);
113   gtk_object_add_arg_type ("GtkScrolledWindow::vscrollbar_policy",
114                            GTK_TYPE_POLICY_TYPE,
115                            GTK_ARG_READWRITE,
116                            ARG_VSCROLLBAR_POLICY);
117
118   object_class->set_arg = gtk_scrolled_window_set_arg;
119   object_class->get_arg = gtk_scrolled_window_get_arg;
120   object_class->destroy = gtk_scrolled_window_destroy;
121   object_class->finalize = gtk_scrolled_window_finalize;
122
123   widget_class->map = gtk_scrolled_window_map;
124   widget_class->unmap = gtk_scrolled_window_unmap;
125   widget_class->draw = gtk_scrolled_window_draw;
126   widget_class->size_request = gtk_scrolled_window_size_request;
127   widget_class->size_allocate = gtk_scrolled_window_size_allocate;
128
129   container_class->add = gtk_scrolled_window_add;
130   container_class->remove = gtk_scrolled_window_remove;
131   container_class->forall = gtk_scrolled_window_forall;
132
133   class->scrollbar_spacing = 5;
134 }
135
136 static void
137 gtk_scrolled_window_set_arg (GtkObject        *object,
138                              GtkArg           *arg,
139                              guint             arg_id)
140 {
141   GtkScrolledWindow *scrolled_window;
142
143   scrolled_window = GTK_SCROLLED_WINDOW (object);
144
145   switch (arg_id)
146     {
147       GtkWidget *viewport;
148
149     case ARG_VIEWPORT:
150       g_return_if_fail (scrolled_window->viewport == NULL);
151       viewport = GTK_VALUE_POINTER (*arg);
152       if (!viewport)
153         viewport = gtk_viewport_new (NULL, NULL);
154       scrolled_window->viewport = viewport;
155       gtk_scrolled_window_construct (scrolled_window, NULL, NULL);
156     case ARG_HSCROLLBAR_POLICY:
157       gtk_scrolled_window_set_policy (scrolled_window,
158                                       GTK_VALUE_ENUM (*arg),
159                                       scrolled_window->vscrollbar_policy);
160       break;
161     case ARG_VSCROLLBAR_POLICY:
162       gtk_scrolled_window_set_policy (scrolled_window,
163                                       scrolled_window->hscrollbar_policy,
164                                       GTK_VALUE_ENUM (*arg));
165       break;
166     default:
167       break;
168     }
169 }
170
171 static void
172 gtk_scrolled_window_get_arg (GtkObject        *object,
173                              GtkArg           *arg,
174                              guint             arg_id)
175 {
176   GtkScrolledWindow *scrolled_window;
177
178   scrolled_window = GTK_SCROLLED_WINDOW (object);
179
180   switch (arg_id)
181     {
182     case ARG_VIEWPORT:
183       GTK_VALUE_POINTER (*arg) = scrolled_window->viewport;
184       break;
185     case ARG_HSCROLLBAR_POLICY:
186       GTK_VALUE_ENUM (*arg) = scrolled_window->hscrollbar_policy;
187       break;
188     case ARG_VSCROLLBAR_POLICY:
189       GTK_VALUE_ENUM (*arg) = scrolled_window->vscrollbar_policy;
190       break;
191     default:
192       arg->type = GTK_TYPE_INVALID;
193       break;
194     }
195 }
196
197 static void
198 gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
199 {
200   GTK_WIDGET_SET_FLAGS (scrolled_window, GTK_NO_WINDOW);
201
202   gtk_container_set_resize_mode (GTK_CONTAINER (scrolled_window), GTK_RESIZE_QUEUE);
203
204   scrolled_window->hscrollbar = NULL;
205   scrolled_window->vscrollbar = NULL;
206   scrolled_window->hscrollbar_policy = GTK_POLICY_ALWAYS;
207   scrolled_window->vscrollbar_policy = GTK_POLICY_ALWAYS;
208 }
209
210 GtkWidget*
211 gtk_scrolled_window_new (GtkAdjustment *hadjustment,
212                          GtkAdjustment *vadjustment)
213 {
214   GtkWidget *scrolled_window;
215
216   scrolled_window = gtk_type_new (GTK_TYPE_SCROLLED_WINDOW);
217
218   gtk_scrolled_window_construct (GTK_SCROLLED_WINDOW (scrolled_window), hadjustment, vadjustment);
219   
220   return scrolled_window;
221 }
222
223 void
224 gtk_scrolled_window_construct (GtkScrolledWindow *scrolled_window,
225                                GtkAdjustment     *hadjustment,
226                                GtkAdjustment     *vadjustment)
227 {
228   g_return_if_fail (scrolled_window != NULL);
229   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
230   g_return_if_fail (scrolled_window->hscrollbar == NULL);
231   g_return_if_fail (scrolled_window->vscrollbar == NULL);
232
233   if (scrolled_window->viewport)
234     g_return_if_fail (hadjustment == NULL && vadjustment == NULL);
235   else
236     scrolled_window->viewport = gtk_viewport_new (hadjustment, vadjustment);
237
238   hadjustment = gtk_viewport_get_hadjustment (GTK_VIEWPORT (scrolled_window->viewport));
239   vadjustment = gtk_viewport_get_vadjustment (GTK_VIEWPORT (scrolled_window->viewport));
240   gtk_container_set_resize_mode (GTK_CONTAINER (scrolled_window->viewport), GTK_RESIZE_PARENT);
241
242   gtk_signal_connect (GTK_OBJECT (hadjustment), "changed",
243                       (GtkSignalFunc) gtk_scrolled_window_adjustment_changed,
244                       (gpointer) scrolled_window);
245   gtk_signal_connect (GTK_OBJECT (vadjustment), "changed",
246                       (GtkSignalFunc) gtk_scrolled_window_adjustment_changed,
247                       (gpointer) scrolled_window);
248
249   scrolled_window->hscrollbar = gtk_hscrollbar_new (hadjustment);
250   scrolled_window->vscrollbar = gtk_vscrollbar_new (vadjustment);
251
252   gtk_widget_set_parent (scrolled_window->viewport, GTK_WIDGET (scrolled_window));
253   gtk_widget_set_parent (scrolled_window->hscrollbar, GTK_WIDGET (scrolled_window));
254   gtk_widget_set_parent (scrolled_window->vscrollbar, GTK_WIDGET (scrolled_window));
255
256   gtk_widget_show (scrolled_window->viewport);
257   gtk_widget_show (scrolled_window->hscrollbar);
258   gtk_widget_show (scrolled_window->vscrollbar);
259   
260   gtk_widget_ref (scrolled_window->viewport);
261   gtk_widget_ref (scrolled_window->hscrollbar);
262   gtk_widget_ref (scrolled_window->vscrollbar);
263 }
264
265 GtkAdjustment*
266 gtk_scrolled_window_get_hadjustment (GtkScrolledWindow *scrolled_window)
267 {
268   g_return_val_if_fail (scrolled_window != NULL, NULL);
269   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
270
271   return gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
272 }
273
274 GtkAdjustment*
275 gtk_scrolled_window_get_vadjustment (GtkScrolledWindow *scrolled_window)
276 {
277   g_return_val_if_fail (scrolled_window != NULL, NULL);
278   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
279
280   return gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
281 }
282
283 void
284 gtk_scrolled_window_set_policy (GtkScrolledWindow *scrolled_window,
285                                 GtkPolicyType      hscrollbar_policy,
286                                 GtkPolicyType      vscrollbar_policy)
287 {
288   g_return_if_fail (scrolled_window != NULL);
289   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
290
291   if ((scrolled_window->hscrollbar_policy != hscrollbar_policy) ||
292       (scrolled_window->vscrollbar_policy != vscrollbar_policy))
293     {
294       scrolled_window->hscrollbar_policy = hscrollbar_policy;
295       scrolled_window->vscrollbar_policy = vscrollbar_policy;
296
297       if (GTK_WIDGET (scrolled_window)->parent)
298         gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
299     }
300 }
301
302
303 static void
304 gtk_scrolled_window_destroy (GtkObject *object)
305 {
306   GtkScrolledWindow *scrolled_window;
307
308   g_return_if_fail (object != NULL);
309   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (object));
310
311   scrolled_window = GTK_SCROLLED_WINDOW (object);
312
313   gtk_widget_destroy (scrolled_window->viewport);
314   gtk_widget_destroy (scrolled_window->hscrollbar);
315   gtk_widget_destroy (scrolled_window->vscrollbar);
316
317   if (GTK_OBJECT_CLASS (parent_class)->destroy)
318     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
319 }
320
321 static void
322 gtk_scrolled_window_finalize (GtkObject *object)
323 {
324   GtkScrolledWindow *scrolled_window;
325
326   scrolled_window = GTK_SCROLLED_WINDOW (object);
327   gtk_widget_unref (scrolled_window->viewport);
328   gtk_widget_unref (scrolled_window->hscrollbar);
329   gtk_widget_unref (scrolled_window->vscrollbar);
330
331   GTK_OBJECT_CLASS (parent_class)->finalize (object);
332 }
333
334 static void
335 gtk_scrolled_window_map (GtkWidget *widget)
336 {
337   GtkScrolledWindow *scrolled_window;
338
339   g_return_if_fail (widget != NULL);
340   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
341
342   if (!GTK_WIDGET_MAPPED (widget))
343     {
344       GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
345       scrolled_window = GTK_SCROLLED_WINDOW (widget);
346
347       if (GTK_WIDGET_VISIBLE (scrolled_window->viewport) &&
348           !GTK_WIDGET_MAPPED (scrolled_window->viewport))
349         gtk_widget_map (scrolled_window->viewport);
350
351       if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar) &&
352           !GTK_WIDGET_MAPPED (scrolled_window->hscrollbar))
353         gtk_widget_map (scrolled_window->hscrollbar);
354
355       if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar) &&
356           !GTK_WIDGET_MAPPED (scrolled_window->vscrollbar))
357         gtk_widget_map (scrolled_window->vscrollbar);
358     }
359 }
360
361 static void
362 gtk_scrolled_window_unmap (GtkWidget *widget)
363 {
364   GtkScrolledWindow *scrolled_window;
365
366   g_return_if_fail (widget != NULL);
367   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
368
369   if (GTK_WIDGET_MAPPED (widget))
370     {
371       GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
372       scrolled_window = GTK_SCROLLED_WINDOW (widget);
373
374       if (GTK_WIDGET_MAPPED (scrolled_window->viewport))
375         gtk_widget_unmap (scrolled_window->viewport);
376
377       if (GTK_WIDGET_MAPPED (scrolled_window->hscrollbar))
378         gtk_widget_unmap (scrolled_window->hscrollbar);
379
380       if (GTK_WIDGET_MAPPED (scrolled_window->vscrollbar))
381         gtk_widget_unmap (scrolled_window->vscrollbar);
382     }
383 }
384
385 static void
386 gtk_scrolled_window_draw (GtkWidget    *widget,
387                           GdkRectangle *area)
388 {
389   GtkScrolledWindow *scrolled_window;
390   GdkRectangle child_area;
391
392   g_return_if_fail (widget != NULL);
393   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
394   g_return_if_fail (area != NULL);
395
396   if (GTK_WIDGET_DRAWABLE (widget))
397     {
398       scrolled_window = GTK_SCROLLED_WINDOW (widget);
399
400       if (gtk_widget_intersect (scrolled_window->viewport, area, &child_area))
401         gtk_widget_draw (scrolled_window->viewport, &child_area);
402
403       if (gtk_widget_intersect (scrolled_window->hscrollbar, area, &child_area))
404         gtk_widget_draw (scrolled_window->hscrollbar, &child_area);
405
406       if (gtk_widget_intersect (scrolled_window->vscrollbar, area, &child_area))
407         gtk_widget_draw (scrolled_window->vscrollbar, &child_area);
408     }
409 }
410
411 static void
412 gtk_scrolled_window_size_request (GtkWidget      *widget,
413                                   GtkRequisition *requisition)
414 {
415   GtkScrolledWindow *scrolled_window;
416   gint extra_height;
417   gint extra_width;
418
419   g_return_if_fail (widget != NULL);
420   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
421   g_return_if_fail (requisition != NULL);
422
423   scrolled_window = GTK_SCROLLED_WINDOW (widget);
424
425   requisition->width = 0;
426   requisition->height = 0;
427
428   if (GTK_WIDGET_VISIBLE (scrolled_window->viewport))
429     {
430       gtk_widget_size_request (scrolled_window->viewport, &scrolled_window->viewport->requisition);
431
432       requisition->width += scrolled_window->viewport->requisition.width;
433       requisition->height += scrolled_window->viewport->requisition.height;
434     }
435
436   extra_width = 0;
437   extra_height = 0;
438
439   if ((scrolled_window->hscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
440       GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar))
441     {
442       gtk_widget_size_request (scrolled_window->hscrollbar,
443                                &scrolled_window->hscrollbar->requisition);
444
445       requisition->width = MAX (requisition->width, scrolled_window->hscrollbar->requisition.width);
446       extra_height = SCROLLBAR_SPACING (scrolled_window) + scrolled_window->hscrollbar->requisition.height;
447     }
448
449   if ((scrolled_window->vscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
450       GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar))
451     {
452       gtk_widget_size_request (scrolled_window->vscrollbar,
453                                &scrolled_window->vscrollbar->requisition);
454
455       requisition->height = MAX (requisition->height, scrolled_window->vscrollbar->requisition.height);
456       extra_width = SCROLLBAR_SPACING (scrolled_window) + scrolled_window->vscrollbar->requisition.width;
457     }
458
459   requisition->width += GTK_CONTAINER (widget)->border_width * 2 + extra_width;
460   requisition->height += GTK_CONTAINER (widget)->border_width * 2 + extra_height;
461 }
462
463 static void
464 gtk_scrolled_window_size_allocate (GtkWidget     *widget,
465                                    GtkAllocation *allocation)
466 {
467   GtkScrolledWindow *scrolled_window;
468   GtkAllocation viewport_allocation;
469   GtkAllocation child_allocation;
470   guint previous_hvis;
471   guint previous_vvis;
472   gint count;
473   
474   g_return_if_fail (widget != NULL);
475   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
476   g_return_if_fail (allocation != NULL);
477
478   scrolled_window = GTK_SCROLLED_WINDOW (widget);
479   widget->allocation = *allocation;
480
481   if (scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
482     scrolled_window->hscrollbar_visible = TRUE;
483   if (scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
484     scrolled_window->vscrollbar_visible = TRUE;
485
486   if (GTK_WIDGET_VISIBLE (scrolled_window->viewport))
487     {
488       count = 0;
489
490       do {
491         gtk_scrolled_window_viewport_allocate (widget, &viewport_allocation);
492
493         child_allocation.x = viewport_allocation.x + allocation->x;
494         child_allocation.y = viewport_allocation.y + allocation->y;
495         child_allocation.width = viewport_allocation.width;
496         child_allocation.height = viewport_allocation.height;
497
498         previous_hvis = scrolled_window->hscrollbar_visible;
499         previous_vvis = scrolled_window->vscrollbar_visible;
500
501         gtk_widget_size_allocate (scrolled_window->viewport, &child_allocation);
502         /* If, after the first iteration, the hscrollbar and the
503          * vscrollbar flip visiblity, then we need both.
504          */
505         if ((count++) && 
506             (previous_hvis != scrolled_window->hscrollbar_visible) &&
507             (previous_vvis != scrolled_window->vscrollbar_visible))
508           {
509             scrolled_window->hscrollbar_visible = TRUE;
510             scrolled_window->vscrollbar_visible = TRUE;
511             break;
512           }
513
514         count++;
515       } while ((previous_hvis != scrolled_window->hscrollbar_visible) ||
516                (previous_vvis != scrolled_window->vscrollbar_visible));
517     }
518
519   if (scrolled_window->hscrollbar_visible)
520     {
521       if (!GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar))
522         gtk_widget_show (scrolled_window->hscrollbar);
523
524       child_allocation.x = viewport_allocation.x;
525       child_allocation.y = viewport_allocation.y + viewport_allocation.height + SCROLLBAR_SPACING (scrolled_window);
526       child_allocation.width = viewport_allocation.width;
527       child_allocation.height = scrolled_window->hscrollbar->requisition.height;
528       child_allocation.x += allocation->x;
529       child_allocation.y += allocation->y;
530
531       gtk_widget_size_allocate (scrolled_window->hscrollbar, &child_allocation);
532     }
533   else
534     {
535       if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar))
536         gtk_widget_hide (scrolled_window->hscrollbar);
537     }
538
539   if (scrolled_window->vscrollbar_visible)
540     {
541       if (!GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar))
542         gtk_widget_show (scrolled_window->vscrollbar);
543
544       child_allocation.x = viewport_allocation.x + viewport_allocation.width + SCROLLBAR_SPACING (scrolled_window);
545       child_allocation.y = viewport_allocation.y;
546       child_allocation.width = scrolled_window->vscrollbar->requisition.width;
547       child_allocation.height = viewport_allocation.height;
548       child_allocation.x += allocation->x;
549       child_allocation.y += allocation->y;
550
551       gtk_widget_size_allocate (scrolled_window->vscrollbar, &child_allocation);
552     }
553   else
554     {
555       if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar))
556         gtk_widget_hide (scrolled_window->vscrollbar);
557     }
558 }
559
560 static void
561 gtk_scrolled_window_add (GtkContainer *container,
562                          GtkWidget    *widget)
563 {
564   GtkScrolledWindow *scrolled_window;
565
566   g_return_if_fail (container != NULL);
567   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
568   g_return_if_fail (widget != NULL);
569
570   scrolled_window = GTK_SCROLLED_WINDOW (container);
571   gtk_container_add (GTK_CONTAINER (scrolled_window->viewport), widget);
572 }
573
574 static void
575 gtk_scrolled_window_remove (GtkContainer *container,
576                             GtkWidget    *widget)
577 {
578   GtkScrolledWindow *scrolled_window;
579
580   g_return_if_fail (container != NULL);
581   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
582   g_return_if_fail (widget != NULL);
583
584   scrolled_window = GTK_SCROLLED_WINDOW (container);
585
586   if (scrolled_window->viewport == widget ||
587       scrolled_window->hscrollbar == widget ||
588       scrolled_window->vscrollbar == widget)
589     {
590       /* this happens during destroy */
591       gtk_widget_unparent (widget);
592     }
593   else
594     gtk_container_remove (GTK_CONTAINER (scrolled_window->viewport), widget);
595 }
596
597 static void
598 gtk_scrolled_window_forall (GtkContainer *container,
599                             gboolean      include_internals,
600                             GtkCallback   callback,
601                             gpointer      callback_data)
602 {
603   GtkScrolledWindow *scrolled_window;
604
605   g_return_if_fail (container != NULL);
606   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
607   g_return_if_fail (callback != NULL);
608
609   scrolled_window = GTK_SCROLLED_WINDOW (container);
610
611   if (include_internals)
612     {
613       if (scrolled_window->viewport)
614         (* callback) (scrolled_window->viewport, callback_data);
615       
616       (* callback) (scrolled_window->vscrollbar, callback_data);
617       (* callback) (scrolled_window->hscrollbar, callback_data);
618     }
619   else if (scrolled_window->viewport)
620     gtk_container_foreach (GTK_CONTAINER (scrolled_window->viewport), callback, callback_data);
621 }
622
623 static void
624 gtk_scrolled_window_viewport_allocate (GtkWidget     *widget,
625                                        GtkAllocation *allocation)
626 {
627   GtkScrolledWindow *scrolled_window;
628
629   g_return_if_fail (widget != NULL);
630   g_return_if_fail (allocation != NULL);
631
632   scrolled_window = GTK_SCROLLED_WINDOW (widget);
633
634   allocation->x = GTK_CONTAINER (widget)->border_width;
635   allocation->y = GTK_CONTAINER (widget)->border_width;
636   allocation->width = MAX (1, widget->allocation.width - allocation->x * 2);
637   allocation->height = MAX (1, widget->allocation.height - allocation->y * 2);
638
639   if (scrolled_window->vscrollbar_visible)
640     allocation->width = MAX (1,
641       allocation->width - (scrolled_window->vscrollbar->requisition.width + SCROLLBAR_SPACING (scrolled_window)));
642   if (scrolled_window->hscrollbar_visible)
643     allocation->height = MAX (1, 
644       allocation->height - (scrolled_window->hscrollbar->requisition.height + SCROLLBAR_SPACING (scrolled_window)));
645 }
646
647 static void
648 gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment,
649                                         gpointer       data)
650 {
651   GtkScrolledWindow *scrolled_win;
652
653   g_return_if_fail (adjustment != NULL);
654   g_return_if_fail (data != NULL);
655
656   scrolled_win = GTK_SCROLLED_WINDOW (data);
657
658   if (adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_win->hscrollbar)))
659     {
660       if (scrolled_win->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
661         {
662           scrolled_win->hscrollbar_visible =
663             ((adjustment->upper - adjustment->lower) > adjustment->page_size);
664         }
665     }
666   else if (adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_win->vscrollbar)))
667     {
668       if (scrolled_win->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
669         {
670           scrolled_win->vscrollbar_visible =
671             ((adjustment->upper - adjustment->lower) > adjustment->page_size);
672         }
673     }
674   else
675     {
676       g_warning ("could not determine which adjustment scrollbar received change signal for");
677       return;
678     }
679 }